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 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 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 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 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 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<HeRu::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<HeRu::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 HeRu::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 bool primary80 = !(txChannelWidth == MHz_u{160} && i > nRus / 2);
826 std::size_t index = (primary80 ? i : i - nRus / 2);
827
828 auto staDev = DynamicCast<WifiNetDevice>(m_staDevices[bss].Get(i - 1));
829 uint16_t staId = DynamicCast<StaWifiMac>(staDev->GetMac())->GetAssociationId();
830 txVector.SetHeMuUserInfo(staId, {{ruType, index, primary80}, 8, 1});
831 hdr.SetAddr1(staDev->GetMac()->GetAddress());
832 psduMap[staId] = Create<const WifiPsdu>(Create<Packet>(1000), hdr);
833 }
835 RuAllocation ruAllocations;
836 const auto numRuAllocs = Count20MHzSubchannels(txChannelWidth);
837 ruAllocations.resize(numRuAllocs);
838 auto IsOddNum = (nRus / numRuAllocs) % 2 == 1;
839 auto ruAlloc = HeRu::GetEqualizedRuAllocation(ruType, IsOddNum);
840 std::fill_n(ruAllocations.begin(), numRuAllocs, ruAlloc);
841 txVector.SetRuAllocation(ruAllocations, 0);
842
843 apDev->GetPhy()->Send(psduMap, txVector);
844}
845
846void
848 MHz_u txChannelWidth,
849 HeRu::RuType ruType,
850 std::size_t nRus)
851{
852 NS_LOG_INFO("*** BSS " << +bss << " transmits a Basic Trigger Frame");
853
854 auto apDev = DynamicCast<WifiNetDevice>(m_apDevices.Get(bss));
855
856 m_trigger->GetHeader(0).SetAddr2(apDev->GetMac()->GetAddress());
857
858 apDev->GetPhy()->Send(m_trigger, m_triggerTxVector);
859
860 // schedule the transmission of HE TB PPDUs
861 Simulator::Schedule(m_triggerTxDuration + apDev->GetPhy()->GetSifs(),
863 this,
864 bss,
865 txChannelWidth,
866 ruType,
867 nRus);
868}
869
870void
872 MHz_u txChannelWidth,
873 HeRu::RuType ruType,
874 std::size_t nRus)
875{
876 auto apDev = DynamicCast<WifiNetDevice>(m_apDevices.Get(bss));
877 uint8_t bssColor = apDev->GetHeConfiguration()->m_bssColor;
878
879 WifiMacHeader hdr;
881 hdr.SetQosTid(0);
882 hdr.SetAddr1(apDev->GetMac()->GetAddress());
883 hdr.SetAddr3(apDev->GetMac()->GetBssid(0));
884 hdr.SetSequenceNumber(1);
885
886 Time duration;
887 uint16_t length = 0;
888 WifiTxVector trigVector(HePhy::GetHeMcs8(),
889 0,
891 NanoSeconds(3200),
892 1,
893 1,
894 0,
895 txChannelWidth,
896 false,
897 false,
898 false,
899 bssColor);
900
901 for (std::size_t i = 1; i <= nRus; i++)
902 {
903 NS_LOG_INFO("*** BSS " << +bss << " STA " << i - 1 << " transmits on primary "
904 << txChannelWidth
905 << " MHz channel an HE TB PPDU (RU type: " << ruType << ")");
906
907 bool primary80 = !(txChannelWidth == MHz_u{160} && i > nRus / 2);
908 std::size_t index = (primary80 ? i : i - nRus / 2);
909
910 auto staDev = DynamicCast<WifiNetDevice>(m_staDevices[bss].Get(i - 1));
911 uint16_t staId = DynamicCast<StaWifiMac>(staDev->GetMac())->GetAssociationId();
912
914 0,
916 NanoSeconds(3200),
917 1,
918 1,
919 0,
920 txChannelWidth,
921 false,
922 false,
923 false,
924 bssColor);
925 txVector.SetHeMuUserInfo(staId, {{ruType, index, primary80}, 8, 1});
926 trigVector.SetHeMuUserInfo(staId, {{ruType, index, primary80}, 8, 1});
927
928 hdr.SetAddr2(staDev->GetMac()->GetAddress());
930
931 if (duration.IsZero())
932 {
933 // calculate just once
934 duration = WifiPhy::CalculateTxDuration(psdu->GetSize(),
935 txVector,
936 staDev->GetMac()->GetWifiPhy()->GetPhyBand(),
937 staId);
938 std::tie(length, duration) = HePhy::ConvertHeTbPpduDurationToLSigLength(
939 duration,
940 txVector,
941 staDev->GetMac()->GetWifiPhy()->GetPhyBand());
942 }
943 txVector.SetLength(length);
944
945 staDev->GetPhy()->Send(WifiConstPsduMap{{staId, psdu}}, txVector);
946 }
947
948 // AP's PHY expects to receive a TRIGVECTOR (just once)
949 trigVector.SetLength(length);
950 auto apHePhy = StaticCast<HePhy>(apDev->GetPhy()->GetLatestPhyEntity());
951 apHePhy->SetTrigVector(trigVector, duration);
952}
953
954void
956{
957 for (uint8_t bss = 0; bss < m_nBss; bss++)
958 {
960 auto mac = DynamicCast<ApWifiMac>(dev->GetMac());
961 NS_TEST_EXPECT_MSG_EQ(mac->GetStaList(SINGLE_LINK_OP_ID).size(),
963 "Not all the stations completed association");
964 }
965}
966
967void
968WifiPrimaryChannelsTest::CheckReceivedSuPpdus(std::set<uint8_t> txBss, MHz_u txChannelWidth)
969{
970 for (uint8_t bss = 0; bss < m_nBss; bss++)
971 {
972 if (txBss.find(bss) != txBss.end())
973 {
974 // Every station in the BSS of an AP that transmitted the frame hears (i.e.,
975 // passes to the MAC) the frame
976 for (uint8_t sta = 0; sta < m_nStationsPerBss; sta++)
977 {
979 true,
980 "Station [" << +bss << "][" << +sta
981 << "] did not receive the SU frame on primary"
982 << txChannelWidth << " channel");
983 }
984 // only the first station actually processed the frames
986 true,
987 "Station [" << +bss << "][0]"
988 << " did not process the SU frame on primary"
989 << txChannelWidth << " channel");
990 for (uint8_t sta = 1; sta < m_nStationsPerBss; sta++)
991 {
993 false,
994 "Station [" << +bss << "][" << +sta
995 << "] processed the SU frame on primary"
996 << txChannelWidth << " channel");
997 }
998 }
999 else
1000 {
1001 // There was no transmission in this BSS. If BSS Color filtering is enabled or no frame
1002 // transmission overlaps with the primary20 channel of this BSS, stations in this BSS
1003 // did not hear any frame.
1005 std::none_of(txBss.begin(), txBss.end(), [&](const uint8_t& txAp) {
1006 auto txApPhy = DynamicCast<WifiNetDevice>(m_apDevices.Get(txAp))->GetPhy();
1007 auto thisApPhy = DynamicCast<WifiNetDevice>(m_apDevices.Get(bss))->GetPhy();
1008 return txApPhy->GetOperatingChannel().GetPrimaryChannelIndex(txChannelWidth) ==
1009 thisApPhy->GetOperatingChannel().GetPrimaryChannelIndex(txChannelWidth);
1010 }))
1011 {
1012 for (uint8_t sta = 0; sta < m_nStationsPerBss; sta++)
1013 {
1015 false,
1016 "Station [" << +bss << "][" << +sta
1017 << "] received the SU frame on primary"
1018 << txChannelWidth << " channel");
1019 }
1020 }
1021 else
1022 {
1023 // all stations heard the frame but no station processed it
1024 for (uint8_t sta = 0; sta < m_nStationsPerBss; sta++)
1025 {
1027 true,
1028 "Station [" << +bss << "][" << +sta
1029 << "] did not receive the SU frame on primary"
1030 << txChannelWidth << " channel");
1032 false,
1033 "Station [" << +bss << "][" << +sta
1034 << "] processed the SU frame on primary"
1035 << txChannelWidth << " channel");
1036 }
1037 }
1038 }
1039 // reset bitmaps
1040 m_received[bss].reset();
1041 m_processed[bss].reset();
1042 }
1043}
1044
1045void
1047 MHz_u txChannelWidth,
1048 HeRu::RuType ruType,
1049 std::size_t nRus,
1050 bool isDlMu)
1051{
1052 for (uint8_t bss = 0; bss < m_nBss; bss++)
1053 {
1054 if (txBss.find(bss) != txBss.end())
1055 {
1056 // There was a transmission in this BSS.
1057 // [DL] Due to AID filtering, only stations that are addressed by the MU PPDU do hear
1058 // the frame [UL] The AP hears a TB PPDU sent by all and only the solicited stations
1059 for (std::size_t sta = 0; sta < nRus; sta++)
1060 {
1062 m_received[bss].test(sta),
1063 true,
1064 (isDlMu ? "A DL MU PPDU transmitted to" : "An HE TB PPDU transmitted by")
1065 << " station [" << +bss << "][" << +sta << "] on primary" << txChannelWidth
1066 << " channel, RU type " << ruType << " was not received");
1067 }
1068 for (uint8_t sta = nRus; sta < m_nStationsPerBss; sta++)
1069 {
1071 false,
1072 (isDlMu ? "A DL MU PPDU" : "An HE TB PPDU")
1073 << " transmitted on primary" << txChannelWidth
1074 << " channel, RU type " << ruType << " was received "
1075 << (isDlMu ? "by" : "from") << " station [" << +bss
1076 << "][" << +sta << "]");
1077 }
1078 // [DL] Only the addressed stations actually processed the frames
1079 // [UL] The AP processed the frames sent by all and only the addressed stations
1080 for (std::size_t sta = 0; sta < nRus; sta++)
1081 {
1083 m_processed[bss].test(sta),
1084 true,
1085 (isDlMu ? "A DL MU PPDU transmitted to" : "An HE TB PPDU transmitted by")
1086 << " station [" << +bss << "][" << +sta << "] on primary" << txChannelWidth
1087 << " channel, RU type " << ruType << " was not processed");
1088 }
1089 for (uint8_t sta = nRus; sta < m_nStationsPerBss; sta++)
1090 {
1092 false,
1093 (isDlMu ? "A DL MU PPDU" : "An HE TB PPDU")
1094 << " transmitted on primary" << txChannelWidth
1095 << " channel, RU type " << ruType << " was received "
1096 << (isDlMu ? "by" : "from") << " station [" << +bss
1097 << "][" << +sta << "] and processed");
1098 }
1099 }
1100 else
1101 {
1102 // There was no transmission in this BSS.
1103 // [DL] If BSS Color filtering is enabled or no frame transmission overlaps with
1104 // the primary20 channel of this BSS, stations in this BSS did not hear any frame.
1105 // [UL] The AP did not hear any TB PPDU because no TRIGVECTOR was passed to the PHY
1106 if (!isDlMu || m_useDistinctBssColors ||
1107 std::none_of(txBss.begin(), txBss.end(), [&](const uint8_t& txAp) {
1108 auto txApPhy = DynamicCast<WifiNetDevice>(m_apDevices.Get(txAp))->GetPhy();
1109 auto thisApPhy = DynamicCast<WifiNetDevice>(m_apDevices.Get(bss))->GetPhy();
1110 return txApPhy->GetOperatingChannel().GetPrimaryChannelIndex(txChannelWidth) ==
1111 thisApPhy->GetOperatingChannel().GetPrimaryChannelIndex(txChannelWidth);
1112 }))
1113 {
1114 for (uint8_t sta = 0; sta < m_nStationsPerBss; sta++)
1115 {
1117 false,
1118 (isDlMu ? "A DL MU PPDU" : "An HE TB PPDU")
1119 << " transmitted on primary" << txChannelWidth
1120 << " channel, RU type " << ruType << " was received "
1121 << (isDlMu ? "by" : "from") << " station [" << +bss
1122 << "][" << +sta << "]");
1123 }
1124 }
1125 else
1126 {
1127 // [DL] Stations having the same AID of the stations addressed by the MU PPDU
1128 // received the frame
1129 for (std::size_t sta = 0; sta < nRus; sta++)
1130 {
1132 m_received[bss].test(sta),
1133 true,
1134 (isDlMu ? "A DL MU PPDU transmitted to" : "An HE TB PPDU transmitted by")
1135 << " station [" << +bss << "][" << +sta << "] on primary"
1136 << txChannelWidth << " channel, RU type " << ruType
1137 << " was not received");
1138 }
1139 for (uint8_t sta = nRus; sta < m_nStationsPerBss; sta++)
1140 {
1142 false,
1143 (isDlMu ? "A DL MU PPDU" : "An HE TB PPDU")
1144 << " transmitted on primary" << txChannelWidth
1145 << " channel, RU type " << ruType << " was received "
1146 << (isDlMu ? "by" : "from") << " station [" << +bss
1147 << "][" << +sta << "]");
1148 }
1149 // no station processed the frame
1150 for (uint8_t sta = 0; sta < m_nStationsPerBss; sta++)
1151 {
1153 false,
1154 (isDlMu ? "A DL MU PPDU" : "An HE TB PPDU")
1155 << " transmitted on primary" << txChannelWidth
1156 << " channel, RU type " << ruType << " was received "
1157 << (isDlMu ? "by" : "from") << " station [" << +bss
1158 << "][" << +sta << "] and processed");
1159 }
1160 }
1161 }
1162 // reset bitmaps
1163 m_received[bss].reset();
1164 m_processed[bss].reset();
1165 }
1166}
1167
1168void
1169WifiPrimaryChannelsTest::CheckReceivedTriggerFrames(std::set<uint8_t> txBss, MHz_u txChannelWidth)
1170{
1171 for (uint8_t bss = 0; bss < m_nBss; bss++)
1172 {
1173 if (txBss.find(bss) != txBss.end())
1174 {
1175 // Every station in the BSS of an AP that transmitted the Trigger Frame hears (i.e.,
1176 // passes to the MAC) and processes the frame
1177 for (uint8_t sta = 0; sta < m_nStationsPerBss; sta++)
1178 {
1180 true,
1181 "Station [" << +bss << "][" << +sta
1182 << "] did not receive the Trigger Frame "
1183 "soliciting a transmission on primary"
1184 << txChannelWidth << " channel");
1186 true,
1187 "Station [" << +bss << "][" << +sta
1188 << "] did not process the Trigger Frame "
1189 "soliciting a transmission on primary"
1190 << txChannelWidth << " channel");
1191 }
1192 }
1193 else
1194 {
1195 // Given that a Trigger Frame is transmitted on the primary20 channel and all the
1196 // primary20 channels are distinct, stations in other BSSes did not hear the frame
1197 for (uint8_t sta = 0; sta < m_nStationsPerBss; sta++)
1198 {
1200 m_received[bss].test(sta),
1201 false,
1202 "Station ["
1203 << +bss << "][" << +sta
1204 << "] received the Trigger Frame soliciting a transmission on primary"
1205 << txChannelWidth << " channel");
1206 }
1207 }
1208 // reset bitmaps
1209 m_received[bss].reset();
1210 m_processed[bss].reset();
1211 }
1212}
1213
1214/**
1215 * @ingroup wifi-test
1216 * @ingroup tests
1217 *
1218 * @brief Test functions returning the indices of primary and secondary channels
1219 * of different width.
1220 */
1222{
1223 public:
1224 /**
1225 * Constructor
1226 */
1228 ~Wifi20MHzChannelIndicesTest() override = default;
1229
1230 /**
1231 * Check that the indices of the 20 MHz channels included in all the primary
1232 * and secondary channels are correct when setting the given primary20 channel.
1233 *
1234 * @param primary20 the index of the primary20 channel to configure
1235 * @param secondary20 the expected index of the secondary20 channel
1236 * @param primary40 the expected indices of the 20 MHz channels in the primary40 channel
1237 * @param secondary40 the expected indices of the 20 MHz channels in the secondary40 channel
1238 * @param primary80 the expected indices of the 20 MHz channels in the primary80 channel
1239 * @param secondary80 the expected indices of the 20 MHz channels in the secondary80 channel
1240 */
1241 void RunOne(uint8_t primary20,
1242 const std::set<uint8_t>& secondary20,
1243 const std::set<uint8_t>& primary40,
1244 const std::set<uint8_t>& secondary40,
1245 const std::set<uint8_t>& primary80,
1246 const std::set<uint8_t>& secondary80);
1247
1248 private:
1249 void DoRun() override;
1250
1251 WifiPhyOperatingChannel m_channel; //!< operating channel
1252};
1253
1255 : TestCase("Check computation of primary and secondary channel indices")
1256{
1257}
1258
1259void
1261 const std::set<uint8_t>& secondary20,
1262 const std::set<uint8_t>& primary40,
1263 const std::set<uint8_t>& secondary40,
1264 const std::set<uint8_t>& primary80,
1265 const std::set<uint8_t>& secondary80)
1266{
1267 auto printToStr = [](const std::set<uint8_t>& s) {
1268 std::stringstream ss;
1269 ss << "{";
1270 for (const auto& index : s)
1271 {
1272 ss << +index << " ";
1273 }
1274 ss << "}";
1275 return ss.str();
1276 };
1277
1278 m_channel.SetPrimary20Index(primary20);
1279
1280 auto actualPrimary20 = m_channel.GetAll20MHzChannelIndicesInPrimary(MHz_u{20});
1281 NS_TEST_ASSERT_MSG_EQ((actualPrimary20 == std::set<uint8_t>{primary20}),
1282 true,
1283 "Expected Primary20 {" << +primary20 << "}"
1284 << " differs from actual "
1285 << printToStr(actualPrimary20));
1286
1287 auto actualSecondary20 = m_channel.GetAll20MHzChannelIndicesInSecondary(actualPrimary20);
1288 NS_TEST_ASSERT_MSG_EQ((actualSecondary20 == secondary20),
1289 true,
1290 "Expected Secondary20 " << printToStr(secondary20)
1291 << " differs from actual "
1292 << printToStr(actualSecondary20));
1293
1294 auto actualPrimary40 = m_channel.GetAll20MHzChannelIndicesInPrimary(MHz_u{40});
1295 NS_TEST_ASSERT_MSG_EQ((actualPrimary40 == primary40),
1296 true,
1297 "Expected Primary40 " << printToStr(primary40) << " differs from actual "
1298 << printToStr(actualPrimary40));
1299
1300 auto actualSecondary40 = m_channel.GetAll20MHzChannelIndicesInSecondary(primary40);
1301 NS_TEST_ASSERT_MSG_EQ((actualSecondary40 == secondary40),
1302 true,
1303 "Expected Secondary40 " << printToStr(secondary40)
1304 << " differs from actual "
1305 << printToStr(actualSecondary40));
1306
1307 auto actualPrimary80 = m_channel.GetAll20MHzChannelIndicesInPrimary(MHz_u{80});
1308 NS_TEST_ASSERT_MSG_EQ((actualPrimary80 == primary80),
1309 true,
1310 "Expected Primary80 " << printToStr(primary80) << " differs from actual "
1311 << printToStr(actualPrimary80));
1312
1313 auto actualSecondary80 = m_channel.GetAll20MHzChannelIndicesInSecondary(primary80);
1314 NS_TEST_ASSERT_MSG_EQ((actualSecondary80 == secondary80),
1315 true,
1316 "Expected Secondary80 " << printToStr(secondary80)
1317 << " differs from actual "
1318 << printToStr(actualSecondary80));
1319}
1320
1321void
1323{
1324 /* 20 MHz channel */
1326 RunOne(0, {}, {}, {}, {}, {});
1327
1328 /* 40 MHz channel */
1330 RunOne(0, {1}, {0, 1}, {}, {}, {});
1331 RunOne(1, {0}, {0, 1}, {}, {}, {});
1332
1333 /* 80 MHz channel */
1335 RunOne(0, {1}, {0, 1}, {2, 3}, {0, 1, 2, 3}, {});
1336 RunOne(1, {0}, {0, 1}, {2, 3}, {0, 1, 2, 3}, {});
1337 RunOne(2, {3}, {2, 3}, {0, 1}, {0, 1, 2, 3}, {});
1338 RunOne(3, {2}, {2, 3}, {0, 1}, {0, 1, 2, 3}, {});
1339
1340 /* 160 MHz channel */
1342 RunOne(0, {1}, {0, 1}, {2, 3}, {0, 1, 2, 3}, {4, 5, 6, 7});
1343 RunOne(1, {0}, {0, 1}, {2, 3}, {0, 1, 2, 3}, {4, 5, 6, 7});
1344 RunOne(2, {3}, {2, 3}, {0, 1}, {0, 1, 2, 3}, {4, 5, 6, 7});
1345 RunOne(3, {2}, {2, 3}, {0, 1}, {0, 1, 2, 3}, {4, 5, 6, 7});
1346 RunOne(4, {5}, {4, 5}, {6, 7}, {4, 5, 6, 7}, {0, 1, 2, 3});
1347 RunOne(5, {4}, {4, 5}, {6, 7}, {4, 5, 6, 7}, {0, 1, 2, 3});
1348 RunOne(6, {7}, {6, 7}, {4, 5}, {4, 5, 6, 7}, {0, 1, 2, 3});
1349 RunOne(7, {6}, {6, 7}, {4, 5}, {4, 5, 6, 7}, {0, 1, 2, 3});
1350}
1351
1352/**
1353 * @ingroup wifi-test
1354 * @ingroup tests
1355 *
1356 * @brief wifi primary channels test suite
1357 */
1359{
1360 public:
1362};
1363
1365 : TestSuite("wifi-primary-channels", Type::UNIT)
1366{
1367 // Test cases for 20 MHz can be added, but are not that useful (there would be a single BSS)
1368 AddTestCase(new WifiPrimaryChannelsTest(MHz_u{40}, true), TestCase::Duration::QUICK);
1369 AddTestCase(new WifiPrimaryChannelsTest(MHz_u{40}, false), TestCase::Duration::QUICK);
1370#if 0
1371 // Tests disabled until issue #776 resolved
1372 AddTestCase(new WifiPrimaryChannelsTest(MHz_u{80}, true), TestCase::Duration::EXTENSIVE);
1373 AddTestCase(new WifiPrimaryChannelsTest(MHz_u{80}, false), TestCase::Duration::EXTENSIVE);
1374 AddTestCase(new WifiPrimaryChannelsTest(MHz_u{160}, true), TestCase::Duration::TAKES_FOREVER);
1375 AddTestCase(new WifiPrimaryChannelsTest(MHz_u{160}, false), TestCase::Duration::TAKES_FOREVER);
1376#endif
1377 AddTestCase(new Wifi20MHzChannelIndicesTest(), TestCase::Duration::QUICK);
1378}
1379
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
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.
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.
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 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.
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: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
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:1431
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:520
static Time CalculateTxDuration(uint32_t size, const WifiTxVector &txVector, WifiPhyBand band, uint16_t staId=SU_STA_ID)
Definition wifi-phy.cc:1587
std::vector< ChannelTuple > ChannelSegments
segments identifying an operating channel
Definition wifi-phy.h:927
void SetReceiveOkCallback(RxOkCallback callback)
Definition wifi-phy.cc:478
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 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:1368
Time NanoSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1380
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1356
@ 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
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:134
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:250
@ 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
std::vector< uint16_t > RuAllocation
9 bits RU_ALLOCATION per 20 MHz
-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