16#include "ns3/energy-source-container.h"
17#include "ns3/simulator.h"
34 TypeId(
"ns3::EndDeviceLorawanMac")
36 .SetGroupName(
"lorawan")
37 .AddTraceSource(
"RequiredTransmissions",
38 "Total number of transmissions required to deliver this packet",
40 "ns3::TracedValueCallback::uint8_t")
41 .AddAttribute(
"DataRate",
42 "Data rate currently employed by this end device",
46 .AddTraceSource(
"DataRate",
47 "Data rate currently employed by this end device",
49 "ns3::TracedValueCallback::uint8_t")
52 "Ensure to the network server that this device will accept data rate, transmission "
53 "power and number of retransmissions configurations received via LinkADRReq. This "
54 "also allows the device's local ADR backoff procedure to reset configurations in "
55 "case of connectivity loss.",
59 .AddTraceSource(
"TxPower",
60 "Transmission ERP [dBm] currently employed by this end device",
62 "ns3::TracedValueCallback::Double")
63 .AddTraceSource(
"LastKnownLinkMargin",
64 "Last known demodulation margin in "
65 "communications between this end device "
68 "ns3::TracedValueCallback::uint8_t")
69 .AddTraceSource(
"LastKnownGatewayCount",
70 "Last known number of gateways able to "
71 "listen to this end device",
73 "ns3::TracedValueCallback::uint8_t")
74 .AddTraceSource(
"AggregatedDutyCycle",
75 "Aggregate duty cycle, in fraction form, "
76 "this end device must respect",
78 "ns3::TracedValueCallback::Double")
79 .AddAttribute(
"MaxTransmissions",
80 "Maximum number of transmissions for a packet (NbTrans)",
84 .AddAttribute(
"MType",
85 "Specify type of message will be sent by this end device.",
148 "Max number of transmissions already achieved for this packet");
157 packet->RemoveHeader(macHdr);
159 packet->RemoveHeader(frameHdr);
163 NS_LOG_DEBUG(
"New FRMPayload from application: " << packet);
168 NS_LOG_WARN(
"Stopping retransmission procedure of previous packet. Used "
169 <<
unsigned(txs) <<
" transmissions out of " <<
unsigned(
m_nbTrans));
190 NS_LOG_ERROR(
"Application payload exceeding maximum size. Transmission aborted.");
197 NS_LOG_ERROR(
"No tx channel compatible with current DR/power. Transmission aborted.");
224 NS_LOG_WARN(
"Attempting to send, but the aggregate duty cycle won't allow it. Scheduling a tx "
237 packet->AddHeader(frameHdr);
242 packet->AddHeader(macHdr);
306 channels.at(0)->EnableForUplink();
307 channels.at(1)->EnableForUplink();
308 channels.at(2)->EnableForUplink();
317 fOptsLen += c->GetSerializedSize();
320 NS_LOG_LOGIC(
"FHDR(7+FOpts(" << fOptsLen <<
"))+FPort(1)+FRMPayload(" << appPayloadSize
321 <<
")=" << 7 + fOptsLen + 1 + appPayloadSize
323 <<
"B on DR" <<
unsigned(dataRate));
350 NS_LOG_INFO(
"The message is an ACK, not waiting for it anymore.");
352 NS_LOG_DEBUG(
"Reset retransmission variables to default values and cancel "
353 "retransmission if already scheduled.");
358 <<
unsigned(txs) <<
" transmissions: stopping retransmission procedure. ");
366 "Received downlink message not containing an ACK while we were waiting for it!");
379 OnLinkCheckAns(linkCheckAns->GetMargin(), linkCheckAns->GetGwCnt());
386 linkAdrReq->GetTxPower(),
387 linkAdrReq->GetChMask(),
388 linkAdrReq->GetChMaskCntl(),
389 linkAdrReq->GetNbTrans());
402 rxParamSetupReq->GetRx2DataRate(),
403 rxParamSetupReq->GetFrequency());
416 newChannelReq->GetFrequency(),
417 newChannelReq->GetMinDataRate(),
418 newChannelReq->GetMaxDataRate());
490std::vector<Ptr<LogicalLoraChannel>>
495 std::vector<Ptr<LogicalLoraChannel>> candidates;
498 if (channel && channel->IsEnabledForUplink())
500 uint8_t minDr = channel->GetMinimumDataRate();
501 uint8_t maxDr = channel->GetMaximumDataRate();
503 NS_LOG_DEBUG(
"Enabled channel: frequency=" << channel->GetFrequency()
504 <<
"Hz, minDr=" <<
unsigned(minDr)
505 <<
", maxDr=" <<
unsigned(maxDr)
506 <<
", maxTxPower=" << maxTxPower <<
"dBm");
509 candidates.emplace_back(channel);
525 NS_LOG_DEBUG(
"frequency=" << channel->GetFrequency() <<
"Hz,"
526 <<
" waitTime=" << curr.As(
Time::S));
540 std::vector<Ptr<LogicalLoraChannel>> candidates;
545 candidates.emplace_back(channel);
548 if (candidates.empty())
553 uint8_t i =
m_uniformRV->GetInteger(0, candidates.size() - 1);
554 auto channel = candidates.at(i);
555 NS_LOG_DEBUG(
"Selected channel with frequency=" << channel->GetFrequency() <<
"Hz");
666 NS_LOG_FUNCTION(
this <<
unsigned(dataRate) <<
unsigned(txPower) << std::bitset<16>(chMask)
667 <<
unsigned(chMaskCntl) <<
unsigned(nbTrans));
672 NS_ASSERT_MSG(!(dataRate & 0xF0),
"dataRate field > 4 bits");
674 NS_ASSERT_MSG(!(chMaskCntl & 0xF8),
"chMaskCntl field > 3 bits");
679 bool channelMaskAck =
true;
680 bool dataRateAck =
true;
681 bool powerAck =
true;
683 NS_LOG_DEBUG(
"Channel mask = " << std::bitset<16>(chMask)
684 <<
", ChMaskCtrl = " <<
unsigned(chMaskCntl));
692 for (
size_t i = 0; i < channels.size(); ++i)
694 if ((chMask & 0b1 << i) && !channels.at(i))
697 channelMaskAck =
false;
705 for (
size_t i = 0; i < channels.size(); ++i)
715 channelMaskAck =
false;
723 channelMaskAck =
false;
732 bool compatible =
false;
734 for (
size_t i = 0; i < channels.size(); ++i)
736 if ((chMask & 0b1 << i) &&
m_dataRate >= channels.at(i)->GetMinimumDataRate() &&
737 m_dataRate <= channels.at(i)->GetMaximumDataRate())
745 NS_LOG_WARN(
"Invalid channel mask for current device data rate (ADR off)");
746 channelMaskAck = dataRateAck = powerAck =
false;
750 for (
size_t i = 0; i < channels.size(); ++i)
752 if (
auto c = channels.at(i); c)
754 (chMask & 0b1 << i) ? c->EnableForUplink() : c->DisableForUplink();
757 dataRateAck = powerAck =
false;
763 dataRateAck = powerAck =
false;
770 bool compatible =
false;
772 for (
size_t i = 0; i < channels.size(); ++i)
774 if (chMask & 0b1 << i)
776 if (
const auto& c = channels.at(i); c)
778 if (dataRate >= c->GetMinimumDataRate() &&
779 dataRate <= c->GetMaximumDataRate())
814 if (channelMaskAck && dataRateAck && powerAck)
816 for (
size_t i = 0; i < channels.size(); ++i)
818 if (
auto c = channels.at(i); c)
820 (chMask & 0b1 << i) ? c->EnableForUplink() : c->DisableForUplink();
827 m_nbTrans = (nbTrans == 0) ? 1 : nbTrans;
846 NS_ASSERT_MSG(!(maxDutyCycle & 0xF0),
"maxDutyCycle > 4 bits");
857 uint8_t battery = 255;
861 sc && sc->
GetN() == 1)
863 battery = sc->Get(0)->GetEnergyFraction() * 253 + 1.5;
874 snr = snr < -32 ? -32 : snr > 31 ? 31 : snr;
876 uint8_t margin = std::bitset<6>(snr).to_ulong();
888 NS_LOG_FUNCTION(
this <<
unsigned(chIndex) << frequencyHz <<
unsigned(minDataRate)
889 <<
unsigned(maxDataRate));
891 NS_ASSERT_MSG(!(minDataRate & 0xF0),
"minDataRate field > 4 bits");
892 NS_ASSERT_MSG(!(maxDataRate & 0xF0),
"maxDataRate field > 4 bits");
897 bool dataRateRangeOk =
true;
898 bool channelFrequencyOk =
true;
901 if (chIndex < 3 || chIndex >
m_channelHelper->GetRawChannelArray().size() - 1)
904 dataRateRangeOk = channelFrequencyOk =
false;
908 if (frequencyHz != 0 && !
m_channelHelper->IsFrequencyValid(frequencyHz))
911 channelFrequencyOk =
false;
918 dataRateRangeOk =
false;
924 dataRateRangeOk =
false;
927 if (maxDataRate < minDataRate)
930 dataRateRangeOk =
false;
933 if (dataRateRangeOk && channelFrequencyOk)
936 (frequencyHz == 0) ? channel->DisableForUplink() : channel->EnableForUplink();
938 NS_LOG_DEBUG(
"MacTxFrequency[" <<
unsigned(chIndex) <<
"]=" << frequencyHz
939 <<
", DrMin=" <<
unsigned(minDataRate)
940 <<
", DrMax=" <<
unsigned(maxDataRate));
Hold variables of type enum.
An identifier for simulation events.
Hold a signed integer type.
Smart pointer class similar to boost::intrusive_ptr.
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
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...
Simulation virtual time values and global simulation resolution.
TimeWithUnit As(const Unit unit=Time::AUTO) const
Attach a unit to a Time, to facilitate output in a specific unit.
bool IsStrictlyPositive() const
Exactly equivalent to t > 0.
static Time Max()
Maximum representable Time Not to be confused with Max(Time,Time).
a unique identifier for an interface.
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Hold an unsigned integer type.
Holds a vector of ns3::EnergySource pointers.
uint32_t GetN() const
Get the number of Ptr<EnergySource> stored in this container.
Class representing the MAC layer of a LoRaWAN device.
LorawanMacHeader::MType m_mType
The message type to apply to packets sent with the Send method.
Ptr< LogicalLoraChannel > GetRandomChannelForTx()
Find a suitable channel for transmission.
virtual void ResetRetransmissionParameters()
Reset retransmission parameters contained in the structure LoraRetxParams.
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...
bool m_headerDisabled
Whether or not the LoRa PHY header is disabled for communications by this device.
void OnLinkAdrReq(uint8_t dataRate, uint8_t txPower, uint16_t chMask, uint8_t chMaskCntl, uint8_t nbTrans)
Perform the actions that need to be taken when receiving a LinkAdrReq command.
void OnDutyCycleReq(uint8_t maxDutyCycle)
Perform the actions that need to be taken when receiving a DutyCycleReq command.
TracedValue< double > m_txPowerDbm
The transmission ERP [dBm] this device is currently using.
virtual void PostponeTransmission(Time nextTxDelay, Ptr< Packet > packet)
Postpone transmission to the specified time and delete previously scheduled transmissions if present.
~EndDeviceLorawanMac() override
Destructor.
virtual void SendToPhy(Ptr< Packet > packet)
Add headers and send a packet with the sending function of the physical layer.
double GetTransmissionPowerDbm()
Get the transmission power this end device is set to use.
bool m_adr
Uplink ADR bit contained in the FCtrl field of the LoRaWAN FHDR.
void TxFinished(Ptr< const Packet > packet) override
Perform actions after sending a packet.
void SetUplinkAdrBit(bool adr)
Signals to the network server that this device will or may not comply with LinkADRReq settings (data ...
bool m_adrAckReq
ADRACKReq bit, set to 1 after ADR_ACK_LIMIT consecutive uplinks without downlink messages received fr...
Ptr< UniformRandomVariable > m_uniformRV
An uniform random variable, used to randomly pick from the channel list.
static constexpr uint16_t ADR_ACK_DELAY
ADRACKCnt threshold for ADR backoff action.
static TypeId GetTypeId()
Register this type.
uint8_t GetLastKnownLinkMarginDb() const
Get the last known link margin from the demodulation floor.
TracedValue< double > m_aggregatedDutyCycle
The aggregated duty cycle this device needs to respect across all sub-bands.
double GetAggregatedDutyCycle()
Get the aggregated duty cycle.
void Receive(Ptr< const Packet > packet) override
Receive a packet from the lower layer.
void SetMType(LorawanMacHeader::MType mType)
Set the message type to send when the Send method is called.
uint16_t m_adrAckCnt
ADRACKCnt counter of the number of consecutive uplinks without downlink reply from the server.
std::vector< Ptr< LogicalLoraChannel > > GetCompatibleTxChannels()
Get the set of active transmission channels compatible with the current device data rate and transmis...
void ParseCommands(LoraFrameHeader frameHeader)
Parse and take action on the commands contained on this FrameHeader.
bool IsPayloadSizeValid(uint32_t appPayloadSize, uint8_t dataRate)
Check whether the size of the application payload is under the maximum allowed.
virtual void OnRxParamSetupReq(uint8_t rx1DrOffset, uint8_t rx2DataRate, double frequencyHz)=0
Perform the actions that need to be taken when receiving a RxParamSetupReq command based on the Devic...
CodingRate m_codingRate
The coding rate used by this device.
void OnNewChannelReq(uint8_t chIndex, uint32_t frequencyHz, uint8_t minDataRate, uint8_t maxDataRate)
Perform the actions that need to be taken when receiving a NewChannelReq command.
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.
uint8_t GetMaxNumberOfTransmissions()
Get the max number of unacknowledged redundant transmissions of each packet.
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 SetMaxNumberOfTransmissions(uint8_t nbTrans)
Set the max number of unacknowledged redundant transmissions of each packet.
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.
bool GetUplinkAdrBit() const
Get the current value of the device's uplink ADR bit of the LoRaWAN FHDR.
void Send(Ptr< Packet > packet) override
Send a packet.
uint16_t m_currentFCnt
current value of the device frame counter.
EndDeviceLorawanMac()
Default constructor.
uint8_t GetLastKnownGatewayCount() const
Get the last known number of gateways concurrently receiving transmissions from the device.
void AddMacCommand(Ptr< MacCommand > macCommand)
Add a MAC command to the list of those that will be sent out in the next packet.
static constexpr uint16_t ADR_ACK_LIMIT
ADRACKCnt threshold for setting ADRACKReq.
Time GetNextTransmissionDelay()
Find the base minimum wait time before the next possible transmission.
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.
double m_lastRxSnr
Used to record the last reception SNR measurement to be included in the DevStatusAns.
TracedValue< uint8_t > m_lastKnownGatewayCount
The last known gateway count (i.e., gateways that are in communication range with this end device).
uint8_t m_nbTrans
Default number of unacknowledged redundant transmissions of each packet.
void SetDataRate(uint8_t dataRate)
Set the data rate this end device will use when transmitting.
uint8_t m_receiveWindowDurationInSymbols
The duration of a receive window in number of symbols.
TracedValue< uint8_t > m_lastKnownLinkMarginDb
The last known link margin in dB from the demodulation floor.
void SetTransmissionPowerDbm(double txPowerDbm)
Set the transmission power of this end device.
uint8_t GetDataRate()
Get the data rate this end device is set to use.
virtual Time GetNextClassTransmissionDelay(Time waitTime)
Find the minimum wait time before the next possible transmission based on end device's Class Type.
void ExecuteADRBackoff()
Execute ADR backoff as in LoRaWAN specification, V1.0.4 (2020).
void SetDeviceAddress(LoraDeviceAddress address)
Set the network address of this device.
struct LoraRetxParameters m_retxParams
Structure containing the retransmission parameters for this device.
This class represents the device address of a LoraWAN end device.
TracedCallback< Ptr< const Packet > > m_cannotSendBecauseDutyCycle
The trace source that is fired when a packet cannot be sent because of duty cycle limitations.
LorawanMac()
Default constructor.
double GetDbmForTxPower(uint8_t txPower)
Get the transmission power in dBm that corresponds, in this region, to the encoded 8-bit txPower.
uint8_t GetSfFromDataRate(uint8_t dataRate)
Get the spreading factor corresponding to a data rate, based on this MAC's region.
double GetBandwidthFromDataRate(uint8_t dataRate)
Get the bandwidth corresponding to a data rate, based on this MAC's region.
std::vector< uint32_t > m_maxMacPayloadForDataRate
A vector holding the maximum MACPayload size that corresponds to a certain data rate.
Ptr< LogicalLoraChannelHelper > m_channelHelper
The LogicalLoraChannelHelper instance that is assigned to this MAC.
TracedCallback< Ptr< const Packet > > m_sentNewPacket
Trace source that is fired when a new APP layer packet arrives at the MAC layer.
Ptr< NetDevice > m_device
The device this MAC layer is installed on.
static uint8_t GetCIDFromMacCommand(enum MacCommandType commandType)
Get the CID that corresponds to a type of MAC command.
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
#define NS_LOG_ERROR(msg)
Use NS_LOG to output a message of level LOG_ERROR.
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
#define NS_LOG_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
#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.
#define NS_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
CodingRate
Enumeration of the LoRa supported coding rates.
Ptr< T > CreateObject(Args &&... args)
Create an object by type, with varying number of constructor parameters.
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Ptr< T > Create(Ts &&... args)
Create class instances by constructors with varying numbers of arguments and return them by Ptr.
Time Now()
create an ns3::Time instance which contains the current simulation time.
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.
Every class exported by the ns3 library is enclosed in the ns3 namespace.
Ptr< const AttributeChecker > MakeBooleanChecker()
Ptr< const AttributeChecker > MakeIntegerChecker()
Ptr< const AttributeAccessor > MakeIntegerAccessor(T1 a1)
Ptr< const AttributeChecker > MakeUintegerChecker()
Ptr< const AttributeAccessor > MakeUintegerAccessor(T1 a1)
Ptr< const AttributeChecker > MakeEnumChecker(T v, std::string n, Ts... args)
Make an EnumChecker pre-configured with a set of allowed values by name.
Ptr< T1 > DynamicCast(const Ptr< T2 > &p)
Cast a Ptr.
Ptr< const AttributeAccessor > MakeBooleanAccessor(T1 a1)
Ptr< const AttributeAccessor > MakeEnumAccessor(T1 a1)
Structure representing the parameters that will be used in the retransmission procedure.