A Discrete-Event Network Simulator
API
wifi-primary-channels-test.cc
Go to the documentation of this file.
1/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/*
3 * Copyright (c) 2020 Universita' degli Studi di Napoli Federico II
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation;
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 *
18 * Author: Stefano Avallone <stavallo@unina.it>
19 */
20
21#include "ns3/boolean.h"
22#include "ns3/enum.h"
23#include "ns3/test.h"
24#include "ns3/wifi-net-device.h"
25#include "ns3/mobility-helper.h"
26#include "ns3/spectrum-wifi-helper.h"
27#include "ns3/multi-model-spectrum-channel.h"
28#include "ns3/config.h"
29#include "ns3/rng-seed-manager.h"
30#include "ns3/wifi-psdu.h"
31#include "ns3/ap-wifi-mac.h"
32#include "ns3/sta-wifi-mac.h"
33#include "ns3/he-phy.h"
34#include "ns3/he-configuration.h"
35#include "ns3/ctrl-headers.h"
36#include "ns3/tuple.h"
37#include <bitset>
38#include <algorithm>
39#include <sstream>
40
41using namespace ns3;
42
43NS_LOG_COMPONENT_DEFINE ("WifiPrimaryChannelsTest");
44
62{
63public:
70 WifiPrimaryChannelsTest (uint16_t channelWidth, bool useDistinctBssColors);
71 virtual ~WifiPrimaryChannelsTest ();
72
82 void Transmit (std::string context, WifiConstPsduMap psduMap, WifiTxVector txVector, double txPowerW);
90 void SendDlSuPpdu (uint8_t bss, uint16_t txChannelWidth);
100 void SendDlMuPpdu (uint8_t bss, uint16_t txChannelWidth, HeRu::RuType ruType, std::size_t nRus);
111 void SendHeTbPpdu (uint8_t bss, uint16_t txChannelWidth, HeRu::RuType ruType, std::size_t nRus);
121 void DoSendHeTbPpdu (uint8_t bss, uint16_t txChannelWidth, HeRu::RuType ruType, std::size_t nRus);
132 void ReceiveDl (uint8_t bss, uint8_t station, Ptr<const WifiPsdu> psdu, RxSignalInfo rxSignalInfo,
133 WifiTxVector txVector, std::vector<bool> perMpduStatus);
143 void ReceiveUl (uint8_t bss, Ptr<const WifiPsdu> psdu, RxSignalInfo rxSignalInfo,
144 WifiTxVector txVector, std::vector<bool> perMpduStatus);
148 void CheckAssociation (void);
159 void CheckReceivedSuPpdus (std::set<uint8_t> txBss, uint16_t txChannelWidth);
173 void CheckReceivedMuPpdus (std::set<uint8_t> txBss, uint16_t txChannelWidth, HeRu::RuType ruType,
174 std::size_t nRus, bool isDlMu);
184 void CheckReceivedTriggerFrames (std::set<uint8_t> txBss, uint16_t txChannelWidth);
185
186private:
187 void DoSetup (void) override;
188 void DoRun (void) override;
189
190 uint16_t m_channelWidth;
192 uint8_t m_nBss;
194 std::vector<NetDeviceContainer> m_staDevices;
196 std::vector<std::bitset<74>> m_received;
198 std::vector<std::bitset<74>> m_processed;
204};
205
206WifiPrimaryChannelsTest::WifiPrimaryChannelsTest (uint16_t channelWidth, bool useDistinctBssColors)
207 : TestCase ("Check correct transmissions for various primary channel settings"),
208 m_channelWidth (channelWidth),
209 m_useDistinctBssColors (useDistinctBssColors)
210{
211}
212
214{
215}
216
217void
218WifiPrimaryChannelsTest::Transmit (std::string context, WifiConstPsduMap psduMap, WifiTxVector txVector, double txPowerW)
219{
220 for (const auto& psduPair : psduMap)
221 {
222 std::stringstream ss;
223
224 if (psduPair.first != SU_STA_ID)
225 {
226 ss << " STA-ID " << psduPair.first;
227 }
228 ss << " " << psduPair.second->GetHeader (0).GetTypeString ()
229 << " seq " << psduPair.second->GetHeader (0).GetSequenceNumber ()
230 << " from " << psduPair.second->GetAddr2 ()
231 << " to " << psduPair.second->GetAddr1 ();
232 NS_LOG_INFO (ss.str ());
233 }
234 NS_LOG_INFO (" TXVECTOR " << txVector);
235}
236
237void
238WifiPrimaryChannelsTest::ReceiveDl (uint8_t bss, uint8_t station, Ptr<const WifiPsdu> psdu,
239 RxSignalInfo rxSignalInfo, WifiTxVector txVector,
240 std::vector<bool> perMpduStatus)
241{
242 if (psdu->GetNMpdus () == 1)
243 {
244 const WifiMacHeader& hdr = psdu->GetHeader (0);
245
246 if (hdr.IsQosData () || hdr.IsTrigger ())
247 {
248 NS_LOG_INFO ("RECEIVED BY BSS=" << +bss << " STA=" << +station << " " << *psdu);
249 // the MAC received a PSDU from the PHY
250 NS_TEST_EXPECT_MSG_EQ (m_received[bss].test (station), false, "Station [" << +bss << "]["
251 << +station << "] received a frame twice");
252 m_received[bss].set (station);
253 // check if we are the intended destination of the PSDU
254 auto dev = DynamicCast<WifiNetDevice> (m_staDevices[bss].Get (station));
255 if ((hdr.IsQosData () && hdr.GetAddr1 () == dev->GetMac ()->GetAddress ())
256 || (hdr.IsTrigger () && hdr.GetAddr1 () == Mac48Address::GetBroadcast ()))
257 {
258 NS_TEST_EXPECT_MSG_EQ (m_processed[bss].test (station), false, "Station [" << +bss << "]["
259 << +station << "] processed a frame twice");
260 m_processed[bss].set (station);
261 }
262 }
263 }
264}
265
266void
268 WifiTxVector txVector, std::vector<bool> perMpduStatus)
269{
270 // if the BSS color is zero, this AP might receive the frame sent by another AP. Given that
271 // stations only send TB PPDUs, we ignore this frame if the TX vector is not UL MU.
272 if (psdu->GetNMpdus () == 1 && psdu->GetHeader (0).IsQosData () && txVector.IsUlMu ())
273 {
274 auto dev = DynamicCast<WifiNetDevice> (m_apDevices.Get (bss));
275
276 uint16_t staId = txVector.GetHeMuUserInfoMap ().begin ()->first;
277 uint8_t station = staId - 1;
278 NS_LOG_INFO ("RECEIVED FROM BSSID=" << psdu->GetHeader (0).GetAddr3 () << " STA=" << +station
279 << " " << *psdu);
280 // the MAC received a PSDU containing a QoS data frame from the PHY
281 NS_TEST_EXPECT_MSG_EQ (m_received[bss].test (station), false, "AP of BSS " << +bss
282 << " received a frame from station " << +station << " twice");
283 m_received[bss].set (station);
284 // check if we are the intended destination of the PSDU
285 if (psdu->GetHeader (0).GetAddr1 () == dev->GetMac ()->GetAddress ())
286 {
287 NS_TEST_EXPECT_MSG_EQ (m_processed[bss].test (station), false, "AP of BSS " << +bss
288 << " received a frame from station " << +station << " twice");
289 m_processed[bss].set (station);
290 }
291 }
292}
293
294void
296{
297 RngSeedManager::SetSeed (1);
298 RngSeedManager::SetRun (40);
299 int64_t streamNumber = 100;
300 uint8_t channelNum;
301
302 // we create as many stations per BSS as the number of 26-tone RUs in a channel
303 // of the configured width
304 switch (m_channelWidth)
305 {
306 case 20:
308 channelNum = 36;
309 break;
310 case 40:
312 channelNum = 38;
313 break;
314 case 80:
316 channelNum = 42;
317 break;
318 case 160:
320 channelNum= 50;
321 break;
322 default:
323 NS_ABORT_MSG ("Channel width (" << m_channelWidth << ") not allowed");
324 }
325
326 // we create as many BSSes as the number of 20 MHz subchannels
327 m_nBss = m_channelWidth / 20;
328
329 NodeContainer wifiApNodes;
330 wifiApNodes.Create (m_nBss);
331
332 std::vector<NodeContainer> wifiStaNodes (m_nBss);
333 for (auto& container : wifiStaNodes)
334 {
335 container.Create (m_nStationsPerBss);
336 }
337
338 Ptr<MultiModelSpectrumChannel> spectrumChannel = CreateObject<MultiModelSpectrumChannel> ();
339 Ptr<FriisPropagationLossModel> lossModel = CreateObject<FriisPropagationLossModel> ();
340 spectrumChannel->AddPropagationLossModel (lossModel);
341 Ptr<ConstantSpeedPropagationDelayModel> delayModel = CreateObject<ConstantSpeedPropagationDelayModel> ();
342 spectrumChannel->SetPropagationDelayModel (delayModel);
343
345 phy.SetChannel (spectrumChannel);
346
348 wifi.SetStandard (WIFI_STANDARD_80211ax);
349 wifi.SetRemoteStationManager ("ns3::ConstantRateWifiManager");
350
352 mac.SetType ("ns3::StaWifiMac",
353 "Ssid", SsidValue (Ssid ("non-existent-ssid")),
354 "MaxMissedBeacons", UintegerValue (20),
355 "WaitBeaconTimeout", TimeValue (MicroSeconds (102400))); // same as BeaconInterval
356
358
359 // Each BSS uses a distinct primary20 channel
360 for (uint8_t bss = 0; bss < m_nBss; bss++)
361 {
362 channelValue.Set (WifiPhy::ChannelTuple {channelNum, m_channelWidth, WIFI_PHY_BAND_5GHZ, bss});
363 phy.Set ("ChannelSettings", channelValue);
364
365 m_staDevices.push_back (wifi.Install (phy, mac, wifiStaNodes[bss]));
366 }
367
368 for (uint8_t bss = 0; bss < m_nBss; bss++)
369 {
370 channelValue.Set (WifiPhy::ChannelTuple {channelNum, m_channelWidth, WIFI_PHY_BAND_5GHZ, bss});
371 phy.Set ("ChannelSettings", channelValue);
372
373 mac.SetType ("ns3::ApWifiMac",
374 "Ssid", SsidValue (Ssid ("wifi-ssid-" + std::to_string (bss))),
375 "BeaconInterval", TimeValue (MicroSeconds (102400)),
376 "EnableBeaconJitter", BooleanValue (false));
377
378 m_apDevices.Add (wifi.Install (phy, mac, wifiApNodes.Get (bss)));
379 }
380
381 // Assign fixed streams to random variables in use
382 streamNumber = wifi.AssignStreams (m_apDevices, streamNumber);
383 for (uint8_t bss = 0; bss < m_nBss; bss++)
384 {
385 streamNumber = wifi.AssignStreams (m_staDevices[bss], streamNumber);
386 }
387
388 // set BSS color
390 {
391 for (uint8_t bss = 0; bss < m_nBss; bss++)
392 {
393 auto dev = DynamicCast<WifiNetDevice> (m_apDevices.Get (bss));
394 dev->GetHeConfiguration ()->SetBssColor (bss + 1);
395 }
396 }
397
399 Ptr<ListPositionAllocator> positionAlloc = CreateObject<ListPositionAllocator> ();
400
401 positionAlloc->Add (Vector (0.0, 0.0, 0.0)); // all stations are co-located
402 mobility.SetPositionAllocator (positionAlloc);
403
404 mobility.SetMobilityModel ("ns3::ConstantPositionMobilityModel");
405 mobility.Install (wifiApNodes);
406 for (uint8_t bss = 0; bss < m_nBss; bss++)
407 {
408 mobility.Install (wifiStaNodes[bss]);
409 }
410
411 m_received.resize (m_nBss);
412 m_processed.resize (m_nBss);
413
414 // pre-compute the Basic Trigger Frame to send
415 auto apDev = DynamicCast<WifiNetDevice> (m_apDevices.Get (0));
416
417 WifiMacHeader hdr;
419 hdr.SetAddr1 (Mac48Address::GetBroadcast ());
420 // Addr2 has to be set
421 hdr.SetSequenceNumber (1);
422
423 Ptr<Packet> pkt = Create<Packet> ();
424 CtrlTriggerHeader trigger;
426 pkt->AddHeader (trigger);
427
428 m_triggerTxVector = WifiTxVector (OfdmPhy::GetOfdmRate6Mbps (), 0, WIFI_PREAMBLE_LONG, 800, 1, 1, 0,
429 20, false, false, false);
430 m_trigger = Create<WifiPsdu> (pkt, hdr);
431
432 m_triggerTxDuration = WifiPhy::CalculateTxDuration (m_trigger->GetSize (), m_triggerTxVector,
433 apDev->GetMac ()->GetWifiPhy ()->GetPhyBand ());
434}
435
436void
438{
439 // schedule association requests at different times. One station's SSID is
440 // set to the correct value before initialization, so that such a station
441 // starts the scanning procedure by looking for the correct SSID
443
444 // association can be done in parallel over the multiple BSSes
445 for (uint8_t bss = 0; bss < m_nBss; bss++)
446 {
447 dev = DynamicCast<WifiNetDevice> (m_staDevices[bss].Get (0));
448 dev->GetMac ()->SetSsid (Ssid ("wifi-ssid-" + std::to_string (bss)));
449
450 for (uint16_t i = 1; i < m_nStationsPerBss; i++)
451 {
452 dev = DynamicCast<WifiNetDevice> (m_staDevices[bss].Get (i));
453 Simulator::Schedule (i * MicroSeconds (102400), &WifiMac::SetSsid,
454 dev->GetMac (), Ssid ("wifi-ssid-" + std::to_string (bss)));
455 }
456 }
457
458 // just before sending the beacon preceding the last association, increase the beacon
459 // interval (to the max allowed value) so that beacons do not interfere with data frames
460 for (uint8_t bss = 0; bss < m_nBss; bss++)
461 {
462 dev = DynamicCast<WifiNetDevice> (m_apDevices.Get (bss));
463 auto mac = DynamicCast<ApWifiMac> (dev->GetMac ());
464
465 Simulator::Schedule ((m_nStationsPerBss - 1) * MicroSeconds (102400),
466 &ApWifiMac::SetBeaconInterval, mac, MicroSeconds (1024 * 65535));
467 }
468
469 m_time = (m_nStationsPerBss + 1) * MicroSeconds (102400);
470
471 Simulator::Schedule (m_time, &WifiPrimaryChannelsTest::CheckAssociation, this);
472
473 // we are done with association. We now intercept frames received by the
474 // PHY layer on stations and APs, which will no longer be passed to the FEM.
475 for (uint8_t bss = 0; bss < m_nBss; bss++)
476 {
477 for (uint8_t i = 0; i < m_nStationsPerBss; i++)
478 {
479 auto dev = DynamicCast<WifiNetDevice> (m_staDevices[bss].Get (i));
480 Simulator::Schedule (m_time, &WifiPhy::SetReceiveOkCallback, dev->GetPhy (),
482 .Bind (bss, i));
483 }
484 auto dev = DynamicCast<WifiNetDevice> (m_apDevices.Get (bss));
485 Simulator::Schedule (m_time, &WifiPhy::SetReceiveOkCallback, dev->GetPhy (),
487 .Bind (bss));
488 }
489
490 /*
491 * We start generating (downlink) SU PPDUs.
492 * First, APs operating on non-adjacent primary20 channels send a frame simultaneously
493 * in their primary20. This is done in two rounds. As an example, we consider the
494 * case of an 160 MHz operating channel:
495 *
496 * AP0 AP2 AP4 AP6
497 * |-----| |-----| |-----| |-----| |
498 *
499 * AP1 AP3 AP5 AP7
500 * | |-----| |-----| |-----| |-----|
501 *
502 * Then, we double the transmission channel width. We will have four rounds
503 * of transmissions. We avoid using adjacent channels to avoid interfence
504 * among transmissions:
505 *
506 * AP0 AP4
507 * |-----------| |-----------| |
508 * AP1 AP5
509 * |-----------| |-----------| |
510 * AP2 AP6
511 * | |-----------| |-----------|
512 * AP3 AP7
513 * | |-----------| |-----------|
514 *
515 * We double the transmission channel width again. We will have eight rounds
516 * of transmissions:
517 *
518 * AP0
519 * |-----------------------| |
520 * AP1
521 * |-----------------------| |
522 * AP2
523 * |-----------------------| |
524 * AP3
525 * |-----------------------| |
526 * AP4
527 * | |-----------------------|
528 * AP5
529 * | |-----------------------|
530 * AP6
531 * | |-----------------------|
532 * AP7
533 * | |-----------------------|
534 *
535 * We double the transmission channel width again. We will have eight rounds
536 * of transmissions:
537 *
538 * AP0
539 * |-----------------------------------------------|
540 * AP1
541 * |-----------------------------------------------|
542 * AP2
543 * |-----------------------------------------------|
544 * AP3
545 * |-----------------------------------------------|
546 * AP4
547 * |-----------------------------------------------|
548 * AP5
549 * |-----------------------------------------------|
550 * AP6
551 * |-----------------------------------------------|
552 * AP7
553 * |-----------------------------------------------|
554 *
555 * The transmission channel width reached the operating channel width, we are done.
556 */
557
558 Time roundDuration = MilliSeconds (5); // upper bound on the duration of a round
559
560 // To have simultaneous transmissions on adjacent channels, just initialize
561 // nRounds to 1 and nApsPerRound to m_channelWidth / 20. Of course, the test
562 // will fail because some stations will not receive some frames due to interfence
563 for (uint16_t txChannelWidth = 20, nRounds = 2, nApsPerRound = m_channelWidth / 20 / 2;
564 txChannelWidth <= m_channelWidth;
565 txChannelWidth *= 2, nRounds *= 2, nApsPerRound /= 2)
566 {
567 nRounds = std::min<uint16_t> (nRounds, m_nBss);
568 nApsPerRound = std::max<uint16_t> (nApsPerRound, 1);
569
570 for (uint16_t round = 0; round < nRounds; round++)
571 {
572 std::set<uint8_t> txBss;
573
574 for (uint16_t i = 0; i < nApsPerRound; i++)
575 {
576 uint16_t ap = round + i * nRounds;
577 txBss.insert (ap);
578 Simulator::Schedule (m_time, &WifiPrimaryChannelsTest::SendDlSuPpdu, this,
579 ap, txChannelWidth);
580 }
581 // check that the SU frames were correctly received
582 Simulator::Schedule (m_time + roundDuration, &WifiPrimaryChannelsTest::CheckReceivedSuPpdus,
583 this, txBss, txChannelWidth);
584 m_time += roundDuration;
585 }
586 }
587
588 /*
589 * Repeat the same scheme as before with DL MU transmissions. For each transmission
590 * channel width, every round is repeated as many times as the number of ways in
591 * which we can partition the transmission channel width in equal sized RUs.
592 */
593 for (uint16_t txChannelWidth = 20, nRounds = 2, nApsPerRound = m_channelWidth / 20 / 2;
594 txChannelWidth <= m_channelWidth;
595 txChannelWidth *= 2, nRounds *= 2, nApsPerRound /= 2)
596 {
597 nRounds = std::min<uint16_t> (nRounds, m_nBss);
598 nApsPerRound = std::max<uint16_t> (nApsPerRound, 1);
599
600 for (uint16_t round = 0; round < nRounds; round++)
601 {
602 for (unsigned int type = 0; type < 7; type++)
603 {
604 HeRu::RuType ruType = static_cast <HeRu::RuType> (type);
605 std::size_t nRus = HeRu::GetNRus (txChannelWidth, ruType);
606 std::set<uint8_t> txBss;
607 if (nRus > 0)
608 {
609 for (uint16_t i = 0; i < nApsPerRound; i++)
610 {
611 uint16_t ap = round + i * nRounds;
612 txBss.insert (ap);
613 Simulator::Schedule (m_time, &WifiPrimaryChannelsTest::SendDlMuPpdu, this,
614 ap, txChannelWidth, ruType, nRus);
615 }
616 // check that the MU frame was correctly received
617 Simulator::Schedule (m_time + roundDuration, &WifiPrimaryChannelsTest::CheckReceivedMuPpdus,
618 this, txBss, txChannelWidth, ruType, nRus, /* isDlMu */ true);
619 m_time += roundDuration;
620 }
621 }
622 }
623 }
624
625 /*
626 * Repeat the same scheme as before with UL MU transmissions. For each transmission
627 * channel width, every round is repeated as many times as the number of ways in
628 * which we can partition the transmission channel width in equal sized RUs.
629 */
630 for (uint16_t txChannelWidth = 20, nRounds = 2, nApsPerRound = m_channelWidth / 20 / 2;
631 txChannelWidth <= m_channelWidth;
632 txChannelWidth *= 2, nRounds *= 2, nApsPerRound /= 2)
633 {
634 nRounds = std::min<uint16_t> (nRounds, m_nBss);
635 nApsPerRound = std::max<uint16_t> (nApsPerRound, 1);
636
637 for (uint16_t round = 0; round < nRounds; round++)
638 {
639 for (unsigned int type = 0; type < 7; type++)
640 {
641 HeRu::RuType ruType = static_cast <HeRu::RuType> (type);
642 std::size_t nRus = HeRu::GetNRus (txChannelWidth, ruType);
643 std::set<uint8_t> txBss;
644 if (nRus > 0)
645 {
646 for (uint16_t i = 0; i < nApsPerRound; i++)
647 {
648 uint16_t ap = round + i * nRounds;
649 txBss.insert (ap);
650 Simulator::Schedule (m_time, &WifiPrimaryChannelsTest::SendHeTbPpdu, this,
651 ap, txChannelWidth, ruType, nRus);
652 }
653 // check that Trigger Frames and TB PPDUs were correctly received
654 Simulator::Schedule (m_time + m_triggerTxDuration + MicroSeconds (10), /* during SIFS */
656 this, txBss, txChannelWidth);
657 Simulator::Schedule (m_time + roundDuration, &WifiPrimaryChannelsTest::CheckReceivedMuPpdus,
658 this, txBss, txChannelWidth, ruType, nRus, /* isDlMu */ false);
659 m_time += roundDuration;
660 }
661 }
662 }
663 }
664
665 // Trace PSDUs passed to the PHY on all devices
666 Config::Connect ("/NodeList/*/DeviceList/*/$ns3::WifiNetDevice/Phy/PhyTxPsduBegin",
668
669 Simulator::Stop (m_time);
670 Simulator::Run ();
671
672 Simulator::Destroy ();
673}
674
675void
676WifiPrimaryChannelsTest::SendDlSuPpdu (uint8_t bss, uint16_t txChannelWidth)
677{
678 NS_LOG_INFO ("*** BSS " << +bss << " transmits on primary " << txChannelWidth << " MHz channel");
679
680 auto apDev = DynamicCast<WifiNetDevice> (m_apDevices.Get (bss));
681 auto staDev = DynamicCast<WifiNetDevice> (m_staDevices[bss].Get (0));
682
683 uint8_t bssColor = apDev->GetHeConfiguration ()->GetBssColor ();
684 WifiTxVector txVector = WifiTxVector (HePhy::GetHeMcs8 (), 0, WIFI_PREAMBLE_HE_SU, 800, 1, 1, 0, txChannelWidth, false, false, false, bssColor);
685 WifiMacHeader hdr;
687 hdr.SetQosTid (0);
688 hdr.SetAddr1 (staDev->GetMac ()->GetAddress ());
689 hdr.SetAddr2 (apDev->GetMac ()->GetAddress ());
690 hdr.SetAddr3 (apDev->GetMac ()->GetBssid (0));
691 hdr.SetSequenceNumber (1);
692 Ptr<WifiPsdu> psdu = Create<WifiPsdu> (Create<Packet> (1000), hdr);
693 apDev->GetPhy ()->Send (WifiConstPsduMap ({std::make_pair (SU_STA_ID, psdu)}), txVector);
694}
695
696void
697WifiPrimaryChannelsTest::SendDlMuPpdu (uint8_t bss, uint16_t txChannelWidth, HeRu::RuType ruType, std::size_t nRus)
698{
699 NS_LOG_INFO ("*** BSS " << +bss << " transmits on primary " << txChannelWidth
700 << " MHz channel a DL MU PPDU " << "addressed to " << nRus
701 << " stations (RU type: " << ruType << ")");
702
703 auto apDev = DynamicCast<WifiNetDevice> (m_apDevices.Get (bss));
704 uint8_t bssColor = apDev->GetHeConfiguration ()->GetBssColor ();
705
706 WifiTxVector txVector = WifiTxVector (HePhy::GetHeMcs8 (), 0, WIFI_PREAMBLE_HE_MU, 800, 1, 1, 0, txChannelWidth, false, false, false, bssColor);
707 WifiMacHeader hdr;
709 hdr.SetQosTid (0);
710 hdr.SetAddr2 (apDev->GetMac ()->GetAddress ());
711 hdr.SetAddr3 (apDev->GetMac ()->GetBssid (0));
712 hdr.SetSequenceNumber (1);
713
714 WifiConstPsduMap psduMap;
715
716 for (std::size_t i = 1; i <= nRus; i++)
717 {
718 bool primary80 = !(txChannelWidth == 160 && i > nRus / 2);
719 std::size_t index = (primary80 ? i : i - nRus / 2);
720
721 auto staDev = DynamicCast<WifiNetDevice> (m_staDevices[bss].Get (i - 1));
722 uint16_t staId = DynamicCast<StaWifiMac> (staDev->GetMac ())->GetAssociationId ();
723 txVector.SetHeMuUserInfo (staId, {{ruType, index, primary80}, HePhy::GetHeMcs8 (), 1});
724 hdr.SetAddr1 (staDev->GetMac ()->GetAddress ());
725 psduMap[staId] = Create<const WifiPsdu> (Create<Packet> (1000), hdr);
726 }
727 txVector.SetSigBMode (VhtPhy::GetVhtMcs5 ());
728 RuAllocation ruAllocations;
729 auto numRuAllocs = txChannelWidth / 20;
730 ruAllocations.resize (numRuAllocs);
731 auto IsOddNum = (nRus / numRuAllocs) % 2 == 1;
732 auto ruAlloc = HeRu::GetEqualizedRuAllocation (ruType, IsOddNum);
733 std::fill_n (ruAllocations.begin (), numRuAllocs, ruAlloc);
734 txVector.SetRuAllocation (ruAllocations);
735
736 apDev->GetPhy ()->Send (psduMap, txVector);
737}
738
739void
740WifiPrimaryChannelsTest::SendHeTbPpdu (uint8_t bss, uint16_t txChannelWidth, HeRu::RuType ruType, std::size_t nRus)
741{
742 NS_LOG_INFO ("*** BSS " << +bss << " transmits a Basic Trigger Frame");
743
744 auto apDev = DynamicCast<WifiNetDevice> (m_apDevices.Get (bss));
745
746 m_trigger->GetHeader (0).SetAddr2 (apDev->GetMac ()->GetAddress ());
747
748 apDev->GetPhy ()->Send (m_trigger, m_triggerTxVector);
749
750 // schedule the transmission of HE TB PPDUs
751 Simulator::Schedule (m_triggerTxDuration + apDev->GetPhy ()->GetSifs (),
753 bss, txChannelWidth, ruType, nRus);
754}
755
756void
757WifiPrimaryChannelsTest::DoSendHeTbPpdu (uint8_t bss, uint16_t txChannelWidth, HeRu::RuType ruType, std::size_t nRus)
758{
759 auto apDev = DynamicCast<WifiNetDevice> (m_apDevices.Get (bss));
760 uint8_t bssColor = apDev->GetHeConfiguration ()->GetBssColor ();
761
762 WifiMacHeader hdr;
764 hdr.SetQosTid (0);
765 hdr.SetAddr1 (apDev->GetMac ()->GetAddress ());
766 hdr.SetAddr3 (apDev->GetMac ()->GetBssid (0));
767 hdr.SetSequenceNumber (1);
768
769 Time duration = Seconds (0);
770 uint16_t length = 0;
771 WifiTxVector trigVector (HePhy::GetHeMcs8 (), 0, WIFI_PREAMBLE_HE_TB, 3200, 1, 1, 0, txChannelWidth, false, false, false, bssColor);
772
773 for (std::size_t i = 1; i <= nRus; i++)
774 {
775 NS_LOG_INFO ("*** BSS " << +bss << " STA " << i - 1 << " transmits on primary "
776 << txChannelWidth << " MHz channel an HE TB PPDU (RU type: " << ruType << ")");
777
778 bool primary80 = !(txChannelWidth == 160 && i > nRus / 2);
779 std::size_t index = (primary80 ? i : i - nRus / 2);
780
781 auto staDev = DynamicCast<WifiNetDevice> (m_staDevices[bss].Get (i - 1));
782 uint16_t staId = DynamicCast<StaWifiMac> (staDev->GetMac ())->GetAssociationId ();
783
784 WifiTxVector txVector (HePhy::GetHeMcs8 (), 0, WIFI_PREAMBLE_HE_TB, 3200, 1, 1, 0, txChannelWidth, false, false, false, bssColor);
785 txVector.SetHeMuUserInfo (staId, {{ruType, index, primary80}, HePhy::GetHeMcs8 (), 1});
786 trigVector.SetHeMuUserInfo (staId, {{ruType, index, primary80}, HePhy::GetHeMcs8 (), 1});
787
788 hdr.SetAddr2 (staDev->GetMac ()->GetAddress ());
789 Ptr<const WifiPsdu> psdu = Create<const WifiPsdu> (Create<Packet> (1000), hdr);
790
791 if (duration.IsZero ())
792 {
793 // calculate just once
794 duration = WifiPhy::CalculateTxDuration (psdu->GetSize (), txVector,
795 staDev->GetMac ()->GetWifiPhy ()->GetPhyBand (), staId);
796 std::tie (length, duration) = HePhy::ConvertHeTbPpduDurationToLSigLength (duration, txVector,
797 staDev->GetMac ()->GetWifiPhy ()->GetPhyBand ());
798 }
799 txVector.SetLength (length);
800
801 staDev->GetPhy ()->Send (WifiConstPsduMap {{staId, psdu}}, txVector);
802 }
803
804 // AP's PHY expects to receive a TRIGVECTOR (just once)
805 trigVector.SetLength (length);
806 auto apHePhy = StaticCast<HePhy> (apDev->GetPhy ()->GetPhyEntity (WIFI_MOD_CLASS_HE));
807 apHePhy->SetTrigVector (trigVector, duration);
808}
809
810void
812{
813 for (uint8_t bss = 0; bss < m_nBss; bss++)
814 {
815 auto dev = DynamicCast<WifiNetDevice> (m_apDevices.Get (bss));
816 auto mac = DynamicCast<ApWifiMac> (dev->GetMac ());
817 NS_TEST_EXPECT_MSG_EQ (mac->GetStaList ().size (), m_nStationsPerBss,
818 "Not all the stations completed association");
819 }
820}
821
822void
823WifiPrimaryChannelsTest::CheckReceivedSuPpdus (std::set<uint8_t> txBss, uint16_t txChannelWidth)
824{
825 for (uint8_t bss = 0; bss < m_nBss; bss++)
826 {
827 if (txBss.find (bss) != txBss.end ())
828 {
829 // Every station in the BSS of an AP that transmitted the frame hears (i.e.,
830 // passes to the MAC) the frame
831 for (uint8_t sta = 0; sta < m_nStationsPerBss; sta++)
832 {
833 NS_TEST_EXPECT_MSG_EQ (m_received[bss].test (sta), true, "Station [" << +bss << "][" << +sta
834 << "] did not receive the SU frame on primary" << txChannelWidth << " channel");
835 }
836 // only the first station actually processed the frames
837 NS_TEST_EXPECT_MSG_EQ (m_processed[bss].test (0), true, "Station [" << +bss << "][0]"
838 << " did not process the SU frame on primary" << txChannelWidth << " channel");
839 for (uint8_t sta = 1; sta < m_nStationsPerBss; sta++)
840 {
841 NS_TEST_EXPECT_MSG_EQ (m_processed[bss].test (sta), false, "Station [" << +bss << "][" << +sta
842 << "] processed the SU frame on primary" << txChannelWidth << " channel");
843 }
844 }
845 else
846 {
847 // There was no transmission in this BSS. If BSS Color filtering is enabled or no frame
848 // transmission overlaps with the primary20 channel of this BSS, stations in this BSS
849 // did not hear any frame.
851 || std::none_of (txBss.begin (), txBss.end (),
852 [&](const uint8_t& txAp)
853 {
854 auto txApPhy = DynamicCast<WifiNetDevice> (m_apDevices.Get (txAp))->GetPhy ();
855 auto thisApPhy = DynamicCast<WifiNetDevice> (m_apDevices.Get (bss))->GetPhy ();
856 return txApPhy->GetOperatingChannel ().GetPrimaryChannelIndex (txChannelWidth)
857 == thisApPhy->GetOperatingChannel ().GetPrimaryChannelIndex (txChannelWidth);
858 }))
859 {
860 for (uint8_t sta = 0; sta < m_nStationsPerBss; sta++)
861 {
862 NS_TEST_EXPECT_MSG_EQ (m_received[bss].test (sta), false, "Station [" << +bss << "][" << +sta
863 << "] received the SU frame on primary" << txChannelWidth << " channel");
864 }
865 }
866 else
867 {
868 // all stations heard the frame but no station processed it
869 for (uint8_t sta = 0; sta < m_nStationsPerBss; sta++)
870 {
871 NS_TEST_EXPECT_MSG_EQ (m_received[bss].test (sta), true, "Station [" << +bss << "][" << +sta
872 << "] did not receive the SU frame on primary" << txChannelWidth << " channel");
873 NS_TEST_EXPECT_MSG_EQ (m_processed[bss].test (sta), false, "Station [" << +bss << "][" << +sta
874 << "] processed the SU frame on primary" << txChannelWidth << " channel");
875 }
876 }
877 }
878 // reset bitmaps
879 m_received[bss].reset ();
880 m_processed[bss].reset ();
881 }
882}
883
884void
885WifiPrimaryChannelsTest::CheckReceivedMuPpdus (std::set<uint8_t> txBss, uint16_t txChannelWidth,
886 HeRu::RuType ruType, std::size_t nRus, bool isDlMu)
887{
888 for (uint8_t bss = 0; bss < m_nBss; bss++)
889 {
890 if (txBss.find (bss) != txBss.end ())
891 {
892 // There was a transmission in this BSS.
893 // [DL] Due to AID filtering, only stations that are addressed by the MU PPDU do hear the frame
894 // [UL] The AP hears a TB PPDU sent by all and only the solicited stations
895 for (uint8_t sta = 0; sta < nRus; sta++)
896 {
897 NS_TEST_EXPECT_MSG_EQ (m_received[bss].test (sta), true,
898 (isDlMu ? "A DL MU PPDU transmitted to" : "An HE TB PPDU transmitted by")
899 << " station [" << +bss << "][" << +sta << "] on primary"
900 << txChannelWidth << " channel, RU type " << ruType
901 << " was not received");
902 }
903 for (uint8_t sta = nRus; sta < m_nStationsPerBss; sta++)
904 {
905 NS_TEST_EXPECT_MSG_EQ (m_received[bss].test (sta), false,
906 (isDlMu ? "A DL MU PPDU" : "An HE TB PPDU")
907 << " transmitted on primary" << txChannelWidth
908 << " channel, RU type " << ruType << " was received "
909 << (isDlMu ? "by" : "from") << " station [" << +bss << "]["
910 << +sta << "]");
911 }
912 // [DL] Only the addressed stations actually processed the frames
913 // [UL] The AP processed the frames sent by all and only the addressed stations
914 for (uint8_t sta = 0; sta < nRus; sta++)
915 {
916 NS_TEST_EXPECT_MSG_EQ (m_processed[bss].test (sta), true,
917 (isDlMu ? "A DL MU PPDU transmitted to" : "An HE TB PPDU transmitted by")
918 << " station [" << +bss << "][" << +sta << "] on primary"
919 << txChannelWidth << " channel, RU type " << ruType
920 << " was not processed");
921 }
922 for (uint8_t sta = nRus; sta < m_nStationsPerBss; sta++)
923 {
924 NS_TEST_EXPECT_MSG_EQ (m_processed[bss].test (sta), false,
925 (isDlMu ? "A DL MU PPDU" : "An HE TB PPDU")
926 << " transmitted on primary" << txChannelWidth
927 << " channel, RU type " << ruType << " was received "
928 << (isDlMu ? "by" : "from") << " station [" << +bss << "]["
929 << +sta << "] and processed");
930 }
931 }
932 else
933 {
934 // There was no transmission in this BSS.
935 // [DL] If BSS Color filtering is enabled or no frame transmission overlaps with
936 // the primary20 channel of this BSS, stations in this BSS did not hear any frame.
937 // [UL] The AP did not hear any TB PPDU because no TRIGVECTOR was passed to the PHY
938 if (!isDlMu || m_useDistinctBssColors
939 || std::none_of (txBss.begin (), txBss.end (),
940 [&](const uint8_t& txAp)
941 {
942 auto txApPhy = DynamicCast<WifiNetDevice> (m_apDevices.Get (txAp))->GetPhy ();
943 auto thisApPhy = DynamicCast<WifiNetDevice> (m_apDevices.Get (bss))->GetPhy ();
944 return txApPhy->GetOperatingChannel ().GetPrimaryChannelIndex (txChannelWidth)
945 == thisApPhy->GetOperatingChannel ().GetPrimaryChannelIndex (txChannelWidth);
946 }))
947 {
948 for (uint8_t sta = 0; sta < m_nStationsPerBss; sta++)
949 {
950 NS_TEST_EXPECT_MSG_EQ (m_received[bss].test (sta), false,
951 (isDlMu ? "A DL MU PPDU" : "An HE TB PPDU")
952 << " transmitted on primary" << txChannelWidth
953 << " channel, RU type " << ruType << " was received "
954 << (isDlMu ? "by" : "from") << " station [" << +bss << "]["
955 << +sta << "]");
956 }
957 }
958 else
959 {
960 // [DL] Stations having the same AID of the stations addressed by the MU PPDU received the frame
961 for (uint8_t sta = 0; sta < nRus; sta++)
962 {
963 NS_TEST_EXPECT_MSG_EQ (m_received[bss].test (sta), true,
964 (isDlMu ? "A DL MU PPDU transmitted to" : "An HE TB PPDU transmitted by")
965 << " station [" << +bss << "][" << +sta << "] on primary"
966 << txChannelWidth << " channel, RU type " << ruType
967 << " was not received");
968 }
969 for (uint8_t sta = nRus; sta < m_nStationsPerBss; sta++)
970 {
971 NS_TEST_EXPECT_MSG_EQ (m_received[bss].test (sta), false,
972 (isDlMu ? "A DL MU PPDU" : "An HE TB PPDU")
973 << " transmitted on primary" << txChannelWidth
974 << " channel, RU type " << ruType << " was received "
975 << (isDlMu ? "by" : "from") << " station [" << +bss << "]["
976 << +sta << "]");
977 }
978 // no station processed the frame
979 for (uint8_t sta = 0; sta < m_nStationsPerBss; sta++)
980 {
981 NS_TEST_EXPECT_MSG_EQ (m_processed[bss].test (sta), false,
982 (isDlMu ? "A DL MU PPDU" : "An HE TB PPDU")
983 << " transmitted on primary" << txChannelWidth
984 << " channel, RU type " << ruType << " was received "
985 << (isDlMu ? "by" : "from") << " station [" << +bss << "]["
986 << +sta << "] and processed");
987 }
988 }
989 }
990 // reset bitmaps
991 m_received[bss].reset ();
992 m_processed[bss].reset ();
993 }
994}
995
996void
997WifiPrimaryChannelsTest::CheckReceivedTriggerFrames (std::set<uint8_t> txBss, uint16_t txChannelWidth)
998{
999 for (uint8_t bss = 0; bss < m_nBss; bss++)
1000 {
1001 if (txBss.find (bss) != txBss.end ())
1002 {
1003 // Every station in the BSS of an AP that transmitted the Trigger Frame hears (i.e.,
1004 // passes to the MAC) and processes the frame
1005 for (uint8_t sta = 0; sta < m_nStationsPerBss; sta++)
1006 {
1007 NS_TEST_EXPECT_MSG_EQ (m_received[bss].test (sta), true, "Station [" << +bss << "][" << +sta
1008 << "] did not receive the Trigger Frame soliciting a transmission on primary"
1009 << txChannelWidth << " channel");
1010 NS_TEST_EXPECT_MSG_EQ (m_processed[bss].test (sta), true, "Station [" << +bss << "][" << +sta
1011 << "] did not process the Trigger Frame soliciting a transmission on primary"
1012 << txChannelWidth << " channel");
1013 }
1014 }
1015 else
1016 {
1017 // Given that a Trigger Frame is transmitted on the primary20 channel and all the
1018 // primary20 channels are distinct, stations in other BSSes did not hear the frame
1019 for (uint8_t sta = 0; sta < m_nStationsPerBss; sta++)
1020 {
1021 NS_TEST_EXPECT_MSG_EQ (m_received[bss].test (sta), false, "Station [" << +bss << "][" << +sta
1022 << "] received the Trigger Frame soliciting a transmission on primary"
1023 << txChannelWidth << " channel");
1024 }
1025 }
1026 // reset bitmaps
1027 m_received[bss].reset ();
1028 m_processed[bss].reset ();
1029 }
1030}
1031
1032
1041{
1042public:
1047 virtual ~Wifi20MHzChannelIndicesTest () = default;
1048
1060 void RunOne (uint8_t primary20, const std::set<uint8_t>& secondary20,
1061 const std::set<uint8_t>& primary40, const std::set<uint8_t>& secondary40,
1062 const std::set<uint8_t>& primary80, const std::set<uint8_t>& secondary80);
1063
1064private:
1065 void DoRun (void) override;
1066
1068};
1069
1071 : TestCase ("Check computation of primary and secondary channel indices")
1072{
1073}
1074
1075void
1077 const std::set<uint8_t>& secondary20,
1078 const std::set<uint8_t>& primary40,
1079 const std::set<uint8_t>& secondary40,
1080 const std::set<uint8_t>& primary80,
1081 const std::set<uint8_t>& secondary80)
1082{
1083 auto printToStr = [](const std::set<uint8_t>& s)
1084 {
1085 std::stringstream ss;
1086 ss << "{";
1087 for (const auto& index : s) ss << +index << " ";
1088 ss << "}";
1089 return ss.str ();
1090 };
1091
1092 m_channel.SetPrimary20Index (primary20);
1093
1094 auto actualPrimary20 = m_channel.GetAll20MHzChannelIndicesInPrimary (20);
1095 NS_TEST_ASSERT_MSG_EQ ((actualPrimary20 == std::set<uint8_t> {primary20}),
1096 true,
1097 "Expected Primary20 {" << +primary20 << "}"
1098 << " differs from actual " << printToStr (actualPrimary20));
1099
1100 auto actualSecondary20 = m_channel.GetAll20MHzChannelIndicesInSecondary (actualPrimary20);
1101 NS_TEST_ASSERT_MSG_EQ ((actualSecondary20 == secondary20),
1102 true,
1103 "Expected Secondary20 " << printToStr (secondary20)
1104 << " differs from actual " << printToStr (actualSecondary20));
1105
1106 auto actualPrimary40 = m_channel.GetAll20MHzChannelIndicesInPrimary (40);
1107 NS_TEST_ASSERT_MSG_EQ ((actualPrimary40 == primary40),
1108 true,
1109 "Expected Primary40 " << printToStr (primary40)
1110 << " differs from actual " << printToStr (actualPrimary40));
1111
1112 auto actualSecondary40 = m_channel.GetAll20MHzChannelIndicesInSecondary (primary40);
1113 NS_TEST_ASSERT_MSG_EQ ((actualSecondary40 == secondary40),
1114 true,
1115 "Expected Secondary40 " << printToStr (secondary40)
1116 << " differs from actual " << printToStr (actualSecondary40));
1117
1118 auto actualPrimary80 = m_channel.GetAll20MHzChannelIndicesInPrimary (80);
1119 NS_TEST_ASSERT_MSG_EQ ((actualPrimary80 == primary80),
1120 true,
1121 "Expected Primary80 " << printToStr (primary80)
1122 << " differs from actual " << printToStr (actualPrimary80));
1123
1124 auto actualSecondary80 = m_channel.GetAll20MHzChannelIndicesInSecondary (primary80);
1125 NS_TEST_ASSERT_MSG_EQ ((actualSecondary80 == secondary80),
1126 true,
1127 "Expected Secondary80 " << printToStr (secondary80)
1128 << " differs from actual " << printToStr (actualSecondary80));
1129}
1130
1131void
1133{
1134 /* 20 MHz channel */
1136 RunOne (0, {}, {}, {}, {}, {});
1137
1138 /* 40 MHz channel */
1140 RunOne (0, {1}, {0, 1}, {}, {}, {});
1141 RunOne (1, {0}, {0, 1}, {}, {}, {});
1142
1143 /* 80 MHz channel */
1145 RunOne (0, {1}, {0, 1}, {2, 3}, {0, 1, 2, 3}, {});
1146 RunOne (1, {0}, {0, 1}, {2, 3}, {0, 1, 2, 3}, {});
1147 RunOne (2, {3}, {2, 3}, {0, 1}, {0, 1, 2, 3}, {});
1148 RunOne (3, {2}, {2, 3}, {0, 1}, {0, 1, 2, 3}, {});
1149
1150 /* 160 MHz channel */
1152 RunOne (0, {1}, {0, 1}, {2, 3}, {0, 1, 2, 3}, {4, 5, 6, 7});
1153 RunOne (1, {0}, {0, 1}, {2, 3}, {0, 1, 2, 3}, {4, 5, 6, 7});
1154 RunOne (2, {3}, {2, 3}, {0, 1}, {0, 1, 2, 3}, {4, 5, 6, 7});
1155 RunOne (3, {2}, {2, 3}, {0, 1}, {0, 1, 2, 3}, {4, 5, 6, 7});
1156 RunOne (4, {5}, {4, 5}, {6, 7}, {4, 5, 6, 7}, {0, 1, 2, 3});
1157 RunOne (5, {4}, {4, 5}, {6, 7}, {4, 5, 6, 7}, {0, 1, 2, 3});
1158 RunOne (6, {7}, {6, 7}, {4, 5}, {4, 5, 6, 7}, {0, 1, 2, 3});
1159 RunOne (7, {6}, {6, 7}, {4, 5}, {4, 5, 6, 7}, {0, 1, 2, 3});
1160}
1161
1162
1170{
1171public:
1173};
1174
1176 : TestSuite ("wifi-primary-channels", UNIT)
1177{
1178 // Test cases for 20 MHz can be added, but are not that useful (there would be a single BSS)
1179 AddTestCase (new WifiPrimaryChannelsTest (40, true), TestCase::QUICK);
1180 AddTestCase (new WifiPrimaryChannelsTest (40, false), TestCase::QUICK);
1181 AddTestCase (new WifiPrimaryChannelsTest (80, true), TestCase::EXTENSIVE);
1182 AddTestCase (new WifiPrimaryChannelsTest (80, false), TestCase::EXTENSIVE);
1183 AddTestCase (new WifiPrimaryChannelsTest (160, true), TestCase::TAKES_FOREVER);
1184 AddTestCase (new WifiPrimaryChannelsTest (160, false), TestCase::TAKES_FOREVER);
1185 AddTestCase (new Wifi20MHzChannelIndicesTest (), TestCase::QUICK);
1186}
1187
Test functions returning the indices of primary and secondary channels of different width.
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
void DoRun(void) override
Implementation to actually run this TestCase.
virtual ~Wifi20MHzChannelIndicesTest()=default
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
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 DoSetup(void) override
Implementation to do any local setup required for this TestCase.
void CheckAssociation(void)
Check that all stations associated with an AP.
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.
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.
void DoRun(void) override
Implementation to actually run this TestCase.
wifi primary channels test suite
AttributeValue implementation for Boolean.
Definition: boolean.h:37
Headers for Trigger frames.
Definition: ctrl-headers.h:886
void SetType(TriggerFrameType type)
Set the Trigger frame type.
RuType
The different HE Resource Unit (RU) types.
Definition: he-ru.h:42
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.
void AddHeader(const Header &header)
Add header to this packet.
Definition: packet.cc:256
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.
encapsulates test code
Definition: test.h:994
void AddTestCase(TestCase *testCase, TestDuration duration=QUICK)
Add an individual child TestCase to this test suite.
Definition: test.cc:299
A suite of tests to run.
Definition: test.h:1188
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:104
bool IsZero(void) const
Exactly equivalent to t == 0.
Definition: nstime.h:301
AttributeValue implementation for Time.
Definition: nstime.h:1309
Hold objects of type std::tuple<Args...>.
Definition: tuple.h:70
void Set(const result_type &value)
Set the stored values.
Definition: tuple.h:325
Hold an unsigned integer type.
Definition: uinteger.h:44
helps to create WifiNetDevice objects
Definition: wifi-helper.h:322
Implements the IEEE 802.11 MAC header.
Mac48Address GetAddr3(void) const
Return the address in the Address 3 field.
bool IsTrigger(void) const
Return true if the header is a Trigger header.
bool IsQosData(void) const
Return true if the Type is DATA and Subtype is one of the possible values for QoS Data.
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.
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.
Mac48Address GetAddr1(void) const
Return the address in the Address 1 field.
void SetAddr2(Mac48Address address)
Fill the Address 2 field with the given address.
void SetAddr3(Mac48Address address)
Fill the Address 3 field with the given address.
create MAC layers for a ns3::WifiNetDevice.
Ptr< WifiMac > GetMac(void) const
Ptr< WifiPhy > GetPhy(void) const
std::tuple< uint8_t, uint16_t, int, uint8_t > ChannelTuple
Tuple identifying an operating channel.
Definition: wifi-phy.h:839
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...
uint32_t GetSize(void) const
Return the size of the PSDU in bytes.
Definition: wifi-psdu.cc:260
const WifiMacHeader & GetHeader(std::size_t i) const
Get the header of the i-th MPDU.
Definition: wifi-psdu.cc:266
std::size_t GetNMpdus(void) const
Return the number of MPDUs constituting the PSDU.
Definition: wifi-psdu.cc:313
This class mimics the TXVECTOR which is to be passed to the PHY in order to define the parameters whi...
void SetHeMuUserInfo(uint16_t staId, HeMuUserInfo userInfo)
Set the HE MU user-specific transmission information for the given STA-ID.
void SetRuAllocation(const RuAllocation &ruAlloc)
Set RU Allocation of SIG-B common field.
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.
const HeMuUserInfoMap & GetHeMuUserInfoMap(void) const
Get a const reference to the map HE MU user-specific transmission information indexed by STA-ID.
bool IsUlMu(void) const
Return true if this TX vector is used for an uplink multi-user transmission.
void Connect(std::string path, const CallbackBase &cb)
Definition: config.cc:920
#define NS_ABORT_MSG(msg)
Unconditional abnormal program termination with a message.
Definition: abort.h:50
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:206
#define NS_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
Definition: log.h:282
#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:141
#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:240
Time MicroSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1261
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1245
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1253
@ 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
@ WIFI_MOD_CLASS_HE
HE (Clause 27)
@ BASIC_TRIGGER
Definition: ctrl-headers.h:562
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:661
@ WIFI_MAC_CTL_TRIGGER
@ WIFI_MAC_QOSDATA
std::vector< uint8_t > RuAllocation
mac
Definition: third.py:87
wifi
Definition: third.py:90
mobility
Definition: third.py:98
wifiStaNodes
Definition: third.py:79
phy
Definition: third.py:84
RxSignalInfo structure containing info on the received signal.
Definition: phy-entity.h:69
#define SU_STA_ID
Definition: wifi-mode.h:32
static WifiPrimaryChannelsTestSuite g_wifiPrimaryChannelsTestSuite
the test suite