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"
16#include "lora-tag.h"
17
18#include "ns3/simulator.h"
19
20namespace ns3
21{
22namespace lorawan
23{
24
25NS_LOG_COMPONENT_DEFINE("ClassAEndDeviceLorawanMac");
26
28
29TypeId
31{
32 static TypeId tid = TypeId("ns3::ClassAEndDeviceLorawanMac")
34 .SetGroupName("lorawan")
35 .AddConstructor<ClassAEndDeviceLorawanMac>();
36 return tid;
37}
38
40 : // LoraWAN default
42 // LoraWAN default
45{
46 NS_LOG_FUNCTION(this);
47
48 // Void the two receiveWindow events
50 m_closeFirstWindow.Cancel();
52 m_closeSecondWindow.Cancel();
54 m_secondReceiveWindow.Cancel();
55}
56
61
62/////////////////////
63// Sending methods //
64/////////////////////
65
66void
68{
69 /////////////////////////////////////////////////////////
70 // Add headers, prepare TX parameters and send the packet
71 /////////////////////////////////////////////////////////
72
73 NS_LOG_DEBUG("PacketToSend: " << packetToSend);
74
75 // Craft LoraTxParameters object
76 LoraTxParameters params;
77 params.sf = GetSfFromDataRate(m_dataRate);
78 params.headerDisabled = m_headerDisabled;
79 params.codingRate = m_codingRate;
80 params.bandwidthHz = GetBandwidthFromDataRate(m_dataRate);
81 params.nPreamble = m_nPreambleSymbols;
82 params.crcEnabled = true;
83 params.lowDataRateOptimizationEnabled = LoraPhy::GetTSym(params) > MilliSeconds(16);
84
85 // Wake up PHY layer and directly send the packet
86
88
89 NS_LOG_DEBUG("PacketToSend: " << packetToSend);
90 m_phy->Send(packetToSend, params, txChannel->GetFrequency(), m_txPowerDbm);
91
92 //////////////////////////////////////////////
93 // Register packet transmission for duty cycle
94 //////////////////////////////////////////////
95
96 // Compute packet duration
97 Time duration = LoraPhy::GetOnAirTime(packetToSend, params);
98
99 // Register the sent packet into the DutyCycleHelper
100 m_channelHelper->AddEvent(duration, txChannel);
101
102 //////////////////////////////
103 // Prepare for the downlink //
104 //////////////////////////////
105
106 // Switch the PHY to the channel so that it will listen here for downlink
107 DynamicCast<EndDeviceLoraPhy>(m_phy)->SetFrequency(txChannel->GetFrequency());
108
109 // Instruct the PHY on the right Spreading Factor to listen for during the window
110 // create a SetReplyDataRate function?
111 uint8_t replyDataRate = GetFirstReceiveWindowDataRate();
112 NS_LOG_DEBUG("m_dataRate: " << unsigned(m_dataRate)
113 << ", m_rx1DrOffset: " << unsigned(m_rx1DrOffset)
114 << ", replyDataRate: " << unsigned(replyDataRate) << ".");
115
116 DynamicCast<EndDeviceLoraPhy>(m_phy)->SetSpreadingFactor(GetSfFromDataRate(replyDataRate));
117}
118
119//////////////////////////
120// Receiving methods //
121//////////////////////////
122void
124{
125 NS_LOG_FUNCTION(this << packet);
126
127 // Work on a copy of the packet
128 Ptr<Packet> packetCopy = packet->Copy();
129
130 // Remove the Mac Header to get some information
131 LorawanMacHeader mHdr;
132 packetCopy->RemoveHeader(mHdr);
133
134 NS_LOG_DEBUG("Mac Header: " << mHdr);
135
136 // Only keep analyzing the packet if it's downlink
137 if (!mHdr.IsUplink())
138 {
139 NS_LOG_INFO("Found a downlink packet.");
140
141 // Remove the Frame Header
142 LoraFrameHeader fHdr;
143 fHdr.SetAsDownlink();
144 packetCopy->RemoveHeader(fHdr);
145
146 NS_LOG_DEBUG("Frame Header: " << fHdr);
147
148 // Determine whether this packet is for us
149 bool messageForUs = (m_address == fHdr.GetAddress());
150
151 if (messageForUs)
152 {
153 NS_LOG_INFO("The message is for us!");
154
155 // If it exists, cancel the second receive window event
156 // THIS WILL BE GetReceiveWindow()
158
159 // Reset ADR backoff counter
160 m_adrAckCnt = 0;
161
162 LoraTag tag;
163 packet->PeekPacketTag(tag);
164 /// @see ns3::lorawan::AdrComponent::RxPowerToSNR
165 m_lastRxSnr = tag.GetReceivePower() + 174 - 10 * log10(125000) - 6;
166
167 // Parse the MAC commands
168 ParseCommands(fHdr);
169
170 // TODO Pass the packet up to the NetDevice
171
172 // Call the trace source
173 m_receivedPacket(packet);
174 }
175 else
176 {
177 NS_LOG_DEBUG("The message is intended for another recipient.");
178
179 // In this case, we are either receiving in the first receive window
180 // and finishing reception inside the second one, or receiving a
181 // packet in the second receive window and finding out, after the
182 // fact, that the packet is not for us. In either case, if we no
183 // longer have any retransmissions left, we declare failure.
184 if (m_retxParams.waitingAck && m_secondReceiveWindow.IsExpired())
185 {
186 /// TODO: UNCONFIRMED packets CAN be retransmitted, but behave slightly differently.
187 /// The current implementation only considers re-txs for CONFIRMED, change this
188 if (m_retxParams.retxLeft == 0)
189 {
190 uint8_t txs = m_nbTrans - (m_retxParams.retxLeft);
192 false,
193 m_retxParams.firstAttempt,
194 m_retxParams.packet);
195 NS_LOG_DEBUG("Failure: no more retransmissions left. Used "
196 << unsigned(txs) << " transmissions.");
197
198 // Reset retransmission parameters
200 }
201 else // Reschedule
202 {
203 this->Send(m_retxParams.packet);
204 NS_LOG_INFO("We have " << unsigned(m_retxParams.retxLeft)
205 << " retransmissions left: rescheduling transmission.");
206 }
207 }
208 }
209 }
210 else if (m_retxParams.waitingAck && m_secondReceiveWindow.IsExpired())
211 {
212 NS_LOG_INFO("The packet we are receiving is in uplink.");
213 if (m_retxParams.retxLeft > 0)
214 {
215 this->Send(m_retxParams.packet);
216 NS_LOG_INFO("We have " << unsigned(m_retxParams.retxLeft)
217 << " retransmissions left: rescheduling transmission.");
218 }
219 else
220 {
221 uint8_t txs = m_nbTrans - (m_retxParams.retxLeft);
222 m_requiredTxCallback(txs, false, m_retxParams.firstAttempt, m_retxParams.packet);
223 NS_LOG_DEBUG("Failure: no more retransmissions left. Used " << unsigned(txs)
224 << " transmissions.");
225
226 // Reset retransmission parameters
228 }
229 }
230
231 DynamicCast<EndDeviceLoraPhy>(m_phy)->SwitchToSleep();
232}
233
234void
236{
237 NS_LOG_FUNCTION(this << packet);
238
239 // Switch to sleep after a failed reception
240 DynamicCast<EndDeviceLoraPhy>(m_phy)->SwitchToSleep();
241
242 if (m_secondReceiveWindow.IsExpired() && m_retxParams.waitingAck)
243 {
244 if (m_retxParams.retxLeft > 0)
245 {
246 this->Send(m_retxParams.packet);
247 NS_LOG_INFO("We have " << unsigned(m_retxParams.retxLeft)
248 << " retransmissions left: rescheduling transmission.");
249 }
250 else
251 {
252 uint8_t txs = m_nbTrans - (m_retxParams.retxLeft);
253 m_requiredTxCallback(txs, false, m_retxParams.firstAttempt, m_retxParams.packet);
254 NS_LOG_DEBUG("Failure: no more retransmissions left. Used " << unsigned(txs)
255 << " transmissions.");
256
257 // Reset retransmission parameters
259 }
260 }
261}
262
263void
265{
267
268 // Schedule the opening of the first receive window
270
271 // Schedule the opening of the second receive window
274 this);
275 // // Schedule the opening of the first receive window
276 // Simulator::Schedule (m_receiveDelay1,
277 // &ClassAEndDeviceLorawanMac::OpenFirstReceiveWindow, this);
278 //
279 // // Schedule the opening of the second receive window
280 // m_secondReceiveWindow = Simulator::Schedule (m_receiveDelay2,
281 // &ClassAEndDeviceLorawanMac::OpenSecondReceiveWindow,
282 // this);
283
284 // Switch the PHY to sleep
285 DynamicCast<EndDeviceLoraPhy>(m_phy)->SwitchToSleep();
286}
287
288void
290{
292
293 // Set Phy in Standby mode
294 DynamicCast<EndDeviceLoraPhy>(m_phy)->SwitchToStandby();
295
296 // Calculate the duration of a single symbol for the first receive window data rate
297 double tSym = pow(2, GetSfFromDataRate(GetFirstReceiveWindowDataRate())) /
299
300 // Schedule return to sleep after "at least the time required by the end
301 // device's radio transceiver to effectively detect a downlink preamble"
302 // (LoraWAN specification)
305 this); // m_receiveWindowDuration
306}
307
308void
310{
312
314
315 // Check the Phy layer's state:
316 // - RX -> We are receiving a preamble.
317 // - STANDBY -> Nothing was received.
318 // - SLEEP -> We have received a packet.
319 // We should never be in TX or SLEEP mode at this point
320 switch (phy->GetState())
321 {
323 NS_ABORT_MSG("PHY was in TX mode when attempting to close a receive window.");
324 break;
326 // PHY is receiving: let it finish. The Receive method will switch it back to SLEEP.
328 // PHY has received, and the MAC's Receive already put the device to sleep
329 break;
331 // Turn PHY layer to SLEEP
332 phy->SwitchToSleep();
333 break;
334 }
335}
336
337void
339{
341
342 // Check for receiver status: if it's locked on a packet, don't open this
343 // window at all.
345 {
346 NS_LOG_INFO("Won't open second receive window since we are in RX mode.");
347
348 return;
349 }
350
351 // Set Phy in Standby mode
352 DynamicCast<EndDeviceLoraPhy>(m_phy)->SwitchToStandby();
353
354 // Switch to appropriate channel and data rate
355 NS_LOG_INFO("Using parameters: " << m_secondReceiveWindowFrequencyHz << " Hz, DR"
356 << unsigned(m_secondReceiveWindowDataRate));
357
359 DynamicCast<EndDeviceLoraPhy>(m_phy)->SetSpreadingFactor(
361
362 // Calculate the duration of a single symbol for the second receive window data rate
363 double tSym = pow(2, GetSfFromDataRate(GetSecondReceiveWindowDataRate())) /
365
366 // Schedule return to sleep after "at least the time required by the end
367 // device's radio transceiver to effectively detect a downlink preamble"
368 // (LoraWAN specification)
371 this);
372}
373
374void
376{
378
380
381 // NS_ASSERT (phy->m_state != EndDeviceLoraPhy::State::TX &&
382 // phy->m_state != EndDeviceLoraPhy::State::SLEEP);
383
384 // Check the Phy layer's state:
385 // - RX -> We have received a preamble.
386 // - STANDBY -> Nothing was detected.
387 switch (phy->GetState())
388 {
391 break;
393 // PHY is receiving: let it finish
394 NS_LOG_DEBUG("PHY is receiving: Receive will handle the result.");
395 return;
397 // Turn PHY layer to sleep
398 phy->SwitchToSleep();
399 break;
400 }
401
402 if (m_retxParams.waitingAck)
403 {
404 NS_LOG_DEBUG("No reception initiated by PHY: rescheduling transmission.");
405 if (m_retxParams.retxLeft > 0)
406 {
407 NS_LOG_INFO("We have " << unsigned(m_retxParams.retxLeft)
408 << " retransmissions left: rescheduling transmission.");
409 this->Send(m_retxParams.packet);
410 }
411
412 else if (m_retxParams.retxLeft == 0 &&
414 {
415 uint8_t txs = m_nbTrans - (m_retxParams.retxLeft);
416 m_requiredTxCallback(txs, false, m_retxParams.firstAttempt, m_retxParams.packet);
417 NS_LOG_DEBUG("Failure: no more retransmissions left. Used " << unsigned(txs)
418 << " transmissions.");
419
420 // Reset retransmission parameters
422 }
423
424 else
425 {
426 NS_ABORT_MSG("The number of retransmissions left is negative ! ");
427 }
428 }
429 else
430 {
431 uint8_t txs = m_nbTrans - (m_retxParams.retxLeft);
432 m_requiredTxCallback(txs, true, m_retxParams.firstAttempt, m_retxParams.packet);
434 "We have " << unsigned(m_retxParams.retxLeft)
435 << " transmissions left. We were not transmitting confirmed messages.");
436
437 // Reset retransmission parameters
439 }
440}
441
442/////////////////////////
443// Getters and Setters //
444/////////////////////////
445
446Time
448{
450
451 // This is a new packet from APP; it can not be sent until the end of the
452 // second receive window (if the second receive window has not closed yet)
453 if (!m_retxParams.waitingAck)
454 {
455 if (!m_closeFirstWindow.IsExpired() || !m_closeSecondWindow.IsExpired() ||
456 !m_secondReceiveWindow.IsExpired())
457 {
459 "Attempting to send when there are receive windows: Transmission postponed.");
460 // Compute the duration of a single symbol for the second receive window data rate
461 double tSym = pow(2, GetSfFromDataRate(GetSecondReceiveWindowDataRate())) /
463 // Compute the closing time of the second receive window
464 Time endSecondRxWindow = Time(m_secondReceiveWindow.GetTs()) +
466
467 NS_LOG_DEBUG("Duration until endSecondRxWindow for new transmission:"
468 << (endSecondRxWindow - Now()).As(Time::S));
469 waitTime = Max(waitTime, endSecondRxWindow - Now());
470 }
471 }
472 // This is a retransmitted packet, it can not be sent until the end of
473 // ACK_TIMEOUT (this timer starts when the second receive window was open)
474 else
475 {
476 double ack_timeout = m_uniformRV->GetValue(1, 3);
477 // Compute the duration until ACK_TIMEOUT (It may be a negative number, but it doesn't
478 // matter.)
479 Time retransmitWaitTime =
480 Time(m_secondReceiveWindow.GetTs()) - Now() + Seconds(ack_timeout);
481
482 NS_LOG_DEBUG("ack_timeout:" << ack_timeout
483 << " retransmitWaitTime:" << retransmitWaitTime.As(Time::S));
484 waitTime = Max(waitTime, retransmitWaitTime);
485 }
486
487 return waitTime;
488}
489
490uint8_t
495
496void
501
502uint8_t
507
508void
513
519
520/////////////////////////
521// MAC command methods //
522/////////////////////////
523
524void
526 uint8_t rx2DataRate,
527 double frequencyHz)
528{
529 NS_LOG_FUNCTION(this << unsigned(rx1DrOffset) << unsigned(rx2DataRate)
530 << uint32_t(frequencyHz));
531
532 // Adapted from: github.com/Lora-net/SWL2001.git v4.3.1
533 // For the time being, this implementation is valid for the EU868 region
534
535 bool rx1DrOffsetAck = true;
536 bool rx2DataRateAck = true;
537 bool channelAck = true;
538
539 if (rx1DrOffset >= m_replyDataRateMatrix.at(m_dataRate).size())
540 {
541 NS_LOG_WARN("Invalid rx1DrOffset");
542 rx1DrOffsetAck = false;
543 }
544
545 if (!GetSfFromDataRate(rx2DataRate) || !GetBandwidthFromDataRate(rx2DataRate))
546 {
547 NS_LOG_WARN("Invalid rx2DataRate");
548 rx2DataRateAck = false;
549 }
550
551 if (!m_channelHelper->IsFrequencyValid(frequencyHz))
552 {
553 NS_LOG_WARN("Invalid rx2 frequency");
554 channelAck = false;
555 }
556
557 if (rx1DrOffsetAck && rx2DataRateAck && channelAck)
558 {
559 m_rx1DrOffset = rx1DrOffset;
560 m_secondReceiveWindowDataRate = rx2DataRate;
562 }
563
564 NS_LOG_INFO("Adding RxParamSetupAns reply");
565 m_macCommandList.emplace_back(
566 Create<RxParamSetupAns>(rx1DrOffsetAck, rx2DataRateAck, channelAck));
567}
568
569} /* namespace lorawan */
570} /* namespace ns3 */
#define Max(a, b)
An identifier for simulation events.
Definition event-id.h:45
Smart pointer class similar to boost::intrusive_ptr.
Definition ptr.h:70
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition simulator.h:580
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:268
Simulation virtual time values and global simulation resolution.
Definition nstime.h:95
TimeWithUnit As(const Unit unit=Time::AUTO) const
Attach a unit to a Time, to facilitate output in a specific unit.
Definition time.cc:408
@ S
second
Definition nstime.h:106
a unique identifier for an interface.
Definition type-id.h:50
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition type-id.cc:999
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.
@ TX
The PHY layer is sending a packet.
@ STANDBY
The PHY layer is in STANDBY.
@ RX
The PHY layer is receiving a packet.
Ptr< LogicalLoraChannel > GetRandomChannelForTx()
Find a suitable channel for transmission.
virtual void ResetRetransmissionParameters()
Reset retransmission parameters contained in the structure LoraRetxParams.
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< UniformRandomVariable > m_uniformRV
An uniform random variable, used to randomly pick from the channel list.
uint16_t m_adrAckCnt
ADRACKCnt counter of the number of consecutive uplinks without downlink reply from the server.
void ParseCommands(LoraFrameHeader frameHeader)
Parse and take action on the commands contained on this FrameHeader.
CodingRate m_codingRate
The coding rate used by this device.
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:155
static Time GetTSym(LoraTxParameters txParams)
Compute the symbol time from spreading factor and bandwidth.
Definition lora-phy.cc:149
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:92
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:194
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition log.h:260
#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:253
#define NS_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
Definition log.h:267
#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:454
Time Now()
create an ns3::Time instance which contains the current simulation time.
Definition simulator.cc:288
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition nstime.h:1273
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1290
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:605
Structure to collect all parameters that are used to compute the duration of a packet (excluding payl...
Definition lora-phy.h:54