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