A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
channel-access-manager-test.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2005,2006 INRIA
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation;
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 *
17 * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
18 */
19
20#include "ns3/adhoc-wifi-mac.h"
21#include "ns3/channel-access-manager.h"
22#include "ns3/frame-exchange-manager.h"
23#include "ns3/interference-helper.h"
24#include "ns3/multi-model-spectrum-channel.h"
25#include "ns3/pointer.h"
26#include "ns3/qos-txop.h"
27#include "ns3/simulator.h"
28#include "ns3/spectrum-wifi-phy.h"
29#include "ns3/string.h"
30#include "ns3/test.h"
31
32#include <list>
33#include <numeric>
34
35using namespace ns3;
36
37template <typename TxopType>
39
40/**
41 * \ingroup wifi-test
42 * \ingroup tests
43 *
44 * \brief TxopTest Txop Test
45 */
46template <typename TxopType>
47class TxopTest : public TxopType
48{
49 public:
50 /**
51 * Constructor
52 *
53 * \param test the test channel access manager
54 * \param i the index of the Txop
55 */
57
58 /**
59 * Queue transmit function
60 * \param txTime the transmit time
61 * \param expectedGrantTime the expected grant time
62 */
63 void QueueTx(uint64_t txTime, uint64_t expectedGrantTime);
64
65 private:
66 /// allow ChannelAccessManagerTest class access
68
69 /// \copydoc ns3::Txop::DoDispose
70 void DoDispose() override;
71 /// \copydoc ns3::Txop::NotifyChannelAccessed
72 void NotifyChannelAccessed(uint8_t linkId, Time txopDuration = Seconds(0)) override;
73 /// \copydoc ns3::Txop::HasFramesToTransmit
74 bool HasFramesToTransmit(uint8_t linkId) override;
75 /// \copydoc ns3::Txop::NotifySleep
76 void NotifySleep(uint8_t linkId) override;
77 /// \copydoc ns3::Txop::NotifyWakeUp
78 void NotifyWakeUp(uint8_t linkId) override;
79 /// \copydoc ns3::Txop::GenerateBackoff
80 void GenerateBackoff(uint8_t linkId) override;
81
82 typedef std::pair<uint64_t, uint64_t> ExpectedGrant; //!< the expected grant typedef
83 typedef std::list<ExpectedGrant> ExpectedGrants; //!< the collection of expected grants typedef
84
85 /// ExpectedBackoff structure
87 {
88 uint64_t at; //!< at
89 uint32_t nSlots; //!< number of slots
90 };
91
92 typedef std::list<ExpectedBackoff> ExpectedBackoffs; //!< expected backoffs typedef
93
94 ExpectedBackoffs m_expectedInternalCollision; //!< expected backoff due to an internal collision
95 ExpectedBackoffs m_expectedBackoff; //!< expected backoff (not due to an internal collision)
96 ExpectedGrants m_expectedGrants; //!< expected grants
97
98 /**
99 * Check if the Txop has frames to transmit.
100 * \return true if the Txop has frames to transmit.
101 */
102
103 ChannelAccessManagerTest<TxopType>* m_test; //!< the test DCF/EDCA manager
104 uint32_t m_i; //!< the index of the Txop
105};
106
107/**
108 * \ingroup wifi-test
109 * \ingroup tests
110 *
111 * \brief ChannelAccessManager Stub
112 */
114{
115 public:
117 {
118 }
119
120 /**
121 * Set the Short Interframe Space (SIFS).
122 *
123 * \param sifs the SIFS duration
124 */
125 void SetSifs(Time sifs)
126 {
127 m_sifs = sifs;
128 }
129
130 /**
131 * Set the slot duration.
132 *
133 * \param slot the slot duration
134 */
135 void SetSlot(Time slot)
136 {
137 m_slot = slot;
138 }
139
140 /**
141 * Set the duration of EIFS - DIFS
142 *
143 * \param eifsNoDifs the duration of EIFS - DIFS
144 */
145 void SetEifsNoDifs(Time eifsNoDifs)
146 {
147 m_eifsNoDifs = eifsNoDifs;
148 }
149
150 private:
151 Time GetSifs() const override
152 {
153 return m_sifs;
154 }
155
156 Time GetSlot() const override
157 {
158 return m_slot;
159 }
160
161 Time GetEifsNoDifs() const override
162 {
163 return m_eifsNoDifs;
164 }
165
166 Time m_slot; //!< slot duration
167 Time m_sifs; //!< SIFS duration
168 Time m_eifsNoDifs; //!< EIFS duration minus a DIFS
169};
170
171/**
172 * \ingroup wifi-test
173 * \ingroup tests
174 *
175 * \brief Frame Exchange Manager Stub
176 */
177template <typename TxopType>
179{
180 public:
181 /**
182 * Constructor
183 *
184 * \param test the test channel access manager
185 */
187 : m_test(test)
188 {
189 }
190
191 /**
192 * Request the FrameExchangeManager to start a frame exchange sequence.
193 *
194 * \param dcf the channel access function that gained channel access. It is
195 * the DCF on non-QoS stations and an EDCA on QoS stations.
196 * \param allowedWidth the maximum allowed TX width in MHz
197 * \return true if a frame exchange sequence was started, false otherwise
198 */
199 bool StartTransmission(Ptr<Txop> dcf, uint16_t allowedWidth) override
200 {
201 dcf->NotifyChannelAccessed(0);
202 return true;
203 }
204
205 /// \copydoc ns3::FrameExchangeManager::NotifyInternalCollision
207 {
208 m_test->NotifyInternalCollision(DynamicCast<TxopTest<TxopType>>(txop));
209 }
210
211 /// \copydoc ns3::FrameExchangeManager::NotifySwitchingStartNow
212 void NotifySwitchingStartNow(Time duration) override
213 {
214 m_test->NotifyChannelSwitching();
215 }
216
217 private:
218 ChannelAccessManagerTest<TxopType>* m_test; //!< the test DCF/EDCA manager
219};
220
221/**
222 * \ingroup wifi-test
223 * \ingroup tests
224 *
225 * \brief Channel Access Manager Test
226 */
227template <typename TxopType>
229{
230 public:
232 void DoRun() override;
233
234 /**
235 * Notify access granted function
236 * \param i the index of the Txop
237 */
239 /**
240 * Notify internal collision function
241 * \param state the Txop
242 */
244 /**
245 * Generate backoff function
246 * \param i the index of the Txop
247 */
249 /**
250 * Notify channel switching function
251 */
253
254 private:
255 /**
256 * Start test function
257 * \param slotTime the slot time
258 * \param sifs the SIFS
259 * \param eifsNoDifsNoSifs the EIFS no DIFS no SIFS
260 * \param ackTimeoutValue the Ack timeout value
261 * \param chWidth the channel width in MHz
262 */
263 void StartTest(uint64_t slotTime,
264 uint64_t sifs,
265 uint64_t eifsNoDifsNoSifs,
266 uint32_t ackTimeoutValue = 20,
267 uint16_t chWidth = 20);
268 /**
269 * Add Txop function
270 * \param aifsn the AIFSN
271 */
272 void AddTxop(uint32_t aifsn);
273 /// End test function
274 void EndTest();
275 /**
276 * Expect internal collision function
277 * \param time the expected time
278 * \param nSlots the number of slots
279 * \param from the expected from
280 */
281 void ExpectInternalCollision(uint64_t time, uint32_t nSlots, uint32_t from);
282 /**
283 * Expect generate backoff function
284 * \param time the expected time
285 * \param nSlots the number of slots
286 * \param from the expected from
287 */
288 void ExpectBackoff(uint64_t time, uint32_t nSlots, uint32_t from);
289 /**
290 * Schedule a check that the channel access manager is busy or idle
291 * \param time the expected time
292 * \param busy whether the manager is expected to be busy
293 */
294 void ExpectBusy(uint64_t time, bool busy);
295 /**
296 * Perform check that channel access manager is busy or idle
297 * \param busy whether expected state is busy
298 */
299 void DoCheckBusy(bool busy);
300 /**
301 * Add receive OK event function
302 * \param at the event time
303 * \param duration the duration
304 */
305 void AddRxOkEvt(uint64_t at, uint64_t duration);
306 /**
307 * Add receive error event function for error at end of frame
308 * \param at the event time
309 * \param duration the duration
310 */
311 void AddRxErrorEvt(uint64_t at, uint64_t duration);
312 /**
313 * Add receive error event function for error during frame
314 * \param at the event time
315 * \param duration the duration
316 * \param timeUntilError the time after event time to force the error
317 */
318 void AddRxErrorEvt(uint64_t at, uint64_t duration, uint64_t timeUntilError);
319 /**
320 * Add receive inside SIFS event function
321 * \param at the event time
322 * \param duration the duration
323 */
324 void AddRxInsideSifsEvt(uint64_t at, uint64_t duration);
325 /**
326 * Add transmit event function
327 * \param at the event time
328 * \param duration the duration
329 */
330 void AddTxEvt(uint64_t at, uint64_t duration);
331 /**
332 * Add NAV reset function
333 * \param at the event time
334 * \param duration the duration
335 */
336 void AddNavReset(uint64_t at, uint64_t duration);
337 /**
338 * Add NAV start function
339 * \param at the event time
340 * \param duration the duration
341 */
342 void AddNavStart(uint64_t at, uint64_t duration);
343 /**
344 * Add Ack timeout reset function
345 * \param at the event time
346 */
347 void AddAckTimeoutReset(uint64_t at);
348 /**
349 * Add access function
350 * \param at the event time
351 * \param txTime the transmit time
352 * \param expectedGrantTime the expected grant time
353 * \param from the index of the requesting Txop
354 */
355 void AddAccessRequest(uint64_t at, uint64_t txTime, uint64_t expectedGrantTime, uint32_t from);
356 /**
357 * Add access request with Ack timeout
358 * \param at time to schedule DoAccessRequest event
359 * \param txTime the transmit time
360 * \param expectedGrantTime the expected grant time
361 * \param from the index of the requesting Txop
362 */
363 void AddAccessRequestWithAckTimeout(uint64_t at,
364 uint64_t txTime,
365 uint64_t expectedGrantTime,
366 uint32_t from);
367 /**
368 * Add access request with successful ack
369 * \param at time to schedule DoAccessRequest event
370 * \param txTime the transmit time
371 * \param expectedGrantTime the expected grant time
372 * \param ackDelay the delay of the Ack after txEnd
373 * \param from the index of the requesting Txop
374 */
375 void AddAccessRequestWithSuccessfulAck(uint64_t at,
376 uint64_t txTime,
377 uint64_t expectedGrantTime,
378 uint32_t ackDelay,
379 uint32_t from);
380 /**
381 * Add access request with successful Ack
382 * \param txTime the transmit time
383 * \param expectedGrantTime the expected grant time
384 * \param state TxopTest
385 */
386 void DoAccessRequest(uint64_t txTime,
387 uint64_t expectedGrantTime,
388 Ptr<TxopTest<TxopType>> state);
389 /**
390 * Add CCA busy event function
391 * \param at the event time
392 * \param duration the duration
393 * \param channelType the channel type
394 * \param per20MhzDurations vector that indicates for how long each 20 MHz subchannel is busy
395 */
396 void AddCcaBusyEvt(uint64_t at,
397 uint64_t duration,
399 const std::vector<Time>& per20MhzDurations = {});
400 /**
401 * Add switching event function
402 * \param at the event time
403 * \param duration the duration
404 */
405 void AddSwitchingEvt(uint64_t at, uint64_t duration);
406 /**
407 * Add receive start event function
408 * \param at the event time
409 * \param duration the duration
410 */
411 void AddRxStartEvt(uint64_t at, uint64_t duration);
412
413 typedef std::vector<Ptr<TxopTest<TxopType>>> TxopTests; //!< the TXOP tests typedef
414
415 Ptr<FrameExchangeManagerStub<TxopType>> m_feManager; //!< the Frame Exchange Manager stubbed
417 Ptr<SpectrumWifiPhy> m_phy; //!< the PHY object
418 TxopTests m_txop; //!< the vector of Txop test instances
419 uint32_t m_ackTimeoutValue; //!< the Ack timeout value
420};
421
422template <typename TxopType>
423void
424TxopTest<TxopType>::QueueTx(uint64_t txTime, uint64_t expectedGrantTime)
425{
426 m_expectedGrants.emplace_back(txTime, expectedGrantTime);
427}
428
429template <typename TxopType>
431 : m_test(test),
432 m_i(i)
433{
434}
435
436template <typename TxopType>
437void
439{
440 m_test = nullptr;
441 TxopType::DoDispose();
442}
443
444template <typename TxopType>
445void
447{
449 m_test->NotifyAccessGranted(m_i);
450}
451
452template <typename TxopType>
453void
455{
456 m_test->GenerateBackoff(m_i);
457}
458
459template <typename TxopType>
460bool
462{
463 return !m_expectedGrants.empty();
464}
465
466template <typename TxopType>
467void
469{
470}
471
472template <typename TxopType>
473void
475{
476}
477
478template <typename TxopType>
480 : TestCase("ChannelAccessManager")
481{
482}
483
484template <typename TxopType>
485void
487{
488 Ptr<TxopTest<TxopType>> state = m_txop[i];
489 NS_TEST_EXPECT_MSG_EQ(state->m_expectedGrants.empty(), false, "Have expected grants");
490 if (!state->m_expectedGrants.empty())
491 {
492 std::pair<uint64_t, uint64_t> expected = state->m_expectedGrants.front();
493 state->m_expectedGrants.pop_front();
495 MicroSeconds(expected.second),
496 "Expected access grant is now");
497 m_ChannelAccessManager->NotifyTxStartNow(MicroSeconds(expected.first));
498 m_ChannelAccessManager->NotifyAckTimeoutStartNow(
499 MicroSeconds(m_ackTimeoutValue + expected.first));
500 }
501}
502
503template <typename TxopType>
504void
505ChannelAccessManagerTest<TxopType>::AddTxEvt(uint64_t at, uint64_t duration)
506{
509 m_ChannelAccessManager,
510 MicroSeconds(duration));
511}
512
513template <typename TxopType>
514void
516{
517 NS_TEST_EXPECT_MSG_EQ(state->m_expectedInternalCollision.empty(),
518 false,
519 "Have expected internal collisions");
520 if (!state->m_expectedInternalCollision.empty())
521 {
522 struct TxopTest<TxopType>::ExpectedBackoff expected =
523 state->m_expectedInternalCollision.front();
524 state->m_expectedInternalCollision.pop_front();
525 NS_TEST_EXPECT_MSG_EQ(Simulator::Now(),
526 MicroSeconds(expected.at),
527 "Expected internal collision time is now");
528 state->StartBackoffNow(expected.nSlots, 0);
529 }
530}
531
532template <typename TxopType>
533void
535{
536 Ptr<TxopTest<TxopType>> state = m_txop[i];
537 NS_TEST_EXPECT_MSG_EQ(state->m_expectedBackoff.empty(), false, "Have expected backoffs");
538 if (!state->m_expectedBackoff.empty())
539 {
540 struct TxopTest<TxopType>::ExpectedBackoff expected = state->m_expectedBackoff.front();
541 state->m_expectedBackoff.pop_front();
542 NS_TEST_EXPECT_MSG_EQ(Simulator::Now(),
543 MicroSeconds(expected.at),
544 "Expected backoff is now");
545 state->StartBackoffNow(expected.nSlots, 0);
546 }
547}
548
549template <typename TxopType>
550void
551ChannelAccessManagerTest<TxopType>::NotifyChannelSwitching()
552{
553 for (auto& state : m_txop)
554 {
555 if (!state->m_expectedGrants.empty())
556 {
557 std::pair<uint64_t, uint64_t> expected = state->m_expectedGrants.front();
558 state->m_expectedGrants.pop_front();
560 MicroSeconds(expected.second),
561 "Expected grant is now");
562 }
563 state->Txop::GetLink(0).access = Txop::NOT_REQUESTED;
564 }
565}
566
567template <typename TxopType>
568void
570 uint32_t nSlots,
571 uint32_t from)
572{
573 Ptr<TxopTest<TxopType>> state = m_txop[from];
574 struct TxopTest<TxopType>::ExpectedBackoff col;
575 col.at = time;
576 col.nSlots = nSlots;
577 state->m_expectedInternalCollision.push_back(col);
578}
579
580template <typename TxopType>
581void
582ChannelAccessManagerTest<TxopType>::ExpectBackoff(uint64_t time, uint32_t nSlots, uint32_t from)
583{
584 Ptr<TxopTest<TxopType>> state = m_txop[from];
585 struct TxopTest<TxopType>::ExpectedBackoff backoff;
586 backoff.at = time;
587 backoff.nSlots = nSlots;
588 state->m_expectedBackoff.push_back(backoff);
589}
590
591template <typename TxopType>
592void
593ChannelAccessManagerTest<TxopType>::ExpectBusy(uint64_t time, bool busy)
594{
597 this,
598 busy);
599}
600
601template <typename TxopType>
602void
604{
605 NS_TEST_EXPECT_MSG_EQ(m_ChannelAccessManager->IsBusy(), busy, "Incorrect busy/idle state");
606}
607
608template <typename TxopType>
609void
611 uint64_t sifs,
612 uint64_t eifsNoDifsNoSifs,
613 uint32_t ackTimeoutValue,
614 uint16_t chWidth)
615{
616 m_ChannelAccessManager = CreateObject<ChannelAccessManagerStub>();
617 m_feManager = CreateObject<FrameExchangeManagerStub<TxopType>>(this);
618 m_ChannelAccessManager->SetupFrameExchangeManager(m_feManager);
619 m_ChannelAccessManager->SetSlot(MicroSeconds(slotTime));
620 m_ChannelAccessManager->SetSifs(MicroSeconds(sifs));
621 m_ChannelAccessManager->SetEifsNoDifs(MicroSeconds(eifsNoDifsNoSifs + sifs));
622 m_ackTimeoutValue = ackTimeoutValue;
623 // the purpose of the following operations is to initialize the last busy struct
624 // of the ChannelAccessManager. Indeed, InitLastBusyStructs(), which is called by
625 // SetupPhyListener(), requires an attached PHY to determine the channel types
626 // to initialize
627 m_phy = CreateObject<SpectrumWifiPhy>();
628 m_phy->SetInterferenceHelper(CreateObject<InterferenceHelper>());
629 m_phy->AddChannel(CreateObject<MultiModelSpectrumChannel>());
630 m_phy->SetOperatingChannel(WifiPhy::ChannelTuple{0, chWidth, WIFI_PHY_BAND_UNSPECIFIED, 0});
631 m_phy->ConfigureStandard(WIFI_STANDARD_80211ac); // required to use 160 MHz channels
632 m_ChannelAccessManager->SetupPhyListener(m_phy);
633}
634
635template <typename TxopType>
636void
638{
639 Ptr<TxopTest<TxopType>> txop = CreateObject<TxopTest<TxopType>>(this, m_txop.size());
640 m_txop.push_back(txop);
641 m_ChannelAccessManager->Add(txop);
642 // the following causes the creation of a link for the txop object
643 auto mac = CreateObjectWithAttributes<AdhocWifiMac>(
644 "Txop",
645 PointerValue(CreateObjectWithAttributes<Txop>("AcIndex", StringValue("AC_BE_NQOS"))));
646 mac->SetWifiPhys({nullptr});
647 txop->SetWifiMac(mac);
648 txop->SetAifsn(aifsn);
649}
650
651template <typename TxopType>
652void
654{
656
657 for (auto i = m_txop.begin(); i != m_txop.end(); i++)
658 {
659 Ptr<TxopTest<TxopType>> state = *i;
660 NS_TEST_EXPECT_MSG_EQ(state->m_expectedGrants.empty(), true, "Have no expected grants");
661 NS_TEST_EXPECT_MSG_EQ(state->m_expectedInternalCollision.empty(),
662 true,
663 "Have no internal collisions");
664 NS_TEST_EXPECT_MSG_EQ(state->m_expectedBackoff.empty(), true, "Have no expected backoffs");
665 state->Dispose();
666 state = nullptr;
667 }
668 m_txop.clear();
669
670 m_ChannelAccessManager->RemovePhyListener(m_phy);
671 m_phy->Dispose();
672 m_ChannelAccessManager->Dispose();
673 m_ChannelAccessManager = nullptr;
674 m_feManager = nullptr;
676}
677
678template <typename TxopType>
679void
681{
684 m_ChannelAccessManager,
685 MicroSeconds(duration));
686 Simulator::Schedule(MicroSeconds(at + duration) - Now(),
688 m_ChannelAccessManager);
689}
690
691template <typename TxopType>
692void
694{
697 m_ChannelAccessManager,
698 MicroSeconds(duration));
699}
700
701template <typename TxopType>
702void
704{
707 m_ChannelAccessManager,
708 MicroSeconds(duration));
709 Simulator::Schedule(MicroSeconds(at + duration) - Now(),
711 m_ChannelAccessManager);
712}
713
714template <typename TxopType>
715void
717 uint64_t duration,
718 uint64_t timeUntilError)
719{
722 m_ChannelAccessManager,
723 MicroSeconds(duration));
724 Simulator::Schedule(MicroSeconds(at + timeUntilError) - Now(),
726 m_ChannelAccessManager);
727 Simulator::Schedule(MicroSeconds(at + timeUntilError) - Now(),
729 m_ChannelAccessManager,
730 MicroSeconds(duration - timeUntilError),
732 std::vector<Time>{});
733}
734
735template <typename TxopType>
736void
738{
741 m_ChannelAccessManager,
742 MicroSeconds(duration));
743}
744
745template <typename TxopType>
746void
748{
751 m_ChannelAccessManager,
752 MicroSeconds(duration));
753}
754
755template <typename TxopType>
756void
758{
761 m_ChannelAccessManager);
762}
763
764template <typename TxopType>
765void
767 uint64_t txTime,
768 uint64_t expectedGrantTime,
769 uint32_t from)
770{
771 AddAccessRequestWithSuccessfulAck(at, txTime, expectedGrantTime, 0, from);
772}
773
774template <typename TxopType>
775void
777 uint64_t txTime,
778 uint64_t expectedGrantTime,
779 uint32_t from)
780{
783 this,
784 txTime,
785 expectedGrantTime,
786 m_txop[from]);
787}
788
789template <typename TxopType>
790void
792 uint64_t txTime,
793 uint64_t expectedGrantTime,
794 uint32_t ackDelay,
795 uint32_t from)
796{
797 NS_ASSERT(ackDelay < m_ackTimeoutValue);
800 this,
801 txTime,
802 expectedGrantTime,
803 m_txop[from]);
804 AddAckTimeoutReset(expectedGrantTime + txTime + ackDelay);
805}
806
807template <typename TxopType>
808void
810 uint64_t expectedGrantTime,
811 Ptr<TxopTest<TxopType>> state)
812{
813 auto hadFramesToTransmit = state->HasFramesToTransmit(SINGLE_LINK_OP_ID);
814 state->QueueTx(txTime, expectedGrantTime);
815 if (m_ChannelAccessManager->NeedBackoffUponAccess(state, hadFramesToTransmit, true))
816 {
817 state->GenerateBackoff(0);
818 }
819 m_ChannelAccessManager->RequestAccess(state);
820}
821
822template <typename TxopType>
823void
825 uint64_t duration,
826 WifiChannelListType channelType,
827 const std::vector<Time>& per20MhzDurations)
828{
831 m_ChannelAccessManager,
832 MicroSeconds(duration),
833 channelType,
834 per20MhzDurations);
835}
836
837template <typename TxopType>
838void
840{
843 m_ChannelAccessManager,
844 nullptr,
845 MicroSeconds(duration));
846}
847
848template <typename TxopType>
849void
851{
854 m_ChannelAccessManager,
855 MicroSeconds(duration));
856}
857
858/*
859 * Specialization of DoRun () method for DCF
860 */
861template <>
862void
864{
865 // DCF immediate access (no backoff)
866 // 1 4 5 6 8 11 12
867 // | sifs | aifsn | tx | idle | sifs | aifsn | tx |
868 //
869 StartTest(1, 3, 10);
870 AddTxop(1);
871 AddAccessRequest(1, 1, 5, 0);
872 AddAccessRequest(8, 2, 12, 0);
873 EndTest();
874 // Check that receiving inside SIFS shall be cancelled properly:
875 // 1 4 5 6 9 10 14 17 18
876 // | sifs | aifsn | tx | sifs | ack | idle | sifs | aifsn | tx |
877 // |
878 // 7 start rx
879 //
880
881 StartTest(1, 3, 10);
882 AddTxop(1);
883 AddAccessRequest(1, 1, 5, 0);
884 AddRxInsideSifsEvt(7, 10);
885 AddTxEvt(9, 1);
886 AddAccessRequest(14, 2, 18, 0);
887 EndTest();
888 // The test below mainly intends to test the case where the medium
889 // becomes busy in the middle of a backoff slot: the backoff counter
890 // must not be decremented for this backoff slot. This is the case
891 // below for the backoff slot starting at time 78us.
892 //
893 // 20 60 66 70 74 78 80 100 106 110 114 118
894 // 120
895 // | rx | sifs | aifsn | bslot0 | bslot1 | | rx | sifs | aifsn | bslot2 |
896 // bslot3 | tx |
897 // |
898 // 30 request access. backoff slots: 4
899
900 StartTest(4, 6, 10);
901 AddTxop(1);
902 AddRxOkEvt(20, 40);
903 AddRxOkEvt(80, 20);
904 AddAccessRequest(30, 2, 118, 0);
905 ExpectBackoff(30, 4, 0); // backoff: 4 slots
906 EndTest();
907 // Test the case where the backoff slots is zero.
908 //
909 // 20 60 66 70 72
910 // | rx | sifs | aifsn | tx |
911 // |
912 // 30 request access. backoff slots: 0
913
914 StartTest(4, 6, 10);
915 AddTxop(1);
916 AddRxOkEvt(20, 40);
917 AddAccessRequest(30, 2, 70, 0);
918 ExpectBackoff(30, 0, 0); // backoff: 0 slots
919 EndTest();
920 // Test shows when two frames are received without interval between
921 // them:
922 // 20 60 100 106 110 112
923 // | rx | rx |sifs | aifsn | tx |
924 // |
925 // 30 request access. backoff slots: 0
926
927 StartTest(4, 6, 10);
928 AddTxop(1);
929 AddRxOkEvt(20, 40);
930 AddRxOkEvt(60, 40);
931 AddAccessRequest(30, 2, 110, 0);
932 ExpectBackoff(30, 0, 0); // backoff: 0 slots
933 EndTest();
934
935 // Requesting access within SIFS interval (DCF immediate access)
936 //
937 // 20 60 62 68 72
938 // | rx | idle | sifs | aifsn | tx |
939 //
940 StartTest(4, 6, 10);
941 AddTxop(1);
942 AddRxOkEvt(20, 40);
943 AddAccessRequest(62, 2, 72, 0);
944 EndTest();
945
946 // Requesting access after DIFS (DCF immediate access)
947 //
948 // 20 60 70 76 80
949 // | rx | idle | sifs | aifsn | tx |
950 //
951 StartTest(4, 6, 10);
952 AddTxop(1);
953 AddRxOkEvt(20, 40);
954 AddAccessRequest(70, 2, 80, 0);
955 EndTest();
956
957 // Test an EIFS
958 //
959 // 20 60 66 76 86 90 94 98 102 106
960 // | rx | sifs | acktxttime | sifs + aifsn | bslot0 | bslot1 | bslot2 | bslot3 | tx |
961 // | | <------eifs------>|
962 // 30 request access. backoff slots: 4
963 StartTest(4, 6, 10);
964 AddTxop(1);
965 AddRxErrorEvt(20, 40);
966 AddAccessRequest(30, 2, 102, 0);
967 ExpectBackoff(30, 4, 0); // backoff: 4 slots
968 EndTest();
969
970 // Test DCF immediate access after an EIFS (EIFS is greater)
971 //
972 // 20 60 66 76 86
973 // | <----+-eifs------>|
974 // | rx | sifs | acktxttime | sifs + aifsn | tx |
975 // | sifs + aifsn |
976 // request access 70 80
977 StartTest(4, 6, 10);
978 AddTxop(1);
979 AddRxErrorEvt(20, 40);
980 AddAccessRequest(70, 2, 86, 0);
981 EndTest();
982
983 // Test that channel stays busy for first frame's duration after Rx error
984 //
985 // 20 60
986 // | rx |
987 // |
988 // 40 force Rx error
989 StartTest(4, 6, 10);
990 AddTxop(1);
991 AddRxErrorEvt(20, 40, 20); // At time 20, start reception for 40, but force error 20 into frame
992 ExpectBusy(41, true); // channel should remain busy for remaining duration
993 ExpectBusy(59, true);
994 ExpectBusy(61, false);
995 EndTest();
996
997 // Test an EIFS which is interrupted by a successful transmission.
998 //
999 // 20 60 66 69 75 81 85 89 93 97 101 103
1000 // | rx | sifs | | rx | sifs | aifsn | bslot0 | bslot1 | bslot2 | bslot3 | tx |
1001 // | | <--eifs-->|
1002 // 30 request access. backoff slots: 4
1003 StartTest(4, 6, 10);
1004 AddTxop(1);
1005 AddRxErrorEvt(20, 40);
1006 AddAccessRequest(30, 2, 101, 0);
1007 ExpectBackoff(30, 4, 0); // backoff: 4 slots
1008 AddRxOkEvt(69, 6);
1009 EndTest();
1010
1011 // Test two DCFs which suffer an internal collision. the first DCF has a higher
1012 // priority than the second DCF.
1013 //
1014 // 20 60 66 70 74 78 88
1015 // DCF0 | rx | sifs | aifsn | bslot0 | bslot1 | tx |
1016 // DCF1 | rx | sifs | aifsn | aifsn | aifsn | | sifs | aifsn | aifsn | aifsn |
1017 // bslot | tx |
1018 // 94 98 102 106
1019 // 110 112
1020 StartTest(4, 6, 10);
1021 AddTxop(1); // high priority DCF
1022 AddTxop(3); // low priority DCF
1023 AddRxOkEvt(20, 40);
1024 AddAccessRequest(30, 10, 78, 0);
1025 ExpectBackoff(30, 2, 0); // backoff: 2 slot
1026 AddAccessRequest(40, 2, 110, 1);
1027 ExpectBackoff(40, 0, 1); // backoff: 0 slot
1028 ExpectInternalCollision(78, 1, 1); // backoff: 1 slot
1029 EndTest();
1030
1031 // Test of AckTimeout handling: First queue requests access and ack procedure fails,
1032 // inside the Ack timeout second queue with higher priority requests access.
1033 //
1034 // 20 26 34 54 74 80
1035 // DCF1 - low | sifs | aifsn | tx | Ack timeout | sifs | |
1036 // DCF0 - high | | | sifs | tx |
1037 // ^ request access
1038 StartTest(4, 6, 10);
1039 AddTxop(0); // high priority DCF
1040 AddTxop(2); // low priority DCF
1041 AddAccessRequestWithAckTimeout(20, 20, 34, 1);
1042 AddAccessRequest(64, 10, 80, 0);
1043 EndTest();
1044
1045 // Test of AckTimeout handling:
1046 //
1047 // First queue requests access and Ack is 2 us delayed (got Ack interval at the picture),
1048 // inside this interval second queue with higher priority requests access.
1049 //
1050 // 20 26 34 54 56 62
1051 // DCF1 - low | sifs | aifsn | tx | got Ack | sifs | |
1052 // DCF0 - high | | | sifs | tx |
1053 // ^ request access
1054 StartTest(4, 6, 10);
1055 AddTxop(0); // high priority DCF
1056 AddTxop(2); // low priority DCF
1057 AddAccessRequestWithSuccessfulAck(20, 20, 34, 2, 1);
1058 AddAccessRequest(55, 10, 62, 0);
1059 EndTest();
1060
1061 // Repeat the same but with one queue:
1062 // 20 26 34 54 60 62 68 76 80
1063 // DCF0 | sifs | aifsn | tx | sifs | Ack | sifs | aifsn | bslot0 | tx |
1064 // ^ request access
1065 StartTest(4, 6, 10);
1066 AddTxop(2);
1067 AddAccessRequest(20, 20, 34, 0);
1068 AddRxOkEvt(60, 2); // Ack
1069 AddAccessRequest(61, 10, 80, 0);
1070 ExpectBackoff(61, 1, 0); // 1 slot
1071 EndTest();
1072
1073 // test simple NAV count. This scenario models a simple Data+Ack handshake
1074 // where the data rate used for the Ack is higher than expected by the Data source
1075 // so, the data exchange completes before the end of NAV.
1076 StartTest(4, 6, 10);
1077 AddTxop(1);
1078 AddRxOkEvt(20, 40);
1079 AddNavStart(60, 15);
1080 AddRxOkEvt(66, 5);
1081 AddNavStart(71, 0);
1082 AddAccessRequest(30, 10, 93, 0);
1083 ExpectBackoff(30, 2, 0); // backoff: 2 slots
1084 EndTest();
1085
1086 // test more complex NAV handling by a CF-poll. This scenario models a
1087 // simple Data+Ack handshake interrupted by a CF-poll which resets the
1088 // NAV counter.
1089 StartTest(4, 6, 10);
1090 AddTxop(1);
1091 AddRxOkEvt(20, 40);
1092 AddNavStart(60, 15);
1093 AddRxOkEvt(66, 5);
1094 AddNavReset(71, 2);
1095 AddAccessRequest(30, 10, 91, 0);
1096 ExpectBackoff(30, 2, 0); // backoff: 2 slots
1097 EndTest();
1098
1099 // 20 60 80 86 94
1100 // | rx | idle | sifs | aifsn | tx |
1101 // ^ request access
1102 StartTest(4, 6, 10);
1103 AddTxop(2);
1104 AddRxOkEvt(20, 40);
1105 AddAccessRequest(80, 10, 94, 0);
1106 EndTest();
1107
1108 StartTest(4, 6, 10);
1109 AddTxop(2);
1110 AddRxOkEvt(20, 40);
1111 AddRxOkEvt(78, 8);
1112 AddAccessRequest(30, 50, 108, 0);
1113 ExpectBackoff(30, 3, 0); // backoff: 3 slots
1114 EndTest();
1115
1116 // Channel switching tests
1117
1118 // 0 20 21 24 25 26
1119 // | switching | idle | sifs | aifsn | tx |
1120 // ^ access request.
1121 StartTest(1, 3, 10);
1122 AddTxop(1);
1123 AddSwitchingEvt(0, 20);
1124 AddAccessRequest(21, 1, 25, 0);
1125 EndTest();
1126
1127 // 20 40 50 53 54 55 56 57
1128 // | switching | busy | sifs | aifsn | bslot0 | bslot 1 | tx |
1129 // | |
1130 // 30 busy. 45 access request.
1131 //
1132 StartTest(1, 3, 10);
1133 AddTxop(1);
1134 AddSwitchingEvt(20, 20);
1135 AddCcaBusyEvt(30, 20);
1136 ExpectBackoff(45, 2, 0); // backoff: 2 slots
1137 AddAccessRequest(45, 1, 56, 0);
1138 EndTest();
1139
1140 // 20 30 50 51 54 55 56
1141 // | rx | switching | idle | sifs | aifsn | tx |
1142 // ^ access request.
1143 //
1144 StartTest(1, 3, 10);
1145 AddTxop(1);
1146 AddRxStartEvt(20, 40);
1147 AddSwitchingEvt(30, 20);
1148 AddAccessRequest(51, 1, 55, 0);
1149 EndTest();
1150
1151 // 20 30 50 51 54 55 56
1152 // | busy | switching | idle | sifs | aifsn | tx |
1153 // ^ access request.
1154 //
1155 StartTest(1, 3, 10);
1156 AddTxop(1);
1157 AddCcaBusyEvt(20, 40);
1158 AddSwitchingEvt(30, 20);
1159 AddAccessRequest(51, 1, 55, 0);
1160 EndTest();
1161
1162 // 20 30 50 51 54 55 56
1163 // | nav | switching | idle | sifs | aifsn | tx |
1164 // ^ access request.
1165 //
1166 StartTest(1, 3, 10);
1167 AddTxop(1);
1168 AddNavStart(20, 40);
1169 AddSwitchingEvt(30, 20);
1170 AddAccessRequest(51, 1, 55, 0);
1171 EndTest();
1172
1173 // 20 23 24 44 54 59 60 63 64 65
1174 // | sifs | aifsn | tx | Ack timeout | switching | idle | sifs | aifsn | tx |
1175 // | |
1176 // 49 access request. ^ access request.
1177 //
1178 StartTest(1, 3, 10);
1179 AddTxop(1);
1180 AddAccessRequestWithAckTimeout(20, 20, 24, 0);
1181 AddAccessRequest(49, 1, 54, 0);
1182 AddSwitchingEvt(54, 5);
1183 AddAccessRequest(60, 1, 64, 0);
1184 EndTest();
1185
1186 // 20 60 66 70 74 78 80 100 101 107 111 113
1187 // | rx | sifs | aifsn | bslot0 | bslot1 | | switching | idle | sifs | aifsn | tx |
1188 // | |
1189 // 30 access request. ^ access request.
1190 //
1191 StartTest(4, 6, 10);
1192 AddTxop(1);
1193 AddRxOkEvt(20, 40);
1194 AddAccessRequest(30, 2, 80, 0);
1195 ExpectBackoff(30, 4, 0); // backoff: 4 slots
1196 AddSwitchingEvt(80, 20);
1197 AddAccessRequest(101, 2, 111, 0);
1198 EndTest();
1199}
1200
1201/*
1202 * Specialization of DoRun () method for EDCA
1203 */
1204template <>
1205void
1207{
1208 // Check alignment at slot boundary after successful reception (backoff = 0).
1209 // Also, check that CCA BUSY on a secondary channel does not affect channel access:
1210 // 20 50 56 60 80
1211 // | cca_busy |
1212 // | rx | sifs | aifsn | tx |
1213 // |
1214 // 52 request access
1215 StartTest(4, 6, 10, 20, 40);
1216 AddTxop(1);
1217 AddRxOkEvt(20, 30);
1218 AddCcaBusyEvt(50, 10, WIFI_CHANLIST_SECONDARY);
1219 AddAccessRequest(52, 20, 60, 0);
1220 EndTest();
1221
1222 // Check alignment at slot boundary after successful reception (backoff = 0).
1223 // Also, check that CCA BUSY on a secondary channel does not affect channel access:
1224 // 20 50 56 60 80
1225 // | cca_busy |
1226 // | rx | sifs | aifsn | tx |
1227 // |
1228 // 58 request access
1229 StartTest(4, 6, 10, 20, 80);
1230 AddTxop(1);
1231 AddRxOkEvt(20, 30);
1232 AddCcaBusyEvt(50, 10, WIFI_CHANLIST_SECONDARY);
1233 AddAccessRequest(58, 20, 60, 0);
1234 EndTest();
1235
1236 // Check alignment at slot boundary after successful reception (backoff = 0).
1237 // Also, check that CCA BUSY on a secondary channel does not affect channel access:
1238 // 20 50 56 60 64 84
1239 // | cca_busy |
1240 // | rx | sifs | aifsn | idle | tx |
1241 // |
1242 // 62 request access
1243 StartTest(4, 6, 10, 20, 80);
1244 AddTxop(1);
1245 AddRxOkEvt(20, 30);
1246 AddCcaBusyEvt(50, 14, WIFI_CHANLIST_SECONDARY40);
1247 AddAccessRequest(62, 20, 64, 0);
1248 EndTest();
1249
1250 // Check alignment at slot boundary after failed reception (backoff = 0).
1251 // Also, check that CCA BUSY on a secondary channel does not affect channel access:
1252 // 20 50 56 66 76 96
1253 // | cca_busy |
1254 // | | <------eifs------>| | |
1255 // | rx | sifs | acktxttime | sifs + aifsn | tx |
1256 // |
1257 // 55 request access
1258 StartTest(4, 6, 10, 20, 160);
1259 AddTxop(1);
1260 AddRxErrorEvt(20, 30);
1261 AddCcaBusyEvt(50, 26, WIFI_CHANLIST_SECONDARY);
1262 AddAccessRequest(55, 20, 76, 0);
1263 EndTest();
1264
1265 // Check alignment at slot boundary after failed reception (backoff = 0).
1266 // Also, check that CCA BUSY on a secondary channel does not affect channel access:
1267 // 20 50 56 66 76 96
1268 // | cca_busy |
1269 // | | <------eifs------>| | |
1270 // | rx | sifs | acktxttime | sifs + aifsn | tx |
1271 // |
1272 // 70 request access
1273 StartTest(4, 6, 10, 20, 160);
1274 AddTxop(1);
1275 AddRxErrorEvt(20, 30);
1276 AddCcaBusyEvt(50, 26, WIFI_CHANLIST_SECONDARY40);
1277 AddAccessRequest(70, 20, 76, 0);
1278 EndTest();
1279
1280 // Check alignment at slot boundary after failed reception (backoff = 0).
1281 // Also, check that CCA BUSY on a secondary channel does not affect channel access:
1282 // 20 50 56 66 76 84
1283 // | cca_busy |
1284 // | | <------eifs------>| | |
1285 // | rx | sifs | acktxttime | sifs + aifsn | idle | tx |
1286 // |
1287 // 82 request access
1288 StartTest(4, 6, 10, 20, 160);
1289 AddTxop(1);
1290 AddRxErrorEvt(20, 30);
1291 AddCcaBusyEvt(50, 34, WIFI_CHANLIST_SECONDARY80);
1292 AddAccessRequest(82, 20, 84, 0);
1293 EndTest();
1294
1295 // Check backoff decrement at slot boundaries. Medium idle during backoff
1296 // 20 50 56 60 64 68 72 76 96
1297 // | rx | sifs | aifsn | idle | idle | idle | idle | tx |
1298 // | | | | |
1299 // 30 request access. decrement decrement decrement decrement
1300 // backoff slots: 4 slots: 3 slots: 2 slots: 1 slots: 0
1301 StartTest(4, 6, 10);
1302 AddTxop(1);
1303 AddRxOkEvt(20, 30);
1304 AddAccessRequest(30, 20, 76, 0);
1305 ExpectBackoff(30, 4, 0);
1306 EndTest();
1307
1308 // Check backoff decrement at slot boundaries. Medium becomes busy during backoff
1309 // 20 50 56 60 61 71 77 81 85 87 97 103
1310 // 107 127
1311 // | rx | sifs | aifsn | idle | rx | sifs | aifsn | idle | idle | rx | sifs |
1312 // aifsn | tx |
1313 // | | | |
1314 // 30 request access. decrement decrement decrement
1315 // backoff slots: 3 slots: 2 slots: 1 slots: 0
1316 StartTest(4, 6, 10);
1317 AddTxop(1);
1318 AddRxOkEvt(20, 30);
1319 AddRxOkEvt(61, 10);
1320 AddRxOkEvt(87, 10);
1321 AddAccessRequest(30, 20, 107, 0);
1322 ExpectBackoff(30, 3, 0);
1323 EndTest();
1324}
1325
1326/**
1327 * \ingroup wifi-test
1328 * \ingroup tests
1329 *
1330 * \brief Test the calculation of the largest idle primary channel performed by
1331 * ChannelAccessManager::GetLargestIdlePrimaryChannel().
1332 *
1333 * In every test, the ChannelAccessManager is notified of a CCA_BUSY period and
1334 * subsequently of the start of RX. The value returned by GetLargestIdlePrimaryChannel()
1335 * is checked at different times and for different intervals. All the possible
1336 * combinations of operating channel width and busy channel type are tested.
1337 */
1339{
1340 public:
1343
1344 private:
1345 void DoRun() override;
1346
1347 /**
1348 * Test a specific combination of operating channel width and busy channel type.
1349 *
1350 * \param chWidth the operating channel width
1351 * \param busyChannel the busy channel type
1352 */
1353 void RunOne(uint16_t chWidth, WifiChannelListType busyChannel);
1354
1355 Ptr<ChannelAccessManager> m_cam; //!< channel access manager
1357};
1358
1360 : TestCase("Check calculation of the largest idle primary channel")
1361{
1362}
1363
1364void
1366{
1367 /**
1368 * < Interval1 >< Interval2 >
1369 * < Interval3 >
1370 * < Interval4> < Interval5 >
1371 * < Interval6 >
1372 * --------|-------^--------------^------------^-----^------^------------^---
1373 * P20 | | | | | RX | |
1374 * --------|-------|-----IDLE-----|----IDLE----|-----|------|------------|---
1375 * S20 | | | | | | IDLE |
1376 * --------|-------v--------------v------------v-----|------|------------|---
1377 * S40 | | CCA_BUSY | IDLE | | |
1378 * --------|-----------------------------|-----------|------|------------|---
1379 * S80 | | | | |
1380 * --------|----------------------|------v-----|-----v------|------------|---
1381 * start Check times: t1 t2 t3 t5
1382 * t4 t6
1383 */
1384
1385 Time start = Simulator::Now();
1386
1387 // After 1ms, we are notified of CCA_BUSY for 1ms on the given channel
1388 Time ccaBusyStartDelay = MilliSeconds(1);
1389 Time ccaBusyDuration = MilliSeconds(1);
1390 Simulator::Schedule(ccaBusyStartDelay,
1392 m_cam,
1393 ccaBusyDuration,
1394 busyChannel,
1395 std::vector<Time>(chWidth == 20 ? 0 : chWidth / 20, Seconds(0)));
1396
1397 // During any interval ending within CCA_BUSY period, the idle channel is the
1398 // primary channel contiguous to the busy secondary channel, if the busy channel
1399 // is a secondary channel, or there is no idle channel, otherwise.
1400 uint16_t idleWidth = (busyChannel == WifiChannelListType::WIFI_CHANLIST_PRIMARY)
1401 ? 0
1402 : ((1 << (busyChannel - 1)) * 20);
1403
1404 Time checkTime1 = start + ccaBusyStartDelay + ccaBusyDuration / 2;
1405 Simulator::Schedule(checkTime1 - start, [=, this]() {
1406 Time interval1 = (ccaBusyStartDelay + ccaBusyDuration) / 2;
1408 idleWidth,
1409 "Incorrect width of the idle channel in an interval "
1410 << "ending within CCA_BUSY (channel width: " << chWidth
1411 << " MHz, busy channel: " << busyChannel << ")");
1412 });
1413
1414 // During any interval starting within CCA_BUSY period, the idle channel is the
1415 // same as the previous case
1416 Time ccaBusyRxInterval = MilliSeconds(1);
1417 Time checkTime2 = start + ccaBusyStartDelay + ccaBusyDuration + ccaBusyRxInterval / 2;
1418 Simulator::Schedule(checkTime2 - start, [=, this]() {
1419 Time interval2 = (ccaBusyDuration + ccaBusyRxInterval) / 2;
1421 idleWidth,
1422 "Incorrect width of the idle channel in an interval "
1423 << "starting within CCA_BUSY (channel width: " << chWidth
1424 << " MHz, busy channel: " << busyChannel << ")");
1425 });
1426
1427 // Notify RX start
1428 Time rxDuration = MilliSeconds(1);
1429 Simulator::Schedule(ccaBusyStartDelay + ccaBusyDuration + ccaBusyRxInterval,
1431 m_cam,
1432 rxDuration);
1433
1434 // At RX end, we check the status of the channel during an interval immediately
1435 // preceding RX start and overlapping the CCA_BUSY period.
1436 Time checkTime3 = start + ccaBusyStartDelay + ccaBusyDuration + ccaBusyRxInterval + rxDuration;
1437 Simulator::Schedule(checkTime3 - start, [=, this]() {
1438 Time interval3 = ccaBusyDuration / 2 + ccaBusyRxInterval;
1439 Time end3 = checkTime3 - rxDuration;
1441 idleWidth,
1442 "Incorrect width of the idle channel in an interval "
1443 << "preceding RX start and overlapping CCA_BUSY "
1444 << "(channel width: " << chWidth
1445 << " MHz, busy channel: " << busyChannel << ")");
1446 });
1447
1448 // At RX end, we check the status of the channel during the interval following
1449 // the CCA_BUSY period and preceding RX start. The entire operating channel is idle.
1450 const Time& checkTime4 = checkTime3;
1451 Simulator::Schedule(checkTime4 - start, [=, this]() {
1452 const Time& interval4 = ccaBusyRxInterval;
1453 Time end4 = checkTime4 - rxDuration;
1455 chWidth,
1456 "Incorrect width of the idle channel in the interval "
1457 << "following CCA_BUSY and preceding RX start (channel "
1458 << "width: " << chWidth << " MHz, busy channel: " << busyChannel
1459 << ")");
1460 });
1461
1462 // After RX end, the entire operating channel is idle if the interval does not
1463 // overlap the RX period
1464 Time interval5 = MilliSeconds(1);
1465 Time checkTime5 = checkTime4 + interval5;
1466 Simulator::Schedule(checkTime5 - start, [=, this]() {
1468 chWidth,
1469 "Incorrect width of the idle channel in an interval "
1470 << "following RX end (channel width: " << chWidth
1471 << " MHz, busy channel: " << busyChannel << ")");
1472 });
1473
1474 // After RX end, no channel is idle if the interval overlaps the RX period
1475 const Time& checkTime6 = checkTime5;
1476 Simulator::Schedule(checkTime6 - start, [=, this]() {
1477 Time interval6 = interval5 + rxDuration / 2;
1479 0,
1480 "Incorrect width of the idle channel in an interval "
1481 << "overlapping RX (channel width: " << chWidth
1482 << " MHz, busy channel: " << busyChannel << ")");
1483 });
1484}
1485
1486void
1488{
1489 m_cam = CreateObject<ChannelAccessManager>();
1490 uint16_t delay = 0;
1491 uint8_t channel = 0;
1492 std::list<WifiChannelListType> busyChannels;
1493
1494 for (uint16_t chWidth : {20, 40, 80, 160})
1495 {
1496 busyChannels.push_back(static_cast<WifiChannelListType>(channel));
1497
1498 for (const auto busyChannel : busyChannels)
1499 {
1500 Simulator::Schedule(Seconds(delay), [=, this]() {
1501 // reset PHY
1502 if (m_phy)
1503 {
1505 m_phy->Dispose();
1506 }
1507 // create a new PHY operating on a channel of the current width
1508 m_phy = CreateObject<SpectrumWifiPhy>();
1509 m_phy->SetInterferenceHelper(CreateObject<InterferenceHelper>());
1510 m_phy->AddChannel(CreateObject<MultiModelSpectrumChannel>());
1514 // call SetupPhyListener to initialize the ChannelAccessManager
1515 // last busy structs
1517 // run the tests
1518 RunOne(chWidth, busyChannel);
1519 });
1520 delay++;
1521 }
1522 channel++;
1523 }
1524
1527 m_phy->Dispose();
1528 m_cam->Dispose();
1530}
1531
1532/**
1533 * \ingroup wifi-test
1534 * \ingroup tests
1535 *
1536 * \brief Txop Test Suite
1537 */
1539{
1540 public:
1541 TxopTestSuite();
1542};
1543
1545 : TestSuite("wifi-devices-dcf", Type::UNIT)
1546{
1547 AddTestCase(new ChannelAccessManagerTest<Txop>, TestCase::Duration::QUICK);
1548}
1549
1551
1552/**
1553 * \ingroup wifi-test
1554 * \ingroup tests
1555 *
1556 * \brief QosTxop Test Suite
1557 */
1559{
1560 public:
1562};
1563
1565 : TestSuite("wifi-devices-edca", Type::UNIT)
1566{
1567 AddTestCase(new ChannelAccessManagerTest<QosTxop>, TestCase::Duration::QUICK);
1568}
1569
1571
1572/**
1573 * \ingroup wifi-test
1574 * \ingroup tests
1575 *
1576 * \brief ChannelAccessManager Test Suite
1577 */
1579{
1580 public:
1582};
1583
1585 : TestSuite("wifi-channel-access-manager", Type::UNIT)
1586{
1587 AddTestCase(new LargestIdlePrimaryChannelTest, TestCase::Duration::QUICK);
1588}
1589
static ChannelAccessManagerTestSuite g_camTestSuite
static TxopTestSuite g_dcfTestSuite
static QosTxopTestSuite g_edcaTestSuite
Time GetEifsNoDifs() const override
Return the EIFS duration minus a DIFS.
void SetEifsNoDifs(Time eifsNoDifs)
Set the duration of EIFS - DIFS.
void SetSlot(Time slot)
Set the slot duration.
Time GetSlot() const override
Return the slot duration for this PHY.
Time GetSifs() const override
Return the Short Interframe Space (SIFS) for this PHY.
void SetSifs(Time sifs)
Set the Short Interframe Space (SIFS).
Time m_eifsNoDifs
EIFS duration minus a DIFS.
Channel Access Manager Test.
void AddAccessRequestWithSuccessfulAck(uint64_t at, uint64_t txTime, uint64_t expectedGrantTime, uint32_t ackDelay, uint32_t from)
Add access request with successful ack.
void AddAckTimeoutReset(uint64_t at)
Add Ack timeout reset function.
void NotifyInternalCollision(Ptr< TxopTest< TxopType > > state)
Notify internal collision function.
void AddRxOkEvt(uint64_t at, uint64_t duration)
Add receive OK event function.
void AddRxStartEvt(uint64_t at, uint64_t duration)
Add receive start event function.
uint32_t m_ackTimeoutValue
the Ack timeout value
void AddAccessRequestWithAckTimeout(uint64_t at, uint64_t txTime, uint64_t expectedGrantTime, uint32_t from)
Add access request with Ack timeout.
void GenerateBackoff(uint32_t i)
Generate backoff function.
void NotifyAccessGranted(uint32_t i)
Notify access granted function.
std::vector< Ptr< TxopTest< TxopType > > > TxopTests
the TXOP tests typedef
void StartTest(uint64_t slotTime, uint64_t sifs, uint64_t eifsNoDifsNoSifs, uint32_t ackTimeoutValue=20, uint16_t chWidth=20)
Start test function.
void ExpectBackoff(uint64_t time, uint32_t nSlots, uint32_t from)
Expect generate backoff function.
void DoRun() override
Implementation to actually run this TestCase.
void AddTxop(uint32_t aifsn)
Add Txop function.
Ptr< SpectrumWifiPhy > m_phy
the PHY object
void DoAccessRequest(uint64_t txTime, uint64_t expectedGrantTime, Ptr< TxopTest< TxopType > > state)
Add access request with successful Ack.
void AddAccessRequest(uint64_t at, uint64_t txTime, uint64_t expectedGrantTime, uint32_t from)
Add access function.
void AddSwitchingEvt(uint64_t at, uint64_t duration)
Add switching event function.
Ptr< ChannelAccessManagerStub > m_ChannelAccessManager
the channel access manager
void AddRxErrorEvt(uint64_t at, uint64_t duration)
Add receive error event function for error at end of frame.
void ExpectBusy(uint64_t time, bool busy)
Schedule a check that the channel access manager is busy or idle.
void AddCcaBusyEvt(uint64_t at, uint64_t duration, WifiChannelListType channelType=WIFI_CHANLIST_PRIMARY, const std::vector< Time > &per20MhzDurations={})
Add CCA busy event function.
TxopTests m_txop
the vector of Txop test instances
void ExpectInternalCollision(uint64_t time, uint32_t nSlots, uint32_t from)
Expect internal collision function.
void AddNavStart(uint64_t at, uint64_t duration)
Add NAV start function.
void AddRxInsideSifsEvt(uint64_t at, uint64_t duration)
Add receive inside SIFS event function.
Ptr< FrameExchangeManagerStub< TxopType > > m_feManager
the Frame Exchange Manager stubbed
void DoCheckBusy(bool busy)
Perform check that channel access manager is busy or idle.
void AddNavReset(uint64_t at, uint64_t duration)
Add NAV reset function.
void AddTxEvt(uint64_t at, uint64_t duration)
Add transmit event function.
void NotifyChannelSwitching()
Notify channel switching function.
ChannelAccessManager Test Suite.
Frame Exchange Manager Stub.
void NotifySwitchingStartNow(Time duration) override
void NotifyInternalCollision(Ptr< Txop > txop) override
Notify that an internal collision has occurred for the given Txop.
ChannelAccessManagerTest< TxopType > * m_test
the test DCF/EDCA manager
FrameExchangeManagerStub(ChannelAccessManagerTest< TxopType > *test)
Constructor.
bool StartTransmission(Ptr< Txop > dcf, uint16_t allowedWidth) override
Request the FrameExchangeManager to start a frame exchange sequence.
Test the calculation of the largest idle primary channel performed by ChannelAccessManager::GetLarges...
Ptr< SpectrumWifiPhy > m_phy
PHY object.
void RunOne(uint16_t chWidth, WifiChannelListType busyChannel)
Test a specific combination of operating channel width and busy channel type.
~LargestIdlePrimaryChannelTest() override=default
void DoRun() override
Implementation to actually run this TestCase.
Ptr< ChannelAccessManager > m_cam
channel access manager
TxopTest Txop Test.
ExpectedBackoffs m_expectedInternalCollision
expected backoff due to an internal collision
void DoDispose() override
Destructor implementation.
void GenerateBackoff(uint8_t linkId) override
Generate a new backoff for the given link now.
uint32_t m_i
the index of the Txop
void NotifyChannelAccessed(uint8_t linkId, Time txopDuration=Seconds(0)) override
Called by the FrameExchangeManager to notify that channel access has been granted on the given link f...
void QueueTx(uint64_t txTime, uint64_t expectedGrantTime)
Queue transmit function.
ExpectedBackoffs m_expectedBackoff
expected backoff (not due to an internal collision)
std::list< ExpectedGrant > ExpectedGrants
the collection of expected grants typedef
void NotifySleep(uint8_t linkId) override
Notify that the given link switched to sleep mode.
ChannelAccessManagerTest< TxopType > * m_test
Check if the Txop has frames to transmit.
ExpectedGrants m_expectedGrants
expected grants
std::list< ExpectedBackoff > ExpectedBackoffs
expected backoffs typedef
void NotifyWakeUp(uint8_t linkId) override
When wake up operation occurs on a link, channel access on that link will be restarted.
bool HasFramesToTransmit(uint8_t linkId) override
Check if the Txop has frames to transmit over the given link.
TxopTest(ChannelAccessManagerTest< TxopType > *test, uint32_t i)
Constructor.
std::pair< uint64_t, uint64_t > ExpectedGrant
the expected grant typedef
Manage a set of ns3::Txop.
uint16_t GetLargestIdlePrimaryChannel(Time interval, Time end)
Return the width of the largest primary channel that has been idle for the given time interval before...
void NotifyRxEndErrorNow()
Notify the Txop that a packet reception was just completed unsuccessfuly.
void NotifyRxStartNow(Time duration)
void NotifySwitchingStartNow(PhyListener *phyListener, Time duration)
void NotifyAckTimeoutResetNow()
Notify that ack timer has reset.
void NotifyTxStartNow(Time duration)
void NotifyRxEndOkNow()
Notify the Txop that a packet reception was just completed successfully.
void NotifyCcaBusyStartNow(Time duration, WifiChannelListType channelType, const std::vector< Time > &per20MhzDurations)
void RemovePhyListener(Ptr< WifiPhy > phy)
Remove current registered listener for PHY events on the given PHY.
void SetupPhyListener(Ptr< WifiPhy > phy)
Set up (or reactivate) listener for PHY events on the given PHY.
FrameExchangeManager is a base class handling the basic frame exchange sequences for non-QoS stations...
void Dispose()
Dispose of this Object.
Definition: object.cc:258
AttributeValue implementation for Pointer.
Definition: pointer.h:48
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:77
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition: simulator.h:571
static void Destroy()
Execute the events scheduled with ScheduleDestroy().
Definition: simulator.cc:142
static Time Now()
Return the current simulation virtual time.
Definition: simulator.cc:208
static void Run()
Run the simulation.
Definition: simulator.cc:178
void AddChannel(const Ptr< SpectrumChannel > channel, const FrequencyRange &freqRange=WHOLE_WIFI_SPECTRUM)
Attach a SpectrumChannel to use for a given frequency range.
Hold variables of type string.
Definition: string.h:56
encapsulates test code
Definition: test.h:1061
void AddTestCase(TestCase *testCase, Duration duration=Duration::QUICK)
Add an individual child TestCase to this test suite.
Definition: test.cc:302
A suite of tests to run.
Definition: test.h:1273
Type
Type of test.
Definition: test.h:1280
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:105
@ NOT_REQUESTED
Definition: txop.h:103
LinkEntity & GetLink(uint8_t linkId) const
Get a reference to the link associated with the given ID.
Definition: txop.cc:213
virtual void SetInterferenceHelper(const Ptr< InterferenceHelper > helper)
Sets the interference helper.
Definition: wifi-phy.cc:653
virtual void ConfigureStandard(WifiStandard standard)
Configure the PHY-level parameters for different Wi-Fi standard.
Definition: wifi-phy.cc:984
void SetOperatingChannel(const ChannelTuple &channelTuple)
If the standard for this object has not been set yet, store the given channel settings.
Definition: wifi-phy.cc:1121
std::tuple< uint8_t, uint16_t, WifiPhyBand, uint8_t > ChannelTuple
Tuple identifying an operating channel.
Definition: wifi-phy.h:903
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition: assert.h:66
Time Now()
create an ns3::Time instance which contains the current simulation time.
Definition: simulator.cc:305
#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:252
Time MicroSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1343
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1319
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1331
WifiChannelListType
Enumeration of the possible channel-list parameter elements defined in Table 8-5 of IEEE 802....
@ WIFI_STANDARD_80211ax
@ WIFI_STANDARD_80211ac
@ WIFI_PHY_BAND_UNSPECIFIED
Unspecified.
Definition: wifi-phy-band.h:43
@ WIFI_PHY_BAND_5GHZ
The 5 GHz band.
Definition: wifi-phy-band.h:37
@ WIFI_CHANLIST_PRIMARY
@ WIFI_CHANLIST_SECONDARY40
@ WIFI_CHANLIST_SECONDARY
@ WIFI_CHANLIST_SECONDARY80
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:591
static constexpr uint8_t SINGLE_LINK_OP_ID
Link ID for single link operations (helps tracking places where correct link ID is to be used to supp...
Definition: wifi-utils.h:192
-ns3 Test suite for the ns3 wrapper script