A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
class-a-end-device-lorawan-mac.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2017 University of Padova
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 * Author: Davide Magrin <magrinda@dei.unipd.it>
7 * Martina Capuzzo <capuzzom@dei.unipd.it>
8 *
9 * Modified by: Peggy Anderson <peggy.anderson@usask.ca>
10 * qiuyukang <b612n@qq.com>
11 */
12
14
15#include "end-device-lora-phy.h"
17#include "lora-tag.h"
18
19#include "ns3/log.h"
20
21namespace ns3
22{
23namespace lorawan
24{
25
26NS_LOG_COMPONENT_DEFINE("ClassAEndDeviceLorawanMac");
27
28NS_OBJECT_ENSURE_REGISTERED(ClassAEndDeviceLorawanMac);
29
30TypeId
32{
33 static TypeId tid = TypeId("ns3::ClassAEndDeviceLorawanMac")
35 .SetGroupName("lorawan")
36 .AddConstructor<ClassAEndDeviceLorawanMac>();
37 return tid;
38}
39
41 : // LoraWAN default
42 m_receiveDelay1(Seconds(1)),
43 // LoraWAN default
44 m_receiveDelay2(Seconds(2)),
45 m_rx1DrOffset(0)
46{
47 NS_LOG_FUNCTION(this);
48
49 // Void the two receiveWindow events
56}
57
62
63/////////////////////
64// Sending methods //
65/////////////////////
66
67void
69{
70 /////////////////////////////////////////////////////////
71 // Add headers, prepare TX parameters and send the packet
72 /////////////////////////////////////////////////////////
73
74 NS_LOG_DEBUG("PacketToSend: " << packetToSend);
75
76 // Data rate adaptation as in LoRaWAN specification, V1.0.2 (2016)
78 (m_retxParams.retxLeft % 2 == 0))
79 {
80 m_txPowerDbm = 14; // Reset transmission power
82 }
83
84 // Craft LoraTxParameters object
85 LoraTxParameters params;
86 params.sf = GetSfFromDataRate(m_dataRate);
87 params.headerDisabled = m_headerDisabled;
88 params.codingRate = m_codingRate;
89 params.bandwidthHz = GetBandwidthFromDataRate(m_dataRate);
90 params.nPreamble = m_nPreambleSymbols;
91 params.crcEnabled = true;
92 params.lowDataRateOptimizationEnabled = LoraPhy::GetTSym(params) > MilliSeconds(16);
93
94 // Wake up PHY layer and directly send the packet
95
97
98 NS_LOG_DEBUG("PacketToSend: " << packetToSend);
99 m_phy->Send(packetToSend, params, txChannel->GetFrequency(), m_txPowerDbm);
100
101 //////////////////////////////////////////////
102 // Register packet transmission for duty cycle
103 //////////////////////////////////////////////
104
105 // Compute packet duration
106 Time duration = LoraPhy::GetOnAirTime(packetToSend, params);
107
108 // Register the sent packet into the DutyCycleHelper
109 m_channelHelper->AddEvent(duration, txChannel);
110
111 //////////////////////////////
112 // Prepare for the downlink //
113 //////////////////////////////
114
115 // Switch the PHY to the channel so that it will listen here for downlink
116 DynamicCast<EndDeviceLoraPhy>(m_phy)->SetFrequency(txChannel->GetFrequency());
117
118 // Instruct the PHY on the right Spreading Factor to listen for during the window
119 // create a SetReplyDataRate function?
120 uint8_t replyDataRate = GetFirstReceiveWindowDataRate();
121 NS_LOG_DEBUG("m_dataRate: " << unsigned(m_dataRate)
122 << ", m_rx1DrOffset: " << unsigned(m_rx1DrOffset)
123 << ", replyDataRate: " << unsigned(replyDataRate) << ".");
124
125 DynamicCast<EndDeviceLoraPhy>(m_phy)->SetSpreadingFactor(GetSfFromDataRate(replyDataRate));
126}
127
128//////////////////////////
129// Receiving methods //
130//////////////////////////
131void
133{
134 NS_LOG_FUNCTION(this << packet);
135
136 // Work on a copy of the packet
137 Ptr<Packet> packetCopy = packet->Copy();
138
139 // Remove the Mac Header to get some information
140 LorawanMacHeader mHdr;
141 packetCopy->RemoveHeader(mHdr);
142
143 NS_LOG_DEBUG("Mac Header: " << mHdr);
144
145 // Only keep analyzing the packet if it's downlink
146 if (!mHdr.IsUplink())
147 {
148 NS_LOG_INFO("Found a downlink packet.");
149
150 // Remove the Frame Header
151 LoraFrameHeader fHdr;
152 fHdr.SetAsDownlink();
153 packetCopy->RemoveHeader(fHdr);
154
155 NS_LOG_DEBUG("Frame Header: " << fHdr);
156
157 // Determine whether this packet is for us
158 bool messageForUs = (m_address == fHdr.GetAddress());
159
160 if (messageForUs)
161 {
162 NS_LOG_INFO("The message is for us!");
163
164 // If it exists, cancel the second receive window event
165 // THIS WILL BE GetReceiveWindow()
167
168 LoraTag tag;
169 packet->PeekPacketTag(tag);
170 /// @see ns3::lorawan::AdrComponent::RxPowerToSNR
171 m_lastRxSnr = tag.GetReceivePower() + 174 - 10 * log10(125000) - 6;
172
173 // Parse the MAC commands
174 ParseCommands(fHdr);
175
176 // TODO Pass the packet up to the NetDevice
177
178 // Call the trace source
179 m_receivedPacket(packet);
180 }
181 else
182 {
183 NS_LOG_DEBUG("The message is intended for another recipient.");
184
185 // In this case, we are either receiving in the first receive window
186 // and finishing reception inside the second one, or receiving a
187 // packet in the second receive window and finding out, after the
188 // fact, that the packet is not for us. In either case, if we no
189 // longer have any retransmissions left, we declare failure.
191 {
192 if (m_retxParams.retxLeft == 0)
193 {
194 uint8_t txs = m_nbTrans - (m_retxParams.retxLeft);
196 false,
199 NS_LOG_DEBUG("Failure: no more retransmissions left. Used "
200 << unsigned(txs) << " transmissions.");
201
202 // Reset retransmission parameters
204 }
205 else // Reschedule
206 {
207 this->Send(m_retxParams.packet);
208 NS_LOG_INFO("We have " << unsigned(m_retxParams.retxLeft)
209 << " retransmissions left: rescheduling transmission.");
210 }
211 }
212 }
213 }
215 {
216 NS_LOG_INFO("The packet we are receiving is in uplink.");
217 if (m_retxParams.retxLeft > 0)
218 {
219 this->Send(m_retxParams.packet);
220 NS_LOG_INFO("We have " << unsigned(m_retxParams.retxLeft)
221 << " retransmissions left: rescheduling transmission.");
222 }
223 else
224 {
225 uint8_t txs = m_nbTrans - (m_retxParams.retxLeft);
227 NS_LOG_DEBUG("Failure: no more retransmissions left. Used " << unsigned(txs)
228 << " transmissions.");
229
230 // Reset retransmission parameters
232 }
233 }
234
235 DynamicCast<EndDeviceLoraPhy>(m_phy)->SwitchToSleep();
236}
237
238void
240{
241 NS_LOG_FUNCTION(this << packet);
242
243 // Switch to sleep after a failed reception
244 DynamicCast<EndDeviceLoraPhy>(m_phy)->SwitchToSleep();
245
247 {
248 if (m_retxParams.retxLeft > 0)
249 {
250 this->Send(m_retxParams.packet);
251 NS_LOG_INFO("We have " << unsigned(m_retxParams.retxLeft)
252 << " retransmissions left: rescheduling transmission.");
253 }
254 else
255 {
256 uint8_t txs = m_nbTrans - (m_retxParams.retxLeft);
258 NS_LOG_DEBUG("Failure: no more retransmissions left. Used " << unsigned(txs)
259 << " transmissions.");
260
261 // Reset retransmission parameters
263 }
264 }
265}
266
267void
269{
271
272 // Schedule the opening of the first receive window
274
275 // Schedule the opening of the second receive window
278 this);
279 // // Schedule the opening of the first receive window
280 // Simulator::Schedule (m_receiveDelay1,
281 // &ClassAEndDeviceLorawanMac::OpenFirstReceiveWindow, this);
282 //
283 // // Schedule the opening of the second receive window
284 // m_secondReceiveWindow = Simulator::Schedule (m_receiveDelay2,
285 // &ClassAEndDeviceLorawanMac::OpenSecondReceiveWindow,
286 // this);
287
288 // Switch the PHY to sleep
289 DynamicCast<EndDeviceLoraPhy>(m_phy)->SwitchToSleep();
290}
291
292void
294{
296
297 // Set Phy in Standby mode
298 DynamicCast<EndDeviceLoraPhy>(m_phy)->SwitchToStandby();
299
300 // Calculate the duration of a single symbol for the first receive window data rate
301 double tSym = pow(2, GetSfFromDataRate(GetFirstReceiveWindowDataRate())) /
303
304 // Schedule return to sleep after "at least the time required by the end
305 // device's radio transceiver to effectively detect a downlink preamble"
306 // (LoraWAN specification)
309 this); // m_receiveWindowDuration
310}
311
312void
314{
316
318
319 // Check the Phy layer's state:
320 // - RX -> We are receiving a preamble.
321 // - STANDBY -> Nothing was received.
322 // - SLEEP -> We have received a packet.
323 // We should never be in TX or SLEEP mode at this point
324 switch (phy->GetState())
325 {
327 NS_ABORT_MSG("PHY was in TX mode when attempting to close a receive window.");
328 break;
330 // PHY is receiving: let it finish. The Receive method will switch it back to SLEEP.
332 // PHY has received, and the MAC's Receive already put the device to sleep
333 break;
335 // Turn PHY layer to SLEEP
336 phy->SwitchToSleep();
337 break;
338 }
339}
340
341void
343{
345
346 // Check for receiver status: if it's locked on a packet, don't open this
347 // window at all.
349 {
350 NS_LOG_INFO("Won't open second receive window since we are in RX mode.");
351
352 return;
353 }
354
355 // Set Phy in Standby mode
356 DynamicCast<EndDeviceLoraPhy>(m_phy)->SwitchToStandby();
357
358 // Switch to appropriate channel and data rate
359 NS_LOG_INFO("Using parameters: " << m_secondReceiveWindowFrequencyHz << " Hz, DR"
360 << unsigned(m_secondReceiveWindowDataRate));
361
363 DynamicCast<EndDeviceLoraPhy>(m_phy)->SetSpreadingFactor(
365
366 // Calculate the duration of a single symbol for the second receive window data rate
367 double tSym = pow(2, GetSfFromDataRate(GetSecondReceiveWindowDataRate())) /
369
370 // Schedule return to sleep after "at least the time required by the end
371 // device's radio transceiver to effectively detect a downlink preamble"
372 // (LoraWAN specification)
375 this);
376}
377
378void
380{
382
384
385 // NS_ASSERT (phy->m_state != EndDeviceLoraPhy::TX &&
386 // phy->m_state != EndDeviceLoraPhy::SLEEP);
387
388 // Check the Phy layer's state:
389 // - RX -> We have received a preamble.
390 // - STANDBY -> Nothing was detected.
391 switch (phy->GetState())
392 {
395 break;
397 // PHY is receiving: let it finish
398 NS_LOG_DEBUG("PHY is receiving: Receive will handle the result.");
399 return;
401 // Turn PHY layer to sleep
402 phy->SwitchToSleep();
403 break;
404 }
405
407 {
408 NS_LOG_DEBUG("No reception initiated by PHY: rescheduling transmission.");
409 if (m_retxParams.retxLeft > 0)
410 {
411 NS_LOG_INFO("We have " << unsigned(m_retxParams.retxLeft)
412 << " retransmissions left: rescheduling transmission.");
413 this->Send(m_retxParams.packet);
414 }
415
416 else if (m_retxParams.retxLeft == 0 &&
418 {
419 uint8_t txs = m_nbTrans - (m_retxParams.retxLeft);
421 NS_LOG_DEBUG("Failure: no more retransmissions left. Used " << unsigned(txs)
422 << " transmissions.");
423
424 // Reset retransmission parameters
426 }
427
428 else
429 {
430 NS_ABORT_MSG("The number of retransmissions left is negative ! ");
431 }
432 }
433 else
434 {
435 uint8_t txs = m_nbTrans - (m_retxParams.retxLeft);
438 "We have " << unsigned(m_retxParams.retxLeft)
439 << " transmissions left. We were not transmitting confirmed messages.");
440
441 // Reset retransmission parameters
443 }
444}
445
446/////////////////////////
447// Getters and Setters //
448/////////////////////////
449
450Time
452{
454
455 // This is a new packet from APP; it can not be sent until the end of the
456 // second receive window (if the second receive window has not closed yet)
458 {
461 {
463 "Attempting to send when there are receive windows: Transmission postponed.");
464 // Compute the duration of a single symbol for the second receive window data rate
465 double tSym = pow(2, GetSfFromDataRate(GetSecondReceiveWindowDataRate())) /
467 // Compute the closing time of the second receive window
468 Time endSecondRxWindow = Time(m_secondReceiveWindow.GetTs()) +
470
471 NS_LOG_DEBUG("Duration until endSecondRxWindow for new transmission:"
472 << (endSecondRxWindow - Now()).As(Time::S));
473 waitTime = Max(waitTime, endSecondRxWindow - Now());
474 }
475 }
476 // This is a retransmitted packet, it can not be sent until the end of
477 // ACK_TIMEOUT (this timer starts when the second receive window was open)
478 else
479 {
480 double ack_timeout = m_uniformRV->GetValue(1, 3);
481 // Compute the duration until ACK_TIMEOUT (It may be a negative number, but it doesn't
482 // matter.)
483 Time retransmitWaitTime =
484 Time(m_secondReceiveWindow.GetTs()) - Now() + Seconds(ack_timeout);
485
486 NS_LOG_DEBUG("ack_timeout:" << ack_timeout
487 << " retransmitWaitTime:" << retransmitWaitTime.As(Time::S));
488 waitTime = Max(waitTime, retransmitWaitTime);
489 }
490
491 return waitTime;
492}
493
494uint8_t
499
500void
505
506uint8_t
511
512void
517
523
524/////////////////////////
525// MAC command methods //
526/////////////////////////
527
528void
530 uint8_t rx2DataRate,
531 double frequencyHz)
532{
533 NS_LOG_FUNCTION(this << unsigned(rx1DrOffset) << unsigned(rx2DataRate)
534 << uint32_t(frequencyHz));
535
536 // Adapted from: github.com/Lora-net/SWL2001.git v4.3.1
537 // For the time being, this implementation is valid for the EU868 region
538
539 bool rx1DrOffsetAck = true;
540 bool rx2DataRateAck = true;
541 bool channelAck = true;
542
543 if (rx1DrOffset >= m_replyDataRateMatrix.at(m_dataRate).size())
544 {
545 NS_LOG_WARN("Invalid rx1DrOffset");
546 rx1DrOffsetAck = false;
547 }
548
549 if (!GetSfFromDataRate(rx2DataRate) || !GetBandwidthFromDataRate(rx2DataRate))
550 {
551 NS_LOG_WARN("Invalid rx2DataRate");
552 rx2DataRateAck = false;
553 }
554
555 if (!m_channelHelper->IsFrequencyValid(frequencyHz))
556 {
557 NS_LOG_WARN("Invalid rx2 frequency");
558 channelAck = false;
559 }
560
561 if (rx1DrOffsetAck && rx2DataRateAck && channelAck)
562 {
563 m_rx1DrOffset = rx1DrOffset;
564 m_secondReceiveWindowDataRate = rx2DataRate;
566 }
567
568 NS_LOG_INFO("Adding RxParamSetupAns reply");
569 m_macCommandList.emplace_back(
570 Create<RxParamSetupAns>(rx1DrOffsetAck, rx2DataRateAck, channelAck));
571}
572
573} /* namespace lorawan */
574} /* namespace ns3 */
#define Max(a, b)
An identifier for simulation events.
Definition event-id.h:45
void Cancel()
This method is syntactic sugar for the ns3::Simulator::Cancel method.
Definition event-id.cc:44
bool IsExpired() const
This method is syntactic sugar for the ns3::Simulator::IsExpired method.
Definition event-id.cc:58
uint64_t GetTs() const
Definition event-id.cc:85
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.
Definition simulator.h:560
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:274
Simulation virtual time values and global simulation resolution.
Definition nstime.h:94
TimeWithUnit As(const Unit unit=Time::AUTO) const
Attach a unit to a Time, to facilitate output in a specific unit.
Definition time.cc:404
@ S
second
Definition nstime.h:105
a unique identifier for an interface.
Definition type-id.h:49
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition type-id.cc:1001
Class representing the MAC layer of a Class A LoRaWAN device.
uint8_t m_rx1DrOffset
The RX1DROffset parameter value.
void OpenSecondReceiveWindow()
Perform operations needed to open the second receive window.
uint8_t GetSecondReceiveWindowDataRate() const
Get the data rate that will be used in the second receive window.
Time m_receiveDelay2
The interval between when a packet is done sending and when the second receive window is opened.
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...
uint32_t GetSecondReceiveWindowFrequency() const
Get the frequency that is used for the second receive window.
EventId m_closeFirstWindow
The event of the closing the first receive window.
void SetSecondReceiveWindowFrequency(uint32_t frequencyHz)
Set the frequency that will be used for the second receive window.
uint8_t m_secondReceiveWindowDataRate
The data rate to listen for during the second downlink transmission.
Time m_receiveDelay1
The interval between when a packet is done sending and when the first receive window is opened.
Time GetNextClassTransmissionDelay(Time waitTime) override
Find the minimum wait time before the next possible transmission based on end device's Class Type.
void CloseFirstReceiveWindow()
Perform operations needed to close the first receive window.
void SendToPhy(Ptr< Packet > packet) override
Add headers and send a packet with the sending function of the physical layer.
uint32_t m_secondReceiveWindowFrequencyHz
The frequency [Hz] to listen on for the second receive window.
void TxFinished(Ptr< const Packet > packet) override
Perform the actions that are required after a packet send.
void CloseSecondReceiveWindow()
Perform operations needed to close the second receive window.
void OnRxParamSetupReq(uint8_t rx1DrOffset, uint8_t rx2DataRate, double frequencyHz) override
Perform the actions that need to be taken when receiving a RxParamSetupReq command based on the Devic...
uint8_t GetFirstReceiveWindowDataRate()
Get the data rate that will be used in the first receive window.
EventId m_closeSecondWindow
The event of the closing the second receive window.
EventId m_secondReceiveWindow
The event of the second receive window opening.
void SetSecondReceiveWindowDataRate(uint8_t dataRate)
Set the data rate to be used in the second receive window.
void Receive(Ptr< const Packet > packet) override
Receive a packet.
void OpenFirstReceiveWindow()
Perform operations needed to open the first receive window.
@ RX
The PHY layer is receiving a packet.
@ TX
The PHY layer is sending a packet.
@ SLEEP
The PHY layer is sleeping.
@ STANDBY
The PHY layer is in STANDBY.
Class representing the MAC layer of a LoRaWAN device.
bool m_headerDisabled
Whether or not the LoRa PHY header is disabled for communications by this device.
TracedValue< double > m_txPowerDbm
The transmission ERP [dBm] this device is currently using.
Ptr< LogicalLoraChannel > GetChannelForTx()
Find a suitable channel for transmission.
uint8_t m_codingRate
The coding rate used by this device.
bool m_enableDRAdapt
Enable data rate adaptation (ADR) during the retransmission procedure.
Ptr< UniformRandomVariable > m_uniformRV
An uniform random variable, used to randomly pick from the channel list.
virtual void resetRetransmissionParameters()
Reset retransmission parameters contained in the structure LoraRetxParams.
void ParseCommands(LoraFrameHeader frameHeader)
Parse and take action on the commands contained on this FrameHeader.
TracedCallback< uint8_t, bool, Time, Ptr< Packet > > m_requiredTxCallback
The trace source fired when the transmission procedure is finished.
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.
double m_lastRxSnr
Used to record the last reception SNR measurement to be included in the DevStatusAns.
uint8_t m_nbTrans
Default number of unacknowledged redundant transmissions of each packet.
uint8_t m_receiveWindowDurationInSymbols
The duration of a receive window in number of symbols.
struct LoraRetxParameters m_retxParams
Structure containing the retransmission parameters for this device.
This class represents the Frame header (FHDR) used in a LoraWAN network.
LoraDeviceAddress GetAddress() const
Get this header's device address value.
void SetAsDownlink()
State that this is a downlink message.
static Time GetOnAirTime(Ptr< Packet > packet, LoraTxParameters txParams)
Compute the time that a packet with certain characteristics will take to be transmitted.
Definition lora-phy.cc:156
static Time GetTSym(LoraTxParameters txParams)
Compute the symbol time from spreading factor and bandwidth.
Definition lora-phy.cc:150
Tag used to save various data about a packet, like its Spreading Factor and data about interference.
Definition lora-tag.h:26
double GetReceivePower() const
Read the power this packet arrived with.
Definition lora-tag.cc:95
This class represents the Mac header of a LoRaWAN packet.
bool IsUplink() const
Check whether this header is for an uplink message.
TracedCallback< Ptr< const Packet > > m_receivedPacket
Trace source that is fired when a packet reaches the MAC layer.
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.
ReplyDataRateMatrix m_replyDataRateMatrix
The matrix that decides the data rate the gateway will use in a reply based on the end device's sendi...
Ptr< LogicalLoraChannelHelper > m_channelHelper
The LogicalLoraChannelHelper instance that is assigned to this MAC.
Ptr< LoraPhy > m_phy
The PHY instance that sits under this MAC layer.
int m_nPreambleSymbols
The number of symbols to use in the PHY preamble.
#define NS_ABORT_MSG(msg)
Unconditional abnormal program termination with a message.
Definition abort.h:38
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition log.h:191
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition log.h:257
#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:250
#define NS_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
Definition log.h:264
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition object-base.h:35
Ptr< T > Create(Ts &&... args)
Create class instances by constructors with varying numbers of arguments and return them by Ptr.
Definition ptr.h:436
Time Now()
create an ns3::Time instance which contains the current simulation time.
Definition simulator.cc:294
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition nstime.h:1344
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1356
Every class exported by the ns3 library is enclosed in the ns3 namespace.
Ptr< T1 > DynamicCast(const Ptr< T2 > &p)
Cast a Ptr.
Definition ptr.h:580
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.
Structure to collect all parameters that are used to compute the duration of a packet (excluding payl...
Definition lora-phy.h:38