Loading...
Searching...
No Matches
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
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
44namespace ns3
45{
46
47NS_LOG_COMPONENT_DEFINE("LorawanMacEndDevice");
48
49NS_OBJECT_ENSURE_REGISTERED(LorawanMacEndDevice);
50
51TypeId
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
122LorawanMacEndDevice::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
132 // LoraWAN default
134 // LoraWAN default
137 m_isRegenerative(false),
138 // LoraWAN default
139 m_controlDataRate(false),
143 m_mType(LorawanMacHeader::CONFIRMED_DATA_UP),
144 m_currentFCnt(0),
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
159 m_retxParams.retxLeft = m_maxNumbTx;
160}
161
163{
164 NS_LOG_FUNCTION_NOARGS();
165}
166
168// Sending methods //
170
171void
172LorawanMacEndDevice::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
211void
212LorawanMacEndDevice::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
223void
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.");
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
266 if (m_retxParams.waitingAck)
267 {
268 // Call the callback to notify about the failure
269 uint8_t txs = m_maxNumbTx - (m_retxParams.retxLeft);
270 m_requiredTxCallback(txs, false, m_retxParams.firstAttempt, m_retxParams.packet);
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();
285 m_retxParams.retxLeft = m_maxNumbTx;
286 m_retxParams.waitingAck = true;
287 m_retxParams.firstAttempt = Simulator::Now();
288 m_retxParams.retxLeft =
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
299 SendToPhy(m_retxParams.packet);
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);
315 if (m_retxParams.waitingAck)
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);
334 m_retxParams.retxLeft =
335 m_retxParams.retxLeft - 1; // decreasing the number of retransmissions
336 NS_LOG_DEBUG("Retransmitting an old packet.");
337
338 SendToPhy(m_retxParams.packet);
339 }
340 }
341}
342
343void
345{
346}
347
349// Receiving methods //
351
352void
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
363void
365{
366}
367
368void
370{
371 NS_LOG_FUNCTION(this << frameHeader);
372
373 if (m_retxParams.waitingAck)
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);
383 m_requiredTxCallback(txs, true, m_retxParams.firstAttempt, m_retxParams.packet);
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
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
493void
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
517void
519{
520 NS_LOG_FUNCTION_NOARGS();
521
522 macHeader.SetMType(m_mType);
523 macHeader.SetMajor(1);
524}
525
526void
528{
529 m_mType = mType;
530 NS_LOG_DEBUG("Message type is set to " << mType);
531}
532
535{
536 return m_mType;
537}
538
539void
543
544bool
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
608void
609LorawanMacEndDevice::ChangeBeam(uint32_t satId, uint32_t beamId)
610{
611 NS_LOG_FUNCTION(this << satId << beamId);
612}
613
614Time
616{
617 NS_LOG_FUNCTION_NOARGS();
618 return waitingTime;
619}
620
621Time
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
655Ptr<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
695std::vector<Ptr<LoraLogicalChannel>>
696LorawanMacEndDevice::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
717void
719{
720 m_retxParams.waitingAck = false;
721 m_retxParams.retxLeft = m_maxNumbTx;
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
729void
731{
732 NS_LOG_FUNCTION(this << adapt);
733 m_enableDRAdapt = adapt;
734}
735
736bool
741
742void
744{
745 NS_LOG_FUNCTION(this << unsigned(maxNumbTx));
746 m_maxNumbTx = maxNumbTx;
747 m_retxParams.retxLeft = maxNumbTx;
748}
749
750uint8_t
752{
753 NS_LOG_FUNCTION(this);
754 return m_maxNumbTx;
755}
756
757void
759{
760 NS_LOG_FUNCTION(this << unsigned(dataRate));
761
762 m_dataRate = dataRate;
763}
764
765uint8_t
767{
768 NS_LOG_FUNCTION(this);
769
770 return m_dataRate;
771}
772
773void
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
789void
790LorawanMacEndDevice::OnLinkCheckAns(uint8_t margin, uint8_t gwCnt)
791{
792 NS_LOG_FUNCTION(this << unsigned(margin) << unsigned(gwCnt));
793
794 m_lastKnownLinkMargin = margin;
796}
797
798void
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. " << "ChannelMaskOk: " << channelMaskOk << ", "
876 << "DataRateOk: " << dataRateOk << ", "
877 << "txPowerOk: " << txPowerOk);
878
879 // If all checks are successful, set parameters up
881 if (channelMaskOk && dataRateOk && txPowerOk)
882 {
883 // Cycle over all channels in the list
884 for (uint32_t i = 0; i < m_channelHelper.GetChannelList().size(); i++)
885 {
886 if (std::find(enabledChannels.begin(), enabledChannels.end(), i) !=
887 enabledChannels.end())
888 {
889 m_channelHelper.GetChannelList().at(i)->SetEnabledForUplink();
890 NS_LOG_DEBUG("Channel " << i << " enabled");
891 }
892 else
893 {
894 m_channelHelper.GetChannelList().at(i)->DisableForUplink();
895 NS_LOG_DEBUG("Channel " << i << " disabled");
896 }
897 }
898
899 // Set the data rate
900 m_dataRate = dataRate;
901
902 // Set the transmission power
903 m_txPower = GetDbmForTxPower(txPower);
904 }
905
906 // Craft a LinkAdrAns MAC command as a response
908 m_macCommandList.push_back(CreateObject<LinkAdrAns>(txPowerOk, dataRateOk, channelMaskOk));
909}
910
911void
913{
914 NS_LOG_FUNCTION(this << dutyCycle);
915
916 // Make sure we get a value that makes sense
917 NS_ASSERT(0 <= dutyCycle && dutyCycle < 1);
918
919 // Set the new duty cycle value
920 m_aggregatedDutyCycle = dutyCycle;
921
922 // Craft a DutyCycleAns as response
923 NS_LOG_INFO("Adding DutyCycleAns reply");
924 m_macCommandList.push_back(CreateObject<DutyCycleAns>());
925}
926
927void
928LorawanMacEndDevice::OnRxClassParamSetupReq(Ptr<RxParamSetupReq> rxParamSetupReq)
929{
930}
931
932void
933LorawanMacEndDevice::OnRxParamSetupReq(Ptr<RxParamSetupReq> rxParamSetupReq)
934{
935 NS_LOG_FUNCTION(this << rxParamSetupReq);
936
937 // static_cast<ClassALorawanMacEndDevice*>(this)->OnRxClassParamSetupReq (rxParamSetupReq);
938 OnRxClassParamSetupReq(rxParamSetupReq);
939}
940
941void
943{
944 NS_LOG_FUNCTION(this);
945
946 uint8_t battery = 10; // XXX Fake battery level
947 uint8_t margin = 10; // XXX Fake margin
948
949 // Craft a RxParamSetupAns as response
950 NS_LOG_INFO("Adding DevStatusAns reply");
951 m_macCommandList.push_back(CreateObject<DevStatusAns>(battery, margin));
952}
953
954void
956 double frequency,
957 uint8_t minDataRate,
958 uint8_t maxDataRate)
959{
960 NS_LOG_FUNCTION(this);
961
962 bool dataRateRangeOk = true; // XXX Check whether the new data rate range is ok
963 bool channelFrequencyOk = true; // XXX Check whether the frequency is ok
964
965 // TODO Return false if one of the checks above failed
966 // TODO Create new channel in the LoraLogicalChannelHelper
967
968 SetLogicalChannel(chIndex, frequency, minDataRate, maxDataRate);
969
970 NS_LOG_INFO("Adding NewChannelAns reply");
971 m_macCommandList.push_back(CreateObject<NewChannelAns>(dataRateRangeOk, channelFrequencyOk));
972}
973
974void
976{
977 NS_LOG_FUNCTION(this << frequency);
978
979 m_channelHelper.AddChannel(frequency);
980}
981
982void
983LorawanMacEndDevice::AddLogicalChannel(Ptr<LoraLogicalChannel> logicalChannel)
984{
985 NS_LOG_FUNCTION(this << logicalChannel);
986
987 m_channelHelper.AddChannel(logicalChannel);
988}
989
990void
992 double frequency,
993 uint8_t minDataRate,
994 uint8_t maxDataRate)
995{
996 NS_LOG_FUNCTION(this << unsigned(chIndex) << frequency << unsigned(minDataRate)
997 << unsigned(maxDataRate));
998
999 m_channelHelper.SetChannel(
1000 chIndex,
1001 CreateObject<LoraLogicalChannel>(frequency, minDataRate, maxDataRate));
1002}
1003
1004void
1006 double endFrequency,
1007 double dutyCycle,
1008 double maxTxPowerDbm)
1009{
1010 NS_LOG_FUNCTION_NOARGS();
1011
1012 m_channelHelper.AddLoraSubBand(startFrequency, endFrequency, dutyCycle, maxTxPowerDbm);
1013}
1014
1015double
1017{
1018 NS_LOG_FUNCTION_NOARGS();
1019
1020 return m_aggregatedDutyCycle;
1021}
1022
1023void
1024LorawanMacEndDevice::AddLorawanMacCommand(Ptr<LorawanMacCommand> macCommand)
1025{
1026 NS_LOG_FUNCTION(this << macCommand);
1027
1028 m_macCommandList.push_back(macCommand);
1029}
1030
1031uint8_t
1036
1037void
1043
1044void
1050
1051void
1058
1059void
1061{
1062 NS_LOG_FUNCTION(this << gwAddress);
1063
1064 // m_gatewayUpdateCallback (gwAddress);
1065 m_gwAddress = gwAddress;
1066}
1067
1068void
1070{
1071 NS_LOG_FUNCTION(this << satAddress);
1072
1073 m_satelliteAddress = satAddress;
1074}
1075
1076void
1078{
1079 NS_LOG_FUNCTION(this << isRegenerative);
1080
1081 m_isRegenerative = isRegenerative;
1082}
1083
1084void
1086{
1087 m_raChannel = raChannel;
1088}
1089
1090void
1091LorawanMacEndDevice::SetPhyRx(Ptr<SatLoraPhyRx> phyRx)
1092{
1093 m_phyRx = phyRx;
1094}
1095
1096Ptr<SatLoraPhyRx>
1098{
1099 return m_phyRx;
1100}
1101
1102} // 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.
static uint8_t GetCIDFromLorawanMacCommand(enum MacCommandType commandType)
Get the CID that corresponds to this MAC command.
Class representing the MAC layer of a LoRaWAN device.
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_receiveWindowDurationInSymbols
The duration of a receive window in number of symbols.
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.
uint8_t m_codingRate
The coding rate used by this device.
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.
bool m_headerDisabled
Whether or not the header is disabled for communications by this device.
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.
void SetMType(enum MType mtype)
Set the message type.
std::vector< uint32_t > m_maxAppPayloadForDataRate
A vector holding the maximum app payload size that corresponds to a certain DataRate.
uint32_t m_beamId
ID of beam for UT.
TracedCallback< Ptr< const Packet > > m_cannotSendBecauseDutyCycle
The trace source that is fired when a packet cannot be sent because of duty cycle limitations.
TracedCallback< Ptr< const Packet > > m_sentNewPacket
Trace source that is fired when a new APP layer packet arrives at the MAC layer.
uint8_t GetSfFromDataRate(uint8_t dataRate)
Get the SF corresponding to a data rate, based on this MAC's region.
double GetDbmForTxPower(uint8_t txPower)
Get the transmission power in dBm that corresponds, in this region, to the encoded 8-bit txPower.
LoraLogicalChannelHelper m_channelHelper
The LoraLogicalChannelHelper instance that is assigned to this MAC.
double GetBandwidthFromDataRate(uint8_t dataRate)
Get the BW corresponding to a data rate, based on this MAC's region.
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.
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
Structure representing the parameters that will be used in the retransmission procedure.