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