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{
56 NS_LOG_FUNCTION(this);
57 // 4 for DevAddr + 1 for FCtrl + 2 for FCnt + 1 for FPort + 0-15 for FOpts
58 uint32_t size = 8 + m_fOptsLen;
59 NS_LOG_INFO("LoraFrameHeader serialized size: " << size);
60 return size;
61}
62
63void
65{
66 NS_LOG_FUNCTION(this);
67
68 // Device Address field
69 start.WriteU32(m_address.Get());
70
71 // fCtrl field
72 //
73 // TODO FCtrl has different meanings for UL and DL packets. Handle this
74 // correctly here.
75 uint8_t fCtrl = 0;
76 fCtrl |= uint8_t(m_adr << 7 & 0b10000000);
77 fCtrl |= uint8_t(m_adrAckReq << 6 & 0b1000000);
78 fCtrl |= uint8_t(m_ack << 5 & 0b100000);
79 fCtrl |= uint8_t(m_fPending << 4 & 0b10000);
80 fCtrl |= m_fOptsLen & 0b1111;
81 start.WriteU8(fCtrl);
82
83 // FCnt field
84 start.WriteU16(m_fCnt);
85
86 // FOpts field
87 for (const auto& c : m_macCommands)
88 {
89 NS_LOG_DEBUG("Serializing a MAC command");
90 c->Serialize(start);
91 }
92
93 // FPort
94 start.WriteU8(m_fPort);
95}
96
99{
100 NS_LOG_FUNCTION(this);
101
102 // Empty the list of MAC commands
103 m_macCommands.clear();
104
105 // Read from buffer and save into local variables
106 m_address.Set(start.ReadU32());
107 // TODO FCtrl has different meanings for UL and DL packets. Handle this
108 // correctly here.
109 uint8_t fCtrl = start.ReadU8();
110 m_adr = (fCtrl >> 7) & 0b1;
111 m_adrAckReq = (fCtrl >> 6) & 0b1;
112 m_ack = (fCtrl >> 5) & 0b1;
113 m_fPending = (fCtrl >> 4) & 0b1;
114 m_fOptsLen = fCtrl & 0b1111;
115 m_fCnt = start.ReadU16();
116
117 // Deserialize MAC commands
118 NS_LOG_DEBUG("Starting deserialization of MAC commands");
119 for (uint8_t byteNumber = 0; byteNumber < m_fOptsLen;)
120 {
121 uint8_t cid = start.PeekU8();
122 NS_LOG_DEBUG("CID: " << unsigned(cid));
123
124 // Divide Uplink and Downlink messages
125 // This needs to be done because they have the same CID, and the context
126 // about where this message will be Serialized/Deserialized (i.e., at the
127 // end device or at the network server) is umportant.
128 Ptr<MacCommand> command;
129 if (m_isUplink)
130 {
131 switch (cid)
132 {
133 // In the case of Uplink messages, the network server will deserialize the
134 // request for a link check
135 case (0x02): {
136 NS_LOG_DEBUG("Creating a LinkCheckReq command");
137 command = Create<LinkCheckReq>();
138 break;
139 }
140 case (0x03): {
141 NS_LOG_DEBUG("Creating a LinkAdrAns command");
142 command = Create<LinkAdrAns>();
143 break;
144 }
145 case (0x04): {
146 NS_LOG_DEBUG("Creating a DutyCycleAns command");
147 command = Create<DutyCycleAns>();
148 break;
149 }
150 case (0x05): {
151 NS_LOG_DEBUG("Creating a RxParamSetupAns command");
152 command = Create<RxParamSetupAns>();
153 break;
154 }
155 case (0x06): {
156 NS_LOG_DEBUG("Creating a DevStatusAns command");
157 command = Create<DevStatusAns>();
158 break;
159 }
160 case (0x07): {
161 NS_LOG_DEBUG("Creating a NewChannelAns command");
162 command = Create<NewChannelAns>();
163 break;
164 }
165 case (0x08): {
166 NS_LOG_DEBUG("Creating a RxTimingSetupAns command");
167 command = Create<RxTimingSetupAns>();
168 break;
169 }
170 case (0x09): {
171 NS_LOG_DEBUG("Creating a TxParamSetupAns command");
172 command = Create<TxParamSetupAns>();
173 break;
174 }
175 case (0x0A): {
176 NS_LOG_DEBUG("Creating a DlChannelAns command");
177 command = Create<DlChannelAns>();
178 break;
179 }
180 default: {
181 NS_LOG_ERROR("CID not recognized during deserialization");
182 }
183 }
184 }
185 else
186 {
187 switch (cid)
188 {
189 // In the case of Downlink messages, the end device will deserialize the
190 // answer to a link check
191 case (0x02): {
192 NS_LOG_DEBUG("Creating a LinkCheckAns command");
193 command = Create<LinkCheckAns>();
194 break;
195 }
196 case (0x03): {
197 NS_LOG_DEBUG("Creating a LinkAdrReq command");
198 command = Create<LinkAdrReq>();
199 break;
200 }
201 case (0x04): {
202 NS_LOG_DEBUG("Creating a DutyCycleReq command");
203 command = Create<DutyCycleReq>();
204 break;
205 }
206 case (0x05): {
207 NS_LOG_DEBUG("Creating a RxParamSetupReq command");
208 command = Create<RxParamSetupReq>();
209 break;
210 }
211 case (0x06): {
212 NS_LOG_DEBUG("Creating a DevStatusReq command");
213 command = Create<DevStatusReq>();
214 break;
215 }
216 case (0x07): {
217 NS_LOG_DEBUG("Creating a NewChannelReq command");
218 command = Create<NewChannelReq>();
219 break;
220 }
221 case (0x08): {
222 NS_LOG_DEBUG("Creating a RxTimingSetupReq command");
223 command = Create<RxTimingSetupReq>();
224 break;
225 }
226 case (0x09): {
227 NS_LOG_DEBUG("Creating a TxParamSetupReq command");
228 command = Create<TxParamSetupReq>();
229 break;
230 }
231 default: {
232 NS_LOG_ERROR("CID not recognized during deserialization");
233 }
234 }
235 }
236 byteNumber += command->Deserialize(start);
237 m_macCommands.emplace_back(command);
238 }
239 m_fPort = start.ReadU8();
240 return 8 + m_fOptsLen; // the number of bytes consumed.
241}
242
243void
244LoraFrameHeader::Print(std::ostream& os) const
245{
246 os << "Address=" << m_address.Print();
247 os << ", ADR=" << m_adr;
248 os << ", ADRAckReq=" << m_adrAckReq;
249 os << ", ACK=" << m_ack;
250 os << ", FPending=" << m_fPending;
251 os << ", FOptsLen=" << unsigned(m_fOptsLen);
252 os << ", FCnt=" << unsigned(m_fCnt);
253 for (const auto& c : m_macCommands)
254 {
255 os << ", ";
256 c->Print(os);
257 }
258 os << ", FPort=" << unsigned(m_fPort);
259}
260
261void
263{
264 NS_LOG_FUNCTION(this);
265 m_isUplink = true;
266}
267
268void
274
275void
277{
278 m_fPort = fPort;
279}
280
281uint8_t
283{
284 return m_fPort;
285}
286
287void
292
295{
296 return m_address;
297}
298
299void
301{
302 NS_LOG_FUNCTION(this << adr);
303 m_adr = adr;
304}
305
306bool
308{
309 return m_adr;
310}
311
312void
314{
315 m_adrAckReq = adrAckReq;
316}
317
318bool
320{
321 return m_adrAckReq;
322}
323
324void
326{
327 NS_LOG_FUNCTION(this << ack);
328 m_ack = ack;
329}
330
331bool
333{
334 return m_ack;
335}
336
337void
339{
340 m_fPending = fPending;
341}
342
343bool
345{
346 return m_fPending;
347}
348
349uint8_t
351{
352 uint8_t fOptsLen = 0;
353 for (const auto& c : m_macCommands)
354 {
355 fOptsLen += c->GetSerializedSize();
356 }
357 return fOptsLen;
358}
359
360void
362{
363 m_fCnt = fCnt;
364}
365
366uint16_t
368{
369 return m_fCnt;
370}
371
372void
374{
375 NS_LOG_FUNCTION(this);
376 auto command = Create<LinkCheckReq>();
377 m_macCommands.emplace_back(command);
378 m_fOptsLen += command->GetSerializedSize();
379}
380
381void
382LoraFrameHeader::AddLinkCheckAns(uint8_t margin, uint8_t gwCnt)
383{
384 NS_LOG_FUNCTION(this << unsigned(margin) << unsigned(gwCnt));
385 auto command = Create<LinkCheckAns>(margin, gwCnt);
386 m_macCommands.emplace_back(command);
387 m_fOptsLen += command->GetSerializedSize();
388}
389
390void
392 uint8_t txPower,
393 std::list<int> enabledChannels,
394 int repetitions)
395{
396 NS_LOG_FUNCTION(this << unsigned(dataRate) << txPower << repetitions);
397 uint16_t channelMask = 0;
398 for (const auto chId : enabledChannels)
399 {
400 NS_ASSERT(chId < 16 && chId > -1);
401 channelMask |= 0b1 << chId;
402 }
403 /// @todo Implement chMaskCntl field
404 auto command = Create<LinkAdrReq>(dataRate, txPower, channelMask, 0, repetitions);
405 m_macCommands.emplace_back(command);
406 m_fOptsLen += command->GetSerializedSize();
407}
408
409void
410LoraFrameHeader::AddLinkAdrAns(bool powerAck, bool dataRateAck, bool channelMaskAck)
411{
412 NS_LOG_FUNCTION(this << powerAck << dataRateAck << channelMaskAck);
413 auto command = Create<LinkAdrAns>(powerAck, dataRateAck, channelMaskAck);
414 m_macCommands.emplace_back(command);
415 m_fOptsLen += command->GetSerializedSize();
416}
417
418void
420{
421 NS_LOG_FUNCTION(this << unsigned(dutyCycle));
422 auto command = Create<DutyCycleReq>(dutyCycle);
423 m_macCommands.emplace_back(command);
424 m_fOptsLen += command->GetSerializedSize();
425}
426
427void
429{
430 NS_LOG_FUNCTION(this);
431 auto command = Create<DutyCycleAns>();
432 m_macCommands.emplace_back(command);
433 m_fOptsLen += command->GetSerializedSize();
434}
435
436void
437LoraFrameHeader::AddRxParamSetupReq(uint8_t rx1DrOffset, uint8_t rx2DataRate, uint32_t frequencyHz)
438{
439 NS_LOG_FUNCTION(this << unsigned(rx1DrOffset) << unsigned(rx2DataRate) << frequencyHz);
440 // Evaluate whether to eliminate this assert in case new offsets can be defined.
441 NS_ASSERT(0 <= rx1DrOffset && rx1DrOffset <= 5);
442 auto command = Create<RxParamSetupReq>(rx1DrOffset, rx2DataRate, frequencyHz);
443 m_macCommands.emplace_back(command);
444 m_fOptsLen += command->GetSerializedSize();
445}
446
447void
449{
450 NS_LOG_FUNCTION(this);
451 auto command = Create<RxParamSetupAns>();
452 m_macCommands.emplace_back(command);
453 m_fOptsLen += command->GetSerializedSize();
454}
455
456void
458{
459 NS_LOG_FUNCTION(this);
460 auto command = Create<DevStatusReq>();
461 m_macCommands.emplace_back(command);
462 m_fOptsLen += command->GetSerializedSize();
463}
464
465void
467 uint32_t frequencyHz,
468 uint8_t minDataRate,
469 uint8_t maxDataRate)
470{
471 NS_LOG_FUNCTION(this << unsigned(chIndex) << frequencyHz << unsigned(minDataRate)
472 << unsigned(maxDataRate));
473 auto command = Create<NewChannelReq>(chIndex, frequencyHz, minDataRate, maxDataRate);
474 m_macCommands.emplace_back(command);
475 m_fOptsLen += command->GetSerializedSize();
476}
477
478std::vector<Ptr<MacCommand>>
484
485void
487{
488 NS_LOG_FUNCTION(this << macCommand);
489 m_macCommands.emplace_back(macCommand);
490 m_fOptsLen += macCommand->GetSerializedSize();
491}
492
493} // namespace lorawan
494} // 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:49
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.
std::vector< Ptr< MacCommand > > GetCommands()
Return a vector of pointers to all the MAC commands saved in this header.
bool m_ack
The ACK field of the FCtrl.
std::vector< Ptr< MacCommand > > m_macCommands
Vector containing all the MacCommand instances that are contained in this LoraFrameHeader.
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 vector 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 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.
void AddNewChannelReq(uint8_t chIndex, uint32_t frequencyHz, uint8_t minDataRate, uint8_t maxDataRate)
Add a NewChannelReq command with provided fields.
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.
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 AddRxParamSetupReq(uint8_t rx1DrOffset, uint8_t rx2DataRate, uint32_t frequencyHz)
Add a RxParamSetupReq command.
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.
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.
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(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.