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 
27 namespace ns3
28 {
29 
30 NS_LOG_COMPONENT_DEFINE("LoraFrameHeader");
31 
32 // Initialization list
34  : m_fPort(0),
35  m_address(LoraDeviceAddress(0, 0)),
36  m_adr(0),
37  m_adrAckReq(0),
38  m_ack(0),
39  m_fPending(0),
40  m_fOptsLen(0),
41  m_fCnt(0)
42 {
43 }
44 
46 {
47 }
48 
49 TypeId
51 {
52  static TypeId tid =
53  TypeId("LoraFrameHeader").SetParent<Header>().AddConstructor<LoraFrameHeader>();
54  return tid;
55 }
56 
57 TypeId
59 {
60  return GetTypeId();
61 }
62 
63 uint32_t
65 {
66  NS_LOG_FUNCTION_NOARGS();
67 
68  // Sizes in bytes:
69  // 4 for DevAddr + 1 for FCtrl + 2 for FCnt + 1 for FPort + 0-15 for FOpts
70  uint32_t size = 8 + m_fOptsLen;
71 
72  NS_LOG_INFO("LoraFrameHeader serialized size: " << size);
73 
74  return size;
75 }
76 
77 void
78 LoraFrameHeader::Serialize(Buffer::Iterator start) const
79 {
80  NS_LOG_FUNCTION_NOARGS();
81 
82  // Device Address field
83  start.WriteU32(m_address.Get());
84 
85  // fCtrl field
86  uint8_t fCtrl = 0;
87  fCtrl |= uint8_t(m_adr << 6 & 0b1000000);
88  fCtrl |= uint8_t(m_adrAckReq << 5 & 0b100000);
89  fCtrl |= uint8_t(m_ack << 4 & 0b10000);
90  fCtrl |= uint8_t(m_fPending << 3 & 0b1000);
91  fCtrl |= m_fOptsLen & 0b111;
92  start.WriteU8(fCtrl);
93 
94  // FCnt field
95  start.WriteU16(m_fCnt);
96 
97  // FOpts field
98  for (auto it = m_macCommands.begin(); it != m_macCommands.end(); it++)
99  {
100  NS_LOG_DEBUG("Serializing a MAC command");
101  (*it)->Serialize(start);
102  }
103 
104  // FPort
105  start.WriteU8(m_fPort);
106 }
107 
108 uint32_t
109 LoraFrameHeader::Deserialize(Buffer::Iterator start)
110 {
111  NS_LOG_FUNCTION_NOARGS();
112 
113  // Empty the list of MAC commands
114  m_macCommands.clear();
115 
116  // Read from buffer and save into local variables
117  m_address.Set(start.ReadU32());
118  uint8_t fCtl = start.ReadU8();
119  m_adr = (fCtl >> 6) & 0b1;
120  m_adrAckReq = (fCtl >> 5) & 0b1;
121  m_ack = (fCtl >> 4) & 0b1;
122  m_fPending = (fCtl >> 3) & 0b1;
123  m_fOptsLen = fCtl & 0b111;
124  m_fCnt = start.ReadU16();
125 
126  NS_LOG_DEBUG("Deserialized data: ");
127  NS_LOG_DEBUG("Address: " << m_address.Print());
128  NS_LOG_DEBUG("ADR: " << unsigned(m_adr));
129  NS_LOG_DEBUG("ADRAckReq: " << unsigned(m_adrAckReq));
130  NS_LOG_DEBUG("Ack: " << unsigned(m_ack));
131  NS_LOG_DEBUG("fPending: " << unsigned(m_fPending));
132  NS_LOG_DEBUG("fOptsLen: " << unsigned(m_fOptsLen));
133  NS_LOG_DEBUG("fCnt: " << unsigned(m_fCnt));
134 
135  // Deserialize MAC commands
136  NS_LOG_DEBUG("Starting deserialization of MAC commands");
137  for (uint8_t byteNumber = 0; byteNumber < m_fOptsLen;)
138  {
139  uint8_t cid = start.PeekU8();
140  NS_LOG_DEBUG("CID: " << unsigned(cid));
141 
142  // Divide Uplink and Downlink messages
143  // This needs to be done because they have the same CID, and the context
144  // about where this message will be Serialized/Deserialized (i.e., at the
145  // ED or at the NS) is umportant.
146  if (m_isUplink)
147  {
148  switch (cid)
149  {
150  // In the case of Uplink messages, the NS will deserialize the
151  // request for a link check
152  case (0x02): {
153  NS_LOG_DEBUG("Creating a LinkCheckReq command");
154  Ptr<LinkCheckReq> command = Create<LinkCheckReq>();
155  byteNumber += command->Deserialize(start);
156  m_macCommands.push_back(command);
157  break;
158  }
159  case (0x03): {
160  NS_LOG_DEBUG("Creating a LinkAdrAns command");
161  Ptr<LinkAdrAns> command = Create<LinkAdrAns>();
162  byteNumber += command->Deserialize(start);
163  m_macCommands.push_back(command);
164  break;
165  }
166  case (0x04): {
167  NS_LOG_DEBUG("Creating a DutyCycleAns command");
168  Ptr<DutyCycleAns> command = Create<DutyCycleAns>();
169  byteNumber += command->Deserialize(start);
170  m_macCommands.push_back(command);
171  break;
172  }
173  case (0x05): {
174  NS_LOG_DEBUG("Creating a RxParamSetupAns command");
175  Ptr<RxParamSetupAns> command = Create<RxParamSetupAns>();
176  byteNumber += command->Deserialize(start);
177  m_macCommands.push_back(command);
178  break;
179  }
180  case (0x06): {
181  NS_LOG_DEBUG("Creating a DevStatusAns command");
182  Ptr<DevStatusAns> command = Create<DevStatusAns>();
183  byteNumber += command->Deserialize(start);
184  m_macCommands.push_back(command);
185  break;
186  }
187  case (0x07): {
188  NS_LOG_DEBUG("Creating a NewChannelAns command");
189  Ptr<NewChannelAns> command = Create<NewChannelAns>();
190  byteNumber += command->Deserialize(start);
191  m_macCommands.push_back(command);
192  break;
193  }
194  case (0x08): {
195  NS_LOG_DEBUG("Creating a RxTimingSetupAns command");
196  Ptr<RxTimingSetupAns> command = Create<RxTimingSetupAns>();
197  byteNumber += command->Deserialize(start);
198  m_macCommands.push_back(command);
199  break;
200  }
201  case (0x09): {
202  NS_LOG_DEBUG("Creating a TxParamSetupAns command");
203  Ptr<TxParamSetupAns> command = Create<TxParamSetupAns>();
204  byteNumber += command->Deserialize(start);
205  m_macCommands.push_back(command);
206  break;
207  }
208  case (0x0A): {
209  NS_LOG_DEBUG("Creating a DlChannelAns command");
210  Ptr<DlChannelAns> command = Create<DlChannelAns>();
211  byteNumber += command->Deserialize(start);
212  m_macCommands.push_back(command);
213  break;
214  }
215  default: {
216  NS_LOG_ERROR("CID not recognized during deserialization");
217  }
218  }
219  }
220  else
221  {
222  switch (cid)
223  {
224  // In the case of Downlink messages, the ED will deserialize the
225  // answer to a link check
226  case (0x02): {
227  NS_LOG_DEBUG("Creating a LinkCheckAns command");
228  Ptr<LinkCheckAns> command = Create<LinkCheckAns>();
229  byteNumber += command->Deserialize(start);
230  m_macCommands.push_back(command);
231  break;
232  }
233  case (0x03): {
234  NS_LOG_DEBUG("Creating a LinkAdrReq command");
235  Ptr<LinkAdrReq> command = Create<LinkAdrReq>();
236  byteNumber += command->Deserialize(start);
237  m_macCommands.push_back(command);
238  break;
239  }
240  case (0x04): {
241  NS_LOG_DEBUG("Creating a DutyCycleReq command");
242  Ptr<DutyCycleReq> command = Create<DutyCycleReq>();
243  byteNumber += command->Deserialize(start);
244  m_macCommands.push_back(command);
245  break;
246  }
247  case (0x05): {
248  NS_LOG_DEBUG("Creating a RxParamSetupReq command");
249  Ptr<RxParamSetupReq> command = Create<RxParamSetupReq>();
250  byteNumber += command->Deserialize(start);
251  m_macCommands.push_back(command);
252  break;
253  }
254  case (0x06): {
255  NS_LOG_DEBUG("Creating a DevStatusReq command");
256  Ptr<DevStatusReq> command = Create<DevStatusReq>();
257  byteNumber += command->Deserialize(start);
258  m_macCommands.push_back(command);
259  break;
260  }
261  case (0x07): {
262  NS_LOG_DEBUG("Creating a NewChannelReq command");
263  Ptr<NewChannelReq> command = Create<NewChannelReq>();
264  byteNumber += command->Deserialize(start);
265  m_macCommands.push_back(command);
266  break;
267  }
268  case (0x08): {
269  NS_LOG_DEBUG("Creating a RxTimingSetupReq command");
270  Ptr<RxTimingSetupReq> command = Create<RxTimingSetupReq>();
271  byteNumber += command->Deserialize(start);
272  m_macCommands.push_back(command);
273  break;
274  }
275  case (0x09): {
276  NS_LOG_DEBUG("Creating a TxParamSetupReq command");
277  Ptr<TxParamSetupReq> command = Create<TxParamSetupReq>();
278  byteNumber += command->Deserialize(start);
279  m_macCommands.push_back(command);
280  break;
281  }
282  default: {
283  NS_LOG_ERROR("CID not recognized during deserialization");
284  }
285  }
286  }
287  }
288 
289  m_fPort = uint8_t(start.ReadU8());
290 
291  return 8 + m_fOptsLen; // the number of bytes consumed.
292 }
293 
294 void
295 LoraFrameHeader::Print(std::ostream& os) const
296 {
297  NS_LOG_FUNCTION_NOARGS();
298 
299  os << "Address=" << m_address.Print() << std::endl;
300  os << "ADR=" << m_adr << std::endl;
301  os << "ADRAckReq=" << m_adrAckReq << std::endl;
302  os << "ACK=" << m_ack << std::endl;
303  os << "FPending=" << m_fPending << std::endl;
304  os << "FOptsLen=" << unsigned(m_fOptsLen) << std::endl;
305  os << "FCnt=" << unsigned(m_fCnt) << std::endl;
306 
307  for (auto it = m_macCommands.begin(); it != m_macCommands.end(); it++)
308  {
309  (*it)->Print(os);
310  }
311 
312  os << "FPort=" << unsigned(m_fPort) << std::endl;
313 }
314 
315 void
317 {
318  NS_LOG_FUNCTION_NOARGS();
319 
320  m_isUplink = true;
321 }
322 
323 void
325 {
326  NS_LOG_FUNCTION_NOARGS();
327 
328  m_isUplink = false;
329 }
330 
331 void
333 {
334  m_fPort = fPort;
335 }
336 
337 uint8_t
339 {
340  return m_fPort;
341 }
342 
343 void
345 {
346  m_address = address;
347 }
348 
351 {
352  return m_address;
353 }
354 
355 void
357 {
358  NS_LOG_FUNCTION(this << adr);
359  m_adr = adr;
360 }
361 
362 bool
364 {
365  return m_adr;
366 }
367 
368 void
370 {
371  m_adrAckReq = adrAckReq;
372 }
373 
374 bool
376 {
377  return m_adrAckReq;
378 }
379 
380 void
382 {
383  NS_LOG_FUNCTION(this << ack);
384  m_ack = ack;
385 }
386 
387 bool
389 {
390  return m_ack;
391 }
392 
393 void
395 {
396  m_fPending = fPending;
397 }
398 
399 bool
401 {
402  return m_fPending;
403 }
404 
405 uint8_t
407 {
408  // Sum the serialized lenght of all commands in the list
409  uint8_t fOptsLen = 0;
410  std::list<Ptr<LorawanMacCommand>>::const_iterator it;
411  for (it = m_macCommands.begin(); it != m_macCommands.end(); it++)
412  {
413  fOptsLen = fOptsLen + (*it)->GetSerializedSize();
414  }
415  return fOptsLen;
416 }
417 
418 void
420 {
421  m_fCnt = fCnt;
422 }
423 
424 uint16_t
426 {
427  return m_fCnt;
428 }
429 
430 void
432 {
433  NS_LOG_FUNCTION_NOARGS();
434 
435  Ptr<LinkCheckReq> command = Create<LinkCheckReq>();
436  m_macCommands.push_back(command);
437 
438  NS_LOG_DEBUG("Command SerializedSize: " << unsigned(command->GetSerializedSize()));
439  m_fOptsLen += command->GetSerializedSize();
440 }
441 
442 void
443 LoraFrameHeader::AddLinkCheckAns(uint8_t margin, uint8_t gwCnt)
444 {
445  NS_LOG_FUNCTION(this << unsigned(margin) << unsigned(gwCnt));
446 
447  Ptr<LinkCheckAns> command = Create<LinkCheckAns>(margin, gwCnt);
448  m_macCommands.push_back(command);
449 
450  m_fOptsLen += command->GetSerializedSize();
451 }
452 
453 void
455  uint8_t txPower,
456  std::list<int> enabledChannels,
457  int repetitions)
458 {
459  NS_LOG_FUNCTION(this << unsigned(dataRate) << txPower << repetitions);
460 
461  uint16_t channelMask = 0;
462  for (auto it = enabledChannels.begin(); it != enabledChannels.end(); it++)
463  {
464  NS_ASSERT((*it) < 16 && (*it) > -1);
465 
466  channelMask |= 0b1 << (*it);
467  }
468 
469  // TODO Implement chMaskCntl field
470 
471  NS_LOG_DEBUG("Creating LinkAdrReq with: DR = " << unsigned(dataRate)
472  << " and txPower = " << unsigned(txPower));
473 
474  Ptr<LinkAdrReq> command = Create<LinkAdrReq>(dataRate, txPower, channelMask, 0, repetitions);
475  m_macCommands.push_back(command);
476 
477  m_fOptsLen += command->GetSerializedSize();
478 }
479 
480 void
481 LoraFrameHeader::AddLinkAdrAns(bool powerAck, bool dataRateAck, bool channelMaskAck)
482 {
483  NS_LOG_FUNCTION(this << powerAck << dataRateAck << channelMaskAck);
484 
485  Ptr<LinkAdrAns> command = Create<LinkAdrAns>(powerAck, dataRateAck, channelMaskAck);
486  m_macCommands.push_back(command);
487 
488  m_fOptsLen += command->GetSerializedSize();
489 }
490 
491 void
493 {
494  NS_LOG_FUNCTION(this << unsigned(dutyCycle));
495 
496  Ptr<DutyCycleReq> command = Create<DutyCycleReq>(dutyCycle);
497 
498  m_macCommands.push_back(command);
499 
500  m_fOptsLen += command->GetSerializedSize();
501 }
502 
503 void
505 {
506  NS_LOG_FUNCTION(this);
507 
508  Ptr<DutyCycleAns> command = Create<DutyCycleAns>();
509 
510  m_macCommands.push_back(command);
511 
512  m_fOptsLen += command->GetSerializedSize();
513 }
514 
515 void
516 LoraFrameHeader::AddRxParamSetupReq(uint8_t rx1DrOffset, uint8_t rx2DataRate, double frequency)
517 {
518  NS_LOG_FUNCTION(this << unsigned(rx1DrOffset) << unsigned(rx2DataRate) << frequency);
519 
520  // Evaluate whether to eliminate this assert in case new offsets can be defined.
521  NS_ASSERT(0 <= rx1DrOffset && rx1DrOffset <= 5);
522 
523  Ptr<RxParamSetupReq> command = Create<RxParamSetupReq>(rx1DrOffset, rx2DataRate, frequency);
524 
525  m_macCommands.push_back(command);
526 
527  m_fOptsLen += command->GetSerializedSize();
528 }
529 
530 void
532 {
533  NS_LOG_FUNCTION(this);
534 
535  Ptr<RxParamSetupAns> command = Create<RxParamSetupAns>();
536 
537  m_macCommands.push_back(command);
538 
539  m_fOptsLen += command->GetSerializedSize();
540 }
541 
542 void
544 {
545  NS_LOG_FUNCTION(this);
546 
547  Ptr<DevStatusReq> command = Create<DevStatusReq>();
548 
549  m_macCommands.push_back(command);
550 
551  m_fOptsLen += command->GetSerializedSize();
552 }
553 
554 void
556  double frequency,
557  uint8_t minDataRate,
558  uint8_t maxDataRate)
559 {
560  NS_LOG_FUNCTION(this);
561 
562  Ptr<NewChannelReq> command =
563  Create<NewChannelReq>(chIndex, frequency, minDataRate, maxDataRate);
564 
565  m_macCommands.push_back(command);
566 
567  m_fOptsLen += command->GetSerializedSize();
568 }
569 
570 std::list<Ptr<LorawanMacCommand>>
572 {
573  NS_LOG_FUNCTION_NOARGS();
574 
575  return m_macCommands;
576 }
577 
578 void
579 LoraFrameHeader::AddCommand(Ptr<LorawanMacCommand> macCommand)
580 {
581  NS_LOG_FUNCTION(this << macCommand);
582 
583  m_macCommands.push_back(macCommand);
584  m_fOptsLen += macCommand->GetSerializedSize();
585 }
586 
587 } // 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.