EMANE  1.2.1
models/shim/phyapitest/shimlayer.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2013-2014 - Adjacent Link LLC, Bridgewater, New Jersey
3  * Copyright (c) 2012 - DRS CenGen, LLC, Columbia, Maryland
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * * Redistributions of source code must retain the above copyright
11  * notice, this list of conditions and the following disclaimer.
12  * * Redistributions in binary form must reproduce the above copyright
13  * notice, this list of conditions and the following disclaimer in
14  * the documentation and/or other materials provided with the
15  * distribution.
16  * * Neither the name of DRS CenGen, LLC nor the names of its
17  * contributors may be used to endorse or promote products derived
18  * from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31  * POSSIBILITY OF SUCH DAMAGE.
32  *
33  * [DRS CenGen LLC] hereby grants to the U.S. Government a copyright license
34  * to use [the original] computer software/computer software documentation
35  * that is of the same scope as the rights set forth in the definition of
36  * "unlimited rights" found in DFARS 252.227-7014(a)(15)(June 1995).
37  */
38 
39 #include "shimlayer.h"
40 
44 
47 
49 #include "emane/utils/netutils.h"
50 
52 
53 namespace
54 {
55  const char * pzLayerName = "PHYAPITest::ShimLayer";
56 
57  static std::uint8_t PAYLOAD_BUFFER[0xffff] = {0xBE};
58 }
59 
61  PlatformServiceProvider * pPlatformService,
62  RadioServiceProvider * pRadioService):
63  ShimLayerImplementor{id,pPlatformService,pRadioService},
64  u16PacketSize_{},
65  txInterval_{},
66  txTimedEventId_{},
68  antennaProfileId_{},
69  dAntennaAzimuthDegrees_{},
70  dAntennaElevationDegrees_{},
71  fTxPowerdBm_{}
72 {}
73 
74 
76 {}
77 
78 
80 {
83  "SHIMI %03d %s::%s",
84  id_,
85  pzLayerName,
86  __func__);
87 
88  auto & configRegistrar = registrar.configurationRegistrar();
89 
90  configRegistrar.registerNumeric<std::uint16_t>("packetsize",
92  {128},
93  "Packet size in bytes.");
94 
95 
96  configRegistrar.registerNumeric<float>("packetrate",
98  {1},
99  "Defines the transmit rate in packets per second.");
100 
101  configRegistrar.registerNumeric<std::uint16_t>("destination",
104  "Defines the destination NEM Id.",
105  1);
106 
107  configRegistrar.registerNumeric<std::uint64_t>("bandwidth",
109  {},
110  "Defines the transmitter bandwidth in Hz.",
111  1);
112 
113  configRegistrar.registerNumeric<std::uint16_t>("antennaprofileid",
115  {},
116  "Defines the antenna profile id. The antenna profile id is"
117  " used to identify the appropriate antenna pattern and"
118  " blockage pattern to use when calculating the receive"
119  " power for each packet.");
120 
121  configRegistrar.registerNumeric<double>("antennaazimuth",
123  {},
124  "Defines the antenna azimuth pointing angle in degrees.",
125  0,
126  360);
127 
128  configRegistrar.registerNumeric<double>("antennaelevation",
130  {},
131  "Defines the antenna elevation pointing angle in degrees.",
132  -90,
133  90);
134 
135 
136  configRegistrar.registerNonNumeric<std::string>("frequency",
138  {},
139  "Defines a list of transmit frquency segments with each item"
140  " containing the following 3 elements: 1) frequency (center"
141  " frequency Hz), 2) duration (semgent duraton in usec), and 3)"
142  " offset (transmit offset from TxTime in usec)."
143  " <Frequency>:<Duration>:<Offset>",
144  0,
145  255,
146  "^\\d+(\\.\\d+)?[GMK]?:\\d+(\\.\\d+)?:\\d+(\\.\\d+)?$");
147 
148  configRegistrar.registerNumeric<float>("txpower",
150  {0},
151  "Defines the transmit power in dBm.");
152 
153  configRegistrar.registerNonNumeric<std::string>("transmitter",
155  {},
156  "Defines a list of additional collaborative transmitters to be"
157  " included. Each item in the list will include NEM ID and"
158  " transmit power in dBm. <NEM Id>:<Tx Power>.",
159  0,
160  255,
161  "^\\d+:\\d+(\\.\\d+)?$");
162 
163 
164 }
165 
166 
168 {
170  DEBUG_LEVEL,
171  "SHIMI %03d %s::%s",
172  id_,
173  pzLayerName,
174  __func__);
175 
176  for(const auto & item : update)
177  {
178  if(item.first == "packetsize")
179  {
180  u16PacketSize_ = item.second[0].asUINT16();
181 
183  INFO_LEVEL,
184  "SHIMI %03d %s::%s %s = %hu bytes",
185  id_,
186  pzLayerName,
187  __func__,
188  item.first.c_str(),
189  u16PacketSize_);
190  }
191  else if(item.first == "packetrate")
192  {
193  float fPacketRate = item.second[0].asFloat();
194 
196  INFO_LEVEL,
197  "SHIMI %03d %s::%s %s = %3.2f pps",
198  id_,
199  pzLayerName,
200  __func__,
201  item.first.c_str(),
202  fPacketRate);
203 
204  if(fPacketRate > 0.0)
205  {
206  // set the pkt interval
207  txInterval_ = DoubleSeconds{1.0 / fPacketRate};
208  }
209  }
210  else if(item.first == "destination")
211  {
212  dst_ = item.second[0].asUINT16();
213 
215  INFO_LEVEL,
216  "SHIMI %03d %s::%s %s = %hu",
217  id_,
218  pzLayerName,
219  __func__,
220  item.first.c_str(),
221  dst_);
222  }
223  else if(item.first == "bandwidth")
224  {
225  u64BandwidthHz_ = item.second[0].asUINT64();
226 
228  INFO_LEVEL,
229  "SHIMI %03d %s::%s %s = %ju",
230  id_,
231  pzLayerName,
232  __func__,
233  item.first.c_str(),
234  u64BandwidthHz_);
235  }
236  else if(item.first == "antennaprofileid")
237  {
238  antennaProfileId_ = item.second[0].asUINT16();
239 
241  INFO_LEVEL,
242  "SHIMI %03d %s::%s %s = %hu",
243  id_,
244  pzLayerName,
245  __func__,
246  item.first.c_str(),
247  antennaProfileId_);
248  }
249  else if(item.first == "antennaazimuth")
250  {
251  dAntennaAzimuthDegrees_ = item.second[0].asDouble();
252 
254  INFO_LEVEL,
255  "SHIMI %03d %s::%s %s = %lf deg",
256  id_,
257  pzLayerName,
258  __func__,
259  item.first.c_str(),
260  dAntennaAzimuthDegrees_);
261  }
262  else if(item.first == "antennaelevation")
263  {
264  dAntennaElevationDegrees_ = item.second[0].asDouble();
265 
267  INFO_LEVEL,
268  "SHIMI %03d %s::%s %s = %lf deg",
269  id_,
270  pzLayerName,
271  __func__,
272  item.first.c_str(),
273  dAntennaElevationDegrees_);
274  }
275  else if(item.first == "txpower")
276  {
277  fTxPowerdBm_ = item.second[0].asFloat();
278 
280  INFO_LEVEL,
281  "SHIMI %03d %s::%s %s = %f dBm",
282  id_,
283  pzLayerName,
284  __func__,
285  item.first.c_str(),
286  fTxPowerdBm_);
287  }
288  else if(item.first == "transmitter")
289  {
290  for(const auto & any : item.second)
291  {
292  std::string sValue = any.asString();
293 
294  // scan ctrl values
295  std::vector<std::string> tokens = Utils::getTokens(sValue, ":");
296 
297  // check num tokens nem:pwr
298  if(tokens.size() == 2)
299  {
300  std::uint16_t u16TxNEM = Utils::ParameterConvert(tokens[0]).toUINT16();
301  float fTxPower = Utils::ParameterConvert(tokens[1]).toFloat();
302 
304  INFO_LEVEL,
305  "SHIMI %03d %s::%s %s NEM = %hu, txpwr = %f dBm",
306  id_,
307  pzLayerName,
308  __func__,
309  item.first.c_str(),
310  u16TxNEM,
311  fTxPower);
312 
313  // add to the ati
314  transmitters_.push_back({u16TxNEM, fTxPower});
315  }
316  else
317  {
319  ERROR_LEVEL,
320  "SHIMI %03d %s::%s invalid format %s (%s), expected (NEM:txpwr)",
321  id_,
322  pzLayerName,
323  __func__,
324  item.first.c_str(),
325  sValue.c_str());
326 
327  throw makeException<ConfigurationException>("PHYAPITestShimLayer: Invalid format %s = %s",
328  item.first.c_str(),
329  sValue.c_str());
330  }
331  }
332  }
333  else if(item.first == "frequency")
334  {
335  for(const auto & any : item.second)
336  {
337  std::string sValue = any.asString();
338 
339  // scan ctrl values
340  std::vector<std::string> tokens = Utils::getTokens(sValue, ":");
341 
342  // check num tokens freq:duration:offset
343  if(tokens.size() == 3)
344  {
345  uint64_t u64TxFrequency{Utils::ParameterConvert(tokens[0]).toUINT64()};
346  DoubleSeconds duration{Utils::ParameterConvert(tokens[1]).toFloat()};
347  DoubleSeconds offset{Utils::ParameterConvert(tokens[2]).toFloat()};
348 
350  INFO_LEVEL,
351  "SHIMI %03d %s::%s %s freq %ju Hz, duration %lf, offset %lf",
352  id_,
353  pzLayerName,
354  __func__,
355  item.first.c_str(),
356  u64TxFrequency,
357  duration.count(),
358  offset.count());
359 
360  // add to the fi
361  frequencySegments_.push_back({u64TxFrequency,
362  std::chrono::duration_cast<Microseconds>(duration),
363  std::chrono::duration_cast<Microseconds>(offset)});
364  }
365  else
366  {
368  ERROR_LEVEL,
369  "SHIMI %03d %s::%s invalid format %s (%s), expected (freq:duration:offset)",
370  id_,
371  pzLayerName,
372  __func__,
373  item.first.c_str(),
374  sValue.c_str());
375 
376  throw makeException<ConfigurationException>("PHYAPITestShimLayer: Invalid format %s = %s",
377  item.first.c_str(),
378  sValue.c_str());
379  }
380  }
381  }
382  else
383  {
384  throw makeException<ConfigureException>("%s: Unexpected configuration item %s",
385  pzLayerName,
386  item.first.c_str());
387 
388  }
389  }
390 }
391 
392 
394 {
396  DEBUG_LEVEL,
397  "SHIMI %03d %s::%s",
398  id_,
399  pzLayerName,
400  __func__);
401 }
402 
403 
405 {
407  DEBUG_LEVEL,
408  "SHIMI %03d %s::%s",
409  id_,
410  pzLayerName,
411  __func__);
412 
413  if(txTimedEventId_ != 0)
414  {
415  pPlatformService_->timerService().cancelTimedEvent(txTimedEventId_);
416 
417  txTimedEventId_ = 0;
418  }
419 }
420 
421 
422 
424 {
426  DEBUG_LEVEL,
427  "SHIMI %03d %s::%s",
428  id_,
429  pzLayerName,
430  __func__);
431 
432  if(txInterval_ > DoubleSeconds::zero())
433  {
434  // schedule the event id, pkt data, timeout (absolute time), interval time
435  txTimedEventId_ =
437  scheduleTimedEvent(Clock::now() + std::chrono::duration_cast<Microseconds>(txInterval_),
438  nullptr,
439  std::chrono::duration_cast<Microseconds>(txInterval_));
440  }
441 }
442 
443 
444 
446  throw()
447 {
449  DEBUG_LEVEL,
450  "SHIMI %03d %s::%s",
451  id_,
452  pzLayerName,
453  __func__);
454 }
455 
456 
457 
459 {
461  DEBUG_LEVEL,
462  "SHIMI %03d %s::%s, unexpected control message, drop",
463  id_,
464  pzLayerName,
465  __func__);
466 }
467 
468 
469 
471 {
473  DEBUG_LEVEL,
474  "SHIMI %03d %s::%s, unexpected control message, drop",
475  id_,
476  pzLayerName,
477  __func__);
478 }
479 
480 
481 
483  const ControlMessages & msgs)
484 {
485  // get pkt info
486  const PacketInfo & pktInfo = pkt.getPacketInfo();
487 
489  DEBUG_LEVEL,
490  "SHIMI %03d %s::%s src %hu dst %hu size %zu controls %zu",
491  id_,
492  pzLayerName,
493  __func__,
494  pktInfo.getSource(),
495  pktInfo.getDestination(),
496  pkt.length(),
497  msgs.size());
498 
499  for(const auto & pControlMessage : msgs)
500  {
501  switch(pControlMessage->getId())
502  {
504  {
505  const auto pFrequencyControlMessage =
506  static_cast<const Controls::FrequencyControlMessage *>(pControlMessage);
507 
509  DEBUG_LEVEL,
510  Controls::FrequencyControlMessageFormatter{pFrequencyControlMessage},
511  "SHIMI %03d %s::%s Frequency Control Message",
512  id_,
513  pzLayerName,
514  __func__);
515 
516  }
517 
518  break;
519 
521  {
522  const auto pReceivePropertiesControlMessage =
523  static_cast<const Controls::ReceivePropertiesControlMessage *>(pControlMessage);
524 
526  DEBUG_LEVEL,
527  Controls::ReceivePropertiesControlMessageFormatter{pReceivePropertiesControlMessage},
528  "SHIMI %03d %s::%s Receive Properties Control Message",
529  id_,
530  pzLayerName,
531  __func__);
532 
533  }
534 
535  break;
536 
537  default:
539  ERROR_LEVEL,
540  "SHIMI %03d %s::%s Unknown control message id %hu",
541  id_,
542  pzLayerName,
543  __func__,
544  pControlMessage->getId());
545  break;
546  }
547  }
548 }
549 
550 
551 
553 {
555  DEBUG_LEVEL,
556  "SHIMI %03d %s::%s, unexpected packet, drop",
557  id_,
558  pzLayerName,
559  __func__);
560 }
561 
562 
563 
565  const TimePoint &,
566  const TimePoint &,
567  const TimePoint &,
568  const void *)
569 {
572  // the pkt
573  DownstreamPacket pkt{PacketInfo{id_, dst_, 0, Clock::now()}, PAYLOAD_BUFFER, u16PacketSize_};
574 
577  frequencySegments_)};
578 
579  if(antennaProfileId_)
580  {
581  msgs.push_back(Controls::AntennaProfileControlMessage::create(antennaProfileId_,
582  dAntennaAzimuthDegrees_,
583  dAntennaElevationDegrees_));
584  }
585 
586 
587  // send pkt to phy
588  sendDownstreamPacket(pkt, msgs);
589 
591 }
592 
593 
594 
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
static AntennaProfileControlMessage * create(AntennaProfileId id, double dAntennaAzimuthDegrees, double dAntennaElevationDegrees)
virtual ConfigurationRegistrar & configurationRegistrar()=0
std::vector< std::string > getTokens(const std::string &sInput, const char *pzDelimeter)
Definition: netutils.h:881
#define LOGGER_VERBOSE_LOGGING(logger, level, fmt, args...)
Recieve Properties Control Message is sent from the emulator physical layer with every upstream packe...
static TransmitterControlMessage * create(const Transmitters &transmitters)
std::uint16_t toUINT16(std::uint16_t u16Min=std::numeric_limits< std::uint16_t >::min(), std::uint16_t u16Max=std::numeric_limits< std::uint16_t >::max()) const
std::list< const ControlMessage * > ControlMessages
NEMId getSource() const
Definition: packetinfo.inl:64
void processUpstreamPacket(UpstreamPacket &pkt, const ControlMessages &msgs) override
float toFloat(float fMin=std::numeric_limits< float >::lowest(), float fMax=std::numeric_limits< float >::max()) const
void processUpstreamControl(const ControlMessages &msgs) override
NEMId getDestination() const
Definition: packetinfo.inl:70
constexpr NEMId NEM_BROADCAST_MAC_ADDRESS
Definition: types.h:69
std::uint64_t toUINT64(std::uint64_t u64Min=std::numeric_limits< std::uint64_t >::min(), std::uint64_t u64Max=std::numeric_limits< std::uint64_t >::max()) const
The PlatformServiceProvider interface provides access to emulator services.
Store source, destination, creation time and priority information for a packet.
Definition: packetinfo.h:50
static FrequencyControlMessage * create(std::uint64_t u64BandwidthHz, const FrequencySegments &frequencySegments)
void processTimedEvent(TimerEventId eventId, const TimePoint &expireTime, const TimePoint &scheduleTime, const TimePoint &fireTime, const void *arg) override
Interface used to create a Shim layer plugin implementation.
Definition: shimlayerimpl.h:47
The Frequency Control Message is sent to the emulator physical layer to specify the frequency segment...
void initialize(Registrar &registrar) override
const PacketInfo & getPacketInfo() const
Specialized packet the allows downstream processing to add layer specific headers as the packet trave...
std::chrono::microseconds Microseconds
Definition: types.h:45
void processDownstreamPacket(DownstreamPacket &pkt, const ControlMessages &msgs) override
std::chrono::duration< double > DoubleSeconds
Definition: types.h:47
std::uint16_t NEMId
Definition: types.h:52
Callable formatter object for ReceivePropertiesControlMessage instances.
DECLARE_SHIM_LAYER(EMANE::Models::PHYAPITest::ShimLayer)
void processDownstreamControl(const ControlMessages &msgs) override
PlatformServiceProvider * pPlatformService_
The RadioServiceProvider interface provides access to radio (RF) model specific services.
void configure(const ConfigurationUpdate &update) override
virtual LogServiceProvider & logService()=0
Callable formatter object for FrequencyControlMessage instances.
std::vector< ConfigurationNameAnyValues > ConfigurationUpdate
std::size_t TimerEventId
Definition: types.h:54
void registerNumeric(const std::string &sName, const ConfigurationProperties &properties=ConfigurationProperties::NONE, const std::initializer_list< T > &values={}, const std::string &sUsage="", T minValue=std::numeric_limits< T >::lowest(), T maxValue=std::numeric_limits< T >::max(), std::size_t minOccurs=1, std::size_t maxOccurs=1, const std::string &sRegexPattern={})
Clock::time_point TimePoint
Definition: types.h:50
virtual bool cancelTimedEvent(TimerEventId eventId)=0
#define LOGGER_STANDARD_LOGGING(logger, level, fmt, args...)
#define LOGGER_STANDARD_LOGGING_FN_VARGS(logger, level, fn, fmt, args...)
shim layer used to test the universal phy send/recv api
void sendDownstreamPacket(DownstreamPacket &pkt, const ControlMessages &msgs=empty)
Parameter conversion class with range checks.
ShimLayer(NEMId id, PlatformServiceProvider *pPlatformService, RadioServiceProvider *pRadioService)
virtual TimerServiceProvider & timerService()=0