User Manual, Developers Guide and API Documentation

TimingScheduler.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/TimingScheduler.hpp>
00029 #include <LTE/timing/events/Base.hpp>
00030 #include <LTE/timing/events/rap/Events.hpp>
00031 #include <LTE/timing/events/ut/Events.hpp>
00032 #include <LTE/main/Layer2.hpp>
00033 #include <LTE/controlplane/bch/BCHUnitInterface.hpp>
00034 
00035 #include <DLL/StationManager.hpp>
00036 
00037 #include <sstream>
00038 #include <boost/bind.hpp>
00039 #include <boost/shared_ptr.hpp>
00040 
00041 #define A2N(a) layer2->getStationManager()->getStationByMAC(a)->getName()
00042 
00043 using namespace lte::timing;
00044 using namespace lte::timing::events;
00045 
00046 STATIC_FACTORY_REGISTER_WITH_CREATOR(
00047     TimingScheduler,
00048     wns::ldk::ManagementServiceInterface,
00049     "lte.timing.TimingScheduler",
00050     wns::ldk::MSRConfigCreator);
00051 
00052 TimingScheduler::TimingScheduler(wns::ldk::ManagementServiceRegistry* msr,
00053                                  wns::pyconfig::View _config) :
00054     wns::ldk::ManagementService(msr),
00055     lte::helper::HasModeName(_config),
00056     layer2(NULL),
00057     fun(NULL),
00058     config(_config),
00059     logger(config.get("logger")),
00060     superFrameLength(config.get<simTimeType>("mac.superFrameLength")),
00061     superFrameStartTime(0.0),
00062     eventContainer(),
00063     stationTaskPhaseContainer(),
00064     peerTiming(),
00065     peerTimingSchedulers(),
00066     es(wns::simulator::getEventScheduler()),
00067     startOfFirstFrame(config.get<simTimeType>("startOfFirstFrame")),
00068     frameLength(config.get<simTimeType>("frameLength")),
00069     schedulingOffset(config.get<int>("mac.schedulingOffset")),
00070     numberOfFramesToSchedule(config.get<int>("mac.numberOfFramesToSchedule")),
00071     framesPerSuperFrame(config.get<int>("mac.framesPerSuperFrame")),
00072     switchingPointOffset(config.get<simTimeType>("mac.switchingPointOffset")),
00073     duplex(DuplexSchemes::fromString(config.get<std::string>("mac.duplex")))
00074 {
00075     MESSAGE_BEGIN(VERBOSE, logger, m, "TimingScheduler() constructed: ");
00076     m << "superFrameLength=" << superFrameLength << " s\n";
00077     m << "superFrameStartTime=" << superFrameStartTime << " s\n";
00078     m << "switchingPointOffset=" << switchingPointOffset << " s";
00079     MESSAGE_END();
00080 
00081 } // SuperFrameScheduler
00082 
00083 TimingScheduler::~TimingScheduler()
00084 {
00085     while (!eventContainer.empty())
00086     {
00087         delete eventContainer.begin()->event;
00088         eventContainer.erase(eventContainer.begin());
00089     }
00090 }
00091 
00092 void
00093 TimingScheduler::onMSRCreated()
00094 {
00095     MESSAGE_BEGIN(NORMAL, logger, m, "onFUNCreated(): Starting Timing for superFrames with interval of ");
00096     m << superFrameLength << " s";
00097     MESSAGE_END();
00098 
00099     // Obtain FUN pointer
00100     layer2 = dynamic_cast<dll::ILayer2*>(getMSR()->getLayer());
00101     assure(layer2, "WinProSt TimingScheduler could not retrieve dll::ILayer2 pointer");
00102     fun = layer2->getFUN();
00103 
00104     dll::ILayer2::AssociationInfoContainer ais = layer2->getAssociationInfoProvider(mode);
00105     dll::ILayer2::AssociationInfoContainer::const_iterator iter = ais.begin();
00106     for (; iter != ais.end(); ++iter)
00107         this->startObserving(*iter);
00108 
00109     // this is my own frame structure (sequence of Events for one superFrameLength)
00110     readStationTaskPhases("stationTaskPhases");
00111     // ^ too late here for MapHandler::initSuperFrameMap() which needs stationTaskPhases
00112     // NOTE: readEvents has to be re-called each time the Task phases of a
00113     // station are altered
00114     assure(wns::simulator::getEventScheduler()->getTime()==0.0,"this must be called at simTime 0.0");
00115     readEvents("phases");
00116 
00117     startPeriodicTimeout(superFrameLength, 0);
00118 }
00119 
00120 void
00121 TimingScheduler::onWorldCreated()
00122 {
00123     // only for static associations:
00124     for (int i=0; i< config.len("peers"); ++i) // foreach peer
00125     {
00126         wns::service::dll::UnicastAddress peerAddress(config.get<int32_t>("peers",i));
00127         MESSAGE_SINGLE(NORMAL, logger, "onWorldCreated(): getting timingScheduler of peer "<<A2N(peerAddress));
00128         dll::ILayer2* peer = layer2->getStationManager()->getStationByMAC(peerAddress);
00129 
00130         lte::timing::TimingScheduler* peerTimingScheduler = NULL;
00131 
00132     peerTimingScheduler =
00133       peer->
00134       getManagementService<lte::timing::TimingScheduler>(getTimerName());
00135 
00136         assure(peerTimingScheduler,"No valid peerTimingScheduler!");
00137         peerTimingSchedulers.insert(peerAddress, peerTimingScheduler);
00138     }
00139 }
00140 
00141 // SuperFrameStart; called by simulation event scheduler
00142 void
00143 TimingScheduler::periodically()
00144 {
00145     MESSAGE_SINGLE(NORMAL, logger, "========== Start of SuperFrame ==========");
00146     superFrameStartTime = es->getTime();
00147 
00148     // execution of the stored events
00149     for (unsigned int i = 0; i < eventContainer.size(); ++i)
00150     {
00151         lte::timing::events::Base* event = eventContainer.at(i).event;
00152         simTimeType timeOffset = eventContainer.at(i).timeOffset;
00153         simTimeType at = es->getTime() + timeOffset;
00154         es->schedule(boost::bind(&lte::timing::events::Base::operator(), event), at);
00155     }
00156 
00157     // tell all observers that new superframe starts now
00158     this->superFrameTrigger();
00159 } // periodically
00160 
00161 int
00162 TimingScheduler::getSchedulingOffset() const
00163 {
00164     return schedulingOffset;
00165 }
00166 
00167 int
00168 TimingScheduler::getNumberOfFramesToSchedule() const
00169 {
00170     return numberOfFramesToSchedule;
00171 }
00172 
00173 lte::timing::StationTask
00174 TimingScheduler::stationTaskAtFrame(int frameNr /* absolute compared to superFrame start */) const
00175 {
00176     StationTaskPhase taskPhase;
00177     taskPhase = stationTaskPhaseContainer.at( phaseNumberAtFrame(frameNr)/*absolute*/ );
00178     assure(taskPhase.task != StationTasks::INVALID(),"stationTaskAt called with an offset out of bounds");
00179     MESSAGE_SINGLE(VERBOSE, logger, "stationTaskAtFrame(frameNr="<<frameNr<<") = "<<StationTasks::toString(taskPhase.task));
00180     return taskPhase.task;
00181 }
00182 
00183 lte::timing::StationTask
00184 TimingScheduler::stationTaskAtOffset(const simTimeType offset/*relative*/) const /* offset compared to now */
00185 {
00186     assure(offset >= 0.0,"stationTaskAtOffset called with a negative offset"); // only into future
00187 
00188     StationTaskPhase taskPhase;
00189     taskPhase = stationTaskPhaseContainer.at( phaseNumberAtOffset(offset)/*relative*/ );
00190     assure(taskPhase.task != StationTasks::INVALID(),"stationTaskAtOffset called with an offset out of bounds");
00191     MESSAGE_SINGLE(VERBOSE, logger, "stationTaskAtOffset("<<offset<<") = "<<StationTasks::toString(taskPhase.task));
00192     return taskPhase.task;
00193 }
00194 
00195 uint32_t
00196 TimingScheduler::phaseNumberAtFrame(int frameNr /* absolute compared to superFrame start */) const
00197 {
00198     simTimeType offset = startOfFirstFrame + frameNr * frameLength;
00199     assure(stationTaskPhaseContainer.size()>0, "stationTaskPhaseContainer not ready");
00200 
00201     for (uint32_t index = 0; index < stationTaskPhaseContainer.size(); ++index)
00202     {
00203         StationTaskPhase taskPhase = stationTaskPhaseContainer.at(index);
00204         if (taskPhase.startTime + taskPhase.duration > offset)
00205         {
00206             MESSAGE_SINGLE(VERBOSE, logger, "phaseNumberAtFrame(frameNr="<<frameNr<<",offset=" << offset << "): taskPhase=" << index <<", task=" << lte::timing::StationTasks::toString(stationTaskPhaseContainer.at(index).task)<< "");
00207             return index;
00208         }
00209     }
00210     assure(false, "phaseNumberAtFrame("<<frameNr<<"): called with an offset out of bounds");
00211     return 0; // to please the compiler
00212 }
00213 
00214 uint32_t
00215 TimingScheduler::phaseNumberAtOffset(const simTimeType offset /* compared to now */) const
00216 {
00217     simTimeType now = es->getTime();
00218     simTimeType currentOffsetInSuperFrame = now - superFrameStartTime;
00219     simTimeType offsetInSuperFrame = currentOffsetInSuperFrame + offset;
00220     MESSAGE_SINGLE(VERBOSE, logger,  "phaseNumber("<<offset<<"=@"<<offsetInSuperFrame<<")");
00221     assure(stationTaskPhaseContainer.size()>0, "stationTaskPhaseContainer not ready");
00222 
00223     for (uint32_t index = 0; index < stationTaskPhaseContainer.size(); ++index)
00224     { // forall tasks
00225         StationTaskPhase taskPhase = stationTaskPhaseContainer.at(index);
00226         simTimeType endTime = taskPhase.startTime + taskPhase.duration;
00227         if (endTime > offsetInSuperFrame)
00228         { // found
00229             MESSAGE_SINGLE(VERBOSE, logger, "phaseNumberAtOffset(offset=" << offset << "): taskPhase=" << index <<", task=" << lte::timing::StationTasks::toString(stationTaskPhaseContainer.at(index).task)<< "");
00230             return index;
00231         }
00232     }
00233     assure(false, "phaseNumber("<<offset<<") called with an offset out of bounds");
00234     return 0; // to please the compiler
00235 }
00236 
00237 void
00238 TimingScheduler::addPeerTimingScheduler(wns::service::dll::UnicastAddress peerAddress, TimingScheduler* _timingScheduler)
00239 {
00240     peerTimingSchedulers.insert(peerAddress, _timingScheduler);
00241     MESSAGE_SINGLE(VERBOSE, logger, "Added peer Timing of "<<A2N(peerAddress));
00242 }
00243 
00244 void
00245 TimingScheduler::removePeerTimingScheduler(wns::service::dll::UnicastAddress peerAddress)
00246 {
00247     if (peerTimingSchedulers.knows(peerAddress))
00248     {
00249         peerTimingSchedulers.erase(peerAddress);
00250         MESSAGE_SINGLE(VERBOSE, logger, "Successfully removed peer Timing of "<<A2N(peerAddress));
00251     }
00252     else
00253     {
00254         MESSAGE_SINGLE(VERBOSE, logger, "Nothing to be done to remove peer Timing of "<<A2N(peerAddress));
00255     }
00256 }
00257 
00258 // Can a RN receive a map?
00259 bool
00260 TimingScheduler::canReceiveMapNow(const wns::service::dll::UnicastAddress& peerAddress)
00261 {   // the station is identified by its DLL Address
00262     assure(peerTimingSchedulers.knows(peerAddress), "No knowledge about requested Peer's ("<<peerAddress<<") timing!");
00263     bool reachable = (peerTimingSchedulers.find(peerAddress)->stationTaskAtOffset(0.0) == lte::timing::StationTasks::UT());
00264     MESSAGE_SINGLE(VERBOSE, logger, "canReceiveMapNow(user=" << A2N(peerAddress) << "): " << (reachable ? "Yes" : "No"));
00265     return reachable;
00266 }
00267 
00268 // to get info about inferior stations' availability
00269 bool
00270 TimingScheduler::isPeerListeningAt(const wns::service::dll::UnicastAddress& peerAddress, const int frameNr)
00271 {
00272     // the station is identified by its DLL Address
00273     assure(peerTimingSchedulers.knows(peerAddress), "No knowledge about requested Peer's ("<<peerAddress<<") timing!");
00274     MESSAGE_SINGLE(VERBOSE, logger, "isPeerListeningAt(User="<< A2N(peerAddress) <<",frameNr="<<frameNr<<") ?");
00275     bool isListening = (peerTimingSchedulers.find(peerAddress)->stationTaskAtFrame(frameNr/*absolute*/) == lte::timing::StationTasks::UT());
00276     MESSAGE_SINGLE(VERBOSE, logger, "isPeerListeningAt(User="<< A2N(peerAddress) <<",frameNr="<<frameNr<<"): "<< (isListening ? "Yes" : "No"));
00277     return isListening;
00278 }
00279 
00280 void
00281 TimingScheduler::readEvents(std::string viewName)
00282 {
00283     /* this is only called at the beginning of the simulation */
00284     // When it is called, this method assumes that readStationTaskPhases has
00285     // already been called
00286     for(int i = 0; i < config.len(viewName); ++i)
00287     {
00288         wns::pyconfig::View phaseConfig = config.get(viewName, i);
00289         std::string plugin = phaseConfig.get<std::string>("__plugin__");
00290         // a list of prototypes for events which are generated in pyconfig::Parser will be stored in an array
00291         TimingEvent e;
00292         e.event = NULL;
00293         e.timeOffset = phaseConfig.get<simTimeType>("time");
00294         // be sure that this is done only at now=superframe start time.
00295         // stationTaskAtOffset(offset is relative to now)
00296         if (this->stationTaskAtOffset(e.timeOffset) == StationTasks::RAP())
00297         {
00298             lte::timing::events::rap::EventCreator* c =
00299                 lte::timing::events::rap::EventFactory::creator(plugin);
00300             e.event = c->create(fun, phaseConfig);
00301         }
00302         else if (this->stationTaskAtOffset(e.timeOffset) == StationTasks::UT())
00303         {
00304             lte::timing::events::ut::EventCreator* c =
00305                 lte::timing::events::ut::EventFactory::creator(plugin);
00306             e.event = c->create(fun, phaseConfig);
00307         }
00308         else if (this->stationTaskAtOffset(e.timeOffset) == StationTasks::IDLE())
00309         {
00310             // do not create any events
00311         }
00312         else
00313             assure(false, "Unknown StationTask configured!");
00314 
00315         if (e.event!=NULL){
00316             e.event->setTimer(this);
00317             eventContainer.push_back( e );
00318         }
00319 
00320         MESSAGE_BEGIN(VERBOSE, logger, m, viewName);
00321         // print frame structure. For Winner i is from [0..24], 0=Preamble, +
00322         // 3*8 frames (MapTx, DataTx, DataRx)=BS_view, (MapRx, DataRx,
00323         // DataTx)=UTview
00324         simTimeType duration = phaseConfig.get<simTimeType>("duration");
00325         m << ": " << i << ", EvType=" << plugin << ", T=" << e.timeOffset << ", D=" << duration;
00326         MESSAGE_END();
00327     }
00328 } // TimingScheduler::readEvents()
00329 
00330 void
00331 TimingScheduler::initStationTaskPhases()
00332 {
00333     if (stationTaskPhaseContainer.size()==0) {
00334         // this is my own frame structure (sequence of Events for one superFrameLength)
00335         readStationTaskPhases("stationTaskPhases");
00336         // ^ structure needed in MapHandler::initSuperFrameMap()
00337     }
00338 }
00339 
00340 void
00341 TimingScheduler::readStationTaskPhases(std::string viewName)
00342 {
00343     if (stationTaskPhaseContainer.size()>0) {
00344         MESSAGE_SINGLE(NORMAL, logger, "readStationTaskPhases(): already processed ("<<stationTaskPhaseContainer.size()<<" elements)");
00345         return;
00346     }
00347     simTimeType durationSum = 0.0;
00348     // read in all stationTask items. There are (framesPerSuperFrame+1) elements.
00349     for(int i = 0; i < config.len(viewName); ++i)
00350     {
00351         wns::pyconfig::View phaseConfig = config.get(viewName, i);
00352         StationTaskPhase s;
00353         s.startTime = phaseConfig.get<simTimeType>("startTime");
00354         s.duration = phaseConfig.get<simTimeType>("duration");
00355         s.task = StationTasks::fromString(phaseConfig.get<std::string>("task"));
00356         stationTaskPhaseContainer.push_back( s );
00357         durationSum += s.duration;
00358         MESSAGE_BEGIN(NORMAL, logger, m, viewName);
00359         m << ": i=" << i << ", task=" << StationTasks::toString(s.task) << ", T=" << s.startTime << ", D=" << s.duration;
00360         MESSAGE_END();
00361     }
00362     MESSAGE_SINGLE(NORMAL, logger, "readStationTaskPhases(): "<<stationTaskPhaseContainer.size()<<" StationTaskPhases; duration = "<<durationSum);
00363     assure(fabs(durationSum - superFrameLength) < 1e-9 ,"StationTaskPhase durationSum="<<durationSum<<" does not match superFrameLength="<<superFrameLength);
00364     assure(stationTaskPhaseContainer.size()>0, "stationTaskPhaseContainer is empty");
00365 }
00366 
00367 void
00368 TimingScheduler::onDisassociated(wns::service::dll::UnicastAddress userAdr, wns::service::dll::UnicastAddress dstAdr)
00369 {
00370     //RAP task only, UT do nothing here
00371     if (layer2->getDLLAddress() == dstAdr)
00372     {
00373         removePeerTimingScheduler(userAdr);
00374         MESSAGE_SINGLE(NORMAL, logger, "Successfully removed Peer TimingScheduler for user=" << A2N(userAdr));
00375     }
00376 }
00377 
00378 void
00379 TimingScheduler::onAssociated(wns::service::dll::UnicastAddress userAdr, wns::service::dll::UnicastAddress dstAdr)
00380 {
00381     MESSAGE_SINGLE(NORMAL, logger, "TimingScheduler::onAssociated called (user=" << A2N(userAdr) << " dst=" << A2N(dstAdr) << ").");
00382     //RAP task only
00383     if (layer2->getDLLAddress() == dstAdr)
00384     {
00385         dll::ILayer2* newUser = layer2->getStationManager()->getStationByMAC(userAdr);
00386 
00387         TimingScheduler* userTimingScheduler = NULL;
00388 
00389     userTimingScheduler =
00390       newUser->
00391       getManagementService<lte::timing::TimingScheduler>(getTimerName());
00392 
00393         addPeerTimingScheduler(userAdr, userTimingScheduler);
00394         MESSAGE_SINGLE(NORMAL, logger, "Successfully added Peer TimingScheduler for user=" << A2N(userAdr));
00395     }
00396     else if (layer2->getDLLAddress() == userAdr)
00397     {
00398         // Notification in UT -> nothing to do
00399         MESSAGE_SINGLE(VERBOSE, logger, "Not adding Peer TimingScheduler for user with address " << A2N(userAdr) << " at Scheduler with Address " << A2N(userAdr));
00400     }
00401     else
00402     {
00403         // Notification in BS while association is with RN -> nothing to do
00404         MESSAGE_SINGLE(VERBOSE, logger, "Not adding Peer TimingScheduler for user with address " << A2N(userAdr) << " at Scheduler with Address " << A2N(layer2->getDLLAddress()));
00405     }
00406 }
00407 
00408 void
00409 TimingScheduler::superFrameTrigger()
00410 {
00411     this->wns::Subject<SuperFrameStartNotificationInterface>::sendNotifies(&SuperFrameStartNotificationInterface::onSuperFrameStart);
00415     try {
00416         lte::controlplane::bch::IBCHTimingTx* bch = NULL;
00417     bch = this->fun->findFriend<lte::controlplane::bch::IBCHTimingTx*>(mode+separator+"bch");
00418         if (bch != NULL)
00419         {
00420             bch->sendBCH(0.0005);
00421         }
00422 
00423     }
00424     catch (wns::ldk::fun::FindFriendException)
00425     {
00426     }
00427 }
00428 
00429 void
00430 TimingScheduler::frameTrigger()
00431 {
00432     this->wns::Subject<FrameStartNotificationInterface>::sendNotifies(&FrameStartNotificationInterface::onFrameStart);
00433 }
00434 
00435 
00436 
00437 
00438 
00439 

Generated on Sat May 26 03:32:03 2012 for openWNS by  doxygen 1.5.5