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 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation;
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 *
17 * Author: Davide Magrin <magrinda@dei.unipd.it>
18 */
19
20#include "lora-frame-header.h"
21
22#include "ns3/log.h"
23
24#include <bitset>
25
26namespace ns3
27{
28namespace lorawan
29{
30
31NS_LOG_COMPONENT_DEFINE("LoraFrameHeader");
32
33// Initialization list
35 : m_fPort(0),
36 m_address(LoraDeviceAddress(0, 0)),
37 m_adr(false),
38 m_adrAckReq(false),
39 m_ack(false),
40 m_fPending(false),
41 m_fOptsLen(0),
42 m_fCnt(0)
43{
44}
45
47{
48}
49
52{
53 static TypeId tid =
54 TypeId("LoraFrameHeader").SetParent<Header>().AddConstructor<LoraFrameHeader>();
55 return tid;
56}
57
60{
61 return GetTypeId();
62}
63
66{
68
69 // Sizes in bytes:
70 // 4 for DevAddr + 1 for FCtrl + 2 for FCnt + 1 for FPort + 0-15 for FOpts
71 uint32_t size = 8 + m_fOptsLen;
72
73 NS_LOG_INFO("LoraFrameHeader serialized size: " << size);
74
75 return size;
76}
77
78void
80{
82
83 // Device Address field
84 start.WriteU32(m_address.Get());
85
86 // fCtrl field
87 //
88 // TODO FCtrl has different meanings for UL and DL packets. Handle this
89 // correctly here.
90 uint8_t fCtrl = 0;
91 fCtrl |= uint8_t(m_adr << 7 & 0b10000000);
92 fCtrl |= uint8_t(m_adrAckReq << 6 & 0b1000000);
93 fCtrl |= uint8_t(m_ack << 5 & 0b100000);
94 fCtrl |= uint8_t(m_fPending << 4 & 0b10000);
95 fCtrl |= m_fOptsLen & 0b1111;
96 start.WriteU8(fCtrl);
97
98 // FCnt field
99 start.WriteU16(m_fCnt);
100
101 // FOpts field
102 for (auto it = m_macCommands.begin(); it != m_macCommands.end(); it++)
103 {
104 NS_LOG_DEBUG("Serializing a MAC command");
105 (*it)->Serialize(start);
106 }
107
108 // FPort
109 start.WriteU8(m_fPort);
110
111 NS_LOG_DEBUG("Serializing the following data: ");
112 NS_LOG_DEBUG("Address: " << m_address.Print());
113 NS_LOG_DEBUG("ADR: " << unsigned(m_adr));
114 NS_LOG_DEBUG("ADRAckReq: " << unsigned(m_adrAckReq));
115 NS_LOG_DEBUG("Ack: " << unsigned(m_ack));
116 NS_LOG_DEBUG("fPending: " << unsigned(m_fPending));
117 NS_LOG_DEBUG("fOptsLen: " << unsigned(m_fOptsLen));
118 NS_LOG_DEBUG("fCnt: " << unsigned(m_fCnt));
119}
120
123{
125
126 // Empty the list of MAC commands
127 m_macCommands.clear();
128
129 // Read from buffer and save into local variables
130 m_address.Set(start.ReadU32());
131 // TODO FCtrl has different meanings for UL and DL packets. Handle this
132 // correctly here.
133 uint8_t fCtrl = start.ReadU8();
134 m_adr = (fCtrl >> 7) & 0b1;
135 m_adrAckReq = (fCtrl >> 6) & 0b1;
136 m_ack = (fCtrl >> 5) & 0b1;
137 m_fPending = (fCtrl >> 4) & 0b1;
138 m_fOptsLen = fCtrl & 0b1111;
139 m_fCnt = start.ReadU16();
140
141 NS_LOG_DEBUG("Deserialized data: ");
142 NS_LOG_DEBUG("Address: " << m_address.Print());
143 NS_LOG_DEBUG("ADR: " << unsigned(m_adr));
144 NS_LOG_DEBUG("ADRAckReq: " << unsigned(m_adrAckReq));
145 NS_LOG_DEBUG("Ack: " << unsigned(m_ack));
146 NS_LOG_DEBUG("fPending: " << unsigned(m_fPending));
147 NS_LOG_DEBUG("fOptsLen: " << unsigned(m_fOptsLen));
148 NS_LOG_DEBUG("fCnt: " << unsigned(m_fCnt));
149
150 // Deserialize MAC commands
151 NS_LOG_DEBUG("Starting deserialization of MAC commands");
152 for (uint8_t byteNumber = 0; byteNumber < m_fOptsLen;)
153 {
154 uint8_t cid = start.PeekU8();
155 NS_LOG_DEBUG("CID: " << unsigned(cid));
156
157 // Divide Uplink and Downlink messages
158 // This needs to be done because they have the same CID, and the context
159 // about where this message will be Serialized/Deserialized (i.e., at the
160 // end device or at the network server) is umportant.
161 if (m_isUplink)
162 {
163 switch (cid)
164 {
165 // In the case of Uplink messages, the network server will deserialize the
166 // request for a link check
167 case (0x02): {
168 NS_LOG_DEBUG("Creating a LinkCheckReq command");
169 Ptr<LinkCheckReq> command = Create<LinkCheckReq>();
170 byteNumber += command->Deserialize(start);
171 m_macCommands.emplace_back(command);
172 break;
173 }
174 case (0x03): {
175 NS_LOG_DEBUG("Creating a LinkAdrAns command");
176 Ptr<LinkAdrAns> command = Create<LinkAdrAns>();
177 byteNumber += command->Deserialize(start);
178 m_macCommands.emplace_back(command);
179 break;
180 }
181 case (0x04): {
182 NS_LOG_DEBUG("Creating a DutyCycleAns command");
183 Ptr<DutyCycleAns> command = Create<DutyCycleAns>();
184 byteNumber += command->Deserialize(start);
185 m_macCommands.emplace_back(command);
186 break;
187 }
188 case (0x05): {
189 NS_LOG_DEBUG("Creating a RxParamSetupAns command");
190 Ptr<RxParamSetupAns> command = Create<RxParamSetupAns>();
191 byteNumber += command->Deserialize(start);
192 m_macCommands.emplace_back(command);
193 break;
194 }
195 case (0x06): {
196 NS_LOG_DEBUG("Creating a DevStatusAns command");
197 Ptr<DevStatusAns> command = Create<DevStatusAns>();
198 byteNumber += command->Deserialize(start);
199 m_macCommands.emplace_back(command);
200 break;
201 }
202 case (0x07): {
203 NS_LOG_DEBUG("Creating a NewChannelAns command");
204 Ptr<NewChannelAns> command = Create<NewChannelAns>();
205 byteNumber += command->Deserialize(start);
206 m_macCommands.emplace_back(command);
207 break;
208 }
209 case (0x08): {
210 NS_LOG_DEBUG("Creating a RxTimingSetupAns command");
211 Ptr<RxTimingSetupAns> command = Create<RxTimingSetupAns>();
212 byteNumber += command->Deserialize(start);
213 m_macCommands.emplace_back(command);
214 break;
215 }
216 case (0x09): {
217 NS_LOG_DEBUG("Creating a TxParamSetupAns command");
218 Ptr<TxParamSetupAns> command = Create<TxParamSetupAns>();
219 byteNumber += command->Deserialize(start);
220 m_macCommands.emplace_back(command);
221 break;
222 }
223 case (0x0A): {
224 NS_LOG_DEBUG("Creating a DlChannelAns command");
225 Ptr<DlChannelAns> command = Create<DlChannelAns>();
226 byteNumber += command->Deserialize(start);
227 m_macCommands.emplace_back(command);
228 break;
229 }
230 default: {
231 NS_LOG_ERROR("CID not recognized during deserialization");
232 }
233 }
234 }
235 else
236 {
237 switch (cid)
238 {
239 // In the case of Downlink messages, the end device will deserialize the
240 // answer to a link check
241 case (0x02): {
242 NS_LOG_DEBUG("Creating a LinkCheckAns command");
243 Ptr<LinkCheckAns> command = Create<LinkCheckAns>();
244 byteNumber += command->Deserialize(start);
245 m_macCommands.emplace_back(command);
246 break;
247 }
248 case (0x03): {
249 NS_LOG_DEBUG("Creating a LinkAdrReq command");
250 Ptr<LinkAdrReq> command = Create<LinkAdrReq>();
251 byteNumber += command->Deserialize(start);
252 m_macCommands.emplace_back(command);
253 break;
254 }
255 case (0x04): {
256 NS_LOG_DEBUG("Creating a DutyCycleReq command");
257 Ptr<DutyCycleReq> command = Create<DutyCycleReq>();
258 byteNumber += command->Deserialize(start);
259 m_macCommands.emplace_back(command);
260 break;
261 }
262 case (0x05): {
263 NS_LOG_DEBUG("Creating a RxParamSetupReq command");
264 Ptr<RxParamSetupReq> command = Create<RxParamSetupReq>();
265 byteNumber += command->Deserialize(start);
266 m_macCommands.emplace_back(command);
267 break;
268 }
269 case (0x06): {
270 NS_LOG_DEBUG("Creating a DevStatusReq command");
271 Ptr<DevStatusReq> command = Create<DevStatusReq>();
272 byteNumber += command->Deserialize(start);
273 m_macCommands.emplace_back(command);
274 break;
275 }
276 case (0x07): {
277 NS_LOG_DEBUG("Creating a NewChannelReq command");
278 Ptr<NewChannelReq> command = Create<NewChannelReq>();
279 byteNumber += command->Deserialize(start);
280 m_macCommands.emplace_back(command);
281 break;
282 }
283 case (0x08): {
284 NS_LOG_DEBUG("Creating a RxTimingSetupReq command");
285 Ptr<RxTimingSetupReq> command = Create<RxTimingSetupReq>();
286 byteNumber += command->Deserialize(start);
287 m_macCommands.emplace_back(command);
288 break;
289 }
290 case (0x09): {
291 NS_LOG_DEBUG("Creating a TxParamSetupReq command");
292 Ptr<TxParamSetupReq> command = Create<TxParamSetupReq>();
293 byteNumber += command->Deserialize(start);
294 m_macCommands.emplace_back(command);
295 break;
296 }
297 default: {
298 NS_LOG_ERROR("CID not recognized during deserialization");
299 }
300 }
301 }
302 }
303
304 m_fPort = uint8_t(start.ReadU8());
305
306 return 8 + m_fOptsLen; // the number of bytes consumed.
307}
308
309void
310LoraFrameHeader::Print(std::ostream& os) const
311{
313
314 os << "Address=" << m_address.Print() << std::endl;
315 os << "ADR=" << m_adr << std::endl;
316 os << "ADRAckReq=" << m_adrAckReq << std::endl;
317 os << "ACK=" << m_ack << std::endl;
318 os << "FPending=" << m_fPending << std::endl;
319 os << "FOptsLen=" << unsigned(m_fOptsLen) << std::endl;
320 os << "FCnt=" << unsigned(m_fCnt) << std::endl;
321
322 for (auto it = m_macCommands.begin(); it != m_macCommands.end(); it++)
323 {
324 (*it)->Print(os);
325 }
326
327 os << "FPort=" << unsigned(m_fPort) << std::endl;
328}
329
330void
332{
334
335 m_isUplink = true;
336}
337
338void
340{
342
343 m_isUplink = false;
344}
345
346void
348{
349 m_fPort = fPort;
350}
351
352uint8_t
354{
355 return m_fPort;
356}
357
358void
360{
361 m_address = address;
362}
363
366{
367 return m_address;
368}
369
370void
372{
373 NS_LOG_FUNCTION(this << adr);
374 m_adr = adr;
375}
376
377bool
379{
380 return m_adr;
381}
382
383void
385{
386 m_adrAckReq = adrAckReq;
387}
388
389bool
391{
392 return m_adrAckReq;
393}
394
395void
397{
398 NS_LOG_FUNCTION(this << ack);
399 m_ack = ack;
400}
401
402bool
404{
405 return m_ack;
406}
407
408void
410{
411 m_fPending = fPending;
412}
413
414bool
416{
417 return m_fPending;
418}
419
420uint8_t
422{
423 // Sum the serialized length of all commands in the list
424 uint8_t fOptsLen = 0;
425 std::list<Ptr<MacCommand>>::const_iterator it;
426 for (it = m_macCommands.begin(); it != m_macCommands.end(); it++)
427 {
428 fOptsLen = fOptsLen + (*it)->GetSerializedSize();
429 }
430 return fOptsLen;
431}
432
433void
435{
436 m_fCnt = fCnt;
437}
438
439uint16_t
441{
442 return m_fCnt;
443}
444
445void
447{
449
450 Ptr<LinkCheckReq> command = Create<LinkCheckReq>();
451 m_macCommands.emplace_back(command);
452
453 NS_LOG_DEBUG("Command SerializedSize: " << unsigned(command->GetSerializedSize()));
454 m_fOptsLen += command->GetSerializedSize();
455}
456
457void
458LoraFrameHeader::AddLinkCheckAns(uint8_t margin, uint8_t gwCnt)
459{
460 NS_LOG_FUNCTION(this << unsigned(margin) << unsigned(gwCnt));
461
462 Ptr<LinkCheckAns> command = Create<LinkCheckAns>(margin, gwCnt);
463 m_macCommands.emplace_back(command);
464
465 m_fOptsLen += command->GetSerializedSize();
466}
467
468void
470 uint8_t txPower,
471 std::list<int> enabledChannels,
472 int repetitions)
473{
474 NS_LOG_FUNCTION(this << unsigned(dataRate) << txPower << repetitions);
475
476 uint16_t channelMask = 0;
477 for (auto it = enabledChannels.begin(); it != enabledChannels.end(); it++)
478 {
479 NS_ASSERT((*it) < 16 && (*it) > -1);
480
481 channelMask |= 0b1 << (*it);
482 }
483
484 // TODO Implement chMaskCntl field
485
486 NS_LOG_DEBUG("Creating LinkAdrReq with: DR = " << unsigned(dataRate)
487 << " and txPower = " << unsigned(txPower));
488
489 Ptr<LinkAdrReq> command = Create<LinkAdrReq>(dataRate, txPower, channelMask, 0, repetitions);
490 m_macCommands.emplace_back(command);
491
492 m_fOptsLen += command->GetSerializedSize();
493}
494
495void
496LoraFrameHeader::AddLinkAdrAns(bool powerAck, bool dataRateAck, bool channelMaskAck)
497{
498 NS_LOG_FUNCTION(this << powerAck << dataRateAck << channelMaskAck);
499
500 Ptr<LinkAdrAns> command = Create<LinkAdrAns>(powerAck, dataRateAck, channelMaskAck);
501 m_macCommands.emplace_back(command);
502
503 m_fOptsLen += command->GetSerializedSize();
504}
505
506void
508{
509 NS_LOG_FUNCTION(this << unsigned(dutyCycle));
510
511 Ptr<DutyCycleReq> command = Create<DutyCycleReq>(dutyCycle);
512
513 m_macCommands.emplace_back(command);
514
515 m_fOptsLen += command->GetSerializedSize();
516}
517
518void
520{
521 NS_LOG_FUNCTION(this);
522
523 Ptr<DutyCycleAns> command = Create<DutyCycleAns>();
524
525 m_macCommands.emplace_back(command);
526
527 m_fOptsLen += command->GetSerializedSize();
528}
529
530void
531LoraFrameHeader::AddRxParamSetupReq(uint8_t rx1DrOffset, uint8_t rx2DataRate, double frequency)
532{
533 NS_LOG_FUNCTION(this << unsigned(rx1DrOffset) << unsigned(rx2DataRate) << frequency);
534
535 // Evaluate whether to eliminate this assert in case new offsets can be defined.
536 NS_ASSERT(0 <= rx1DrOffset && rx1DrOffset <= 5);
537
538 Ptr<RxParamSetupReq> command = Create<RxParamSetupReq>(rx1DrOffset, rx2DataRate, frequency);
539
540 m_macCommands.emplace_back(command);
541
542 m_fOptsLen += command->GetSerializedSize();
543}
544
545void
547{
548 NS_LOG_FUNCTION(this);
549
550 Ptr<RxParamSetupAns> command = Create<RxParamSetupAns>();
551
552 m_macCommands.emplace_back(command);
553
554 m_fOptsLen += command->GetSerializedSize();
555}
556
557void
559{
560 NS_LOG_FUNCTION(this);
561
562 Ptr<DevStatusReq> command = Create<DevStatusReq>();
563
564 m_macCommands.emplace_back(command);
565
566 m_fOptsLen += command->GetSerializedSize();
567}
568
569void
571 double frequency,
572 uint8_t minDataRate,
573 uint8_t maxDataRate)
574{
575 NS_LOG_FUNCTION(this);
576
577 Ptr<NewChannelReq> command =
578 Create<NewChannelReq>(chIndex, frequency, minDataRate, maxDataRate);
579
580 m_macCommands.emplace_back(command);
581
582 m_fOptsLen += command->GetSerializedSize();
583}
584
585std::list<Ptr<MacCommand>>
587{
589
590 return m_macCommands;
591}
592
593void
595{
596 NS_LOG_FUNCTION(this << macCommand);
597
598 m_macCommands.push_back(macCommand);
599 m_fOptsLen += macCommand->GetSerializedSize();
600}
601
602} // namespace lorawan
603} // namespace ns3
iterator in a Buffer instance
Definition: buffer.h:100
Protocol header serialization and deserialization.
Definition: header.h:44
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:77
a unique identifier for an interface.
Definition: type-id.h:59
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:932
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:66
#define NS_LOG_ERROR(msg)
Use NS_LOG to output a message of level LOG_ERROR.
Definition: log.h:254
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:202
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition: log.h:268
#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:275
Every class exported by the ns3 library is enclosed in the ns3 namespace.