EMANE  1.2.1
eventscheduler.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015 - Adjacent Link LLC, Bridgewater, New Jersey
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * * Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * * Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in
13  * the documentation and/or other materials provided with the
14  * distribution.
15  * * Neither the name of Adjacent Link LLC nor the names of its
16  * contributors may be used to endorse or promote products derived
17  * from this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
25  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 #include "eventscheduler.h"
35 
37  PlatformServiceProvider * pPlatformServiceProvider,
38  SchedulerUser * pSchedulerUser):
39  Scheduler{id,pPlatformServiceProvider,pSchedulerUser},
40  bWaitingFirstTxSlotInfoRequest_{},
41  pNumScheduleRejectSlotIndexOutOfRange_{},
42  pNumScheduleRejectFrameIndexOutOfRange_{},
43  pNumScheduleRejectUpdateBeforeFull_{},
44  pNumScheduleRejectOther_{},
45  pNumScheduleFullAccept_{},
46  pNumScheduleUpdateAccept_{}
47 {}
48 
50 {}
51 
53 {
56  "MACI %03hu TDMA::EventScheduler::%s",
57  id_,
58  __func__);
59 
60  auto & statisticRegistrar = registrar.statisticRegistrar();
61 
62  eventTablePublisher_.registerStatistics(statisticRegistrar);
63 
64  pNumScheduleRejectSlotIndexOutOfRange_ =
65  statisticRegistrar.registerNumeric<std::uint64_t>("scheduler.scheduleRejectSlotIndexRange",
67  "Number of schedules rejected"
68  " due to out of range slot index.");
69 
70  pNumScheduleRejectFrameIndexOutOfRange_ =
71  statisticRegistrar.registerNumeric<std::uint64_t>("scheduler.scheduleRejectFrameIndexRange",
73  "Number of schedules rejected"
74  " due to out of range frame index.");
75 
76  pNumScheduleRejectUpdateBeforeFull_ =
77  statisticRegistrar.registerNumeric<std::uint64_t>("scheduler.scheduleRejectUpdateBeforeFull",
79  "Number of schedules rejected"
80  " due to an update before full schedule.");
81 
82  pNumScheduleRejectOther_ =
83  statisticRegistrar.registerNumeric<std::uint64_t>("scheduler.scheduleRejectOther",
85  "Number of schedules rejected"
86  " due to other reasons.");
87 
88  pNumScheduleFullAccept_ =
89  statisticRegistrar.registerNumeric<std::uint64_t>("scheduler.scheduleAcceptFull",
91  "Number of full schedules accepted.");
92 
93  pNumScheduleUpdateAccept_ =
94  statisticRegistrar.registerNumeric<std::uint64_t>("scheduler.scheduleAcceptUpdate",
96  "Number of update schedules accepted.");
97 
98  auto & eventRegistrar = registrar.eventRegistrar();
99 
101 }
102 
104 {
106  DEBUG_LEVEL,
107  "MACI %03hu TDMA::EventScheduler::%s",
108  id_,
109  __func__);
110 }
111 
113 {
115  DEBUG_LEVEL,
116  "MACI %03hu TDMA::EventScheduler::%s",
117  id_,
118  __func__);
119 }
120 
122 {
124  DEBUG_LEVEL,
125  "MACI %03hu TDMA::EventScheduler::%s",
126  id_,
127  __func__);
128 }
129 
131 {
133  DEBUG_LEVEL,
134  "MACI %03hu TDMA::EventScheduler::%s",
135  id_,
136  __func__);
137 }
138 
140 {
142  DEBUG_LEVEL,
143  "MACI %03hu TDMA::EventScheduler::%s",
144  id_,
145  __func__);
146 }
147 
149  const Serialization & serialization)
150 {
152  DEBUG_LEVEL,
153  "MACI %03hu TDMA::EventScheduler::%s",
154  id_,
155  __func__);
156 
158  {
159  try
160  {
161  Events::TDMAScheduleEvent event{serialization};
162  Events::SlotStructure structure{};
163  bool bHasStructure{};
164  bool bNotify{};
165 
166  std::tie(structure,bHasStructure) = event.getSlotStructure();
167 
168  if(bHasStructure)
169  {
171  DEBUG_LEVEL,
172  "MACI %03hu TDMA::EventScheduler::%s full"
173  " schdule received",
174  id_,
175  __func__);
176 
177  // clear out existing schedule
178  slotInfos_.clear();
179 
180  // store new structure info
181  structure_ = structure;
182 
183 
184  // clear frequencies
185  frequencies_.clear();
186 
187  // store new schedule
188  slotInfos_ = event.getSlotInfos();
189 
190  // will notify ScheduleUser of schedule
191  bNotify = true;
192  }
193  else if(slotInfos_.empty())
194  {
195  // no structure, this is an update but we never received a
196  // schdule to update
198  ERROR_LEVEL,
199  "MACI %03hu TDMA::EventScheduler::%s schedule"
200  " rejected update received before full schedule",
201  id_,
202  __func__);
203 
204  ++*pNumScheduleRejectUpdateBeforeFull_;
205  }
206  else
207  {
208  // process the update
209  auto framesPerMultiFrame = structure_.getFramesPerMultiFrame();
210  auto slotsPerFrame = structure_.getSlotsPerFrame();
211  const auto & slotInfos = event.getSlotInfos();
212 
213  std::vector<int> indexes{};
214  indexes.reserve(slotInfos.size());
215 
216  for(const auto & slotInfo : slotInfos)
217  {
218  if(slotInfo.getFrameIndex() < framesPerMultiFrame)
219  {
220  if(slotInfo.getSlotIndex() < slotsPerFrame)
221  {
222  indexes.push_back(slotInfo.getFrameIndex() *
223  slotsPerFrame +
224  slotInfo.getSlotIndex());
225  }
226  else
227  {
229  ERROR_LEVEL,
230  "MACI %03hu TDMA::EventScheduler::%s schedule"
231  " rejected update slot index %u out of range",
232  id_,
233  __func__,
234  slotInfo.getSlotIndex());
235 
236  ++*pNumScheduleRejectSlotIndexOutOfRange_;
237 
238  flushSchedule();
239 
240  break;
241  }
242  }
243  else
244  {
246  ERROR_LEVEL,
247  "MACI %03hu TDMA::EventScheduler::%s schedule"
248  " rejected update frame index %u out of range",
249  id_,
250  __func__,
251  slotInfo.getFrameIndex());
252 
253  ++*pNumScheduleRejectFrameIndexOutOfRange_;
254 
255  flushSchedule();
256 
257  break;
258  }
259  }
260 
261  // only update schedule if there are no errors
262  if(indexes.size() == slotInfos.size())
263  {
264  auto indexIter = indexes.begin();
265  auto slotInfoIter = slotInfos.begin();
266 
267  for(;indexIter != indexes.end(); ++indexIter, ++slotInfoIter)
268  {
269  slotInfos_[*indexIter] = *slotInfoIter;
270  }
271 
272  // will notify ScheduleUser of schedule update
273  bNotify = true;
274  }
275  }
276 
277  if(bNotify)
278  {
279  if(bHasStructure)
280  {
281  ++*pNumScheduleFullAccept_;
282 
283  eventTablePublisher_.replace(event.getSlotInfos(),structure_);
284  }
285  else
286  {
287  ++*pNumScheduleUpdateAccept_;
288 
289  eventTablePublisher_.update(event.getSlotInfos());
290  }
291 
292  bWaitingFirstTxSlotInfoRequest_ = true;
293 
294  slotter_.reset(structure_.getSlotDuration(),
295  structure_.getSlotsPerFrame(),
296  structure_.getFramesPerMultiFrame());
297 
298  const auto & eventFrequencies = event.getFrequencies();
299 
300  frequencies_.insert(eventFrequencies.begin(),
301  eventFrequencies.end());
302 
304  structure_.getBandwidth(),
305  structure_.getSlotDuration(),
306  structure_.getSlotOverhead());
307  }
308  }
309  catch(SerializationException & exp)
310  {
311  flushSchedule();
312 
314  ERROR_LEVEL,
315  "MACI %03hu TDMA::EventScheduler::%s schedule"
316  " rejected %s",
317  id_,
318  __func__,
319  exp.what());
320 
321  ++*pNumScheduleRejectOther_;
322  }
323 
324  }
325 }
326 
327 void EMANE::Models::TDMA::EventScheduler::flushSchedule()
328 {
329  // clear out existing schedule
330  slotInfos_.clear();
331 
332  // clear structure
333  structure_ = {};
334 
335  // clear frequencies
336  frequencies_.clear();
337 
338  // clear slot and structure stat tables
339  eventTablePublisher_.clear();
340 
341  // reset the slotter
342  slotter_.reset(Microseconds::zero(),0,0);
343 
344  // notify the schedule user of a change
345  pSchedulerUser_->notifyScheduleChange({},0,Microseconds::zero(),Microseconds::zero());
346 }
347 
349 EMANE::Models::TDMA::EventScheduler::getSlotInfo(std::uint64_t u64AbsoluteSlotIndex) const
350 {
351  // no schedule available
352  if(slotInfos_.empty())
353  {
354  return {0,0,0,0,EMANE::TimePoint::min(),SlotInfo::Type::IDLE};
355  }
356 
357  std::uint32_t u32RelativeSlotIndex{};
358  std::uint32_t u32RelativeFrameIndex{};
359 
360  std::tie(u32RelativeSlotIndex,
361  u32RelativeFrameIndex) =
362  slotter_.getRelativeIndex(u64AbsoluteSlotIndex);
363 
364  auto index = u32RelativeFrameIndex * structure_.getSlotsPerFrame() + u32RelativeSlotIndex;
365 
366  const auto & info = slotInfos_[index];
367 
368  return {u64AbsoluteSlotIndex,
369  index,
370  u32RelativeSlotIndex,
371  u32RelativeFrameIndex,
372  slotter_.getSlotTime(u64AbsoluteSlotIndex),
373  info.getType() == Events::SlotInfo::Type::RX ? SlotInfo::Type::RX :
374  info.getType() == Events::SlotInfo::Type::TX ?
376 }
377 
380 {
381  // no schedule available
382  if(slotInfos_.empty())
383  {
384  return {0,0,0,0,EMANE::TimePoint::min(),SlotInfo::Type::IDLE};
385  }
386 
387  std::uint64_t u64AbsoluteSlotIndex{};
388  std::uint64_t u64AbsoluteFrameIndex{};
389  std::uint64_t u64AbsoluteMultiFrameIndex{};
390 
391  std::tie(u64AbsoluteSlotIndex,
392  u64AbsoluteFrameIndex,
393  u64AbsoluteMultiFrameIndex) = slotter_.getAbsoluteIndex(timePoint);
394 
395  return getSlotInfo(u64AbsoluteSlotIndex);
396 }
397 
398 std::pair<EMANE::Models::TDMA::RxSlotInfo,bool>
400 {
402  DEBUG_LEVEL,
403  "MACI %03hu TDMA::EventScheduler::%s",
404  id_,
405  __func__);
406 
407  // no schedule available
408  if(slotInfos_.empty())
409  {
410  return {{0,0,0,0,EMANE::TimePoint::min(),0},false};
411  }
412 
413  std::uint64_t u64AbsoluteSlotIndex{};
414  std::uint64_t u64AbsoluteFrameIndex{};
415  std::uint64_t u64AbsoluteMultiFrameIndex{};
416 
417  std::tie(u64AbsoluteSlotIndex,
418  u64AbsoluteFrameIndex,
419  u64AbsoluteMultiFrameIndex) = slotter_.getAbsoluteIndex(timePoint);
420 
421  std::uint32_t u32RelativeSlotIndex{};
422  std::uint32_t u32RelativeFrameIndex{};
423 
424  std::tie(u32RelativeSlotIndex,
425  u32RelativeFrameIndex) =
426  slotter_.getRelativeIndex(u64AbsoluteSlotIndex);
427 
428  auto index = u32RelativeFrameIndex * structure_.getSlotsPerFrame() + u32RelativeSlotIndex;
429 
430 
431  const auto & info = slotInfos_[index];
432 
433  RxSlotInfo rxSlotInfo{u64AbsoluteSlotIndex,
434  index,
435  u32RelativeSlotIndex,
436  u32RelativeFrameIndex,
437  slotter_.getSlotTime(u64AbsoluteSlotIndex),
438  info.getFrequency()};
439 
440  return {rxSlotInfo,info.getType() == Events::SlotInfo::Type::RX};
441 }
442 
443 std::pair<EMANE::Models::TDMA::TxSlotInfos,EMANE::TimePoint>
445  int multiframes) const
446 {
447  // no scedule available
448  if(slotInfos_.empty())
449  {
450  return {{},EMANE::TimePoint::min()};
451  }
452 
453  TimePoint requestTime{timePoint};
454 
455  if(bWaitingFirstTxSlotInfoRequest_)
456  {
457  // first request since new schedule available
458  auto indexes = slotter_.getAbsoluteIndex(timePoint);
459 
460  requestTime = slotter_.getMultiFrameTime(std::get<2>(indexes) + 1);
461 
462  bWaitingFirstTxSlotInfoRequest_ = false;
463  }
464 
465  std::uint64_t u64AbsoluteSlotIndex{};
466  std::uint64_t u64AbsoluteFrameIndex{};
467  std::uint64_t u64AbsoluteMultiFrameIndex{};
468 
469  std::tie(u64AbsoluteSlotIndex,
470  u64AbsoluteFrameIndex,
471  u64AbsoluteMultiFrameIndex) = slotter_.getAbsoluteIndex(requestTime);
472 
473  std::uint32_t u32RelativeSlotIndex{};
474  std::uint32_t u32RelativeFrameIndex{};
475 
476  std::tie(u32RelativeSlotIndex,
477  u32RelativeFrameIndex) =
478  slotter_.getRelativeIndex(u64AbsoluteSlotIndex);
479 
480  auto index = u32RelativeFrameIndex * structure_.getSlotsPerFrame() + u32RelativeSlotIndex;
481 
482  TxSlotInfos txSlotInfos{};
483 
484  for(int i = 0; i < multiframes; ++i)
485  {
486  while(index < slotInfos_.size())
487  {
488  const auto & info = slotInfos_[index];
489 
490  if(info.getType() == Events::SlotInfo::Type::TX)
491  {
492  txSlotInfos.push_back({u64AbsoluteSlotIndex,
493  index,
494  info.getSlotIndex(),
495  info.getFrameIndex(),
496  slotter_.getSlotTime(u64AbsoluteSlotIndex),
497  info.getFrequency(),
498  info.getDataRate(),
499  info.getServiceClass(),
500  info.getPower(),
501  info.getDestination()});
502  }
503 
504  ++u64AbsoluteSlotIndex;
505  ++index;
506  }
507 
508  index = 0;
509  }
510 
511  return {txSlotInfos,slotter_.getMultiFrameTime(u64AbsoluteMultiFrameIndex + multiframes)};
512 }
513 
515  const PacketMetaInfo &)
516 {
518  DEBUG_LEVEL,
519  "MACI %03hu TDMA::EventScheduler::%s",
520  id_,
521  __func__);
522 }
523 
525 {
527  DEBUG_LEVEL,
528  "MACI %03hu TDMA::EventScheduler::%s",
529  id_,
530  __func__);
531 }
void configure(const ConfigurationUpdate &update) override
std::pair< TxSlotInfos, TimePoint > getTxSlotInfo(const TimePoint &timePoint, int multiframes) const override
std::string Serialization
Definition: serializable.h:42
A Packet class that allows upstream processing to strip layer headers as the packet travels up the st...
The Registrar interface provides access to all of the emulator registrars.
Definition: registrar.h:50
std::pair< RxSlotInfo, bool > getRxSlotInfo(const TimePoint &timePoint) const override
SlotInfo getSlotInfo(std::uint64_t u64AbsoluteSlotIndex) const override
SerializationException is thrown when an exception occurs during serialization or deserialization of ...
void processEvent(const EventId &eventId, const Serialization &serialization) override
TimePoint getMultiFrameTime(std::uint64_t u64MultiFrameIndex) const
Definition: slotter.inl:51
void processSchedulerPacket(UpstreamPacket &pkt, const PacketMetaInfo &packetMetaInfo) override
void replace(const Events::SlotInfos &slotInfos, const Events::SlotStructure &structure)
virtual StatisticRegistrar & statisticRegistrar()=0
std::uint32_t getFramesPerMultiFrame() const
void processPacketMetaInfo(const PacketMetaInfo &packetMetaInfo) override
void initialize(Registrar &registrar) override
std::tuple< std::uint32_t, std::uint32_t > getRelativeIndex(std::uint64_t u64SlotIndex) const
Definition: slotter.inl:91
std::uint16_t EventId
Definition: types.h:53
The PlatformServiceProvider interface provides access to emulator services.
virtual EventRegistrar & eventRegistrar()=0
EventScheduler(NEMId id, PlatformServiceProvider *pPlatformServiceProvider, SchedulerUser *pSchedulerUser)
const char * what() const
Definition: exception.h:62
Current slot information.
std::uint64_t getBandwidth() const
TimePoint getSlotTime(std::uint64_t u64SlotIndex) const
Definition: slotter.inl:68
Receive slot information.
void reset(const EMANE::Microseconds &slotSizeMicroseconds, std::uint64_t u32SlotsPerFrame, std::uint64_t u32FramesPerMultiFrame)
Definition: slotter.inl:40
std::uint32_t getSlotsPerFrame() const
std::uint16_t NEMId
Definition: types.h:52
Received over-the-air message information.
PlatformServiceProvider * pPlatformService_
Interface used by a scheduler module to communicate information with BaseModel.
Definition: scheduleruser.h:52
Scheduler interface used by BaseModel to communicate with a scheduler module.
Definition: scheduler.h:56
const Microseconds & getSlotOverhead() const
virtual void notifyScheduleChange(const Frequencies &frequencies, std::uint64_t u64BandwidthHz, const Microseconds &slotDuration, const Microseconds &slotOverhead)=0
virtual LogServiceProvider & logService()=0
std::vector< ConfigurationNameAnyValues > ConfigurationUpdate
virtual void registerEvent(EventId eventId)=0
std::tuple< std::uint64_t, std::uint64_t, std::uint64_t > getAbsoluteIndex(const EMANE::TimePoint &timePoint) const
Definition: slotter.inl:76
Clock::time_point TimePoint
Definition: types.h:50
std::list< TxSlotInfo > TxSlotInfos
#define LOGGER_STANDARD_LOGGING(logger, level, fmt, args...)
SchedulerUser * pSchedulerUser_
Definition: scheduler.h:139
const Microseconds & getSlotDuration() const