16#include "ns3/energy-source-container.h"
17#include "ns3/simulator.h"
34 TypeId(
"ns3::EndDeviceLorawanMac")
36 .SetGroupName(
"lorawan")
38 "ConfirmedTransmissionOutcome",
39 "Trace number of retransmissions for acknowledgement of confirmed packets",
41 "ns3::EndDeviceLorawanMac::ConfirmedTxOutcomeCallback")
42 .AddAttribute(
"DataRate",
43 "Data rate currently employed by this end device",
47 .AddTraceSource(
"DataRate",
48 "Data rate currently employed by this end device",
50 "ns3::TracedValueCallback::uint8_t")
53 "Ensure to the network server that this device will accept data rate, transmission "
54 "power and number of retransmissions configurations received via LinkADRReq. This "
55 "also allows the device's local ADR backoff procedure to reset configurations in "
56 "case of connectivity loss.",
60 .AddTraceSource(
"TxPower",
61 "Transmission ERP [dBm] currently employed by this end device",
63 "ns3::TracedValueCallback::Double")
64 .AddTraceSource(
"LastKnownLinkMargin",
65 "Last known demodulation margin in "
66 "communications between this end device "
69 "ns3::TracedValueCallback::uint8_t")
70 .AddTraceSource(
"LastKnownGatewayCount",
71 "Last known number of gateways able to "
72 "listen to this end device",
74 "ns3::TracedValueCallback::uint8_t")
75 .AddTraceSource(
"AggregatedDutyCycle",
76 "Aggregate duty cycle, in fraction form, "
77 "this end device must respect",
79 "ns3::TracedValueCallback::Double")
80 .AddAttribute(
"MaxTransmissions",
81 "Maximum number of transmissions for a packet (NbTrans)",
85 .AddAttribute(
"FType",
86 "Specify type of message will be sent by this end device.",
136 NS_LOG_ERROR(
"Packet cannot be sent in the current device state, transmission aborted.");
147 NS_LOG_WARN(
"Attempting to send, but device is busy or duty cycle won't allow it. "
148 "Rescheduling a tx in "
173 for (
auto& c : tmpTxChannels)
195 NS_LOG_WARN(
"Application payload exceeding maximum size.");
201 tmpTxChannels.empty())
203 NS_LOG_WARN(
"No tx channel compatible with current DR/power.");
348 std::vector<Ptr<LogicalLoraChannel>> candidates;
349 for (
const auto& c : compatible)
353 candidates.emplace_back(c);
356 if (candidates.empty())
361 uint8_t i =
m_uniformRV->GetInteger(0, candidates.size() - 1);
362 auto channel = candidates.at(i);
363 NS_LOG_DEBUG(
"Selected channel with frequency=" << channel->GetFrequency() <<
"Hz");
381 OnLinkCheckAns(linkCheckAns->GetMargin(), linkCheckAns->GetGwCnt());
388 linkAdrReq->GetTxPower(),
389 linkAdrReq->GetChMask(),
390 linkAdrReq->GetChMaskCntl(),
391 linkAdrReq->GetNbTrans());
404 rxParamSetupReq->GetRx2DataRate(),
405 rxParamSetupReq->GetFrequency());
418 newChannelReq->GetFrequency(),
419 newChannelReq->GetMinDataRate(),
420 newChannelReq->GetMaxDataRate());
457 txChannelArray.at(0)->EnableForUplink();
458 txChannelArray.at(1)->EnableForUplink();
459 txChannelArray.at(2)->EnableForUplink();
469 fOptsLen += c->GetSerializedSize();
472 uint32_t macPayloadSize = 7 + fOptsLen + 1 + appPayloadSize;
474 NS_LOG_DEBUG(
"macPayloadSize=" << macPayloadSize <<
"B, maxMacPayloadForDataRate="
475 << maxMacPayloadForDataRate <<
"B");
476 return macPayloadSize <= maxMacPayloadForDataRate;
479std::vector<Ptr<LogicalLoraChannel>>
483 double txPowerDbm)
const
487 std::vector<Ptr<LogicalLoraChannel>> candidates;
488 for (
const auto& channel : txChannelArray)
490 if (channel && channel->IsEnabledForUplink())
492 uint8_t minDr = channel->GetMinimumDataRate();
493 uint8_t maxDr = channel->GetMaximumDataRate();
495 NS_LOG_DEBUG(
"Enabled channel: frequency=" << channel->GetFrequency()
496 <<
"Hz, minDr=" <<
unsigned(minDr)
497 <<
", maxDr=" <<
unsigned(maxDr)
498 <<
", maxTxPower=" << maxTxPower <<
"dBm");
499 if (dataRate >= minDr && dataRate <= maxDr && txPowerDbm <= maxTxPower)
501 candidates.emplace_back(channel);
515 for (
const auto& c : txChannelArray)
518 NS_LOG_LOGIC(
"frequency=" << c->GetFrequency() <<
"Hz, "
519 <<
"waitTime=" << channelWait.As(
Time::S));
520 waitTime =
Min(waitTime, channelWait);
542 NS_LOG_DEBUG(
"New FRMPayload from application: " << packet->GetSize() <<
"B");
554 NS_LOG_WARN(
"Previous packet not acknowledged, used "
555 <<
unsigned(txs) <<
" transmissions out of " <<
unsigned(
m_nbTrans));
577 packet->RemoveHeader(macHdr);
579 packet->RemoveHeader(frameHdr);
596 packet->AddHeader(frameHdr);
601 packet->AddHeader(macHdr);
687 NS_LOG_FUNCTION(
this <<
unsigned(dataRate) <<
unsigned(txPower) << std::bitset<16>(chMask)
688 <<
unsigned(chMaskCntl) <<
unsigned(nbTrans));
693 NS_ASSERT_MSG(!(dataRate & 0xF0),
"dataRate field > 4 bits");
695 NS_ASSERT_MSG(!(chMaskCntl & 0xF8),
"chMaskCntl field > 3 bits");
700 bool channelMaskAck =
true;
701 bool dataRateAck =
true;
702 bool powerAck =
true;
704 NS_LOG_DEBUG(
"Channel mask = " << std::bitset<16>(chMask)
705 <<
", ChMaskCtrl = " <<
unsigned(chMaskCntl));
713 for (
size_t i = 0; i < channels.size(); ++i)
715 if ((chMask & 0b1 << i) && !channels.at(i))
718 channelMaskAck =
false;
726 for (
size_t i = 0; i < channels.size(); ++i)
736 channelMaskAck =
false;
744 channelMaskAck =
false;
753 bool compatible =
false;
755 for (
size_t i = 0; i < channels.size(); ++i)
757 if ((chMask & 0b1 << i) &&
m_dataRate >= channels.at(i)->GetMinimumDataRate() &&
758 m_dataRate <= channels.at(i)->GetMaximumDataRate())
766 NS_LOG_WARN(
"Invalid channel mask for current device data rate (ADR off)");
767 channelMaskAck = dataRateAck = powerAck =
false;
771 for (
size_t i = 0; i < channels.size(); ++i)
773 if (
auto c = channels.at(i); c)
775 (chMask & 0b1 << i) ? c->EnableForUplink() : c->DisableForUplink();
778 dataRateAck = powerAck =
false;
784 dataRateAck = powerAck =
false;
791 bool compatible =
false;
793 for (
size_t i = 0; i < channels.size(); ++i)
795 if (chMask & 0b1 << i)
797 if (
const auto& c = channels.at(i); c)
799 if (dataRate >= c->GetMinimumDataRate() &&
800 dataRate <= c->GetMaximumDataRate())
835 if (channelMaskAck && dataRateAck && powerAck)
837 for (
size_t i = 0; i < channels.size(); ++i)
839 if (
auto c = channels.at(i); c)
841 (chMask & 0b1 << i) ? c->EnableForUplink() : c->DisableForUplink();
848 m_nbTrans = (nbTrans == 0) ? 1 : nbTrans;
867 NS_ASSERT_MSG(!(maxDutyCycle & 0xF0),
"maxDutyCycle > 4 bits");
878 uint8_t battery = 255;
882 sc && sc->
GetN() == 1)
884 battery = sc->Get(0)->GetEnergyFraction() * 253 + 1.5;
895 snr = snr < -32 ? -32 : snr > 31 ? 31 : snr;
897 uint8_t margin = std::bitset<6>(snr).to_ulong();
909 NS_LOG_FUNCTION(
this <<
unsigned(chIndex) << frequencyHz <<
unsigned(minDataRate)
910 <<
unsigned(maxDataRate));
912 NS_ASSERT_MSG(!(minDataRate & 0xF0),
"minDataRate field > 4 bits");
913 NS_ASSERT_MSG(!(maxDataRate & 0xF0),
"maxDataRate field > 4 bits");
918 bool dataRateRangeOk =
true;
919 bool channelFrequencyOk =
true;
922 if (chIndex < 3 || chIndex >
m_channelHelper->GetRawChannelArray().size() - 1)
925 dataRateRangeOk = channelFrequencyOk =
false;
929 if (frequencyHz != 0 && !
m_channelHelper->IsFrequencyValid(frequencyHz))
932 channelFrequencyOk =
false;
939 dataRateRangeOk =
false;
945 dataRateRangeOk =
false;
948 if (maxDataRate < minDataRate)
951 dataRateRangeOk =
false;
954 if (dataRateRangeOk && channelFrequencyOk)
957 (frequencyHz == 0) ? channel->DisableForUplink() : channel->EnableForUplink();
959 NS_LOG_DEBUG(
"MacTxFrequency[" <<
unsigned(chIndex) <<
"]=" << frequencyHz
960 <<
", DrMin=" <<
unsigned(minDataRate)
961 <<
", 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 Time Now()
Return the current simulation virtual time.
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.
virtual void SendToPhy(Ptr< Packet > packet)=0
Gather PHY transmission parameters and send a packet through the LoRa physical layer.
bool IsPayloadSizeValid(uint32_t appPayloadSize, uint8_t dataRate) const
Check whether the size of the application payload is under the maximum allowed.
Time GetNextTransmissionDelay(const std::vector< Ptr< LogicalLoraChannel > > &txChannelArray) const
Find the base minimum wait time before the next possible transmission based on channels legal duty cy...
Ptr< LogicalLoraChannel > GetRandomChannelForTx()
Find a suitable channel for transmission.
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.
void PostponeTransmission(Time nextTxDelay, Ptr< Packet > packet)
Postpone transmission to the specified time.
~EndDeviceLorawanMac() override
Destructor.
double GetTransmissionPowerDbm()
Get the transmission power this end device is set to use.
uint16_t GetUplinkFrameCounter() const
Get the current value of the LoRaWAN uplink frame counter (FCnt) of this device.
bool m_adr
Uplink ADR bit contained in the FCtrl field of the LoRaWAN FHDR.
void SetUplinkAdrBit(bool adr)
Signals to the network server that this device will or may not comply with LinkADRReq settings (data ...
TracedCallback< uint8_t, bool, Time, Ptr< Packet > > m_confirmedTxOutcomeCallback
Traced Callback: confirmed transmission process outcome event.
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 and to sample random retransm...
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.
LorawanMacHeader::FType GetFType()
Get the frame type to send when the Send method is called.
double GetAggregatedDutyCycle()
Get the aggregated duty cycle.
uint16_t m_adrAckCnt
ADRACKCnt counter of the number of consecutive uplinks without downlink reply from the server.
void ApplyMACCommands(LoraFrameHeader frameHeader)
Take action on the commands contained on this FrameHeader.
static void DoExecuteADRBackoff(double &txPowerDbm, uint8_t &dataRate, uint8_t &nbTrans, const std::vector< Ptr< LogicalLoraChannel > > &txChannelArray)
Apply ADR backoff as in LoRaWAN specification, V1.0.4 (2020) on the provided input parameters passed ...
virtual Time GetNextClassTransmissionDelay() const =0
Find the minimum wait time before the next possible transmission based on end device's Class Type sch...
void SetFType(LorawanMacHeader::FType fType)
Set the frame type to send when the Send method is called.
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...
std::vector< Ptr< LogicalLoraChannel > > GetCompatibleTxChannels(const std::vector< Ptr< LogicalLoraChannel > > &txChannelArray, uint8_t dataRate, double txPowerDbm) const
Get the set of active transmission channels among the provided array which are compatible with the a ...
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.
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 transmitting a packet at a later moment.
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 LoRaWAN address of this device.
bool GetUplinkAdrBit() const
Get the current value of the device's uplink ADR bit of the LoRaWAN FHDR.
PacketTxContext m_txContext
Structure containing the transmission context for the last packet sent by this device,...
void Send(Ptr< Packet > packet) override
Send a packet.
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.
virtual void DoSend(Ptr< Packet > packet)
Perform operations to update the MAC layer with the new packet context and call SendToPhy function.
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
Record latest reception SNR measurement to provide via DevStatusAns.
TracedValue< uint8_t > m_lastKnownGatewayCount
Last known number of gateways in range of this end device, obtained via LinkCheckReq.
uint8_t m_nbTrans
Default number of repeated 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 reception windows in number of symbols.
TracedValue< uint8_t > m_lastKnownLinkMarginDb
Last known best link margin [dB] from the demodulation floor, obtained via LinkCheckReq.
LorawanMacHeader::FType m_fType
The frame type to apply to packets sent with the Send method.
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.
bool ValidatePacketForSend(Ptr< const Packet > packet, Time &nextTxDelay) const
Evaluate whether this packet can be sent in the current device state.
void ExecuteADRBackoff()
Execute ADR backoff as in LoRaWAN specification, V1.0.4 (2020) on this device.
void SetDeviceAddress(LoraDeviceAddress address)
Set the network address of this device.
uint16_t m_fCnt
Current value of the uplink frame counter.
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.
std::vector< uint32_t > m_maxMacPayloadForDataRate
A vector holding the maximum MACPayload size that corresponds to a certain data rate.
uint32_t GetBandwidthFromDataRate(uint8_t dataRate) const
Get the bandwidth corresponding to a data rate, based on this MAC's region.
uint8_t GetSfFromDataRate(uint8_t dataRate) const
Get the spreading factor corresponding to a data rate, based on this MAC's region.
Ptr< LogicalLoraChannelHelper > m_channelHelper
The LogicalLoraChannelHelper instance that is assigned to this MAC.
double GetDbmForTxPower(uint8_t txPower) const
Get the transmission power in dBm that corresponds, in this region, to the encoded 8-bit txPower.
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.
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< T > Copy(Ptr< T > object)
Return a deep copy of a Ptr.
Ptr< const AttributeAccessor > MakeBooleanAccessor(T1 a1)
Ptr< const AttributeAccessor > MakeEnumAccessor(T1 a1)
Current packet transmission context tracking transmissions attempts mandated by the protocol.