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