User Manual, Developers Guide and API Documentation

ResourceScheduler.cpp

Go to the documentation of this file.
00001 /*******************************************************************************
00002  * This file is part of openWNS (open Wireless Network Simulator)
00003  * _____________________________________________________________________________
00004  *
00005  * Copyright (C) 2004-2007
00006  * Chair of Communication Networks (ComNets)
00007  * Kopernikusstr. 5, D-52074 Aachen, Germany
00008  * phone: ++49-241-80-27910,
00009  * fax: ++49-241-80-22242
00010  * email: info@openwns.org
00011  * www: http://www.openwns.org
00012  * _____________________________________________________________________________
00013  *
00014  * openWNS is free software; you can redistribute it and/or modify it under the
00015  * terms of the GNU Lesser General Public License version 2 as published by the
00016  * Free Software Foundation;
00017  *
00018  * openWNS is distributed in the hope that it will be useful, but WITHOUT ANY
00019  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
00020  * A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
00021  * details.
00022  *
00023  * You should have received a copy of the GNU Lesser General Public License
00024  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
00025  *
00026  ******************************************************************************/
00027 
00028 #include <LTE/timing/ResourceScheduler.hpp>
00029 #include <LTE/controlplane/flowmanagement/FlowManager.hpp>
00030 
00031 #include <LTE/macg/MACg.hpp>
00032 #include <LTE/rlc/RLCCommand.hpp>
00033 #include <LTE/macr/PhyUser.hpp>
00034 #include <LTE/controlplane/associationHandler/AssociationHandler.hpp>
00035 #include <LTE/timing/RegistryProxy.hpp>
00036 #include <LTE/timing/partitioning/PartitioningInfo.hpp>
00037 #include <LTE/helper/QueueProxy.hpp>
00038 
00039 #include <WNS/ldk/helper/FakePDU.hpp>
00040 #include <WNS/probe/bus/ContextProviderCollection.hpp>
00041 #include <WNS/probe/bus/utils.hpp>
00042 
00043 #include <boost/bind.hpp>
00044 
00045 #include <fstream>
00046 
00047 #define A2N(a) (((a).getInteger()>0) ? layer2->getStationManager()->getStationByMAC(a)->getName() : "DLL<0")
00048 
00049 using namespace std;
00050 using namespace lte::timing;
00051 
00052 
00053 ResourceScheduler::ResourceScheduler(wns::ldk::fun::FUN* fun, const wns::pyconfig::View& config) :
00054     wns::ldk::CommandTypeSpecifier<SchedulerCommand>(fun),
00055     HasModeName(config),
00056     pyConfig(config),
00057     logger(config.get("logger")),
00058     layer2(NULL),
00059     associationService(NULL),
00060     friends(),
00061     colleagues(),
00062     framesPerSuperFrame(config.get<int>("framesPerSuperFrame")),
00063     slotDuration(config.get<simTimeType>("slotDuration")), // currently assumed constant for all timeSlots
00064     freqChannels(config.get<int>("freqChannels")),
00065     numberOfTimeSlots(config.get<int>("numberOfTimeSlots")),
00066     maxBeams(config.get<int>("maxBeams")),
00067     beamforming(config.get<bool>("grouper.beamforming")),
00068     partitionGroup(config.get<uint32_t>("group")),
00069     schedulingResultOfFrame(framesPerSuperFrame), // vector schedulingResultOfFrame[frameNr]
00070     scorer(mode,config),
00071     schedulerSpot(-1), // initialized to good value in setFriends
00072     IamUplinkMaster(config.get<bool>("uplinkMaster")), // uplink==true only for RS-RX
00073     writeMapOutput(config.get<bool>("writeMapOutput")),
00074     mapFile(NULL),
00075     transportBlockCounter(0),
00076     maxTxPower(config.get<wns::Power>("maxTxPower"))
00077 {
00078     MESSAGE_SINGLE(NORMAL, logger,"Constructor: Strategy="<<config.get<std::string>("strategy.nameInStrategyFactory"));
00079     if (writeMapOutput)
00080     {
00081         std::string outputDir =
00082             wns::simulator::getConfiguration().get<std::string>("outputDir");
00083         mapOutputFileName = outputDir + "/" + config.get<std::string>("mapOutputFileName");
00084         MESSAGE_SINGLE(NORMAL, logger,"writing maps to "<<mapOutputFileName);
00085     } // else they are None
00086 
00087     colleagues.harq = STATIC_FACTORY_NEW_INSTANCE(wns::scheduler::harq::HARQInterface, wns::PyConfigViewCreator, pyConfig.get("harq"), pyConfig.get("harq"));
00088     assure(colleagues.harq, "HARQ creation failed");
00089 
00090     wns::probe::bus::ContextProviderCollection* cpcParent = &fun->getLayer()->getContextProviderCollection();
00091     wns::probe::bus::ContextProviderCollection cpc(cpcParent);
00092     resUsageProbe_ = wns::probe::bus::collector(cpc, config, "resUsageProbeName");
00093 
00094 } // ResourceScheduler
00095 
00096 
00097 ResourceScheduler::~ResourceScheduler()
00098 {
00099     MESSAGE_SINGLE(VERBOSE, logger, "ResourceScheduler::~ResourceScheduler()");
00100     if (colleagues.registry) delete colleagues.registry; colleagues.registry=NULL;
00101     if (colleagues.strategy) delete colleagues.strategy; colleagues.strategy=NULL;
00102     if (colleagues.grouper)  delete colleagues.grouper; colleagues.grouper=NULL;
00103     if (colleagues.queueProxy) {
00104         delete colleagues.queueProxy; colleagues.queueProxy=NULL;
00105     } else {
00106         if (colleagues.queue) delete colleagues.queue;
00107     }
00108     for (int frame=0; frame<framesPerSuperFrame; ++frame)
00109     {
00110         schedulingResultOfFrame[frame] = wns::scheduler::strategy::StrategyResultPtr(); // empty
00111     }
00112     if (writeMapOutput) closeMapOutput();
00113     MESSAGE_SINGLE(VERBOSE, logger, "ResourceScheduler::~ResourceScheduler() ready");
00114 } // ~ResourceScheduler
00115 
00116 // for MapHandler
00117 int
00118 lte::timing::ResourceScheduler::getPartitionGroup()
00119 {
00120     return partitionGroup;
00121 }
00122 
00123 // this is called by ILayer2::onNodeCreated() via fun->onFUNCreated();
00124 void
00125 ResourceScheduler::onFUNCreated()
00126 {
00127     MESSAGE_SINGLE(NORMAL, logger, "ResourceScheduler::onFUNCreated()");
00128     wns::ldk::fun::FUN* fun = getFUN();
00129     assure(fun, "Could not get my FUN");
00130     layer2 = fun->getLayer<dll::ILayer2*>();
00131     assure(layer2, "could not get ILayer2 from FUN");
00132 
00133     std::string flowmanagername="FlowManager";
00134     if (layer2->getStationType() == wns::service::dll::StationTypes::UE()) {
00135         flowmanagername += "UT";
00136     } else if (layer2->getStationType() == wns::service::dll::StationTypes::FRS()) {
00137         flowmanagername += "RN";
00138     } else { // BS
00139         flowmanagername += "BS";
00140     }
00141 
00142     // remember association service
00143     associationService = layer2->getControlService<dll::services::control::Association>("ASSOCIATION"+modeBase);
00144     // Register as Observer at the association Info providers
00145     dll::ILayer2::AssociationInfoContainer ais = layer2->getAssociationInfoProvider(mode);
00146     dll::ILayer2::AssociationInfoContainer::const_iterator iter = ais.begin();
00147     for (; iter != ais.end(); ++iter)
00148         this->startObserving(*iter);
00149 
00150     if (mode == modeBase)
00151         friends.macg = fun->findFriend<lte::macg::MACg*>("macg");
00152     else
00153         friends.macg = fun->findFriend<lte::macg::MACg*>("macg"+separator+taskID);
00154 
00155     friends.rlcReader        = fun->getCommandReader("rlc");
00156     friends.phyUser          = fun->findFriend<lte::macr::PhyUser*>(modeBase+separator+"phyUser");
00157     friends.mapHandler       = fun->findFriend<lte::controlplane::IMapHandlerRS*>(mode+separator+"mapHandler");
00158     friends.rrHandler        = fun->findFriend<lte::controlplane::RRHandler*>(mode+separator+"RRHandler");
00159     friends.timer            = layer2->getManagementService<lte::timing::TimingScheduler>(mode+separator+"Timer");
00160     friends.flowManager      = layer2->getControlService<lte::controlplane::flowmanagement::FlowManager>(flowmanagername);
00161     friends.partitioningInfo = layer2->getControlService<lte::timing::partitioning::PartitioningInfo>("PARTITIONINGINFO"+modeBase);
00162     assure(friends.flowManager!=NULL,"friends.flowManager==NULL");
00163     assure(friends.rrHandler!=NULL,"friends.rrHandler==NULL");
00164 
00165     // inform my scorer about things it needs to know
00166     scorer.setRLC(friends.rlcReader);
00167     scorer.setAssociationService(associationService);
00168 
00169     std::string registryName   = pyConfig.get<std::string>("registry.nameInRegistryProxyFactory");
00170     std::string strategyName   = pyConfig.get<std::string>("strategy.nameInStrategyFactory");
00171     std::string grouperName    = pyConfig.get<std::string>("grouper.nameInGrouperFactory");
00172 
00173     // the first thing to do is to set up the registry because other colleagues
00174     // may depend on it for their initialization
00175     wns::pyconfig::View registryView = pyConfig.get<wns::pyconfig::View>("registry");
00176     wns::scheduler::RegistryCreator* registryCreator = wns::scheduler::RegistryFactory::creator(registryName);
00177     colleagues.registry = dynamic_cast<lte::timing::RegistryProxy*>(registryCreator->create(fun, registryView));
00178     //registryInLte = colleagues.registry;
00179     assure(colleagues.registry, "Registry creation failed");
00180     /* Registry= System specific proxy that forwards queries from generic scheduler
00181      * components to the system specific entities */
00182     colleagues.registry->setFUN(fun); // ? rs: why again? fun is given with registryCreator->create(fun...) above
00183     colleagues.registry->setHARQ(colleagues.harq);
00184 
00185     //lte::timing::RegistryProxy *registryInLte =
00186     //    dynamic_cast<lte::timing::RegistryProxy*>(colleagues.registry);
00187 
00188     //assure(registryInLte, "dynamic_cast failed when try to get registryInLte");
00189     colleagues.registry->setAssociationHandler(fun->findFriend<lte::controlplane::associationHandler::AssociationHandler*>(mode+separator+ "associationHandler"));
00190 
00191     // create the grouper
00192     wns::scheduler::grouper::SpatialGrouperCreator* grouperCreator = wns::scheduler::grouper::SpatialGrouperFactory::creator(grouperName);
00193     colleagues.grouper = grouperCreator->create(pyConfig.get<wns::pyconfig::View>("grouper"));
00194     assure(colleagues.grouper, "Grouper creation failed");
00195     // tell the modules who their friends and colleagues are
00196     colleagues.grouper->setColleagues(colleagues.registry);
00197 
00198     // create the scheduling strategy (subStrategies are set there)
00199     wns::scheduler::strategy::StrategyCreator* strategyCreator = wns::scheduler::strategy::StrategyFactory::creator(strategyName);
00200     colleagues.strategy = strategyCreator->create(pyConfig.get<wns::pyconfig::View>("strategy"));
00201     assure(colleagues.strategy, "Strategy module creation failed");
00202 
00203     if (IamUplinkMaster) { // RS-RX
00204         MESSAGE_SINGLE(NORMAL, logger, "ResourceScheduler::onFUNCreated(): Strategy creation finished. Now init RS-RX (UL master) specific tasks.");
00205         // create the queueProxy
00206         // The queueProxy knows the real queue if available (Tx) or the RRHandler (Rx)
00207         // It can also imitate a "dynamic segmentation" by sending specific commands...
00208         std::string queueProxyName = pyConfig.get<std::string>("queueProxy.nameInQueueFactory");
00209         MESSAGE_SINGLE(NORMAL, logger, "creating queueProxy of type "<<queueProxyName);
00210         wns::pyconfig::View queueProxyView = pyConfig.get<wns::pyconfig::View>("queueProxy");
00211         wns::scheduler::queue::QueueCreator* queueProxyCreator = wns::scheduler::queue::QueueFactory::creator(queueProxyName);
00212         wns::scheduler::queue::QueueInterface* queueProxySimple = queueProxyCreator->create(NULL, queueProxyView);
00213         assure(queueProxySimple!=NULL, "QueueProxySimple creation failed");
00214         colleagues.queue = queueProxySimple; // satisfy interfaces
00215         MESSAGE_SINGLE(NORMAL, logger, "ResourceScheduler::onFUNCreated(): QueueProxy created");
00216         colleagues.queueProxy = dynamic_cast<lte::helper::QueueProxy*>(queueProxySimple);
00217         assure(colleagues.queueProxy!=NULL, "QueueProxy creation failed");
00218         //colleagues.queueProxy->setQueue(colleagues.queue);
00219         colleagues.queueProxy->setRRHandler(friends.rrHandler);
00220         friends.rrHandler->setColleagues(colleagues.registry);
00221 
00222         // Create the HARQRetransmissionProxy for the uplink scheduler
00223         wns::scheduler::harq::HARQInterface* downlinkHARQ = NULL;
00224         downlinkHARQ = fun->findFriend<lte::timing::ResourceScheduler*>(pyConfig.get<std::string>("txSchedulerFUName"))->colleagues.harq;
00225         colleagues.harq->setDownlinkHARQ(downlinkHARQ);
00226 
00227         colleagues.strategy->setColleagues(colleagues.queueProxy, // NEW[rs]: queueProxy instead of queue
00228                                            colleagues.grouper,
00229                                            colleagues.registry,
00230                                            colleagues.harq
00231             );
00232         colleagues.queueProxy->setColleagues(colleagues.registry);
00233     } else { // RS-TX
00234         MESSAGE_SINGLE(NORMAL, logger, "ResourceScheduler::onFUNCreated(): Strategy creation finished. Now init RS-TX specific tasks.");
00235         // create the queues
00236         std::string queueName = pyConfig.get<std::string>("queue.nameInQueueFactory");
00237         MESSAGE_SINGLE(NORMAL, logger, "creating queue of type "<<queueName);
00238         wns::pyconfig::View queueView = pyConfig.get<wns::pyconfig::View>("queue");
00239         wns::scheduler::queue::QueueCreator* queueCreator = wns::scheduler::queue::QueueFactory::creator(queueName);
00240         colleagues.queue = queueCreator->create(NULL, queueView);
00241         assure(colleagues.queue, "Queue creation failed");
00242 
00243         colleagues.strategy->setColleagues(colleagues.queue,
00244                                            colleagues.grouper,
00245                                            colleagues.registry,
00246                                            colleagues.harq
00247             );
00248     }
00249     assure(colleagues.queue!=NULL,"colleagues.queue==NULL");
00250     colleagues.queue->setColleagues(colleagues.registry);
00251 
00252     if (writeMapOutput) prepareMapOutput();
00253     MESSAGE_SINGLE(NORMAL, logger, "ResourceScheduler::onFUNCreated() finished");
00254 } // onFUNCreated
00255 
00256 // called in ILayer2::onNodeCreated() to connect PHY service with spatial grouper
00257 void
00258 ResourceScheduler::onNodeCreated()
00259 {
00260     MESSAGE_SINGLE(NORMAL, logger, "ResourceScheduler::onNodeCreated()");
00261     wns::service::phy::ofdma::DataTransmission* ofdmaProvider = friends.phyUser->getDataTransmissionService();
00262     colleagues.grouper->setFriends(ofdmaProvider);
00263     colleagues.strategy->setFriends(ofdmaProvider);
00264     colleagues.queue->setFUN(getFUN());
00265     schedulerSpot = colleagues.strategy->getSchedulerSpotType(); // first known after strategy->setFriends
00266 } // onNodeCreated(): setOFDMAService
00267 
00268 void
00269 ResourceScheduler::onFlowReleased(wns::service::dll::FlowID flowId, wns::scheduler::UserID user /*nextHop!*/)
00270 {
00271     MESSAGE_SINGLE(NORMAL, logger, "ResourceScheduler::onFlowReleased("<<flowId<<")");
00272     colleagues.queue->resetQueue(flowId); // cid=flowID
00273     colleagues.registry->deregisterCID(flowId, user);
00274 }
00275 
00276 bool
00277 ResourceScheduler::doIsAccepting(const wns::ldk::CompoundPtr& compound) const
00278 {
00279     return true;
00280     //return colleagues.queue->isAccepting(compound);
00281 } // isAccepting
00282 
00283 void
00284 ResourceScheduler::doSendData(const wns::ldk::CompoundPtr& compound)
00285 {
00286     assure(compound, "sendData called with an invalid compound.");
00287     colleagues.queue->put(compound);
00288 } // doSendData
00289 
00290 void
00291 ResourceScheduler::deliverSchedulingTimeSlot(
00292     bool canBeDecoded,
00293     const wns::scheduler::SchedulingTimeSlotPtr& schedulingTimeSlot,
00294     wns::service::phy::power::PowerMeasurementPtr& phyMeasurement,
00295     int subband)
00296 {
00297     // Iterate over spatial domain
00298     for(wns::scheduler::PhysicalResourceBlockVector::iterator it = schedulingTimeSlot->physicalResources.begin();
00299         it != schedulingTimeSlot->physicalResources.end();
00300         ++it)
00301     {
00302         // Iterate over all contained compounds
00303         for (wns::scheduler::ScheduledCompoundsList::const_iterator compoundIt = it->scheduledCompoundsBegin();
00304              compoundIt != it->scheduledCompoundsEnd();
00305              ++compoundIt)
00306         {
00307             // There may be Non-HARQ transmissions in this SchedulingTimeSlot
00308             // For now these are error free and delivered regardless of canBeDecoded.
00309             // So: only check canBeDecoded flag for HARQ compounds
00310             // Do not deliver NON-HARQ compounds in a retry, they already have been
00311             // delivered.
00312             if ( (compoundIt->harqEnabled && (!canBeDecoded)) ||
00313                  (schedulingTimeSlot->harq.retryCounter > 0 && (!compoundIt->harqEnabled)))
00314             {
00315                 continue;
00316             }
00317 
00318             MESSAGE_BEGIN(NORMAL, logger, m, "onData: ");
00319             if(friends.rlcReader->commandIsActivated(compoundIt->compoundPtr->getCommandPool())) {
00320                 lte::macg::MACgCommand* macgCommand = friends.macg->getCommand(compoundIt->compoundPtr->getCommandPool());
00321                 lte::rlc::RLCCommand* rlcCommand = friends.rlcReader->readCommand<lte::rlc::RLCCommand>(compoundIt->compoundPtr->getCommandPool());
00322                 m << "received PDU";
00323                 m << " from source " << A2N(rlcCommand->peer.source)
00324                   << " via " << A2N(macgCommand->peer.source);
00325             } else {
00326                 m << " rlcReader->commandIsActivated=false !!!";
00327             }
00328             MESSAGE_END();
00329 
00330             if (!getFUN()->getProxy()->commandIsActivated(compoundIt->compoundPtr->getCommandPool(), this))
00331             {
00332                 this->activateCommand(compoundIt->compoundPtr->getCommandPool());
00333             }
00334             SchedulerCommand* myCommand = this->getCommand(compoundIt->compoundPtr->getCommandPool());
00335             myCommand->local.phyMeasurementPtr = phyMeasurement;
00336             myCommand->local.subBand = subband;
00337 
00338             getDeliverer()->getAcceptor(compoundIt->compoundPtr)->onData(compoundIt->compoundPtr);
00339         }
00340 
00341         it->clearScheduledCompounds();
00342     }
00343     schedulingTimeSlot->physicalResources.clear();
00344 }
00345 
00346 void
00347 ResourceScheduler::deliverReceived()
00348 {
00349     wns::scheduler::harq::HARQInterface::DecodeStatusContainer::iterator it;
00350 
00351     MESSAGE_SINGLE(NORMAL, logger, "Delivering " << receivedNonHARQTimeslots_.size() << " NON-HARQ transmissions");
00352 
00353     // First deliver all the non HARQ transmissions
00354     for (it = receivedNonHARQTimeslots_.begin();
00355          it!= receivedNonHARQTimeslots_.end(); ++it)
00356     {
00357       MESSAGE_SINGLE(NORMAL, logger, "Delivering NON-HARQ timeslot " << it->first.getPtr());
00358         deliverSchedulingTimeSlot(it->first->harq.successfullyDecoded,
00359                                   it->first,
00360                                   it->second.powerMeasurement_,
00361                                   it->second.sc_);
00362     }
00363 
00364     // Clear the non HARQ buffer
00365     receivedNonHARQTimeslots_.clear();
00366 
00367     // Now proceed with all that HARQ was able to decode
00368     wns::scheduler::harq::HARQInterface::DecodeStatusContainer compounds = colleagues.harq->decode();
00369 
00370     MESSAGE_SINGLE(NORMAL, logger, "Delivering " << compounds.size() << " HARQ transmissions");
00371 
00372     for (it=compounds.begin(); it!=compounds.end();++it)
00373     {
00374       MESSAGE_SINGLE(NORMAL, logger, "Delivering HARQ timeslot " << it->first.getPtr());
00375 
00376         deliverSchedulingTimeSlot(it->first->harq.successfullyDecoded,
00377                                   it->first,
00378                                   it->second.powerMeasurement_,
00379                                   it->second.sc_);
00380     }
00381 }
00382 
00383 // PDU or ResourceBlock from PHY came in ... just send up. Soneone else is responsible for the correct order (reordering).
00384 void
00385 ResourceScheduler::doOnData(const wns::ldk::CompoundPtr& compound)
00386 {
00387     SchedulerCommand* myCommand = this->getCommand(compound->getCommandPool());
00388     lte::macr::PhyCommand* phyCommand = friends.phyUser->getCommand(compound->getCommandPool());
00389 
00390     wns::scheduler::SchedulingTimeSlotPtr ts = myCommand->magic.schedulingTimeSlotPtr;
00391 
00392     MESSAGE_SINGLE(NORMAL, logger, "Received timeslot " << ts.getPtr());
00393 
00394     // after approx 3ms processing delay
00395     wns::simulator::getEventScheduler()->scheduleDelay(
00396         boost::bind(&ResourceScheduler::postDecoding, this, compound), 0.002999);
00397 }
00398 
00399 void
00400 ResourceScheduler::postDecoding(const wns::ldk::CompoundPtr compound)
00401 {
00402     assure(compound, "onData called with an invalid compound.");
00403 
00404     SchedulerCommand* myCommand = this->getCommand(compound->getCommandPool());
00405     lte::macr::PhyCommand* phyCommand = friends.phyUser->getCommand(compound->getCommandPool());
00406 
00407     wns::scheduler::SchedulingTimeSlotPtr ts = myCommand->magic.schedulingTimeSlotPtr;
00408 
00409     // A ResourceBlock has arrived (not a single compound/packet)
00410     if (ts != NULL)
00411     {
00412         MESSAGE_SINGLE(NORMAL, logger, "Received compound " <<  myCommand->magic.schedulingTimeSlotPtr->toString());
00413 
00414         wns::scheduler::harq::HARQInterface::TimeSlotInfo ti(phyCommand->local.rxPowerMeasurementPtr,
00415                                                              phyCommand->local.subBand);
00416         // Process Non-HARQ protected compounds first
00417         if (!ts->isHARQEnabled())
00418         {
00424         ts->harq.successfullyDecoded = true;
00425             wns::scheduler::harq::HARQInterface::DecodeStatusContainerEntry entry(ts, ti);
00426         receivedNonHARQTimeslots_.push_back(entry);
00427 
00428         MESSAGE_SINGLE(NORMAL, logger, "Stored NON-HARQ " << ts.getPtr());
00429             return;
00430         }
00431     else
00432     {
00433       if (colleagues.harq != NULL)
00434       {
00435         colleagues.harq->onTimeSlotReceived(ts, ti);
00436           }
00437     }
00438     }
00439 } // doOnData
00440 
00441 void
00442 ResourceScheduler::doWakeup()
00443 {} // wakeup
00444 
00445 // asked by MapHandler when it prepares the MAPs
00446 wns::scheduler::SchedulingMapPtr
00447 ResourceScheduler::getSchedulingMap(int frameNr) const
00448 {
00449     //return schedulingMapOfFrame[frameNr];
00450     return schedulingResultOfFrame[frameNr]->schedulingMap;
00451 }
00452 
00456 // triggered by TimingScheduler Event:
00457 void
00458 ResourceScheduler::startCollection(int frameNr /* for advance scheduling */,
00459                                    simTimeType _slotDuration)
00460 {
00461     MESSAGE_SINGLE(NORMAL, logger,"startCollection("<<wns::scheduler::SchedulerSpot::toString(schedulerSpot)
00462                    <<": frameNr=" << frameNr << ", d="<< _slotDuration*1e6<<"us)");
00463     assure(frameNr<framesPerSuperFrame,"invalid frameNr="<<frameNr);
00464 
00465     // wakeup triggers the upper FU to send whatever is to be sent
00466     //getReceptor()->wakeup();
00467 
00468     // this is only required for "setAllStations" and "setRelaysOnly":
00469     lte::timing::RegistryProxy* registryInLte =colleagues.registry; //dynamic_cast<lte::timing::RegistryProxy*>(colleagues.registry);
00470     //assure(registryInLte, "RegistryProxy is not of the LTE type");
00471 
00472     // PREPARE STRATEGY INPUT NOW:
00473     // due to maxBeams, this is already "MIMO-ready" [rs]
00474     // generic call for master or slave scheduling
00475     wns::scheduler::strategy::StrategyInput strategyInput(freqChannels, double(_slotDuration), numberOfTimeSlots, maxBeams, NULL /*this/*callback*/);
00476     strategyInput.beamforming = beamforming; // bool
00477     strategyInput.setFrameNr(frameNr);
00478 
00479     wns::scheduler::SchedulingMapPtr inputSchedulingMap;
00480     if (schedulerSpot==wns::scheduler::SchedulerSpot::ULSlave())
00481     {
00482         colleagues.registry->setDL(false);
00483         // inputSchedulingMap should be a deep_copy of the original SchedulingMap from BS.
00484         // Currently it is not!
00485         // But it works well and this saves a lot of time.
00486         inputSchedulingMap = friends.mapHandler->getMasterMapForSlaveScheduling(frameNr);
00487         if (inputSchedulingMap == wns::scheduler::SchedulingMapPtr()) {
00488             MESSAGE_SINGLE(NORMAL, logger, "SlaveScheduling with null inputSchedulingMap: nothing to do");
00489             return;
00490         } else if (inputSchedulingMap->isEmpty()) { // isEmpty is O(C*S) operation
00491             MESSAGE_SINGLE(NORMAL, logger, "SlaveScheduling with empty inputSchedulingMap: nothing to do");
00492             return;
00493         }
00494         MESSAGE_SINGLE(NORMAL, logger, "SlaveScheduling with inputSchedulingMap="<<inputSchedulingMap.getPtr());
00495         //<<"="<<inputSchedulingMap->toString());
00496         assure(schedulingResultOfFrame[frameNr] == wns::scheduler::strategy::StrategyResultPtr(),"ULSlave must not have stored schedulingMaps");
00497         // ^ this SchedulingMap counts as the "master mask" that the slave scheduler must obeye to.
00498         _slotDuration = inputSchedulingMap->getSlotLength(); // workaround for wrong slotDuration from Python
00499     } else if (schedulerSpot==wns::scheduler::SchedulerSpot::ULMaster()) {
00500         colleagues.registry->setDL(false);
00501         MESSAGE_SINGLE(NORMAL, logger, "MasterScheduling for UL");
00502     } else if (schedulerSpot==wns::scheduler::SchedulerSpot::DLMaster()) {
00503         colleagues.registry->setDL(true);
00504         MESSAGE_SINGLE(NORMAL, logger, "MasterScheduling for DL");
00505     } // switch(schedulerSpot)
00506 
00507     // prepare INPUT schedulingMap; take care of previous results for this frame or UL-master-maps.
00508     if (schedulingResultOfFrame[frameNr] != wns::scheduler::strategy::StrategyResultPtr())
00509     { // there already was a result of this frame (previous round or static allocation)
00510         // only possible in BS-RS-RX+TX (Master Scheduler)
00511         assure(schedulerSpot != wns::scheduler::SchedulerSpot::ULSlave(),"wrong schedulerSpot = "<<wns::scheduler::SchedulerSpot::toString(schedulerSpot));
00512         MESSAGE_SINGLE(NORMAL, logger,"schedulingResultOfFrame[frameNr="<<frameNr<<"] is not empty");
00513         // ^ if this frame was used in a previous round, it already contains the partitioning constraints
00514         inputSchedulingMap = schedulingResultOfFrame[frameNr]->schedulingMap;
00515     } else { // fresh new resource grid
00516         MESSAGE_SINGLE(NORMAL, logger,"schedulingResultOfFrame[frameNr="<<frameNr<<"] is empty. Creating new one.");
00517         if (schedulerSpot == wns::scheduler::SchedulerSpot::ULSlave()) // if I am slave (UT)
00518         {
00519             assure(schedulerSpot == wns::scheduler::SchedulerSpot::ULSlave(),"wrong schedulerSpot = "<<wns::scheduler::SchedulerSpot::toString(schedulerSpot));
00520             assure(inputSchedulingMap != wns::scheduler::SchedulingMapPtr(),"inputSchedulingMap must not be empty in slave mode");
00521         } else { // I am master (RAP)
00522             inputSchedulingMap = strategyInput.getEmptySchedulingMap();
00523             int phaseNrAtFrameNr = friends.timer->phaseNumberAtFrame(frameNr);
00524             std::string resourceDedication  = friends.partitioningInfo->getDedication(phaseNrAtFrameNr, partitionGroup); // string
00525             MESSAGE_SINGLE(NORMAL, logger,"Get partitioning: frameNr="<<frameNr<<", phaseNr="<<phaseNrAtFrameNr<<", d=\""<<resourceDedication<<"\"");
00526             // get partitioning (may depend on DL/UL), i.e. usable subchannels
00527             if (schedulerSpot==wns::scheduler::SchedulerSpot::ULMaster())
00528             { // can be different for UL/DL
00529                 wns::scheduler::UsableSubChannelVector usableSubChannels
00530                     = friends.partitioningInfo->getUsableSubChannels(phaseNrAtFrameNr, partitionGroup);
00531                 assure(usableSubChannels.size()>=freqChannels,"#usableSubChannels="<<usableSubChannels.size());
00532 
00533                 MESSAGE_BEGIN(NORMAL, logger, m, "usableSubChannels: ");
00534                 for (int ii=0; ii< usableSubChannels.size(); ++ii)
00535                 {
00536                     m << (usableSubChannels[ii] ? "1" : "0");
00537                 }
00538                 MESSAGE_END()
00539 
00540                     inputSchedulingMap->maskOutSubChannels(usableSubChannels); // arg is just a const ref
00541             }
00542             else if (schedulerSpot==wns::scheduler::SchedulerSpot::DLMaster())
00543             { // can be different for UL/DL
00544                 const wns::scheduler::UsableSubChannelVector& usableSubChannels
00545                     = friends.partitioningInfo->getUsableSubChannels(phaseNrAtFrameNr, partitionGroup);
00546                 assure(usableSubChannels.size()>=freqChannels,"#usableSubChannels="<<usableSubChannels.size());
00547                 inputSchedulingMap->maskOutSubChannels(usableSubChannels);
00548             } // switch(schedulerSpot)
00549             if (resourceDedication == "Feeder")
00550                 registryInLte->setRelaysOnly(); // used in filterReachable(), which must be changed anyway.
00551         } // if master/slave
00552     } // if empty/nonempty pre-scheduling input
00553     strategyInput.setInputSchedulingMap(inputSchedulingMap);
00554 
00555     // DO THE SCHEDULING (CALL STRATEGY):
00556     wns::scheduler::strategy::StrategyResult strategyResult = // copy small container
00557         colleagues.strategy->startScheduling(strategyInput);
00558     MESSAGE_SINGLE(VERBOSE, logger, "strategyResult.schedulingMap " << strategyResult.schedulingMap->toString());
00559     // we only user strategyResult.schedulingMap and not strategyResult.bursts anymore.
00560 
00561     MESSAGE_SINGLE(NORMAL, logger, "startCollection finished");
00562 
00563     assure(_slotDuration == strategyResult.schedulingMap->getSlotLength(),
00564            "mismatch in slotLength: slotDuration="<<slotDuration<<" vs getSlotLength()="<<strategyResult.schedulingMap->getSlotLength());
00565 
00566     if (schedulerSpot==wns::scheduler::SchedulerSpot::ULMaster())
00567     {
00568         MESSAGE_SINGLE(VERBOSE, logger, "deleteCompoundsInBursts()+deleteCompounds()");
00569         strategyResult.deleteCompoundsInBursts(); // MapInfoCollection is not needed anymore
00570         strategyResult.schedulingMap->deleteCompounds(); // compounds are not needed anymore
00571         strategyResult.schedulingMap->grantFullResources(); // full time length on used subchannels (only for resourceUsage probe and plot)
00572     }
00573 
00574     // save result per frame
00575     // perhaps more? TODO: antennaPatterns
00576     schedulingResultOfFrame[frameNr] = wns::scheduler::strategy::StrategyResultPtr(new wns::scheduler::strategy::StrategyResult(strategyResult)); // make SmartPtr
00577 
00578     // adjustment for filterReachable in RegistyProxy:
00579     registryInLte->setAllStations(); // => relaysOnly = false;
00580     if (schedulerSpot == wns::scheduler::SchedulerSpot::DLMaster()) {
00581         friends.mapHandler->saveDLMap(frameNr,strategyResult.schedulingMap); // push
00582     } else if (schedulerSpot == wns::scheduler::SchedulerSpot::ULMaster()) {
00583         friends.mapHandler->saveULMap(frameNr,strategyResult.schedulingMap); // push
00584     }
00585 } // startCollection()
00586 
00587 // called from rap::Events for RAP or ResourceSchedulerUT for UT:
00588 // this method means: really send out the packets to PhyUser...
00589 void
00590 ResourceScheduler::finishCollection(int frameNr, simTimeType _startTime) {
00591     // startTime is absolute time (==now)
00592     assure(frameNr<framesPerSuperFrame,"invalid frameNr="<<frameNr);
00593     transportBlockCounter++;
00594     if (transportBlockCounter == 0)
00595     {
00596         transportBlockCounter++;
00597     }
00598 
00599     if (schedulingResultOfFrame[frameNr] == wns::scheduler::strategy::StrategyResultPtr())
00600     {
00601         MESSAGE_SINGLE(NORMAL, logger,"finishCollection(frameNr="<<frameNr<<", startTime="<<_startTime<<"): empty schedulingResult. nothing to do");
00602         return;
00603     }
00604     assure(schedulingResultOfFrame[frameNr] != wns::scheduler::strategy::StrategyResultPtr(),"schedulingResultOfFrame[frameNr="<<frameNr<<"]==NULL");
00605     wns::scheduler::SchedulingMapPtr schedulingMap = schedulingResultOfFrame[frameNr]->schedulingMap;
00606     double resourceUsage = schedulingMap->getResourceUsage();
00607     MESSAGE_SINGLE(NORMAL, logger,"finishCollection(frameNr="<<frameNr<<", startTime="<<_startTime<<"): "
00608                    <<"schedulingMap="<<resourceUsage*100.0<<"% full");
00609 
00610     if(resUsageProbe_->hasObservers())
00611         probeResourceUsage(schedulingMap);
00612 
00613     wns::scheduler::UserID myOwnUserID = wns::scheduler::UserID(layer2->getNode());
00614     if (schedulerSpot == wns::scheduler::SchedulerSpot::ULMaster())
00615     { // only beamforming etc.
00616         // RS-RX does not need to transmit pdus
00617         wns::scheduler::GroupingPtr sdmaGrouping = schedulingResultOfFrame[frameNr]->sdmaGrouping;
00618         if (sdmaGrouping != wns::scheduler::GroupingPtr()) {
00619             MESSAGE_SINGLE(NORMAL, logger,"finishCollection(frameNr="<<frameNr<<", startTime="<<_startTime<<"): setting antennaPatterns...");
00620             wns::scheduler::AntennaPatternsPerUser& antennaPatternsPerUser = sdmaGrouping->patterns;
00621             // foreach user in sdmaGrouping:
00622             for (wns::scheduler::AntennaPatternsPerUser::const_iterator iter = antennaPatternsPerUser.begin(); iter != antennaPatternsPerUser.end(); ++iter)
00623             {
00624                 wns::scheduler::UserID user = iter->first;
00625                 wns::service::phy::ofdma::PatternPtr antennaPattern = iter->second;
00626                 MESSAGE_SINGLE(NORMAL, logger,"finishCollection(frameNr="<<frameNr<<"): setReceiveAntennaPattern(user="<<user.getName()<<")");
00627                 friends.phyUser->setReceiveAntennaPattern(user.getNode(), antennaPattern);
00628             } // foreach user in sdmaGrouping
00629         } else {// if not sdmaGrouping used
00630             MESSAGE_SINGLE(NORMAL, logger,"finishCollection(frameNr="<<frameNr<<", startTime="<<_startTime<<"): nothing to do");
00631         }
00632     } else { // RS-TX (BS-DL or UT-UL)
00633         if (colleagues.harq != NULL)
00634         { // process finished schedulingMap in order to store ResourceBlocks into HARQ processes...
00635             for (wns::scheduler::SubChannelVector::iterator iterSubChannel = schedulingMap->subChannels.begin(); iterSubChannel != schedulingMap->subChannels.end(); ++iterSubChannel)
00636             {
00637                 wns::scheduler::SchedulingSubChannel& subChannel = *iterSubChannel;
00638                 // TDMA can be easily supported...
00639                 for (wns::scheduler::SchedulingTimeSlotPtrVector::iterator iterTimeSlot = subChannel.temporalResources.begin();
00640                      iterTimeSlot != subChannel.temporalResources.end(); ++iterTimeSlot)
00641                 {
00642                     wns::scheduler::SchedulingTimeSlotPtr timeSlotPtr = *iterTimeSlot;
00643                     // for the UL slave it is not right to ask isEmpty, since all UL granted resources have isEmpty==false.
00644                     //if (!timeSlotPtr->isEmpty())
00645                     if (timeSlotPtr->countScheduledCompounds()>0)
00646                     {
00647                         if (timeSlotPtr->harq.transportBlockID == 0)
00648                         {
00649                             timeSlotPtr->harq.transportBlockID = transportBlockCounter;
00650                         }
00651                         colleagues.harq->storeSchedulingTimeSlot(transportBlockCounter, timeSlotPtr); // store ResourceBlock
00652                     }
00653                 }
00654             }
00655         } // if HARQ
00656 
00657         applyPowerLimitation(schedulingMap);
00658 
00659         // currently the "SDMA antenna patterns" are set for each packet by bfTransmission->startTransmission() in PhyUser
00660         // but it would be more efficient to set it once, like this:
00661         // set SDMA antenna patterns first
00662         wns::scheduler::GroupingPtr sdmaGrouping = schedulingResultOfFrame[frameNr]->sdmaGrouping;
00663         wns::scheduler::AntennaPatternsPerUser* antennaPatternsPerUser=NULL;
00664         if (sdmaGrouping != wns::scheduler::GroupingPtr()) {
00665             antennaPatternsPerUser = &(sdmaGrouping->patterns);
00666             if (0) { // currently not needed because there's no support for that in PhyUser and OFDMAPhy
00667                 // foreach user in sdmaGrouping:
00668                 for (wns::scheduler::AntennaPatternsPerUser::const_iterator iter = antennaPatternsPerUser->begin(); iter != antennaPatternsPerUser->end(); ++iter)
00669                 {
00670                     wns::scheduler::UserID user = iter->first;
00671                     wns::service::phy::ofdma::PatternPtr antennaPattern = iter->second;
00672                     MESSAGE_SINGLE(NORMAL, logger,"finishCollection(frameNr="<<frameNr<<"): setTransmitAntennaPattern(user="<<user.getName()<<")");
00673                     //friends.phyUser->setTransmitAntennaPattern(user, antennaPattern); // There is currently no support for that in PhyUser and OFDMAPhy
00674                 } // foreach user in sdmaGrouping
00675             }
00676         } // if sdmaGrouping used
00677 
00678         if (writeMapOutput)
00679         { // write schedulingMap to file for visualization purposes:
00680             evaluateMap(schedulingMap,frameNr);
00681         }
00682 
00683         // now send packets=pdus=compounds ...
00684 
00685         // iterate over all compounds in schedulingMap
00686         // forall compounds in schedulingMap:
00687         wns::scheduler::SubChannelVector& subChannels  = schedulingMap->subChannels;
00688 
00689         double _slotDuration = schedulingMap->getSlotLength();
00690 
00691         for ( wns::scheduler::SubChannelVector::iterator iterSubChannel = subChannels.begin();
00692               iterSubChannel != subChannels.end(); ++iterSubChannel)
00693         {
00694             wns::scheduler::SchedulingSubChannel& subChannel = *iterSubChannel;
00695             for ( wns::scheduler::SchedulingTimeSlotPtrVector::iterator iterTimeSlot = subChannel.temporalResources.begin();
00696                   iterTimeSlot != subChannel.temporalResources.end(); ++iterTimeSlot)
00697             {
00698                 wns::scheduler::SchedulingTimeSlotPtr timeSlotPtr = *iterTimeSlot;
00699 
00700                 if (timeSlotPtr->isEmpty())
00701                 {
00702                     // Skip empty time slots
00703                     continue;
00704                 }
00705                 if (timeSlotPtr->countScheduledCompounds()==0)
00706                 {
00707                     MESSAGE_SINGLE(NORMAL, logger, "timeSlotPtr->countScheduledCompounds()==0");
00708                     // Skip if no compound inside
00709                     continue;
00710                 }
00711                 assure(timeSlotPtr->physicalResources[0].hasScheduledCompounds()>0,"PRB[0] has zero compounds");
00712                 wns::scheduler::UserID TSuser = timeSlotPtr->getUserID();
00713                 wns::scheduler::UserID PRBuser = timeSlotPtr->physicalResources[0].getUserID();
00714                 assure( TSuser.isValid(), "Invalid TSuser=NULL");
00715                 assure( PRBuser.isValid(), "Invalid PRBuser=NULL");
00716                 assure(TSuser==PRBuser,"finishCollection("<<myOwnUserID.getName()<<"): PRB on subchannel="<<subChannel.subChannelIndex
00717                        <<" has timeSlotPtr->getUserID()="<<TSuser.getName()
00718                        <<" but physicalResources[0]->getUserID()="<<PRBuser.getName());
00719                 // ^ In the UT these TSuser and PRBuser are still the UT's name (myself)
00720                 // That is important, because the libwns scheduler needs to know where it may put more compounds into;
00721                 // it shall not use PRBs tagged for other UTs. IF ther would be an "BSx" tag,
00722                 // then the UTs could not know which PRB is available for them.
00723                 // Please keep it and don't think about changing this [rs].
00724                 wns::scheduler::UserID user = timeSlotPtr->physicalResources[0].getUserIDOfScheduledCompounds();
00728                 assure(user.isValid(), "Invalid !user.isValid()");
00729                 if ((schedulerSpot==wns::scheduler::SchedulerSpot::ULSlave()) // we are in UT
00730                     //&&(user!=TSuser) // <- happens in UT
00731                     && (TSuser != myOwnUserID))
00732                 { // this is not a resource I'm responsible for (other UT)
00733                     // Skip wrong users (SchedulingMap still has them, because it is the same for all UTs)
00734                     MESSAGE_SINGLE(NORMAL, logger, "skipping PRB on subchannel="<<subChannel.subChannelIndex
00735                                    <<" has timeSlotPtr->userID="<<TSuser.getName()
00736                                    <<" and PRB->userID="<<PRBuser.getName()
00737                                    <<" and compound->userID="<<user.getName());
00738                     continue;
00739                 } else {
00740                     MESSAGE_SINGLE(NORMAL, logger, "PRB on subchannel="<<subChannel.subChannelIndex
00741                                    <<" has timeSlotPtr->userID="<<TSuser.getName()
00742                                    <<" and PRB->userID="<<PRBuser.getName()
00743                                    <<" and compound->userID="<<user.getName());
00744                 }
00745 
00746                 int netDataBits = timeSlotPtr->getNetBlockSizeInBits();
00747                 // (this is one "resource block" for HARQ retransmission)
00748                 wns::ldk::CompoundPtr containerPdu = wns::ldk::CompoundPtr(
00749                     new wns::ldk::Compound(getFUN()->createCommandPool(),
00750                                            wns::ldk::helper::FakePDUPtr(new wns::ldk::helper::FakePDU(netDataBits)))); // magic "2" as marker?
00751                 // set the scheduler command (contained in myPDU)
00752                 SchedulerCommand* myCommand = this->activateCommand(containerPdu->getCommandPool());
00753                 if (timeSlotPtr->getTxPower() == wns::Power())
00754                 {
00755                     MESSAGE_SINGLE(NORMAL, logger, "WARNING: 0 dBm transmit power. I will not send this");
00756                     continue;
00757                 }
00758                 myCommand->magic.schedulingTimeSlotPtr = wns::scheduler::SchedulingTimeSlotPtr(new wns::scheduler::SchedulingTimeSlot(*timeSlotPtr));; // SmartPtr
00759 
00760         // Check for HARQ validity
00761         if (timeSlotPtr->isHARQEnabled())
00762           {
00763             if (timeSlotPtr->harq.ackCallback.empty())
00764               {
00765             std::cout << "Trying to retransmit resource block with empty ack callback in HARQUplinkSlaveRetransmission" << std::endl;
00766             exit(1);
00767           }
00768 
00769             if (timeSlotPtr->harq.nackCallback.empty())
00770               {
00771             std::cout << "Trying to retransmit resource block with empty nack callback in HARQUplinkSlaveRetransmission" << std::endl;
00772             exit(1);
00773               }
00774           }
00775                 lte::macr::PhyCommand* phyCommand = dynamic_cast<lte::macr::PhyCommand*>(
00776                     getFUN()->getProxy()->activateCommand( containerPdu->getCommandPool(), friends.phyUser ));
00777                 assure(user!=myOwnUserID, "Invalid user="<<user.getName()); // don't send to myself.
00778                 // currently assumed constant slotDuration for all timeSlots:
00779                 // later TODO: sum (0..timeSlotPtr->timeSlotIndex) timeSlotPtr->slotLength
00780                 simTimeType timeSlotOffset = (timeSlotPtr->timeSlotIndex * slotDuration);
00781                 phyCommand->magic.source      = myOwnUserID.getNode();
00782                 if (user.isBroadcast())
00783                 {
00784                     phyCommand->magic.destination = NULL;
00785                 }
00786                 else
00787                 {
00788                     phyCommand->magic.destination = user.getNode();
00789                 }
00790                 if(myCommand->magic.schedulingTimeSlotPtr->harq.retryCounter > 0 
00791                     && myCommand->magic.schedulingTimeSlotPtr->harq.NDI == false)
00792                 {
00793                     phyCommand->magic.isRetransmission = true;
00794                 }
00795                 else
00796                 {
00797                     phyCommand->magic.isRetransmission = false;
00798                 }
00799 
00800                 phyCommand->magic.txp         = timeSlotPtr->getTxPower(); // TxPower to use for sending
00801 
00802                 phyCommand->local.subBand     = timeSlotPtr->subChannelIndex;
00803                 phyCommand->local.phyModePtr  = timeSlotPtr->physicalResources[0].getPhyMode(); // just as placeholder; the real phyModes are inside
00804                 phyCommand->local.start       = timeSlotOffset; // time relative to the start of the burst
00805                 phyCommand->local.stop        = timeSlotOffset + _slotDuration;   // time relative to the start of the burst
00806                 phyCommand->local.start      += _startTime;
00807                 phyCommand->local.stop       += _startTime;
00808                 phyCommand->local.stop       -= wns::scheduler::slotLengthRoundingTolerance; // safety
00809                 phyCommand->local.beam        = 0; // beams are inside
00810                 phyCommand->local.beamforming = beamforming;
00811                 if (beamforming) {
00812                     assure(antennaPatternsPerUser!=NULL,"antennaPatternsPerUser==NULL");
00813                     wns::service::phy::ofdma::PatternPtr antennaPattern = (*antennaPatternsPerUser)[user];
00814                     assure(antennaPattern != wns::service::phy::ofdma::PatternPtr(),"No Beamforming antennaPattern set.");
00815                     phyCommand->local.pattern = antennaPattern; // see wns::service::phy::ofdma::PatternPtr()
00816                 }
00817 
00818                 phyCommand->local.modeRxTx = lte::macr::PhyCommand::Tx; // Rx is obsolete. Maybe completely obsolete
00819 
00820                 MESSAGE_BEGIN(NORMAL, logger, m, "PRB for ");
00821                 m << user.getName() << " scheduled on "
00822                   <<"frame="<<frameNr<< ", subChannel="<<timeSlotPtr->subChannelIndex
00823                   << ", T=["<<int(phyCommand->local.start*1e6+.5)<<"-"<<int(phyCommand->local.stop*1e6+.5)<<"us]";
00824                 //m <<", PHY="<<*phyCommand->local.phyModePtr;
00825                 if (beamforming || (maxBeams>1)) { m << ", beam=" << phyCommand->local.beam; }
00826                 //m << "\nEstimated: C=" << estimatedCandI.C << ", I=" << estimatedCandI.I;
00827                 //m << ", SINR="<<estimatedCandI.toSINR();
00828                 m << ", TxP="<<phyCommand->magic.txp << ", TBC=" << myCommand->magic.schedulingTimeSlotPtr->harq.transportBlockID;
00829                 m << ", netBits=" << netDataBits << "/" << containerPdu->getLengthInBits();
00830                 MESSAGE_END();
00831                 assure(phyCommand->local.subBand < freqChannels, "Invalid frequency channel "<<phyCommand->local.subBand);
00832                 assure(phyCommand->local.stop > phyCommand->local.start, "stop-start = "<<phyCommand->local.stop<<" - "<< phyCommand->local.start);
00833                 assure(phyCommand->local.phyModePtr->isValid(),"cannot work when !phyMode.isValid()");
00834                 assure(phyCommand->local.phyModePtr->dataRateIsValid(),"cannot work when !phyMode.dataRateIsValid()");
00835                 assure(colleagues.strategy->isTx(),"must be TxScheduler");
00836                 assure(getConnector()->hasAcceptor(containerPdu),"Lower FU is not accepting compound but is supposed to do so");
00837                 getConnector()->getAcceptor(containerPdu)->sendData(containerPdu); // to PhyUser or HARQ
00838             } // forall timeSlots
00839         } // forall subchannels
00840     } // TxScheduler
00841     schedulingResultOfFrame[frameNr] = wns::scheduler::strategy::StrategyResultPtr(); // clear result; not needed anymore; must be clean before next round
00842 } // finishCollection
00843 
00844 void 
00845 ResourceScheduler::probeResourceUsage(wns::scheduler::SchedulingMapPtr schedulingMap)
00846 {
00847     wns::scheduler::SubChannelVector& subChannels  = schedulingMap->subChannels;
00848 
00849     double _slotDuration = schedulingMap->getSlotLength();
00850 
00851     unsigned int numResources = 0;
00852     unsigned int usedResources = 0;
00853 
00854     for ( wns::scheduler::SubChannelVector::iterator iterSubChannel = subChannels.begin();
00855           iterSubChannel != subChannels.end(); ++iterSubChannel)
00856     {
00857         wns::scheduler::SchedulingSubChannel& subChannel = *iterSubChannel;
00858         for ( wns::scheduler::SchedulingTimeSlotPtrVector::iterator iterTimeSlot = subChannel.temporalResources.begin();
00859               iterTimeSlot != subChannel.temporalResources.end(); ++iterTimeSlot)
00860         {
00861             wns::scheduler::SchedulingTimeSlotPtr timeSlotPtr = *iterTimeSlot;
00862             // Only count resources for this UT in ULSlave
00863             if(schedulerSpot == wns::scheduler::SchedulerSpot::ULSlave())
00864             {
00865                 wns::scheduler::UserID myOwnUserID = wns::scheduler::UserID(layer2->getNode());
00866                 if(timeSlotPtr->getUserID() == myOwnUserID)
00867                     numResources++;            
00868             }
00869             // Count all resources in master
00870             else
00871             {
00872                 numResources++;
00873             }
00874             
00875             if(!timeSlotPtr->isEmpty() && timeSlotPtr->countScheduledCompounds() > 0)
00876                usedResources++;
00877         }
00878     }
00879     resUsageProbe_->put(double(usedResources)/double(numResources), 
00880         boost::make_tuple("SchedulerSpot", schedulerSpot));
00881 }
00882 
00883 void
00884 ResourceScheduler::applyPowerLimitation(wns::scheduler::SchedulingMapPtr schedulingMap)
00885 {
00886     // First pass: Find the sum TxPower
00887     wns::Power sum = wns::Power::from_mW(0.0);
00888     wns::scheduler::UserID myOwnUserID = wns::scheduler::UserID(layer2->getNode());
00889 
00890     for (wns::scheduler::SubChannelVector::iterator iterSubChannel = schedulingMap->subChannels.begin(); iterSubChannel != schedulingMap->subChannels.end(); ++iterSubChannel)
00891     {
00892         wns::scheduler::SchedulingSubChannel& subChannel = *iterSubChannel;
00893         for ( wns::scheduler::SchedulingTimeSlotPtrVector::iterator iterTimeSlot = subChannel.temporalResources.begin();
00894               iterTimeSlot != subChannel.temporalResources.end(); ++iterTimeSlot)
00895         {
00896             wns::scheduler::SchedulingTimeSlotPtr timeSlotPtr = *iterTimeSlot;
00897 
00898             if (schedulerSpot==wns::scheduler::SchedulerSpot::ULSlave())
00899             {
00900                 if (timeSlotPtr->getUserID() != myOwnUserID)
00901                 {
00902                     // Not my transmission. Belongs to another user
00903                     continue;
00904                 }
00905             }
00906             sum += timeSlotPtr->getTxPower();
00907         }
00908     }
00909 
00910     wns::Ratio downscale = wns::Ratio::from_factor(1.0);
00911 
00912     if (sum > maxTxPower)
00913     {
00914         downscale = maxTxPower / sum;
00915 
00916         MESSAGE_SINGLE(NORMAL, logger, "Power limitation reached, downscaling by " << downscale);
00917 
00918         // Second pass:
00919         for (wns::scheduler::SubChannelVector::iterator iterSubChannel = schedulingMap->subChannels.begin(); iterSubChannel != schedulingMap->subChannels.end(); ++iterSubChannel)
00920         {
00921             wns::scheduler::SchedulingSubChannel& subChannel = *iterSubChannel;
00922             for ( wns::scheduler::SchedulingTimeSlotPtrVector::iterator iterTimeSlot = subChannel.temporalResources.begin();
00923                   iterTimeSlot != subChannel.temporalResources.end(); ++iterTimeSlot)
00924             {
00925                 wns::scheduler::SchedulingTimeSlotPtr timeSlotPtr = *iterTimeSlot;
00926 
00927                 if (schedulerSpot==wns::scheduler::SchedulerSpot::ULSlave())
00928                 {
00929                     if (timeSlotPtr->getUserID() != myOwnUserID)
00930                     {
00931                         // Not my transmission. Belongs to another user
00932                         continue;
00933                     }
00934                 }
00935 
00936                 timeSlotPtr->setTxPower( timeSlotPtr->getTxPower() * downscale);
00937             }
00938         }
00939     }
00940 }
00941 
00942 void
00943 ResourceScheduler::resetHARQScheduledPeerRetransmissions()
00944 {
00945     if(IamUplinkMaster)
00946     {
00947         //colleagues.harq->resetAllScheduledPeerRetransmissionCounters();
00948     }
00949 }
00950 
00951 void
00952 ResourceScheduler::sendPendingHARQFeedback()
00953 {
00954     colleagues.harq->sendPendingFeedback();
00955 }
00956 
00957 lte::helper::Route
00958 ResourceScheduler::score(const wns::ldk::CompoundPtr& compound)
00959 {
00960     return scorer.score(compound);
00961 }
00962 
00963 
00964 void
00965 ResourceScheduler::prepareMapOutput()
00966 {
00967     if (!writeMapOutput) return; // nothing to do
00968     MESSAGE_SINGLE(NORMAL, logger, "prepareMapOutput(): opening output file "<<mapOutputFileName);
00969     mapFile = new std::ofstream(mapOutputFileName.c_str());
00970     assure(mapFile!=NULL,"cannot write to mapFile "<<mapOutputFileName);
00971     assure(mapFile->is_open(), "mapFile " << mapOutputFileName << " not open");
00972     (*mapFile) << "# contents=\""<<logger.getLoggerName()<<" map\""<<std::endl;
00973     wns::scheduler::SchedulingMap::writeHeaderToFile(*mapFile);
00974 }
00975 
00976 // analyze MAPs to get performance values from it.
00977 // Probe output and file output for Matlab
00978 void
00979 ResourceScheduler::evaluateMap(wns::scheduler::SchedulingMapPtr schedulingMap, int frameNr)
00980 {
00981     if (!writeMapOutput) return; // nothing to do
00982     MESSAGE_SINGLE(NORMAL, logger, "evaluateMap(): writing to "<<mapOutputFileName);
00983     assure(mapFile!=NULL,"cannot write to mapFile "<<mapOutputFileName);
00984     // write table output to file for postprocessing with Matlab/Gnuplot
00985     //friends.timer
00986     simTimeType now = wns::simulator::getEventScheduler()->getTime();
00987     *mapFile << "# t="<<now<<", frameNr="<<frameNr<<std::endl;
00988     std::stringstream p;
00989     p << now << "\t";
00990     schedulingMap->writeToFile(*mapFile,p.str());
00991     // "ResourceUsage" probe is not written here but in finishCollection()
00992 } // evaluateMap
00993 
00994 void
00995 ResourceScheduler::closeMapOutput()
00996 {
00997     if (!writeMapOutput) return; // nothing to do
00998     MESSAGE_SINGLE(NORMAL, logger, "closeMapOutput(): closing "<<mapOutputFileName);
00999     if (*mapFile) mapFile->close();
01000 }
01001 

Generated on Fri May 25 03:32:07 2012 for openWNS by  doxygen 1.5.5