A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
end-device-lorawan-mac.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2017 University of Padova
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation;
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 *
17 * Author: Davide Magrin <magrinda@dei.unipd.it>
18 * Martina Capuzzo <capuzzom@dei.unipd.it>
19 *
20 * Modified by: Peggy Anderson <peggy.anderson@usask.ca>
21 */
22
24
26#include "end-device-lora-phy.h"
27
28#include "ns3/log.h"
29#include "ns3/simulator.h"
30
31#include <algorithm>
32
33namespace ns3
34{
35namespace lorawan
36{
37
38NS_LOG_COMPONENT_DEFINE("EndDeviceLorawanMac");
39
40NS_OBJECT_ENSURE_REGISTERED(EndDeviceLorawanMac);
41
42TypeId
44{
45 static TypeId tid =
46 TypeId("ns3::EndDeviceLorawanMac")
48 .SetGroupName("lorawan")
49 .AddTraceSource("RequiredTransmissions",
50 "Total number of transmissions required to deliver this packet",
52 "ns3::TracedValueCallback::uint8_t")
53 .AddAttribute("DataRate",
54 "Data rate currently employed by this end device",
57 MakeUintegerChecker<uint8_t>(0, 5))
58 .AddTraceSource("DataRate",
59 "Data rate currently employed by this end device",
61 "ns3::TracedValueCallback::uint8_t")
62 .AddAttribute(
63 "DRControl",
64 "Whether to request the network server to control this device's data rate",
68 .AddTraceSource("TxPower",
69 "Transmission power currently employed by this end device",
71 "ns3::TracedValueCallback::Double")
72 .AddTraceSource("LastKnownLinkMargin",
73 "Last known demodulation margin in "
74 "communications between this end device "
75 "and a gateway",
77 "ns3::TracedValueCallback::Double")
78 .AddTraceSource("LastKnownGatewayCount",
79 "Last known number of gateways able to "
80 "listen to this end device",
82 "ns3::TracedValueCallback::Int")
83 .AddTraceSource("AggregatedDutyCycle",
84 "Aggregate duty cycle, in fraction form, "
85 "this end device must respect",
87 "ns3::TracedValueCallback::Double")
88 .AddAttribute("MaxTransmissions",
89 "Maximum number of transmissions for a packet",
90 IntegerValue(8),
92 MakeIntegerChecker<uint8_t>())
93 .AddAttribute("EnableEDDataRateAdaptation",
94 "Whether the end device should up its data rate "
95 "in case it doesn't get a reply from the network server.",
96 BooleanValue(false),
99 .AddAttribute("MType",
100 "Specify type of message will be sent by this end device.",
102 MakeEnumAccessor<LorawanMacHeader::MType>(&EndDeviceLorawanMac::m_mType),
104 "Unconfirmed",
106 "Confirmed"))
107 .AddConstructor<EndDeviceLorawanMac>();
108 return tid;
109}
110
112 : m_enableDRAdapt(false),
113 m_maxNumbTx(8),
114 m_dataRate(0),
115 m_txPower(14),
116 m_codingRate(1),
117 // LoraWAN default
118 m_headerDisabled(false),
119 // LoraWAN default
120 m_address(LoraDeviceAddress(0)),
121 // LoraWAN default
122 m_receiveWindowDurationInSymbols(8),
123 // LoraWAN default
124 m_controlDataRate(false),
125 m_lastKnownLinkMargin(0),
126 m_lastKnownGatewayCount(0),
127 m_aggregatedDutyCycle(1),
128 m_mType(LorawanMacHeader::CONFIRMED_DATA_UP),
129 m_currentFCnt(0)
130{
131 NS_LOG_FUNCTION(this);
132
133 // Initialize the random variable we'll use to decide which channel to
134 // transmit on.
135 m_uniformRV = CreateObject<UniformRandomVariable>();
136
137 // Void the transmission event
138 m_nextTx = EventId();
140
141 // Initialize structure for retransmission parameters
144}
145
147{
149}
150
151////////////////////////
152// Sending methods //
153////////////////////////
154
155void
157{
158 NS_LOG_FUNCTION(this << packet);
159
160 // If it is not possible to transmit now because of the duty cycle,
161 // or because we are receiving, schedule a tx/retx later
162
163 Time netxTxDelay = GetNextTransmissionDelay();
164 if (netxTxDelay != Seconds(0))
165 {
166 postponeTransmission(netxTxDelay, packet);
167 return;
168 }
169
170 // Pick a channel on which to transmit the packet
172
173 if (!(txChannel && m_retxParams.retxLeft > 0))
174 {
175 if (!txChannel)
176 {
178 }
179 else
180 {
181 NS_LOG_INFO("Max number of transmission achieved: packet not transmitted.");
182 }
183 }
184 else
185 // the transmitting channel is available and we have not run out the maximum number of
186 // retransmissions
187 {
188 // Make sure we can transmit at the current power on this channel
190 " The selected power is too high to be supported by this channel.");
191 DoSend(packet);
192 }
193}
194
195void
197{
198 NS_LOG_FUNCTION(this);
199 // Delete previously scheduled transmissions if any.
201 m_nextTx = Simulator::Schedule(netxTxDelay, &EndDeviceLorawanMac::DoSend, this, packet);
202 NS_LOG_WARN("Attempting to send, but the aggregate duty cycle won't allow it. Scheduling a tx "
203 "at a delay "
204 << netxTxDelay.GetSeconds() << ".");
205}
206
207void
209{
210 NS_LOG_FUNCTION(this);
211 // Checking if this is the transmission of a new packet
212 if (packet != m_retxParams.packet)
213 {
215 "Received a new packet from application. Resetting retransmission parameters.");
217 NS_LOG_DEBUG("APP packet: " << packet << ".");
218
219 // Add the Lora Frame Header to the packet
220 LoraFrameHeader frameHdr;
221 ApplyNecessaryOptions(frameHdr);
222 packet->AddHeader(frameHdr);
223
224 NS_LOG_INFO("Added frame header of size " << frameHdr.GetSerializedSize() << " bytes.");
225
226 // Check that MACPayload length is below the allowed maximum
227 if (packet->GetSize() > m_maxAppPayloadForDataRate.at(m_dataRate))
228 {
229 NS_LOG_WARN("Attempting to send a packet larger than the maximum allowed"
230 << " size at this Data Rate (DR" << unsigned(m_dataRate)
231 << "). Transmission canceled.");
232 return;
233 }
234
235 // Add the Lora Mac header to the packet
236 LorawanMacHeader macHdr;
237 ApplyNecessaryOptions(macHdr);
238 packet->AddHeader(macHdr);
239
240 // Reset MAC command list
241 m_macCommandList.clear();
242
244 {
245 // Call the callback to notify about the failure
246 uint8_t txs = m_maxNumbTx - (m_retxParams.retxLeft);
248 NS_LOG_DEBUG(" Received new packet from the application layer: stopping retransmission "
249 "procedure. Used "
250 << unsigned(txs) << " transmissions out of a maximum of "
251 << unsigned(m_maxNumbTx) << ".");
252 }
253
254 // Reset retransmission parameters
256
257 // If this is the first transmission of a confirmed packet, save parameters for the
258 // (possible) next retransmissions.
260 {
261 m_retxParams.packet = packet->Copy();
266 m_retxParams.retxLeft - 1; // decreasing the number of retransmissions
267
268 NS_LOG_DEBUG("Message type is " << m_mType);
269 NS_LOG_DEBUG("It is a confirmed packet. Setting retransmission parameters and "
270 "decreasing the number of transmissions left.");
271
272 NS_LOG_INFO("Added MAC header of size " << macHdr.GetSerializedSize() << " bytes.");
273
274 // Sent a new packet
275 NS_LOG_DEBUG("Copied packet: " << m_retxParams.packet);
277
278 // static_cast<ClassAEndDeviceLorawanMac*>(this)->SendToPhy (m_retxParams.packet);
280 }
281 else
282 {
283 m_sentNewPacket(packet);
284 // static_cast<ClassAEndDeviceLorawanMac*>(this)->SendToPhy (packet);
285 SendToPhy(packet);
286 }
287 }
288 // this is a retransmission
289 else
290 {
292 {
293 // Remove the headers
294 LorawanMacHeader macHdr;
295 LoraFrameHeader frameHdr;
296 packet->RemoveHeader(macHdr);
297 packet->RemoveHeader(frameHdr);
298
299 // Add the Lora Frame Header to the packet
300 frameHdr = LoraFrameHeader();
301 ApplyNecessaryOptions(frameHdr);
302 packet->AddHeader(frameHdr);
303
304 NS_LOG_INFO("Added frame header of size " << frameHdr.GetSerializedSize() << " bytes.");
305
306 // Add the Lorawan Mac header to the packet
307 macHdr = LorawanMacHeader();
308 ApplyNecessaryOptions(macHdr);
309 packet->AddHeader(macHdr);
311 m_retxParams.retxLeft - 1; // decreasing the number of retransmissions
312 NS_LOG_DEBUG("Retransmitting an old packet.");
313
314 // static_cast<ClassAEndDeviceLorawanMac*>(this)->SendToPhy (m_retxParams.packet);
316 }
317 }
318}
319
320void
322{
323}
324
325//////////////////////////
326// Receiving methods //
327//////////////////////////
328
329void
331{
332}
333
334void
336{
337}
338
339void
341{
342 NS_LOG_FUNCTION(this << frameHeader);
343
345 {
346 if (frameHeader.GetAck())
347 {
348 NS_LOG_INFO("The message is an ACK, not waiting for it anymore.");
349
350 NS_LOG_DEBUG("Reset retransmission variables to default values and cancel "
351 "retransmission if already scheduled.");
352
353 uint8_t txs = m_maxNumbTx - (m_retxParams.retxLeft);
355 NS_LOG_DEBUG("Received ACK packet after "
356 << unsigned(txs) << " transmissions: stopping retransmission procedure. ");
357
358 // Reset retransmission parameters
360 }
361 else
362 {
364 "Received downlink message not containing an ACK while we were waiting for it!");
365 }
366 }
367
368 std::list<Ptr<MacCommand>> commands = frameHeader.GetCommands();
369 std::list<Ptr<MacCommand>>::iterator it;
370 for (it = commands.begin(); it != commands.end(); it++)
371 {
372 NS_LOG_DEBUG("Iterating over the MAC commands...");
373 enum MacCommandType type = (*it)->GetCommandType();
374 switch (type)
375 {
376 case (LINK_CHECK_ANS): {
377 NS_LOG_DEBUG("Detected a LinkCheckAns command.");
378
379 // Cast the command
380 Ptr<LinkCheckAns> linkCheckAns = (*it)->GetObject<LinkCheckAns>();
381
382 // Call the appropriate function to take action
383 OnLinkCheckAns(linkCheckAns->GetMargin(), linkCheckAns->GetGwCnt());
384
385 break;
386 }
387 case (LINK_ADR_REQ): {
388 NS_LOG_DEBUG("Detected a LinkAdrReq command.");
389
390 // Cast the command
391 Ptr<LinkAdrReq> linkAdrReq = (*it)->GetObject<LinkAdrReq>();
392
393 // Call the appropriate function to take action
394 OnLinkAdrReq(linkAdrReq->GetDataRate(),
395 linkAdrReq->GetTxPower(),
396 linkAdrReq->GetEnabledChannelsList(),
397 linkAdrReq->GetRepetitions());
398
399 break;
400 }
401 case (DUTY_CYCLE_REQ): {
402 NS_LOG_DEBUG("Detected a DutyCycleReq command.");
403
404 // Cast the command
405 Ptr<DutyCycleReq> dutyCycleReq = (*it)->GetObject<DutyCycleReq>();
406
407 // Call the appropriate function to take action
408 OnDutyCycleReq(dutyCycleReq->GetMaximumAllowedDutyCycle());
409
410 break;
411 }
412 case (RX_PARAM_SETUP_REQ): {
413 NS_LOG_DEBUG("Detected a RxParamSetupReq command.");
414
415 // Cast the command
416 Ptr<RxParamSetupReq> rxParamSetupReq = (*it)->GetObject<RxParamSetupReq>();
417
418 // Call the appropriate function to take action
419 OnRxParamSetupReq(rxParamSetupReq);
420
421 break;
422 }
423 case (DEV_STATUS_REQ): {
424 NS_LOG_DEBUG("Detected a DevStatusReq command.");
425
426 // Cast the command
427 Ptr<DevStatusReq> devStatusReq = (*it)->GetObject<DevStatusReq>();
428
429 // Call the appropriate function to take action
431
432 break;
433 }
434 case (NEW_CHANNEL_REQ): {
435 NS_LOG_DEBUG("Detected a NewChannelReq command.");
436
437 // Cast the command
438 Ptr<NewChannelReq> newChannelReq = (*it)->GetObject<NewChannelReq>();
439
440 // Call the appropriate function to take action
441 OnNewChannelReq(newChannelReq->GetChannelIndex(),
442 newChannelReq->GetFrequency(),
443 newChannelReq->GetMinDataRate(),
444 newChannelReq->GetMaxDataRate());
445
446 break;
447 }
448 case (RX_TIMING_SETUP_REQ):
449 case (TX_PARAM_SETUP_REQ):
450 case (DL_CHANNEL_REQ):
451 default: {
452 NS_LOG_ERROR("CID not recognized or supported");
453 break;
454 }
455 }
456 }
457}
458
459void
461{
463
464 frameHeader.SetAsUplink();
465 frameHeader.SetFPort(1); // TODO Use an appropriate frame port based on the application
466 frameHeader.SetAddress(m_address);
467 frameHeader.SetAdr(m_controlDataRate);
468 frameHeader.SetAdrAckReq(false); // TODO Set ADRACKREQ if a member variable is true
469
470 // FPending does not exist in uplink messages
471 frameHeader.SetFCnt(m_currentFCnt);
472
473 // Add listed MAC commands
474 for (const auto& command : m_macCommandList)
475 {
476 NS_LOG_INFO("Applying a MAC Command of CID "
477 << unsigned(MacCommand::GetCIDFromMacCommand(command->GetCommandType())));
478
479 frameHeader.AddCommand(command);
480 }
481}
482
483void
485{
487
488 macHeader.SetMType(m_mType);
489 macHeader.SetMajor(1);
490}
491
492void
494{
495 m_mType = mType;
496 NS_LOG_DEBUG("Message type is set to " << mType);
497}
498
501{
502 return m_mType;
503}
504
505void
507{
508}
509
510Time
512{
514 return waitingTime;
515}
516
517Time
519{
521
522 // Check duty cycle //
523
524 // Pick a random channel to transmit on
525 std::vector<Ptr<LogicalLoraChannel>> logicalChannels;
526 logicalChannels =
527 m_channelHelper.GetEnabledChannelList(); // Use a separate list to do the shuffle
528 // logicalChannels = Shuffle (logicalChannels);
529
530 Time waitingTime = Time::Max();
531
532 // Try every channel
533 std::vector<Ptr<LogicalLoraChannel>>::iterator it;
534 for (it = logicalChannels.begin(); it != logicalChannels.end(); ++it)
535 {
536 // Pointer to the current channel
537 Ptr<LogicalLoraChannel> logicalChannel = *it;
538 double frequency = logicalChannel->GetFrequency();
539
540 waitingTime = std::min(waitingTime, m_channelHelper.GetWaitingTime(logicalChannel));
541
542 NS_LOG_DEBUG("Waiting time before the next transmission in channel with frequency "
543 << frequency << " is = " << waitingTime.GetSeconds() << ".");
544 }
545
546 waitingTime = GetNextClassTransmissionDelay(waitingTime);
547
548 return waitingTime;
549}
550
553{
555
556 // Pick a random channel to transmit on
557 std::vector<Ptr<LogicalLoraChannel>> logicalChannels;
558 logicalChannels =
559 m_channelHelper.GetEnabledChannelList(); // Use a separate list to do the shuffle
560 logicalChannels = Shuffle(logicalChannels);
561
562 // Try every channel
563 std::vector<Ptr<LogicalLoraChannel>>::iterator it;
564 for (it = logicalChannels.begin(); it != logicalChannels.end(); ++it)
565 {
566 // Pointer to the current channel
567 Ptr<LogicalLoraChannel> logicalChannel = *it;
568 double frequency = logicalChannel->GetFrequency();
569
570 NS_LOG_DEBUG("Frequency of the current channel: " << frequency);
571
572 // Verify that we can send the packet
573 Time waitingTime = m_channelHelper.GetWaitingTime(logicalChannel);
574
575 NS_LOG_DEBUG("Waiting time for current channel = " << waitingTime.GetSeconds());
576
577 // Send immediately if we can
578 if (waitingTime == Seconds(0))
579 {
580 return *it;
581 }
582 else
583 {
584 NS_LOG_DEBUG("Packet cannot be immediately transmitted on "
585 << "the current channel because of duty cycle limitations.");
586 }
587 }
588 return nullptr; // In this case, no suitable channel was found
589}
590
591std::vector<Ptr<LogicalLoraChannel>>
593{
595
596 int size = vector.size();
597
598 for (int i = 0; i < size; ++i)
599 {
600 uint16_t random = std::floor(m_uniformRV->GetValue(0, size));
601 Ptr<LogicalLoraChannel> temp = vector.at(random);
602 vector.at(random) = vector.at(i);
603 vector.at(i) = temp;
604 }
605
606 return vector;
607}
608
609/////////////////////////
610// Setters and Getters //
611/////////////////////////
612
613void
615{
616 m_retxParams.waitingAck = false;
618 m_retxParams.packet = nullptr;
620
621 // Cancel next retransmissions, if any
623}
624
625void
627{
628 NS_LOG_FUNCTION(this << adapt);
629 m_enableDRAdapt = adapt;
630}
631
632bool
634{
635 return m_enableDRAdapt;
636}
637
638void
640{
641 NS_LOG_FUNCTION(this << unsigned(maxNumbTx));
642 m_maxNumbTx = maxNumbTx;
643 m_retxParams.retxLeft = maxNumbTx;
644}
645
646uint8_t
648{
649 NS_LOG_FUNCTION(this);
650 return m_maxNumbTx;
651}
652
653void
655{
656 NS_LOG_FUNCTION(this << unsigned(dataRate));
657
658 m_dataRate = dataRate;
659}
660
661uint8_t
663{
664 NS_LOG_FUNCTION(this);
665
666 return m_dataRate;
667}
668
669void
671{
672 NS_LOG_FUNCTION(this << address);
673
674 m_address = address;
675}
676
679{
680 NS_LOG_FUNCTION(this);
681
682 return m_address;
683}
684
685void
686EndDeviceLorawanMac::OnLinkCheckAns(uint8_t margin, uint8_t gwCnt)
687{
688 NS_LOG_FUNCTION(this << unsigned(margin) << unsigned(gwCnt));
689
690 m_lastKnownLinkMargin = margin;
692}
693
694void
696 uint8_t txPower,
697 std::list<int> enabledChannels,
698 int repetitions)
699{
700 NS_LOG_FUNCTION(this << unsigned(dataRate) << unsigned(txPower) << repetitions);
701
702 // Three bools for three requirements before setting things up
703 bool channelMaskOk = true;
704 bool dataRateOk = true;
705 bool txPowerOk = true;
706
707 // Check the channel mask
708 /////////////////////////
709 // Check whether all specified channels exist on this device
710 auto channelList = m_channelHelper.GetChannelList();
711 int channelListSize = channelList.size();
712
713 for (auto it = enabledChannels.begin(); it != enabledChannels.end(); it++)
714 {
715 if ((*it) > channelListSize)
716 {
717 channelMaskOk = false;
718 break;
719 }
720 }
721
722 // Check the dataRate
723 /////////////////////
724 // We need to know we can use it at all
725 // To assess this, we try and convert it to a spreading factor / bandwidth combination and check
726 // if those values are valid. Since GetSfFromDataRate and GetBandwidthFromDataRate return 0 if
727 // the dataRate is not recognized, we can check against this.
728 uint8_t sf = GetSfFromDataRate(dataRate);
729 double bw = GetBandwidthFromDataRate(dataRate);
730 NS_LOG_DEBUG("SF: " << unsigned(sf) << ", BW: " << bw);
731 if (sf == 0 || bw == 0)
732 {
733 dataRateOk = false;
734 NS_LOG_DEBUG("Data rate non valid");
735 }
736
737 // We need to know we can use it in at least one of the enabled channels
738 // Cycle through available channels, stop when at least one is enabled for the
739 // specified dataRate.
740 if (dataRateOk && channelMaskOk) // If false, skip the check
741 {
742 bool foundAvailableChannel = false;
743 for (auto it = enabledChannels.begin(); it != enabledChannels.end(); it++)
744 {
745 NS_LOG_DEBUG("MinDR: " << unsigned(channelList.at(*it)->GetMinimumDataRate()));
746 NS_LOG_DEBUG("MaxDR: " << unsigned(channelList.at(*it)->GetMaximumDataRate()));
747 if (channelList.at(*it)->GetMinimumDataRate() <= dataRate &&
748 channelList.at(*it)->GetMaximumDataRate() >= dataRate)
749 {
750 foundAvailableChannel = true;
751 break;
752 }
753 }
754
755 if (!foundAvailableChannel)
756 {
757 dataRateOk = false;
758 NS_LOG_DEBUG("Available channel not found");
759 }
760 }
761
762 // Check the txPower
763 ////////////////////
764 // Check whether we can use this transmission power
765 if (GetDbmForTxPower(txPower) == 0)
766 {
767 txPowerOk = false;
768 }
769
770 NS_LOG_DEBUG("Finished checking. "
771 << "ChannelMaskOk: " << channelMaskOk << ", "
772 << "DataRateOk: " << dataRateOk << ", "
773 << "txPowerOk: " << txPowerOk);
774
775 // If all checks are successful, set parameters up
776 //////////////////////////////////////////////////
777 if (channelMaskOk && dataRateOk && txPowerOk)
778 {
779 // Cycle over all channels in the list
780 for (uint32_t i = 0; i < m_channelHelper.GetChannelList().size(); i++)
781 {
782 if (std::find(enabledChannels.begin(), enabledChannels.end(), i) !=
783 enabledChannels.end())
784 {
785 m_channelHelper.GetChannelList().at(i)->SetEnabledForUplink();
786 NS_LOG_DEBUG("Channel " << i << " enabled");
787 }
788 else
789 {
790 m_channelHelper.GetChannelList().at(i)->DisableForUplink();
791 NS_LOG_DEBUG("Channel " << i << " disabled");
792 }
793 }
794
795 // Set the data rate
796 m_dataRate = dataRate;
797
798 // Set the transmission power
799 m_txPower = GetDbmForTxPower(txPower);
800 }
801
802 // Craft a LinkAdrAns MAC command as a response
803 ///////////////////////////////////////////////
804 m_macCommandList.emplace_back(CreateObject<LinkAdrAns>(txPowerOk, dataRateOk, channelMaskOk));
805}
806
807void
809{
810 NS_LOG_FUNCTION(this << dutyCycle);
811
812 // Make sure we get a value that makes sense
813 NS_ASSERT(0 <= dutyCycle && dutyCycle < 1);
814
815 // Set the new duty cycle value
816 m_aggregatedDutyCycle = dutyCycle;
817
818 // Craft a DutyCycleAns as response
819 NS_LOG_INFO("Adding DutyCycleAns reply");
820 m_macCommandList.emplace_back(CreateObject<DutyCycleAns>());
821}
822
823void
825{
826}
827
828void
830{
831 NS_LOG_FUNCTION(this << rxParamSetupReq);
832
833 // static_cast<ClassAEndDeviceLorawanMac*>(this)->OnRxClassParamSetupReq (rxParamSetupReq);
834 OnRxClassParamSetupReq(rxParamSetupReq);
835}
836
837void
839{
840 NS_LOG_FUNCTION(this);
841
842 uint8_t battery = 10; // XXX Fake battery level
843 uint8_t margin = 10; // XXX Fake margin
844
845 // Craft a RxParamSetupAns as response
846 NS_LOG_INFO("Adding DevStatusAns reply");
847 m_macCommandList.emplace_back(CreateObject<DevStatusAns>(battery, margin));
848}
849
850void
852 double frequency,
853 uint8_t minDataRate,
854 uint8_t maxDataRate)
855{
856 NS_LOG_FUNCTION(this);
857
858 bool dataRateRangeOk = true; // XXX Check whether the new data rate range is ok
859 bool channelFrequencyOk = true; // XXX Check whether the frequency is ok
860
861 // TODO Return false if one of the checks above failed
862 // TODO Create new channel in the LogicalLoraChannelHelper
863
864 SetLogicalChannel(chIndex, frequency, minDataRate, maxDataRate);
865
866 NS_LOG_INFO("Adding NewChannelAns reply");
867 m_macCommandList.emplace_back(CreateObject<NewChannelAns>(dataRateRangeOk, channelFrequencyOk));
868}
869
870void
872{
873 NS_LOG_FUNCTION(this << frequency);
874
875 m_channelHelper.AddChannel(frequency);
876}
877
878void
880{
881 NS_LOG_FUNCTION(this << logicalChannel);
882
883 m_channelHelper.AddChannel(logicalChannel);
884}
885
886void
888 double frequency,
889 uint8_t minDataRate,
890 uint8_t maxDataRate)
891{
892 NS_LOG_FUNCTION(this << unsigned(chIndex) << frequency << unsigned(minDataRate)
893 << unsigned(maxDataRate));
894
896 chIndex,
897 CreateObject<LogicalLoraChannel>(frequency, minDataRate, maxDataRate));
898}
899
900void
902 double endFrequency,
903 double dutyCycle,
904 double maxTxPowerDbm)
905{
907
908 m_channelHelper.AddSubBand(startFrequency, endFrequency, dutyCycle, maxTxPowerDbm);
909}
910
911double
913{
915
917}
918
919void
921{
922 NS_LOG_FUNCTION(this << macCommand);
923
924 m_macCommandList.push_back(macCommand);
925}
926
927uint8_t
929{
930 return m_txPower;
931}
932} // namespace lorawan
933} // namespace ns3
Hold variables of type enum.
Definition: enum.h:62
An identifier for simulation events.
Definition: event-id.h:56
void Cancel()
This method is syntactic sugar for the ns3::Simulator::Cancel method.
Definition: event-id.cc:55
Hold a signed integer type.
Definition: integer.h:45
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:77
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition: simulator.h:571
static void Cancel(const EventId &id)
Set the cancel bit on this event: the event's associated function will not be invoked when it expires...
Definition: simulator.cc:285
static Time Now()
Return the current simulation virtual time.
Definition: simulator.cc:208
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:105
double GetSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
Definition: nstime.h:403
static Time Max()
Maximum representable Time Not to be confused with Max(Time,Time).
Definition: nstime.h:297
a unique identifier for an interface.
Definition: type-id.h:59
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:932
Hold an unsigned integer type.
Definition: uinteger.h:45
double GetValue(double min, double max)
Get the next random value drawn from the distribution.
Implementation of the DevStatusReq LoRaWAN MAC command.
Definition: mac-command.h:460
Implementation of the DutyCycleReq LoRaWAN MAC command.
Definition: mac-command.h:331
LorawanMacHeader::MType m_mType
The message type to apply to packets sent with the Send method.
uint8_t m_maxNumbTx
Default number of unacknowledged redundant transmissions of each packet.
TracedValue< int > m_lastKnownGatewayCount
The last known gateway count (i.e., gateways that are in communication range with this end device).
bool GetDataRateAdaptation() const
Get if data rate adaptation is enabled or not.
void SetLogicalChannel(uint8_t chIndex, double frequency, uint8_t minDataRate, uint8_t maxDataRate)
Set a new logical channel in the helper.
void FailedReception(Ptr< const Packet > packet) override
Function called by lower layers to inform this layer that reception of a packet we were locked on fai...
virtual void OnRxClassParamSetupReq(Ptr< RxParamSetupReq > rxParamSetupReq)
Perform the actions that need to be taken when receiving a RxParamSetupReq command based on the Devic...
void AddSubBand(double startFrequency, double endFrequency, double dutyCycle, double maxTxPowerDbm)
Add a subband to the logical channel helper.
bool m_controlDataRate
Whether this device's data rate should be controlled by the network server.
virtual void postponeTransmission(Time nextTxDelay, Ptr< Packet > packet)
Postpone transmission to the specified time and delete previously scheduled transmissions if present.
virtual void SendToPhy(Ptr< Packet > packet)
Add headers and send a packet with the sending function of the physical layer.
Ptr< LogicalLoraChannel > GetChannelForTx()
Find a suitable channel for transmission.
void OnDutyCycleReq(double dutyCycle)
Perform the actions that need to be taken when receiving a DutyCycleReq command.
TracedValue< double > m_txPower
The transmission power this device is using to transmit.
bool m_enableDRAdapt
Enable data rate adaptation (ADR) during the retransmission procedure.
void TxFinished(Ptr< const Packet > packet) override
Perform the actions that are required after a packet send.
Ptr< UniformRandomVariable > m_uniformRV
An uniform random variable, used by the Shuffle method to randomly reorder the channel list.
void OnRxParamSetupReq(Ptr< RxParamSetupReq > rxParamSetupReq)
Perform the actions that need to be taken when receiving a RxParamSetupReq command.
static TypeId GetTypeId()
Register this type.
TracedValue< double > m_aggregatedDutyCycle
The aggregated duty cycle this device needs to respect across all sub-bands.
void Receive(Ptr< const Packet > packet) override
Receive a packet.
void SetMType(LorawanMacHeader::MType mType)
Set the message type to send when the Send method is called.
virtual void resetRetransmissionParameters()
Reset retransmission parameters contained in the structure LoraRetxParams.
virtual Time GetNextClassTransmissionDelay(Time waitingTime)
Find the minimum waiting time before the next possible transmission based on end device's Class Type.
void ParseCommands(LoraFrameHeader frameHeader)
Parse and take action on the commands contained on this FrameHeader.
void ApplyNecessaryOptions(LoraFrameHeader &frameHeader)
Add the necessary options and MAC commands to the LoraFrameHeader.
TracedCallback< uint8_t, bool, Time, Ptr< Packet > > m_requiredTxCallback
The trace source fired when the transmission procedure is finished.
virtual uint8_t GetTransmissionPower()
Get the transmission power this end device is set to use.
uint8_t GetMaxNumberOfTransmissions()
Get the max number of unacknowledged redundant transmissions of each packet.
void SetDataRateAdaptation(bool adapt)
Enable data rate adaptation in the retransmitting procedure.
void OnLinkCheckAns(uint8_t margin, uint8_t gwCnt)
Perform the actions that need to be taken when receiving a LinkCheckAns command.
EventId m_nextTx
The event of retransmitting a packet in a consecutive moment if an ACK is not received.
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.
std::list< Ptr< MacCommand > > m_macCommandList
List of the MAC commands that need to be applied to the next UL packet.
TracedValue< uint8_t > m_dataRate
The data rate this device is using to transmit.
LoraDeviceAddress m_address
The address of this device.
void Send(Ptr< Packet > packet) override
Send a packet.
uint16_t m_currentFCnt
current value of the device frame counter.
void AddMacCommand(Ptr< MacCommand > macCommand)
Add a MAC command to the list of those that will be sent out in the next packet.
void SetMaxNumberOfTransmissions(uint8_t maxNumbTx)
Set the max number of unacknowledged redundant transmissions of each packet.
TracedValue< double > m_lastKnownLinkMargin
The last known link margin.
void AddLogicalChannel(double frequency)
Add a logical channel to the helper.
Time GetNextTransmissionDelay()
Find the base minimum waiting time before the next possible transmission.
std::vector< Ptr< LogicalLoraChannel > > Shuffle(std::vector< Ptr< LogicalLoraChannel > > vector)
Randomly shuffle a Ptr<LogicalLoraChannel> vector.
LorawanMacHeader::MType GetMType()
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 OnDevStatusReq()
Perform the actions that need to be taken when receiving a DevStatusReq command.
LoraDeviceAddress GetDeviceAddress()
Get the network address of this device.
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.
void SetDataRate(uint8_t dataRate)
Set the data rate this end device will use when transmitting.
uint8_t GetDataRate()
Get the data rate this end device is set to use.
void SetDeviceAddress(LoraDeviceAddress address)
Set the network address of this device.
struct LoraRetxParameters m_retxParams
Structure containing the retransmission parameters for this device.
double GetTxPowerForChannel(Ptr< LogicalLoraChannel > logicalChannel)
Returns the maximum transmission power [dBm] that is allowed on a channel.
void SetChannel(uint8_t chIndex, Ptr< LogicalLoraChannel > logicalChannel)
Set a new channel at a fixed index.
std::vector< Ptr< LogicalLoraChannel > > GetChannelList()
Get the list of LogicalLoraChannels currently registered on this helper.
std::vector< Ptr< LogicalLoraChannel > > GetEnabledChannelList()
Get the list of LogicalLoraChannels currently registered on this helper that have been enabled for Up...
void AddSubBand(double firstFrequency, double lastFrequency, double dutyCycle, double maxTxPowerDbm)
Add a new SubBand to this helper.
Time GetWaitingTime(Ptr< LogicalLoraChannel > channel)
Get the time it is necessary to wait for before transmitting on a given channel.
void AddChannel(double frequency)
Add a new channel to the list.
This class represents the device address of a LoraWAN end device.
This class represents the Frame header (FHDR) used in a LoraWAN network.
bool GetAck() const
Get the value of the ACK bit field.
void AddCommand(Ptr< MacCommand > macCommand)
Add a predefined command to the list in this frame header.
void SetFCnt(uint16_t fCnt)
Set the FCnt value.
void SetAdr(bool adr)
Set the value of the ADR bit field.
uint32_t GetSerializedSize() const override
Return the size required for serialization of this header.
void SetAddress(LoraDeviceAddress address)
Set the address.
void SetAsUplink()
State that this is an uplink message.
void SetAdrAckReq(bool adrAckReq)
Set the value of the ADRACKReq bit field.
std::list< Ptr< MacCommand > > GetCommands()
Return a list of pointers to all the MAC commands saved in this header.
void SetFPort(uint8_t fPort)
Set the FPort value.
This class represents the Mac header of a LoRaWAN packet.
void SetMajor(uint8_t major)
Set the major version of this header.
void SetMType(enum MType mtype)
Set the message type.
uint32_t GetSerializedSize() const override
Class representing the LoRaWAN MAC layer.
Definition: lorawan-mac.h:48
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:231
std::vector< uint32_t > m_maxAppPayloadForDataRate
A vector holding the maximum app payload size that corresponds to a certain data rate.
Definition: lorawan-mac.h:273
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:139
uint8_t GetSfFromDataRate(uint8_t dataRate)
Get the spreading factor corresponding to a data rate, based on this MAC's region.
Definition: lorawan-mac.cc:111
double GetBandwidthFromDataRate(uint8_t dataRate)
Get the bandwidth corresponding to a data rate, based on this MAC's region.
Definition: lorawan-mac.cc:125
LogicalLoraChannelHelper m_channelHelper
The LogicalLoraChannelHelper instance that is assigned to this MAC.
Definition: lorawan-mac.h:257
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:242
static uint8_t GetCIDFromMacCommand(enum MacCommandType commandType)
Get the CID that corresponds to a type of MAC command.
Definition: mac-command.cc:70
Implementation of the NewChannelReq LoRaWAN MAC command.
Definition: mac-command.h:519
Implementation of the RxParamSetupReq LoRaWAN MAC command.
Definition: mac-command.h:382
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition: assert.h:66
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
Definition: assert.h:86
#define NS_LOG_ERROR(msg)
Use NS_LOG to output a message of level LOG_ERROR.
Definition: log.h:254
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:202
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition: log.h:268
#define NS_LOG_FUNCTION_NOARGS()
Output the name of the function.
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_LOG_WARN(msg)
Use NS_LOG to output a message of level LOG_WARN.
Definition: log.h:261
#define NS_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
Definition: log.h:275
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition: object-base.h:46
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1319
Ptr< const TraceSourceAccessor > MakeTraceSourceAccessor(T a)
Create a TraceSourceAccessor which will control access to the underlying trace source.
MacCommandType
Enum for every possible command type.
Definition: mac-command.h:36
@ RX_PARAM_SETUP_REQ
Definition: mac-command.h:44
@ RX_TIMING_SETUP_REQ
Definition: mac-command.h:50
@ TX_PARAM_SETUP_REQ
Definition: mac-command.h:52
Every class exported by the ns3 library is enclosed in the ns3 namespace.
Ptr< const AttributeChecker > MakeBooleanChecker()
Definition: boolean.cc:124
Ptr< const AttributeAccessor > MakeIntegerAccessor(T1 a1)
Definition: integer.h:46
Ptr< const AttributeAccessor > MakeUintegerAccessor(T1 a1)
Definition: uinteger.h:46
Ptr< const AttributeChecker > MakeEnumChecker(T v, std::string n, Ts... args)
Make an EnumChecker pre-configured with a set of allowed values by name.
Definition: enum.h:189
Ptr< const AttributeAccessor > MakeBooleanAccessor(T1 a1)
Definition: boolean.h:81
Structure representing the parameters that will be used in the retransmission procedure.
bool waitingAck
Whether the packet requires explicit acknowledgment.
uint8_t retxLeft
Number of retransmission attempts left.
Time firstAttempt
Timestamp of the first transmission of the packet.
Ptr< Packet > packet
A pointer to the packet being retransmitted.