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, 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, 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, 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 const WifiTxVector& txVector,
130 const 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 const WifiTxVector& txVector,
144 const 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 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 const WifiTxVector& txVector,
248 const 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 const WifiTxVector& txVector,
283 const 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
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()->m_bssColor = 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 MHz_u{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 interference
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 interference
611 uint16_t nRounds = 2;
612 uint16_t nApsPerRound = Count20MHzSubchannels(m_channelWidth) / 2;
613 for (MHz_u txChannelWidth{20}; txChannelWidth <= m_channelWidth;
614 txChannelWidth *= 2, nRounds *= 2, nApsPerRound /= 2)
615 {
616 nRounds = std::min<uint16_t>(nRounds, m_nBss);
617 nApsPerRound = std::max<uint16_t>(nApsPerRound, 1);
618
619 for (uint16_t round = 0; round < nRounds; round++)
620 {
621 std::set<uint8_t> txBss;
622
623 for (uint16_t i = 0; i < nApsPerRound; i++)
624 {
625 uint16_t ap = round + i * nRounds;
626 txBss.insert(ap);
629 this,
630 ap,
631 txChannelWidth);
632 }
633 // check that the SU frames were correctly received
634 Simulator::Schedule(m_time + roundDuration,
636 this,
637 txBss,
638 txChannelWidth);
639 m_time += roundDuration;
640 }
641 }
642
643 /*
644 * Repeat the same scheme as before with DL MU transmissions. For each transmission
645 * channel width, every round is repeated as many times as the number of ways in
646 * which we can partition the transmission channel width in equal sized RUs.
647 */
648 nRounds = 2;
649 nApsPerRound = Count20MHzSubchannels(m_channelWidth) / 2;
650 for (MHz_u txChannelWidth{20}; txChannelWidth <= m_channelWidth;
651 txChannelWidth *= 2, nRounds *= 2, nApsPerRound /= 2)
652 {
653 nRounds = std::min<uint16_t>(nRounds, m_nBss);
654 nApsPerRound = std::max<uint16_t>(nApsPerRound, 1);
655
656 for (uint16_t round = 0; round < nRounds; round++)
657 {
658 for (unsigned int type = 0; type < 7; type++)
659 {
660 auto ruType = static_cast<RuType>(type);
661 std::size_t nRus = HeRu::GetNRus(txChannelWidth, ruType);
662 std::set<uint8_t> txBss;
663 if (nRus > 0)
664 {
665 for (uint16_t i = 0; i < nApsPerRound; i++)
666 {
667 uint16_t ap = round + i * nRounds;
668 txBss.insert(ap);
671 this,
672 ap,
673 txChannelWidth,
674 ruType,
675 nRus);
676 }
677 // check that the MU frame was correctly received
678 Simulator::Schedule(m_time + roundDuration,
680 this,
681 txBss,
682 txChannelWidth,
683 ruType,
684 nRus,
685 /* isDlMu */ true);
686 m_time += roundDuration;
687 }
688 }
689 }
690 }
691
692 /*
693 * Repeat the same scheme as before with UL MU transmissions. For each transmission
694 * channel width, every round is repeated as many times as the number of ways in
695 * which we can partition the transmission channel width in equal sized RUs.
696 */
697 nRounds = 2;
698 nApsPerRound = Count20MHzSubchannels(m_channelWidth) / 2;
699 for (MHz_u txChannelWidth{20}; txChannelWidth <= m_channelWidth;
700 txChannelWidth *= 2, nRounds *= 2, nApsPerRound /= 2)
701 {
702 nRounds = std::min<uint16_t>(nRounds, m_nBss);
703 nApsPerRound = std::max<uint16_t>(nApsPerRound, 1);
704
705 for (uint16_t round = 0; round < nRounds; round++)
706 {
707 for (unsigned int type = 0; type < 7; type++)
708 {
709 auto ruType = static_cast<RuType>(type);
710 std::size_t nRus = HeRu::GetNRus(txChannelWidth, ruType);
711 std::set<uint8_t> txBss;
712 if (nRus > 0)
713 {
714 for (uint16_t i = 0; i < nApsPerRound; i++)
715 {
716 uint16_t ap = round + i * nRounds;
717 txBss.insert(ap);
720 this,
721 ap,
722 txChannelWidth,
723 ruType,
724 nRus);
725 }
726 // check that Trigger Frames and TB PPDUs were correctly received
728 MicroSeconds(10), /* during SIFS */
730 this,
731 txBss,
732 txChannelWidth);
733 Simulator::Schedule(m_time + roundDuration,
735 this,
736 txBss,
737 txChannelWidth,
738 ruType,
739 nRus,
740 /* isDlMu */ false);
741 m_time += roundDuration;
742 }
743 }
744 }
745 }
746
747 // Trace PSDUs passed to the PHY on all devices
748 Config::Connect("/NodeList/*/DeviceList/*/$ns3::WifiNetDevice/Phy/PhyTxPsduBegin",
750
753
755}
756
757void
759{
760 NS_LOG_INFO("*** BSS " << +bss << " transmits on primary " << txChannelWidth << " MHz channel");
761
762 auto apDev = DynamicCast<WifiNetDevice>(m_apDevices.Get(bss));
763 auto staDev = DynamicCast<WifiNetDevice>(m_staDevices[bss].Get(0));
764
765 uint8_t bssColor = apDev->GetHeConfiguration()->m_bssColor;
767 0,
769 NanoSeconds(800),
770 1,
771 1,
772 0,
773 txChannelWidth,
774 false,
775 false,
776 false,
777 bssColor);
778 WifiMacHeader hdr;
780 hdr.SetQosTid(0);
781 hdr.SetAddr1(staDev->GetMac()->GetAddress());
782 hdr.SetAddr2(apDev->GetMac()->GetAddress());
783 hdr.SetAddr3(apDev->GetMac()->GetBssid(0));
784 hdr.SetSequenceNumber(1);
786 apDev->GetPhy()->Send(WifiConstPsduMap({std::make_pair(SU_STA_ID, psdu)}), txVector);
787}
788
789void
791 MHz_u txChannelWidth,
792 RuType ruType,
793 std::size_t nRus)
794{
795 NS_LOG_INFO("*** BSS " << +bss << " transmits on primary " << txChannelWidth
796 << " MHz channel a DL MU PPDU "
797 << "addressed to " << nRus << " stations (RU type: " << ruType << ")");
798
799 auto apDev = DynamicCast<WifiNetDevice>(m_apDevices.Get(bss));
800 uint8_t bssColor = apDev->GetHeConfiguration()->m_bssColor;
801
803 0,
805 NanoSeconds(800),
806 1,
807 1,
808 0,
809 txChannelWidth,
810 false,
811 false,
812 false,
813 bssColor);
814 WifiMacHeader hdr;
816 hdr.SetQosTid(0);
817 hdr.SetAddr2(apDev->GetMac()->GetAddress());
818 hdr.SetAddr3(apDev->GetMac()->GetBssid(0));
819 hdr.SetSequenceNumber(1);
820
821 WifiConstPsduMap psduMap;
822
823 for (std::size_t i = 1; i <= nRus; i++)
824 {
825 auto primary80{true};
826 auto index{i};
827 if ((txChannelWidth == MHz_u{160}) && (i > nRus / 2))
828 {
829 index = HeRu::GetIndexIn80MHzSegment(txChannelWidth, ruType, i);
830 primary80 = HeRu::GetPrimary80MHzFlag(txChannelWidth,
831 ruType,
832 i,
833 apDev->GetPhy()->GetPrimary20Index());
834 }
835
836 auto staDev = DynamicCast<WifiNetDevice>(m_staDevices[bss].Get(i - 1));
837 uint16_t staId = DynamicCast<StaWifiMac>(staDev->GetMac())->GetAssociationId();
838 txVector.SetHeMuUserInfo(staId, {HeRu::RuSpec{ruType, index, primary80}, 8, 1});
839 hdr.SetAddr1(staDev->GetMac()->GetAddress());
840 psduMap[staId] = Create<const WifiPsdu>(Create<Packet>(1000), hdr);
841 }
843
844 apDev->GetPhy()->Send(psduMap, txVector);
845}
846
847void
849 MHz_u txChannelWidth,
850 RuType ruType,
851 std::size_t nRus)
852{
853 NS_LOG_INFO("*** BSS " << +bss << " transmits a Basic Trigger Frame");
854
855 auto apDev = DynamicCast<WifiNetDevice>(m_apDevices.Get(bss));
856
857 m_trigger->GetHeader(0).SetAddr2(apDev->GetMac()->GetAddress());
858
859 apDev->GetPhy()->Send(m_trigger, m_triggerTxVector);
860
861 // schedule the transmission of HE TB PPDUs
862 Simulator::Schedule(m_triggerTxDuration + apDev->GetPhy()->GetSifs(),
864 this,
865 bss,
866 txChannelWidth,
867 ruType,
868 nRus);
869}
870
871void
873 MHz_u txChannelWidth,
874 RuType ruType,
875 std::size_t nRus)
876{
877 auto apDev = DynamicCast<WifiNetDevice>(m_apDevices.Get(bss));
878 uint8_t bssColor = apDev->GetHeConfiguration()->m_bssColor;
879
880 WifiMacHeader hdr;
882 hdr.SetQosTid(0);
883 hdr.SetAddr1(apDev->GetMac()->GetAddress());
884 hdr.SetAddr3(apDev->GetMac()->GetBssid(0));
885 hdr.SetSequenceNumber(1);
886
887 Time duration;
888 uint16_t length = 0;
889 WifiTxVector trigVector(HePhy::GetHeMcs8(),
890 0,
892 NanoSeconds(3200),
893 1,
894 1,
895 0,
896 txChannelWidth,
897 false,
898 false,
899 false,
900 bssColor);
901
902 for (std::size_t i = 1; i <= nRus; i++)
903 {
904 NS_LOG_INFO("*** BSS " << +bss << " STA " << i - 1 << " transmits on primary "
905 << txChannelWidth
906 << " MHz channel an HE TB PPDU (RU type: " << ruType << ")");
907
908 auto primary80{true};
909 auto index{i};
910 if ((txChannelWidth == MHz_u{160}) && (i > nRus / 2))
911 {
912 index = HeRu::GetIndexIn80MHzSegment(txChannelWidth, ruType, i);
913 primary80 = HeRu::GetPrimary80MHzFlag(txChannelWidth,
914 ruType,
915 i,
916 apDev->GetPhy()->GetPrimary20Index());
917 }
918
919 auto staDev = DynamicCast<WifiNetDevice>(m_staDevices[bss].Get(i - 1));
920 uint16_t staId = DynamicCast<StaWifiMac>(staDev->GetMac())->GetAssociationId();
921
923 0,
925 NanoSeconds(3200),
926 1,
927 1,
928 0,
929 txChannelWidth,
930 false,
931 false,
932 false,
933 bssColor);
934 txVector.SetHeMuUserInfo(staId, {HeRu::RuSpec{ruType, index, primary80}, 8, 1});
935 trigVector.SetHeMuUserInfo(staId, {HeRu::RuSpec{ruType, index, primary80}, 8, 1});
936
937 hdr.SetAddr2(staDev->GetMac()->GetAddress());
939
940 if (duration.IsZero())
941 {
942 // calculate just once
943 duration = WifiPhy::CalculateTxDuration(psdu->GetSize(),
944 txVector,
945 staDev->GetMac()->GetWifiPhy()->GetPhyBand(),
946 staId);
947 std::tie(length, duration) = HePhy::ConvertHeTbPpduDurationToLSigLength(
948 duration,
949 txVector,
950 staDev->GetMac()->GetWifiPhy()->GetPhyBand());
951 }
952 txVector.SetLength(length);
953
954 staDev->GetPhy()->Send(WifiConstPsduMap{{staId, psdu}}, txVector);
955 }
956
957 // AP's PHY expects to receive a TRIGVECTOR (just once)
958 trigVector.SetLength(length);
959 auto apHePhy = StaticCast<HePhy>(apDev->GetPhy()->GetLatestPhyEntity());
960 apHePhy->SetTrigVector(trigVector, duration);
961}
962
963void
965{
966 for (uint8_t bss = 0; bss < m_nBss; bss++)
967 {
969 auto mac = DynamicCast<ApWifiMac>(dev->GetMac());
970 NS_TEST_EXPECT_MSG_EQ(mac->GetStaList(SINGLE_LINK_OP_ID).size(),
972 "Not all the stations completed association");
973 }
974}
975
976void
977WifiPrimaryChannelsTest::CheckReceivedSuPpdus(std::set<uint8_t> txBss, MHz_u txChannelWidth)
978{
979 for (uint8_t bss = 0; bss < m_nBss; bss++)
980 {
981 if (txBss.find(bss) != txBss.end())
982 {
983 // Every station in the BSS of an AP that transmitted the frame hears (i.e.,
984 // passes to the MAC) the frame
985 for (uint8_t sta = 0; sta < m_nStationsPerBss; sta++)
986 {
988 true,
989 "Station [" << +bss << "][" << +sta
990 << "] did not receive the SU frame on primary"
991 << txChannelWidth << " channel");
992 }
993 // only the first station actually processed the frames
995 true,
996 "Station [" << +bss << "][0]"
997 << " did not process the SU frame on primary"
998 << txChannelWidth << " channel");
999 for (uint8_t sta = 1; sta < m_nStationsPerBss; sta++)
1000 {
1002 false,
1003 "Station [" << +bss << "][" << +sta
1004 << "] processed the SU frame on primary"
1005 << txChannelWidth << " channel");
1006 }
1007 }
1008 else
1009 {
1010 // There was no transmission in this BSS. If BSS Color filtering is enabled or no frame
1011 // transmission overlaps with the primary20 channel of this BSS, stations in this BSS
1012 // did not hear any frame.
1014 std::none_of(txBss.begin(), txBss.end(), [&](const uint8_t& txAp) {
1015 auto txApPhy = DynamicCast<WifiNetDevice>(m_apDevices.Get(txAp))->GetPhy();
1016 auto thisApPhy = DynamicCast<WifiNetDevice>(m_apDevices.Get(bss))->GetPhy();
1017 return txApPhy->GetOperatingChannel().GetPrimaryChannelIndex(txChannelWidth) ==
1018 thisApPhy->GetOperatingChannel().GetPrimaryChannelIndex(txChannelWidth);
1019 }))
1020 {
1021 for (uint8_t sta = 0; sta < m_nStationsPerBss; sta++)
1022 {
1024 false,
1025 "Station [" << +bss << "][" << +sta
1026 << "] received the SU frame on primary"
1027 << txChannelWidth << " channel");
1028 }
1029 }
1030 else
1031 {
1032 // all stations heard the frame but no station processed it
1033 for (uint8_t sta = 0; sta < m_nStationsPerBss; sta++)
1034 {
1036 true,
1037 "Station [" << +bss << "][" << +sta
1038 << "] did not receive the SU frame on primary"
1039 << txChannelWidth << " channel");
1041 false,
1042 "Station [" << +bss << "][" << +sta
1043 << "] processed the SU frame on primary"
1044 << txChannelWidth << " channel");
1045 }
1046 }
1047 }
1048 // reset bitmaps
1049 m_received[bss].reset();
1050 m_processed[bss].reset();
1051 }
1052}
1053
1054void
1056 MHz_u txChannelWidth,
1057 RuType ruType,
1058 std::size_t nRus,
1059 bool isDlMu)
1060{
1061 for (uint8_t bss = 0; bss < m_nBss; bss++)
1062 {
1063 if (txBss.find(bss) != txBss.end())
1064 {
1065 // There was a transmission in this BSS.
1066 // [DL] Due to AID filtering, only stations that are addressed by the MU PPDU do hear
1067 // the frame [UL] The AP hears a TB PPDU sent by all and only the solicited stations
1068 for (std::size_t sta = 0; sta < nRus; sta++)
1069 {
1071 m_received[bss].test(sta),
1072 true,
1073 (isDlMu ? "A DL MU PPDU transmitted to" : "An HE TB PPDU transmitted by")
1074 << " station [" << +bss << "][" << +sta << "] on primary" << txChannelWidth
1075 << " channel, RU type " << ruType << " was not received");
1076 }
1077 for (uint8_t sta = nRus; sta < m_nStationsPerBss; sta++)
1078 {
1080 false,
1081 (isDlMu ? "A DL MU PPDU" : "An HE TB PPDU")
1082 << " transmitted on primary" << txChannelWidth
1083 << " channel, RU type " << ruType << " was received "
1084 << (isDlMu ? "by" : "from") << " station [" << +bss
1085 << "][" << +sta << "]");
1086 }
1087 // [DL] Only the addressed stations actually processed the frames
1088 // [UL] The AP processed the frames sent by all and only the addressed stations
1089 for (std::size_t sta = 0; sta < nRus; sta++)
1090 {
1092 m_processed[bss].test(sta),
1093 true,
1094 (isDlMu ? "A DL MU PPDU transmitted to" : "An HE TB PPDU transmitted by")
1095 << " station [" << +bss << "][" << +sta << "] on primary" << txChannelWidth
1096 << " channel, RU type " << ruType << " was not processed");
1097 }
1098 for (uint8_t sta = nRus; sta < m_nStationsPerBss; sta++)
1099 {
1101 false,
1102 (isDlMu ? "A DL MU PPDU" : "An HE TB PPDU")
1103 << " transmitted on primary" << txChannelWidth
1104 << " channel, RU type " << ruType << " was received "
1105 << (isDlMu ? "by" : "from") << " station [" << +bss
1106 << "][" << +sta << "] and processed");
1107 }
1108 }
1109 else
1110 {
1111 // There was no transmission in this BSS.
1112 // [DL] If BSS Color filtering is enabled or no frame transmission overlaps with
1113 // the primary20 channel of this BSS, stations in this BSS did not hear any frame.
1114 // [UL] The AP did not hear any TB PPDU because no TRIGVECTOR was passed to the PHY
1115 if (!isDlMu || m_useDistinctBssColors ||
1116 std::none_of(txBss.begin(), txBss.end(), [&](const uint8_t& txAp) {
1117 auto txApPhy = DynamicCast<WifiNetDevice>(m_apDevices.Get(txAp))->GetPhy();
1118 auto thisApPhy = DynamicCast<WifiNetDevice>(m_apDevices.Get(bss))->GetPhy();
1119 return txApPhy->GetOperatingChannel().GetPrimaryChannelIndex(txChannelWidth) ==
1120 thisApPhy->GetOperatingChannel().GetPrimaryChannelIndex(txChannelWidth);
1121 }))
1122 {
1123 for (uint8_t sta = 0; sta < m_nStationsPerBss; sta++)
1124 {
1126 false,
1127 (isDlMu ? "A DL MU PPDU" : "An HE TB PPDU")
1128 << " transmitted on primary" << txChannelWidth
1129 << " channel, RU type " << ruType << " was received "
1130 << (isDlMu ? "by" : "from") << " station [" << +bss
1131 << "][" << +sta << "]");
1132 }
1133 }
1134 else
1135 {
1136 // [DL] Stations having the same AID of the stations addressed by the MU PPDU
1137 // received the frame
1138 for (std::size_t sta = 0; sta < nRus; sta++)
1139 {
1141 m_received[bss].test(sta),
1142 true,
1143 (isDlMu ? "A DL MU PPDU transmitted to" : "An HE TB PPDU transmitted by")
1144 << " station [" << +bss << "][" << +sta << "] on primary"
1145 << txChannelWidth << " channel, RU type " << ruType
1146 << " was not received");
1147 }
1148 for (uint8_t sta = nRus; sta < m_nStationsPerBss; sta++)
1149 {
1151 false,
1152 (isDlMu ? "A DL MU PPDU" : "An HE TB PPDU")
1153 << " transmitted on primary" << txChannelWidth
1154 << " channel, RU type " << ruType << " was received "
1155 << (isDlMu ? "by" : "from") << " station [" << +bss
1156 << "][" << +sta << "]");
1157 }
1158 // no station processed the frame
1159 for (uint8_t sta = 0; sta < m_nStationsPerBss; sta++)
1160 {
1162 false,
1163 (isDlMu ? "A DL MU PPDU" : "An HE TB PPDU")
1164 << " transmitted on primary" << txChannelWidth
1165 << " channel, RU type " << ruType << " was received "
1166 << (isDlMu ? "by" : "from") << " station [" << +bss
1167 << "][" << +sta << "] and processed");
1168 }
1169 }
1170 }
1171 // reset bitmaps
1172 m_received[bss].reset();
1173 m_processed[bss].reset();
1174 }
1175}
1176
1177void
1178WifiPrimaryChannelsTest::CheckReceivedTriggerFrames(std::set<uint8_t> txBss, MHz_u txChannelWidth)
1179{
1180 for (uint8_t bss = 0; bss < m_nBss; bss++)
1181 {
1182 if (txBss.find(bss) != txBss.end())
1183 {
1184 // Every station in the BSS of an AP that transmitted the Trigger Frame hears (i.e.,
1185 // passes to the MAC) and processes the frame
1186 for (uint8_t sta = 0; sta < m_nStationsPerBss; sta++)
1187 {
1189 true,
1190 "Station [" << +bss << "][" << +sta
1191 << "] did not receive the Trigger Frame "
1192 "soliciting a transmission on primary"
1193 << txChannelWidth << " channel");
1195 true,
1196 "Station [" << +bss << "][" << +sta
1197 << "] did not process the Trigger Frame "
1198 "soliciting a transmission on primary"
1199 << txChannelWidth << " channel");
1200 }
1201 }
1202 else
1203 {
1204 // Given that a Trigger Frame is transmitted on the primary20 channel and all the
1205 // primary20 channels are distinct, stations in other BSSes did not hear the frame
1206 for (uint8_t sta = 0; sta < m_nStationsPerBss; sta++)
1207 {
1209 m_received[bss].test(sta),
1210 false,
1211 "Station ["
1212 << +bss << "][" << +sta
1213 << "] received the Trigger Frame soliciting a transmission on primary"
1214 << txChannelWidth << " channel");
1215 }
1216 }
1217 // reset bitmaps
1218 m_received[bss].reset();
1219 m_processed[bss].reset();
1220 }
1221}
1222
1223/**
1224 * @ingroup wifi-test
1225 * @ingroup tests
1226 *
1227 * @brief Test functions returning the indices of primary and secondary channels
1228 * of different width.
1229 */
1231{
1232 public:
1233 /**
1234 * Constructor
1235 */
1237 ~Wifi20MHzChannelIndicesTest() override = default;
1238
1239 /**
1240 * Check that the indices of the 20 MHz channels included in all the primary
1241 * and secondary channels are correct when setting the given primary20 channel.
1242 *
1243 * @param primary20 the index of the primary20 channel to configure
1244 * @param secondary20 the expected index of the secondary20 channel
1245 * @param primary40 the expected indices of the 20 MHz channels in the primary40 channel
1246 * @param secondary40 the expected indices of the 20 MHz channels in the secondary40 channel
1247 * @param primary80 the expected indices of the 20 MHz channels in the primary80 channel
1248 * @param secondary80 the expected indices of the 20 MHz channels in the secondary80 channel
1249 */
1250 void RunOne(uint8_t primary20,
1251 const std::set<uint8_t>& secondary20,
1252 const std::set<uint8_t>& primary40,
1253 const std::set<uint8_t>& secondary40,
1254 const std::set<uint8_t>& primary80,
1255 const std::set<uint8_t>& secondary80);
1256
1257 private:
1258 void DoRun() override;
1259
1260 WifiPhyOperatingChannel m_channel; //!< operating channel
1261};
1262
1264 : TestCase("Check computation of primary and secondary channel indices")
1265{
1266}
1267
1268void
1270 const std::set<uint8_t>& secondary20,
1271 const std::set<uint8_t>& primary40,
1272 const std::set<uint8_t>& secondary40,
1273 const std::set<uint8_t>& primary80,
1274 const std::set<uint8_t>& secondary80)
1275{
1276 auto printToStr = [](const std::set<uint8_t>& s) {
1277 std::stringstream ss;
1278 ss << "{";
1279 for (const auto& index : s)
1280 {
1281 ss << +index << " ";
1282 }
1283 ss << "}";
1284 return ss.str();
1285 };
1286
1287 m_channel.SetPrimary20Index(primary20);
1288
1289 auto actualPrimary20 = m_channel.GetAll20MHzChannelIndicesInPrimary(MHz_u{20});
1290 NS_TEST_ASSERT_MSG_EQ((actualPrimary20 == std::set<uint8_t>{primary20}),
1291 true,
1292 "Expected Primary20 {" << +primary20 << "}"
1293 << " differs from actual "
1294 << printToStr(actualPrimary20));
1295
1296 auto actualSecondary20 = m_channel.GetAll20MHzChannelIndicesInSecondary(actualPrimary20);
1297 NS_TEST_ASSERT_MSG_EQ((actualSecondary20 == secondary20),
1298 true,
1299 "Expected Secondary20 " << printToStr(secondary20)
1300 << " differs from actual "
1301 << printToStr(actualSecondary20));
1302
1303 auto actualPrimary40 = m_channel.GetAll20MHzChannelIndicesInPrimary(MHz_u{40});
1304 NS_TEST_ASSERT_MSG_EQ((actualPrimary40 == primary40),
1305 true,
1306 "Expected Primary40 " << printToStr(primary40) << " differs from actual "
1307 << printToStr(actualPrimary40));
1308
1309 auto actualSecondary40 = m_channel.GetAll20MHzChannelIndicesInSecondary(primary40);
1310 NS_TEST_ASSERT_MSG_EQ((actualSecondary40 == secondary40),
1311 true,
1312 "Expected Secondary40 " << printToStr(secondary40)
1313 << " differs from actual "
1314 << printToStr(actualSecondary40));
1315
1316 auto actualPrimary80 = m_channel.GetAll20MHzChannelIndicesInPrimary(MHz_u{80});
1317 NS_TEST_ASSERT_MSG_EQ((actualPrimary80 == primary80),
1318 true,
1319 "Expected Primary80 " << printToStr(primary80) << " differs from actual "
1320 << printToStr(actualPrimary80));
1321
1322 auto actualSecondary80 = m_channel.GetAll20MHzChannelIndicesInSecondary(primary80);
1323 NS_TEST_ASSERT_MSG_EQ((actualSecondary80 == secondary80),
1324 true,
1325 "Expected Secondary80 " << printToStr(secondary80)
1326 << " differs from actual "
1327 << printToStr(actualSecondary80));
1328}
1329
1330void
1332{
1333 /* 20 MHz channel */
1335 RunOne(0, {}, {}, {}, {}, {});
1336
1337 /* 40 MHz channel */
1339 RunOne(0, {1}, {0, 1}, {}, {}, {});
1340 RunOne(1, {0}, {0, 1}, {}, {}, {});
1341
1342 /* 80 MHz channel */
1344 RunOne(0, {1}, {0, 1}, {2, 3}, {0, 1, 2, 3}, {});
1345 RunOne(1, {0}, {0, 1}, {2, 3}, {0, 1, 2, 3}, {});
1346 RunOne(2, {3}, {2, 3}, {0, 1}, {0, 1, 2, 3}, {});
1347 RunOne(3, {2}, {2, 3}, {0, 1}, {0, 1, 2, 3}, {});
1348
1349 /* 160 MHz channel */
1351 RunOne(0, {1}, {0, 1}, {2, 3}, {0, 1, 2, 3}, {4, 5, 6, 7});
1352 RunOne(1, {0}, {0, 1}, {2, 3}, {0, 1, 2, 3}, {4, 5, 6, 7});
1353 RunOne(2, {3}, {2, 3}, {0, 1}, {0, 1, 2, 3}, {4, 5, 6, 7});
1354 RunOne(3, {2}, {2, 3}, {0, 1}, {0, 1, 2, 3}, {4, 5, 6, 7});
1355 RunOne(4, {5}, {4, 5}, {6, 7}, {4, 5, 6, 7}, {0, 1, 2, 3});
1356 RunOne(5, {4}, {4, 5}, {6, 7}, {4, 5, 6, 7}, {0, 1, 2, 3});
1357 RunOne(6, {7}, {6, 7}, {4, 5}, {4, 5, 6, 7}, {0, 1, 2, 3});
1358 RunOne(7, {6}, {6, 7}, {4, 5}, {4, 5, 6, 7}, {0, 1, 2, 3});
1359}
1360
1361/**
1362 * @ingroup wifi-test
1363 * @ingroup tests
1364 *
1365 * @brief wifi primary channels test suite
1366 */
1368{
1369 public:
1371};
1372
1374 : TestSuite("wifi-primary-channels", Type::UNIT)
1375{
1376 // Test cases for 20 MHz can be added, but are not that useful (there would be a single BSS)
1377 AddTestCase(new WifiPrimaryChannelsTest(MHz_u{40}, true), TestCase::Duration::QUICK);
1378 AddTestCase(new WifiPrimaryChannelsTest(MHz_u{40}, false), TestCase::Duration::QUICK);
1379 AddTestCase(new WifiPrimaryChannelsTest(MHz_u{80}, true), TestCase::Duration::EXTENSIVE);
1380 AddTestCase(new WifiPrimaryChannelsTest(MHz_u{80}, false), TestCase::Duration::EXTENSIVE);
1381 AddTestCase(new WifiPrimaryChannelsTest(MHz_u{160}, true), TestCase::Duration::TAKES_FOREVER);
1382 AddTestCase(new WifiPrimaryChannelsTest(MHz_u{160}, false), TestCase::Duration::TAKES_FOREVER);
1383 AddTestCase(new Wifi20MHzChannelIndicesTest(), TestCase::Duration::QUICK);
1384}
1385
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.
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.
MHz_u m_channelWidth
operating channel width
void ReceiveUl(uint8_t bss, Ptr< const WifiPsdu > psdu, RxSignalInfo rxSignalInfo, const WifiTxVector &txVector, const std::vector< bool > &perMpduStatus)
Callback invoked when an AP receives an UL PPDU.
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.
void SendDlMuPpdu(uint8_t bss, MHz_u txChannelWidth, 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...
uint8_t m_nStationsPerBss
number of stations per AP
void ReceiveDl(uint8_t bss, uint8_t station, Ptr< const WifiPsdu > psdu, RxSignalInfo rxSignalInfo, const WifiTxVector &txVector, const std::vector< bool > &perMpduStatus)
Callback invoked when a station receives a DL PPDU.
std::vector< NetDeviceContainer > m_staDevices
containers for stations' NetDevices
void SendHeTbPpdu(uint8_t bss, MHz_u txChannelWidth, RuType ruType, std::size_t nRus)
Have the AP of the given BSS transmit a Basic Trigger Frame.
NetDeviceContainer m_apDevices
container for AP's NetDevice
void DoSendHeTbPpdu(uint8_t bss, MHz_u txChannelWidth, 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 ...
void CheckReceivedMuPpdus(std::set< uint8_t > txBss, MHz_u txChannelWidth, 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 ...
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.
AttributeValue implementation for Boolean.
Definition boolean.h:26
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:262
RU Specification.
Definition he-ru.h:37
static std::size_t GetIndexIn80MHzSegment(MHz_u bw, RuType ruType, std::size_t phyIndex)
Get the index of a given RU transmitted in a PPDU within its 80 MHz segment.
Definition he-ru.cc:475
static bool GetPrimary80MHzFlag(MHz_u bw, RuType ruType, std::size_t phyIndex, uint8_t p20Index)
Get the primary 80 MHz flag of a given RU transmitted in a PPDU.
Definition he-ru.cc:462
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:491
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:561
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
AttributeValue implementation for Ssid.
Definition ssid.h:85
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 Time.
Definition nstime.h:1432
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:527
static Time CalculateTxDuration(uint32_t size, const WifiTxVector &txVector, WifiPhyBand band, uint16_t staId=SU_STA_ID)
Definition wifi-phy.cc:1588
std::vector< ChannelTuple > ChannelSegments
segments identifying an operating channel
Definition wifi-phy.h:946
void SetReceiveOkCallback(RxOkCallback callback)
Definition wifi-phy.cc:479
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:278
uint32_t GetSize() const
Return the size of the PSDU in bytes.
Definition wifi-psdu.cc:272
This class mimics the TXVECTOR which is to be passed to the PHY in order to define the parameters whi...
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:970
#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:1369
Time NanoSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1381
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1357
@ 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.
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
RuType
The different Resource Unit (RU) types.
Definition wifi-types.h:98
Ptr< T1 > DynamicCast(const Ptr< T2 > &p)
Cast a Ptr.
Definition ptr.h:580
std::size_t Count20MHzSubchannels(MHz_u channelWidth)
Return the number of 20 MHz subchannels covering the channel width.
Definition wifi-utils.h:135
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:272
@ WIFI_MAC_CTL_TRIGGER
@ WIFI_MAC_QOSDATA
Ptr< T1 > StaticCast(const Ptr< T2 > &p)
Cast a Ptr.
Definition ptr.h:587
std::unordered_map< uint16_t, Ptr< const WifiPsdu > > WifiConstPsduMap
Map of const PSDUs indexed by STA-ID.
Definition wifi-ppdu.h:38
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:78
static WifiPrimaryChannelsTestSuite g_wifiPrimaryChannelsTestSuite
the test suite