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