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// An essential include is test.h
10#include "ns3/constant-position-mobility-model.h"
11#include "ns3/simulator.h"
12#include "ns3/test.h"
13
14// Include headers of classes to test
15#include "ns3/lorawan-module.h"
16
17using namespace ns3;
18using namespace lorawan;
19
20NS_LOG_COMPONENT_DEFINE("LorawanTestSuite");
21
22/**
23 * @ingroup lorawan
24 *
25 * It tests interference computations in a number of possible scenarios using the
26 * LoraInterferenceHelper class
27 */
29{
30 public:
31 InterferenceTest(); //!< Default constructor
32 ~InterferenceTest() override; //!< Destructor
33
34 private:
35 void DoRun() override;
36};
37
38// Add some help text to this case to describe what it is intended to test
40 : TestCase("Verify that LoraInterferenceHelper works as expected")
41{
42}
43
44// Reminder that the test case should clean up after itself
48
49// This method is the pure virtual method from class TestCase that every
50// TestCase must implement
51void
53{
54 NS_LOG_DEBUG("InterferenceTest");
55
56 LoraInterferenceHelper interferenceHelper;
57
58 uint32_t frequencyHz = 868100000;
59 uint32_t differentFrequencyHz = 868300000;
60
63
64 // Test overlap duration
65 event = interferenceHelper.Add(Seconds(2), 14, 7, nullptr, frequencyHz);
66 event1 = interferenceHelper.Add(Seconds(1), 14, 12, nullptr, frequencyHz);
67 NS_TEST_EXPECT_MSG_EQ(interferenceHelper.GetOverlapTime(event, event1),
68 Seconds(1),
69 "Overlap computation didn't give the expected result");
70 interferenceHelper.ClearAllEvents();
71
72 event = interferenceHelper.Add(Seconds(2), 14, 7, nullptr, frequencyHz);
73 event1 = interferenceHelper.Add(Seconds(1.5), 14, 12, nullptr, frequencyHz);
74 NS_TEST_EXPECT_MSG_EQ(interferenceHelper.GetOverlapTime(event, event1),
75 Seconds(1.5),
76 "Overlap computation didn't give the expected result");
77 interferenceHelper.ClearAllEvents();
78
79 event = interferenceHelper.Add(Seconds(2), 14, 7, nullptr, frequencyHz);
80 event1 = interferenceHelper.Add(Seconds(3), 14, 12, nullptr, frequencyHz);
81 NS_TEST_EXPECT_MSG_EQ(interferenceHelper.GetOverlapTime(event, event1),
82 Seconds(2),
83 "Overlap computation didn't give the expected result");
84 interferenceHelper.ClearAllEvents();
85
86 event = interferenceHelper.Add(Seconds(2), 14, 7, nullptr, frequencyHz);
87 event1 = interferenceHelper.Add(Seconds(2), 14, 12, nullptr, frequencyHz);
88 // Because of some strange behavior, this test would get stuck if we used the same syntax of the
89 // previous ones. This works instead.
90 bool retval = interferenceHelper.GetOverlapTime(event, event1) == Seconds(2);
91 NS_TEST_EXPECT_MSG_EQ(retval, true, "Overlap computation didn't give the expected result");
92 interferenceHelper.ClearAllEvents();
93
94 // Perfect overlap, packet survives
95 event = interferenceHelper.Add(Seconds(2), 14, 7, nullptr, frequencyHz);
96 interferenceHelper.Add(Seconds(2), 14, 12, nullptr, frequencyHz);
97 NS_TEST_EXPECT_MSG_EQ(interferenceHelper.IsDestroyedByInterference(event),
98 0,
99 "Packet did not survive interference as expected");
100 interferenceHelper.ClearAllEvents();
101
102 // Perfect overlap, packet survives
103 event = interferenceHelper.Add(Seconds(2), 14, 7, nullptr, frequencyHz);
104 interferenceHelper.Add(Seconds(2), 14 - 7, 7, nullptr, frequencyHz);
105 NS_TEST_EXPECT_MSG_EQ(interferenceHelper.IsDestroyedByInterference(event),
106 0,
107 "Packet did not survive interference as expected");
108 interferenceHelper.ClearAllEvents();
109
110 // Perfect overlap, packet destroyed
111 event = interferenceHelper.Add(Seconds(2), 14, 7, nullptr, frequencyHz);
112 interferenceHelper.Add(Seconds(2), 14 - 6, 7, nullptr, frequencyHz);
113 NS_TEST_EXPECT_MSG_EQ(interferenceHelper.IsDestroyedByInterference(event),
114 7,
115 "Packet was not destroyed by interference as expected");
116 interferenceHelper.ClearAllEvents();
117
118 // Partial overlap, packet survives
119 event = interferenceHelper.Add(Seconds(2), 14, 7, nullptr, frequencyHz);
120 interferenceHelper.Add(Seconds(1), 14 - 6, 7, nullptr, frequencyHz);
121 NS_TEST_EXPECT_MSG_EQ(interferenceHelper.IsDestroyedByInterference(event),
122 0,
123 "Packet did not survive interference as expected");
124 interferenceHelper.ClearAllEvents();
125
126 // Different frequencys
127 // Packet would be destroyed if they were on the same frequency, but survives
128 // since they are on different frequencies
129 event = interferenceHelper.Add(Seconds(2), 14, 7, nullptr, frequencyHz);
130 interferenceHelper.Add(Seconds(2), 14, 7, nullptr, differentFrequencyHz);
131 NS_TEST_EXPECT_MSG_EQ(interferenceHelper.IsDestroyedByInterference(event),
132 0,
133 "Packet did not survive interference as expected");
134 interferenceHelper.ClearAllEvents();
135
136 // Different SFs
137 // Packet would be destroyed if they both were SF7, but survives thanks to spreading factor
138 // semi-orthogonality
139 event = interferenceHelper.Add(Seconds(2), 14, 7, nullptr, frequencyHz);
140 interferenceHelper.Add(Seconds(2), 14 + 16, 8, nullptr, frequencyHz);
141 NS_TEST_EXPECT_MSG_EQ(interferenceHelper.IsDestroyedByInterference(event),
142 0,
143 "Packet did not survive interference as expected");
144 interferenceHelper.ClearAllEvents();
145
146 // Spreading factor imperfect orthogonality
147 // Different SFs are orthogonal only up to a point
148 event = interferenceHelper.Add(Seconds(2), 14, 7, nullptr, frequencyHz);
149 interferenceHelper.Add(Seconds(2), 14 + 17, 8, nullptr, frequencyHz);
150 NS_TEST_EXPECT_MSG_EQ(interferenceHelper.IsDestroyedByInterference(event),
151 8,
152 "Packet was not destroyed by interference as expected");
153 interferenceHelper.ClearAllEvents();
154
155 // If a more 'distant' spreading factor is used, isolation gets better
156 event = interferenceHelper.Add(Seconds(2), 14, 7, nullptr, frequencyHz);
157 interferenceHelper.Add(Seconds(2), 14 + 17, 10, nullptr, frequencyHz);
158 NS_TEST_EXPECT_MSG_EQ(interferenceHelper.IsDestroyedByInterference(event),
159 0,
160 "Packet was destroyed by interference while it should have survived");
161 interferenceHelper.ClearAllEvents();
162
163 // Cumulative interference
164 // Same spreading factor interference is cumulative
165 event = interferenceHelper.Add(Seconds(2), 14, 7, nullptr, frequencyHz);
166 interferenceHelper.Add(Seconds(2), 14 + 16, 8, nullptr, frequencyHz);
167 interferenceHelper.Add(Seconds(2), 14 + 16, 8, nullptr, frequencyHz);
168 interferenceHelper.Add(Seconds(2), 14 + 16, 8, nullptr, frequencyHz);
169 NS_TEST_EXPECT_MSG_EQ(interferenceHelper.IsDestroyedByInterference(event),
170 8,
171 "Packet was not destroyed by interference as expected");
172 interferenceHelper.ClearAllEvents();
173
174 // Cumulative interference
175 // Interference is not cumulative between different SFs
176 event = interferenceHelper.Add(Seconds(2), 14, 7, nullptr, frequencyHz);
177 interferenceHelper.Add(Seconds(2), 14 + 16, 8, nullptr, frequencyHz);
178 interferenceHelper.Add(Seconds(2), 14 + 16, 9, nullptr, frequencyHz);
179 interferenceHelper.Add(Seconds(2), 14 + 16, 10, nullptr, frequencyHz);
180 NS_TEST_EXPECT_MSG_EQ(interferenceHelper.IsDestroyedByInterference(event),
181 0,
182 "Packet did not survive interference as expected");
183 interferenceHelper.ClearAllEvents();
184}
185
186/**
187 * @ingroup lorawan
188 *
189 * It tests LoraDeviceAddress comparison operators overrides and generation of new addresses with
190 * LoraDeviceAddressGenerator
191 */
192class AddressTest : public TestCase
193{
194 public:
195 AddressTest(); //!< Default constructor
196 ~AddressTest() override; //!< Destructor
197
198 private:
199 void DoRun() override;
200};
201
202// Add some help text to this case to describe what it is intended to test
204 : TestCase("Verify that LoraDeviceAddress works as expected")
205{
206}
207
208// Reminder that the test case should clean up after itself
212
213// This method is the pure virtual method from class TestCase that every
214// TestCase must implement
215void
217{
218 NS_LOG_DEBUG("AddressTest");
219
220 //////////////////////////////////////
221 // Test the LoraDeviceAddress class //
222 //////////////////////////////////////
223
224 // Address equality
225 LoraDeviceAddress firstAddress(0xFFFFFFFF);
226 LoraDeviceAddress secondAddress(0xFFFFFFFF);
227 NS_TEST_EXPECT_MSG_EQ((firstAddress == secondAddress), true, "Addresses don't match");
228
229 // Address ordering
230 LoraDeviceAddress bigAddress(0xFFFFFF00);
231 LoraDeviceAddress smallAddress(0xFFF00000);
232 NS_TEST_EXPECT_MSG_EQ((bigAddress > smallAddress),
233 true,
234 "> function for addresses doesn't work correctly");
235
236 // Setting and getting
237 LoraDeviceAddress referenceAddress(0xFFFFFFFF);
238 LoraDeviceAddress address(0x00000000);
239 NS_TEST_EXPECT_MSG_EQ((address != referenceAddress), true, "Different addresses match!");
240 address.SetNwkAddr(0xFFFFFFF);
241 address.SetNwkID(0b1111111);
242 NS_TEST_EXPECT_MSG_EQ((address == referenceAddress),
243 true,
244 "Addresses set to be equal don't match");
245
246 // Serialization and deserialization
247 uint8_t buffer[4];
248 LoraDeviceAddress toSerialize(0x0F0F0F0F);
249 toSerialize.Serialize(buffer);
251 NS_TEST_EXPECT_MSG_EQ((toSerialize == deserialized),
252 true,
253 "Serialization + Deserialization doesn't yield an equal address");
254
255 ///////////////////////////////////
256 // Test the address generator class
257 ///////////////////////////////////
258
259 LoraDeviceAddressGenerator addressGenerator;
260 for (int i = 0; i < 200; i++)
261 {
262 addressGenerator.NextAddress();
263 }
264 // After 200 iterations, the address should be 0xC9
265 NS_TEST_EXPECT_MSG_EQ((addressGenerator.GetNextAddress() == LoraDeviceAddress(0xC9)),
266 true,
267 "LoraDeviceAddressGenerator doesn't increment as expected");
268}
269
270/**
271 * @ingroup lorawan
272 *
273 * It tests serialization/deserialization of LoRaWAN headers (the LorawanMacHeader and
274 * LoraFrameHeader classes) on packets
275 */
276class HeaderTest : public TestCase
277{
278 public:
279 HeaderTest(); //!< Default constructor
280 ~HeaderTest() override; //!< Destructor
281
282 private:
283 void DoRun() override;
284};
285
286// Add some help text to this case to describe what it is intended to test
288 : TestCase("Verify that LorawanMacHeader and LoraFrameHeader work as expected")
289{
290}
291
292// Reminder that the test case should clean up after itself
296
297// This method is the pure virtual method from class TestCase that every
298// TestCase must implement
299void
301{
302 NS_LOG_DEBUG("HeaderTest");
303
304 //////////////////////////////////
305 // Test the LorawanMacHeader class //
306 //////////////////////////////////
307 LorawanMacHeader macHdr;
309 macHdr.SetMajor(1);
310
311 Buffer macBuf;
312 macBuf.AddAtStart(100);
313 Buffer::Iterator macSerialized = macBuf.Begin();
314 macHdr.Serialize(macSerialized);
315
316 macHdr.Deserialize(macSerialized);
317
319 true,
320 "FType changes in the serialization/deserialization process");
321 NS_TEST_EXPECT_MSG_EQ((macHdr.GetMajor() == 1),
322 true,
323 "FType changes in the serialization/deserialization process");
324
325 ////////////////////////////////////
326 // Test the LoraFrameHeader class //
327 ////////////////////////////////////
328 LoraFrameHeader frameHdr;
329 frameHdr.SetAsDownlink();
330 frameHdr.SetAck(true);
331 frameHdr.SetAdr(false);
332 frameHdr.SetFCnt(1);
333 frameHdr.SetAddress(LoraDeviceAddress(56, 1864));
334 frameHdr.AddLinkCheckAns(10, 1);
335
336 // Serialization
337 Buffer buf;
338 buf.AddAtStart(100);
339 Buffer::Iterator serialized = buf.Begin();
340 frameHdr.Serialize(serialized);
341
342 // Deserialization
343 frameHdr.Deserialize(serialized);
344
345 Ptr<LinkCheckAns> command = DynamicCast<LinkCheckAns>(frameHdr.GetCommands().at(0));
346 uint8_t margin = command->GetMargin();
347 uint8_t gwCnt = command->GetGwCnt();
348
349 NS_TEST_EXPECT_MSG_EQ(frameHdr.GetAck(),
350 true,
351 "ACK bit changes in the serialization/deserialization process");
352 NS_TEST_EXPECT_MSG_EQ(frameHdr.GetAdr(),
353 false,
354 "ADR bit changes in the serialization/deserialization process");
356 1,
357 "FCnt changes in the serialization/deserialization process");
358 NS_TEST_EXPECT_MSG_EQ((frameHdr.GetAddress() == LoraDeviceAddress(56, 1864)),
359 true,
360 "Address changes in the serialization/deserialization process");
362 10,
363 "Margin changes in the serialization/deserialization process");
364 NS_TEST_EXPECT_MSG_EQ(gwCnt, 1, "GwCnt changes in the serialization/deserialization process");
365
366 /////////////////////////////////////////////////
367 // Test a combination of the two above classes //
368 /////////////////////////////////////////////////
369 Ptr<Packet> pkt = Create<Packet>(10);
370 pkt->AddHeader(frameHdr);
371 pkt->AddHeader(macHdr);
372
373 // Length = Payload + FrameHeader + MacHeader
374 // = 10 + (8+3) + 1 = 22
375 NS_TEST_EXPECT_MSG_EQ((pkt->GetSize()), 22, "Wrong size of packet + headers");
376
377 LorawanMacHeader macHdr1;
378
379 pkt->RemoveHeader(macHdr1);
380
381 NS_TEST_EXPECT_MSG_EQ((pkt->GetSize()), 21, "Wrong size of packet + headers - macHeader");
382
383 LoraFrameHeader frameHdr1;
384 frameHdr1.SetAsDownlink();
385
386 pkt->RemoveHeader(frameHdr1);
387 Ptr<LinkCheckAns> linkCheckAns = DynamicCast<LinkCheckAns>(frameHdr1.GetCommands().at(0));
388
389 NS_TEST_EXPECT_MSG_EQ((pkt->GetSize()),
390 10,
391 "Wrong size of packet + headers - macHeader - frameHeader");
392
393 // Verify contents of removed MAC header
395 macHdr.GetFType(),
396 "Removed header contents don't match");
398 macHdr.GetMajor(),
399 "Removed header contents don't match");
400
401 // Verify contents of removed frame header
402 NS_TEST_EXPECT_MSG_EQ(frameHdr1.GetAck(),
403 frameHdr.GetAck(),
404 "Removed header contents don't match");
405 NS_TEST_EXPECT_MSG_EQ(frameHdr1.GetAdr(),
406 frameHdr.GetAdr(),
407 "Removed header contents don't match");
408 NS_TEST_EXPECT_MSG_EQ(frameHdr1.GetFCnt(),
409 frameHdr.GetFCnt(),
410 "Removed header contents don't match");
411 NS_TEST_EXPECT_MSG_EQ((frameHdr1.GetAddress() == frameHdr.GetAddress()),
412 true,
413 "Removed header contents don't match");
414 NS_TEST_EXPECT_MSG_EQ(linkCheckAns->GetMargin(),
415 10,
416 "Removed header's MAC command contents don't match");
417 NS_TEST_EXPECT_MSG_EQ(linkCheckAns->GetGwCnt(),
418 1,
419 "Removed header's MAC command contents don't match");
420}
421
422/**
423 * @ingroup lorawan
424 *
425 * It tests a number of cases related to SimpleGatewayLoraPhy's parallel reception paths
426 */
428{
429 public:
430 ReceivePathTest(); //!< Default constructor
431 ~ReceivePathTest() override; //!< Destructor
432
433 private:
434 void DoRun() override;
435 /**
436 * Reset counters and gateway PHY for new sub test case.
437 *
438 * @param rxPathNb Number of reception paths to be created on the gateway PHY
439 */
440 void Reset(uint8_t rxPathNb);
441 /**
442 * Callback for tracing OccupiedReceptionPaths.
443 *
444 * @param oldValue The old value.
445 * @param newValue The new value.
446 */
447 void OccupiedReceptionPaths(int oldValue, int newValue);
448 /**
449 * Callback for tracing LostPacketBecauseNoMoreReceivers.
450 *
451 * @param packet The packet lost.
452 * @param node The receiver node id if any, 0 otherwise.
453 */
455 /**
456 * Callback for tracing LostPacketBecauseInterference.
457 *
458 * @param packet The packet lost.
459 * @param node The receiver node id if any, 0 otherwise.
460 */
461 void Interference(Ptr<const Packet> packet, uint32_t node);
462 /**
463 * Callback for tracing ReceivedPacket.
464 *
465 * @param packet The packet received.
466 * @param node The receiver node id if any, 0 otherwise.
467 */
468 void ReceivedPacket(Ptr<const Packet> packet, uint32_t node);
469
470 Ptr<SimpleGatewayLoraPhy> gatewayPhy; //!< PHY layer of a gateway to be tested
471
472 int m_noMoreDemodulatorsCalls = 0; //!< Counter for LostPacketBecauseNoMoreReceivers calls
473 int m_interferenceCalls = 0; //!< Counter for LostPacketBecauseInterference calls
474 int m_receivedPacketCalls = 0; //!< Counter for ReceivedPacket calls
475 int m_maxOccupiedReceptionPaths = 0; //!< Max number of concurrent OccupiedReceptionPaths
476};
477
478// Add some help text to this case to describe what it is intended to test
480 : TestCase("Verify that ReceivePaths work as expected")
481{
482}
483
484// Reminder that the test case should clean up after itself
488
489void
490ReceivePathTest::Reset(uint8_t rxPathNb)
491{
496
497 // The following tests are designed around GOURSAUD signal-to-interference matrix
499
501
502 gatewayPhy->AddFrequency(868'100'000);
503 gatewayPhy->AddFrequency(868'300'000);
504 gatewayPhy->AddFrequency(868'500'000);
505
506 for (uint8_t i = 0; i < rxPathNb; i++)
507 {
508 gatewayPhy->AddReceptionPath();
509 }
510
511 // From GatewayLoraPhy
512 gatewayPhy->TraceConnectWithoutContext(
513 "LostPacketBecauseNoMoreReceivers",
515 gatewayPhy->TraceConnectWithoutContext(
516 "OccupiedReceptionPaths",
518
519 // From LoraPhy
520 gatewayPhy->TraceConnectWithoutContext("LostPacketBecauseInterference",
522 gatewayPhy->TraceConnectWithoutContext("ReceivedPacket",
524}
525
526void
528{
529 NS_LOG_FUNCTION(oldValue << newValue);
530
531 if (m_maxOccupiedReceptionPaths < newValue)
532 {
534 }
535}
536
537void
544
545void
552
553void
560
561// This method is the pure virtual method from class TestCase that every
562// TestCase must implement
563void
565{
566 NS_LOG_DEBUG("ReceivePathTest");
567
568 Ptr<Packet> packet = Create<Packet>();
569
570 ///////////////////////////////////////////////////////////
571 // If no ReceptionPath is configured, no packet is received
572 ///////////////////////////////////////////////////////////
573
574 Reset(0);
575
579 packet,
580 868'100'000,
582 7,
583 14,
584 Seconds(1));
585
589
590 NS_TEST_EXPECT_MSG_EQ(m_noMoreDemodulatorsCalls, 1, "Unexpected value");
591
592 //////////////////////////////////////////////////////////////////////////////
593 // A ReceptionPath can receive a packet of any SF without any preconfiguration
594 //////////////////////////////////////////////////////////////////////////////
595
596 Reset(1);
597
601 packet,
602 868'100'000,
604 7,
605 14,
606 Seconds(1));
610 packet,
611 868'100'000,
613 8,
614 14,
615 Seconds(1));
619 packet,
620 868'100'000,
622 9,
623 14,
624 Seconds(1));
628 packet,
629 868'100'000,
631 10,
632 14,
633 Seconds(1));
637 packet,
638 868'100'000,
640 11,
641 14,
642 Seconds(1));
646 packet,
647 868'100'000,
649 12,
650 14,
651 Seconds(1));
652
656
657 NS_TEST_EXPECT_MSG_EQ(m_noMoreDemodulatorsCalls, 0, "Unexpected value");
658 NS_TEST_EXPECT_MSG_EQ(m_receivedPacketCalls, 6, "Unexpected value");
659
660 ///////////////////////////////////////////////////////////////////////////////////////
661 // Schedule two overlapping reception events. Each packet should be received correctly.
662 ///////////////////////////////////////////////////////////////////////////////////////
663
664 Reset(2);
665
669 packet,
670 868'100'000,
672 7,
673 14,
674 Seconds(4));
678 packet,
679 868'100'000,
681 9,
682 14,
683 Seconds(4));
684
688
689 NS_TEST_EXPECT_MSG_EQ(m_noMoreDemodulatorsCalls, 0, "Unexpected value");
690 NS_TEST_EXPECT_MSG_EQ(m_receivedPacketCalls, 2, "Unexpected value");
692
693 //////////////////////////////////////////////////////////////////////////////////
694 // Interference between packets on the same frequency and different ReceptionPaths
695 //////////////////////////////////////////////////////////////////////////////////
696
697 Reset(2);
698
702 packet,
703 868'100'000,
705 7,
706 14,
707 Seconds(4));
711 packet,
712 868'100'000,
714 7,
715 14,
716 Seconds(4));
717
721
722 NS_TEST_EXPECT_MSG_EQ(m_noMoreDemodulatorsCalls, 0, "Unexpected value");
723 NS_TEST_EXPECT_MSG_EQ(m_interferenceCalls, 2, "Unexpected value");
724
725 /////////////////////////////////////////////////////////////
726 // Three receptions where only two receivePaths are available
727 /////////////////////////////////////////////////////////////
728
729 Reset(2);
730
734 packet,
735 868'100'000,
737 7,
738 14,
739 Seconds(4));
743 packet,
744 868'100'000,
746 7,
747 14,
748 Seconds(4));
752 packet,
753 868'100'000,
755 7,
756 14,
757 Seconds(4));
758
762
763 NS_TEST_EXPECT_MSG_EQ(m_noMoreDemodulatorsCalls, 1, "Unexpected value");
764
765 ///////////////////////////////////////////////////////////////////////////
766 // Packets that are on different frequencys do not interfere
767 ///////////////////////////////////////////////////////////////////////////
768
769 Reset(2);
770
774 packet,
775 868'100'000,
777 7,
778 14,
779 Seconds(4));
783 packet,
784 868'300'000,
786 7,
787 14,
788 Seconds(4));
789
793
794 NS_TEST_EXPECT_MSG_EQ(m_interferenceCalls, 0, "Unexpected value");
795
796 ///////////////////////////////////////////////////////////////////////////
797 // Full capacity (siw packets, on six SFs, distributed over 3 frequencies)
798 ///////////////////////////////////////////////////////////////////////////
799
800 Reset(6);
801
805 packet,
806 868'100'000,
808 7,
809 14,
810 Seconds(4));
814 packet,
815 868'100'000,
817 8,
818 14,
819 Seconds(4));
823 packet,
824 868'300'000,
826 9,
827 14,
828 Seconds(4));
832 packet,
833 868'300'000,
835 10,
836 14,
837 Seconds(4));
841 packet,
842 868'500'000,
844 11,
845 14,
846 Seconds(4));
850 packet,
851 868'500'000,
853 12,
854 14,
855 Seconds(4));
856
860
861 NS_TEST_EXPECT_MSG_EQ(m_noMoreDemodulatorsCalls, 0, "Unexpected value");
862 NS_TEST_EXPECT_MSG_EQ(m_interferenceCalls, 0, "Unexpected value");
863 NS_TEST_EXPECT_MSG_EQ(m_receivedPacketCalls, 6, "Unexpected value");
864
865 ///////////////////////////////////////////////////////////////////////////
866 // Full capacity + 1
867 ///////////////////////////////////////////////////////////////////////////
868
869 Reset(6);
870
874 packet,
875 868'100'000,
877 7,
878 14,
879 Seconds(4));
883 packet,
884 868'100'000,
886 8,
887 14,
888 Seconds(4));
892 packet,
893 868'300'000,
895 9,
896 14,
897 Seconds(4));
901 packet,
902 868'300'000,
904 10,
905 14,
906 Seconds(4));
910 packet,
911 868'500'000,
913 11,
914 14,
915 Seconds(4));
919 packet,
920 868'500'000,
922 12,
923 14,
924 Seconds(4));
928 packet,
929 868'500'000,
931 10,
932 14,
933 Seconds(4));
934
938
939 NS_TEST_EXPECT_MSG_EQ(m_noMoreDemodulatorsCalls, 1, "Unexpected value");
940 NS_TEST_EXPECT_MSG_EQ(m_interferenceCalls, 0, "Unexpected value");
941 NS_TEST_EXPECT_MSG_EQ(m_receivedPacketCalls, 6, "Unexpected value");
942
943 ////////////////////////////////////
944 // Receive Paths are correctly freed
945 ////////////////////////////////////
946
947 Reset(6);
948
952 packet,
953 868'100'000,
955 7,
956 14,
957 Seconds(4));
961 packet,
962 868'100'000,
964 8,
965 14,
966 Seconds(4));
970 packet,
971 868'300'000,
973 9,
974 14,
975 Seconds(4));
979 packet,
980 868'300'000,
982 10,
983 14,
984 Seconds(4));
988 packet,
989 868'500'000,
991 11,
992 14,
993 Seconds(4));
997 packet,
998 868'500'000,
1000 12,
1001 14,
1002 Seconds(4));
1003
1006 gatewayPhy,
1007 packet,
1008 868'100'000,
1010 7,
1011 14,
1012 Seconds(4));
1015 gatewayPhy,
1016 packet,
1017 868'100'000,
1019 8,
1020 14,
1021 Seconds(4));
1024 gatewayPhy,
1025 packet,
1026 868'300'000,
1028 9,
1029 14,
1030 Seconds(4));
1033 gatewayPhy,
1034 packet,
1035 868'300'000,
1037 10,
1038 14,
1039 Seconds(4));
1042 gatewayPhy,
1043 packet,
1044 868'500'000,
1046 11,
1047 14,
1048 Seconds(4));
1051 gatewayPhy,
1052 packet,
1053 868'500'000,
1055 12,
1056 14,
1057 Seconds(4));
1058
1062
1063 NS_TEST_EXPECT_MSG_EQ(m_noMoreDemodulatorsCalls, 0, "Unexpected value");
1064 NS_TEST_EXPECT_MSG_EQ(m_interferenceCalls, 0, "Unexpected value");
1065 NS_TEST_EXPECT_MSG_EQ(m_receivedPacketCalls, 12, "Unexpected value");
1066
1067 /////////////////////////////////////////////////////////////
1068 // Receive Paths stay occupied exactly for the necessary time
1069 /////////////////////////////////////////////////////////////
1070
1071 Reset(2);
1072
1075 gatewayPhy,
1076 packet,
1077 868'100'000,
1079 7,
1080 14,
1081 Seconds(4));
1084 gatewayPhy,
1085 packet,
1086 868'100'000,
1088 8,
1089 14,
1090 Seconds(4));
1091
1092 // This packet will find no free ReceptionPaths
1095 gatewayPhy,
1096 packet,
1097 868'100'000,
1099 9,
1100 14,
1101 Seconds(4));
1102
1103 // This packet will find a free ReceptionPath
1106 gatewayPhy,
1107 packet,
1108 868'100'000,
1110 10,
1111 14,
1112 Seconds(4));
1113
1117
1118 NS_TEST_EXPECT_MSG_EQ(m_noMoreDemodulatorsCalls, 1, "Unexpected value");
1119 NS_TEST_EXPECT_MSG_EQ(m_interferenceCalls, 0, "Unexpected value");
1120 NS_TEST_EXPECT_MSG_EQ(m_receivedPacketCalls, 3, "Unexpected value");
1121
1122 ////////////////////////////////////////////////////
1123 // Only one ReceivePath locks on the incoming packet
1124 ////////////////////////////////////////////////////
1125
1126 Reset(6);
1127
1130 gatewayPhy,
1131 packet,
1132 868'100'000,
1134 7,
1135 14,
1136 Seconds(4));
1137
1141
1142 NS_TEST_EXPECT_MSG_EQ(m_noMoreDemodulatorsCalls, 0, "Unexpected value");
1143 NS_TEST_EXPECT_MSG_EQ(m_interferenceCalls, 0, "Unexpected value");
1144 NS_TEST_EXPECT_MSG_EQ(m_receivedPacketCalls, 1, "Unexpected value");
1145 NS_TEST_EXPECT_MSG_EQ(m_maxOccupiedReceptionPaths, 1, "Unexpected value");
1146}
1147
1148/**
1149 * @ingroup lorawan
1150 *
1151 * It tests functionality of the LogicalLoraChannel, SubBand and LogicalLoraChannelHelper classes
1152 */
1154{
1155 public:
1156 LogicalLoraChannelTest(); //!< Default constructor
1157 ~LogicalLoraChannelTest() override; //!< Destructor
1158
1159 private:
1160 void DoRun() override;
1161};
1162
1163// Add some help text to this case to describe what it is intended to test
1165 : TestCase("Verify that LogicalLoraChannel and LogicalLoraChannelHelper work as expected")
1166{
1167}
1168
1169// Reminder that the test case should clean up after itself
1173
1174// This method is the pure virtual method from class TestCase that every
1175// TestCase must implement
1176void
1178{
1179 NS_LOG_DEBUG("LogicalLoraChannelTest");
1180
1181 /////////////////////////////
1182 // Test LogicalLoraChannel //
1183 /////////////////////////////
1184
1185 // Setup
1186 Ptr<LogicalLoraChannel> channel1 = Create<LogicalLoraChannel>(868000000, 0, 5);
1187 Ptr<LogicalLoraChannel> channel2 = Create<LogicalLoraChannel>(868000000, 0, 5);
1188 Ptr<LogicalLoraChannel> channel3 = Create<LogicalLoraChannel>(868100000, 0, 5);
1189 Ptr<LogicalLoraChannel> channel4 = Create<LogicalLoraChannel>(868001000, 0, 5);
1190
1191 // Equality between channels
1192 // Test the == and != operators
1193 NS_TEST_EXPECT_MSG_EQ(channel1, channel2, "== operator doesn't work as expected");
1194 NS_TEST_EXPECT_MSG_NE(channel1, channel3, "!= operator doesn't work as expected");
1195 NS_TEST_EXPECT_MSG_NE(channel1, channel4, "!= operator doesn't work as expected");
1196
1197 //////////////////
1198 // Test SubBand //
1199 //////////////////
1200 // Setup
1201
1202 auto subBand = Create<SubBand>(868000000, 868600000, 0.01, 14);
1203 Ptr<LogicalLoraChannel> channel5 = Create<LogicalLoraChannel>(870000000, 0, 5);
1204
1205 // Test Contains
1206 NS_TEST_EXPECT_MSG_EQ(subBand->Contains(channel3),
1207 true,
1208 "Contains does not behave as expected");
1209 NS_TEST_EXPECT_MSG_EQ(subBand->Contains(channel3->GetFrequency()),
1210 true,
1211 "Contains does not behave as expected");
1212 NS_TEST_EXPECT_MSG_EQ(subBand->Contains(channel5),
1213 false,
1214 "Contains does not behave as expected");
1215
1216 ///////////////////////////////////
1217 // Test LogicalLoraChannelHelper //
1218 ///////////////////////////////////
1219
1220 // Setup
1221 auto channelHelper = Create<LogicalLoraChannelHelper>(16);
1222 auto subBand1 = Create<SubBand>(869400000, 869650000, 0.10, 27);
1223 channel1 = Create<LogicalLoraChannel>(868100000, 0, 5);
1224 channel2 = Create<LogicalLoraChannel>(868300000, 0, 5);
1225 channel3 = Create<LogicalLoraChannel>(869525000, 0, 5);
1226
1227 // Channel diagram
1228 //
1229 // Channels 1 2 3
1230 // SubBands 868 ----- 1% ----- 868.6 869 ----- 10% ----- 869.4
1231
1232 // Add SubBands and LogicalLoraChannels to the helper
1233 channelHelper->AddSubBand(subBand);
1234 channelHelper->AddSubBand(subBand1);
1235 channelHelper->SetChannel(0, channel1);
1236 channelHelper->SetChannel(1, channel2);
1237 channelHelper->SetChannel(2, channel3);
1238
1239 // Duty Cycle tests
1240 // (high level duty cycle behavior)
1241 ///////////////////////////////////
1242
1243 channelHelper->AddEvent(Seconds(2), channel1);
1244 Time expectedTimeOff = Seconds(2 / 0.01);
1245
1246 // Wait time is computed correctly
1247 NS_TEST_EXPECT_MSG_EQ(channelHelper->GetWaitTime(channel1),
1248 expectedTimeOff,
1249 "Wait time doesn't behave as expected");
1250
1251 // Duty Cycle involves the whole SubBand, not just a channel
1252 NS_TEST_EXPECT_MSG_EQ(channelHelper->GetWaitTime(channel2),
1253 expectedTimeOff,
1254 "Wait time doesn't behave as expected");
1255
1256 // Other bands are not affected by this transmission
1257 NS_TEST_EXPECT_MSG_EQ(channelHelper->GetWaitTime(channel3),
1258 Time(0),
1259 "Wait time affects other subbands");
1260}
1261
1262/**
1263 * @ingroup lorawan
1264 *
1265 * It tests the correctness of the LoraPhy::GetTimeOnAir calculator against a number of pre-sourced
1266 * time values of known scenarios
1267 */
1269{
1270 public:
1271 TimeOnAirTest(); //!< Default constructor
1272 ~TimeOnAirTest() override; //!< Destructor
1273
1274 private:
1275 void DoRun() override;
1276};
1277
1278// Add some help text to this case to describe what it is intended to test
1280 : TestCase(
1281 "Verify that LoraPhy's function to compute the time on air of a packet works as expected")
1282{
1283}
1284
1285// Reminder that the test case should clean up after itself
1289
1290// This method is the pure virtual method from class TestCase that every
1291// TestCase must implement
1292void
1294{
1295 NS_LOG_DEBUG("TimeOnAirTest");
1296
1297 Ptr<Packet> packet;
1298 Time duration;
1299
1300 // Starting parameters
1301 packet = Create<Packet>(10);
1302 LoraTxParameters txParams;
1303 txParams.spreadingFactor = 7;
1304 txParams.bandwidthHz = 125'000;
1305 txParams.codingRate = CodingRate::CR_4_5;
1306 txParams.lowDataRateOptimize = false;
1307 txParams.preambleLenSymb = 8;
1308 txParams.implicitHeader = false;
1309 txParams.crcEnabled = true;
1310
1311 duration = LoraPhy::GetTimeOnAir(packet->GetSize(), txParams);
1312 NS_TEST_EXPECT_MSG_EQ_TOL(duration.GetSeconds(), 0.041216, 0.0001, "Unexpected duration");
1313
1314 txParams.spreadingFactor = 8;
1315 duration = LoraPhy::GetTimeOnAir(packet->GetSize(), txParams);
1316 NS_TEST_EXPECT_MSG_EQ_TOL(duration.GetSeconds(), 0.072192, 0.0001, "Unexpected duration");
1317
1318 txParams.implicitHeader = true;
1319 duration = LoraPhy::GetTimeOnAir(packet->GetSize(), txParams);
1320 NS_TEST_EXPECT_MSG_EQ_TOL(duration.GetSeconds(), 0.072192, 0.0001, "Unexpected duration");
1321
1322 txParams.codingRate = CodingRate::CR_4_6;
1323 duration = LoraPhy::GetTimeOnAir(packet->GetSize(), txParams);
1324 NS_TEST_EXPECT_MSG_EQ_TOL(duration.GetSeconds(), 0.078336, 0.0001, "Unexpected duration");
1325
1326 txParams.preambleLenSymb = 10;
1327 duration = LoraPhy::GetTimeOnAir(packet->GetSize(), txParams);
1328 NS_TEST_EXPECT_MSG_EQ_TOL(duration.GetSeconds(), 0.082432, 0.0001, "Unexpected duration");
1329
1330 txParams.lowDataRateOptimize = true;
1331 duration = LoraPhy::GetTimeOnAir(packet->GetSize(), txParams);
1332 NS_TEST_EXPECT_MSG_EQ_TOL(duration.GetSeconds(), 0.082432, 0.0001, "Unexpected duration");
1333
1334 txParams.spreadingFactor = 10;
1335 duration = LoraPhy::GetTimeOnAir(packet->GetSize(), txParams);
1336 NS_TEST_EXPECT_MSG_EQ_TOL(duration.GetSeconds(), 0.280576, 0.0001, "Unexpected duration");
1337
1338 txParams.bandwidthHz = 250000;
1339 duration = LoraPhy::GetTimeOnAir(packet->GetSize(), txParams);
1340 NS_TEST_EXPECT_MSG_EQ_TOL(duration.GetSeconds(), 0.14028, 0.0001, "Unexpected duration");
1341
1342 txParams.bandwidthHz = 500000;
1343 duration = LoraPhy::GetTimeOnAir(packet->GetSize(), txParams);
1344 NS_TEST_EXPECT_MSG_EQ_TOL(duration.GetSeconds(), 0.070144, 0.0001, "Unexpected duration");
1345
1346 txParams.implicitHeader = false;
1347 duration = LoraPhy::GetTimeOnAir(packet->GetSize(), txParams);
1348 NS_TEST_EXPECT_MSG_EQ_TOL(duration.GetSeconds(), 0.082432, 0.0001, "Unexpected duration");
1349
1350 txParams.preambleLenSymb = 8;
1351 duration = LoraPhy::GetTimeOnAir(packet->GetSize(), txParams);
1352 NS_TEST_EXPECT_MSG_EQ_TOL(duration.GetSeconds(), 0.078336, 0.0001, "Unexpected duration");
1353
1354 txParams.spreadingFactor = 12;
1355 duration = LoraPhy::GetTimeOnAir(packet->GetSize(), txParams);
1356 NS_TEST_EXPECT_MSG_EQ_TOL(duration.GetSeconds(), 0.264192, 0.0001, "Unexpected duration");
1357
1358 packet = Create<Packet>(50);
1359 duration = LoraPhy::GetTimeOnAir(packet->GetSize(), txParams);
1360 NS_TEST_EXPECT_MSG_EQ_TOL(duration.GetSeconds(), 0.657408, 0.0001, "Unexpected duration");
1361
1362 txParams.bandwidthHz = 125000;
1363 duration = LoraPhy::GetTimeOnAir(packet->GetSize(), txParams);
1364 NS_TEST_EXPECT_MSG_EQ_TOL(duration.GetSeconds(), 2.629632, 0.0001, "Unexpected duration");
1365
1366 txParams.codingRate = CodingRate::CR_4_5;
1367 duration = LoraPhy::GetTimeOnAir(packet->GetSize(), txParams);
1368 NS_TEST_EXPECT_MSG_EQ_TOL(duration.GetSeconds(), 2.301952, 0.0001, "Unexpected duration");
1369}
1370
1371/**
1372 * @ingroup lorawan
1373 *
1374 * It tests sending packets over a LoRa physical channel between multiple devices and the resulting
1375 * possible outcomes
1376 */
1378{
1379 public:
1380 PhyConnectivityTest(); //!< Default constructor
1381 ~PhyConnectivityTest() override; //!< Destructor
1382
1383 /**
1384 * Reset counters and end devices' PHYs for new sub test case.
1385 */
1386 void Reset();
1387
1388 /**
1389 * Callback for tracing ReceivedPacket.
1390 *
1391 * @param packet The packet received.
1392 * @param node The receiver node id if any, 0 otherwise.
1393 */
1394 void ReceivedPacket(Ptr<const Packet> packet, uint32_t node);
1395
1396 /**
1397 * Callback for tracing LostPacketBecauseUnderSensitivity.
1398 *
1399 * @param packet The packet lost.
1400 * @param node The receiver node id if any, 0 otherwise.
1401 */
1402 void UnderSensitivity(Ptr<const Packet> packet, uint32_t node);
1403
1404 /**
1405 * Callback for tracing LostPacketBecauseInterference.
1406 *
1407 * @param packet The packet lost.
1408 * @param node The receiver node id if any, 0 otherwise.
1409 */
1410 void Interference(Ptr<const Packet> packet, uint32_t node);
1411
1412 /**
1413 * Callback for tracing LostPacketBecauseWrongFrequency.
1414 *
1415 * @param packet The packet lost.
1416 * @param node The receiver node id if any, 0 otherwise.
1417 */
1418 void WrongFrequency(Ptr<const Packet> packet, uint32_t node);
1419
1420 /**
1421 * Callback for tracing LostPacketBecauseWrongSpreadingFactor.
1422 *
1423 * @param packet The packet lost.
1424 * @param node The receiver node id if any, 0 otherwise.
1425 */
1426 void WrongSf(Ptr<const Packet> packet, uint32_t node);
1427
1428 /**
1429 * Compare two packets to check if they are equal.
1430 *
1431 * @param packet1 A first packet.
1432 * @param packet2 A second packet.
1433 * @return True if their unique identifiers are equal,
1434 * @return false otherwise.
1435 */
1436 bool IsSamePacket(Ptr<Packet> packet1, Ptr<Packet> packet2);
1437
1438 private:
1439 void DoRun() override;
1440
1441 Ptr<LoraChannel> channel; //!< The LoRa channel used for tests
1442 Ptr<SimpleEndDeviceLoraPhy> edPhy1; //!< The first end device's PHY layer used in tests
1443 Ptr<SimpleEndDeviceLoraPhy> edPhy2; //!< The second end device's PHY layer used in tests
1444 Ptr<SimpleEndDeviceLoraPhy> edPhy3; //!< The third end device's PHY layer used in tests
1445
1446 Ptr<Packet> m_latestReceivedPacket; //!< Pointer to track the last received packet
1447 int m_receivedPacketCalls = 0; //!< Counter for ReceivedPacket calls
1448 int m_underSensitivityCalls = 0; //!< Counter for LostPacketBecauseUnderSensitivity calls
1449 int m_interferenceCalls = 0; //!< Counter for LostPacketBecauseInterference calls
1450 int m_wrongSfCalls = 0; //!< Counter for LostPacketBecauseWrongSpreadingFactor calls
1451 int m_wrongFrequencyCalls = 0; //!< Counter for LostPacketBecauseWrongFrequency calls
1452};
1453
1454// Add some help text to this case to describe what it is intended to test
1456 : TestCase("Verify that PhyConnectivity works as expected")
1457{
1458}
1459
1460// Reminder that the test case should clean up after itself
1464
1465void
1467{
1468 NS_LOG_FUNCTION(packet << node);
1469
1471
1472 m_latestReceivedPacket = packet->Copy();
1473}
1474
1475void
1482
1483void
1485{
1486 NS_LOG_FUNCTION(packet << node);
1487
1489}
1490
1491void
1493{
1494 NS_LOG_FUNCTION(packet << node);
1495
1497}
1498
1499void
1506
1507bool
1509{
1510 return packet1->GetUid() == packet2->GetUid();
1511}
1512
1513void
1515{
1519 m_wrongSfCalls = 0;
1521
1523 loss->SetPathLossExponent(3.76);
1524 loss->SetReference(1, 7.7);
1525
1527
1528 // Create the channel
1529 channel = CreateObject<LoraChannel>(loss, delay);
1530
1531 // Connect PHYs
1535
1539
1540 mob1->SetPosition(Vector(0.0, 0.0, 0.0));
1541 mob2->SetPosition(Vector(10.0, 0.0, 0.0));
1542 mob3->SetPosition(Vector(20.0, 0.0, 0.0));
1543
1544 edPhy1->SetMobility(mob1);
1545 edPhy2->SetMobility(mob2);
1546 edPhy3->SetMobility(mob3);
1547
1548 channel->Add(edPhy1);
1549 channel->Add(edPhy2);
1550 channel->Add(edPhy3);
1551
1552 edPhy1->SetChannel(channel);
1553 edPhy2->SetChannel(channel);
1554 edPhy3->SetChannel(channel);
1555
1556 edPhy1->TraceConnectWithoutContext("ReceivedPacket",
1558 edPhy2->TraceConnectWithoutContext("ReceivedPacket",
1560 edPhy3->TraceConnectWithoutContext("ReceivedPacket",
1562
1563 edPhy1->TraceConnectWithoutContext("LostPacketBecauseUnderSensitivity",
1565 edPhy2->TraceConnectWithoutContext("LostPacketBecauseUnderSensitivity",
1567 edPhy3->TraceConnectWithoutContext("LostPacketBecauseUnderSensitivity",
1569
1570 edPhy1->TraceConnectWithoutContext("LostPacketBecauseInterference",
1572 edPhy2->TraceConnectWithoutContext("LostPacketBecauseInterference",
1574 edPhy3->TraceConnectWithoutContext("LostPacketBecauseInterference",
1576
1577 edPhy1->TraceConnectWithoutContext("LostPacketBecauseWrongFrequency",
1579 edPhy2->TraceConnectWithoutContext("LostPacketBecauseWrongFrequency",
1581 edPhy3->TraceConnectWithoutContext("LostPacketBecauseWrongFrequency",
1583
1584 edPhy1->TraceConnectWithoutContext("LostPacketBecauseWrongSpreadingFactor",
1586 edPhy2->TraceConnectWithoutContext("LostPacketBecauseWrongSpreadingFactor",
1588 edPhy3->TraceConnectWithoutContext("LostPacketBecauseWrongSpreadingFactor",
1590}
1591
1592// This method is the pure virtual method from class TestCase that every
1593// TestCase must implement
1594void
1596{
1597 NS_LOG_DEBUG("PhyConnectivityTest");
1598
1599 // Setup
1600 ////////
1601
1602 uint8_t buffer[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
1603 Ptr<Packet> packet = Create<Packet>(buffer, 10);
1604
1605 LoraTxParameters txParams;
1606 txParams.spreadingFactor = 12;
1607 txParams.bandwidthHz = 125'000;
1608 txParams.codingRate = CodingRate::CR_4_5;
1609 txParams.lowDataRateOptimize = true;
1610 txParams.preambleLenSymb = 8;
1611 txParams.implicitHeader = false;
1612 txParams.crcEnabled = true;
1613
1614 Reset();
1615
1616 // Testing
1617 //////////
1618
1619 // Basic packet delivery test
1620 /////////////////////////////
1621
1624 edPhy1,
1625 868'100'000,
1627 txParams.spreadingFactor,
1628 txParams.bandwidthHz,
1629 8,
1631
1634 edPhy2,
1635 868'100'000,
1637 txParams.spreadingFactor,
1638 txParams.bandwidthHz,
1639 8,
1641
1644 edPhy3,
1645 packet,
1646 868'100'000,
1648 txParams,
1649 14);
1650
1654
1657 2,
1658 "Channel skipped some PHYs when delivering a packet"); // All PHYs except the sender
1659
1660 Reset();
1661
1662 // Sleeping PHYs do not receive the packet
1663
1664 edPhy1->Sleep();
1665
1668 edPhy2,
1669 868'100'000,
1671 txParams.spreadingFactor,
1672 txParams.bandwidthHz,
1673 8,
1675
1678 edPhy3,
1679 packet,
1680 868'100'000,
1682 txParams,
1683 14);
1684
1688
1691 1,
1692 "Packet was received by a PHY in SLEEP mode"); // All PHYs in Rx except the sender
1693
1694 Reset();
1695
1696 // Packet that arrives under sensitivity is received correctly if the spreading factor increases
1697
1698 txParams.spreadingFactor = 7;
1699
1701 ->SetPosition(Vector(2990, 0, 0));
1702
1705 edPhy1,
1706 868'100'000,
1708 txParams.spreadingFactor,
1709 txParams.bandwidthHz,
1710 8,
1712
1715 edPhy2,
1716 packet,
1717 868'100'000,
1719 txParams,
1720 14);
1721
1725
1728 1,
1729 "Packet that should have been lost because of low receive power was received");
1730
1731 Reset();
1732
1733 // Try again using a packet with higher spreading factor
1734 txParams.spreadingFactor = 8;
1735
1737 ->SetPosition(Vector(2990, 0, 0));
1738
1741 edPhy1,
1742 868'100'000,
1744 txParams.spreadingFactor,
1745 txParams.bandwidthHz,
1746 8,
1748
1751 edPhy2,
1752 packet,
1753 868'100'000,
1755 txParams,
1756 14);
1757
1761
1763 0,
1764 "Packets that should have arrived above sensitivity were under it");
1765
1766 Reset();
1767
1768 // Packets can be destroyed by interference
1769
1770 txParams.spreadingFactor = 12;
1771
1774 edPhy2,
1775 868'100'000,
1777 txParams.spreadingFactor,
1778 txParams.bandwidthHz,
1779 8,
1781
1784 edPhy1,
1785 packet,
1786 868'100'000,
1788 txParams,
1789 14);
1790
1793 edPhy3,
1794 packet,
1795 868'100'000,
1797 txParams,
1798 14);
1799
1803
1805 1,
1806 "Packets that should be destroyed by interference weren't");
1807
1808 Reset();
1809
1810 // Packets can be lost because the PHY is not listening on the right frequency
1811
1814 edPhy1,
1815 868'100'000,
1817 txParams.spreadingFactor,
1818 txParams.bandwidthHz,
1819 8,
1821
1824 edPhy2,
1825 packet,
1826 868'300'000,
1828 txParams,
1829 14);
1830
1834
1836 1,
1837 "Packets were received even though PHY was on a different frequency");
1838
1839 Reset();
1840
1841 // Packets can be lost because the PHY is not listening for the right spreading factor
1842
1843 txParams.spreadingFactor = 8; // Send with 8, listening for 12
1844
1847 edPhy1,
1848 868'100'000,
1850 12,
1851 txParams.bandwidthHz,
1852 8,
1854
1857 edPhy2,
1858 packet,
1859 868'100'000,
1861 txParams,
1862 14);
1863
1867
1870 1,
1871 "Packets were received even though PHY was listening for a different spreading factor.");
1872
1873 Reset();
1874
1875 // Sending of packets
1876 /////////////////////
1877
1878 // The very same packet arrives at the other PHY
1879
1882 edPhy1,
1883 868'100'000,
1885 txParams.spreadingFactor,
1886 txParams.bandwidthHz,
1887 8,
1889
1892 edPhy2,
1893 packet,
1894 868'100'000,
1896 txParams,
1897 14);
1898
1902
1904 true,
1905 "Packet changed contents when going through the channel");
1906
1907 Reset();
1908
1909 // Correct state transitions
1910 ////////////////////////////
1911
1912 // PHY switches to STANDBY after TX and RX
1913
1916 edPhy1,
1917 868'100'000,
1919 txParams.spreadingFactor,
1920 txParams.bandwidthHz,
1921 8,
1923
1926 edPhy2,
1927 packet,
1928 868'100'000,
1930 txParams,
1931 14);
1932
1936
1937 NS_TEST_EXPECT_MSG_EQ(edPhy1->GetState(),
1939 "State didn't switch to STANDBY as expected");
1940 NS_TEST_EXPECT_MSG_EQ(edPhy2->GetState(),
1942 "State didn't switch to STANDBY as expected");
1943}
1944
1945/**
1946 * @ingroup lorawan
1947 *
1948 * It tests the functionalities of the MAC layer of LoRaWAN devices
1949 *
1950 * @todo Not implemented yet.
1951 */
1953{
1954 public:
1955 LorawanMacTest(); //!< Default constructor
1956 ~LorawanMacTest() override; //!< Destructor
1957
1958 private:
1959 void DoRun() override;
1960};
1961
1962// Add some help text to this case to describe what it is intended to test
1964 : TestCase("Verify that the MAC layer of end devices behaves as expected")
1965{
1966}
1967
1968// Reminder that the test case should clean up after itself
1972
1973// This method is the pure virtual method from class TestCase that every
1974// TestCase must implement
1975void
1977{
1978 NS_LOG_DEBUG("LorawanMacTest");
1979}
1980
1981/**
1982 * @ingroup lorawan
1983 *
1984 * It tests the functionalities of LoRaWAN MAC commands received by devices.
1985 *
1986 * This means testing that (i) settings in the downlink MAC commands are correctly applied/rejected
1987 * by the device, and that (ii) the correct answer (if expected) is produced by the device.
1988 */
1990{
1991 public:
1992 MacCommandTest(); //!< Default constructor
1993 ~MacCommandTest() override; //!< Destructor
1994
1995 private:
1996 /**
1997 * Have this class' MAC layer receive a downlink packet carrying the input MAC command. After,
1998 * trigger a new empty uplink packet send that can then be used to examine the MAC command
1999 * answers in the header.
2000 *
2001 * @tparam T \explicit The type of MAC command to create.
2002 * @tparam Ts \deduced Types of the constructor arguments.
2003 * @param [in] args MAC command constructor arguments.
2004 * @return The list of MAC commands produced by the device as an answer.
2005 */
2006 template <typename T, typename... Ts>
2007 std::vector<Ptr<MacCommand>> RunMacCommand(Ts&&... args);
2008
2009 /**
2010 * This function resets the state of the MAC layer used for tests. Use it before each call of
2011 * RunMacCommand. Otherwise, on consecutive calls the MAC layer will not send due to duty-cycle
2012 * limitations.
2013 */
2014 void Reset();
2015
2016 void DoRun() override;
2017
2018 Ptr<ClassAEndDeviceLorawanMac> m_mac; //!< The end device's MAC layer used in tests.
2019};
2020
2022 : TestCase("Test functionality of MAC commands when received by a device")
2023{
2024}
2025
2027{
2028 m_mac = nullptr;
2029}
2030
2031template <typename T, typename... Ts>
2032std::vector<Ptr<MacCommand>>
2034{
2035 Ptr<Packet> pkt;
2036 LoraFrameHeader fhdr;
2037 LorawanMacHeader mhdr;
2038 // Prepare DL packet with input command
2039 pkt = Create<Packet>(0);
2040 fhdr.SetAsDownlink();
2041 auto cmd = Create<T>(args...);
2042 fhdr.AddCommand(cmd);
2043 pkt->AddHeader(fhdr);
2045 pkt->AddHeader(mhdr);
2046 // Trigger MAC layer reception
2047 DynamicCast<LorawanMac>(m_mac)->Receive(pkt);
2048 // Trigger MAC layer send
2049 pkt = Create<Packet>(0);
2050 m_mac->Send(pkt);
2051 // Retrieve uplink MAC commands
2052 pkt->RemoveHeader(mhdr);
2053 fhdr.SetAsUplink();
2054 pkt->RemoveHeader(fhdr);
2055 return fhdr.GetCommands();
2056}
2057
2058void
2060{
2061 // Reset MAC state
2062 LorawanMacHelper macHelper;
2065 /// @todo Create should not require a node in input.
2066 m_mac = DynamicCast<ClassAEndDeviceLorawanMac>(macHelper.Install(nullptr, nullptr));
2067 NS_TEST_EXPECT_MSG_NE(m_mac, nullptr, "Failed to initialize MAC layer object.");
2069 phy->SetChannel(CreateObject<LoraChannel>());
2071 m_mac->SetPhy(phy);
2072}
2073
2074void
2076{
2077 NS_LOG_DEBUG("MacCommandTest");
2078
2079 Reset();
2080 // LinkCheckAns: get connectivity metrics of last uplink LinkCheckReq command
2081 {
2082 uint8_t margin = 20; // best reception margin [dB] from demodulation floor
2083 uint8_t gwCnt = 3; // number of gateways that received last uplink
2084 auto answers = RunMacCommand<LinkCheckAns>(margin, gwCnt);
2085 NS_TEST_EXPECT_MSG_EQ(unsigned(m_mac->GetLastKnownLinkMarginDb()),
2086 unsigned(margin),
2087 "m_lastKnownMarginDb differs from Margin field of LinkCheckAns");
2088 NS_TEST_EXPECT_MSG_EQ(unsigned(m_mac->GetLastKnownGatewayCount()),
2089 unsigned(gwCnt),
2090 "m_lastKnownGatewayCount differs GwCnt field of LinkCheckAns");
2091 NS_TEST_EXPECT_MSG_EQ(answers.size(),
2092 0,
2093 "Unexpected uplink MAC command answer(s) to LinkCheckAns");
2094 }
2095
2096 Reset();
2097 // LinkAdrReq: change data rate, TX power, redundancy, or channel mask
2098 {
2099 uint8_t dataRate = 5;
2100 uint8_t txPower = 2;
2101 uint16_t chMask = 0b101;
2102 uint8_t chMaskCntl = 0;
2103 uint8_t nbTrans = 13;
2104 auto answers = RunMacCommand<LinkAdrReq>(dataRate, txPower, chMask, chMaskCntl, nbTrans);
2105 NS_TEST_EXPECT_MSG_EQ(unsigned(m_mac->GetDataRate()),
2106 unsigned(dataRate),
2107 "m_dataRate does not match DataRate field of LinkAdrReq");
2108 NS_TEST_EXPECT_MSG_EQ(m_mac->GetTransmissionPowerDbm(),
2109 14 - txPower * 2,
2110 "m_txPowerDbm does not match txPower field of LinkAdrReq");
2111 NS_TEST_EXPECT_MSG_EQ(unsigned(m_mac->GetMaxNumberOfTransmissions()),
2112 unsigned(nbTrans),
2113 "m_nbTrans does not match nbTrans field of LinkAdrReq");
2114 auto channels = m_mac->GetLogicalLoraChannelHelper()->GetRawChannelArray();
2115 for (size_t i = 0; i < channels.size(); i++)
2116 {
2117 const auto& c = channels.at(i + 16 * chMaskCntl);
2118 bool actual = (c) ? c->IsEnabledForUplink() : false;
2119 bool expected = (chMask & 0b1 << i);
2120 NS_TEST_EXPECT_MSG_EQ(actual, expected, "Channel " << i << " state != chMask");
2121 }
2122 NS_TEST_ASSERT_MSG_EQ(answers.size(), 1, "1 answer cmd was expected, found 0 or >1");
2123 auto laa = DynamicCast<LinkAdrAns>(answers.at(0));
2124 NS_TEST_ASSERT_MSG_NE(laa, nullptr, "LinkAdrAns was expected, cmd type cast failed");
2125 NS_TEST_EXPECT_MSG_EQ(laa->GetChannelMaskAck(), true, "ChannelMaskAck expected to be true");
2126 NS_TEST_EXPECT_MSG_EQ(laa->GetDataRateAck(), true, "DataRateAck expected to be true");
2127 NS_TEST_EXPECT_MSG_EQ(laa->GetPowerAck(), true, "PowerAck expected to be true");
2128 }
2129
2130 Reset();
2131 // LinkAdrReq: ADR bit off, only change channel mask
2132 {
2133 uint8_t dataRate = 5;
2134 uint8_t txPower = 2;
2135 uint16_t chMask = 0b010;
2136 uint8_t chMaskCntl = 0;
2137 uint8_t nbTrans = 13;
2138 m_mac->SetUplinkAdrBit(false);
2139 auto answers = RunMacCommand<LinkAdrReq>(dataRate, txPower, chMask, chMaskCntl, nbTrans);
2140 NS_TEST_EXPECT_MSG_NE(unsigned(m_mac->GetDataRate()),
2141 unsigned(dataRate),
2142 "m_dataRate expected to differ from DataRate field of LinkAdrReq");
2143 NS_TEST_EXPECT_MSG_NE(m_mac->GetTransmissionPowerDbm(),
2144 14 - txPower * 2,
2145 "m_txPowerDbm expected to not match txPower field of LinkAdrReq");
2146 NS_TEST_EXPECT_MSG_NE(unsigned(m_mac->GetMaxNumberOfTransmissions()),
2147 unsigned(nbTrans),
2148 "m_nbTrans expected to differ from nbTrans field of LinkAdrReq");
2149 auto channels = m_mac->GetLogicalLoraChannelHelper()->GetRawChannelArray();
2150 for (size_t i = 0; i < channels.size(); i++)
2151 {
2152 const auto& c = channels.at(i + 16 * chMaskCntl);
2153 bool actual = (c) ? c->IsEnabledForUplink() : false;
2154 bool expected = (chMask & 0b1 << i);
2155 NS_TEST_EXPECT_MSG_EQ(actual, expected, "Channel " << i << " state != chMask");
2156 }
2157 NS_TEST_ASSERT_MSG_EQ(answers.size(), 1, "1 answer cmd was expected, found 0 or >1");
2158 auto laa = DynamicCast<LinkAdrAns>(answers.at(0));
2159 NS_TEST_ASSERT_MSG_NE(laa, nullptr, "LinkAdrAns was expected, cmd type cast failed");
2160 NS_TEST_EXPECT_MSG_EQ(laa->GetChannelMaskAck(), true, "ChannelMaskAck expected to be true");
2161 NS_TEST_EXPECT_MSG_EQ(laa->GetDataRateAck(), false, "DataRateAck expected to be false");
2162 NS_TEST_EXPECT_MSG_EQ(laa->GetPowerAck(), false, "PowerAck expected to be false");
2163 }
2164
2165 Reset();
2166 // LinkAdrReq: invalid chMask, data rate and power
2167 { // WARNING: default values are manually set here
2168 uint8_t dataRate = 12;
2169 uint8_t txPower = 8;
2170 uint16_t chMask = 0b0;
2171 uint8_t chMaskCntl = 0;
2172 uint8_t nbTrans = 6;
2173 auto answers = RunMacCommand<LinkAdrReq>(dataRate, txPower, chMask, chMaskCntl, nbTrans);
2174 NS_TEST_EXPECT_MSG_EQ(unsigned(m_mac->GetDataRate()),
2175 0,
2176 "m_dataRate expected to be default value");
2177 NS_TEST_EXPECT_MSG_EQ(m_mac->GetTransmissionPowerDbm(),
2178 14,
2179 "m_txPowerDbm expected to be default value");
2180 NS_TEST_EXPECT_MSG_EQ(unsigned(m_mac->GetMaxNumberOfTransmissions()),
2181 1,
2182 "m_nbTrans expected to be default value");
2183 auto channels = m_mac->GetLogicalLoraChannelHelper()->GetRawChannelArray();
2184 for (size_t i = 0; i < channels.size(); i++)
2185 {
2186 const auto& c = channels.at(i + 16 * chMaskCntl);
2187 bool actual = (c) ? c->IsEnabledForUplink() : false;
2188 bool expected = (uint16_t(0b111) & 0b1 << i);
2189 NS_TEST_EXPECT_MSG_EQ(actual, expected, "Channel " << i << " state != default");
2190 }
2191 NS_TEST_ASSERT_MSG_EQ(answers.size(), 1, "1 answer cmd was expected, found 0 or >1");
2192 auto laa = DynamicCast<LinkAdrAns>(answers.at(0));
2193 NS_TEST_ASSERT_MSG_NE(laa, nullptr, "LinkAdrAns was expected, cmd type cast failed");
2194 NS_TEST_EXPECT_MSG_EQ(laa->GetChannelMaskAck(), false, "ChannelMaskAck != false");
2195 NS_TEST_EXPECT_MSG_EQ(laa->GetDataRateAck(), false, "DataRateAck expected to be false");
2196 NS_TEST_EXPECT_MSG_EQ(laa->GetPowerAck(), false, "PowerAck expected to be false");
2197 }
2198
2199 Reset();
2200 // LinkAdrReq: invalid chMask, valid data rate and power
2201 { // WARNING: default values are manually set here
2202 uint8_t dataRate = 1;
2203 uint8_t txPower = 7;
2204 uint16_t chMask = 0b1000; // enable only non-exisitng channel
2205 uint8_t chMaskCntl = 0;
2206 uint8_t nbTrans = 3;
2207 auto answers = RunMacCommand<LinkAdrReq>(dataRate, txPower, chMask, chMaskCntl, nbTrans);
2208 NS_TEST_EXPECT_MSG_EQ(unsigned(m_mac->GetDataRate()),
2209 0,
2210 "m_dataRate expected to be default value");
2211 NS_TEST_EXPECT_MSG_EQ(m_mac->GetTransmissionPowerDbm(),
2212 14,
2213 "m_txPowerDbm expected to be default value");
2214 NS_TEST_EXPECT_MSG_EQ(unsigned(m_mac->GetMaxNumberOfTransmissions()),
2215 1,
2216 "m_nbTrans expected to be default value");
2217 auto channels = m_mac->GetLogicalLoraChannelHelper()->GetRawChannelArray();
2218 for (size_t i = 0; i < channels.size(); i++)
2219 {
2220 const auto& c = channels.at(i + 16 * chMaskCntl);
2221 bool actual = (c) ? c->IsEnabledForUplink() : false;
2222 bool expected = (uint16_t(0b111) & 0b1 << i);
2223 NS_TEST_EXPECT_MSG_EQ(actual, expected, "Channel " << i << " state != default");
2224 }
2225 NS_TEST_ASSERT_MSG_EQ(answers.size(), 1, "1 answer cmd was expected, found 0 or >1");
2226 auto laa = DynamicCast<LinkAdrAns>(answers.at(0));
2227 NS_TEST_ASSERT_MSG_NE(laa, nullptr, "LinkAdrAns was expected, cmd type cast failed");
2228 NS_TEST_EXPECT_MSG_EQ(laa->GetChannelMaskAck(), false, "ChannelMaskAck != false");
2229 NS_TEST_EXPECT_MSG_EQ(laa->GetDataRateAck(), true, "DataRateAck expected to be true");
2230 NS_TEST_EXPECT_MSG_EQ(laa->GetPowerAck(), true, "PowerAck expected to be true");
2231 }
2232
2233 Reset();
2234 // LinkAdrReq: fringe parameter values
2235 { // WARNING: default values are manually set here
2236 uint8_t dataRate = 0xF;
2237 uint8_t txPower = 0xF; // 0x0F ignores config
2238 uint16_t chMask = 0b0; // should be ignored because chMaskCntl is 6
2239 uint8_t chMaskCntl = 6; // all channels on
2240 uint8_t nbTrans = 0; // restore default 1
2241 // Set device params to values different from default
2242 m_mac->SetDataRate(3);
2243 m_mac->SetTransmissionPowerDbm(12);
2244 m_mac->SetMaxNumberOfTransmissions(15);
2245 auto channels = m_mac->GetLogicalLoraChannelHelper()->GetRawChannelArray();
2246 channels.at(0)->DisableForUplink();
2247 auto answers = RunMacCommand<LinkAdrReq>(dataRate, txPower, chMask, chMaskCntl, nbTrans);
2248 NS_TEST_EXPECT_MSG_EQ(unsigned(m_mac->GetDataRate()),
2249 3,
2250 "m_dataRate expected to be default value");
2251 NS_TEST_EXPECT_MSG_EQ(m_mac->GetTransmissionPowerDbm(),
2252 12,
2253 "m_txPowerDbm expected to be default value");
2254 NS_TEST_EXPECT_MSG_EQ(unsigned(m_mac->GetMaxNumberOfTransmissions()),
2255 1,
2256 "m_nbTrans expected to be default value");
2257 for (size_t i = 0; i < channels.size(); i++)
2258 {
2259 const auto& c = channels.at(i);
2260 bool actual = (c) ? c->IsEnabledForUplink() : false;
2261 bool expected = (uint16_t(0b111) & 0b1 << i);
2262 NS_TEST_EXPECT_MSG_EQ(actual, expected, "Channel " << i << " state != default");
2263 }
2264 NS_TEST_ASSERT_MSG_EQ(answers.size(), 1, "1 answer cmd was expected, found 0 or >1");
2265 auto laa = DynamicCast<LinkAdrAns>(answers.at(0));
2266 NS_TEST_ASSERT_MSG_NE(laa, nullptr, "LinkAdrAns was expected, cmd type cast failed");
2267 NS_TEST_EXPECT_MSG_EQ(laa->GetChannelMaskAck(), true, "ChannelMaskAck != true");
2268 NS_TEST_EXPECT_MSG_EQ(laa->GetDataRateAck(), true, "DataRateAck expected to be true");
2269 NS_TEST_EXPECT_MSG_EQ(laa->GetPowerAck(), true, "PowerAck expected to be true");
2270 }
2271
2272 Reset();
2273 // DutyCycleReq: duty cycle to 100%
2274 {
2275 uint8_t maxDutyCycle = 0;
2276 auto answers = RunMacCommand<DutyCycleReq>(maxDutyCycle);
2277 NS_TEST_EXPECT_MSG_EQ(m_mac->GetAggregatedDutyCycle(),
2278 1 / std::pow(2, maxDutyCycle),
2279 "m_aggregatedDutyCycle != 1");
2280 NS_TEST_ASSERT_MSG_EQ(answers.size(), 1, "1 answer cmd was expected, found 0 or >1");
2281 auto dca = DynamicCast<DutyCycleAns>(answers.at(0));
2282 NS_TEST_EXPECT_MSG_NE(dca, nullptr, "DutyCycleAns was expected, cmd type cast failed");
2283 }
2284
2285 Reset();
2286 // DutyCycleReq: duty cycle to 12.5%
2287 {
2288 uint8_t maxDutyCycle = 3;
2289 auto answers = RunMacCommand<DutyCycleReq>(maxDutyCycle);
2290 NS_TEST_EXPECT_MSG_EQ(m_mac->GetAggregatedDutyCycle(),
2291 1 / std::pow(2, maxDutyCycle),
2292 "m_aggregatedDutyCycle != 1");
2293 NS_TEST_ASSERT_MSG_EQ(answers.size(), 1, "1 answer cmd was expected, found 0 or >1");
2294 auto dca = DynamicCast<DutyCycleAns>(answers.at(0));
2295 NS_TEST_EXPECT_MSG_NE(dca, nullptr, "DutyCycleAns was expected, cmd type cast failed");
2296 }
2297
2298 Reset();
2299 // RxParamSetupReq: set rx1Dr, rx2Dr, frequency
2300 {
2301 uint8_t rx1DrOffset = 5;
2302 uint8_t rx2DataRate = 5;
2303 double frequencyHz = 863500000;
2304 m_mac->SetDataRate(5);
2305 auto answers = RunMacCommand<RxParamSetupReq>(rx1DrOffset, rx2DataRate, frequencyHz);
2306 NS_TEST_EXPECT_MSG_EQ(unsigned(m_mac->GetFirstReceiveWindowDataRate()),
2307 unsigned(5 - rx1DrOffset),
2308 "Rx1DataRate does not match rx1DrOffset from RxParamSetupReq");
2309 NS_TEST_EXPECT_MSG_EQ(unsigned(m_mac->GetSecondReceiveWindowDataRate()),
2310 unsigned(rx2DataRate),
2311 "Rx2DataRate does not match rx2DataRate from RxParamSetupReq");
2312 NS_TEST_EXPECT_MSG_EQ(m_mac->GetSecondReceiveWindowFrequency(),
2313 frequencyHz,
2314 "Rx2 frequency does not match frequency from RxParamSetupReq");
2315 NS_TEST_ASSERT_MSG_EQ(answers.size(), 1, "1 answer cmd was expected, found 0 or >1");
2316 auto rpsa = DynamicCast<RxParamSetupAns>(answers.at(0));
2317 NS_TEST_ASSERT_MSG_NE(rpsa, nullptr, "RxParamSetupAns was expected, cmd type cast failed");
2318 NS_TEST_EXPECT_MSG_EQ(rpsa->GetRx1DrOffsetAck(), true, "Rx1DrOffsetAck != true");
2319 NS_TEST_EXPECT_MSG_EQ(rpsa->GetRx2DataRateAck(), true, "Rx2DataRateAck != true");
2320 NS_TEST_EXPECT_MSG_EQ(rpsa->GetChannelAck(), true, "ChannelAck expected to be true");
2321 }
2322
2323 Reset();
2324 // RxParamSetupReq: invalid rx1Dr, rx2Dr, frequency
2325 { // WARNING: default values are manually set here
2326 uint8_t rx1DrOffset = 6;
2327 uint8_t rx2DataRate = 12;
2328 double frequencyHz = 871000000;
2329 m_mac->SetDataRate(5);
2330 auto answers = RunMacCommand<RxParamSetupReq>(rx1DrOffset, rx2DataRate, frequencyHz);
2331 NS_TEST_EXPECT_MSG_EQ(unsigned(m_mac->GetFirstReceiveWindowDataRate()),
2332 5,
2333 "Rx1DataRate expected to be default value");
2334 NS_TEST_EXPECT_MSG_EQ(unsigned(m_mac->GetSecondReceiveWindowDataRate()),
2335 0,
2336 "Rx2DataRate expected to be default value");
2337 NS_TEST_EXPECT_MSG_EQ(m_mac->GetSecondReceiveWindowFrequency(),
2338 869525000,
2339 "Rx2 frequency expected to be default value");
2340 NS_TEST_ASSERT_MSG_EQ(answers.size(), 1, "1 answer cmd was expected, found 0 or >1");
2341 auto rpsa = DynamicCast<RxParamSetupAns>(answers.at(0));
2342 NS_TEST_ASSERT_MSG_NE(rpsa, nullptr, "RxParamSetupAns was expected, cmd type cast failed");
2343 NS_TEST_EXPECT_MSG_EQ(rpsa->GetRx1DrOffsetAck(), false, "Rx1DrOffsetAck != false");
2344 NS_TEST_EXPECT_MSG_EQ(rpsa->GetRx2DataRateAck(), false, "Rx2DataRateAck != false");
2345 NS_TEST_EXPECT_MSG_EQ(rpsa->GetChannelAck(), false, "ChannelAck expected to be false");
2346 }
2347
2348 Reset();
2349 // DevStatusReq: get default values
2350 { // WARNING: default values are manually set here
2351 auto answers = RunMacCommand<DevStatusReq>();
2352 NS_TEST_ASSERT_MSG_EQ(answers.size(), 1, "1 answer cmd was expected, found 0 or >1");
2353 auto dsa = DynamicCast<DevStatusAns>(answers.at(0));
2354 NS_TEST_ASSERT_MSG_NE(dsa, nullptr, "DevStatusAns was expected, cmd type cast failed");
2355 NS_TEST_EXPECT_MSG_EQ(unsigned(dsa->GetBattery()), 0, "Battery expected == 0 (ext power)");
2356 NS_TEST_EXPECT_MSG_EQ(unsigned(dsa->GetMargin()), 31, "Margin expected to be 31 (default)");
2357 }
2358
2359 Reset();
2360 // NewChannelReq: add a new channel
2361 {
2362 uint8_t chIndex = 4;
2363 double frequencyHz = 865100000;
2364 uint8_t minDataRate = 1;
2365 uint8_t maxDataRate = 4;
2366 auto answers = RunMacCommand<NewChannelReq>(chIndex, frequencyHz, minDataRate, maxDataRate);
2367 NS_TEST_ASSERT_MSG_EQ(answers.size(), 1, "1 answer cmd was expected, found 0 or >1");
2368 auto c = m_mac->GetLogicalLoraChannelHelper()->GetRawChannelArray().at(chIndex);
2369 NS_TEST_ASSERT_MSG_NE(c, nullptr, "Channel at chIndex slot expected not to be nullptr");
2370 NS_TEST_EXPECT_MSG_EQ(c->GetFrequency(),
2371 frequencyHz,
2372 "Channel frequency expected to equal NewChannelReq frequency");
2373 NS_TEST_EXPECT_MSG_EQ(c->GetMinimumDataRate(),
2374 unsigned(minDataRate),
2375 "Channel minDataRate expected to equal NewChannelReq minDataRate");
2376 NS_TEST_EXPECT_MSG_EQ(c->GetMaximumDataRate(),
2377 unsigned(maxDataRate),
2378 "Channel maxDataRate expected to equal NewChannelReq maxDataRate");
2379 auto nca = DynamicCast<NewChannelAns>(answers.at(0));
2380 NS_TEST_ASSERT_MSG_NE(nca, nullptr, "NewChannelAns was expected, cmd type cast failed");
2381 NS_TEST_EXPECT_MSG_EQ(nca->GetDataRateRangeOk(), true, "DataRateRangeOk != true");
2382 NS_TEST_EXPECT_MSG_EQ(nca->GetChannelFrequencyOk(), true, "ChannelFrequencyOk != true");
2383 }
2384
2385 Reset();
2386 // NewChannelReq: invalid new channel
2387 { // WARNING: default values are manually set here
2388 uint8_t chIndex = 1;
2389 double frequencyHz = 862000000;
2390 uint8_t minDataRate = 14;
2391 uint8_t maxDataRate = 13;
2392 auto answers = RunMacCommand<NewChannelReq>(chIndex, frequencyHz, minDataRate, maxDataRate);
2393 NS_TEST_ASSERT_MSG_EQ(answers.size(), 1, "1 answer cmd was expected, found 0 or >1");
2394 double defaultFrequenciesHz[3] = {868100000, 868300000, 868500000};
2395 auto channels = m_mac->GetLogicalLoraChannelHelper()->GetRawChannelArray();
2396 for (size_t i = 0; i < channels.size(); i++)
2397 {
2398 const auto& c = channels.at(i);
2399 if (i > 2)
2400 {
2401 NS_TEST_ASSERT_MSG_EQ(c, nullptr, "Channel " << i << "expected to be nullptr");
2402 continue;
2403 }
2404 NS_TEST_EXPECT_MSG_EQ(c->GetFrequency(),
2405 defaultFrequenciesHz[i],
2406 "Channel frequency expected to equal NewChannelReq frequency");
2407 NS_TEST_EXPECT_MSG_EQ(unsigned(c->GetMinimumDataRate()),
2408 0,
2409 "Channel " << i << " minDataRate expected to be default");
2410 NS_TEST_EXPECT_MSG_EQ(unsigned(c->GetMaximumDataRate()),
2411 5,
2412 "Channel " << i << " maxDataRate expected to be default");
2413 NS_TEST_EXPECT_MSG_EQ(c->IsEnabledForUplink(),
2414 true,
2415 "Channel " << i << " state expected to be active by default");
2416 }
2417 auto nca = DynamicCast<NewChannelAns>(answers.at(0));
2418 NS_TEST_ASSERT_MSG_NE(nca, nullptr, "NewChannelAns was expected, cmd type cast failed");
2419 NS_TEST_EXPECT_MSG_EQ(nca->GetDataRateRangeOk(), false, "DataRateRangeOk != false");
2420 NS_TEST_EXPECT_MSG_EQ(nca->GetChannelFrequencyOk(), false, "ChannelFrequencyOk != false");
2421 }
2422}
2423
2424/**
2425 * @ingroup lorawan
2426 *
2427 * It tests the correct execution of the ADR backoff procedure of LoRaWAN devices.
2428 * (See, LoRaWAN L2 1.0.4 Specifications (2020), Section 4.3.1.1)
2429 */
2431{
2432 public:
2433 AdrBackoffTest(); //!< Default constructor
2434 ~AdrBackoffTest() override; //!< Destructor
2435
2436 private:
2437 /**
2438 * Create and send an empty app payload unconfirmed frame through the MAC layer to increment
2439 * of the FCnt and ADRACKCnt and eventually activate the ADR backoff procedure configurations of
2440 * the MAC layer. The packet is sent after a delay (simulated time is fast-forwarded to the
2441 * event) such that the device does not incur any duty-cycle limitation. The sent packet FHDR is
2442 * returned as argument for validation purposes.
2443 *
2444 * @param after Delay to schedule the packet after to avoid duty-cycle limitations
2445 * @param fhdr [out] FHDR of the constructed frame passed to PHY by the MAC
2446 */
2447 void SendUplink(Time after, LoraFrameHeader& fhdr);
2448
2449 /**
2450 * Create and schedule the PHY reception of a downlink transmission configured for the LoRaWAN
2451 * MAC first reception window. This is used to test resetting the ADR backoff procedure.
2452 *
2453 * @note This does not call Simulator::Run(), enabling preemptive scheduling, but must be
2454 * manually timed to happen during the first reception window
2455 *
2456 * It constrains the device to a single uplink channel to force-out the first reception window
2457 * frequency. The downlink spreading factor is taken from the current MAC configuration.
2458 *
2459 * @param after Delay to schedule the packet after (must target the first reception window)
2460 */
2461 void ScheduleRx1Downlink(Time after);
2462
2463 /**
2464 * This function resets the simulation and device MAC layer, use before test sub-cases.
2465 */
2466 void Reset();
2467
2468 void DoRun() override;
2469
2470 Ptr<ClassAEndDeviceLorawanMac> m_mac; //!< The end device's MAC layer used in tests.
2471};
2472
2474 : TestCase("Test the ADR backoff procedure of the LoRaWAN MAC protocol")
2475{
2476}
2477
2479{
2480 m_mac = nullptr;
2481}
2482
2483void
2485{
2486 Ptr<Packet> pkt;
2487 LorawanMacHeader mhdr;
2488 // Send packet through the MAC layer
2489 pkt = Create<Packet>(0);
2492 // Retrieve uplink FHDR
2493 pkt->RemoveHeader(mhdr);
2494 fhdr.SetAsUplink();
2495 pkt->RemoveHeader(fhdr);
2496 NS_LOG_LOGIC("FHDR: " << fhdr);
2497}
2498
2499void
2501{
2502 Ptr<Packet> pkt;
2503 LoraFrameHeader fhdr;
2504 LorawanMacHeader mhdr;
2505 // Prepare DL packet
2506 pkt = Create<Packet>(0);
2507 fhdr.SetAsDownlink();
2508 pkt->AddHeader(fhdr);
2510 pkt->AddHeader(mhdr);
2511 // Force the next RX1 window channel frequency
2512 auto chVec = m_mac->GetLogicalLoraChannelHelper()->GetRawChannelArray();
2513 chVec.at(1)->DisableForUplink();
2514 chVec.at(2)->DisableForUplink();
2515 // Schedule MAC layer reception through PHY
2516 auto phy = DynamicCast<SimpleEndDeviceLoraPhy>(m_mac->GetPhy());
2517 Simulator::Schedule(after,
2519 phy,
2520 pkt,
2521 chVec.at(0)->GetFrequency(),
2523 12,
2524 -100,
2525 MilliSeconds(10));
2526}
2527
2528void
2530{
2532 // Reset MAC state
2533 LorawanMacHelper macHelper;
2536 /// @todo Install should not require a node in input.
2537 m_mac = DynamicCast<ClassAEndDeviceLorawanMac>(macHelper.Install(nullptr, nullptr));
2538 NS_TEST_EXPECT_MSG_NE(m_mac, nullptr, "Failed to initialize MAC layer object.");
2540 phy->SetChannel(CreateObject<LoraChannel>());
2542 m_mac->SetPhy(phy);
2543}
2544
2545void
2547{
2548 NS_LOG_DEBUG("AdrBackoffTest");
2549
2550 Reset();
2551 // Full ADR Backoff procedure
2552 {
2553 LoraFrameHeader fhdr;
2554 auto llch = m_mac->GetLogicalLoraChannelHelper();
2555 auto ADR_ACK_LIMIT = EndDeviceLorawanMac::ADR_ACK_LIMIT;
2556 auto ADR_ACK_DELAY = EndDeviceLorawanMac::ADR_ACK_DELAY;
2557 // Custom config to force full ADR backoff
2558 {
2559 // Tx parameters to furthest settings from default
2560 m_mac->SetDataRate(5);
2561 m_mac->SetTransmissionPowerDbm(0);
2562 m_mac->SetMaxNumberOfTransmissions(8);
2563 auto chVec = llch->GetRawChannelArray();
2564 chVec.at(0)->DisableForUplink();
2565 chVec.at(1)->DisableForUplink();
2566 chVec.at(2)->DisableForUplink();
2567 // Provide additional non-default channel for uplinks
2568 auto nonDefaultChannel = Create<LogicalLoraChannel>(869850000, 0, 5);
2569 llch->SetChannel(3, nonDefaultChannel);
2570 }
2571 // 7 total backoff steps: 1 tx power + 5 data rate + 1 nbtrans & channels
2572 for (uint32_t fCnt = 0; fCnt <= ADR_ACK_LIMIT + ADR_ACK_DELAY * 7U; ++fCnt)
2573 {
2574 SendUplink(Minutes(20), fhdr);
2575 NS_TEST_EXPECT_MSG_EQ(fhdr.GetFCnt(), fCnt, "Unexpected FCnt value in uplink FHDR");
2577 fCnt >= ADR_ACK_LIMIT,
2578 "Unexpected ADRACKReq value in FHDR of uplink fCnt=" << fCnt);
2579 uint8_t step = (fCnt >= ADR_ACK_LIMIT) ? (fCnt - ADR_ACK_LIMIT) / ADR_ACK_DELAY : 0;
2580 NS_TEST_EXPECT_MSG_EQ(m_mac->GetTransmissionPowerDbm(),
2581 (step > 0) ? 14 : 0,
2582 "Unexpected tx power on uplink fCnt=" << fCnt);
2583 uint8_t expectedDr = (step == 0) ? 5 : (step < 7) ? 5 - (step - 1) : 0;
2584 NS_TEST_EXPECT_MSG_EQ(m_mac->GetDataRate(),
2585 expectedDr,
2586 "Unexpected data rate on uplink fCnt=" << fCnt);
2587 const auto chVec = llch->GetRawChannelArray();
2588 for (uint8_t i = 0; i < 3; ++i)
2589 {
2590 NS_TEST_EXPECT_MSG_EQ(chVec.at(i)->IsEnabledForUplink(),
2591 step >= 7,
2592 "Unexpected activation state of channel "
2593 << unsigned(i) << " on uplink fCnt=" << fCnt);
2594 }
2596 chVec.at(3)->IsEnabledForUplink(),
2597 true,
2598 "Unexpected activation state of channel 3 on uplink fCnt=" << fCnt);
2599 }
2600 }
2601
2602 Reset();
2603 // ADRACKReq back to false after downlink
2604 {
2605 LoraFrameHeader fhdr;
2606 auto ADR_ACK_LIMIT = EndDeviceLorawanMac::ADR_ACK_LIMIT;
2607 // Trigger ADRACKReq
2608 for (uint16_t fCnt = 0; fCnt <= ADR_ACK_LIMIT + 5; ++fCnt)
2609 {
2610 SendUplink(Minutes(20), fhdr);
2611 NS_TEST_EXPECT_MSG_EQ(fhdr.GetFCnt(), fCnt, "Unexpected FCnt value in uplink FHDR");
2613 fCnt >= ADR_ACK_LIMIT,
2614 "Unexpected ADRACKReq value in FHDR of uplink fCnt=" << fCnt);
2615 }
2616 // Receive downlink for the next packet RX window
2618 // Trigger reception windows with new uplink
2619 SendUplink(Minutes(20), fhdr);
2621 ADR_ACK_LIMIT + 5 + 1,
2622 "Unexpected FCnt value in uplink FHDR");
2624 fhdr.GetAdrAckReq(),
2625 true,
2626 "Unexpected ADRACKReq value in FHDR of uplink fCnt=" << fhdr.GetFCnt());
2627 // Next uplink should have ADRACKReq unset because a downlink was received
2628 SendUplink(Minutes(20), fhdr);
2630 ADR_ACK_LIMIT + 5 + 2,
2631 "Unexpected FCnt value in uplink FHDR");
2633 fhdr.GetAdrAckReq(),
2634 false,
2635 "Unexpected ADRACKReq value in FHDR of uplink fCnt=" << fhdr.GetFCnt());
2636 }
2637}
2638
2639/**
2640 * @ingroup lorawan
2641 *
2642 * It tests the correct execution of the retransmissions in LoRaWAN devices.
2643 * (See, LoRaWAN L2 1.0.4 Specifications (2020), Section 4.3.1.3)
2644 */
2646{
2647 public:
2648 RetransmissionTest(); //!< Default constructor
2649 ~RetransmissionTest() override; //!< Destructor
2650
2651 private:
2652 /**
2653 * Create and send an empty app payload unconfirmed frame through the MAC layer NbTrans times.
2654 * The sent packet FHDR is returned as argument for validation purposes.
2655 *
2656 * @param fhdr [out] FHDR of the constructed frame passed to PHY by the MAC
2657 */
2658 void SendUplink(LoraFrameHeader& fhdr);
2659
2660 /**
2661 * Create and schedule the PHY reception of a downlink transmission configured for the LoRaWAN
2662 * MAC first reception window. This is used to test stopping the retransmission process.
2663 *
2664 * @note This does not call Simulator::Run(), enabling preemptive scheduling, but must be
2665 * manually timed to happen during the first reception window
2666 *
2667 * It constrains the device to a single uplink channel to force-out the first reception window
2668 * frequency. The downlink spreading factor is taken from the current MAC configuration.
2669 *
2670 * @param after Delay to schedule the packet after (must target the first reception window)
2671 * @param ack Whether to set the ACK flag in the frame header
2672 */
2673 void ScheduleRx1Downlink(Time after, bool ack = false);
2674
2675 /**
2676 * Callback for tracing MAC layer SentNewPacket.
2677 *
2678 * @param packet The packet sent.
2679 */
2681
2682 /**
2683 * Callback for tracing the outcome of MAC layer's confirmed packet retransmission and
2684 * acknowledgement.
2685 *
2686 * @note This callback only traces confirmed packets, unused otherwise.
2687 *
2688 * @param txCount Number of transmissions attempted during the process.
2689 * @param ack Whether the retransmission process led to acknowledgement.
2690 * @param firstAttempt Timestamp of the initial transmission attempt.
2691 * @param packet The packet being retransmitted.
2692 */
2693 void MacConfirmedTransmissionOutcome(uint8_t txCount,
2694 bool ack,
2695 Time firstAttempt,
2696 Ptr<Packet> packet);
2697
2698 /**
2699 * Callback for tracing PHY layer StartSending.
2700 *
2701 * @param packet The packet being sent.
2702 * @param node The sender node id if any, 0 otherwise.
2703 */
2704 void PhyStartSending(Ptr<const Packet> packet, uint32_t node);
2705
2706 /**
2707 * Callback for tracing PHY layer ReceivedPacket.
2708 *
2709 * @param packet The packet being received.
2710 * @param node The sender node id if any, 0 otherwise.
2711 */
2712 void PhyReceivedPacket(Ptr<const Packet> packet, uint32_t node);
2713
2714 /**
2715 * This function resets the simulation and device MAC layer, use before test sub-cases.
2716 */
2717 void Reset();
2718
2719 void DoRun() override;
2720
2721 Ptr<ClassAEndDeviceLorawanMac> m_mac; //!< The end device's MAC layer used in tests.
2722 Ptr<Packet> m_packet; //!< Target packet for tracing
2723
2724 int m_macSentNewPacketCalls = 0; //!< Counter for MacSentNewPacket calls
2725 int m_macConfirmedTxOutcome = 0; //!< Counter for MacConfirmedTransmissionOutcome calls
2726 int m_phyStartSendingCalls = 0; //!< Counter for PhyStartSending calls
2727 int m_phyReceivedPacketCalls = 0; //!< Counter for PhyReceivedPacket calls
2728
2729 uint8_t m_numTransmissions = 0; //!< Number of confirmed packet transmissions
2730 bool m_successfullyAcked = false; //!< Acknowledgement of confirmed packet
2731};
2732
2734 : TestCase("Test the retransmission process of the LoRaWAN MAC protocol")
2735{
2736}
2737
2742
2743void
2745{
2746 Ptr<Packet> pkt;
2747 LorawanMacHeader mhdr;
2748 // Send packet through the MAC layer
2749 pkt = Create<Packet>(0);
2750 m_packet = pkt;
2753 // Retrieve uplink FHDR
2754 pkt->RemoveHeader(mhdr);
2755 fhdr.SetAsUplink();
2756 pkt->RemoveHeader(fhdr);
2757 NS_LOG_LOGIC("Frame Header: " << fhdr);
2758}
2759
2760void
2762{
2763 Ptr<Packet> pkt;
2764 LoraFrameHeader fhdr;
2765 LorawanMacHeader mhdr;
2766 // Prepare DL packet
2767 pkt = Create<Packet>(0);
2768 fhdr.SetAsDownlink();
2769 fhdr.SetAck(ack);
2770 pkt->AddHeader(fhdr);
2772 pkt->AddHeader(mhdr);
2773 // Force the next RX1 window channel frequency
2774 auto chVec = m_mac->GetLogicalLoraChannelHelper()->GetRawChannelArray();
2775 chVec.at(1)->DisableForUplink();
2776 chVec.at(2)->DisableForUplink();
2777 // Schedule MAC layer reception through PHY
2778 auto phy = DynamicCast<SimpleEndDeviceLoraPhy>(m_mac->GetPhy());
2779 Simulator::Schedule(after,
2781 phy,
2782 pkt,
2783 chVec.at(0)->GetFrequency(),
2785 m_mac->GetSfFromDataRate(m_mac->GetDataRate()),
2786 -100,
2787 MilliSeconds(10));
2788}
2789
2790void
2795
2796void
2798 bool ack,
2799 Time firstAttempt,
2800 Ptr<Packet> packet)
2801{
2803 if (m_packet == packet)
2804 {
2805 m_numTransmissions = txCount;
2806 m_successfullyAcked = ack;
2807 }
2808}
2809
2810void
2815
2816void
2821
2822void
2824{
2830 m_successfullyAcked = false;
2832 // Reset MAC state
2833 LorawanMacHelper macHelper;
2836 m_mac = DynamicCast<ClassAEndDeviceLorawanMac>(macHelper.Install(nullptr, nullptr));
2837 m_mac->SetDataRate(5);
2838 m_mac->TraceConnectWithoutContext("SentNewPacket",
2840 m_mac->TraceConnectWithoutContext(
2841 "ConfirmedTransmissionOutcome",
2843 NS_TEST_EXPECT_MSG_NE(m_mac, nullptr, "Failed to initialize MAC layer object.");
2845 phy->SetChannel(CreateObject<LoraChannel>());
2847 phy->TraceConnectWithoutContext("StartSending",
2849 phy->TraceConnectWithoutContext("ReceivedPacket",
2851 m_mac->SetPhy(phy);
2852 m_mac->Initialize();
2853}
2854
2855void
2857{
2858 NS_LOG_DEBUG("RetransmissionTest");
2859
2860 Reset();
2861 // Unconfirmed send yields the correct number of retransmissions (base case)
2862 { // WARNING: default values are manually set here
2864 LoraFrameHeader fhdr;
2865 SendUplink(fhdr);
2866 NS_TEST_EXPECT_MSG_EQ(fhdr.GetFCnt(), 0, "Unexpected FCnt value in uplink FHDR");
2867 NS_TEST_ASSERT_MSG_EQ(m_mac->GetUplinkFrameCounter(),
2868 1,
2869 "Unexpected MAC frame counter value");
2871 1,
2872 "Unexpected number of PHY layer StartSending calls");
2874 0,
2875 "Unexpected number of PHY layer ReceivedPacket calls");
2877 1,
2878 "Unexpected number of MAC layer SendNewPacket calls");
2880 0,
2881 "Unexpected number of MAC layer ConfirmedTransmissionOutcome calls");
2882 }
2883
2884 Reset();
2885 // Unconfirmed send yields the correct number of retransmissions
2886 {
2887 uint8_t nbTrans = 4;
2888 m_mac->SetMaxNumberOfTransmissions(nbTrans);
2890 LoraFrameHeader fhdr;
2891 SendUplink(fhdr);
2892 NS_TEST_EXPECT_MSG_EQ(fhdr.GetFCnt(), 0, "Unexpected FCnt value in uplink FHDR");
2893 NS_TEST_ASSERT_MSG_EQ(m_mac->GetUplinkFrameCounter(),
2894 1,
2895 "Unexpected FCnt value in MAC layer");
2897 nbTrans,
2898 "Unexpected number of PHY layer StartSending calls");
2900 0,
2901 "Unexpected number of PHY layer ReceivedPacket calls");
2903 1,
2904 "Unexpected number of MAC layer SendNewPacket calls");
2906 0,
2907 "Unexpected number of MAC layer ConfirmedTransmissionOutcome calls");
2908 }
2909
2910 Reset();
2911 // Unconfirmed send yields the correct number of retransmissions (limit case)
2912 {
2913 uint8_t nbTrans = 15;
2914 m_mac->SetMaxNumberOfTransmissions(nbTrans);
2916 LoraFrameHeader fhdr;
2917 SendUplink(fhdr);
2918 NS_TEST_EXPECT_MSG_EQ(fhdr.GetFCnt(), 0, "Unexpected FCnt value in uplink FHDR");
2919 NS_TEST_ASSERT_MSG_EQ(m_mac->GetUplinkFrameCounter(),
2920 1,
2921 "Unexpected MAC frame counter value");
2923 nbTrans,
2924 "Unexpected number of physical layer transmissions");
2926 0,
2927 "Unexpected number of PHY layer ReceivedPacket calls");
2929 1,
2930 "Unexpected number of MAC layer SendNewPacket calls");
2932 0,
2933 "Unexpected number of MAC layer ConfirmedTransmissionOutcome calls");
2934 }
2935
2936 Reset();
2937 // Unconfirmed send interrupted in-between retransmissions
2938 {
2939 uint8_t nbTrans = 9;
2940 m_mac->SetMaxNumberOfTransmissions(nbTrans);
2944 m_mac,
2945 Create<Packet>(0));
2946 LoraFrameHeader fhdr;
2947 SendUplink(fhdr);
2948 NS_TEST_EXPECT_MSG_EQ(fhdr.GetFCnt(), 0, "Unexpected FCnt value in uplink FHDR");
2949 NS_TEST_ASSERT_MSG_EQ(m_mac->GetUplinkFrameCounter(),
2950 2,
2951 "Unexpected FCnt value in MAC layer");
2953 1 + nbTrans,
2954 "Unexpected number of PHY layer StartSending calls");
2956 0,
2957 "Unexpected number of PHY layer ReceivedPacket calls");
2959 2,
2960 "Unexpected number of MAC layer SendNewPacket calls");
2962 0,
2963 "Unexpected number of MAC layer ConfirmedTransmissionOutcome calls");
2964 }
2965
2966 Reset();
2967 // Unconfirmed send retransmissions interrupted while MAC layer busy
2968 {
2969 uint8_t nbTrans = 8;
2970 m_mac->SetMaxNumberOfTransmissions(nbTrans);
2973 LoraFrameHeader fhdr;
2974 SendUplink(fhdr);
2975 NS_TEST_EXPECT_MSG_EQ(fhdr.GetFCnt(), 0, "Unexpected FCnt value in uplink FHDR");
2976 NS_TEST_ASSERT_MSG_EQ(m_mac->GetUplinkFrameCounter(),
2977 2,
2978 "Unexpected FCnt value in MAC layer");
2980 2 + nbTrans,
2981 "Unexpected number of PHY layer StartSending calls");
2983 0,
2984 "Unexpected number of PHY layer ReceivedPacket calls");
2986 2,
2987 "Unexpected number of MAC layer SendNewPacket calls");
2989 0,
2990 "Unexpected number of MAC layer ConfirmedTransmissionOutcome calls");
2991 }
2992
2993 Reset();
2994 // Unconfirmed send retransmissions interrupted after downlink
2995 {
2996 uint8_t nbTrans = 3;
2997 m_mac->SetMaxNumberOfTransmissions(nbTrans);
3000 LoraFrameHeader fhdr;
3001 SendUplink(fhdr);
3002 NS_TEST_EXPECT_MSG_EQ(fhdr.GetFCnt(), 0, "Unexpected FCnt value in uplink FHDR");
3003 NS_TEST_ASSERT_MSG_EQ(m_mac->GetUplinkFrameCounter(),
3004 1,
3005 "Unexpected FCnt value in MAC layer");
3007 1,
3008 "Unexpected number of PHY layer StartSending calls");
3010 1,
3011 "Unexpected number of PHY layer ReceivedPacket calls");
3013 1,
3014 "Unexpected number of MAC layer SendNewPacket calls");
3016 0,
3017 "Unexpected number of MAC layer ConfirmedTransmissionOutcome calls");
3018 }
3019
3020 Reset();
3021 // Unconfirmed send retransmissions interrupted after downlink (different params)
3022 {
3023 uint8_t nbTrans = 13;
3024 m_mac->SetMaxNumberOfTransmissions(nbTrans);
3027 LoraFrameHeader fhdr;
3028 SendUplink(fhdr);
3029 NS_TEST_EXPECT_MSG_EQ(fhdr.GetFCnt(), 0, "Unexpected FCnt value in uplink FHDR");
3030 NS_TEST_ASSERT_MSG_EQ(m_mac->GetUplinkFrameCounter(),
3031 1,
3032 "Unexpected FCnt value in MAC layer");
3034 7,
3035 "Unexpected number of PHY layer StartSending calls");
3037 1,
3038 "Unexpected number of PHY layer ReceivedPacket calls");
3040 1,
3041 "Unexpected number of MAC layer SendNewPacket calls");
3043 0,
3044 "Unexpected number of MAC layer ConfirmedTransmissionOutcome calls");
3045 }
3046
3047 Reset();
3048 // Confirmed yields the correct number of unacknowledged retransmissions
3049 {
3050 uint8_t nbTrans = 7;
3051 m_mac->SetMaxNumberOfTransmissions(nbTrans);
3053 LoraFrameHeader fhdr;
3054 SendUplink(fhdr);
3055 NS_TEST_EXPECT_MSG_EQ(fhdr.GetFCnt(), 0, "Unexpected FCnt value in uplink FHDR");
3056 NS_TEST_ASSERT_MSG_EQ(m_mac->GetUplinkFrameCounter(),
3057 1,
3058 "Unexpected FCnt value in MAC layer");
3060 nbTrans,
3061 "Unexpected number of PHY layer StartSending calls");
3063 0,
3064 "Unexpected number of PHY layer ReceivedPacket calls");
3066 1,
3067 "Unexpected number of MAC layer SendNewPacket calls");
3069 1,
3070 "Unexpected number of MAC layer ConfirmedTransmissionOutcome calls");
3072 nbTrans,
3073 "Unexpected number of transmissions for confirmed packet");
3075 false,
3076 "Unexpected acknowledgment state for confirmed packet");
3077 }
3078
3079 Reset();
3080 // Confirmed send retransmissions interrupted in-between retransmissions
3081 {
3082 uint8_t nbTrans = 6;
3083 m_mac->SetMaxNumberOfTransmissions(nbTrans);
3087 m_mac,
3088 Create<Packet>(0));
3089 LoraFrameHeader fhdr;
3090 SendUplink(fhdr);
3091 NS_TEST_EXPECT_MSG_EQ(fhdr.GetFCnt(), 0, "Unexpected FCnt value in uplink FHDR");
3092 NS_TEST_ASSERT_MSG_EQ(m_mac->GetUplinkFrameCounter(),
3093 2,
3094 "Unexpected FCnt value in MAC layer");
3096 2 + nbTrans,
3097 "Unexpected number of PHY layer StartSending calls");
3099 0,
3100 "Unexpected number of PHY layer ReceivedPacket calls");
3102 2,
3103 "Unexpected number of MAC layer SendNewPacket calls");
3105 2,
3106 "Unexpected number of MAC layer ConfirmedTransmissionOutcome calls");
3108 2,
3109 "Unexpected number of transmissions for confirmed packet");
3111 false,
3112 "Unexpected acknowledgment state for confirmed packet");
3113 }
3114
3115 Reset();
3116 // Confirmed send retransmissions interrupted interrupted while MAC layer busy
3117 {
3118 uint8_t nbTrans = 9;
3119 m_mac->SetMaxNumberOfTransmissions(nbTrans);
3123 m_mac,
3124 Create<Packet>(0));
3125 LoraFrameHeader fhdr;
3126 SendUplink(fhdr);
3127 NS_TEST_EXPECT_MSG_EQ(fhdr.GetFCnt(), 0, "Unexpected FCnt value in uplink FHDR");
3128 NS_TEST_ASSERT_MSG_EQ(m_mac->GetUplinkFrameCounter(),
3129 2,
3130 "Unexpected FCnt value in MAC layer");
3132 3 + nbTrans,
3133 "Unexpected number of PHY layer StartSending calls");
3135 0,
3136 "Unexpected number of PHY layer ReceivedPacket calls");
3138 2,
3139 "Unexpected number of MAC layer SendNewPacket calls");
3141 2,
3142 "Unexpected number of MAC layer ConfirmedTransmissionOutcome calls");
3144 3,
3145 "Unexpected number of transmissions for confirmed packet");
3147 false,
3148 "Unexpected acknowledgment state for confirmed packet");
3149 }
3150
3151 Reset();
3152 // Confirmed send retransmissions not interrupted after downlink without ACK
3153 {
3154 uint8_t nbTrans = 10;
3155 m_mac->SetMaxNumberOfTransmissions(nbTrans);
3158 LoraFrameHeader fhdr;
3159 SendUplink(fhdr);
3160 NS_TEST_EXPECT_MSG_EQ(fhdr.GetFCnt(), 0, "Unexpected FCnt value in uplink FHDR");
3161 NS_TEST_ASSERT_MSG_EQ(m_mac->GetUplinkFrameCounter(),
3162 1,
3163 "Unexpected FCnt value in MAC layer");
3165 nbTrans,
3166 "Unexpected number of PHY layer StartSending calls");
3168 1,
3169 "Unexpected number of PHY layer ReceivedPacket calls");
3171 1,
3172 "Unexpected number of MAC layer SendNewPacket calls");
3174 1,
3175 "Unexpected number of MAC layer ConfirmedTransmissionOutcome calls");
3177 nbTrans,
3178 "Unexpected number of transmissions for confirmed packet");
3180 false,
3181 "Unexpected acknowledgment state for confirmed packet");
3182 }
3183
3184 Reset();
3185 // Confirmed send retransmissions interrupted after downlink with ACK
3186 {
3187 uint8_t nbTrans = 14;
3188 m_mac->SetMaxNumberOfTransmissions(nbTrans);
3190 ScheduleRx1Downlink(Seconds(41.28), true);
3191 LoraFrameHeader fhdr;
3192 SendUplink(fhdr);
3193 NS_TEST_EXPECT_MSG_EQ(fhdr.GetFCnt(), 0, "Unexpected FCnt value in uplink FHDR");
3194 NS_TEST_ASSERT_MSG_EQ(m_mac->GetUplinkFrameCounter(),
3195 1,
3196 "Unexpected FCnt value in MAC layer");
3198 10,
3199 "Unexpected number of PHY layer StartSending calls");
3201 1,
3202 "Unexpected number of PHY layer ReceivedPacket calls");
3204 1,
3205 "Unexpected number of MAC layer SendNewPacket calls");
3207 1,
3208 "Unexpected number of MAC layer ConfirmedTransmissionOutcome calls");
3210 10,
3211 "Unexpected number of transmissions for confirmed packet");
3213 true,
3214 "Unexpected acknowledgment state for confirmed packet");
3215 }
3216}
3217
3218/**
3219 * @ingroup lorawan
3220 *
3221 * The TestSuite class names the TestSuite, identifies what type of TestSuite, and enables the
3222 * TestCases to be run. Typically, only the constructor for this class must be defined
3223 */
3225{
3226 public:
3227 LorawanTestSuite(); //!< Default constructor
3228};
3229
3231 : TestSuite("lorawan", Type::UNIT)
3232{
3233 // LogComponentEnable("LorawanTestSuite", LOG_LEVEL_DEBUG);
3234 // LogComponentEnable("LorawanMac", LOG_LEVEL_DEBUG);
3235 // LogComponentEnable("EndDeviceLorawanMac", LOG_LEVEL_DEBUG);
3236 // LogComponentEnable("ClassAEndDeviceLorawanMac", LOG_LEVEL_DEBUG);
3237 // LogComponentEnable("SimpleEndDeviceLoraPhy", LOG_LEVEL_DEBUG);
3238 // LogComponentEnable("EndDeviceLoraPhy", LOG_LEVEL_DEBUG);
3239 // LogComponentEnable("LoraPhy", LOG_LEVEL_DEBUG);
3240 // LogComponentEnable("LoraChannel", LOG_LEVEL_DEBUG);
3241 // LogComponentEnable("LoraFrameHeader", LOG_LEVEL_DEBUG);
3242 // LogComponentEnableAll(LOG_PREFIX_FUNC);
3243 // LogComponentEnableAll(LOG_PREFIX_NODE);
3244 // LogComponentEnableAll(LOG_PREFIX_TIME);
3245
3256}
3257
3258// 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 the correct execution of the ADR backoff procedure of LoRaWAN devices.
AdrBackoffTest()
Default constructor.
void DoRun() override
Implementation to actually run this TestCase.
Ptr< ClassAEndDeviceLorawanMac > m_mac
The end device's MAC layer used in tests.
~AdrBackoffTest() override
Destructor.
void ScheduleRx1Downlink(Time after)
Create and schedule the PHY reception of a downlink transmission configured for the LoRaWAN MAC first...
void Reset()
This function resets the simulation and device MAC layer, use before test sub-cases.
void SendUplink(Time after, LoraFrameHeader &fhdr)
Create and send an empty app payload unconfirmed frame through the MAC layer to increment of the FCnt...
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.
~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.
void Reset(uint8_t rxPathNb)
Reset counters and gateway PHY for new sub test case.
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.
int m_interferenceCalls
Counter for LostPacketBecauseInterference calls.
int m_maxOccupiedReceptionPaths
Max number of concurrent OccupiedReceptionPaths.
It tests the correct execution of the retransmissions in LoRaWAN devices.
int m_macConfirmedTxOutcome
Counter for MacConfirmedTransmissionOutcome calls.
RetransmissionTest()
Default constructor.
int m_phyStartSendingCalls
Counter for PhyStartSending calls.
Ptr< Packet > m_packet
Target packet for tracing.
void DoRun() override
Implementation to actually run this TestCase.
Ptr< ClassAEndDeviceLorawanMac > m_mac
The end device's MAC layer used in tests.
int m_macSentNewPacketCalls
Counter for MacSentNewPacket calls.
uint8_t m_numTransmissions
Number of confirmed packet transmissions.
void PhyStartSending(Ptr< const Packet > packet, uint32_t node)
Callback for tracing PHY layer StartSending.
~RetransmissionTest() override
Destructor.
int m_phyReceivedPacketCalls
Counter for PhyReceivedPacket calls.
bool m_successfullyAcked
Acknowledgement of confirmed packet.
void SendUplink(LoraFrameHeader &fhdr)
Create and send an empty app payload unconfirmed frame through the MAC layer NbTrans times.
void PhyReceivedPacket(Ptr< const Packet > packet, uint32_t node)
Callback for tracing PHY layer ReceivedPacket.
void ScheduleRx1Downlink(Time after, bool ack=false)
Create and schedule the PHY reception of a downlink transmission configured for the LoRaWAN MAC first...
void MacConfirmedTransmissionOutcome(uint8_t txCount, bool ack, Time firstAttempt, Ptr< Packet > packet)
Callback for tracing the outcome of MAC layer's confirmed packet retransmission and acknowledgement.
void MacSentNewPacket(Ptr< const Packet > packet)
Callback for tracing MAC layer SentNewPacket.
void Reset()
This function resets the simulation and device MAC layer, use before test sub-cases.
It tests the correctness of the LoraPhy::GetTimeOnAir 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:98
automatically resized byte buffer
Definition buffer.h:92
void AddAtStart(uint32_t start)
Definition buffer.cc:303
Buffer::Iterator Begin() const
Definition buffer.h:1090
Smart pointer class similar to boost::intrusive_ptr.
Definition ptr.h:70
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition simulator.h:580
static void Destroy()
Execute the events scheduled with ScheduleDestroy().
Definition simulator.cc:125
static void Run()
Run the simulation.
Definition simulator.cc:161
static EventId ScheduleNow(FUNC f, Ts &&... args)
Schedule an event to expire Now.
Definition simulator.h:614
static void Stop()
Tell the Simulator the calling event should be the last one executed.
Definition simulator.cc:169
void AddTestCase(TestCase *testCase, Duration duration=Duration::QUICK)
Add an individual child TestCase to this test suite.
Definition test.cc:296
@ QUICK
Fast test.
Definition test.h:1057
TestCase(const TestCase &)=delete
Caller graph was not generated because of its size.
Type
Type of test.
Definition test.h:1271
TestSuite(std::string name, Type type=Type::UNIT)
Construct a new test suite.
Definition test.cc:494
Simulation virtual time values and global simulation resolution.
Definition nstime.h:95
double GetSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
Definition nstime.h:398
void ReceiveSingle(uint32_t frequencyHz, IQPolarity iqPolarity, uint8_t spreadingFactor, uint32_t bandwidthHz, uint8_t symbNumTimeout, RxTimeoutCallback rxTimeoutCallback)
This function starts a reception attempt that will time-out if no transmission preamble is detected.
Callback< void > RxTimeoutCallback
Type definition for a callback for when a packet reception hardware timeout expires.
@ STANDBY
The PHY layer is in standby mode.
static constexpr uint16_t ADR_ACK_DELAY
ADRACKCnt threshold for ADR backoff action.
void Send(Ptr< Packet > packet) override
Send a packet.
static constexpr uint16_t ADR_ACK_LIMIT
ADRACKCnt threshold for setting ADRACKReq.
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.
bool GetAdrAckReq() const
Get the value of the ADRACKReq bit field.
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.
static CollisionMatrix collisionMatrix
Collision matrix type set by the constructor.
uint8_t IsDestroyedByInterference(Ptr< LoraInterferenceHelper::Event > event)
Determine whether the event was destroyed by interference or not.
static Time GetTimeOnAir(uint32_t phyPayloadLen, const LoraTxParameters &txParams)
Compute the total transmission time for a physical packet based on modulation parameters.
Definition lora-phy.cc:110
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.
void SetFType(enum FType fType)
Set the frame type.
FType GetFType() const
Get the frame type from the header.
void Serialize(Buffer::Iterator start) const override
Serialize the header.
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 StartReceive(Ptr< Packet > packet, uint32_t frequencyHz, IQPolarity iqPolarity, uint8_t spreadingFactor, double rxPowerDbm, Time duration) override
Start receiving a packet.
void Send(Ptr< Packet > packet, uint32_t frequencyHz, IQPolarity iqPolarity, const LoraTxParameters &txParams, double txPowerDbm) override
Instruct the PHY to send a packet according to some parameters.
void StartReceive(Ptr< Packet > packet, uint32_t frequencyHz, IQPolarity iqPolarity, uint8_t spreadingFactor, double rxPowerDbm, Time duration) override
Start receiving a packet.
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:690
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition log.h:194
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition log.h:260
#define NS_LOG_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
Definition log.h:274
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
@ CR_4_5
Coding rate 4/5.
Definition lora-phy.h:50
@ CR_4_6
Coding rate 4/6.
Definition lora-phy.h:51
@ DOWN
Downlink / Downchirp / Inverted polarity.
Definition lora-phy.h:35
@ UP
Uplink / Upchirp / Normal polarity.
Definition lora-phy.h:34
Ptr< T > CreateObject(Args &&... args)
Create an object by type, with varying number of constructor parameters.
Definition object.h:627
Ptr< T > Create(Ts &&... args)
Create class instances by constructors with varying numbers of arguments and return them by Ptr.
Definition ptr.h:492
#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:133
#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:655
#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:240
#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:553
#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:499
Time NanoSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1324
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition nstime.h:1273
Time Hours(double value)
Construct a Time in the indicated unit.
Definition nstime.h:1244
Time Minutes(double value)
Construct a Time in the indicated unit.
Definition nstime.h:1256
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1290
static LorawanTestSuite lorawanTestSuite
Every class exported by the ns3 library is enclosed in the ns3 namespace.
Ptr< T1 > DynamicCast(const Ptr< T2 > &p)
Cast a Ptr.
Definition ptr.h:643
Structure to collect all parameters that are used to compute the duration of a packet (excluding payl...
Definition lora-phy.h:73
CodingRate codingRate
Transmission coding rate.
Definition lora-phy.h:77
uint32_t bandwidthHz
Transmission bandwidth in Hz.
Definition lora-phy.h:76
bool implicitHeader
Whether to use implicit header mode.
Definition lora-phy.h:81
uint8_t spreadingFactor
Symbol Spreading Factor (SF).
Definition lora-phy.h:75
bool crcEnabled
Whether Cyclic Redundancy Check (CRC) is enabled.
Definition lora-phy.h:82
bool lowDataRateOptimize
Low Data Rate Optimization (mandated for SF11 and SF12).
Definition lora-phy.h:78
uint16_t preambleLenSymb
Number of symbols in the packet preamble.
Definition lora-phy.h:80