A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
wifi-primary-channels-test.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2020 Universita' degli Studi di Napoli Federico II
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 * Author: Stefano Avallone <stavallo@unina.it>
7 */
8
9#include "ns3/ap-wifi-mac.h"
10#include "ns3/attribute-container.h"
11#include "ns3/boolean.h"
12#include "ns3/config.h"
13#include "ns3/ctrl-headers.h"
14#include "ns3/enum.h"
15#include "ns3/he-configuration.h"
16#include "ns3/he-phy.h"
17#include "ns3/mobility-helper.h"
18#include "ns3/multi-model-spectrum-channel.h"
19#include "ns3/rng-seed-manager.h"
20#include "ns3/spectrum-wifi-helper.h"
21#include "ns3/sta-wifi-mac.h"
22#include "ns3/test.h"
23#include "ns3/tuple.h"
24#include "ns3/wifi-net-device.h"
25#include "ns3/wifi-psdu.h"
26
27#include <algorithm>
28#include <bitset>
29#include <sstream>
30
31using namespace ns3;
32
33NS_LOG_COMPONENT_DEFINE("WifiPrimaryChannelsTest");
34
35/**
36 * \ingroup wifi-test
37 * \ingroup tests
38 *
39 * \brief Test transmissions under different primary channel settings
40 *
41 * This test can be repeated for different widths of the operating channel. We
42 * configure as many BSSes as the number of distinct 20 MHz subchannels in the
43 * operating channel, so that each BSS is assigned a distinct primary20 channel.
44 * For each BSS, we test the transmission of SU PPDUs, DL MU PPDUs and HE TB PPDUs
45 * of all the widths (20 MHz, 40 MHz, etc.) allowed by the operating channel.
46 * Transmissions of a given type take place simultaneously in BSSes that do not
47 * operate on adjacent primary channels of the considered width (so that
48 * transmissions do not interfere with each other). It is also possible to
49 * select whether BSSes should be assigned (distinct) BSS colors or not.
50 */
52{
53 public:
54 /**
55 * Constructor
56 *
57 * \param channelWidth the operating channel width
58 * \param useDistinctBssColors whether to set distinct BSS colors to BSSes
59 */
60 WifiPrimaryChannelsTest(MHz_u channelWidth, bool useDistinctBssColors);
61 ~WifiPrimaryChannelsTest() override;
62
63 /**
64 * Callback invoked when PHY receives a PSDU to transmit. Used to print
65 * transmitted PSDUs for debug purposes.
66 *
67 * \param context the context
68 * \param psduMap the PSDU map
69 * \param txVector the TX vector
70 * \param txPowerW the tx power in Watts
71 */
72 void Transmit(std::string context,
73 WifiConstPsduMap psduMap,
74 WifiTxVector txVector,
75 double txPowerW);
76 /**
77 * Have the AP of the given BSS transmit a SU PPDU using the given
78 * transmission channel width
79 *
80 * \param bss the given BSS
81 * \param txChannelWidth the given transmission channel width
82 */
83 void SendDlSuPpdu(uint8_t bss, MHz_u txChannelWidth);
84 /**
85 * Have the AP of the given BSS transmit a MU PPDU using the given
86 * transmission channel width and RU type
87 *
88 * \param bss the given BSS
89 * \param txChannelWidth the given transmission channel width
90 * \param ruType the given RU type
91 * \param nRus the number of RUs
92 */
93 void SendDlMuPpdu(uint8_t bss, MHz_u txChannelWidth, HeRu::RuType ruType, std::size_t nRus);
94 /**
95 * Have the AP of the given BSS transmit a Basic Trigger Frame. This method calls
96 * DoSendHeTbPpdu to actually have STAs transmit HE TB PPDUs using the given
97 * transmission channel width and RU type
98 *
99 * \param bss the given BSS
100 * \param txChannelWidth the given transmission channel width
101 * \param ruType the given RU type
102 * \param nRus the number of RUs
103 */
104 void SendHeTbPpdu(uint8_t bss, MHz_u txChannelWidth, HeRu::RuType ruType, std::size_t nRus);
105 /**
106 * Have the STAs of the given BSS transmit an HE TB PPDU using the given
107 * transmission channel width and RU type
108 *
109 * \param bss the given BSS
110 * \param txChannelWidth the given transmission channel width
111 * \param ruType the given RU type
112 * \param nRus the number of RUs
113 */
114 void DoSendHeTbPpdu(uint8_t bss, MHz_u txChannelWidth, HeRu::RuType ruType, std::size_t nRus);
115 /**
116 * Callback invoked when a station receives a DL PPDU.
117 *
118 * \param bss the BSS the receiving STA belongs to
119 * \param station the receiving station
120 * \param psdu the received PSDU
121 * \param rxSignalInfo the info on the received signal (\see RxSignalInfo)
122 * \param txVector TxVector of the received PSDU
123 * \param perMpduStatus per MPDU reception status
124 */
125 void ReceiveDl(uint8_t bss,
126 uint8_t station,
128 RxSignalInfo rxSignalInfo,
129 WifiTxVector txVector,
130 std::vector<bool> perMpduStatus);
131 /**
132 * Callback invoked when an AP receives an UL PPDU.
133 *
134 * \param bss the BSS the receiving AP belongs to
135 * \param psdu the received PSDU
136 * \param rxSignalInfo the info on the received signal (\see RxSignalInfo)
137 * \param txVector TxVector of the received PSDU
138 * \param perMpduStatus per MPDU reception status
139 */
140 void ReceiveUl(uint8_t bss,
142 RxSignalInfo rxSignalInfo,
143 WifiTxVector txVector,
144 std::vector<bool> perMpduStatus);
145 /**
146 * Check that all stations associated with an AP.
147 */
148 void CheckAssociation();
149 /**
150 * Check that (i) all stations belonging to the given BSSes received the SU PPDUs
151 * transmitted over the given channel width; and (ii) all stations belonging to
152 * the other BSSes did not receive any frame if BSS Color is set (due to BSS Color
153 * filtering) or if no transmission was performed on a channel adjacent to the one
154 * they operate on, otherwise.
155 *
156 * \param txBss the set of BSSes that transmitted an SU PPDU
157 * \param txChannelWidth the given transmission channel width
158 */
159 void CheckReceivedSuPpdus(std::set<uint8_t> txBss, MHz_u txChannelWidth);
160 /**
161 * Check that (i) all stations/APs belonging to the given BSSes received the DL/UL MU PPDUs
162 * transmitted over the given channel width and RU width; and (ii) stations/APs belonging to
163 * the other BSSes did not receive any frame if BSS Color is set (due to BSS Color
164 * filtering) or if no transmission addressed to/from stations with the same AID was
165 * performed on a channel adjacent to the one they operate on, otherwise.
166 *
167 * \param txBss the set of BSSes that transmitted an SU PPDU
168 * \param txChannelWidth the given transmission channel width
169 * \param ruType the given RU type
170 * \param nRus the number of RUs
171 * \param isDlMu true for DL MU PPDU, false for HE TB PPDU
172 */
173 void CheckReceivedMuPpdus(std::set<uint8_t> txBss,
174 MHz_u txChannelWidth,
175 HeRu::RuType ruType,
176 std::size_t nRus,
177 bool isDlMu);
178 /**
179 * Check that (i) all stations belonging to the given BSSes received the transmitted
180 * Trigger Frame; and (ii) all stations belonging to the other BSSes did not receive
181 * any frame Trigger Frame (given that a Trigger Frame is transmitted on the primary20
182 * channel and all the primary20 channels are distinct).
183 *
184 * \param txBss the set of BSSes that transmitted a Trigger Frame
185 * \param txChannelWidth the given transmission channel width
186 */
187 void CheckReceivedTriggerFrames(std::set<uint8_t> txBss, MHz_u txChannelWidth);
188
189 private:
190 void DoSetup() override;
191 void DoRun() override;
192
193 MHz_u m_channelWidth; ///< operating channel width
194 bool m_useDistinctBssColors; ///< true to set distinct BSS colors to BSSes
195 uint8_t m_nBss; ///< number of BSSes
196 uint8_t m_nStationsPerBss; ///< number of stations per AP
197 std::vector<NetDeviceContainer> m_staDevices; ///< containers for stations' NetDevices
198 NetDeviceContainer m_apDevices; ///< container for AP's NetDevice
199 std::vector<std::bitset<74>> m_received; /**< whether the last packet transmitted to/from each
200 of the (up to 74 per BSS) stations was received */
201 std::vector<std::bitset<74>> m_processed; /**< whether the last packet transmitted to/from each
202 of the (up to 74 per BSS) stations was processed */
203 Time m_time; ///< the time when the current action is executed
204 Ptr<WifiPsdu> m_trigger; ///< Basic Trigger Frame
205 WifiTxVector m_triggerTxVector; ///< TX vector for Basic Trigger Frame
206 Time m_triggerTxDuration; ///< TX duration for Basic Trigger Frame
207};
208
209WifiPrimaryChannelsTest::WifiPrimaryChannelsTest(MHz_u channelWidth, bool useDistinctBssColors)
210 : TestCase("Check correct transmissions for various primary channel settings"),
211 m_channelWidth(channelWidth),
212 m_useDistinctBssColors(useDistinctBssColors)
213{
214}
215
219
220void
222 WifiConstPsduMap psduMap,
223 WifiTxVector txVector,
224 double txPowerW)
225{
226 for (const auto& psduPair : psduMap)
227 {
228 std::stringstream ss;
229
230 if (psduPair.first != SU_STA_ID)
231 {
232 ss << " STA-ID " << psduPair.first;
233 }
234 ss << " " << psduPair.second->GetHeader(0).GetTypeString() << " seq "
235 << psduPair.second->GetHeader(0).GetSequenceNumber() << " from "
236 << psduPair.second->GetAddr2() << " to " << psduPair.second->GetAddr1();
237 NS_LOG_INFO(ss.str());
238 }
239 NS_LOG_INFO(" TXVECTOR " << txVector);
240}
241
242void
244 uint8_t station,
246 RxSignalInfo rxSignalInfo,
247 WifiTxVector txVector,
248 std::vector<bool> perMpduStatus)
249{
250 if (psdu->GetNMpdus() == 1)
251 {
252 const WifiMacHeader& hdr = psdu->GetHeader(0);
253
254 if (hdr.IsQosData() || hdr.IsTrigger())
255 {
256 NS_LOG_INFO("RECEIVED BY BSS=" << +bss << " STA=" << +station << " " << *psdu);
257 // the MAC received a PSDU from the PHY
259 false,
260 "Station [" << +bss << "][" << +station
261 << "] received a frame twice");
262 m_received[bss].set(station);
263 // check if we are the intended destination of the PSDU
264 auto dev = DynamicCast<WifiNetDevice>(m_staDevices[bss].Get(station));
265 if ((hdr.IsQosData() && hdr.GetAddr1() == dev->GetMac()->GetAddress()) ||
266 (hdr.IsTrigger() && hdr.GetAddr1() == Mac48Address::GetBroadcast()))
267 {
269 false,
270 "Station [" << +bss << "][" << +station
271 << "] processed a frame twice");
272 m_processed[bss].set(station);
273 }
274 }
275 }
276}
277
278void
281 RxSignalInfo rxSignalInfo,
282 WifiTxVector txVector,
283 std::vector<bool> perMpduStatus)
284{
285 // if the BSS color is zero, this AP might receive the frame sent by another AP. Given that
286 // stations only send TB PPDUs, we ignore this frame if the TX vector is not UL MU.
287 if (psdu->GetNMpdus() == 1 && psdu->GetHeader(0).IsQosData() && txVector.IsUlMu())
288 {
290
291 uint16_t staId = txVector.GetHeMuUserInfoMap().begin()->first;
292 uint8_t station = staId - 1;
293 NS_LOG_INFO("RECEIVED FROM BSSID=" << psdu->GetHeader(0).GetAddr3() << " STA=" << +station
294 << " " << *psdu);
295 // the MAC received a PSDU containing a QoS data frame from the PHY
297 false,
298 "AP of BSS " << +bss << " received a frame from station " << +station
299 << " twice");
300 m_received[bss].set(station);
301 // check if we are the intended destination of the PSDU
302 if (psdu->GetHeader(0).GetAddr1() == dev->GetMac()->GetAddress())
303 {
305 false,
306 "AP of BSS " << +bss << " received a frame from station "
307 << +station << " twice");
308 m_processed[bss].set(station);
309 }
310 }
311}
312
313void
315{
318 int64_t streamNumber = 100;
319 uint8_t channelNum;
320
321 // we create as many stations per BSS as the number of 26-tone RUs in a channel
322 // of the configured width
323 switch (static_cast<uint16_t>(m_channelWidth))
324 {
325 case 20:
327 channelNum = 36;
328 break;
329 case 40:
331 channelNum = 38;
332 break;
333 case 80:
335 channelNum = 42;
336 break;
337 case 160:
339 channelNum = 50;
340 break;
341 default:
342 NS_ABORT_MSG("Channel width (" << m_channelWidth << ") not allowed");
343 }
344
345 // we create as many BSSes as the number of 20 MHz subchannels
346 m_nBss = m_channelWidth / 20;
347
348 NodeContainer wifiApNodes;
349 wifiApNodes.Create(m_nBss);
350
351 std::vector<NodeContainer> wifiStaNodes(m_nBss);
352 for (auto& container : wifiStaNodes)
353 {
354 container.Create(m_nStationsPerBss);
355 }
356
359 spectrumChannel->AddPropagationLossModel(lossModel);
362 spectrumChannel->SetPropagationDelayModel(delayModel);
363
365 phy.SetChannel(spectrumChannel);
366
367 WifiHelper wifi;
368 wifi.SetStandard(WIFI_STANDARD_80211ax);
369 wifi.SetRemoteStationManager("ns3::ConstantRateWifiManager");
370
371 WifiMacHelper mac;
372 mac.SetType("ns3::StaWifiMac",
373 "Ssid",
374 SsidValue(Ssid("non-existent-ssid")),
375 "MaxMissedBeacons",
376 UintegerValue(20),
377 "WaitBeaconTimeout",
378 TimeValue(MicroSeconds(102400))); // same as BeaconInterval
379
382 ';'>
383 channelValue;
384
385 // Each BSS uses a distinct primary20 channel
386 for (uint8_t bss = 0; bss < m_nBss; bss++)
387 {
388 channelValue.Set(
390 phy.Set("ChannelSettings", channelValue);
391
392 m_staDevices.push_back(wifi.Install(phy, mac, wifiStaNodes[bss]));
393 }
394
395 for (uint8_t bss = 0; bss < m_nBss; bss++)
396 {
397 channelValue.Set(
399 phy.Set("ChannelSettings", channelValue);
400
401 mac.SetType("ns3::ApWifiMac",
402 "Ssid",
403 SsidValue(Ssid("wifi-ssid-" + std::to_string(bss))),
404 "BeaconInterval",
405 TimeValue(MicroSeconds(102400)),
406 "EnableBeaconJitter",
407 BooleanValue(false));
408
409 m_apDevices.Add(wifi.Install(phy, mac, wifiApNodes.Get(bss)));
410 }
411
412 // Assign fixed streams to random variables in use
413 streamNumber = WifiHelper::AssignStreams(m_apDevices, streamNumber);
414 for (uint8_t bss = 0; bss < m_nBss; bss++)
415 {
416 streamNumber = WifiHelper::AssignStreams(m_staDevices[bss], streamNumber);
417 }
418
419 // set BSS color
421 {
422 for (uint8_t bss = 0; bss < m_nBss; bss++)
423 {
425 dev->GetHeConfiguration()->SetBssColor(bss + 1);
426 }
427 }
428
429 MobilityHelper mobility;
431
432 positionAlloc->Add(Vector(0.0, 0.0, 0.0)); // all stations are co-located
433 mobility.SetPositionAllocator(positionAlloc);
434
435 mobility.SetMobilityModel("ns3::ConstantPositionMobilityModel");
436 mobility.Install(wifiApNodes);
437 for (uint8_t bss = 0; bss < m_nBss; bss++)
438 {
439 mobility.Install(wifiStaNodes[bss]);
440 }
441
442 m_received.resize(m_nBss);
443 m_processed.resize(m_nBss);
444
445 // pre-compute the Basic Trigger Frame to send
447
448 WifiMacHeader hdr;
451 // Addr2 has to be set
452 hdr.SetSequenceNumber(1);
453
455 CtrlTriggerHeader trigger;
456 trigger.SetType(TriggerFrameType::BASIC_TRIGGER);
457 pkt->AddHeader(trigger);
458
460 0,
462 NanoSeconds(800),
463 1,
464 1,
465 0,
466 20,
467 false,
468 false,
469 false);
470 m_trigger = Create<WifiPsdu>(pkt, hdr);
471
474 apDev->GetMac()->GetWifiPhy()->GetPhyBand());
475}
476
477void
479{
480 // schedule association requests at different times. One station's SSID is
481 // set to the correct value before initialization, so that such a station
482 // starts the scanning procedure by looking for the correct SSID
484
485 // association can be done in parallel over the multiple BSSes
486 for (uint8_t bss = 0; bss < m_nBss; bss++)
487 {
488 dev = DynamicCast<WifiNetDevice>(m_staDevices[bss].Get(0));
489 dev->GetMac()->SetSsid(Ssid("wifi-ssid-" + std::to_string(bss)));
490
491 for (uint16_t i = 1; i < m_nStationsPerBss; i++)
492 {
493 dev = DynamicCast<WifiNetDevice>(m_staDevices[bss].Get(i));
496 dev->GetMac(),
497 Ssid("wifi-ssid-" + std::to_string(bss)));
498 }
499 }
500
501 // just before sending the beacon preceding the last association, increase the beacon
502 // interval (to the max allowed value) so that beacons do not interfere with data frames
503 for (uint8_t bss = 0; bss < m_nBss; bss++)
504 {
506 auto mac = DynamicCast<ApWifiMac>(dev->GetMac());
507
510 mac,
511 MicroSeconds(1024 * 65535));
512 }
513
514 m_time = (m_nStationsPerBss + 1) * MicroSeconds(102400);
515
517
518 // we are done with association. We now intercept frames received by the
519 // PHY layer on stations and APs, which will no longer be passed to the FEM.
520 for (uint8_t bss = 0; bss < m_nBss; bss++)
521 {
522 for (uint8_t i = 0; i < m_nStationsPerBss; i++)
523 {
524 auto dev = DynamicCast<WifiNetDevice>(m_staDevices[bss].Get(i));
526 m_time,
528 dev->GetPhy(),
530 }
534 dev->GetPhy(),
536 }
537
538 /*
539 * We start generating (downlink) SU PPDUs.
540 * First, APs operating on non-adjacent primary20 channels send a frame simultaneously
541 * in their primary20. This is done in two rounds. As an example, we consider the
542 * case of an 160 MHz operating channel:
543 *
544 * AP0 AP2 AP4 AP6
545 * |-----| |-----| |-----| |-----| |
546 *
547 * AP1 AP3 AP5 AP7
548 * | |-----| |-----| |-----| |-----|
549 *
550 * Then, we double the transmission channel width. We will have four rounds
551 * of transmissions. We avoid using adjacent channels to avoid interfence
552 * among transmissions:
553 *
554 * AP0 AP4
555 * |-----------| |-----------| |
556 * AP1 AP5
557 * |-----------| |-----------| |
558 * AP2 AP6
559 * | |-----------| |-----------|
560 * AP3 AP7
561 * | |-----------| |-----------|
562 *
563 * We double the transmission channel width again. We will have eight rounds
564 * of transmissions:
565 *
566 * AP0
567 * |-----------------------| |
568 * AP1
569 * |-----------------------| |
570 * AP2
571 * |-----------------------| |
572 * AP3
573 * |-----------------------| |
574 * AP4
575 * | |-----------------------|
576 * AP5
577 * | |-----------------------|
578 * AP6
579 * | |-----------------------|
580 * AP7
581 * | |-----------------------|
582 *
583 * We double the transmission channel width again. We will have eight rounds
584 * of transmissions:
585 *
586 * AP0
587 * |-----------------------------------------------|
588 * AP1
589 * |-----------------------------------------------|
590 * AP2
591 * |-----------------------------------------------|
592 * AP3
593 * |-----------------------------------------------|
594 * AP4
595 * |-----------------------------------------------|
596 * AP5
597 * |-----------------------------------------------|
598 * AP6
599 * |-----------------------------------------------|
600 * AP7
601 * |-----------------------------------------------|
602 *
603 * The transmission channel width reached the operating channel width, we are done.
604 */
605
606 Time roundDuration = MilliSeconds(5); // upper bound on the duration of a round
607
608 // To have simultaneous transmissions on adjacent channels, just initialize
609 // nRounds to 1 and nApsPerRound to m_channelWidth / 20. Of course, the test
610 // will fail because some stations will not receive some frames due to interfence
611 for (MHz_u txChannelWidth = 20, nRounds = 2, nApsPerRound = m_channelWidth / 20 / 2;
612 txChannelWidth <= m_channelWidth;
613 txChannelWidth *= 2, nRounds *= 2, nApsPerRound /= 2)
614 {
615 nRounds = std::min<uint16_t>(nRounds, m_nBss);
616 nApsPerRound = std::max<uint16_t>(nApsPerRound, 1);
617
618 for (uint16_t round = 0; round < nRounds; round++)
619 {
620 std::set<uint8_t> txBss;
621
622 for (uint16_t i = 0; i < nApsPerRound; i++)
623 {
624 uint16_t ap = round + i * nRounds;
625 txBss.insert(ap);
628 this,
629 ap,
630 txChannelWidth);
631 }
632 // check that the SU frames were correctly received
633 Simulator::Schedule(m_time + roundDuration,
635 this,
636 txBss,
637 txChannelWidth);
638 m_time += roundDuration;
639 }
640 }
641
642 /*
643 * Repeat the same scheme as before with DL MU transmissions. For each transmission
644 * channel width, every round is repeated as many times as the number of ways in
645 * which we can partition the transmission channel width in equal sized RUs.
646 */
647 for (MHz_u txChannelWidth = 20, nRounds = 2, nApsPerRound = m_channelWidth / 20 / 2;
648 txChannelWidth <= m_channelWidth;
649 txChannelWidth *= 2, nRounds *= 2, nApsPerRound /= 2)
650 {
651 nRounds = std::min<uint16_t>(nRounds, m_nBss);
652 nApsPerRound = std::max<uint16_t>(nApsPerRound, 1);
653
654 for (uint16_t round = 0; round < nRounds; round++)
655 {
656 for (unsigned int type = 0; type < 7; type++)
657 {
658 auto ruType = static_cast<HeRu::RuType>(type);
659 std::size_t nRus = HeRu::GetNRus(txChannelWidth, ruType);
660 std::set<uint8_t> txBss;
661 if (nRus > 0)
662 {
663 for (uint16_t i = 0; i < nApsPerRound; i++)
664 {
665 uint16_t ap = round + i * nRounds;
666 txBss.insert(ap);
669 this,
670 ap,
671 txChannelWidth,
672 ruType,
673 nRus);
674 }
675 // check that the MU frame was correctly received
676 Simulator::Schedule(m_time + roundDuration,
678 this,
679 txBss,
680 txChannelWidth,
681 ruType,
682 nRus,
683 /* isDlMu */ true);
684 m_time += roundDuration;
685 }
686 }
687 }
688 }
689
690 /*
691 * Repeat the same scheme as before with UL MU transmissions. For each transmission
692 * channel width, every round is repeated as many times as the number of ways in
693 * which we can partition the transmission channel width in equal sized RUs.
694 */
695 for (MHz_u txChannelWidth = 20, nRounds = 2, nApsPerRound = m_channelWidth / 20 / 2;
696 txChannelWidth <= m_channelWidth;
697 txChannelWidth *= 2, nRounds *= 2, nApsPerRound /= 2)
698 {
699 nRounds = std::min<uint16_t>(nRounds, m_nBss);
700 nApsPerRound = std::max<uint16_t>(nApsPerRound, 1);
701
702 for (uint16_t round = 0; round < nRounds; round++)
703 {
704 for (unsigned int type = 0; type < 7; type++)
705 {
706 auto ruType = static_cast<HeRu::RuType>(type);
707 std::size_t nRus = HeRu::GetNRus(txChannelWidth, ruType);
708 std::set<uint8_t> txBss;
709 if (nRus > 0)
710 {
711 for (uint16_t i = 0; i < nApsPerRound; i++)
712 {
713 uint16_t ap = round + i * nRounds;
714 txBss.insert(ap);
717 this,
718 ap,
719 txChannelWidth,
720 ruType,
721 nRus);
722 }
723 // check that Trigger Frames and TB PPDUs were correctly received
725 MicroSeconds(10), /* during SIFS */
727 this,
728 txBss,
729 txChannelWidth);
730 Simulator::Schedule(m_time + roundDuration,
732 this,
733 txBss,
734 txChannelWidth,
735 ruType,
736 nRus,
737 /* isDlMu */ false);
738 m_time += roundDuration;
739 }
740 }
741 }
742 }
743
744 // Trace PSDUs passed to the PHY on all devices
745 Config::Connect("/NodeList/*/DeviceList/*/$ns3::WifiNetDevice/Phy/PhyTxPsduBegin",
747
750
752}
753
754void
756{
757 NS_LOG_INFO("*** BSS " << +bss << " transmits on primary " << txChannelWidth << " MHz channel");
758
759 auto apDev = DynamicCast<WifiNetDevice>(m_apDevices.Get(bss));
760 auto staDev = DynamicCast<WifiNetDevice>(m_staDevices[bss].Get(0));
761
762 uint8_t bssColor = apDev->GetHeConfiguration()->GetBssColor();
764 0,
766 NanoSeconds(800),
767 1,
768 1,
769 0,
770 txChannelWidth,
771 false,
772 false,
773 false,
774 bssColor);
775 WifiMacHeader hdr;
777 hdr.SetQosTid(0);
778 hdr.SetAddr1(staDev->GetMac()->GetAddress());
779 hdr.SetAddr2(apDev->GetMac()->GetAddress());
780 hdr.SetAddr3(apDev->GetMac()->GetBssid(0));
781 hdr.SetSequenceNumber(1);
783 apDev->GetPhy()->Send(WifiConstPsduMap({std::make_pair(SU_STA_ID, psdu)}), txVector);
784}
785
786void
788 MHz_u txChannelWidth,
789 HeRu::RuType ruType,
790 std::size_t nRus)
791{
792 NS_LOG_INFO("*** BSS " << +bss << " transmits on primary " << txChannelWidth
793 << " MHz channel a DL MU PPDU "
794 << "addressed to " << nRus << " stations (RU type: " << ruType << ")");
795
796 auto apDev = DynamicCast<WifiNetDevice>(m_apDevices.Get(bss));
797 uint8_t bssColor = apDev->GetHeConfiguration()->GetBssColor();
798
800 0,
802 NanoSeconds(800),
803 1,
804 1,
805 0,
806 txChannelWidth,
807 false,
808 false,
809 false,
810 bssColor);
811 WifiMacHeader hdr;
813 hdr.SetQosTid(0);
814 hdr.SetAddr2(apDev->GetMac()->GetAddress());
815 hdr.SetAddr3(apDev->GetMac()->GetBssid(0));
816 hdr.SetSequenceNumber(1);
817
818 WifiConstPsduMap psduMap;
819
820 for (std::size_t i = 1; i <= nRus; i++)
821 {
822 bool primary80 = !(txChannelWidth == 160 && i > nRus / 2);
823 std::size_t index = (primary80 ? i : i - nRus / 2);
824
825 auto staDev = DynamicCast<WifiNetDevice>(m_staDevices[bss].Get(i - 1));
826 uint16_t staId = DynamicCast<StaWifiMac>(staDev->GetMac())->GetAssociationId();
827 txVector.SetHeMuUserInfo(staId, {{ruType, index, primary80}, 8, 1});
828 hdr.SetAddr1(staDev->GetMac()->GetAddress());
829 psduMap[staId] = Create<const WifiPsdu>(Create<Packet>(1000), hdr);
830 }
832 RuAllocation ruAllocations;
833 const std::size_t numRuAllocs = txChannelWidth / 20;
834 ruAllocations.resize(numRuAllocs);
835 auto IsOddNum = (nRus / numRuAllocs) % 2 == 1;
836 auto ruAlloc = HeRu::GetEqualizedRuAllocation(ruType, IsOddNum);
837 std::fill_n(ruAllocations.begin(), numRuAllocs, ruAlloc);
838 txVector.SetRuAllocation(ruAllocations, 0);
839
840 apDev->GetPhy()->Send(psduMap, txVector);
841}
842
843void
845 MHz_u txChannelWidth,
846 HeRu::RuType ruType,
847 std::size_t nRus)
848{
849 NS_LOG_INFO("*** BSS " << +bss << " transmits a Basic Trigger Frame");
850
851 auto apDev = DynamicCast<WifiNetDevice>(m_apDevices.Get(bss));
852
853 m_trigger->GetHeader(0).SetAddr2(apDev->GetMac()->GetAddress());
854
855 apDev->GetPhy()->Send(m_trigger, m_triggerTxVector);
856
857 // schedule the transmission of HE TB PPDUs
858 Simulator::Schedule(m_triggerTxDuration + apDev->GetPhy()->GetSifs(),
860 this,
861 bss,
862 txChannelWidth,
863 ruType,
864 nRus);
865}
866
867void
869 MHz_u txChannelWidth,
870 HeRu::RuType ruType,
871 std::size_t nRus)
872{
873 auto apDev = DynamicCast<WifiNetDevice>(m_apDevices.Get(bss));
874 uint8_t bssColor = apDev->GetHeConfiguration()->GetBssColor();
875
876 WifiMacHeader hdr;
878 hdr.SetQosTid(0);
879 hdr.SetAddr1(apDev->GetMac()->GetAddress());
880 hdr.SetAddr3(apDev->GetMac()->GetBssid(0));
881 hdr.SetSequenceNumber(1);
882
883 Time duration = Seconds(0);
884 uint16_t length = 0;
885 WifiTxVector trigVector(HePhy::GetHeMcs8(),
886 0,
888 NanoSeconds(3200),
889 1,
890 1,
891 0,
892 txChannelWidth,
893 false,
894 false,
895 false,
896 bssColor);
897
898 for (std::size_t i = 1; i <= nRus; i++)
899 {
900 NS_LOG_INFO("*** BSS " << +bss << " STA " << i - 1 << " transmits on primary "
901 << txChannelWidth
902 << " MHz channel an HE TB PPDU (RU type: " << ruType << ")");
903
904 bool primary80 = !(txChannelWidth == 160 && i > nRus / 2);
905 std::size_t index = (primary80 ? i : i - nRus / 2);
906
907 auto staDev = DynamicCast<WifiNetDevice>(m_staDevices[bss].Get(i - 1));
908 uint16_t staId = DynamicCast<StaWifiMac>(staDev->GetMac())->GetAssociationId();
909
911 0,
913 NanoSeconds(3200),
914 1,
915 1,
916 0,
917 txChannelWidth,
918 false,
919 false,
920 false,
921 bssColor);
922 txVector.SetHeMuUserInfo(staId, {{ruType, index, primary80}, 8, 1});
923 trigVector.SetHeMuUserInfo(staId, {{ruType, index, primary80}, 8, 1});
924
925 hdr.SetAddr2(staDev->GetMac()->GetAddress());
927
928 if (duration.IsZero())
929 {
930 // calculate just once
931 duration = WifiPhy::CalculateTxDuration(psdu->GetSize(),
932 txVector,
933 staDev->GetMac()->GetWifiPhy()->GetPhyBand(),
934 staId);
935 std::tie(length, duration) = HePhy::ConvertHeTbPpduDurationToLSigLength(
936 duration,
937 txVector,
938 staDev->GetMac()->GetWifiPhy()->GetPhyBand());
939 }
940 txVector.SetLength(length);
941
942 staDev->GetPhy()->Send(WifiConstPsduMap{{staId, psdu}}, txVector);
943 }
944
945 // AP's PHY expects to receive a TRIGVECTOR (just once)
946 trigVector.SetLength(length);
947 auto apHePhy = StaticCast<HePhy>(apDev->GetPhy()->GetLatestPhyEntity());
948 apHePhy->SetTrigVector(trigVector, duration);
949}
950
951void
953{
954 for (uint8_t bss = 0; bss < m_nBss; bss++)
955 {
957 auto mac = DynamicCast<ApWifiMac>(dev->GetMac());
958 NS_TEST_EXPECT_MSG_EQ(mac->GetStaList(SINGLE_LINK_OP_ID).size(),
960 "Not all the stations completed association");
961 }
962}
963
964void
965WifiPrimaryChannelsTest::CheckReceivedSuPpdus(std::set<uint8_t> txBss, MHz_u txChannelWidth)
966{
967 for (uint8_t bss = 0; bss < m_nBss; bss++)
968 {
969 if (txBss.find(bss) != txBss.end())
970 {
971 // Every station in the BSS of an AP that transmitted the frame hears (i.e.,
972 // passes to the MAC) the frame
973 for (uint8_t sta = 0; sta < m_nStationsPerBss; sta++)
974 {
976 true,
977 "Station [" << +bss << "][" << +sta
978 << "] did not receive the SU frame on primary"
979 << txChannelWidth << " channel");
980 }
981 // only the first station actually processed the frames
983 true,
984 "Station [" << +bss << "][0]"
985 << " did not process the SU frame on primary"
986 << txChannelWidth << " channel");
987 for (uint8_t sta = 1; sta < m_nStationsPerBss; sta++)
988 {
990 false,
991 "Station [" << +bss << "][" << +sta
992 << "] processed the SU frame on primary"
993 << txChannelWidth << " channel");
994 }
995 }
996 else
997 {
998 // There was no transmission in this BSS. If BSS Color filtering is enabled or no frame
999 // transmission overlaps with the primary20 channel of this BSS, stations in this BSS
1000 // did not hear any frame.
1002 std::none_of(txBss.begin(), txBss.end(), [&](const uint8_t& txAp) {
1003 auto txApPhy = DynamicCast<WifiNetDevice>(m_apDevices.Get(txAp))->GetPhy();
1004 auto thisApPhy = DynamicCast<WifiNetDevice>(m_apDevices.Get(bss))->GetPhy();
1005 return txApPhy->GetOperatingChannel().GetPrimaryChannelIndex(txChannelWidth) ==
1006 thisApPhy->GetOperatingChannel().GetPrimaryChannelIndex(txChannelWidth);
1007 }))
1008 {
1009 for (uint8_t sta = 0; sta < m_nStationsPerBss; sta++)
1010 {
1012 false,
1013 "Station [" << +bss << "][" << +sta
1014 << "] received the SU frame on primary"
1015 << txChannelWidth << " channel");
1016 }
1017 }
1018 else
1019 {
1020 // all stations heard the frame but no station processed it
1021 for (uint8_t sta = 0; sta < m_nStationsPerBss; sta++)
1022 {
1024 true,
1025 "Station [" << +bss << "][" << +sta
1026 << "] did not receive the SU frame on primary"
1027 << txChannelWidth << " channel");
1029 false,
1030 "Station [" << +bss << "][" << +sta
1031 << "] processed the SU frame on primary"
1032 << txChannelWidth << " channel");
1033 }
1034 }
1035 }
1036 // reset bitmaps
1037 m_received[bss].reset();
1038 m_processed[bss].reset();
1039 }
1040}
1041
1042void
1044 MHz_u txChannelWidth,
1045 HeRu::RuType ruType,
1046 std::size_t nRus,
1047 bool isDlMu)
1048{
1049 for (uint8_t bss = 0; bss < m_nBss; bss++)
1050 {
1051 if (txBss.find(bss) != txBss.end())
1052 {
1053 // There was a transmission in this BSS.
1054 // [DL] Due to AID filtering, only stations that are addressed by the MU PPDU do hear
1055 // the frame [UL] The AP hears a TB PPDU sent by all and only the solicited stations
1056 for (std::size_t sta = 0; sta < nRus; sta++)
1057 {
1059 m_received[bss].test(sta),
1060 true,
1061 (isDlMu ? "A DL MU PPDU transmitted to" : "An HE TB PPDU transmitted by")
1062 << " station [" << +bss << "][" << +sta << "] on primary" << txChannelWidth
1063 << " channel, RU type " << ruType << " was not received");
1064 }
1065 for (uint8_t sta = nRus; sta < m_nStationsPerBss; sta++)
1066 {
1068 false,
1069 (isDlMu ? "A DL MU PPDU" : "An HE TB PPDU")
1070 << " transmitted on primary" << txChannelWidth
1071 << " channel, RU type " << ruType << " was received "
1072 << (isDlMu ? "by" : "from") << " station [" << +bss
1073 << "][" << +sta << "]");
1074 }
1075 // [DL] Only the addressed stations actually processed the frames
1076 // [UL] The AP processed the frames sent by all and only the addressed stations
1077 for (std::size_t sta = 0; sta < nRus; sta++)
1078 {
1080 m_processed[bss].test(sta),
1081 true,
1082 (isDlMu ? "A DL MU PPDU transmitted to" : "An HE TB PPDU transmitted by")
1083 << " station [" << +bss << "][" << +sta << "] on primary" << txChannelWidth
1084 << " channel, RU type " << ruType << " was not processed");
1085 }
1086 for (uint8_t sta = nRus; sta < m_nStationsPerBss; sta++)
1087 {
1089 false,
1090 (isDlMu ? "A DL MU PPDU" : "An HE TB PPDU")
1091 << " transmitted on primary" << txChannelWidth
1092 << " channel, RU type " << ruType << " was received "
1093 << (isDlMu ? "by" : "from") << " station [" << +bss
1094 << "][" << +sta << "] and processed");
1095 }
1096 }
1097 else
1098 {
1099 // There was no transmission in this BSS.
1100 // [DL] If BSS Color filtering is enabled or no frame transmission overlaps with
1101 // the primary20 channel of this BSS, stations in this BSS did not hear any frame.
1102 // [UL] The AP did not hear any TB PPDU because no TRIGVECTOR was passed to the PHY
1103 if (!isDlMu || m_useDistinctBssColors ||
1104 std::none_of(txBss.begin(), txBss.end(), [&](const uint8_t& txAp) {
1105 auto txApPhy = DynamicCast<WifiNetDevice>(m_apDevices.Get(txAp))->GetPhy();
1106 auto thisApPhy = DynamicCast<WifiNetDevice>(m_apDevices.Get(bss))->GetPhy();
1107 return txApPhy->GetOperatingChannel().GetPrimaryChannelIndex(txChannelWidth) ==
1108 thisApPhy->GetOperatingChannel().GetPrimaryChannelIndex(txChannelWidth);
1109 }))
1110 {
1111 for (uint8_t sta = 0; sta < m_nStationsPerBss; sta++)
1112 {
1114 false,
1115 (isDlMu ? "A DL MU PPDU" : "An HE TB PPDU")
1116 << " transmitted on primary" << txChannelWidth
1117 << " channel, RU type " << ruType << " was received "
1118 << (isDlMu ? "by" : "from") << " station [" << +bss
1119 << "][" << +sta << "]");
1120 }
1121 }
1122 else
1123 {
1124 // [DL] Stations having the same AID of the stations addressed by the MU PPDU
1125 // received the frame
1126 for (std::size_t sta = 0; sta < nRus; sta++)
1127 {
1129 m_received[bss].test(sta),
1130 true,
1131 (isDlMu ? "A DL MU PPDU transmitted to" : "An HE TB PPDU transmitted by")
1132 << " station [" << +bss << "][" << +sta << "] on primary"
1133 << txChannelWidth << " channel, RU type " << ruType
1134 << " was not received");
1135 }
1136 for (uint8_t sta = nRus; sta < m_nStationsPerBss; sta++)
1137 {
1139 false,
1140 (isDlMu ? "A DL MU PPDU" : "An HE TB PPDU")
1141 << " transmitted on primary" << txChannelWidth
1142 << " channel, RU type " << ruType << " was received "
1143 << (isDlMu ? "by" : "from") << " station [" << +bss
1144 << "][" << +sta << "]");
1145 }
1146 // no station processed the frame
1147 for (uint8_t sta = 0; sta < m_nStationsPerBss; sta++)
1148 {
1150 false,
1151 (isDlMu ? "A DL MU PPDU" : "An HE TB PPDU")
1152 << " transmitted on primary" << txChannelWidth
1153 << " channel, RU type " << ruType << " was received "
1154 << (isDlMu ? "by" : "from") << " station [" << +bss
1155 << "][" << +sta << "] and processed");
1156 }
1157 }
1158 }
1159 // reset bitmaps
1160 m_received[bss].reset();
1161 m_processed[bss].reset();
1162 }
1163}
1164
1165void
1166WifiPrimaryChannelsTest::CheckReceivedTriggerFrames(std::set<uint8_t> txBss, MHz_u txChannelWidth)
1167{
1168 for (uint8_t bss = 0; bss < m_nBss; bss++)
1169 {
1170 if (txBss.find(bss) != txBss.end())
1171 {
1172 // Every station in the BSS of an AP that transmitted the Trigger Frame hears (i.e.,
1173 // passes to the MAC) and processes the frame
1174 for (uint8_t sta = 0; sta < m_nStationsPerBss; sta++)
1175 {
1177 true,
1178 "Station [" << +bss << "][" << +sta
1179 << "] did not receive the Trigger Frame "
1180 "soliciting a transmission on primary"
1181 << txChannelWidth << " channel");
1183 true,
1184 "Station [" << +bss << "][" << +sta
1185 << "] did not process the Trigger Frame "
1186 "soliciting a transmission on primary"
1187 << txChannelWidth << " channel");
1188 }
1189 }
1190 else
1191 {
1192 // Given that a Trigger Frame is transmitted on the primary20 channel and all the
1193 // primary20 channels are distinct, stations in other BSSes did not hear the frame
1194 for (uint8_t sta = 0; sta < m_nStationsPerBss; sta++)
1195 {
1197 m_received[bss].test(sta),
1198 false,
1199 "Station ["
1200 << +bss << "][" << +sta
1201 << "] received the Trigger Frame soliciting a transmission on primary"
1202 << txChannelWidth << " channel");
1203 }
1204 }
1205 // reset bitmaps
1206 m_received[bss].reset();
1207 m_processed[bss].reset();
1208 }
1209}
1210
1211/**
1212 * \ingroup wifi-test
1213 * \ingroup tests
1214 *
1215 * \brief Test functions returning the indices of primary and secondary channels
1216 * of different width.
1217 */
1219{
1220 public:
1221 /**
1222 * Constructor
1223 */
1225 ~Wifi20MHzChannelIndicesTest() override = default;
1226
1227 /**
1228 * Check that the indices of the 20 MHz channels included in all the primary
1229 * and secondary channels are correct when setting the given primary20 channel.
1230 *
1231 * \param primary20 the index of the primary20 channel to configure
1232 * \param secondary20 the expected index of the secondary20 channel
1233 * \param primary40 the expected indices of the 20 MHz channels in the primary40 channel
1234 * \param secondary40 the expected indices of the 20 MHz channels in the secondary40 channel
1235 * \param primary80 the expected indices of the 20 MHz channels in the primary80 channel
1236 * \param secondary80 the expected indices of the 20 MHz channels in the secondary80 channel
1237 */
1238 void RunOne(uint8_t primary20,
1239 const std::set<uint8_t>& secondary20,
1240 const std::set<uint8_t>& primary40,
1241 const std::set<uint8_t>& secondary40,
1242 const std::set<uint8_t>& primary80,
1243 const std::set<uint8_t>& secondary80);
1244
1245 private:
1246 void DoRun() override;
1247
1248 WifiPhyOperatingChannel m_channel; //!< operating channel
1249};
1250
1252 : TestCase("Check computation of primary and secondary channel indices")
1253{
1254}
1255
1256void
1258 const std::set<uint8_t>& secondary20,
1259 const std::set<uint8_t>& primary40,
1260 const std::set<uint8_t>& secondary40,
1261 const std::set<uint8_t>& primary80,
1262 const std::set<uint8_t>& secondary80)
1263{
1264 auto printToStr = [](const std::set<uint8_t>& s) {
1265 std::stringstream ss;
1266 ss << "{";
1267 for (const auto& index : s)
1268 {
1269 ss << +index << " ";
1270 }
1271 ss << "}";
1272 return ss.str();
1273 };
1274
1275 m_channel.SetPrimary20Index(primary20);
1276
1277 auto actualPrimary20 = m_channel.GetAll20MHzChannelIndicesInPrimary(20);
1278 NS_TEST_ASSERT_MSG_EQ((actualPrimary20 == std::set<uint8_t>{primary20}),
1279 true,
1280 "Expected Primary20 {" << +primary20 << "}"
1281 << " differs from actual "
1282 << printToStr(actualPrimary20));
1283
1284 auto actualSecondary20 = m_channel.GetAll20MHzChannelIndicesInSecondary(actualPrimary20);
1285 NS_TEST_ASSERT_MSG_EQ((actualSecondary20 == secondary20),
1286 true,
1287 "Expected Secondary20 " << printToStr(secondary20)
1288 << " differs from actual "
1289 << printToStr(actualSecondary20));
1290
1291 auto actualPrimary40 = m_channel.GetAll20MHzChannelIndicesInPrimary(40);
1292 NS_TEST_ASSERT_MSG_EQ((actualPrimary40 == primary40),
1293 true,
1294 "Expected Primary40 " << printToStr(primary40) << " differs from actual "
1295 << printToStr(actualPrimary40));
1296
1297 auto actualSecondary40 = m_channel.GetAll20MHzChannelIndicesInSecondary(primary40);
1298 NS_TEST_ASSERT_MSG_EQ((actualSecondary40 == secondary40),
1299 true,
1300 "Expected Secondary40 " << printToStr(secondary40)
1301 << " differs from actual "
1302 << printToStr(actualSecondary40));
1303
1304 auto actualPrimary80 = m_channel.GetAll20MHzChannelIndicesInPrimary(80);
1305 NS_TEST_ASSERT_MSG_EQ((actualPrimary80 == primary80),
1306 true,
1307 "Expected Primary80 " << printToStr(primary80) << " differs from actual "
1308 << printToStr(actualPrimary80));
1309
1310 auto actualSecondary80 = m_channel.GetAll20MHzChannelIndicesInSecondary(primary80);
1311 NS_TEST_ASSERT_MSG_EQ((actualSecondary80 == secondary80),
1312 true,
1313 "Expected Secondary80 " << printToStr(secondary80)
1314 << " differs from actual "
1315 << printToStr(actualSecondary80));
1316}
1317
1318void
1320{
1321 /* 20 MHz channel */
1323 RunOne(0, {}, {}, {}, {}, {});
1324
1325 /* 40 MHz channel */
1327 RunOne(0, {1}, {0, 1}, {}, {}, {});
1328 RunOne(1, {0}, {0, 1}, {}, {}, {});
1329
1330 /* 80 MHz channel */
1332 RunOne(0, {1}, {0, 1}, {2, 3}, {0, 1, 2, 3}, {});
1333 RunOne(1, {0}, {0, 1}, {2, 3}, {0, 1, 2, 3}, {});
1334 RunOne(2, {3}, {2, 3}, {0, 1}, {0, 1, 2, 3}, {});
1335 RunOne(3, {2}, {2, 3}, {0, 1}, {0, 1, 2, 3}, {});
1336
1337 /* 160 MHz channel */
1339 RunOne(0, {1}, {0, 1}, {2, 3}, {0, 1, 2, 3}, {4, 5, 6, 7});
1340 RunOne(1, {0}, {0, 1}, {2, 3}, {0, 1, 2, 3}, {4, 5, 6, 7});
1341 RunOne(2, {3}, {2, 3}, {0, 1}, {0, 1, 2, 3}, {4, 5, 6, 7});
1342 RunOne(3, {2}, {2, 3}, {0, 1}, {0, 1, 2, 3}, {4, 5, 6, 7});
1343 RunOne(4, {5}, {4, 5}, {6, 7}, {4, 5, 6, 7}, {0, 1, 2, 3});
1344 RunOne(5, {4}, {4, 5}, {6, 7}, {4, 5, 6, 7}, {0, 1, 2, 3});
1345 RunOne(6, {7}, {6, 7}, {4, 5}, {4, 5, 6, 7}, {0, 1, 2, 3});
1346 RunOne(7, {6}, {6, 7}, {4, 5}, {4, 5, 6, 7}, {0, 1, 2, 3});
1347}
1348
1349/**
1350 * \ingroup wifi-test
1351 * \ingroup tests
1352 *
1353 * \brief wifi primary channels test suite
1354 */
1356{
1357 public:
1359};
1360
1362 : TestSuite("wifi-primary-channels", Type::UNIT)
1363{
1364 // Test cases for 20 MHz can be added, but are not that useful (there would be a single BSS)
1365 AddTestCase(new WifiPrimaryChannelsTest(40, true), TestCase::Duration::QUICK);
1366 AddTestCase(new WifiPrimaryChannelsTest(40, false), TestCase::Duration::QUICK);
1367#if 0
1368 // Tests disabled until issue #776 resolved
1369 AddTestCase(new WifiPrimaryChannelsTest(80, true), TestCase::Duration::EXTENSIVE);
1370 AddTestCase(new WifiPrimaryChannelsTest(80, false), TestCase::Duration::EXTENSIVE);
1371 AddTestCase(new WifiPrimaryChannelsTest(160, true), TestCase::Duration::TAKES_FOREVER);
1372 AddTestCase(new WifiPrimaryChannelsTest(160, false), TestCase::Duration::TAKES_FOREVER);
1373#endif
1374 AddTestCase(new Wifi20MHzChannelIndicesTest(), TestCase::Duration::QUICK);
1375}
1376
Test functions returning the indices of primary and secondary channels of different width.
void DoRun() override
Implementation to actually run this TestCase.
~Wifi20MHzChannelIndicesTest() override=default
void RunOne(uint8_t primary20, const std::set< uint8_t > &secondary20, const std::set< uint8_t > &primary40, const std::set< uint8_t > &secondary40, const std::set< uint8_t > &primary80, const std::set< uint8_t > &secondary80)
Check that the indices of the 20 MHz channels included in all the primary and secondary channels are ...
WifiPhyOperatingChannel m_channel
operating channel
Test transmissions under different primary channel settings.
void DoSendHeTbPpdu(uint8_t bss, MHz_u txChannelWidth, HeRu::RuType ruType, std::size_t nRus)
Have the STAs of the given BSS transmit an HE TB PPDU using the given transmission channel width and ...
std::vector< std::bitset< 74 > > m_processed
whether the last packet transmitted to/from each of the (up to 74 per BSS) stations was processed
WifiPrimaryChannelsTest(MHz_u channelWidth, bool useDistinctBssColors)
Constructor.
void CheckAssociation()
Check that all stations associated with an AP.
void CheckReceivedSuPpdus(std::set< uint8_t > txBss, MHz_u txChannelWidth)
Check that (i) all stations belonging to the given BSSes received the SU PPDUs transmitted over the g...
std::vector< std::bitset< 74 > > m_received
whether the last packet transmitted to/from each of the (up to 74 per BSS) stations was received
void CheckReceivedTriggerFrames(std::set< uint8_t > txBss, MHz_u txChannelWidth)
Check that (i) all stations belonging to the given BSSes received the transmitted Trigger Frame; and ...
void Transmit(std::string context, WifiConstPsduMap psduMap, WifiTxVector txVector, double txPowerW)
Callback invoked when PHY receives a PSDU to transmit.
void SendDlMuPpdu(uint8_t bss, MHz_u txChannelWidth, HeRu::RuType ruType, std::size_t nRus)
Have the AP of the given BSS transmit a MU PPDU using the given transmission channel width and RU typ...
MHz_u m_channelWidth
operating channel width
Ptr< WifiPsdu > m_trigger
Basic Trigger Frame.
void DoRun() override
Implementation to actually run this TestCase.
void DoSetup() override
Implementation to do any local setup required for this TestCase.
Time m_time
the time when the current action is executed
Time m_triggerTxDuration
TX duration for Basic Trigger Frame.
uint8_t m_nStationsPerBss
number of stations per AP
void CheckReceivedMuPpdus(std::set< uint8_t > txBss, MHz_u txChannelWidth, HeRu::RuType ruType, std::size_t nRus, bool isDlMu)
Check that (i) all stations/APs belonging to the given BSSes received the DL/UL MU PPDUs transmitted ...
std::vector< NetDeviceContainer > m_staDevices
containers for stations' NetDevices
NetDeviceContainer m_apDevices
container for AP's NetDevice
void ReceiveDl(uint8_t bss, uint8_t station, Ptr< const WifiPsdu > psdu, RxSignalInfo rxSignalInfo, WifiTxVector txVector, std::vector< bool > perMpduStatus)
Callback invoked when a station receives a DL PPDU.
void ReceiveUl(uint8_t bss, Ptr< const WifiPsdu > psdu, RxSignalInfo rxSignalInfo, WifiTxVector txVector, std::vector< bool > perMpduStatus)
Callback invoked when an AP receives an UL PPDU.
void SendHeTbPpdu(uint8_t bss, MHz_u txChannelWidth, HeRu::RuType ruType, std::size_t nRus)
Have the AP of the given BSS transmit a Basic Trigger Frame.
bool m_useDistinctBssColors
true to set distinct BSS colors to BSSes
WifiTxVector m_triggerTxVector
TX vector for Basic Trigger Frame.
void SendDlSuPpdu(uint8_t bss, MHz_u txChannelWidth)
Have the AP of the given BSS transmit a SU PPDU using the given transmission channel width.
wifi primary channels test suite
void SetBeaconInterval(Time interval)
A container for one type of attribute.
void Set(const T &c)
Copy items from container c.
Headers for Trigger frames.
void SetType(TriggerFrameType type)
Set the Trigger frame type.
static WifiMode GetHeMcs8()
Return MCS 8 from HE MCS values.
static std::pair< uint16_t, Time > ConvertHeTbPpduDurationToLSigLength(Time ppduDuration, const WifiTxVector &txVector, WifiPhyBand band)
Compute the L-SIG length value corresponding to the given HE TB PPDU duration.
Definition he-phy.cc:261
static uint8_t GetEqualizedRuAllocation(RuType ruType, bool isOdd)
Get the RU_ALLOCATION value for equal size RUs.
Definition he-ru.cc:414
static std::size_t GetNRus(MHz_u bw, RuType ruType)
Get the number of distinct RUs of the given type (number of tones) available in a HE PPDU of the give...
Definition he-ru.cc:484
RuType
The different HE Resource Unit (RU) types.
Definition he-ru.h:32
static Mac48Address GetBroadcast()
Helper class used to assign positions and mobility models to nodes.
holds a vector of ns3::NetDevice pointers
void Add(NetDeviceContainer other)
Append the contents of another NetDeviceContainer to the end of this container.
Ptr< NetDevice > Get(uint32_t i) const
Get the Ptr<NetDevice> stored in this container at a given index.
keep track of a set of node pointers.
void Create(uint32_t n)
Create n nodes and append pointers to them to the end of this NodeContainer.
Ptr< Node > Get(uint32_t i) const
Get the Ptr<Node> stored in this container at a given index.
static WifiMode GetOfdmRate6Mbps()
Return a WifiMode for OFDM at 6 Mbps.
Smart pointer class similar to boost::intrusive_ptr.
static void SetRun(uint64_t run)
Set the run number of simulation.
static void SetSeed(uint32_t seed)
Set the seed.
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition simulator.h:560
static void Destroy()
Execute the events scheduled with ScheduleDestroy().
Definition simulator.cc:131
static void Run()
Run the simulation.
Definition simulator.cc:167
static void Stop()
Tell the Simulator the calling event should be the last one executed.
Definition simulator.cc:175
Make it easy to create and manage PHY objects for the spectrum model.
The IEEE 802.11 SSID Information Element.
Definition ssid.h:25
encapsulates test code
Definition test.h:1050
void AddTestCase(TestCase *testCase, Duration duration=Duration::QUICK)
Add an individual child TestCase to this test suite.
Definition test.cc:292
A suite of tests to run.
Definition test.h:1267
Type
Type of test.
Definition test.h:1274
Simulation virtual time values and global simulation resolution.
Definition nstime.h:94
bool IsZero() const
Exactly equivalent to t == 0.
Definition nstime.h:304
AttributeValue implementation for Tuple.
Definition tuple.h:67
Hold an unsigned integer type.
Definition uinteger.h:34
static WifiMode GetVhtMcs5()
Return MCS 5 from VHT MCS values.
helps to create WifiNetDevice objects
static int64_t AssignStreams(NetDeviceContainer c, int64_t stream)
Assign a fixed random variable stream number to the random variables used by the PHY and MAC aspects ...
Implements the IEEE 802.11 MAC header.
Mac48Address GetAddr1() const
Return the address in the Address 1 field.
bool IsTrigger() const
Return true if the header is a Trigger header.
void SetSequenceNumber(uint16_t seq)
Set the sequence number of the header.
void SetAddr1(Mac48Address address)
Fill the Address 1 field with the given address.
virtual void SetType(WifiMacType type, bool resetToDsFromDs=true)
Set Type/Subtype values with the correct values depending on the given type.
void SetQosTid(uint8_t tid)
Set the TID for the QoS header.
void SetAddr2(Mac48Address address)
Fill the Address 2 field with the given address.
bool IsQosData() const
Return true if the Type is DATA and Subtype is one of the possible values for QoS Data.
void SetAddr3(Mac48Address address)
Fill the Address 3 field with the given address.
create MAC layers for a ns3::WifiNetDevice.
void SetSsid(Ssid ssid)
Definition wifi-mac.cc:512
static Time CalculateTxDuration(uint32_t size, const WifiTxVector &txVector, WifiPhyBand band, uint16_t staId=SU_STA_ID)
Definition wifi-phy.cc:1572
std::vector< ChannelTuple > ChannelSegments
segments identifying an operating channel
Definition wifi-phy.h:925
void SetReceiveOkCallback(RxOkCallback callback)
Definition wifi-phy.cc:472
Class that keeps track of all information about the current PHY operating channel.
std::set< uint8_t > GetAll20MHzChannelIndicesInSecondary(MHz_u width) const
Get the channel indices of all the 20 MHz channels included in the secondary channel of the given wid...
void SetPrimary20Index(uint8_t index)
Set the index of the primary 20 MHz channel (0 indicates the 20 MHz subchannel with the lowest center...
std::set< uint8_t > GetAll20MHzChannelIndicesInPrimary(MHz_u width) const
Get the channel indices of all the 20 MHz channels included in the primary channel of the given width...
void SetDefault(MHz_u width, WifiStandard standard, WifiPhyBand band)
Set the default channel of the given width and for the given standard and band.
const WifiMacHeader & GetHeader(std::size_t i) const
Get the header of the i-th MPDU.
Definition wifi-psdu.cc:268
uint32_t GetSize() const
Return the size of the PSDU in bytes.
Definition wifi-psdu.cc:262
This class mimics the TXVECTOR which is to be passed to the PHY in order to define the parameters whi...
void SetRuAllocation(const RuAllocation &ruAlloc, uint8_t p20Index)
Set RU_ALLOCATION field.
void SetHeMuUserInfo(uint16_t staId, HeMuUserInfo userInfo)
Set the HE MU user-specific transmission information for the given STA-ID.
const HeMuUserInfoMap & GetHeMuUserInfoMap() const
Get a const reference to the map HE MU user-specific transmission information indexed by STA-ID.
void SetLength(uint16_t length)
Set the LENGTH field of the L-SIG.
void SetSigBMode(const WifiMode &mode)
Set the MCS used for SIG-B.
void Connect(std::string path, const CallbackBase &cb)
Definition config.cc:967
#define NS_ABORT_MSG(msg)
Unconditional abnormal program termination with a message.
Definition abort.h:38
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition log.h:191
#define NS_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
Definition log.h:264
Ptr< T > CreateObject(Args &&... args)
Create an object by type, with varying number of constructor parameters.
Definition object.h:619
Ptr< T > Create(Ts &&... args)
Create class instances by constructors with varying numbers of arguments and return them by Ptr.
Definition ptr.h:436
#define NS_TEST_ASSERT_MSG_EQ(actual, limit, msg)
Test that an actual and expected (limit) value are equal and report and abort if not.
Definition test.h:134
#define NS_TEST_EXPECT_MSG_EQ(actual, limit, msg)
Test that an actual and expected (limit) value are equal and report if not.
Definition test.h:241
Time MicroSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1332
Time NanoSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1344
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition nstime.h:1308
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1320
@ WIFI_STANDARD_80211ax
@ WIFI_PREAMBLE_LONG
@ WIFI_PREAMBLE_HE_TB
@ WIFI_PREAMBLE_HE_MU
@ WIFI_PREAMBLE_HE_SU
@ WIFI_PHY_BAND_5GHZ
The 5 GHz band.
Every class exported by the ns3 library is enclosed in the ns3 namespace.
std::unordered_map< uint16_t, Ptr< const WifiPsdu > > WifiConstPsduMap
Map of const PSDUs indexed by STA-ID.
Callback< R, Args... > MakeCallback(R(T::*memPtr)(Args...), OBJ objPtr)
Build Callbacks for class method members which take varying numbers of arguments and potentially retu...
Definition callback.h:684
Ptr< T1 > DynamicCast(const Ptr< T2 > &p)
Cast a Ptr.
Definition ptr.h:580
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:183
@ WIFI_MAC_CTL_TRIGGER
@ WIFI_MAC_QOSDATA
Ptr< T1 > StaticCast(const Ptr< T2 > &p)
Cast a Ptr.
Definition ptr.h:587
std::vector< uint8_t > RuAllocation
8 bit RU_ALLOCATION per 20 MHz
static constexpr uint16_t SU_STA_ID
STA_ID to identify a single user (SU)
Definition wifi-mode.h:24
-ns3 Test suite for the ns3 wrapper script
RxSignalInfo structure containing info on the received signal.
Definition wifi-types.h:72
static WifiPrimaryChannelsTestSuite g_wifiPrimaryChannelsTestSuite
the test suite