A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
lora-frame-header.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 */
8
9#include "lora-frame-header.h"
10
11#include "ns3/log.h"
12
13#include <bitset>
14
15namespace ns3
16{
17namespace lorawan
18{
19
20NS_LOG_COMPONENT_DEFINE("LoraFrameHeader");
21
22// Initialization list
24 : m_fPort(0),
25 m_address(LoraDeviceAddress(0, 0)),
26 m_adr(false),
27 m_adrAckReq(false),
28 m_ack(false),
29 m_fPending(false),
30 m_fOptsLen(0),
31 m_fCnt(0)
32{
33}
34
38
41{
42 static TypeId tid =
43 TypeId("LoraFrameHeader").SetParent<Header>().AddConstructor<LoraFrameHeader>();
44 return tid;
45}
46
49{
50 return GetTypeId();
51}
52
55{
57
58 // Sizes in bytes:
59 // 4 for DevAddr + 1 for FCtrl + 2 for FCnt + 1 for FPort + 0-15 for FOpts
60 uint32_t size = 8 + m_fOptsLen;
61
62 NS_LOG_INFO("LoraFrameHeader serialized size: " << size);
63
64 return size;
65}
66
67void
69{
71
72 // Device Address field
73 start.WriteU32(m_address.Get());
74
75 // fCtrl field
76 //
77 // TODO FCtrl has different meanings for UL and DL packets. Handle this
78 // correctly here.
79 uint8_t fCtrl = 0;
80 fCtrl |= uint8_t(m_adr << 7 & 0b10000000);
81 fCtrl |= uint8_t(m_adrAckReq << 6 & 0b1000000);
82 fCtrl |= uint8_t(m_ack << 5 & 0b100000);
83 fCtrl |= uint8_t(m_fPending << 4 & 0b10000);
84 fCtrl |= m_fOptsLen & 0b1111;
85 start.WriteU8(fCtrl);
86
87 // FCnt field
88 start.WriteU16(m_fCnt);
89
90 // FOpts field
91 for (auto it = m_macCommands.begin(); it != m_macCommands.end(); it++)
92 {
93 NS_LOG_DEBUG("Serializing a MAC command");
94 (*it)->Serialize(start);
95 }
96
97 // FPort
98 start.WriteU8(m_fPort);
99
100 NS_LOG_DEBUG("Serializing the following data: ");
101 NS_LOG_DEBUG("Address: " << m_address.Print());
102 NS_LOG_DEBUG("ADR: " << unsigned(m_adr));
103 NS_LOG_DEBUG("ADRAckReq: " << unsigned(m_adrAckReq));
104 NS_LOG_DEBUG("Ack: " << unsigned(m_ack));
105 NS_LOG_DEBUG("fPending: " << unsigned(m_fPending));
106 NS_LOG_DEBUG("fOptsLen: " << unsigned(m_fOptsLen));
107 NS_LOG_DEBUG("fCnt: " << unsigned(m_fCnt));
108}
109
112{
114
115 // Empty the list of MAC commands
116 m_macCommands.clear();
117
118 // Read from buffer and save into local variables
119 m_address.Set(start.ReadU32());
120 // TODO FCtrl has different meanings for UL and DL packets. Handle this
121 // correctly here.
122 uint8_t fCtrl = start.ReadU8();
123 m_adr = (fCtrl >> 7) & 0b1;
124 m_adrAckReq = (fCtrl >> 6) & 0b1;
125 m_ack = (fCtrl >> 5) & 0b1;
126 m_fPending = (fCtrl >> 4) & 0b1;
127 m_fOptsLen = fCtrl & 0b1111;
128 m_fCnt = start.ReadU16();
129
130 NS_LOG_DEBUG("Deserialized data: ");
131 NS_LOG_DEBUG("Address: " << m_address.Print());
132 NS_LOG_DEBUG("ADR: " << unsigned(m_adr));
133 NS_LOG_DEBUG("ADRAckReq: " << unsigned(m_adrAckReq));
134 NS_LOG_DEBUG("Ack: " << unsigned(m_ack));
135 NS_LOG_DEBUG("fPending: " << unsigned(m_fPending));
136 NS_LOG_DEBUG("fOptsLen: " << unsigned(m_fOptsLen));
137 NS_LOG_DEBUG("fCnt: " << unsigned(m_fCnt));
138
139 // Deserialize MAC commands
140 NS_LOG_DEBUG("Starting deserialization of MAC commands");
141 for (uint8_t byteNumber = 0; byteNumber < m_fOptsLen;)
142 {
143 uint8_t cid = start.PeekU8();
144 NS_LOG_DEBUG("CID: " << unsigned(cid));
145
146 // Divide Uplink and Downlink messages
147 // This needs to be done because they have the same CID, and the context
148 // about where this message will be Serialized/Deserialized (i.e., at the
149 // end device or at the network server) is umportant.
150 if (m_isUplink)
151 {
152 switch (cid)
153 {
154 // In the case of Uplink messages, the network server will deserialize the
155 // request for a link check
156 case (0x02): {
157 NS_LOG_DEBUG("Creating a LinkCheckReq command");
159 byteNumber += command->Deserialize(start);
160 m_macCommands.emplace_back(command);
161 break;
162 }
163 case (0x03): {
164 NS_LOG_DEBUG("Creating a LinkAdrAns command");
166 byteNumber += command->Deserialize(start);
167 m_macCommands.emplace_back(command);
168 break;
169 }
170 case (0x04): {
171 NS_LOG_DEBUG("Creating a DutyCycleAns command");
173 byteNumber += command->Deserialize(start);
174 m_macCommands.emplace_back(command);
175 break;
176 }
177 case (0x05): {
178 NS_LOG_DEBUG("Creating a RxParamSetupAns command");
180 byteNumber += command->Deserialize(start);
181 m_macCommands.emplace_back(command);
182 break;
183 }
184 case (0x06): {
185 NS_LOG_DEBUG("Creating a DevStatusAns command");
187 byteNumber += command->Deserialize(start);
188 m_macCommands.emplace_back(command);
189 break;
190 }
191 case (0x07): {
192 NS_LOG_DEBUG("Creating a NewChannelAns command");
194 byteNumber += command->Deserialize(start);
195 m_macCommands.emplace_back(command);
196 break;
197 }
198 case (0x08): {
199 NS_LOG_DEBUG("Creating a RxTimingSetupAns command");
201 byteNumber += command->Deserialize(start);
202 m_macCommands.emplace_back(command);
203 break;
204 }
205 case (0x09): {
206 NS_LOG_DEBUG("Creating a TxParamSetupAns command");
208 byteNumber += command->Deserialize(start);
209 m_macCommands.emplace_back(command);
210 break;
211 }
212 case (0x0A): {
213 NS_LOG_DEBUG("Creating a DlChannelAns command");
215 byteNumber += command->Deserialize(start);
216 m_macCommands.emplace_back(command);
217 break;
218 }
219 default: {
220 NS_LOG_ERROR("CID not recognized during deserialization");
221 }
222 }
223 }
224 else
225 {
226 switch (cid)
227 {
228 // In the case of Downlink messages, the end device will deserialize the
229 // answer to a link check
230 case (0x02): {
231 NS_LOG_DEBUG("Creating a LinkCheckAns command");
233 byteNumber += command->Deserialize(start);
234 m_macCommands.emplace_back(command);
235 break;
236 }
237 case (0x03): {
238 NS_LOG_DEBUG("Creating a LinkAdrReq command");
240 byteNumber += command->Deserialize(start);
241 m_macCommands.emplace_back(command);
242 break;
243 }
244 case (0x04): {
245 NS_LOG_DEBUG("Creating a DutyCycleReq command");
247 byteNumber += command->Deserialize(start);
248 m_macCommands.emplace_back(command);
249 break;
250 }
251 case (0x05): {
252 NS_LOG_DEBUG("Creating a RxParamSetupReq command");
254 byteNumber += command->Deserialize(start);
255 m_macCommands.emplace_back(command);
256 break;
257 }
258 case (0x06): {
259 NS_LOG_DEBUG("Creating a DevStatusReq command");
261 byteNumber += command->Deserialize(start);
262 m_macCommands.emplace_back(command);
263 break;
264 }
265 case (0x07): {
266 NS_LOG_DEBUG("Creating a NewChannelReq command");
268 byteNumber += command->Deserialize(start);
269 m_macCommands.emplace_back(command);
270 break;
271 }
272 case (0x08): {
273 NS_LOG_DEBUG("Creating a RxTimingSetupReq command");
275 byteNumber += command->Deserialize(start);
276 m_macCommands.emplace_back(command);
277 break;
278 }
279 case (0x09): {
280 NS_LOG_DEBUG("Creating a TxParamSetupReq command");
282 byteNumber += command->Deserialize(start);
283 m_macCommands.emplace_back(command);
284 break;
285 }
286 default: {
287 NS_LOG_ERROR("CID not recognized during deserialization");
288 }
289 }
290 }
291 }
292
293 m_fPort = uint8_t(start.ReadU8());
294
295 return 8 + m_fOptsLen; // the number of bytes consumed.
296}
297
298void
299LoraFrameHeader::Print(std::ostream& os) const
300{
302
303 os << "Address=" << m_address.Print() << std::endl;
304 os << "ADR=" << m_adr << std::endl;
305 os << "ADRAckReq=" << m_adrAckReq << std::endl;
306 os << "ACK=" << m_ack << std::endl;
307 os << "FPending=" << m_fPending << std::endl;
308 os << "FOptsLen=" << unsigned(m_fOptsLen) << std::endl;
309 os << "FCnt=" << unsigned(m_fCnt) << std::endl;
310
311 for (auto it = m_macCommands.begin(); it != m_macCommands.end(); it++)
312 {
313 (*it)->Print(os);
314 }
315
316 os << "FPort=" << unsigned(m_fPort) << std::endl;
317}
318
319void
326
327void
334
335void
337{
338 m_fPort = fPort;
339}
340
341uint8_t
343{
344 return m_fPort;
345}
346
347void
352
355{
356 return m_address;
357}
358
359void
361{
362 NS_LOG_FUNCTION(this << adr);
363 m_adr = adr;
364}
365
366bool
368{
369 return m_adr;
370}
371
372void
374{
375 m_adrAckReq = adrAckReq;
376}
377
378bool
380{
381 return m_adrAckReq;
382}
383
384void
386{
387 NS_LOG_FUNCTION(this << ack);
388 m_ack = ack;
389}
390
391bool
393{
394 return m_ack;
395}
396
397void
399{
400 m_fPending = fPending;
401}
402
403bool
405{
406 return m_fPending;
407}
408
409uint8_t
411{
412 // Sum the serialized length of all commands in the list
413 uint8_t fOptsLen = 0;
414 std::list<Ptr<MacCommand>>::const_iterator it;
415 for (it = m_macCommands.begin(); it != m_macCommands.end(); it++)
416 {
417 fOptsLen = fOptsLen + (*it)->GetSerializedSize();
418 }
419 return fOptsLen;
420}
421
422void
424{
425 m_fCnt = fCnt;
426}
427
428uint16_t
430{
431 return m_fCnt;
432}
433
434void
436{
438
440 m_macCommands.emplace_back(command);
441
442 NS_LOG_DEBUG("Command SerializedSize: " << unsigned(command->GetSerializedSize()));
443 m_fOptsLen += command->GetSerializedSize();
444}
445
446void
447LoraFrameHeader::AddLinkCheckAns(uint8_t margin, uint8_t gwCnt)
448{
449 NS_LOG_FUNCTION(this << unsigned(margin) << unsigned(gwCnt));
450
451 Ptr<LinkCheckAns> command = Create<LinkCheckAns>(margin, gwCnt);
452 m_macCommands.emplace_back(command);
453
454 m_fOptsLen += command->GetSerializedSize();
455}
456
457void
459 uint8_t txPower,
460 std::list<int> enabledChannels,
461 int repetitions)
462{
463 NS_LOG_FUNCTION(this << unsigned(dataRate) << txPower << repetitions);
464
465 uint16_t channelMask = 0;
466 for (auto it = enabledChannels.begin(); it != enabledChannels.end(); it++)
467 {
468 NS_ASSERT((*it) < 16 && (*it) > -1);
469
470 channelMask |= 0b1 << (*it);
471 }
472
473 // TODO Implement chMaskCntl field
474
475 NS_LOG_DEBUG("Creating LinkAdrReq with: DR = " << unsigned(dataRate)
476 << " and txPower = " << unsigned(txPower));
477
478 Ptr<LinkAdrReq> command = Create<LinkAdrReq>(dataRate, txPower, channelMask, 0, repetitions);
479 m_macCommands.emplace_back(command);
480
481 m_fOptsLen += command->GetSerializedSize();
482}
483
484void
485LoraFrameHeader::AddLinkAdrAns(bool powerAck, bool dataRateAck, bool channelMaskAck)
486{
487 NS_LOG_FUNCTION(this << powerAck << dataRateAck << channelMaskAck);
488
489 Ptr<LinkAdrAns> command = Create<LinkAdrAns>(powerAck, dataRateAck, channelMaskAck);
490 m_macCommands.emplace_back(command);
491
492 m_fOptsLen += command->GetSerializedSize();
493}
494
495void
497{
498 NS_LOG_FUNCTION(this << unsigned(dutyCycle));
499
500 Ptr<DutyCycleReq> command = Create<DutyCycleReq>(dutyCycle);
501
502 m_macCommands.emplace_back(command);
503
504 m_fOptsLen += command->GetSerializedSize();
505}
506
507void
509{
510 NS_LOG_FUNCTION(this);
511
513
514 m_macCommands.emplace_back(command);
515
516 m_fOptsLen += command->GetSerializedSize();
517}
518
519void
520LoraFrameHeader::AddRxParamSetupReq(uint8_t rx1DrOffset, uint8_t rx2DataRate, double frequency)
521{
522 NS_LOG_FUNCTION(this << unsigned(rx1DrOffset) << unsigned(rx2DataRate) << frequency);
523
524 // Evaluate whether to eliminate this assert in case new offsets can be defined.
525 NS_ASSERT(0 <= rx1DrOffset && rx1DrOffset <= 5);
526
527 Ptr<RxParamSetupReq> command = Create<RxParamSetupReq>(rx1DrOffset, rx2DataRate, frequency);
528
529 m_macCommands.emplace_back(command);
530
531 m_fOptsLen += command->GetSerializedSize();
532}
533
534void
536{
537 NS_LOG_FUNCTION(this);
538
540
541 m_macCommands.emplace_back(command);
542
543 m_fOptsLen += command->GetSerializedSize();
544}
545
546void
548{
549 NS_LOG_FUNCTION(this);
550
552
553 m_macCommands.emplace_back(command);
554
555 m_fOptsLen += command->GetSerializedSize();
556}
557
558void
560 double frequency,
561 uint8_t minDataRate,
562 uint8_t maxDataRate)
563{
564 NS_LOG_FUNCTION(this);
565
566 Ptr<NewChannelReq> command =
567 Create<NewChannelReq>(chIndex, frequency, minDataRate, maxDataRate);
568
569 m_macCommands.emplace_back(command);
570
571 m_fOptsLen += command->GetSerializedSize();
572}
573
574std::list<Ptr<MacCommand>>
581
582void
584{
585 NS_LOG_FUNCTION(this << macCommand);
586
587 m_macCommands.push_back(macCommand);
588 m_fOptsLen += macCommand->GetSerializedSize();
589}
590
591} // namespace lorawan
592} // namespace ns3
iterator in a Buffer instance
Definition buffer.h:89
Protocol header serialization and deserialization.
Definition header.h:33
Smart pointer class similar to boost::intrusive_ptr.
a unique identifier for an interface.
Definition type-id.h:48
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition type-id.cc:1001
This class represents the device address of a LoraWAN end device.
uint32_t Get() const
Get the address in 32-bit integer form.
void Set(uint32_t address)
Set the address as a 32 bit integer.
std::string Print() const
Print the address bit-by-bit to a human-readable string.
bool m_ack
The ACK field of the FCtrl.
void AddDutyCycleReq(uint8_t dutyCycle)
Add a DutyCycleReq command.
bool GetAck() const
Get the value of the ACK bit field.
uint8_t GetFPort() const
Get the FPort value.
void AddLinkCheckReq()
Add a LinkCheckReq command.
uint32_t Deserialize(Buffer::Iterator start) override
Deserialize the contents of the buffer into a LoraFrameHeader object.
void AddCommand(Ptr< MacCommand > macCommand)
Add a predefined command to the list in this frame header.
void SetFCnt(uint16_t fCnt)
Set the FCnt value.
bool GetAdr() const
Get the value of the ADR bit field.
void AddNewChannelReq(uint8_t chIndex, double frequency, uint8_t minDataRate, uint8_t maxDataRate)
Add a NewChannelReq command with provided fields.
void AddDutyCycleAns()
Add a DutyCycleAns command.
bool m_fPending
The FPending/ClassB field of the FCtrl.
void AddRxParamSetupAns()
Add a RxParamSetupAns command.
void SetAck(bool ack)
Set the value of the ACK bit field.
bool m_adr
The ADR field of the FCtrl.
uint16_t m_fCnt
The FCnt field.
void SetAdr(bool adr)
Set the value of the ADR bit field.
uint8_t m_fOptsLen
The FOptsLen field of the FCtrl.
void AddDevStatusReq()
Add a DevStatusReq command.
bool GetFPending() const
Get the value of the FPending bit field.
uint32_t GetSerializedSize() const override
Return the size required for serialization of this header.
void SetAddress(LoraDeviceAddress address)
Set the address.
uint16_t GetFCnt() const
Get the FCnt value.
void Print(std::ostream &os) const override
Print the header in a human-readable format.
bool GetAdrAckReq() const
Get the value of the ADRACKReq bit field.
std::list< Ptr< MacCommand > > m_macCommands
List containing all the MacCommand instances that are contained in this LoraFrameHeader.
void SetAsUplink()
State that this is an uplink message.
LoraDeviceAddress m_address
The DevAddr field.
LoraDeviceAddress GetAddress() const
Get this header's device address value.
void SetAdrAckReq(bool adrAckReq)
Set the value of the ADRACKReq bit field.
~LoraFrameHeader() override
Destructor.
void Serialize(Buffer::Iterator start) const override
Serialize the header.
static TypeId GetTypeId()
Register this type.
bool m_adrAckReq
The ADRACKReq field of the FCtrl.
void SetFPending(bool fPending)
Set the value of the FPending bit field.
void AddLinkCheckAns(uint8_t margin, uint8_t gwCnt)
Add a LinkCheckAns command.
void AddLinkAdrAns(bool powerAck, bool dataRateAck, bool channelMaskAck)
Add a LinkAdrAns command.
bool m_isUplink
Whether this frame header is uplink or not.
void AddLinkAdrReq(uint8_t dataRate, uint8_t txPower, std::list< int > enabledChannels, int repetitions)
Add a LinkAdrReq command.
uint8_t m_fPort
The FPort field.
LoraFrameHeader()
Default constructor.
std::list< Ptr< MacCommand > > GetCommands()
Return a list of pointers to all the MAC commands saved in this header.
TypeId GetInstanceTypeId() const override
Get the most derived TypeId for this Object.
void SetAsDownlink()
State that this is a downlink message.
void SetFPort(uint8_t fPort)
Set the FPort value.
void AddRxParamSetupReq(uint8_t rx1DrOffset, uint8_t rx2DataRate, double frequency)
Add a RxParamSetupReq command.
uint8_t GetFOptsLen() const
Get the FOptsLen value.
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition assert.h:55
#define NS_LOG_ERROR(msg)
Use NS_LOG to output a message of level LOG_ERROR.
Definition log.h:243
#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_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
Definition log.h:264
Ptr< T > Create(Ts &&... args)
Create class instances by constructors with varying numbers of arguments and return them by Ptr.
Definition ptr.h:436
Every class exported by the ns3 library is enclosed in the ns3 namespace.