A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
lorawan-test-suite.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 headers of classes to test
10#include "ns3/constant-position-mobility-model.h"
11#include "ns3/log.h"
12#include "ns3/lora-helper.h"
13#include "ns3/mobility-helper.h"
14#include "ns3/one-shot-sender-helper.h"
15#include "ns3/simple-end-device-lora-phy.h"
16#include "ns3/simple-gateway-lora-phy.h"
17
18// An essential include is test.h
19#include "ns3/test.h"
20
21using namespace ns3;
22using namespace lorawan;
23
24NS_LOG_COMPONENT_DEFINE("LorawanTestSuite");
25
26/**
27 * @ingroup lorawan
28 *
29 * It tests interference computations in a number of possible scenarios using the
30 * LoraInterferenceHelper class
31 */
33{
34 public:
35 InterferenceTest(); //!< Default constructor
36 ~InterferenceTest() override; //!< Destructor
37
38 private:
39 void DoRun() override;
40};
41
42// Add some help text to this case to describe what it is intended to test
44 : TestCase("Verify that LoraInterferenceHelper works as expected")
45{
46}
47
48// Reminder that the test case should clean up after itself
52
53// This method is the pure virtual method from class TestCase that every
54// TestCase must implement
55void
57{
58 NS_LOG_DEBUG("InterferenceTest");
59
60 LoraInterferenceHelper interferenceHelper;
61
62 uint32_t frequencyHz = 868100000;
63 uint32_t differentFrequencyHz = 868300000;
64
67
68 // Test overlap duration
69 event = interferenceHelper.Add(Seconds(2), 14, 7, nullptr, frequencyHz);
70 event1 = interferenceHelper.Add(Seconds(1), 14, 12, nullptr, frequencyHz);
71 NS_TEST_EXPECT_MSG_EQ(interferenceHelper.GetOverlapTime(event, event1),
72 Seconds(1),
73 "Overlap computation didn't give the expected result");
74 interferenceHelper.ClearAllEvents();
75
76 event = interferenceHelper.Add(Seconds(2), 14, 7, nullptr, frequencyHz);
77 event1 = interferenceHelper.Add(Seconds(1.5), 14, 12, nullptr, frequencyHz);
78 NS_TEST_EXPECT_MSG_EQ(interferenceHelper.GetOverlapTime(event, event1),
79 Seconds(1.5),
80 "Overlap computation didn't give the expected result");
81 interferenceHelper.ClearAllEvents();
82
83 event = interferenceHelper.Add(Seconds(2), 14, 7, nullptr, frequencyHz);
84 event1 = interferenceHelper.Add(Seconds(3), 14, 12, nullptr, frequencyHz);
85 NS_TEST_EXPECT_MSG_EQ(interferenceHelper.GetOverlapTime(event, event1),
86 Seconds(2),
87 "Overlap computation didn't give the expected result");
88 interferenceHelper.ClearAllEvents();
89
90 event = interferenceHelper.Add(Seconds(2), 14, 7, nullptr, frequencyHz);
91 event1 = interferenceHelper.Add(Seconds(2), 14, 12, nullptr, frequencyHz);
92 // Because of some strange behavior, this test would get stuck if we used the same syntax of the
93 // previous ones. This works instead.
94 bool retval = interferenceHelper.GetOverlapTime(event, event1) == Seconds(2);
95 NS_TEST_EXPECT_MSG_EQ(retval, true, "Overlap computation didn't give the expected result");
96 interferenceHelper.ClearAllEvents();
97
98 // Perfect overlap, packet survives
99 event = interferenceHelper.Add(Seconds(2), 14, 7, nullptr, frequencyHz);
100 interferenceHelper.Add(Seconds(2), 14, 12, nullptr, frequencyHz);
101 NS_TEST_EXPECT_MSG_EQ(interferenceHelper.IsDestroyedByInterference(event),
102 0,
103 "Packet did not survive interference as expected");
104 interferenceHelper.ClearAllEvents();
105
106 // Perfect overlap, packet survives
107 event = interferenceHelper.Add(Seconds(2), 14, 7, nullptr, frequencyHz);
108 interferenceHelper.Add(Seconds(2), 14 - 7, 7, nullptr, frequencyHz);
109 NS_TEST_EXPECT_MSG_EQ(interferenceHelper.IsDestroyedByInterference(event),
110 0,
111 "Packet did not survive interference as expected");
112 interferenceHelper.ClearAllEvents();
113
114 // Perfect overlap, packet destroyed
115 event = interferenceHelper.Add(Seconds(2), 14, 7, nullptr, frequencyHz);
116 interferenceHelper.Add(Seconds(2), 14 - 6, 7, nullptr, frequencyHz);
117 NS_TEST_EXPECT_MSG_EQ(interferenceHelper.IsDestroyedByInterference(event),
118 7,
119 "Packet was not destroyed by interference as expected");
120 interferenceHelper.ClearAllEvents();
121
122 // Partial overlap, packet survives
123 event = interferenceHelper.Add(Seconds(2), 14, 7, nullptr, frequencyHz);
124 interferenceHelper.Add(Seconds(1), 14 - 6, 7, nullptr, frequencyHz);
125 NS_TEST_EXPECT_MSG_EQ(interferenceHelper.IsDestroyedByInterference(event),
126 0,
127 "Packet did not survive interference as expected");
128 interferenceHelper.ClearAllEvents();
129
130 // Different frequencys
131 // Packet would be destroyed if they were on the same frequency, but survives
132 // since they are on different frequencies
133 event = interferenceHelper.Add(Seconds(2), 14, 7, nullptr, frequencyHz);
134 interferenceHelper.Add(Seconds(2), 14, 7, nullptr, differentFrequencyHz);
135 NS_TEST_EXPECT_MSG_EQ(interferenceHelper.IsDestroyedByInterference(event),
136 0,
137 "Packet did not survive interference as expected");
138 interferenceHelper.ClearAllEvents();
139
140 // Different SFs
141 // Packet would be destroyed if they both were SF7, but survives thanks to spreading factor
142 // semi-orthogonality
143 event = interferenceHelper.Add(Seconds(2), 14, 7, nullptr, frequencyHz);
144 interferenceHelper.Add(Seconds(2), 14 + 16, 8, nullptr, frequencyHz);
145 NS_TEST_EXPECT_MSG_EQ(interferenceHelper.IsDestroyedByInterference(event),
146 0,
147 "Packet did not survive interference as expected");
148 interferenceHelper.ClearAllEvents();
149
150 // Spreading factor imperfect orthogonality
151 // Different SFs are orthogonal only up to a point
152 event = interferenceHelper.Add(Seconds(2), 14, 7, nullptr, frequencyHz);
153 interferenceHelper.Add(Seconds(2), 14 + 17, 8, nullptr, frequencyHz);
154 NS_TEST_EXPECT_MSG_EQ(interferenceHelper.IsDestroyedByInterference(event),
155 8,
156 "Packet was not destroyed by interference as expected");
157 interferenceHelper.ClearAllEvents();
158
159 // If a more 'distant' spreading factor is used, isolation gets better
160 event = interferenceHelper.Add(Seconds(2), 14, 7, nullptr, frequencyHz);
161 interferenceHelper.Add(Seconds(2), 14 + 17, 10, nullptr, frequencyHz);
162 NS_TEST_EXPECT_MSG_EQ(interferenceHelper.IsDestroyedByInterference(event),
163 0,
164 "Packet was destroyed by interference while it should have survived");
165 interferenceHelper.ClearAllEvents();
166
167 // Cumulative interference
168 // Same spreading factor interference is cumulative
169 event = interferenceHelper.Add(Seconds(2), 14, 7, nullptr, frequencyHz);
170 interferenceHelper.Add(Seconds(2), 14 + 16, 8, nullptr, frequencyHz);
171 interferenceHelper.Add(Seconds(2), 14 + 16, 8, nullptr, frequencyHz);
172 interferenceHelper.Add(Seconds(2), 14 + 16, 8, nullptr, frequencyHz);
173 NS_TEST_EXPECT_MSG_EQ(interferenceHelper.IsDestroyedByInterference(event),
174 8,
175 "Packet was not destroyed by interference as expected");
176 interferenceHelper.ClearAllEvents();
177
178 // Cumulative interference
179 // Interference is not cumulative between different SFs
180 event = interferenceHelper.Add(Seconds(2), 14, 7, nullptr, frequencyHz);
181 interferenceHelper.Add(Seconds(2), 14 + 16, 8, nullptr, frequencyHz);
182 interferenceHelper.Add(Seconds(2), 14 + 16, 9, nullptr, frequencyHz);
183 interferenceHelper.Add(Seconds(2), 14 + 16, 10, nullptr, frequencyHz);
184 NS_TEST_EXPECT_MSG_EQ(interferenceHelper.IsDestroyedByInterference(event),
185 0,
186 "Packet did not survive interference as expected");
187 interferenceHelper.ClearAllEvents();
188}
189
190/**
191 * @ingroup lorawan
192 *
193 * It tests LoraDeviceAddress comparison operators overrides and generation of new addresses with
194 * LoraDeviceAddressGenerator
195 */
196class AddressTest : public TestCase
197{
198 public:
199 AddressTest(); //!< Default constructor
200 ~AddressTest() override; //!< Destructor
201
202 private:
203 void DoRun() override;
204};
205
206// Add some help text to this case to describe what it is intended to test
208 : TestCase("Verify that LoraDeviceAddress works as expected")
209{
210}
211
212// Reminder that the test case should clean up after itself
216
217// This method is the pure virtual method from class TestCase that every
218// TestCase must implement
219void
221{
222 NS_LOG_DEBUG("AddressTest");
223
224 //////////////////////////////////////
225 // Test the LoraDeviceAddress class //
226 //////////////////////////////////////
227
228 // Address equality
229 LoraDeviceAddress firstAddress(0xFFFFFFFF);
230 LoraDeviceAddress secondAddress(0xFFFFFFFF);
231 NS_TEST_EXPECT_MSG_EQ((firstAddress == secondAddress), true, "Addresses don't match");
232
233 // Address ordering
234 LoraDeviceAddress bigAddress(0xFFFFFF00);
235 LoraDeviceAddress smallAddress(0xFFF00000);
236 NS_TEST_EXPECT_MSG_EQ((bigAddress > smallAddress),
237 true,
238 "> function for addresses doesn't work correctly");
239
240 // Setting and getting
241 LoraDeviceAddress referenceAddress(0xFFFFFFFF);
242 LoraDeviceAddress address(0x00000000);
243 NS_TEST_EXPECT_MSG_EQ((address != referenceAddress), true, "Different addresses match!");
244 address.SetNwkAddr(0xFFFFFFF);
245 address.SetNwkID(0b1111111);
246 NS_TEST_EXPECT_MSG_EQ((address == referenceAddress),
247 true,
248 "Addresses set to be equal don't match");
249
250 // Serialization and deserialization
251 uint8_t buffer[4];
252 LoraDeviceAddress toSerialize(0x0F0F0F0F);
253 toSerialize.Serialize(buffer);
255 NS_TEST_EXPECT_MSG_EQ((toSerialize == deserialized),
256 true,
257 "Serialization + Deserialization doesn't yield an equal address");
258
259 ///////////////////////////////////
260 // Test the address generator class
261 ///////////////////////////////////
262
263 LoraDeviceAddressGenerator addressGenerator;
264 for (int i = 0; i < 200; i++)
265 {
266 addressGenerator.NextAddress();
267 }
268 // After 200 iterations, the address should be 0xC9
269 NS_TEST_EXPECT_MSG_EQ((addressGenerator.GetNextAddress() == LoraDeviceAddress(0xC9)),
270 true,
271 "LoraDeviceAddressGenerator doesn't increment as expected");
272}
273
274/**
275 * @ingroup lorawan
276 *
277 * It tests serialization/deserialization of LoRaWAN headers (the LorawanMacHeader and
278 * LoraFrameHeader classes) on packets
279 */
280class HeaderTest : public TestCase
281{
282 public:
283 HeaderTest(); //!< Default constructor
284 ~HeaderTest() override; //!< Destructor
285
286 private:
287 void DoRun() override;
288};
289
290// Add some help text to this case to describe what it is intended to test
292 : TestCase("Verify that LorawanMacHeader and LoraFrameHeader work as expected")
293{
294}
295
296// Reminder that the test case should clean up after itself
300
301// This method is the pure virtual method from class TestCase that every
302// TestCase must implement
303void
305{
306 NS_LOG_DEBUG("HeaderTest");
307
308 //////////////////////////////////
309 // Test the LorawanMacHeader class //
310 //////////////////////////////////
311 LorawanMacHeader macHdr;
313 macHdr.SetMajor(1);
314
315 Buffer macBuf;
316 macBuf.AddAtStart(100);
317 Buffer::Iterator macSerialized = macBuf.Begin();
318 macHdr.Serialize(macSerialized);
319
320 macHdr.Deserialize(macSerialized);
321
323 true,
324 "MType changes in the serialization/deserialization process");
325 NS_TEST_EXPECT_MSG_EQ((macHdr.GetMajor() == 1),
326 true,
327 "MType changes in the serialization/deserialization process");
328
329 ////////////////////////////////////
330 // Test the LoraFrameHeader class //
331 ////////////////////////////////////
332 LoraFrameHeader frameHdr;
333 frameHdr.SetAsDownlink();
334 frameHdr.SetAck(true);
335 frameHdr.SetAdr(false);
336 frameHdr.SetFCnt(1);
337 frameHdr.SetAddress(LoraDeviceAddress(56, 1864));
338 frameHdr.AddLinkCheckAns(10, 1);
339
340 // Serialization
341 Buffer buf;
342 buf.AddAtStart(100);
343 Buffer::Iterator serialized = buf.Begin();
344 frameHdr.Serialize(serialized);
345
346 // Deserialization
347 frameHdr.Deserialize(serialized);
348
349 Ptr<LinkCheckAns> command = DynamicCast<LinkCheckAns>(frameHdr.GetCommands().at(0));
350 uint8_t margin = command->GetMargin();
351 uint8_t gwCnt = command->GetGwCnt();
352
353 NS_TEST_EXPECT_MSG_EQ(frameHdr.GetAck(),
354 true,
355 "ACK bit changes in the serialization/deserialization process");
356 NS_TEST_EXPECT_MSG_EQ(frameHdr.GetAdr(),
357 false,
358 "ADR bit changes in the serialization/deserialization process");
360 1,
361 "FCnt changes in the serialization/deserialization process");
362 NS_TEST_EXPECT_MSG_EQ((frameHdr.GetAddress() == LoraDeviceAddress(56, 1864)),
363 true,
364 "Address changes in the serialization/deserialization process");
366 10,
367 "Margin changes in the serialization/deserialization process");
368 NS_TEST_EXPECT_MSG_EQ(gwCnt, 1, "GwCnt changes in the serialization/deserialization process");
369
370 /////////////////////////////////////////////////
371 // Test a combination of the two above classes //
372 /////////////////////////////////////////////////
373 Ptr<Packet> pkt = Create<Packet>(10);
374 pkt->AddHeader(frameHdr);
375 pkt->AddHeader(macHdr);
376
377 // Length = Payload + FrameHeader + MacHeader
378 // = 10 + (8+3) + 1 = 22
379 NS_TEST_EXPECT_MSG_EQ((pkt->GetSize()), 22, "Wrong size of packet + headers");
380
381 LorawanMacHeader macHdr1;
382
383 pkt->RemoveHeader(macHdr1);
384
385 NS_TEST_EXPECT_MSG_EQ((pkt->GetSize()), 21, "Wrong size of packet + headers - macHeader");
386
387 LoraFrameHeader frameHdr1;
388 frameHdr1.SetAsDownlink();
389
390 pkt->RemoveHeader(frameHdr1);
391 Ptr<LinkCheckAns> linkCheckAns = DynamicCast<LinkCheckAns>(frameHdr1.GetCommands().at(0));
392
393 NS_TEST_EXPECT_MSG_EQ((pkt->GetSize()),
394 10,
395 "Wrong size of packet + headers - macHeader - frameHeader");
396
397 // Verify contents of removed MAC header
399 macHdr.GetMType(),
400 "Removed header contents don't match");
402 macHdr.GetMajor(),
403 "Removed header contents don't match");
404
405 // Verify contents of removed frame header
406 NS_TEST_EXPECT_MSG_EQ(frameHdr1.GetAck(),
407 frameHdr.GetAck(),
408 "Removed header contents don't match");
409 NS_TEST_EXPECT_MSG_EQ(frameHdr1.GetAdr(),
410 frameHdr.GetAdr(),
411 "Removed header contents don't match");
412 NS_TEST_EXPECT_MSG_EQ(frameHdr1.GetFCnt(),
413 frameHdr.GetFCnt(),
414 "Removed header contents don't match");
415 NS_TEST_EXPECT_MSG_EQ((frameHdr1.GetAddress() == frameHdr.GetAddress()),
416 true,
417 "Removed header contents don't match");
418 NS_TEST_EXPECT_MSG_EQ(linkCheckAns->GetMargin(),
419 10,
420 "Removed header's MAC command contents don't match");
421 NS_TEST_EXPECT_MSG_EQ(linkCheckAns->GetGwCnt(),
422 1,
423 "Removed header's MAC command contents don't match");
424}
425
426/**
427 * @ingroup lorawan
428 *
429 * It tests a number of cases related to SimpleGatewayLoraPhy's parallel reception paths
430 *
431 * @todo The test is commented out. To be fixed.
432 */
434{
435 public:
436 ReceivePathTest(); //!< Default constructor
437 ~ReceivePathTest() override; //!< Destructor
438
439 private:
440 void DoRun() override;
441 /**
442 * Reset counters and gateway PHY for new sub test case.
443 */
444 void Reset();
445 /**
446 * Callback for tracing OccupiedReceptionPaths.
447 *
448 * @param oldValue The old value.
449 * @param newValue The new value.
450 */
451 void OccupiedReceptionPaths(int oldValue, int newValue);
452 /**
453 * Callback for tracing LostPacketBecauseNoMoreReceivers.
454 *
455 * @param packet The packet lost.
456 * @param node The receiver node id if any, 0 otherwise.
457 */
459 /**
460 * Callback for tracing LostPacketBecauseInterference.
461 *
462 * @param packet The packet lost.
463 * @param node The receiver node id if any, 0 otherwise.
464 */
465 void Interference(Ptr<const Packet> packet, uint32_t node);
466 /**
467 * Callback for tracing ReceivedPacket.
468 *
469 * @param packet The packet received.
470 * @param node The receiver node id if any, 0 otherwise.
471 */
472 void ReceivedPacket(Ptr<const Packet> packet, uint32_t node);
473
474 Ptr<SimpleGatewayLoraPhy> gatewayPhy; //!< PHY layer of a gateway to be tested
475
476 int m_noMoreDemodulatorsCalls = 0; //!< Counter for LostPacketBecauseNoMoreReceivers calls
477 int m_interferenceCalls = 0; //!< Counter for LostPacketBecauseInterference calls
478 int m_receivedPacketCalls = 0; //!< Counter for ReceivedPacket calls
479 int m_maxOccupiedReceptionPaths = 0; //!< Max number of concurrent OccupiedReceptionPaths
480};
481
482// Add some help text to this case to describe what it is intended to test
484 : TestCase("Verify that ReceivePaths work as expected")
485{
486}
487
488// Reminder that the test case should clean up after itself
492
493void
495{
496 // FIXME
497 // m_noMoreDemodulatorsCalls = 0;
498 // m_interferenceCalls = 0;
499 // m_receivedPacketCalls = 0;
500 // m_maxOccupiedReceptionPaths = 0;
501
502 // gatewayPhy = CreateObject<SimpleGatewayLoraPhy> ();
503 // gatewayPhy->TraceConnectWithoutContext (
504 // "LostPacketBecauseNoMoreReceivers",
505 // MakeCallback (&ReceivePathTest::NoMoreDemodulators, this));
506 // gatewayPhy->TraceConnectWithoutContext ("LostPacketBecauseInterference",
507 // MakeCallback (&ReceivePathTest::Interference, this));
508 // gatewayPhy->TraceConnectWithoutContext ("ReceivedPacket",
509 // MakeCallback (&ReceivePathTest::ReceivedPacket,
510 // this));
511 // gatewayPhy->TraceConnectWithoutContext (
512 // "OccupiedReceptionPaths", MakeCallback (&ReceivePathTest::OccupiedReceptionPaths, this));
513
514 // // Add receive paths
515 // gatewayPhy->AddReceptionPath ();
516 // gatewayPhy->AddReceptionPath ();
517 // gatewayPhy->AddReceptionPath ();
518 // gatewayPhy->AddReceptionPath ();
519 // gatewayPhy->AddReceptionPath ();
520 // gatewayPhy->AddReceptionPath ();
521}
522
523void
525{
526 NS_LOG_FUNCTION(oldValue << newValue);
527
528 if (m_maxOccupiedReceptionPaths < newValue)
529 {
531 }
532}
533
534void
541
542void
549
550void
557
558// This method is the pure virtual method from class TestCase that every
559// TestCase must implement
560void
562{
563 NS_LOG_DEBUG("ReceivePathTest");
564
565 Ptr<Packet> packet = Create<Packet>();
566
567 Reset();
568
569 // FIXME
570 // //////////////////////////////////////////////////////////////////////////////////
571 // // If no ReceptionPath is configured to listen on a frequency, no packet is received
572 // //////////////////////////////////////////////////////////////////////////////////
573
574 // Simulator::Schedule (Seconds (1), &SimpleGatewayLoraPhy::StartReceive, gatewayPhy, packet,
575 // 14, 7,
576 // Seconds (1), frequency4);
577
578 // Simulator::Stop (Hours (2));
579 // Simulator::Run ();
580 // Simulator::Destroy ();
581
582 // NS_TEST_EXPECT_MSG_EQ (m_noMoreDemodulatorsCalls, 1, "Unexpected value");
583
584 // Reset ();
585
586 // //////////////////////////////////////////////////////////////////////////////
587 // // A ReceptionPath can receive a packet of any spreading factor without any preconfiguration
588 // //////////////////////////////////////////////////////////////////////////////
589
590 // Simulator::Schedule (Seconds (1), &SimpleGatewayLoraPhy::StartReceive, gatewayPhy, packet,
591 // 14, 7,
592 // Seconds (1), frequency1);
593 // Simulator::Schedule (Seconds (3), &SimpleGatewayLoraPhy::StartReceive, gatewayPhy, packet,
594 // 14, 8,
595 // Seconds (1), frequency1);
596 // Simulator::Schedule (Seconds (5), &SimpleGatewayLoraPhy::StartReceive, gatewayPhy, packet,
597 // 14, 9,
598 // Seconds (1), frequency1);
599 // Simulator::Schedule (Seconds (7), &SimpleGatewayLoraPhy::StartReceive, gatewayPhy, packet,
600 // 14, 10,
601 // Seconds (1), frequency1);
602 // Simulator::Schedule (Seconds (9), &SimpleGatewayLoraPhy::StartReceive, gatewayPhy, packet,
603 // 14, 11,
604 // Seconds (1), frequency1);
605 // Simulator::Schedule (Seconds (11), &SimpleGatewayLoraPhy::StartReceive, gatewayPhy, packet,
606 // 14,
607 // 12, Seconds (1), frequency1);
608
609 // Simulator::Stop (Hours (2));
610 // Simulator::Run ();
611 // Simulator::Destroy ();
612
613 // NS_TEST_EXPECT_MSG_EQ (m_noMoreDemodulatorsCalls, 0, "Unexpected value");
614 // NS_TEST_EXPECT_MSG_EQ (m_receivedPacketCalls, 6, "Unexpected value");
615
616 // Reset ();
617
618 // ///////////////////////////////////////////////////////////////////////////
619 // // Schedule two reception events at the first frequency, where there are two
620 // // reception paths listening. Each packet should be received correctly.
621 // ///////////////////////////////////////////////////////////////////////////
622 // Simulator::Schedule (Seconds (2), &SimpleGatewayLoraPhy::StartReceive, gatewayPhy, packet,
623 // 14, 7,
624 // Seconds (4), frequency1);
625 // Simulator::Schedule (Seconds (3), &SimpleGatewayLoraPhy::StartReceive, gatewayPhy, packet,
626 // 14, 9,
627 // Seconds (4), frequency1);
628
629 // Simulator::Stop (Hours (2));
630 // Simulator::Run ();
631 // Simulator::Destroy ();
632
633 // NS_TEST_EXPECT_MSG_EQ (m_noMoreDemodulatorsCalls, 0, "Unexpected value");
634 // NS_TEST_EXPECT_MSG_EQ (m_receivedPacketCalls, 2, "Unexpected value");
635
636 // Reset ();
637
638 // ///////////////////////////////////////////////////////////////////////////
639 // // Interference between packets on the same frequency and different ReceptionPaths
640 // ///////////////////////////////////////////////////////////////////////////
641 // Simulator::Schedule (Seconds (2), &SimpleGatewayLoraPhy::StartReceive, gatewayPhy, packet,
642 // 14, 7,
643 // Seconds (4), frequency1);
644 // Simulator::Schedule (Seconds (3), &SimpleGatewayLoraPhy::StartReceive, gatewayPhy, packet,
645 // 14, 7,
646 // Seconds (4), frequency1);
647
648 // Simulator::Stop (Hours (2));
649 // Simulator::Run ();
650 // Simulator::Destroy ();
651
652 // NS_TEST_EXPECT_MSG_EQ (m_noMoreDemodulatorsCalls, 0, "Unexpected value");
653 // NS_TEST_EXPECT_MSG_EQ (m_interferenceCalls, 2, "Unexpected value");
654
655 // Reset ();
656
657 // ///////////////////////////////////////////////////////////////////////////
658 // // Three receptions where only two receivePaths are available
659 // ///////////////////////////////////////////////////////////////////////////
660 // Simulator::Schedule (Seconds (2), &SimpleGatewayLoraPhy::StartReceive, gatewayPhy, packet,
661 // 14, 7,
662 // Seconds (4), frequency1);
663 // Simulator::Schedule (Seconds (2), &SimpleGatewayLoraPhy::StartReceive, gatewayPhy, packet,
664 // 14, 7,
665 // Seconds (4), frequency1);
666 // Simulator::Schedule (Seconds (3), &SimpleGatewayLoraPhy::StartReceive, gatewayPhy, packet,
667 // 14, 7,
668 // Seconds (4), frequency1);
669
670 // Simulator::Stop (Hours (2));
671 // Simulator::Run ();
672 // Simulator::Destroy ();
673
674 // NS_TEST_EXPECT_MSG_EQ (m_noMoreDemodulatorsCalls, 1, "Unexpected value");
675
676 // Reset ();
677
678 // ///////////////////////////////////////////////////////////////////////////
679 // // Packets that are on different frequencys do not interfere
680 // ///////////////////////////////////////////////////////////////////////////
681 // Simulator::Schedule (Seconds (2), &SimpleGatewayLoraPhy::StartReceive, gatewayPhy, packet,
682 // 14, 7,
683 // Seconds (4), frequency1);
684 // Simulator::Schedule (Seconds (2), &SimpleGatewayLoraPhy::StartReceive, gatewayPhy, packet,
685 // 14, 7,
686 // Seconds (4), frequency2);
687
688 // Simulator::Stop (Hours (2));
689 // Simulator::Run ();
690 // Simulator::Destroy ();
691
692 // NS_TEST_EXPECT_MSG_EQ (m_interferenceCalls, 0, "Unexpected value");
693
694 // Reset ();
695
696 // ///////////////////////////////////////////////////////////////////////////
697 // // Full capacity
698 // ///////////////////////////////////////////////////////////////////////////
699 // Simulator::Schedule (Seconds (2), &SimpleGatewayLoraPhy::StartReceive, gatewayPhy, packet,
700 // 14, 7,
701 // Seconds (4), frequency1);
702 // Simulator::Schedule (Seconds (2), &SimpleGatewayLoraPhy::StartReceive, gatewayPhy, packet,
703 // 14, 8,
704 // Seconds (4), frequency1);
705 // Simulator::Schedule (Seconds (2), &SimpleGatewayLoraPhy::StartReceive, gatewayPhy, packet,
706 // 14, 9,
707 // Seconds (4), frequency2);
708 // Simulator::Schedule (Seconds (2), &SimpleGatewayLoraPhy::StartReceive, gatewayPhy, packet,
709 // 14, 10,
710 // Seconds (4), frequency2);
711 // Simulator::Schedule (Seconds (2), &SimpleGatewayLoraPhy::StartReceive, gatewayPhy, packet,
712 // 14, 11,
713 // Seconds (4), frequency3);
714 // Simulator::Schedule (Seconds (2), &SimpleGatewayLoraPhy::StartReceive, gatewayPhy, packet,
715 // 14, 12,
716 // Seconds (4), frequency3);
717
718 // Simulator::Stop (Hours (2));
719 // Simulator::Run ();
720 // Simulator::Destroy ();
721
722 // NS_TEST_EXPECT_MSG_EQ (m_noMoreDemodulatorsCalls, 0, "Unexpected value");
723 // NS_TEST_EXPECT_MSG_EQ (m_interferenceCalls, 0, "Unexpected value");
724 // NS_TEST_EXPECT_MSG_EQ (m_receivedPacketCalls, 6, "Unexpected value");
725
726 // Reset ();
727
728 // ///////////////////////////////////////////////////////////////////////////
729 // // Full capacity + 1
730 // ///////////////////////////////////////////////////////////////////////////
731 // Simulator::Schedule (Seconds (2), &SimpleGatewayLoraPhy::StartReceive, gatewayPhy, packet,
732 // 14, 7,
733 // Seconds (4), frequency1);
734 // Simulator::Schedule (Seconds (2), &SimpleGatewayLoraPhy::StartReceive, gatewayPhy, packet,
735 // 14, 8,
736 // Seconds (4), frequency1);
737 // Simulator::Schedule (Seconds (2), &SimpleGatewayLoraPhy::StartReceive, gatewayPhy, packet,
738 // 14, 9,
739 // Seconds (4), frequency2);
740 // Simulator::Schedule (Seconds (2), &SimpleGatewayLoraPhy::StartReceive, gatewayPhy, packet,
741 // 14, 10,
742 // Seconds (4), frequency2);
743 // Simulator::Schedule (Seconds (2), &SimpleGatewayLoraPhy::StartReceive, gatewayPhy, packet,
744 // 14, 11,
745 // Seconds (4), frequency3);
746 // Simulator::Schedule (Seconds (2), &SimpleGatewayLoraPhy::StartReceive, gatewayPhy, packet,
747 // 14, 12,
748 // Seconds (4), frequency3);
749 // Simulator::Schedule (Seconds (2), &SimpleGatewayLoraPhy::StartReceive, gatewayPhy, packet,
750 // 14, 10,
751 // Seconds (4), frequency3);
752
753 // Simulator::Stop (Hours (2));
754 // Simulator::Run ();
755 // Simulator::Destroy ();
756
757 // NS_TEST_EXPECT_MSG_EQ (m_noMoreDemodulatorsCalls, 1, "Unexpected value");
758 // NS_TEST_EXPECT_MSG_EQ (m_interferenceCalls, 0, "Unexpected value");
759 // NS_TEST_EXPECT_MSG_EQ (m_receivedPacketCalls, 6, "Unexpected value");
760
761 // Reset ();
762
763 // ///////////////////////////////////////////////////////////////////////////
764 // // Receive Paths are correctly freed
765 // ///////////////////////////////////////////////////////////////////////////
766 // Simulator::Schedule (Seconds (2), &SimpleGatewayLoraPhy::StartReceive, gatewayPhy, packet,
767 // 14, 7,
768 // Seconds (4), frequency1);
769 // Simulator::Schedule (Seconds (2), &SimpleGatewayLoraPhy::StartReceive, gatewayPhy, packet,
770 // 14, 8,
771 // Seconds (4), frequency1);
772 // Simulator::Schedule (Seconds (2), &SimpleGatewayLoraPhy::StartReceive, gatewayPhy, packet,
773 // 14, 9,
774 // Seconds (4), frequency2);
775 // Simulator::Schedule (Seconds (2), &SimpleGatewayLoraPhy::StartReceive, gatewayPhy, packet,
776 // 14, 10,
777 // Seconds (4), frequency2);
778 // Simulator::Schedule (Seconds (2), &SimpleGatewayLoraPhy::StartReceive, gatewayPhy, packet,
779 // 14, 11,
780 // Seconds (4), frequency3);
781 // Simulator::Schedule (Seconds (2), &SimpleGatewayLoraPhy::StartReceive, gatewayPhy, packet,
782 // 14, 12,
783 // Seconds (4), frequency3);
784
785 // Simulator::Schedule (Seconds (8), &SimpleGatewayLoraPhy::StartReceive, gatewayPhy, packet,
786 // 14, 7,
787 // Seconds (4), frequency1);
788 // Simulator::Schedule (Seconds (8), &SimpleGatewayLoraPhy::StartReceive, gatewayPhy, packet,
789 // 14, 8,
790 // Seconds (4), frequency1);
791 // Simulator::Schedule (Seconds (8), &SimpleGatewayLoraPhy::StartReceive, gatewayPhy, packet,
792 // 14, 9,
793 // Seconds (4), frequency2);
794 // Simulator::Schedule (Seconds (8), &SimpleGatewayLoraPhy::StartReceive, gatewayPhy, packet,
795 // 14, 10,
796 // Seconds (4), frequency2);
797 // Simulator::Schedule (Seconds (8), &SimpleGatewayLoraPhy::StartReceive, gatewayPhy, packet,
798 // 14, 11,
799 // Seconds (4), frequency3);
800 // Simulator::Schedule (Seconds (8), &SimpleGatewayLoraPhy::StartReceive, gatewayPhy, packet,
801 // 14, 12,
802 // Seconds (4), frequency3);
803
804 // Simulator::Stop (Hours (2));
805 // Simulator::Run ();
806 // Simulator::Destroy ();
807
808 // NS_TEST_EXPECT_MSG_EQ (m_noMoreDemodulatorsCalls, 0, "Unexpected value");
809 // NS_TEST_EXPECT_MSG_EQ (m_interferenceCalls, 0, "Unexpected value");
810 // NS_TEST_EXPECT_MSG_EQ (m_receivedPacketCalls, 12, "Unexpected value");
811
812 // Reset ();
813
814 // ///////////////////////////////////////////////////////////////////////////
815 // // Receive Paths stay occupied exactly for the necessary time
816 // // Occupy both ReceptionPaths centered at frequency1
817 // ///////////////////////////////////////////////////////////////////////////
818 // Simulator::Schedule (Seconds (2), &SimpleGatewayLoraPhy::StartReceive, gatewayPhy, packet,
819 // 14, 7,
820 // Seconds (4), frequency1);
821 // Simulator::Schedule (Seconds (2), &SimpleGatewayLoraPhy::StartReceive, gatewayPhy, packet,
822 // 14, 8,
823 // Seconds (4), frequency1);
824
825 // // This packet will find no free ReceptionPaths
826 // Simulator::Schedule (Seconds (2 + 4) - NanoSeconds (1), &SimpleGatewayLoraPhy::StartReceive,
827 // gatewayPhy, packet, 14, 9, Seconds (4), frequency1);
828
829 // // This packet will find a free ReceptionPath
830 // Simulator::Schedule (Seconds (2 + 4) + NanoSeconds (1), &SimpleGatewayLoraPhy::StartReceive,
831 // gatewayPhy, packet, 14, 10, Seconds (4), frequency1);
832
833 // Simulator::Stop (Hours (2));
834 // Simulator::Run ();
835 // Simulator::Destroy ();
836
837 // NS_TEST_EXPECT_MSG_EQ (m_noMoreDemodulatorsCalls, 1, "Unexpected value");
838 // NS_TEST_EXPECT_MSG_EQ (m_interferenceCalls, 0, "Unexpected value");
839 // NS_TEST_EXPECT_MSG_EQ (m_receivedPacketCalls, 3, "Unexpected value");
840
841 // Reset ();
842
843 // ///////////////////////////////////////////////////////////////////////////
844 // // Only one ReceivePath locks on the incoming packet
845 // ///////////////////////////////////////////////////////////////////////////
846 // Simulator::Schedule (Seconds (2), &SimpleGatewayLoraPhy::StartReceive, gatewayPhy, packet,
847 // 14, 7,
848 // Seconds (4), frequency1);
849
850 // Simulator::Stop (Hours (2));
851 // Simulator::Run ();
852 // Simulator::Destroy ();
853
854 // NS_TEST_EXPECT_MSG_EQ (m_noMoreDemodulatorsCalls, 0, "Unexpected value");
855 // NS_TEST_EXPECT_MSG_EQ (m_interferenceCalls, 0, "Unexpected value");
856 // NS_TEST_EXPECT_MSG_EQ (m_receivedPacketCalls, 1, "Unexpected value");
857 // NS_TEST_EXPECT_MSG_EQ (m_maxOccupiedReceptionPaths, 1, "Unexpected value");
858}
859
860/**
861 * @ingroup lorawan
862 *
863 * It tests functionality of the LogicalLoraChannel, SubBand and LogicalLoraChannelHelper classes
864 */
866{
867 public:
868 LogicalLoraChannelTest(); //!< Default constructor
869 ~LogicalLoraChannelTest() override; //!< Destructor
870
871 private:
872 void DoRun() override;
873};
874
875// Add some help text to this case to describe what it is intended to test
877 : TestCase("Verify that LogicalLoraChannel and LogicalLoraChannelHelper work as expected")
878{
879}
880
881// Reminder that the test case should clean up after itself
885
886// This method is the pure virtual method from class TestCase that every
887// TestCase must implement
888void
890{
891 NS_LOG_DEBUG("LogicalLoraChannelTest");
892
893 /////////////////////////////
894 // Test LogicalLoraChannel //
895 /////////////////////////////
896
897 // Setup
898 Ptr<LogicalLoraChannel> channel1 = Create<LogicalLoraChannel>(868000000, 0, 5);
899 Ptr<LogicalLoraChannel> channel2 = Create<LogicalLoraChannel>(868000000, 0, 5);
900 Ptr<LogicalLoraChannel> channel3 = Create<LogicalLoraChannel>(868100000, 0, 5);
901 Ptr<LogicalLoraChannel> channel4 = Create<LogicalLoraChannel>(868001000, 0, 5);
902
903 // Equality between channels
904 // Test the == and != operators
905 NS_TEST_EXPECT_MSG_EQ(channel1, channel2, "== operator doesn't work as expected");
906 NS_TEST_EXPECT_MSG_NE(channel1, channel3, "!= operator doesn't work as expected");
907 NS_TEST_EXPECT_MSG_NE(channel1, channel4, "!= operator doesn't work as expected");
908
909 //////////////////
910 // Test SubBand //
911 //////////////////
912
913 // Setup
914 auto subBand = Create<SubBand>(868000000, 868600000, 0.01, 14);
915 Ptr<LogicalLoraChannel> channel5 = Create<LogicalLoraChannel>(870000000, 0, 5);
916
917 // Test Contains
918 NS_TEST_EXPECT_MSG_EQ(subBand->Contains(channel3),
919 true,
920 "Contains does not behave as expected");
921 NS_TEST_EXPECT_MSG_EQ(subBand->Contains(channel3->GetFrequency()),
922 true,
923 "Contains does not behave as expected");
924 NS_TEST_EXPECT_MSG_EQ(subBand->Contains(channel5),
925 false,
926 "Contains does not behave as expected");
927
928 ///////////////////////////////////
929 // Test LogicalLoraChannelHelper //
930 ///////////////////////////////////
931
932 // Setup
933 auto channelHelper = Create<LogicalLoraChannelHelper>(16);
934 auto subBand1 = Create<SubBand>(869400000, 869650000, 0.10, 27);
935 channel1 = Create<LogicalLoraChannel>(868100000, 0, 5);
936 channel2 = Create<LogicalLoraChannel>(868300000, 0, 5);
937 channel3 = Create<LogicalLoraChannel>(869525000, 0, 5);
938
939 // Channel diagram
940 //
941 // Channels 1 2 3
942 // SubBands 868 ----- 1% ----- 868.6 869 ----- 10% ----- 869.4
943
944 // Add SubBands and LogicalLoraChannels to the helper
945 channelHelper->AddSubBand(subBand);
946 channelHelper->AddSubBand(subBand1);
947 channelHelper->SetChannel(0, channel1);
948 channelHelper->SetChannel(1, channel2);
949 channelHelper->SetChannel(2, channel3);
950
951 // Duty Cycle tests
952 // (high level duty cycle behavior)
953 ///////////////////////////////////
954
955 channelHelper->AddEvent(Seconds(2), channel1);
956 Time expectedTimeOff = Seconds(2 / 0.01);
957
958 // Wait time is computed correctly
959 NS_TEST_EXPECT_MSG_EQ(channelHelper->GetWaitTime(channel1),
960 expectedTimeOff,
961 "Wait time doesn't behave as expected");
962
963 // Duty Cycle involves the whole SubBand, not just a channel
964 NS_TEST_EXPECT_MSG_EQ(channelHelper->GetWaitTime(channel2),
965 expectedTimeOff,
966 "Wait time doesn't behave as expected");
967
968 // Other bands are not affected by this transmission
969 NS_TEST_EXPECT_MSG_EQ(channelHelper->GetWaitTime(channel3),
970 Time(0),
971 "Wait time affects other subbands");
972}
973
974/**
975 * @ingroup lorawan
976 *
977 * It tests the correctness of the LoraPhy::GetOnAirTime calculator against a number of pre-sourced
978 * time values of known scenarios
979 */
981{
982 public:
983 TimeOnAirTest(); //!< Default constructor
984 ~TimeOnAirTest() override; //!< Destructor
985
986 private:
987 void DoRun() override;
988};
989
990// Add some help text to this case to describe what it is intended to test
992 : TestCase(
993 "Verify that LoraPhy's function to compute the time on air of a packet works as expected")
994{
995}
996
997// Reminder that the test case should clean up after itself
1001
1002// This method is the pure virtual method from class TestCase that every
1003// TestCase must implement
1004void
1006{
1007 NS_LOG_DEBUG("TimeOnAirTest");
1008
1009 Ptr<Packet> packet;
1010 Time duration;
1011
1012 // Available parameters:
1013 // PayloadSize, SF, HeaderDisabled, CodingRate, Bandwidth, nPreambleSyms, crcEnabled,
1014 // lowDROptimization
1015
1016 // Starting parameters
1017 packet = Create<Packet>(10);
1018 LoraTxParameters txParams;
1019 txParams.sf = 7;
1020 txParams.headerDisabled = false;
1021 txParams.codingRate = 1;
1022 txParams.bandwidthHz = 125000;
1023 txParams.nPreamble = 8;
1024 txParams.crcEnabled = true;
1025 txParams.lowDataRateOptimizationEnabled = false;
1026
1027 duration = LoraPhy::GetOnAirTime(packet, txParams);
1028 NS_TEST_EXPECT_MSG_EQ_TOL(duration.GetSeconds(), 0.041216, 0.0001, "Unexpected duration");
1029
1030 txParams.sf = 8;
1031 duration = LoraPhy::GetOnAirTime(packet, txParams);
1032 NS_TEST_EXPECT_MSG_EQ_TOL(duration.GetSeconds(), 0.072192, 0.0001, "Unexpected duration");
1033
1034 txParams.headerDisabled = true;
1035 duration = LoraPhy::GetOnAirTime(packet, txParams);
1036 NS_TEST_EXPECT_MSG_EQ_TOL(duration.GetSeconds(), 0.072192, 0.0001, "Unexpected duration");
1037
1038 txParams.codingRate = 2;
1039 duration = LoraPhy::GetOnAirTime(packet, txParams);
1040 NS_TEST_EXPECT_MSG_EQ_TOL(duration.GetSeconds(), 0.078336, 0.0001, "Unexpected duration");
1041
1042 txParams.nPreamble = 10;
1043 duration = LoraPhy::GetOnAirTime(packet, txParams);
1044 NS_TEST_EXPECT_MSG_EQ_TOL(duration.GetSeconds(), 0.082432, 0.0001, "Unexpected duration");
1045
1046 txParams.lowDataRateOptimizationEnabled = true;
1047 duration = LoraPhy::GetOnAirTime(packet, txParams);
1048 NS_TEST_EXPECT_MSG_EQ_TOL(duration.GetSeconds(), 0.082432, 0.0001, "Unexpected duration");
1049
1050 txParams.sf = 10;
1051 duration = LoraPhy::GetOnAirTime(packet, txParams);
1052 NS_TEST_EXPECT_MSG_EQ_TOL(duration.GetSeconds(), 0.280576, 0.0001, "Unexpected duration");
1053
1054 txParams.bandwidthHz = 250000;
1055 duration = LoraPhy::GetOnAirTime(packet, txParams);
1056 NS_TEST_EXPECT_MSG_EQ_TOL(duration.GetSeconds(), 0.14028, 0.0001, "Unexpected duration");
1057
1058 txParams.bandwidthHz = 500000;
1059 duration = LoraPhy::GetOnAirTime(packet, txParams);
1060 NS_TEST_EXPECT_MSG_EQ_TOL(duration.GetSeconds(), 0.070144, 0.0001, "Unexpected duration");
1061
1062 txParams.headerDisabled = false;
1063 duration = LoraPhy::GetOnAirTime(packet, txParams);
1064 NS_TEST_EXPECT_MSG_EQ_TOL(duration.GetSeconds(), 0.082432, 0.0001, "Unexpected duration");
1065
1066 txParams.nPreamble = 8;
1067 duration = LoraPhy::GetOnAirTime(packet, txParams);
1068 NS_TEST_EXPECT_MSG_EQ_TOL(duration.GetSeconds(), 0.078336, 0.0001, "Unexpected duration");
1069
1070 txParams.sf = 12;
1071 duration = LoraPhy::GetOnAirTime(packet, txParams);
1072 NS_TEST_EXPECT_MSG_EQ_TOL(duration.GetSeconds(), 0.264192, 0.0001, "Unexpected duration");
1073
1074 packet = Create<Packet>(50);
1075 duration = LoraPhy::GetOnAirTime(packet, txParams);
1076 NS_TEST_EXPECT_MSG_EQ_TOL(duration.GetSeconds(), 0.657408, 0.0001, "Unexpected duration");
1077
1078 txParams.bandwidthHz = 125000;
1079 duration = LoraPhy::GetOnAirTime(packet, txParams);
1080 NS_TEST_EXPECT_MSG_EQ_TOL(duration.GetSeconds(), 2.629632, 0.0001, "Unexpected duration");
1081
1082 txParams.codingRate = 1;
1083 duration = LoraPhy::GetOnAirTime(packet, txParams);
1084 NS_TEST_EXPECT_MSG_EQ_TOL(duration.GetSeconds(), 2.301952, 0.0001, "Unexpected duration");
1085}
1086
1087/**
1088 * @ingroup lorawan
1089 *
1090 * It tests sending packets over a LoRa physical channel between multiple devices and the resulting
1091 * possible outcomes
1092 */
1094{
1095 public:
1096 PhyConnectivityTest(); //!< Default constructor
1097 ~PhyConnectivityTest() override; //!< Destructor
1098
1099 /**
1100 * Reset counters and end devices' PHYs for new sub test case.
1101 */
1102 void Reset();
1103
1104 /**
1105 * Callback for tracing ReceivedPacket.
1106 *
1107 * @param packet The packet received.
1108 * @param node The receiver node id if any, 0 otherwise.
1109 */
1110 void ReceivedPacket(Ptr<const Packet> packet, uint32_t node);
1111
1112 /**
1113 * Callback for tracing LostPacketBecauseUnderSensitivity.
1114 *
1115 * @param packet The packet lost.
1116 * @param node The receiver node id if any, 0 otherwise.
1117 */
1118 void UnderSensitivity(Ptr<const Packet> packet, uint32_t node);
1119
1120 /**
1121 * Callback for tracing LostPacketBecauseInterference.
1122 *
1123 * @param packet The packet lost.
1124 * @param node The receiver node id if any, 0 otherwise.
1125 */
1126 void Interference(Ptr<const Packet> packet, uint32_t node);
1127
1128 /**
1129 * Callback for tracing LostPacketBecauseWrongFrequency.
1130 *
1131 * @param packet The packet lost.
1132 * @param node The receiver node id if any, 0 otherwise.
1133 */
1134 void WrongFrequency(Ptr<const Packet> packet, uint32_t node);
1135
1136 /**
1137 * Callback for tracing LostPacketBecauseWrongSpreadingFactor.
1138 *
1139 * @param packet The packet lost.
1140 * @param node The receiver node id if any, 0 otherwise.
1141 */
1142 void WrongSf(Ptr<const Packet> packet, uint32_t node);
1143
1144 /**
1145 * Compare two packets to check if they are equal.
1146 *
1147 * @param packet1 A first packet.
1148 * @param packet2 A second packet.
1149 * @return True if their unique identifiers are equal,
1150 * @return false otherwise.
1151 */
1152 bool IsSamePacket(Ptr<Packet> packet1, Ptr<Packet> packet2);
1153
1154 private:
1155 void DoRun() override;
1156
1157 Ptr<LoraChannel> channel; //!< The LoRa channel used for tests
1158 Ptr<SimpleEndDeviceLoraPhy> edPhy1; //!< The first end device's PHY layer used in tests
1159 Ptr<SimpleEndDeviceLoraPhy> edPhy2; //!< The second end device's PHY layer used in tests
1160 Ptr<SimpleEndDeviceLoraPhy> edPhy3; //!< The third end device's PHY layer used in tests
1161
1162 Ptr<Packet> m_latestReceivedPacket; //!< Pointer to track the last received packet
1163 int m_receivedPacketCalls = 0; //!< Counter for ReceivedPacket calls
1164 int m_underSensitivityCalls = 0; //!< Counter for LostPacketBecauseUnderSensitivity calls
1165 int m_interferenceCalls = 0; //!< Counter for LostPacketBecauseInterference calls
1166 int m_wrongSfCalls = 0; //!< Counter for LostPacketBecauseWrongSpreadingFactor calls
1167 int m_wrongFrequencyCalls = 0; //!< Counter for LostPacketBecauseWrongFrequency calls
1168};
1169
1170// Add some help text to this case to describe what it is intended to test
1172 : TestCase("Verify that PhyConnectivity works as expected")
1173{
1174}
1175
1176// Reminder that the test case should clean up after itself
1180
1181void
1183{
1184 NS_LOG_FUNCTION(packet << node);
1185
1187
1188 m_latestReceivedPacket = packet->Copy();
1189}
1190
1191void
1198
1199void
1201{
1202 NS_LOG_FUNCTION(packet << node);
1203
1205}
1206
1207void
1209{
1210 NS_LOG_FUNCTION(packet << node);
1211
1213}
1214
1215void
1222
1223bool
1225{
1226 return packet1->GetUid() == packet2->GetUid();
1227}
1228
1229void
1231{
1235 m_wrongSfCalls = 0;
1237
1239 loss->SetPathLossExponent(3.76);
1240 loss->SetReference(1, 7.7);
1241
1243
1244 // Create the channel
1245 channel = CreateObject<LoraChannel>(loss, delay);
1246
1247 // Connect PHYs
1251
1252 edPhy1->SetFrequency(868100000);
1253 edPhy2->SetFrequency(868100000);
1254 edPhy3->SetFrequency(868100000);
1255
1259
1260 mob1->SetPosition(Vector(0.0, 0.0, 0.0));
1261 mob2->SetPosition(Vector(10.0, 0.0, 0.0));
1262 mob3->SetPosition(Vector(20.0, 0.0, 0.0));
1263
1264 edPhy1->SetMobility(mob1);
1265 edPhy2->SetMobility(mob2);
1266 edPhy3->SetMobility(mob3);
1267
1268 edPhy1->SwitchToStandby();
1269 edPhy2->SwitchToStandby();
1270 edPhy3->SwitchToStandby();
1271
1272 channel->Add(edPhy1);
1273 channel->Add(edPhy2);
1274 channel->Add(edPhy3);
1275
1276 edPhy1->SetChannel(channel);
1277 edPhy2->SetChannel(channel);
1278 edPhy3->SetChannel(channel);
1279
1280 // Listen for a specific SpreadingFactor
1281 edPhy1->SetSpreadingFactor(12);
1282 edPhy2->SetSpreadingFactor(12);
1283 edPhy3->SetSpreadingFactor(12);
1284
1285 // Listen on a specific frequency
1286 edPhy1->SetFrequency(868100000);
1287 edPhy2->SetFrequency(868100000);
1288 edPhy3->SetFrequency(868100000);
1289
1290 edPhy1->TraceConnectWithoutContext("ReceivedPacket",
1292 edPhy2->TraceConnectWithoutContext("ReceivedPacket",
1294 edPhy3->TraceConnectWithoutContext("ReceivedPacket",
1296
1297 edPhy1->TraceConnectWithoutContext("LostPacketBecauseUnderSensitivity",
1299 edPhy2->TraceConnectWithoutContext("LostPacketBecauseUnderSensitivity",
1301 edPhy3->TraceConnectWithoutContext("LostPacketBecauseUnderSensitivity",
1303
1304 edPhy1->TraceConnectWithoutContext("LostPacketBecauseInterference",
1306 edPhy2->TraceConnectWithoutContext("LostPacketBecauseInterference",
1308 edPhy3->TraceConnectWithoutContext("LostPacketBecauseInterference",
1310
1311 edPhy1->TraceConnectWithoutContext("LostPacketBecauseWrongFrequency",
1313 edPhy2->TraceConnectWithoutContext("LostPacketBecauseWrongFrequency",
1315 edPhy3->TraceConnectWithoutContext("LostPacketBecauseWrongFrequency",
1317
1318 edPhy1->TraceConnectWithoutContext("LostPacketBecauseWrongSpreadingFactor",
1320 edPhy2->TraceConnectWithoutContext("LostPacketBecauseWrongSpreadingFactor",
1322 edPhy3->TraceConnectWithoutContext("LostPacketBecauseWrongSpreadingFactor",
1324}
1325
1326// This method is the pure virtual method from class TestCase that every
1327// TestCase must implement
1328void
1330{
1331 NS_LOG_DEBUG("PhyConnectivityTest");
1332
1333 // Setup
1334 ////////
1335
1336 Reset();
1337
1338 LoraTxParameters txParams;
1339 txParams.sf = 12;
1340
1341 uint8_t buffer[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
1342 Ptr<Packet> packet = Create<Packet>(buffer, 10);
1343
1344 // Testing
1345 //////////
1346
1347 // Basic packet delivery test
1348 /////////////////////////////
1349
1352 edPhy1,
1353 packet,
1354 txParams,
1355 868100000,
1356 14);
1357
1361
1364 2,
1365 "Channel skipped some PHYs when delivering a packet"); // All PHYs except the sender
1366
1367 Reset();
1368
1369 // Sleeping PHYs do not receive the packet
1370
1371 edPhy2->SwitchToSleep();
1372
1375 edPhy1,
1376 packet,
1377 txParams,
1378 868100000,
1379 14);
1380
1384
1387 1,
1388 "Packet was received by a PHY in SLEEP mode"); // All PHYs in Standby except the sender
1389
1390 Reset();
1391
1392 // Packet that arrives under sensitivity is received correctly if the spreading factor increases
1393
1394 txParams.sf = 7;
1395 edPhy2->SetSpreadingFactor(7);
1397 ->SetPosition(Vector(2990, 0, 0));
1398
1401 edPhy1,
1402 packet,
1403 txParams,
1404 868100000,
1405 14);
1406
1410
1413 1,
1414 "Packet that should have been lost because of low receive power was received");
1415
1416 Reset();
1417
1418 // Try again using a packet with higher spreading factor
1419 txParams.sf = 8;
1420 edPhy2->SetSpreadingFactor(8);
1422 ->SetPosition(Vector(2990, 0, 0));
1423
1426 edPhy1,
1427 packet,
1428 txParams,
1429 868100000,
1430 14);
1431
1435
1437 0,
1438 "Packets that should have arrived above sensitivity were under it");
1439
1440 Reset();
1441
1442 // Packets can be destroyed by interference
1443
1444 txParams.sf = 12;
1447 edPhy1,
1448 packet,
1449 txParams,
1450 868100000,
1451 14);
1454 edPhy3,
1455 packet,
1456 txParams,
1457 868100000,
1458 14);
1459
1463
1465 1,
1466 "Packets that should be destroyed by interference weren't");
1467
1468 Reset();
1469
1470 // Packets can be lost because the PHY is not listening on the right frequency
1471
1474 edPhy1,
1475 packet,
1476 txParams,
1477 868300000,
1478 14);
1479
1483
1485 2,
1486 "Packets were received even though PHY was on a different frequency");
1487
1488 Reset();
1489
1490 // Packets can be lost because the PHY is not listening for the right spreading factor
1491
1492 txParams.sf = 8; // Send with 8, listening for 12
1495 edPhy1,
1496 packet,
1497 txParams,
1498 868100000,
1499 14);
1500
1504
1507 2,
1508 "Packets were received even though PHY was listening for a different spreading factor.");
1509
1510 Reset();
1511
1512 // Sending of packets
1513 /////////////////////
1514
1515 // The very same packet arrives at the other PHY
1518 edPhy1,
1519 packet,
1520 txParams,
1521 868100000,
1522 14);
1523
1527
1529 true,
1530 "Packet changed contents when going through the channel");
1531
1532 Reset();
1533
1534 // Correct state transitions
1535 ////////////////////////////
1536
1537 // PHY switches to STANDBY after TX and RX
1538
1541 edPhy1,
1542 packet,
1543 txParams,
1544 868100000,
1545 14);
1546
1550
1551 NS_TEST_EXPECT_MSG_EQ(edPhy1->GetState(),
1552 SimpleEndDeviceLoraPhy::STANDBY,
1553 "State didn't switch to STANDBY as expected");
1554 NS_TEST_EXPECT_MSG_EQ(edPhy2->GetState(),
1555 SimpleEndDeviceLoraPhy::STANDBY,
1556 "State didn't switch to STANDBY as expected");
1557}
1558
1559/**
1560 * @ingroup lorawan
1561 *
1562 * It tests the functionalities of the MAC layer of LoRaWAN devices
1563 *
1564 * @todo Not implemented yet.
1565 */
1567{
1568 public:
1569 LorawanMacTest(); //!< Default constructor
1570 ~LorawanMacTest() override; //!< Destructor
1571
1572 private:
1573 void DoRun() override;
1574};
1575
1576// Add some help text to this case to describe what it is intended to test
1578 : TestCase("Verify that the MAC layer of end devices behaves as expected")
1579{
1580}
1581
1582// Reminder that the test case should clean up after itself
1586
1587// This method is the pure virtual method from class TestCase that every
1588// TestCase must implement
1589void
1591{
1592 NS_LOG_DEBUG("LorawanMacTest");
1593}
1594
1595/**
1596 * @ingroup lorawan
1597 *
1598 * It tests the functionalities of LoRaWAN MAC commands received by devices.
1599 *
1600 * This means testing that (i) settings in the downlink MAC commands are correctly applied/rejected
1601 * by the device, and that (ii) the correct answer (if expected) is produced by the device.
1602 */
1604{
1605 public:
1606 MacCommandTest(); //!< Default constructor
1607 ~MacCommandTest() override; //!< Destructor
1608
1609 private:
1610 /**
1611 * Have this class' MAC layer receive a downlink packet carrying the input MAC command. After,
1612 * trigger a new empty uplink packet send that can then be used to examine the MAC command
1613 * answers in the header.
1614 *
1615 * @tparam T \explicit The type of MAC command to create.
1616 * @tparam Ts \deduced Types of the constructor arguments.
1617 * @param [in] args MAC command constructor arguments.
1618 * @return The list of MAC commands produced by the device as an answer.
1619 */
1620 template <typename T, typename... Ts>
1621 std::vector<Ptr<MacCommand>> RunMacCommand(Ts&&... args);
1622
1623 /**
1624 * This function resets the state of the MAC layer used for tests. Use it before each call of
1625 * RunMacCommand. Otherwise, on consecutive calls the MAC layer will not send due to duty-cycle
1626 * limitations.
1627 */
1628 void Reset();
1629
1630 void DoRun() override;
1631
1632 Ptr<ClassAEndDeviceLorawanMac> m_mac; //!< The end device's MAC layer used in tests.
1633};
1634
1636 : TestCase("Test functionality of MAC commands when received by a device")
1637{
1638}
1639
1641{
1642 m_mac = nullptr;
1643}
1644
1645template <typename T, typename... Ts>
1646std::vector<Ptr<MacCommand>>
1648{
1649 Ptr<Packet> pkt;
1650 LoraFrameHeader fhdr;
1651 LorawanMacHeader mhdr;
1652 // Prepare DL packet with input command
1653 pkt = Create<Packet>(0);
1654 fhdr.SetAsDownlink();
1655 auto cmd = Create<T>(args...);
1656 fhdr.AddCommand(cmd);
1657 pkt->AddHeader(fhdr);
1659 pkt->AddHeader(mhdr);
1660 // Trigger MAC layer reception
1662 ->SwitchToStandby(); // usually done as we open Rx windows
1663 m_mac->Receive(pkt);
1664 // Trigger MAC layer send
1665 pkt = Create<Packet>(0);
1666 m_mac->Send(pkt);
1667 // Retrieve uplink MAC commands
1668 pkt->RemoveHeader(mhdr);
1669 fhdr.SetAsUplink();
1670 pkt->RemoveHeader(fhdr);
1671 return fhdr.GetCommands();
1672}
1673
1674void
1676{
1677 // Reset MAC state
1678 LorawanMacHelper macHelper;
1681 /// @todo Create should not require a node in input.
1682 m_mac = DynamicCast<ClassAEndDeviceLorawanMac>(macHelper.Install(nullptr, nullptr));
1683 NS_TEST_EXPECT_MSG_NE(m_mac, nullptr, "Failed to initialize MAC layer object.");
1685 phy->SetChannel(CreateObject<LoraChannel>());
1687 m_mac->SetPhy(phy);
1688}
1689
1690void
1692{
1693 NS_LOG_DEBUG("MacCommandTest");
1694
1695 Reset();
1696 // LinkCheckAns: get connectivity metrics of last uplink LinkCheckReq command
1697 {
1698 uint8_t margin = 20; // best reception margin [dB] from demodulation floor
1699 uint8_t gwCnt = 3; // number of gateways that received last uplink
1700 auto answers = RunMacCommand<LinkCheckAns>(margin, gwCnt);
1701 NS_TEST_EXPECT_MSG_EQ(unsigned(m_mac->GetLastKnownLinkMarginDb()),
1702 unsigned(margin),
1703 "m_lastKnownMarginDb differs from Margin field of LinkCheckAns");
1704 NS_TEST_EXPECT_MSG_EQ(unsigned(m_mac->GetLastKnownGatewayCount()),
1705 unsigned(gwCnt),
1706 "m_lastKnownGatewayCount differs GwCnt field of LinkCheckAns");
1707 NS_TEST_EXPECT_MSG_EQ(answers.size(),
1708 0,
1709 "Unexpected uplink MAC command answer(s) to LinkCheckAns");
1710 }
1711
1712 Reset();
1713 // LinkAdrReq: change data rate, TX power, redundancy, or channel mask
1714 {
1715 uint8_t dataRate = 5;
1716 uint8_t txPower = 2;
1717 uint16_t chMask = 0b101;
1718 uint8_t chMaskCntl = 0;
1719 uint8_t nbTrans = 13;
1720 auto answers = RunMacCommand<LinkAdrReq>(dataRate, txPower, chMask, chMaskCntl, nbTrans);
1721 NS_TEST_EXPECT_MSG_EQ(unsigned(m_mac->GetDataRate()),
1722 unsigned(dataRate),
1723 "m_dataRate does not match DataRate field of LinkAdrReq");
1724 NS_TEST_EXPECT_MSG_EQ(m_mac->GetTransmissionPowerDbm(),
1725 14 - txPower * 2,
1726 "m_txPowerDbm does not match txPower field of LinkAdrReq");
1727 NS_TEST_EXPECT_MSG_EQ(unsigned(m_mac->GetMaxNumberOfTransmissions()),
1728 unsigned(nbTrans),
1729 "m_nbTrans does not match nbTrans field of LinkAdrReq");
1730 auto channels = m_mac->GetLogicalLoraChannelHelper()->GetRawChannelArray();
1731 for (size_t i = 0; i < channels.size(); i++)
1732 {
1733 const auto& c = channels.at(i + 16 * chMaskCntl);
1734 bool actual = (c) ? c->IsEnabledForUplink() : false;
1735 bool expected = (chMask & 0b1 << i);
1736 NS_TEST_EXPECT_MSG_EQ(actual, expected, "Channel " << i << " state != chMask");
1737 }
1738 NS_TEST_ASSERT_MSG_EQ(answers.size(), 1, "1 answer cmd was expected, found 0 or >1");
1739 auto laa = DynamicCast<LinkAdrAns>(answers.at(0));
1740 NS_TEST_ASSERT_MSG_NE(laa, nullptr, "LinkAdrAns was expected, cmd type cast failed");
1741 NS_TEST_EXPECT_MSG_EQ(laa->GetChannelMaskAck(), true, "ChannelMaskAck expected to be true");
1742 NS_TEST_EXPECT_MSG_EQ(laa->GetDataRateAck(), true, "DataRateAck expected to be true");
1743 NS_TEST_EXPECT_MSG_EQ(laa->GetPowerAck(), true, "PowerAck expected to be true");
1744 }
1745
1746 Reset();
1747 // LinkAdrReq: ADR bit off, only change channel mask
1748 {
1749 uint8_t dataRate = 5;
1750 uint8_t txPower = 2;
1751 uint16_t chMask = 0b010;
1752 uint8_t chMaskCntl = 0;
1753 uint8_t nbTrans = 13;
1754 m_mac->SetUplinkAdrBit(false);
1755 auto answers = RunMacCommand<LinkAdrReq>(dataRate, txPower, chMask, chMaskCntl, nbTrans);
1756 NS_TEST_EXPECT_MSG_NE(unsigned(m_mac->GetDataRate()),
1757 unsigned(dataRate),
1758 "m_dataRate expected to differ from DataRate field of LinkAdrReq");
1759 NS_TEST_EXPECT_MSG_NE(m_mac->GetTransmissionPowerDbm(),
1760 14 - txPower * 2,
1761 "m_txPowerDbm expected to not match txPower field of LinkAdrReq");
1762 NS_TEST_EXPECT_MSG_NE(unsigned(m_mac->GetMaxNumberOfTransmissions()),
1763 unsigned(nbTrans),
1764 "m_nbTrans expected to differ from nbTrans field of LinkAdrReq");
1765 auto channels = m_mac->GetLogicalLoraChannelHelper()->GetRawChannelArray();
1766 for (size_t i = 0; i < channels.size(); i++)
1767 {
1768 const auto& c = channels.at(i + 16 * chMaskCntl);
1769 bool actual = (c) ? c->IsEnabledForUplink() : false;
1770 bool expected = (chMask & 0b1 << i);
1771 NS_TEST_EXPECT_MSG_EQ(actual, expected, "Channel " << i << " state != chMask");
1772 }
1773 NS_TEST_ASSERT_MSG_EQ(answers.size(), 1, "1 answer cmd was expected, found 0 or >1");
1774 auto laa = DynamicCast<LinkAdrAns>(answers.at(0));
1775 NS_TEST_ASSERT_MSG_NE(laa, nullptr, "LinkAdrAns was expected, cmd type cast failed");
1776 NS_TEST_EXPECT_MSG_EQ(laa->GetChannelMaskAck(), true, "ChannelMaskAck expected to be true");
1777 NS_TEST_EXPECT_MSG_EQ(laa->GetDataRateAck(), false, "DataRateAck expected to be false");
1778 NS_TEST_EXPECT_MSG_EQ(laa->GetPowerAck(), false, "PowerAck expected to be false");
1779 }
1780
1781 Reset();
1782 // LinkAdrReq: invalid chMask, data rate and power
1783 { // WARNING: default values are manually set here
1784 uint8_t dataRate = 12;
1785 uint8_t txPower = 8;
1786 uint16_t chMask = 0b0;
1787 uint8_t chMaskCntl = 0;
1788 uint8_t nbTrans = 6;
1789 auto answers = RunMacCommand<LinkAdrReq>(dataRate, txPower, chMask, chMaskCntl, nbTrans);
1790 NS_TEST_EXPECT_MSG_EQ(unsigned(m_mac->GetDataRate()),
1791 0,
1792 "m_dataRate expected to be default value");
1793 NS_TEST_EXPECT_MSG_EQ(m_mac->GetTransmissionPowerDbm(),
1794 14,
1795 "m_txPowerDbm expected to be default value");
1796 NS_TEST_EXPECT_MSG_EQ(unsigned(m_mac->GetMaxNumberOfTransmissions()),
1797 1,
1798 "m_nbTrans expected to be default value");
1799 auto channels = m_mac->GetLogicalLoraChannelHelper()->GetRawChannelArray();
1800 for (size_t i = 0; i < channels.size(); i++)
1801 {
1802 const auto& c = channels.at(i + 16 * chMaskCntl);
1803 bool actual = (c) ? c->IsEnabledForUplink() : false;
1804 bool expected = (uint16_t(0b111) & 0b1 << i);
1805 NS_TEST_EXPECT_MSG_EQ(actual, expected, "Channel " << i << " state != default");
1806 }
1807 NS_TEST_ASSERT_MSG_EQ(answers.size(), 1, "1 answer cmd was expected, found 0 or >1");
1808 auto laa = DynamicCast<LinkAdrAns>(answers.at(0));
1809 NS_TEST_ASSERT_MSG_NE(laa, nullptr, "LinkAdrAns was expected, cmd type cast failed");
1810 NS_TEST_EXPECT_MSG_EQ(laa->GetChannelMaskAck(), false, "ChannelMaskAck != false");
1811 NS_TEST_EXPECT_MSG_EQ(laa->GetDataRateAck(), false, "DataRateAck expected to be false");
1812 NS_TEST_EXPECT_MSG_EQ(laa->GetPowerAck(), false, "PowerAck expected to be false");
1813 }
1814
1815 Reset();
1816 // LinkAdrReq: invalid chMask, valid data rate and power
1817 { // WARNING: default values are manually set here
1818 uint8_t dataRate = 1;
1819 uint8_t txPower = 7;
1820 uint16_t chMask = 0b1000; // enable only non-exisitng channel
1821 uint8_t chMaskCntl = 0;
1822 uint8_t nbTrans = 3;
1823 auto answers = RunMacCommand<LinkAdrReq>(dataRate, txPower, chMask, chMaskCntl, nbTrans);
1824 NS_TEST_EXPECT_MSG_EQ(unsigned(m_mac->GetDataRate()),
1825 0,
1826 "m_dataRate expected to be default value");
1827 NS_TEST_EXPECT_MSG_EQ(m_mac->GetTransmissionPowerDbm(),
1828 14,
1829 "m_txPowerDbm expected to be default value");
1830 NS_TEST_EXPECT_MSG_EQ(unsigned(m_mac->GetMaxNumberOfTransmissions()),
1831 1,
1832 "m_nbTrans expected to be default value");
1833 auto channels = m_mac->GetLogicalLoraChannelHelper()->GetRawChannelArray();
1834 for (size_t i = 0; i < channels.size(); i++)
1835 {
1836 const auto& c = channels.at(i + 16 * chMaskCntl);
1837 bool actual = (c) ? c->IsEnabledForUplink() : false;
1838 bool expected = (uint16_t(0b111) & 0b1 << i);
1839 NS_TEST_EXPECT_MSG_EQ(actual, expected, "Channel " << i << " state != default");
1840 }
1841 NS_TEST_ASSERT_MSG_EQ(answers.size(), 1, "1 answer cmd was expected, found 0 or >1");
1842 auto laa = DynamicCast<LinkAdrAns>(answers.at(0));
1843 NS_TEST_ASSERT_MSG_NE(laa, nullptr, "LinkAdrAns was expected, cmd type cast failed");
1844 NS_TEST_EXPECT_MSG_EQ(laa->GetChannelMaskAck(), false, "ChannelMaskAck != false");
1845 NS_TEST_EXPECT_MSG_EQ(laa->GetDataRateAck(), true, "DataRateAck expected to be true");
1846 NS_TEST_EXPECT_MSG_EQ(laa->GetPowerAck(), true, "PowerAck expected to be true");
1847 }
1848
1849 Reset();
1850 // LinkAdrReq: fringe parameter values
1851 { // WARNING: default values are manually set here
1852 uint8_t dataRate = 0xF;
1853 uint8_t txPower = 0xF; // 0x0F ignores config
1854 uint16_t chMask = 0b0; // should be ignored because chMaskCntl is 6
1855 uint8_t chMaskCntl = 6; // all channels on
1856 uint8_t nbTrans = 0; // restore default 1
1857 // Set device params to values different from default
1858 m_mac->SetDataRate(3);
1859 m_mac->SetTransmissionPowerDbm(12);
1860 m_mac->SetMaxNumberOfTransmissions(15);
1861 auto channels = m_mac->GetLogicalLoraChannelHelper()->GetRawChannelArray();
1862 channels.at(0)->DisableForUplink();
1863 auto answers = RunMacCommand<LinkAdrReq>(dataRate, txPower, chMask, chMaskCntl, nbTrans);
1864 NS_TEST_EXPECT_MSG_EQ(unsigned(m_mac->GetDataRate()),
1865 3,
1866 "m_dataRate expected to be default value");
1867 NS_TEST_EXPECT_MSG_EQ(m_mac->GetTransmissionPowerDbm(),
1868 12,
1869 "m_txPowerDbm expected to be default value");
1870 NS_TEST_EXPECT_MSG_EQ(unsigned(m_mac->GetMaxNumberOfTransmissions()),
1871 1,
1872 "m_nbTrans expected to be default value");
1873 for (size_t i = 0; i < channels.size(); i++)
1874 {
1875 const auto& c = channels.at(i);
1876 bool actual = (c) ? c->IsEnabledForUplink() : false;
1877 bool expected = (uint16_t(0b111) & 0b1 << i);
1878 NS_TEST_EXPECT_MSG_EQ(actual, expected, "Channel " << i << " state != default");
1879 }
1880 NS_TEST_ASSERT_MSG_EQ(answers.size(), 1, "1 answer cmd was expected, found 0 or >1");
1881 auto laa = DynamicCast<LinkAdrAns>(answers.at(0));
1882 NS_TEST_ASSERT_MSG_NE(laa, nullptr, "LinkAdrAns was expected, cmd type cast failed");
1883 NS_TEST_EXPECT_MSG_EQ(laa->GetChannelMaskAck(), true, "ChannelMaskAck != true");
1884 NS_TEST_EXPECT_MSG_EQ(laa->GetDataRateAck(), true, "DataRateAck expected to be true");
1885 NS_TEST_EXPECT_MSG_EQ(laa->GetPowerAck(), true, "PowerAck expected to be true");
1886 }
1887
1888 Reset();
1889 // DutyCycleReq: duty cycle to 100%
1890 {
1891 uint8_t maxDutyCycle = 0;
1892 auto answers = RunMacCommand<DutyCycleReq>(maxDutyCycle);
1893 NS_TEST_EXPECT_MSG_EQ(m_mac->GetAggregatedDutyCycle(),
1894 1 / std::pow(2, maxDutyCycle),
1895 "m_aggregatedDutyCycle != 1");
1896 NS_TEST_ASSERT_MSG_EQ(answers.size(), 1, "1 answer cmd was expected, found 0 or >1");
1897 auto dca = DynamicCast<DutyCycleAns>(answers.at(0));
1898 NS_TEST_EXPECT_MSG_NE(dca, nullptr, "DutyCycleAns was expected, cmd type cast failed");
1899 }
1900
1901 Reset();
1902 // DutyCycleReq: duty cycle to 12.5%
1903 {
1904 uint8_t maxDutyCycle = 3;
1905 auto answers = RunMacCommand<DutyCycleReq>(maxDutyCycle);
1906 NS_TEST_EXPECT_MSG_EQ(m_mac->GetAggregatedDutyCycle(),
1907 1 / std::pow(2, maxDutyCycle),
1908 "m_aggregatedDutyCycle != 1");
1909 NS_TEST_ASSERT_MSG_EQ(answers.size(), 1, "1 answer cmd was expected, found 0 or >1");
1910 auto dca = DynamicCast<DutyCycleAns>(answers.at(0));
1911 NS_TEST_EXPECT_MSG_NE(dca, nullptr, "DutyCycleAns was expected, cmd type cast failed");
1912 }
1913
1914 Reset();
1915 // RxParamSetupReq: set rx1Dr, rx2Dr, frequency
1916 {
1917 uint8_t rx1DrOffset = 5;
1918 uint8_t rx2DataRate = 5;
1919 double frequencyHz = 863500000;
1920 m_mac->SetDataRate(5);
1921 auto answers = RunMacCommand<RxParamSetupReq>(rx1DrOffset, rx2DataRate, frequencyHz);
1922 NS_TEST_EXPECT_MSG_EQ(unsigned(m_mac->GetFirstReceiveWindowDataRate()),
1923 unsigned(5 - rx1DrOffset),
1924 "Rx1DataRate does not match rx1DrOffset from RxParamSetupReq");
1925 NS_TEST_EXPECT_MSG_EQ(unsigned(m_mac->GetSecondReceiveWindowDataRate()),
1926 unsigned(rx2DataRate),
1927 "Rx2DataRate does not match rx2DataRate from RxParamSetupReq");
1928 NS_TEST_EXPECT_MSG_EQ(m_mac->GetSecondReceiveWindowFrequency(),
1929 frequencyHz,
1930 "Rx2 frequency does not match frequency from RxParamSetupReq");
1931 NS_TEST_ASSERT_MSG_EQ(answers.size(), 1, "1 answer cmd was expected, found 0 or >1");
1932 auto rpsa = DynamicCast<RxParamSetupAns>(answers.at(0));
1933 NS_TEST_ASSERT_MSG_NE(rpsa, nullptr, "RxParamSetupAns was expected, cmd type cast failed");
1934 NS_TEST_EXPECT_MSG_EQ(rpsa->GetRx1DrOffsetAck(), true, "Rx1DrOffsetAck != true");
1935 NS_TEST_EXPECT_MSG_EQ(rpsa->GetRx2DataRateAck(), true, "Rx2DataRateAck != true");
1936 NS_TEST_EXPECT_MSG_EQ(rpsa->GetChannelAck(), true, "ChannelAck expected to be true");
1937 }
1938
1939 Reset();
1940 // RxParamSetupReq: invalid rx1Dr, rx2Dr, frequency
1941 { // WARNING: default values are manually set here
1942 uint8_t rx1DrOffset = 6;
1943 uint8_t rx2DataRate = 12;
1944 double frequencyHz = 871000000;
1945 m_mac->SetDataRate(5);
1946 auto answers = RunMacCommand<RxParamSetupReq>(rx1DrOffset, rx2DataRate, frequencyHz);
1947 NS_TEST_EXPECT_MSG_EQ(unsigned(m_mac->GetFirstReceiveWindowDataRate()),
1948 5,
1949 "Rx1DataRate expected to be default value");
1950 NS_TEST_EXPECT_MSG_EQ(unsigned(m_mac->GetSecondReceiveWindowDataRate()),
1951 0,
1952 "Rx2DataRate expected to be default value");
1953 NS_TEST_EXPECT_MSG_EQ(m_mac->GetSecondReceiveWindowFrequency(),
1954 869525000,
1955 "Rx2 frequency expected to be default value");
1956 NS_TEST_ASSERT_MSG_EQ(answers.size(), 1, "1 answer cmd was expected, found 0 or >1");
1957 auto rpsa = DynamicCast<RxParamSetupAns>(answers.at(0));
1958 NS_TEST_ASSERT_MSG_NE(rpsa, nullptr, "RxParamSetupAns was expected, cmd type cast failed");
1959 NS_TEST_EXPECT_MSG_EQ(rpsa->GetRx1DrOffsetAck(), false, "Rx1DrOffsetAck != false");
1960 NS_TEST_EXPECT_MSG_EQ(rpsa->GetRx2DataRateAck(), false, "Rx2DataRateAck != false");
1961 NS_TEST_EXPECT_MSG_EQ(rpsa->GetChannelAck(), false, "ChannelAck expected to be false");
1962 }
1963
1964 Reset();
1965 // DevStatusReq: get default values
1966 { // WARNING: default values are manually set here
1967 auto answers = RunMacCommand<DevStatusReq>();
1968 NS_TEST_ASSERT_MSG_EQ(answers.size(), 1, "1 answer cmd was expected, found 0 or >1");
1969 auto dsa = DynamicCast<DevStatusAns>(answers.at(0));
1970 NS_TEST_ASSERT_MSG_NE(dsa, nullptr, "DevStatusAns was expected, cmd type cast failed");
1971 NS_TEST_EXPECT_MSG_EQ(unsigned(dsa->GetBattery()), 0, "Battery expected == 0 (ext power)");
1972 NS_TEST_EXPECT_MSG_EQ(unsigned(dsa->GetMargin()), 31, "Margin expected to be 31 (default)");
1973 }
1974
1975 Reset();
1976 // NewChannelReq: add a new channel
1977 {
1978 uint8_t chIndex = 4;
1979 double frequencyHz = 865100000;
1980 uint8_t minDataRate = 1;
1981 uint8_t maxDataRate = 4;
1982 auto answers = RunMacCommand<NewChannelReq>(chIndex, frequencyHz, minDataRate, maxDataRate);
1983 NS_TEST_ASSERT_MSG_EQ(answers.size(), 1, "1 answer cmd was expected, found 0 or >1");
1984 auto c = m_mac->GetLogicalLoraChannelHelper()->GetRawChannelArray().at(chIndex);
1985 NS_TEST_ASSERT_MSG_NE(c, nullptr, "Channel at chIndex slot expected not to be nullptr");
1986 NS_TEST_EXPECT_MSG_EQ(c->GetFrequency(),
1987 frequencyHz,
1988 "Channel frequency expected to equal NewChannelReq frequency");
1989 NS_TEST_EXPECT_MSG_EQ(c->GetMinimumDataRate(),
1990 unsigned(minDataRate),
1991 "Channel minDataRate expected to equal NewChannelReq minDataRate");
1992 NS_TEST_EXPECT_MSG_EQ(c->GetMaximumDataRate(),
1993 unsigned(maxDataRate),
1994 "Channel maxDataRate expected to equal NewChannelReq maxDataRate");
1995 auto nca = DynamicCast<NewChannelAns>(answers.at(0));
1996 NS_TEST_ASSERT_MSG_NE(nca, nullptr, "NewChannelAns was expected, cmd type cast failed");
1997 NS_TEST_EXPECT_MSG_EQ(nca->GetDataRateRangeOk(), true, "DataRateRangeOk != true");
1998 NS_TEST_EXPECT_MSG_EQ(nca->GetChannelFrequencyOk(), true, "ChannelFrequencyOk != true");
1999 }
2000
2001 Reset();
2002 // NewChannelReq: invalid new channel
2003 { // WARNING: default values are manually set here
2004 uint8_t chIndex = 1;
2005 double frequencyHz = 862000000;
2006 uint8_t minDataRate = 14;
2007 uint8_t maxDataRate = 13;
2008 auto answers = RunMacCommand<NewChannelReq>(chIndex, frequencyHz, minDataRate, maxDataRate);
2009 NS_TEST_ASSERT_MSG_EQ(answers.size(), 1, "1 answer cmd was expected, found 0 or >1");
2010 double defaultFrequenciesHz[3] = {868100000, 868300000, 868500000};
2011 auto channels = m_mac->GetLogicalLoraChannelHelper()->GetRawChannelArray();
2012 for (size_t i = 0; i < channels.size(); i++)
2013 {
2014 const auto& c = channels.at(i);
2015 if (i > 2)
2016 {
2017 NS_TEST_ASSERT_MSG_EQ(c, nullptr, "Channel " << i << "expected to be nullptr");
2018 continue;
2019 }
2020 NS_TEST_EXPECT_MSG_EQ(c->GetFrequency(),
2021 defaultFrequenciesHz[i],
2022 "Channel frequency expected to equal NewChannelReq frequency");
2023 NS_TEST_EXPECT_MSG_EQ(unsigned(c->GetMinimumDataRate()),
2024 0,
2025 "Channel " << i << " minDataRate expected to be default");
2026 NS_TEST_EXPECT_MSG_EQ(unsigned(c->GetMaximumDataRate()),
2027 5,
2028 "Channel " << i << " maxDataRate expected to be default");
2029 NS_TEST_EXPECT_MSG_EQ(c->IsEnabledForUplink(),
2030 true,
2031 "Channel " << i << " state expected to be active by default");
2032 }
2033 auto nca = DynamicCast<NewChannelAns>(answers.at(0));
2034 NS_TEST_ASSERT_MSG_NE(nca, nullptr, "NewChannelAns was expected, cmd type cast failed");
2035 NS_TEST_EXPECT_MSG_EQ(nca->GetDataRateRangeOk(), false, "DataRateRangeOk != false");
2036 NS_TEST_EXPECT_MSG_EQ(nca->GetChannelFrequencyOk(), false, "ChannelFrequencyOk != false");
2037 }
2038}
2039
2040/**
2041 * @ingroup lorawan
2042 *
2043 * The TestSuite class names the TestSuite, identifies what type of TestSuite, and enables the
2044 * TestCases to be run. Typically, only the constructor for this class must be defined
2045 */
2047{
2048 public:
2049 LorawanTestSuite(); //!< Default constructor
2050};
2051
2053 : TestSuite("lorawan", Type::UNIT)
2054{
2055 // LogComponentEnable("LorawanTestSuite", LOG_LEVEL_DEBUG);
2056 // LogComponentEnable("LorawanMac", LOG_LEVEL_DEBUG);
2057 // LogComponentEnable("EndDeviceLorawanMac", LOG_LEVEL_DEBUG);
2058 // LogComponentEnable("ClassAEndDeviceLorawanMac", LOG_LEVEL_DEBUG);
2059 // LogComponentEnable("SimpleEndDeviceLoraPhy", LOG_LEVEL_DEBUG);
2060 // LogComponentEnable("EndDeviceLoraPhy", LOG_LEVEL_DEBUG);
2061 // LogComponentEnable("LoraPhy", LOG_LEVEL_DEBUG);
2062 // LogComponentEnable("LoraChannel", LOG_LEVEL_DEBUG);
2063 // LogComponentEnable("LoraFrameHeader", LOG_LEVEL_DEBUG);
2064 // LogComponentEnableAll(LOG_PREFIX_FUNC);
2065 // LogComponentEnableAll(LOG_PREFIX_NODE);
2066 // LogComponentEnableAll(LOG_PREFIX_TIME);
2067
2076}
2077
2078// Do not forget to allocate an instance of this TestSuite
It tests LoraDeviceAddress comparison operators overrides and generation of new addresses with LoraDe...
AddressTest()
Default constructor.
void DoRun() override
Implementation to actually run this TestCase.
~AddressTest() override
Destructor.
It tests serialization/deserialization of LoRaWAN headers (the LorawanMacHeader and LoraFrameHeader c...
void DoRun() override
Implementation to actually run this TestCase.
HeaderTest()
Default constructor.
~HeaderTest() override
Destructor.
It tests interference computations in a number of possible scenarios using the LoraInterferenceHelper...
~InterferenceTest() override
Destructor.
void DoRun() override
Implementation to actually run this TestCase.
InterferenceTest()
Default constructor.
It tests functionality of the LogicalLoraChannel, SubBand and LogicalLoraChannelHelper classes.
LogicalLoraChannelTest()
Default constructor.
~LogicalLoraChannelTest() override
Destructor.
void DoRun() override
Implementation to actually run this TestCase.
It tests the functionalities of the MAC layer of LoRaWAN devices.
~LorawanMacTest() override
Destructor.
LorawanMacTest()
Default constructor.
void DoRun() override
Implementation to actually run this TestCase.
The TestSuite class names the TestSuite, identifies what type of TestSuite, and enables the TestCases...
LorawanTestSuite()
Default constructor.
It tests the functionalities of LoRaWAN MAC commands received by devices.
~MacCommandTest() override
Destructor.
MacCommandTest()
Default constructor.
void Reset()
This function resets the state of the MAC layer used for tests.
void DoRun() override
Implementation to actually run this TestCase.
Ptr< ClassAEndDeviceLorawanMac > m_mac
The end device's MAC layer used in tests.
std::vector< Ptr< MacCommand > > RunMacCommand(Ts &&... args)
Have this class' MAC layer receive a downlink packet carrying the input MAC command.
It tests sending packets over a LoRa physical channel between multiple devices and the resulting poss...
int m_interferenceCalls
Counter for LostPacketBecauseInterference calls.
void Reset()
Reset counters and end devices' PHYs for new sub test case.
Ptr< SimpleEndDeviceLoraPhy > edPhy2
The second end device's PHY layer used in tests.
void WrongFrequency(Ptr< const Packet > packet, uint32_t node)
Callback for tracing LostPacketBecauseWrongFrequency.
void DoRun() override
Implementation to actually run this TestCase.
void UnderSensitivity(Ptr< const Packet > packet, uint32_t node)
Callback for tracing LostPacketBecauseUnderSensitivity.
bool IsSamePacket(Ptr< Packet > packet1, Ptr< Packet > packet2)
Compare two packets to check if they are equal.
Ptr< SimpleEndDeviceLoraPhy > edPhy3
The third end device's PHY layer used in tests.
Ptr< SimpleEndDeviceLoraPhy > edPhy1
The first end device's PHY layer used in tests.
int m_wrongSfCalls
Counter for LostPacketBecauseWrongSpreadingFactor calls.
int m_wrongFrequencyCalls
Counter for LostPacketBecauseWrongFrequency calls.
~PhyConnectivityTest() override
Destructor.
int m_underSensitivityCalls
Counter for LostPacketBecauseUnderSensitivity calls.
int m_receivedPacketCalls
Counter for ReceivedPacket calls.
void WrongSf(Ptr< const Packet > packet, uint32_t node)
Callback for tracing LostPacketBecauseWrongSpreadingFactor.
Ptr< LoraChannel > channel
The LoRa channel used for tests.
PhyConnectivityTest()
Default constructor.
void Interference(Ptr< const Packet > packet, uint32_t node)
Callback for tracing LostPacketBecauseInterference.
Ptr< Packet > m_latestReceivedPacket
Pointer to track the last received packet.
void ReceivedPacket(Ptr< const Packet > packet, uint32_t node)
Callback for tracing ReceivedPacket.
It tests a number of cases related to SimpleGatewayLoraPhy's parallel reception paths.
~ReceivePathTest() override
Destructor.
ReceivePathTest()
Default constructor.
int m_receivedPacketCalls
Counter for ReceivedPacket calls.
void OccupiedReceptionPaths(int oldValue, int newValue)
Callback for tracing OccupiedReceptionPaths.
Ptr< SimpleGatewayLoraPhy > gatewayPhy
PHY layer of a gateway to be tested.
void ReceivedPacket(Ptr< const Packet > packet, uint32_t node)
Callback for tracing ReceivedPacket.
void Interference(Ptr< const Packet > packet, uint32_t node)
Callback for tracing LostPacketBecauseInterference.
void NoMoreDemodulators(Ptr< const Packet > packet, uint32_t node)
Callback for tracing LostPacketBecauseNoMoreReceivers.
void DoRun() override
Implementation to actually run this TestCase.
int m_noMoreDemodulatorsCalls
Counter for LostPacketBecauseNoMoreReceivers calls.
void Reset()
Reset counters and gateway PHY for new sub test case.
int m_interferenceCalls
Counter for LostPacketBecauseInterference calls.
int m_maxOccupiedReceptionPaths
Max number of concurrent OccupiedReceptionPaths.
It tests the correctness of the LoraPhy::GetOnAirTime calculator against a number of pre-sourced time...
void DoRun() override
Implementation to actually run this TestCase.
~TimeOnAirTest() override
Destructor.
TimeOnAirTest()
Default constructor.
iterator in a Buffer instance
Definition buffer.h:89
automatically resized byte buffer
Definition buffer.h:83
void AddAtStart(uint32_t start)
Definition buffer.cc:303
Buffer::Iterator Begin() const
Definition buffer.h:1063
Smart pointer class similar to boost::intrusive_ptr.
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition simulator.h:560
static void Destroy()
Execute the events scheduled with ScheduleDestroy().
Definition simulator.cc:131
static void Run()
Run the simulation.
Definition simulator.cc:167
static void Stop()
Tell the Simulator the calling event should be the last one executed.
Definition simulator.cc:175
encapsulates test code
Definition test.h:1050
void AddTestCase(TestCase *testCase, Duration duration=Duration::QUICK)
Add an individual child TestCase to this test suite.
Definition test.cc:292
A suite of tests to run.
Definition test.h:1267
Type
Type of test.
Definition test.h:1274
Simulation virtual time values and global simulation resolution.
Definition nstime.h:94
double GetSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
Definition nstime.h:392
This class generates sequential LoraDeviceAddress instances.
LoraDeviceAddress NextAddress()
Allocate the next LoraDeviceAddress.
LoraDeviceAddress GetNextAddress()
Get the LoraDeviceAddress that will be allocated upon a call to NextAddress.
This class represents the device address of a LoraWAN end device.
static LoraDeviceAddress Deserialize(const uint8_t buf[4])
Convert the input buffer into a new address.
void Serialize(uint8_t buf[4]) const
Convert this address to a buffer.
This class represents the Frame header (FHDR) used in a LoraWAN network.
std::vector< Ptr< MacCommand > > GetCommands()
Return a vector of pointers to all the MAC commands saved in this header.
bool GetAck() const
Get the value of the ACK bit field.
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 SetAck(bool ack)
Set the value of the ACK bit field.
void SetAdr(bool adr)
Set the value of the ADR bit field.
void SetAddress(LoraDeviceAddress address)
Set the address.
uint16_t GetFCnt() const
Get the FCnt value.
void SetAsUplink()
State that this is an uplink message.
LoraDeviceAddress GetAddress() const
Get this header's device address value.
void Serialize(Buffer::Iterator start) const override
Serialize the header.
void AddLinkCheckAns(uint8_t margin, uint8_t gwCnt)
Add a LinkCheckAns command.
void SetAsDownlink()
State that this is a downlink message.
Helper for LoraPhy that manages interference calculations.
Time GetOverlapTime(Ptr< LoraInterferenceHelper::Event > event1, Ptr< LoraInterferenceHelper::Event > event2)
Compute the time duration in which two given events are overlapping.
Ptr< LoraInterferenceHelper::Event > Add(Time duration, double rxPower, uint8_t spreadingFactor, Ptr< Packet > packet, uint32_t frequencyHz)
Add an event to the InterferenceHelper.
void ClearAllEvents()
Delete all events in the LoraInterferenceHelper.
uint8_t IsDestroyedByInterference(Ptr< LoraInterferenceHelper::Event > event)
Determine whether the event was destroyed by interference or not.
static Time GetOnAirTime(Ptr< Packet > packet, LoraTxParameters txParams)
Compute the time that a packet with certain characteristics will take to be transmitted.
Definition lora-phy.cc:156
This class represents the Mac header of a LoRaWAN packet.
void SetMajor(uint8_t major)
Set the major version of this header.
uint32_t Deserialize(Buffer::Iterator start) override
Deserialize the header.
uint8_t GetMType() const
Get the message type from the header.
void Serialize(Buffer::Iterator start) const override
Serialize the header.
void SetMType(enum MType mtype)
Set the message type.
uint8_t GetMajor() const
Get the major version from the header.
Helper class for configuring and installing the LorawanMac class on devices and gateways.
void SetDeviceType(enum DeviceType dt)
Set the kind of MAC this helper will create.
void SetRegion(enum Regions region)
Set the region in which the device is to operate.
Ptr< LorawanMac > Install(Ptr< Node > node, Ptr< NetDevice > device) const
Create the LorawanMac instance and connect it to a device.
void Send(Ptr< Packet > packet, LoraTxParameters txParams, uint32_t frequencyHz, double txPowerDbm) override
Instruct the PHY to send a packet according to some parameters.
#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 ",...
Ptr< T > CreateObject(Args &&... args)
Create an object by type, with varying number of constructor parameters.
Definition object.h:619
Ptr< T > Create(Ts &&... args)
Create class instances by constructors with varying numbers of arguments and return them by Ptr.
Definition ptr.h:436
#define NS_TEST_ASSERT_MSG_EQ(actual, limit, msg)
Test that an actual and expected (limit) value are equal and report and abort if not.
Definition test.h:134
#define NS_TEST_EXPECT_MSG_NE(actual, limit, msg)
Test that an actual and expected (limit) value are not equal and report if not.
Definition test.h:656
#define NS_TEST_EXPECT_MSG_EQ(actual, limit, msg)
Test that an actual and expected (limit) value are equal and report if not.
Definition test.h:241
#define NS_TEST_ASSERT_MSG_NE(actual, limit, msg)
Test that an actual and expected (limit) value are not equal and report and abort if not.
Definition test.h:554
#define NS_TEST_EXPECT_MSG_EQ_TOL(actual, limit, tol, msg)
Test that actual and expected (limit) values are equal to plus or minus some tolerance and report if ...
Definition test.h:500
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition nstime.h:1344
Time Hours(double value)
Construct a Time in the indicated unit.
Definition nstime.h:1320
static LorawanTestSuite lorawanTestSuite
Every class exported by the ns3 library is enclosed in the ns3 namespace.
Callback< R, Args... > MakeCallback(R(T::*memPtr)(Args...), OBJ objPtr)
Build Callbacks for class method members which take varying numbers of arguments and potentially retu...
Definition callback.h:684
Ptr< T1 > DynamicCast(const Ptr< T2 > &p)
Cast a Ptr.
Definition ptr.h:580
Structure to collect all parameters that are used to compute the duration of a packet (excluding payl...
Definition lora-phy.h:38
uint8_t codingRate
Code rate (obtained as 4/(codingRate+4))
Definition lora-phy.h:41
uint32_t nPreamble
Number of preamble symbols.
Definition lora-phy.h:43
uint32_t bandwidthHz
Bandwidth in Hz.
Definition lora-phy.h:42
bool headerDisabled
Whether to use implicit header mode.
Definition lora-phy.h:40
bool lowDataRateOptimizationEnabled
Whether low data rate optimization is enabled.
Definition lora-phy.h:45
bool crcEnabled
Whether Cyclic Redundancy Check (CRC) is enabled.
Definition lora-phy.h:44
uint8_t sf
Spreading Factor.
Definition lora-phy.h:39