lorawan-mac-end-device.cc
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2017 University of Padova
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation;
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17  *
18  * Author: Davide Magrin <magrinda@dei.unipd.it>
19  * Martina Capuzzo <capuzzom@dei.unipd.it>
20  *
21  * Modified by: Peggy Anderson <peggy.anderson@usask.ca>
22  * Bastien Tauran <bastien.tauran@viveris.fr>
23  */
24 
25 #include "lorawan-mac-end-device.h"
26 
27 #include "lora-tag.h"
29 #include "satellite-id-mapper.h"
30 #include "satellite-phy.h"
31 #include "satellite-time-tag.h"
32 #include "satellite-topology.h"
33 
34 #include <ns3/ipv4-header.h>
35 #include <ns3/log.h>
36 #include <ns3/simulator.h>
37 #include <ns3/singleton.h>
38 
39 #include <algorithm>
40 #include <cmath>
41 #include <list>
42 #include <vector>
43 
44 namespace ns3
45 {
46 
47 NS_LOG_COMPONENT_DEFINE("LorawanMacEndDevice");
48 
49 NS_OBJECT_ENSURE_REGISTERED(LorawanMacEndDevice);
50 
51 TypeId
53 {
54  static TypeId tid =
55  TypeId("ns3::LorawanMacEndDevice")
56  .SetParent<LorawanMac>()
57  .AddTraceSource("RequiredTransmissions",
58  "Total number of transmissions required to deliver this packet",
59  MakeTraceSourceAccessor(&LorawanMacEndDevice::m_requiredTxCallback),
60  "ns3::TracedValueCallback::uint8_t")
61  .AddAttribute("DataRate",
62  "Data Rate currently employed by this end device",
63  UintegerValue(0),
64  MakeUintegerAccessor(&LorawanMacEndDevice::m_dataRate),
65  MakeUintegerChecker<uint8_t>(0, 5))
66  .AddTraceSource("DataRate",
67  "Data Rate currently employed by this end device",
68  MakeTraceSourceAccessor(&LorawanMacEndDevice::m_dataRate),
69  "ns3::TracedValueCallback::uint8_t")
70  .AddAttribute("DRControl",
71  "Whether to request the NS to control this device's Data Rate",
72  BooleanValue(),
73  MakeBooleanAccessor(&LorawanMacEndDevice::m_controlDataRate),
74  MakeBooleanChecker())
75  .AddTraceSource("TxPower",
76  "Transmission power currently employed by this end device",
77  MakeTraceSourceAccessor(&LorawanMacEndDevice::m_txPower),
78  "ns3::TracedValueCallback::Double")
79  .AddTraceSource("LastKnownLinkMargin",
80  "Last known demodulation margin in "
81  "communications between this end device "
82  "and a gateway",
83  MakeTraceSourceAccessor(&LorawanMacEndDevice::m_lastKnownLinkMargin),
84  "ns3::TracedValueCallback::Double")
85  .AddTraceSource("LastKnownGatewayCount",
86  "Last known number of gateways able to "
87  "listen to this end device",
88  MakeTraceSourceAccessor(&LorawanMacEndDevice::m_lastKnownGatewayCount),
89  "ns3::TracedValueCallback::Int")
90  .AddTraceSource("AggregatedDutyCycle",
91  "Aggregate duty cycle, in fraction form, "
92  "this end device must respect",
93  MakeTraceSourceAccessor(&LorawanMacEndDevice::m_aggregatedDutyCycle),
94  "ns3::TracedValueCallback::Double")
95  .AddAttribute("MaxTransmissions",
96  "Maximum number of transmissions for a packet",
97  IntegerValue(8),
98  MakeIntegerAccessor(&LorawanMacEndDevice::m_maxNumbTx),
99  MakeIntegerChecker<uint8_t>())
100  .AddAttribute("EnableEDDataRateAdaptation",
101  "Whether the End Device should up its Data Rate "
102  "in case it doesn't get a reply from the NS.",
103  BooleanValue(false),
104  MakeBooleanAccessor(&LorawanMacEndDevice::m_enableDRAdapt),
105  MakeBooleanChecker())
106  .AddAttribute("MType",
107  "Specify type of message will be sent by this ED.",
109  MakeEnumAccessor<LorawanMacHeader::MType>(&LorawanMacEndDevice::m_mType),
111  "Unconfirmed",
113  "Confirmed"));
114  return tid;
115 }
116 
118 {
119  NS_FATAL_ERROR("Default constructor not in use");
120 }
121 
122 LorawanMacEndDevice::LorawanMacEndDevice(Ptr<Node> node, uint32_t satId, uint32_t beamId)
123  : LorawanMac(satId, beamId),
124  m_node(node),
125  m_enableDRAdapt(false),
126  m_maxNumbTx(8),
127  m_dataRate(0),
128  m_txPower(14),
129  m_codingRate(4.0 / 5),
130  // LoraWAN default
131  m_headerDisabled(0),
132  // LoraWAN default
133  m_address(LoraDeviceAddress(0)),
134  // LoraWAN default
135  m_receiveWindowDurationInSymbols(8),
136  m_gatewayUpdateCallback(),
137  m_isRegenerative(false),
138  // LoraWAN default
139  m_controlDataRate(false),
140  m_lastKnownLinkMargin(0),
141  m_lastKnownGatewayCount(0),
142  m_aggregatedDutyCycle(1),
143  m_mType(LorawanMacHeader::CONFIRMED_DATA_UP),
144  m_currentFCnt(0),
145  m_handoverCallback()
146 {
147  NS_LOG_FUNCTION(this);
148 
149  // Initialize the random variable we'll use to decide which channel to
150  // transmit on.
151  m_uniformRV = CreateObject<UniformRandomVariable>();
152 
153  // Void the transmission event
154  m_nextTx = EventId();
155  m_nextTx.Cancel();
156 
157  // Initialize structure for retransmission parameters
160 }
161 
163 {
164  NS_LOG_FUNCTION_NOARGS();
165 }
166 
168 // Sending methods //
170 
171 void
172 LorawanMacEndDevice::Send(Ptr<Packet> packet)
173 {
174  NS_LOG_FUNCTION(this << packet);
175 
176  // If it is not possible to transmit now because of the duty cycle,
177  // or because we are receiving, schedule a tx/retx later
178  Time nextTxDelay = GetNextTransmissionDelay();
179  if (nextTxDelay != Seconds(0))
180  {
181  postponeTransmission(nextTxDelay, packet);
182  return;
183  }
184 
185  // Pick a channel on which to transmit the packet
186  Ptr<LoraLogicalChannel> txChannel = GetChannelForTx();
187 
188  if (!(txChannel && m_retxParams.retxLeft > 0))
189  {
190  if (!txChannel)
191  {
192  NS_LOG_INFO("Cannot send because of duty cycle.");
194  }
195  else
196  {
197  NS_LOG_INFO("Max number of transmission achieved: packet not transmitted.");
198  }
199  }
200  else
201  // the transmitting channel is available and we have not run out the maximum number of
202  // retransmissions
203  {
204  // Make sure we can transmit at the current power on this channel
205  NS_ASSERT_MSG(m_txPower <= m_channelHelper.GetTxPowerForChannel(txChannel),
206  " The selected power is too hight to be supported by this channel.");
207  DoSend(packet);
208  }
209 }
210 
211 void
212 LorawanMacEndDevice::postponeTransmission(Time nextTxDelay, Ptr<Packet> packet)
213 {
214  NS_LOG_FUNCTION(this);
215  // Delete previously scheduled transmissions if any.
216  Simulator::Cancel(m_nextTx);
217  m_nextTx = Simulator::Schedule(nextTxDelay, &LorawanMacEndDevice::DoSend, this, packet);
218  NS_LOG_WARN("Attempting to send, but the aggregate duty cycle won't allow it. Scheduling a tx "
219  "at a delay "
220  << nextTxDelay.GetSeconds() << ".");
221 }
222 
223 void
224 LorawanMacEndDevice::DoSend(Ptr<Packet> packet)
225 {
226  NS_LOG_FUNCTION(this << packet);
227 
228  if (CheckHandovers())
229  {
230  // If handover, wait a short time that hadover has been made
231  Simulator::Schedule(MicroSeconds(1), &LorawanMacEndDevice::DoSend, this, packet);
232  return;
233  }
234 
235  // Checking if this is the transmission of a new packet
236  if (packet != m_retxParams.packet)
237  {
238  NS_LOG_DEBUG(
239  "Received a new packet from application. Resetting retransmission parameters.");
240  m_currentFCnt++;
241  NS_LOG_DEBUG("APP packet: " << packet << ".");
242 
243  // Check that MACPayload length is below the allowed maximum
244  if (packet->GetSize() > m_maxAppPayloadForDataRate.at(m_dataRate))
245  {
246  NS_LOG_WARN("Attempting to send a packet larger than the maximum allowed"
247  << " size at this DataRate (DR" << unsigned(m_dataRate)
248  << "). Transmission canceled. ");
249  return;
250  }
251 
252  // Add the Lora Frame Header to the packet
253  LoraFrameHeader frameHdr;
254  ApplyNecessaryOptions(frameHdr);
255  packet->AddHeader(frameHdr);
256  NS_LOG_INFO("Added frame header of size " << frameHdr.GetSerializedSize() << " bytes.");
257 
258  // Add the Lora Mac header to the packet
259  LorawanMacHeader macHdr;
260  ApplyNecessaryOptions(macHdr);
261  packet->AddHeader(macHdr);
262 
263  // Reset MAC command list
264  m_macCommandList.clear();
265 
267  {
268  // Call the callback to notify about the failure
269  uint8_t txs = m_maxNumbTx - (m_retxParams.retxLeft);
271  NS_LOG_DEBUG(" Received new packet from the application layer: stopping retransmission "
272  "procedure. Used "
273  << unsigned(txs) << " transmissions out of a maximum of "
274  << unsigned(m_maxNumbTx) << ".");
275  }
276 
277  // Reset retransmission parameters
279 
280  // If this is the first transmission of a confirmed packet, save parameters for the
281  // (possible) next retransmissions.
283  {
284  m_retxParams.packet = packet->Copy();
286  m_retxParams.waitingAck = true;
287  m_retxParams.firstAttempt = Simulator::Now();
289  m_retxParams.retxLeft - 1; // decreasing the number of retransmissions
290 
291  NS_LOG_DEBUG("Message type is " << m_mType);
292  NS_LOG_DEBUG("It is a confirmed packet. Setting retransmission parameters and "
293  "decreasing the number of transmissions left.");
294 
295  // Sent a new packet
296  NS_LOG_DEBUG("Copied packet: " << m_retxParams.packet);
298 
300  }
301  else
302  {
303  m_sentNewPacket(packet);
304  SendToPhy(packet);
305  }
306  }
307  // this is a retransmission
308  else
309  {
310  // Removing SatPhyTimeTag if it exists
311  SatPhyTimeTag satPhyTimeTag;
312  packet->RemovePacketTag(satPhyTimeTag);
313  SatPhyLinkTimeTag satPhyLinkTimeTag;
314  packet->RemovePacketTag(satPhyLinkTimeTag);
316  {
317  // Remove the headers
318  LorawanMacHeader macHdr;
319  LoraFrameHeader frameHdr;
320  packet->RemoveHeader(macHdr);
321  packet->RemoveHeader(frameHdr);
322 
323  // Add the Lora Frame Header to the packet
324  frameHdr = LoraFrameHeader();
325  ApplyNecessaryOptions(frameHdr);
326  packet->AddHeader(frameHdr);
327 
328  NS_LOG_INFO("Added frame header of size " << frameHdr.GetSerializedSize() << " bytes.");
329 
330  // Add the Lorawan Mac header to the packet
331  macHdr = LorawanMacHeader();
332  ApplyNecessaryOptions(macHdr);
333  packet->AddHeader(macHdr);
335  m_retxParams.retxLeft - 1; // decreasing the number of retransmissions
336  NS_LOG_DEBUG("Retransmitting an old packet.");
337 
339  }
340  }
341 }
342 
343 void
345 {
346 }
347 
349 // Receiving methods //
351 
352 void
354  Ptr<SatSignalParameters> /*rxParams*/)
355 {
356  Ptr<Packet> packet;
357  for (SatPhy::PacketContainer_t::iterator i = packets.begin(); i != packets.end(); i++)
358  {
359  Receive(*i);
360  }
361 }
362 
363 void
364 LorawanMacEndDevice::FailedReception(Ptr<const Packet> packet)
365 {
366 }
367 
368 void
370 {
371  NS_LOG_FUNCTION(this << frameHeader);
372 
374  {
375  if (frameHeader.GetAck())
376  {
377  NS_LOG_INFO("The message is an ACK, not waiting for it anymore.");
378 
379  NS_LOG_DEBUG("Reset retransmission variables to default values and cancel "
380  "retransmission if already scheduled.");
381 
382  uint8_t txs = m_maxNumbTx - (m_retxParams.retxLeft);
384  NS_LOG_DEBUG("Received ACK packet after "
385  << unsigned(txs) << " transmissions: stopping retransmission procedure. ");
386 
387  // Reset retransmission parameters
389  }
390  else
391  {
392  NS_LOG_ERROR(
393  "Received downlink message not containing an ACK while we were waiting for it!");
394  }
395  }
396 
397  std::list<Ptr<LorawanMacCommand>> commands = frameHeader.GetCommands();
398  std::list<Ptr<LorawanMacCommand>>::iterator it;
399  for (it = commands.begin(); it != commands.end(); it++)
400  {
401  NS_LOG_DEBUG("Iterating over the MAC commands...");
402  enum MacCommandType type = (*it)->GetCommandType();
403  switch (type)
404  {
405  case (LINK_CHECK_ANS): {
406  NS_LOG_DEBUG("Detected a LinkCheckAns command.");
407 
408  // Cast the command
409  Ptr<LinkCheckAns> linkCheckAns = (*it)->GetObject<LinkCheckAns>();
410 
411  // Call the appropriate function to take action
412  OnLinkCheckAns(linkCheckAns->GetMargin(), linkCheckAns->GetGwCnt());
413 
414  break;
415  }
416  case (LINK_ADR_REQ): {
417  NS_LOG_DEBUG("Detected a LinkAdrReq command.");
418 
419  // Cast the command
420  Ptr<LinkAdrReq> linkAdrReq = (*it)->GetObject<LinkAdrReq>();
421 
422  // Call the appropriate function to take action
423  OnLinkAdrReq(linkAdrReq->GetDataRate(),
424  linkAdrReq->GetTxPower(),
425  linkAdrReq->GetEnabledChannelsList(),
426  linkAdrReq->GetRepetitions());
427 
428  break;
429  }
430  case (DUTY_CYCLE_REQ): {
431  NS_LOG_DEBUG("Detected a DutyCycleReq command.");
432 
433  // Cast the command
434  Ptr<DutyCycleReq> dutyCycleReq = (*it)->GetObject<DutyCycleReq>();
435 
436  // Call the appropriate function to take action
437  OnDutyCycleReq(dutyCycleReq->GetMaximumAllowedDutyCycle());
438 
439  break;
440  }
441  case (RX_PARAM_SETUP_REQ): {
442  NS_LOG_DEBUG("Detected a RxParamSetupReq command.");
443 
444  // Cast the command
445  Ptr<RxParamSetupReq> rxParamSetupReq = (*it)->GetObject<RxParamSetupReq>();
446 
447  // Call the appropriate function to take action
448  OnRxParamSetupReq(rxParamSetupReq);
449 
450  break;
451  }
452  case (DEV_STATUS_REQ): {
453  NS_LOG_DEBUG("Detected a DevStatusReq command.");
454 
455  // Cast the command
456  Ptr<DevStatusReq> devStatusReq = (*it)->GetObject<DevStatusReq>();
457 
458  // Call the appropriate function to take action
459  OnDevStatusReq();
460 
461  break;
462  }
463  case (NEW_CHANNEL_REQ): {
464  NS_LOG_DEBUG("Detected a NewChannelReq command.");
465 
466  // Cast the command
467  Ptr<NewChannelReq> newChannelReq = (*it)->GetObject<NewChannelReq>();
468 
469  // Call the appropriate function to take action
470  OnNewChannelReq(newChannelReq->GetChannelIndex(),
471  newChannelReq->GetFrequency(),
472  newChannelReq->GetMinDataRate(),
473  newChannelReq->GetMaxDataRate());
474  break;
475  }
476  case (RX_TIMING_SETUP_REQ): {
477  break;
478  }
479  case (TX_PARAM_SETUP_REQ): {
480  break;
481  }
482  case (DL_CHANNEL_REQ): {
483  break;
484  }
485  default: {
486  NS_LOG_ERROR("CID not recognized");
487  break;
488  }
489  }
490  }
491 }
492 
493 void
495 {
496  NS_LOG_FUNCTION_NOARGS();
497 
498  frameHeader.SetAsUplink();
499  frameHeader.SetFPort(1); // TODO Use an appropriate frame port based on the application
500  frameHeader.SetAddress(m_address);
501  frameHeader.SetAdr(m_controlDataRate);
502  frameHeader.SetAdrAckReq(0); // TODO Set ADRACKREQ if a member variable is true
503 
504  // FPending does not exist in uplink messages
505  frameHeader.SetFCnt(m_currentFCnt);
506 
507  // Add listed MAC commands
508  for (const auto& command : m_macCommandList)
509  {
510  NS_LOG_INFO("Applying a MAC Command of CID " << unsigned(
511  LorawanMacCommand::GetCIDFromLorawanMacCommand(command->GetCommandType())));
512 
513  frameHeader.AddCommand(command);
514  }
515 }
516 
517 void
519 {
520  NS_LOG_FUNCTION_NOARGS();
521 
522  macHeader.SetMType(m_mType);
523  macHeader.SetMajor(1);
524 }
525 
526 void
528 {
529  m_mType = mType;
530  NS_LOG_DEBUG("Message type is set to " << mType);
531 }
532 
535 {
536  return m_mType;
537 }
538 
539 void
541 {
542 }
543 
544 bool
546 {
547  NS_LOG_FUNCTION(this);
548 
549  if (m_handoverModule != nullptr)
550  {
551  if (m_handoverModule->CheckForHandoverRecommendation(m_satId, m_beamId))
552  {
553  NS_LOG_INFO("Lora UT handover, old satellite is " << m_satId << ", old beam is "
554  << m_beamId);
555 
556  Ptr<SatBeamScheduler> srcScheduler = m_beamSchedulerCallback(m_satId, m_beamId);
557 
558  m_satId = m_handoverModule->GetAskedSatId();
559  m_beamId = m_handoverModule->GetAskedBeamId();
560 
561  NS_LOG_INFO("Lora UT handover, new satellite is " << m_satId << ", new beam is "
562  << m_beamId);
563 
564  Ptr<SatTopology> satTopology = Singleton<SatTopology>::Get();
565 
566  satTopology->UpdateUtSatAndBeam(m_node, m_satId, m_beamId);
567  Ptr<Node> gwNode = satTopology->GetGwFromBeam(m_beamId);
568  satTopology->UpdateGwConnectedToUt(m_node, gwNode);
569 
570  Address satAddress = m_beamSchedulerCallback(m_satId, m_beamId)->GetSatAddress();
571  Mac48Address satAddress48 = Mac48Address::ConvertFrom(satAddress);
572  if (satAddress48 != m_satelliteAddress)
573  {
574  SetSatelliteAddress(satAddress48);
575  }
576 
577  Mac48Address gwAddress =
578  Singleton<SatTopology>::Get()->GetGwAddressInUt(m_nodeInfo->GetNodeId());
579  if (gwAddress != m_gwAddress)
580  {
581  SetGwAddress(gwAddress);
582  m_routingUpdateCallback(m_nodeInfo->GetMacAddress(), gwAddress);
583  }
585 
586  Ptr<SatBeamScheduler> dstScheduler = m_beamSchedulerCallback(m_satId, m_beamId);
587  srcScheduler->DisconnectUt(m_nodeInfo->GetMacAddress());
588  dstScheduler->ConnectUt(m_nodeInfo->GetMacAddress());
589 
590  Ptr<SatIdMapper> satIdMapper = Singleton<SatIdMapper>::Get();
591  satIdMapper->UpdateMacToSatId(m_nodeInfo->GetMacAddress(), m_satId);
592  satIdMapper->UpdateMacToBeamId(m_nodeInfo->GetMacAddress(), m_beamId);
593  satTopology->UpdateUtSatAndBeam(m_node, m_satId, m_beamId);
595 
597  {
599  }
600 
601  return true;
602  }
603  }
604 
605  return false;
606 }
607 
608 void
609 LorawanMacEndDevice::ChangeBeam(uint32_t satId, uint32_t beamId)
610 {
611  NS_LOG_FUNCTION(this << satId << beamId);
612 }
613 
614 Time
616 {
617  NS_LOG_FUNCTION_NOARGS();
618  return waitingTime;
619 }
620 
621 Time
623 {
624  NS_LOG_FUNCTION_NOARGS();
625 
626  // Check duty cycle //
627 
628  // Pick a random channel to transmit on
629  std::vector<Ptr<LoraLogicalChannel>> logicalChannels;
630  logicalChannels =
631  m_channelHelper.GetEnabledChannelList(); // Use a separate list to do the shuffle
632  // logicalChannels = Shuffle (logicalChannels);
633 
634  Time waitingTime = Time::Max();
635 
636  // Try every channel
637  std::vector<Ptr<LoraLogicalChannel>>::iterator it;
638  for (it = logicalChannels.begin(); it != logicalChannels.end(); ++it)
639  {
640  // Pointer to the current channel
641  Ptr<LoraLogicalChannel> logicalChannel = *it;
642  double frequency = logicalChannel->GetFrequency();
643 
644  waitingTime = std::min(waitingTime, m_channelHelper.GetWaitingTime(logicalChannel));
645 
646  NS_LOG_DEBUG("Waiting time before the next transmission in channel with frequecy "
647  << frequency << " is = " << waitingTime.GetSeconds() << ".");
648  }
649 
650  waitingTime = GetNextClassTransmissionDelay(waitingTime);
651 
652  return waitingTime;
653 }
654 
655 Ptr<LoraLogicalChannel>
657 {
658  NS_LOG_FUNCTION_NOARGS();
659 
660  // Pick a random channel to transmit on
661  std::vector<Ptr<LoraLogicalChannel>> logicalChannels;
662  logicalChannels =
663  m_channelHelper.GetEnabledChannelList(); // Use a separate list to do the shuffle
664  logicalChannels = Shuffle(logicalChannels);
665 
666  // Try every channel
667  std::vector<Ptr<LoraLogicalChannel>>::iterator it;
668  for (it = logicalChannels.begin(); it != logicalChannels.end(); ++it)
669  {
670  // Pointer to the current channel
671  Ptr<LoraLogicalChannel> logicalChannel = *it;
672  double frequency = logicalChannel->GetFrequency();
673 
674  NS_LOG_DEBUG("Frequency of the current channel: " << frequency);
675 
676  // Verify that we can send the packet
677  Time waitingTime = m_channelHelper.GetWaitingTime(logicalChannel);
678 
679  NS_LOG_DEBUG("Waiting time for current channel = " << waitingTime.GetSeconds());
680 
681  // Send immediately if we can
682  if (waitingTime == Seconds(0))
683  {
684  return *it;
685  }
686  else
687  {
688  NS_LOG_DEBUG("Packet cannot be immediately transmitted on "
689  << "the current channel because of duty cycle limitations.");
690  }
691  }
692  return 0; // In this case, no suitable channel was found
693 }
694 
695 std::vector<Ptr<LoraLogicalChannel>>
696 LorawanMacEndDevice::Shuffle(std::vector<Ptr<LoraLogicalChannel>> vector)
697 {
698  NS_LOG_FUNCTION_NOARGS();
699 
700  int size = vector.size();
701 
702  for (int i = 0; i < size; ++i)
703  {
704  uint16_t random = std::floor(m_uniformRV->GetValue(0, size));
705  Ptr<LoraLogicalChannel> temp = vector.at(random);
706  vector.at(random) = vector.at(i);
707  vector.at(i) = temp;
708  }
709 
710  return vector;
711 }
712 
714 // Setters and Getters //
716 
717 void
719 {
720  m_retxParams.waitingAck = false;
722  m_retxParams.packet = 0;
723  m_retxParams.firstAttempt = Seconds(0);
724 
725  // Cancel next retransmissions, if any
726  Simulator::Cancel(m_nextTx);
727 }
728 
729 void
731 {
732  NS_LOG_FUNCTION(this << adapt);
733  m_enableDRAdapt = adapt;
734 }
735 
736 bool
738 {
739  return m_enableDRAdapt;
740 }
741 
742 void
744 {
745  NS_LOG_FUNCTION(this << unsigned(maxNumbTx));
746  m_maxNumbTx = maxNumbTx;
747  m_retxParams.retxLeft = maxNumbTx;
748 }
749 
750 uint8_t
752 {
753  NS_LOG_FUNCTION(this);
754  return m_maxNumbTx;
755 }
756 
757 void
759 {
760  NS_LOG_FUNCTION(this << unsigned(dataRate));
761 
762  m_dataRate = dataRate;
763 }
764 
765 uint8_t
767 {
768  NS_LOG_FUNCTION(this);
769 
770  return m_dataRate;
771 }
772 
773 void
775 {
776  NS_LOG_FUNCTION(this << address);
777 
778  m_address = address;
779 }
780 
783 {
784  NS_LOG_FUNCTION(this);
785 
786  return m_address;
787 }
788 
789 void
790 LorawanMacEndDevice::OnLinkCheckAns(uint8_t margin, uint8_t gwCnt)
791 {
792  NS_LOG_FUNCTION(this << unsigned(margin) << unsigned(gwCnt));
793 
794  m_lastKnownLinkMargin = margin;
795  m_lastKnownGatewayCount = gwCnt;
796 }
797 
798 void
800  uint8_t txPower,
801  std::list<int> enabledChannels,
802  int repetitions)
803 {
804  NS_LOG_FUNCTION(this << unsigned(dataRate) << unsigned(txPower) << repetitions);
805 
806  // Three bools for three requirements before setting things up
807  bool channelMaskOk = true;
808  bool dataRateOk = true;
809  bool txPowerOk = true;
810 
811  // Check the channel mask
813  // Check whether all specified channels exist on this device
814  auto channelList = m_channelHelper.GetChannelList();
815  int channelListSize = channelList.size();
816 
817  for (auto it = enabledChannels.begin(); it != enabledChannels.end(); it++)
818  {
819  if ((*it) > channelListSize)
820  {
821  channelMaskOk = false;
822  break;
823  }
824  }
825 
826  // Check the dataRate
828  // We need to know we can use it at all
829  // To assess this, we try and convert it to a SF/BW combination and check if
830  // those values are valid. Since GetSfFromDataRate and
831  // GetBandwidthFromDataRate return 0 if the dataRate is not recognized, we
832  // can check against this.
833  uint8_t sf = GetSfFromDataRate(dataRate);
834  double bw = GetBandwidthFromDataRate(dataRate);
835  NS_LOG_DEBUG("SF: " << unsigned(sf) << ", BW: " << bw);
836  if (sf == 0 || bw == 0)
837  {
838  dataRateOk = false;
839  NS_LOG_DEBUG("Data rate non valid");
840  }
841 
842  // We need to know we can use it in at least one of the enabled channels
843  // Cycle through available channels, stop when at least one is enabled for the
844  // specified dataRate.
845  if (dataRateOk && channelMaskOk) // If false, skip the check
846  {
847  bool foundAvailableChannel = false;
848  for (auto it = enabledChannels.begin(); it != enabledChannels.end(); it++)
849  {
850  NS_LOG_DEBUG("MinDR: " << unsigned(channelList.at(*it)->GetMinimumDataRate()));
851  NS_LOG_DEBUG("MaxDR: " << unsigned(channelList.at(*it)->GetMaximumDataRate()));
852  if (channelList.at(*it)->GetMinimumDataRate() <= dataRate &&
853  channelList.at(*it)->GetMaximumDataRate() >= dataRate)
854  {
855  foundAvailableChannel = true;
856  break;
857  }
858  }
859 
860  if (!foundAvailableChannel)
861  {
862  dataRateOk = false;
863  NS_LOG_DEBUG("Available channel not found");
864  }
865  }
866 
867  // Check the txPower
869  // Check whether we can use this transmission power
870  if (GetDbmForTxPower(txPower) == 0)
871  {
872  txPowerOk = false;
873  }
874 
875  NS_LOG_DEBUG("Finished checking. "
876  << "ChannelMaskOk: " << channelMaskOk << ", "
877  << "DataRateOk: " << dataRateOk << ", "
878  << "txPowerOk: " << txPowerOk);
879 
880  // If all checks are successful, set parameters up
882  if (channelMaskOk && dataRateOk && txPowerOk)
883  {
884  // Cycle over all channels in the list
885  for (uint32_t i = 0; i < m_channelHelper.GetChannelList().size(); i++)
886  {
887  if (std::find(enabledChannels.begin(), enabledChannels.end(), i) !=
888  enabledChannels.end())
889  {
890  m_channelHelper.GetChannelList().at(i)->SetEnabledForUplink();
891  NS_LOG_DEBUG("Channel " << i << " enabled");
892  }
893  else
894  {
895  m_channelHelper.GetChannelList().at(i)->DisableForUplink();
896  NS_LOG_DEBUG("Channel " << i << " disabled");
897  }
898  }
899 
900  // Set the data rate
901  m_dataRate = dataRate;
902 
903  // Set the transmission power
904  m_txPower = GetDbmForTxPower(txPower);
905  }
906 
907  // Craft a LinkAdrAns MAC command as a response
909  m_macCommandList.push_back(CreateObject<LinkAdrAns>(txPowerOk, dataRateOk, channelMaskOk));
910 }
911 
912 void
914 {
915  NS_LOG_FUNCTION(this << dutyCycle);
916 
917  // Make sure we get a value that makes sense
918  NS_ASSERT(0 <= dutyCycle && dutyCycle < 1);
919 
920  // Set the new duty cycle value
921  m_aggregatedDutyCycle = dutyCycle;
922 
923  // Craft a DutyCycleAns as response
924  NS_LOG_INFO("Adding DutyCycleAns reply");
925  m_macCommandList.push_back(CreateObject<DutyCycleAns>());
926 }
927 
928 void
929 LorawanMacEndDevice::OnRxClassParamSetupReq(Ptr<RxParamSetupReq> rxParamSetupReq)
930 {
931 }
932 
933 void
934 LorawanMacEndDevice::OnRxParamSetupReq(Ptr<RxParamSetupReq> rxParamSetupReq)
935 {
936  NS_LOG_FUNCTION(this << rxParamSetupReq);
937 
938  // static_cast<ClassALorawanMacEndDevice*>(this)->OnRxClassParamSetupReq (rxParamSetupReq);
939  OnRxClassParamSetupReq(rxParamSetupReq);
940 }
941 
942 void
944 {
945  NS_LOG_FUNCTION(this);
946 
947  uint8_t battery = 10; // XXX Fake battery level
948  uint8_t margin = 10; // XXX Fake margin
949 
950  // Craft a RxParamSetupAns as response
951  NS_LOG_INFO("Adding DevStatusAns reply");
952  m_macCommandList.push_back(CreateObject<DevStatusAns>(battery, margin));
953 }
954 
955 void
957  double frequency,
958  uint8_t minDataRate,
959  uint8_t maxDataRate)
960 {
961  NS_LOG_FUNCTION(this);
962 
963  bool dataRateRangeOk = true; // XXX Check whether the new data rate range is ok
964  bool channelFrequencyOk = true; // XXX Check whether the frequency is ok
965 
966  // TODO Return false if one of the checks above failed
967  // TODO Create new channel in the LoraLogicalChannelHelper
968 
969  SetLogicalChannel(chIndex, frequency, minDataRate, maxDataRate);
970 
971  NS_LOG_INFO("Adding NewChannelAns reply");
972  m_macCommandList.push_back(CreateObject<NewChannelAns>(dataRateRangeOk, channelFrequencyOk));
973 }
974 
975 void
977 {
978  NS_LOG_FUNCTION(this << frequency);
979 
980  m_channelHelper.AddChannel(frequency);
981 }
982 
983 void
984 LorawanMacEndDevice::AddLogicalChannel(Ptr<LoraLogicalChannel> logicalChannel)
985 {
986  NS_LOG_FUNCTION(this << logicalChannel);
987 
988  m_channelHelper.AddChannel(logicalChannel);
989 }
990 
991 void
993  double frequency,
994  uint8_t minDataRate,
995  uint8_t maxDataRate)
996 {
997  NS_LOG_FUNCTION(this << unsigned(chIndex) << frequency << unsigned(minDataRate)
998  << unsigned(maxDataRate));
999 
1001  chIndex,
1002  CreateObject<LoraLogicalChannel>(frequency, minDataRate, maxDataRate));
1003 }
1004 
1005 void
1007  double endFrequency,
1008  double dutyCycle,
1009  double maxTxPowerDbm)
1010 {
1011  NS_LOG_FUNCTION_NOARGS();
1012 
1013  m_channelHelper.AddLoraSubBand(startFrequency, endFrequency, dutyCycle, maxTxPowerDbm);
1014 }
1015 
1016 double
1018 {
1019  NS_LOG_FUNCTION_NOARGS();
1020 
1021  return m_aggregatedDutyCycle;
1022 }
1023 
1024 void
1025 LorawanMacEndDevice::AddLorawanMacCommand(Ptr<LorawanMacCommand> macCommand)
1026 {
1027  NS_LOG_FUNCTION(this << macCommand);
1028 
1029  m_macCommandList.push_back(macCommand);
1030 }
1031 
1032 uint8_t
1034 {
1035  return m_txPower;
1036 }
1037 
1038 void
1040 {
1041  NS_LOG_FUNCTION(this << &cb);
1043 }
1044 
1045 void
1047 {
1048  NS_LOG_FUNCTION(this << &cb);
1049  m_handoverCallback = cb;
1050 }
1051 
1052 void
1055 {
1056  NS_LOG_FUNCTION(this << &cb);
1058 }
1059 
1060 void
1061 LorawanMacEndDevice::SetGwAddress(Mac48Address gwAddress)
1062 {
1063  NS_LOG_FUNCTION(this << gwAddress);
1064 
1065  // m_gatewayUpdateCallback (gwAddress);
1066  m_gwAddress = gwAddress;
1067 }
1068 
1069 void
1070 LorawanMacEndDevice::SetSatAddress(Mac48Address satAddress)
1071 {
1072  NS_LOG_FUNCTION(this << satAddress);
1073 
1074  m_satelliteAddress = satAddress;
1075 }
1076 
1077 void
1079 {
1080  NS_LOG_FUNCTION(this << isRegenerative);
1081 
1082  m_isRegenerative = isRegenerative;
1083 }
1084 
1085 void
1087 {
1088  m_raChannel = raChannel;
1089 }
1090 
1091 void
1092 LorawanMacEndDevice::SetPhyRx(Ptr<SatLoraPhyRx> phyRx)
1093 {
1094  m_phyRx = phyRx;
1095 }
1096 
1097 Ptr<SatLoraPhyRx>
1099 {
1100  return m_phyRx;
1101 }
1102 
1103 } // namespace ns3
Implementation of the DevStatusReq LoRaWAN MAC command.
Implementation of the DutyCycleReq LoRaWAN MAC command.
This class represents the device address of a LoraWAN End Device.
This class represents the Frame header (FHDR) used in a LoraWAN network.
void SetAddress(LoraDeviceAddress address)
Set the address.
void SetAsUplink(void)
State that this is an uplink message.
void AddCommand(Ptr< LorawanMacCommand > macCommand)
Add a predefined command to the list.
void SetFCnt(uint16_t fCnt)
Set the FCnt value.
void SetAdrAckReq(bool adrAckReq)
Set the AdrAckReq value.
bool GetAck(void) const
Get the Ack bit value.
std::list< Ptr< LorawanMacCommand > > GetCommands(void)
Return a list of pointers to all the MAC commands saved in this header.
virtual uint32_t GetSerializedSize(void) const
Return the size required for serialization of this header.
void SetAdr(bool adr)
Set the Adr value.
void SetFPort(uint8_t fPort)
Set the FPort value.
Time GetWaitingTime(Ptr< LoraLogicalChannel > channel)
Get the time it is necessary to wait for before transmitting on a given channel.
void AddLoraSubBand(double firstFrequency, double lastFrequency, double dutyCycle, double maxTxPowerDbm)
Add a new LoraSubBand to this helper.
void SetChannel(uint8_t chIndex, Ptr< LoraLogicalChannel > logicalChannel)
Set a new channel at a fixed index.
void AddChannel(double frequency)
Add a new channel to the list.
std::vector< Ptr< LoraLogicalChannel > > GetChannelList(void)
Get the list of LoraLogicalChannels currently registered on this helper.
std::vector< Ptr< LoraLogicalChannel > > GetEnabledChannelList(void)
Get the list of LoraLogicalChannels currently registered on this helper that have been enabled for Up...
double GetTxPowerForChannel(Ptr< LoraLogicalChannel > logicalChannel)
Returns the maximum transmission power [dBm] that is allowed on a channel.
static uint8_t GetCIDFromLorawanMacCommand(enum MacCommandType commandType)
Get the CID that corresponds to this MAC command.
void SetDeviceAddress(LoraDeviceAddress address)
Set the network address of this device.
Time GetNextTransmissionDelay(void)
Find the minimum waiting time before the next possible transmission.
std::list< Ptr< LorawanMacCommand > > m_macCommandList
List of the MAC commands that need to be applied to the next UL packet.
uint8_t GetDataRate(void)
Get the data rate this end device is set to use.
void OnNewChannelReq(uint8_t chIndex, double frequency, uint8_t minDataRate, uint8_t maxDataRate)
Perform the actions that need to be taken when receiving a NewChannelReq command.
uint8_t GetMaxNumberOfTransmissions(void)
Set the maximum number of transmissions allowed.
bool m_enableDRAdapt
Enable Data Rate adaptation during the retransmission procedure.
EventId m_nextTx
The event of retransmitting a packet in a consecutive moment if an ACK is not received.
virtual void FailedReception(Ptr< const Packet > packet)
Function called by lower layers to inform this layer that reception of a packet we were locked on fai...
TracedValue< double > m_txPower
The transmission power this device is using to transmit.
TracedCallback< uint8_t, bool, Time, Ptr< Packet > > m_requiredTxCallback
The trace source fired when the transmission procedure is finished.
LorawanMacHeader::MType m_mType
The message type to apply to packets sent with the Send method.
void SetSatAddress(Mac48Address satAddress)
Set address of the Lorawan GW (or its MAC) serving this UT.
void OnLinkCheckAns(uint8_t margin, uint8_t gwCnt)
Perform the actions that need to be taken when receiving a LinkCheckAns command.
Callback< void, Mac48Address > GatewayUpdateCallback
Callback to update gateway address after handover.
void SetHandoverCallback(LorawanMacEndDevice::HandoverCallback cb)
Method to set handover callback.
Callback< void, uint32_t, uint32_t > HandoverCallback
Callback to reconfigure physical layer during handover.
LorawanMacHeader::MType GetMType(void)
Get the message type to send when the Send method is called.
virtual void DoSend(Ptr< Packet > packet)
Checking if we are performing the transmission of a new packet or a retransmission,...
void SetMType(LorawanMacHeader::MType mType)
Set the message type to send when the Send method is called.
bool GetDataRateAdaptation(void)
Get if data rate adaptation is enabled or not.
TracedValue< double > m_aggregatedDutyCycle
The aggregated duty cycle this device needs to respect across all sub-bands.
virtual void postponeTransmission(Time nextTxDelay, Ptr< Packet >)
Postpone transmission to the specified time and delete previously scheduled transmissions if present.
LorawanMacEndDevice::GatewayUpdateCallback m_gatewayUpdateCallback
Gateway address update callback.
void SetRegenerative(bool isRegenerative)
Set if associated satellite is regenerative.
void SetPhyRx(Ptr< SatLoraPhyRx > phyRx)
Ptr< LoraLogicalChannel > GetChannelForTx(void)
Find a suitable channel for transmission.
Ptr< SatLoraPhyRx > m_phyRx
Reception phy layer for Lora operations.
double GetAggregatedDutyCycle(void)
Set a value for the RX1DROffset parameter.
TracedValue< double > m_lastKnownLinkMargin
The last known link margin.
Mac48Address m_gwAddress
Gateway address used in case of transparent satellite.
uint8_t m_maxNumbTx
Maximum number of transmission allowed.
bool m_controlDataRate
Whether this device's data rate should be controlled by the NS.
uint32_t m_raChannel
RA channel assigned to the UT.
virtual void SendToPhy(Ptr< Packet > packet)
Add headers and send a packet with the sending function of the physical layer.
void SetUpdateAddressAndIdentifierCallback(LorawanMacEndDevice::UpdateAddressAndIdentifierCallback cb)
Set the callback to update addresses in statistics helpers.
void SetDataRateAdaptation(bool adapt)
Enable data rate adaptation in the retransmitting procedure.
void OnDevStatusReq(void)
Perform the actions that need to be taken when receiving a DevStatusReq command.
Ptr< UniformRandomVariable > m_uniformRV
An uniform random variable, used by the Shuffle method to randomly reorder the channel list.
virtual void Send(Ptr< Packet > packet)
Send a packet.
void SetDataRate(uint8_t dataRate)
Set the data rate this end device will use when transmitting.
void AddLogicalChannel(double frequency)
Add a logical channel to the helper.
Callback< void, Ptr< Node > > UpdateAddressAndIdentifierCallback
Callback to update addresses in statistics helpers.
void OnLinkAdrReq(uint8_t dataRate, uint8_t txPower, std::list< int > enabledChannels, int repetitions)
Perform the actions that need to be taken when receiving a LinkAdrReq command.
void AddLorawanMacCommand(Ptr< LorawanMacCommand > macCommand)
Add a MAC command to the list of those that will be sent out in the next packet.
void AddLoraSubBand(double startFrequency, double endFrequency, double dutyCycle, double maxTxPowerDbm)
Add a subband to the logical channel helper.
void SetLogicalChannel(uint8_t chIndex, double frequency, uint8_t minDataRate, uint8_t maxDataRate)
Set a new logical channel in the helper.
void ChangeBeam(uint32_t satId, uint32_t beamId)
Method handling beam handover.
Ptr< Node > m_node
Node containing this MAC.
void SetRaChannel(uint32_t raChannel)
Set RA channel assigned for this UT.
TracedValue< uint8_t > m_dataRate
The DataRate this device is using to transmit.
LoraDeviceAddress GetDeviceAddress(void)
Get the network address of this device.
TracedValue< int > m_lastKnownGatewayCount
The last known gateway count (i.e., gateways that are in communication range with this end device)
virtual void TxFinished()
Perform the actions that are required after a packet send.
void ParseCommands(LoraFrameHeader frameHeader)
Parse and take action on the commands contained on this FrameHeader.
bool CheckHandovers()
Check for UT handovers and perform it if necessary.
void SetGwAddress(Mac48Address gwAddress)
Set address of the GW (or its MAC) serving this UT.
std::vector< Ptr< LoraLogicalChannel > > Shuffle(std::vector< Ptr< LoraLogicalChannel >> vector)
Randomly shuffle a Ptr<LoraLogicalChannel> vector.
virtual void resetRetransmissionParameters()
Reset retransmission parameters contained in the structure LoraRetxParams.
virtual uint8_t GetTransmissionPower(void)
Get the transmission power this end device is set to use.
bool m_isRegenerative
Tell if satellite is regenerative.
void SetGatewayUpdateCallback(LorawanMacEndDevice::GatewayUpdateCallback cb)
Method to set the gateway address update callback.
LoraDeviceAddress m_address
The address of this device.
LorawanMacEndDevice::UpdateAddressAndIdentifierCallback m_updateAddressAndIdentifierCallback
Callback to update addresses in statistics helpers.
struct LoraRetxParameters m_retxParams
void ApplyNecessaryOptions(LoraFrameHeader &frameHeader)
Add the necessary options and MAC commands to the LoraFrameHeader.
virtual void Receive(Ptr< Packet > packet)=0
Receive a packet.
virtual void OnRxClassParamSetupReq(Ptr< RxParamSetupReq > rxParamSetupReq)
Perform the actions that need to be taken when receiving a RxParamSetupReq command based on the Devic...
virtual Time GetNextClassTransmissionDelay(Time waitingTime)
Find the minimum waiting time before the next possible transmission based on End Device's Class Type.
void OnDutyCycleReq(double dutyCycle)
Perform the actions that need to be taken when receiving a DutyCycleReq command.
void OnRxParamSetupReq(Ptr< RxParamSetupReq > rxParamSetupReq)
Perform the actions that need to be taken when receiving a RxParamSetupReq command.
LorawanMacEndDevice::HandoverCallback m_handoverCallback
The physical layer handover callback.
void SetMaxNumberOfTransmissions(uint8_t maxNumbTx)
Set the maximum number of transmissions allowed.
This class represents the Mac header of a LoRaWAN packet.
void SetMajor(uint8_t major)
Set the major version of this header.
MType
The message type.
void SetMType(enum MType mtype)
Set the message type.
Class representing the LoRaWAN MAC layer.
Definition: lorawan-mac.h:49
std::vector< uint32_t > m_maxAppPayloadForDataRate
A vector holding the maximum app payload size that corresponds to a certain DataRate.
Definition: lorawan-mac.h:307
uint32_t m_beamId
ID of beam for UT.
Definition: lorawan-mac.h:328
TracedCallback< Ptr< const Packet > > m_cannotSendBecauseDutyCycle
The trace source that is fired when a packet cannot be sent because of duty cycle limitations.
Definition: lorawan-mac.h:265
TracedCallback< Ptr< const Packet > > m_sentNewPacket
Trace source that is fired when a new APP layer packet arrives at the MAC layer.
Definition: lorawan-mac.h:276
uint8_t GetSfFromDataRate(uint8_t dataRate)
Get the SF corresponding to a data rate, based on this MAC's region.
Definition: lorawan-mac.cc:128
double GetDbmForTxPower(uint8_t txPower)
Get the transmission power in dBm that corresponds, in this region, to the encoded 8-bit txPower.
Definition: lorawan-mac.cc:156
LoraLogicalChannelHelper m_channelHelper
The LoraLogicalChannelHelper instance that is assigned to this MAC.
Definition: lorawan-mac.h:291
double GetBandwidthFromDataRate(uint8_t dataRate)
Get the BW corresponding to a data rate, based on this MAC's region.
Definition: lorawan-mac.cc:142
Implementation of the NewChannelReq LoRaWAN MAC command.
Implementation of the RxParamSetupReq LoRaWAN MAC command.
virtual void SetSatelliteAddress(Address satelliteAddress)
Set the satellite MAC address on the other side of this link (if regenerative satellite).
SatMac::BeamSchedulerCallback m_beamSchedulerCallback
Callback to get the SatBeamScheduler linked to a beam ID.
SatMac::RoutingUpdateCallback m_routingUpdateCallback
Callback to update routing and ARP tables after a beam handover.
Address m_satelliteAddress
MAC address of satellite on other side of the link.
Ptr< SatHandoverModule > m_handoverModule
Module used to perform handovers.
Ptr< SatNodeInfo > m_nodeInfo
Node info containing node related information, such as node type, node id and MAC address (of the Sat...
uint32_t m_satId
The ID of the sat where mac belongs.
SatMac::UpdateIslCallback m_updateIslCallback
The update ISL routes callback.
SatSignalParameters::PacketsInBurst_t PacketContainer_t
Define PacketContainer in SatPhy.
Definition: satellite-phy.h:79
Time tag used to identify the time when packet is enqueued at PHY on first link between GW and UT lev...
SatArqSequenceNumber is handling the sequence numbers for the ARQ process.
MacCommandType
Enum for every possible command type.
@ RX_TIMING_SETUP_REQ
@ RX_PARAM_SETUP_REQ
@ TX_PARAM_SETUP_REQ
Structure representing the parameters that will be used in the retransmission procedure.