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
11namespace ns3
12{
13namespace lorawan
14{
15
16NS_LOG_COMPONENT_DEFINE("LoraFrameHeader");
17
18// Initialization list
20 : m_fPort(0),
22 m_adr(false),
23 m_adrAckReq(false),
24 m_ack(false),
25 m_fPending(false),
26 m_fOptsLen(0),
27 m_fCnt(0)
28{
29}
30
34
37{
38 static TypeId tid =
39 TypeId("LoraFrameHeader").SetParent<Header>().AddConstructor<LoraFrameHeader>();
40 return tid;
41}
42
45{
46 return GetTypeId();
47}
48
51{
52 NS_LOG_FUNCTION(this);
53 // 4 for DevAddr + 1 for FCtrl + 2 for FCnt + 1 for FPort + 0-15 for FOpts
54 uint32_t size = 8 + m_fOptsLen;
55 NS_LOG_INFO("LoraFrameHeader serialized size: " << size);
56 return size;
57}
58
59void
61{
62 NS_LOG_FUNCTION(this);
63
64 // Device Address field
65 start.WriteU32(m_address.Get());
66
67 // fCtrl field
68 //
69 // TODO FCtrl has different meanings for UL and DL packets. Handle this
70 // correctly here.
71 uint8_t fCtrl = 0;
72 fCtrl |= uint8_t(m_adr << 7 & 0b10000000);
73 fCtrl |= uint8_t(m_adrAckReq << 6 & 0b1000000);
74 fCtrl |= uint8_t(m_ack << 5 & 0b100000);
75 fCtrl |= uint8_t(m_fPending << 4 & 0b10000);
76 fCtrl |= m_fOptsLen & 0b1111;
77 start.WriteU8(fCtrl);
78
79 // FCnt field
80 start.WriteU16(m_fCnt);
81
82 // FOpts field
83 for (const auto& c : m_macCommands)
84 {
85 NS_LOG_DEBUG("Serializing a MAC command");
86 c->Serialize(start);
87 }
88
89 // FPort
90 start.WriteU8(m_fPort);
91}
92
95{
96 NS_LOG_FUNCTION(this);
97
98 // Empty the list of MAC commands
99 m_macCommands.clear();
100
101 // Read from buffer and save into local variables
102 m_address.Set(start.ReadU32());
103 // TODO FCtrl has different meanings for UL and DL packets. Handle this
104 // correctly here.
105 uint8_t fCtrl = start.ReadU8();
106 m_adr = (fCtrl >> 7) & 0b1;
107 m_adrAckReq = (fCtrl >> 6) & 0b1;
108 m_ack = (fCtrl >> 5) & 0b1;
109 m_fPending = (fCtrl >> 4) & 0b1;
110 m_fOptsLen = fCtrl & 0b1111;
111 m_fCnt = start.ReadU16();
112
113 // Deserialize MAC commands
114 NS_LOG_DEBUG("Starting deserialization of MAC commands");
115 for (uint8_t byteNumber = 0; byteNumber < m_fOptsLen;)
116 {
117 uint8_t cid = start.PeekU8();
118 NS_LOG_DEBUG("CID: " << unsigned(cid));
119
120 // Divide Uplink and Downlink messages
121 // This needs to be done because they have the same CID, and the context
122 // about where this message will be Serialized/Deserialized (i.e., at the
123 // end device or at the network server) is umportant.
124 Ptr<MacCommand> command;
125 if (m_isUplink)
126 {
127 switch (cid)
128 {
129 // In the case of Uplink messages, the network server will deserialize the
130 // request for a link check
131 case (0x02): {
132 NS_LOG_DEBUG("Creating a LinkCheckReq command");
133 command = Create<LinkCheckReq>();
134 break;
135 }
136 case (0x03): {
137 NS_LOG_DEBUG("Creating a LinkAdrAns command");
138 command = Create<LinkAdrAns>();
139 break;
140 }
141 case (0x04): {
142 NS_LOG_DEBUG("Creating a DutyCycleAns command");
143 command = Create<DutyCycleAns>();
144 break;
145 }
146 case (0x05): {
147 NS_LOG_DEBUG("Creating a RxParamSetupAns command");
148 command = Create<RxParamSetupAns>();
149 break;
150 }
151 case (0x06): {
152 NS_LOG_DEBUG("Creating a DevStatusAns command");
153 command = Create<DevStatusAns>();
154 break;
155 }
156 case (0x07): {
157 NS_LOG_DEBUG("Creating a NewChannelAns command");
158 command = Create<NewChannelAns>();
159 break;
160 }
161 case (0x08): {
162 NS_LOG_DEBUG("Creating a RxTimingSetupAns command");
163 command = Create<RxTimingSetupAns>();
164 break;
165 }
166 case (0x09): {
167 NS_LOG_DEBUG("Creating a TxParamSetupAns command");
168 command = Create<TxParamSetupAns>();
169 break;
170 }
171 case (0x0A): {
172 NS_LOG_DEBUG("Creating a DlChannelAns command");
173 command = Create<DlChannelAns>();
174 break;
175 }
176 default: {
177 NS_LOG_ERROR("CID not recognized during deserialization");
178 }
179 }
180 }
181 else
182 {
183 switch (cid)
184 {
185 // In the case of Downlink messages, the end device will deserialize the
186 // answer to a link check
187 case (0x02): {
188 NS_LOG_DEBUG("Creating a LinkCheckAns command");
189 command = Create<LinkCheckAns>();
190 break;
191 }
192 case (0x03): {
193 NS_LOG_DEBUG("Creating a LinkAdrReq command");
194 command = Create<LinkAdrReq>();
195 break;
196 }
197 case (0x04): {
198 NS_LOG_DEBUG("Creating a DutyCycleReq command");
199 command = Create<DutyCycleReq>();
200 break;
201 }
202 case (0x05): {
203 NS_LOG_DEBUG("Creating a RxParamSetupReq command");
204 command = Create<RxParamSetupReq>();
205 break;
206 }
207 case (0x06): {
208 NS_LOG_DEBUG("Creating a DevStatusReq command");
209 command = Create<DevStatusReq>();
210 break;
211 }
212 case (0x07): {
213 NS_LOG_DEBUG("Creating a NewChannelReq command");
214 command = Create<NewChannelReq>();
215 break;
216 }
217 case (0x08): {
218 NS_LOG_DEBUG("Creating a RxTimingSetupReq command");
219 command = Create<RxTimingSetupReq>();
220 break;
221 }
222 case (0x09): {
223 NS_LOG_DEBUG("Creating a TxParamSetupReq command");
224 command = Create<TxParamSetupReq>();
225 break;
226 }
227 default: {
228 NS_LOG_ERROR("CID not recognized during deserialization");
229 }
230 }
231 }
232 byteNumber += command->Deserialize(start);
233 m_macCommands.emplace_back(command);
234 }
235 m_fPort = start.ReadU8();
236 return 8 + m_fOptsLen; // the number of bytes consumed.
237}
238
239void
240LoraFrameHeader::Print(std::ostream& os) const
241{
242 os << "Address=" << m_address.Print();
243 os << ", ADR=" << m_adr;
244 os << ", ADRAckReq=" << m_adrAckReq;
245 os << ", ACK=" << m_ack;
246 os << ", FPending=" << m_fPending;
247 os << ", FOptsLen=" << unsigned(m_fOptsLen);
248 os << ", FCnt=" << unsigned(m_fCnt);
249 for (const auto& c : m_macCommands)
250 {
251 os << ", ";
252 c->Print(os);
253 }
254 os << ", FPort=" << unsigned(m_fPort);
255}
256
257void
259{
260 NS_LOG_FUNCTION(this);
261 m_isUplink = true;
262}
263
264void
270
271void
273{
274 m_fPort = fPort;
275}
276
277uint8_t
279{
280 return m_fPort;
281}
282
283void
288
291{
292 return m_address;
293}
294
295void
297{
298 NS_LOG_FUNCTION(this << adr);
299 m_adr = adr;
300}
301
302bool
304{
305 return m_adr;
306}
307
308void
310{
311 m_adrAckReq = adrAckReq;
312}
313
314bool
316{
317 return m_adrAckReq;
318}
319
320void
322{
323 NS_LOG_FUNCTION(this << ack);
324 m_ack = ack;
325}
326
327bool
329{
330 return m_ack;
331}
332
333void
335{
336 m_fPending = fPending;
337}
338
339bool
341{
342 return m_fPending;
343}
344
345uint8_t
347{
348 uint8_t fOptsLen = 0;
349 for (const auto& c : m_macCommands)
350 {
351 fOptsLen += c->GetSerializedSize();
352 }
353 return fOptsLen;
354}
355
356void
358{
359 m_fCnt = fCnt;
360}
361
362uint16_t
364{
365 return m_fCnt;
366}
367
368void
370{
371 NS_LOG_FUNCTION(this);
372 auto command = Create<LinkCheckReq>();
373 m_macCommands.emplace_back(command);
374 m_fOptsLen += command->GetSerializedSize();
375}
376
377void
378LoraFrameHeader::AddLinkCheckAns(uint8_t margin, uint8_t gwCnt)
379{
380 NS_LOG_FUNCTION(this << unsigned(margin) << unsigned(gwCnt));
381 auto command = Create<LinkCheckAns>(margin, gwCnt);
382 m_macCommands.emplace_back(command);
383 m_fOptsLen += command->GetSerializedSize();
384}
385
386void
388 uint8_t txPower,
389 std::list<int> enabledChannels,
390 int repetitions)
391{
392 NS_LOG_FUNCTION(this << unsigned(dataRate) << txPower << repetitions);
393 uint16_t channelMask = 0;
394 for (const auto chId : enabledChannels)
395 {
396 NS_ASSERT(chId < 16 && chId > -1);
397 channelMask |= 0b1 << chId;
398 }
399 /// @todo Implement chMaskCntl field
400 auto command = Create<LinkAdrReq>(dataRate, txPower, channelMask, 0, repetitions);
401 m_macCommands.emplace_back(command);
402 m_fOptsLen += command->GetSerializedSize();
403}
404
405void
406LoraFrameHeader::AddLinkAdrAns(bool powerAck, bool dataRateAck, bool channelMaskAck)
407{
408 NS_LOG_FUNCTION(this << powerAck << dataRateAck << channelMaskAck);
409 auto command = Create<LinkAdrAns>(powerAck, dataRateAck, channelMaskAck);
410 m_macCommands.emplace_back(command);
411 m_fOptsLen += command->GetSerializedSize();
412}
413
414void
416{
417 NS_LOG_FUNCTION(this << unsigned(dutyCycle));
418 auto command = Create<DutyCycleReq>(dutyCycle);
419 m_macCommands.emplace_back(command);
420 m_fOptsLen += command->GetSerializedSize();
421}
422
423void
425{
426 NS_LOG_FUNCTION(this);
427 auto command = Create<DutyCycleAns>();
428 m_macCommands.emplace_back(command);
429 m_fOptsLen += command->GetSerializedSize();
430}
431
432void
433LoraFrameHeader::AddRxParamSetupReq(uint8_t rx1DrOffset, uint8_t rx2DataRate, uint32_t frequencyHz)
434{
435 NS_LOG_FUNCTION(this << unsigned(rx1DrOffset) << unsigned(rx2DataRate) << frequencyHz);
436 // Evaluate whether to eliminate this assert in case new offsets can be defined.
437 NS_ASSERT(0 <= rx1DrOffset && rx1DrOffset <= 5);
438 auto command = Create<RxParamSetupReq>(rx1DrOffset, rx2DataRate, frequencyHz);
439 m_macCommands.emplace_back(command);
440 m_fOptsLen += command->GetSerializedSize();
441}
442
443void
445{
446 NS_LOG_FUNCTION(this);
447 auto command = Create<RxParamSetupAns>();
448 m_macCommands.emplace_back(command);
449 m_fOptsLen += command->GetSerializedSize();
450}
451
452void
454{
455 NS_LOG_FUNCTION(this);
456 auto command = Create<DevStatusReq>();
457 m_macCommands.emplace_back(command);
458 m_fOptsLen += command->GetSerializedSize();
459}
460
461void
463 uint32_t frequencyHz,
464 uint8_t minDataRate,
465 uint8_t maxDataRate)
466{
467 NS_LOG_FUNCTION(this << unsigned(chIndex) << frequencyHz << unsigned(minDataRate)
468 << unsigned(maxDataRate));
469 auto command = Create<NewChannelReq>(chIndex, frequencyHz, minDataRate, maxDataRate);
470 m_macCommands.emplace_back(command);
471 m_fOptsLen += command->GetSerializedSize();
472}
473
474std::vector<Ptr<MacCommand>>
480
481void
483{
484 NS_LOG_FUNCTION(this << macCommand);
485 m_macCommands.emplace_back(macCommand);
486 m_fOptsLen += macCommand->GetSerializedSize();
487}
488
489} // namespace lorawan
490} // namespace ns3
iterator in a Buffer instance
Definition buffer.h:89
Protocol header serialization and deserialization.
Definition header.h:36
Smart pointer class similar to boost::intrusive_ptr.
Definition ptr.h:70
a unique identifier for an interface.
Definition type-id.h:50
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition type-id.cc:999
This class represents the device address of a LoraWAN end device.
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:246
#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(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:267
Ptr< T > Create(Ts &&... args)
Create class instances by constructors with varying numbers of arguments and return them by Ptr.
Definition ptr.h:454
Every class exported by the ns3 library is enclosed in the ns3 namespace.