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<WifiPsdu> psdu, RxSignalInfo rxSignalInfo,
133 WifiTxVector txVector, std::vector<bool> perMpduStatus);
143 void ReceiveUl (uint8_t bss, Ptr<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<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 "WaitBeaconTimeout", TimeValue (MicroSeconds (102400))); // same as BeaconInterval
355
357
358 // Each BSS uses a distinct primary20 channel
359 for (uint8_t bss = 0; bss < m_nBss; bss++)
360 {
361 channelValue.Set (WifiPhy::ChannelTuple {channelNum, m_channelWidth, WIFI_PHY_BAND_5GHZ, bss});
362 phy.Set ("ChannelSettings", channelValue);
363
364 m_staDevices.push_back (wifi.Install (phy, mac, wifiStaNodes[bss]));
365 }
366
367 for (uint8_t bss = 0; bss < m_nBss; bss++)
368 {
369 channelValue.Set (WifiPhy::ChannelTuple {channelNum, m_channelWidth, WIFI_PHY_BAND_5GHZ, bss});
370 phy.Set ("ChannelSettings", channelValue);
371
372 mac.SetType ("ns3::ApWifiMac",
373 "Ssid", SsidValue (Ssid ("wifi-ssid-" + std::to_string (bss))),
374 "BeaconInterval", TimeValue (MicroSeconds (102400)),
375 "EnableBeaconJitter", BooleanValue (false));
376
377 m_apDevices.Add (wifi.Install (phy, mac, wifiApNodes.Get (bss)));
378 }
379
380 // Assign fixed streams to random variables in use
381 streamNumber = wifi.AssignStreams (m_apDevices, streamNumber);
382 for (uint8_t bss = 0; bss < m_nBss; bss++)
383 {
384 streamNumber = wifi.AssignStreams (m_staDevices[bss], streamNumber);
385 }
386
387 // set BSS color
389 {
390 for (uint8_t bss = 0; bss < m_nBss; bss++)
391 {
392 auto dev = DynamicCast<WifiNetDevice> (m_apDevices.Get (bss));
393 dev->GetHeConfiguration ()->SetBssColor (bss + 1);
394 }
395 }
396
398 Ptr<ListPositionAllocator> positionAlloc = CreateObject<ListPositionAllocator> ();
399
400 positionAlloc->Add (Vector (0.0, 0.0, 0.0)); // all stations are co-located
401 mobility.SetPositionAllocator (positionAlloc);
402
403 mobility.SetMobilityModel ("ns3::ConstantPositionMobilityModel");
404 mobility.Install (wifiApNodes);
405 for (uint8_t bss = 0; bss < m_nBss; bss++)
406 {
407 mobility.Install (wifiStaNodes[bss]);
408 }
409
410 m_received.resize (m_nBss);
411 m_processed.resize (m_nBss);
412
413 // pre-compute the Basic Trigger Frame to send
414 auto apDev = DynamicCast<WifiNetDevice> (m_apDevices.Get (0));
415
416 WifiMacHeader hdr;
418 hdr.SetAddr1 (Mac48Address::GetBroadcast ());
419 // Addr2 has to be set
420 hdr.SetSequenceNumber (1);
421
422 Ptr<Packet> pkt = Create<Packet> ();
423 CtrlTriggerHeader trigger;
425 pkt->AddHeader (trigger);
426
427 m_triggerTxVector = WifiTxVector (OfdmPhy::GetOfdmRate6Mbps (), 0, WIFI_PREAMBLE_LONG, 800, 1, 1, 0,
428 20, false, false, false);
429 m_trigger = Create<WifiPsdu> (pkt, hdr);
430
431 m_triggerTxDuration = WifiPhy::CalculateTxDuration (m_trigger->GetSize (), m_triggerTxVector,
432 apDev->GetMac ()->GetWifiPhy ()->GetPhyBand ());
433}
434
435void
437{
438 // schedule association requests at different times
440
441 for (uint16_t i = 0; i < m_nStationsPerBss; i++)
442 {
443 // association can be done in parallel over the multiple BSSes
444 for (uint8_t bss = 0; bss < m_nBss; bss++)
445 {
446 dev = DynamicCast<WifiNetDevice> (m_staDevices[bss].Get (i));
447 Simulator::Schedule (i * MicroSeconds (102400), &WifiMac::SetSsid,
448 dev->GetMac (), Ssid ("wifi-ssid-" + std::to_string (bss)));
449 }
450 }
451
452 // just before sending the beacon preceding the last association, increase the beacon
453 // interval (to the max allowed value) so that beacons do not interfere with data frames
454 for (uint8_t bss = 0; bss < m_nBss; bss++)
455 {
456 dev = DynamicCast<WifiNetDevice> (m_apDevices.Get (bss));
457 auto mac = DynamicCast<ApWifiMac> (dev->GetMac ());
458
459 Simulator::Schedule ((m_nStationsPerBss - 1) * MicroSeconds (102400),
460 &ApWifiMac::SetBeaconInterval, mac, MicroSeconds (1024 * 65535));
461 }
462
463 m_time = (m_nStationsPerBss + 1) * MicroSeconds (102400);
464
465 Simulator::Schedule (m_time, &WifiPrimaryChannelsTest::CheckAssociation, this);
466
467 // we are done with association. We now intercept frames received by the
468 // PHY layer on stations and APs, which will no longer be passed to the FEM.
469 for (uint8_t bss = 0; bss < m_nBss; bss++)
470 {
471 for (uint8_t i = 0; i < m_nStationsPerBss; i++)
472 {
473 auto dev = DynamicCast<WifiNetDevice> (m_staDevices[bss].Get (i));
474 Simulator::Schedule (m_time, &WifiPhy::SetReceiveOkCallback, dev->GetPhy (),
476 .TwoBind (bss, i));
477 }
478 auto dev = DynamicCast<WifiNetDevice> (m_apDevices.Get (bss));
479 Simulator::Schedule (m_time, &WifiPhy::SetReceiveOkCallback, dev->GetPhy (),
481 .Bind (bss));
482 }
483
484 /*
485 * We start generating (downlink) SU PPDUs.
486 * First, APs operating on non-adjacent primary20 channels send a frame simultaneously
487 * in their primary20. This is done in two rounds. As an example, we consider the
488 * case of an 160 MHz operating channel:
489 *
490 * AP0 AP2 AP4 AP6
491 * |-----| |-----| |-----| |-----| |
492 *
493 * AP1 AP3 AP5 AP7
494 * | |-----| |-----| |-----| |-----|
495 *
496 * Then, we double the transmission channel width. We will have four rounds
497 * of transmissions. We avoid using adjacent channels to avoid interfence
498 * among transmissions:
499 *
500 * AP0 AP4
501 * |-----------| |-----------| |
502 * AP1 AP5
503 * |-----------| |-----------| |
504 * AP2 AP6
505 * | |-----------| |-----------|
506 * AP3 AP7
507 * | |-----------| |-----------|
508 *
509 * We double the transmission channel width again. We will have eight rounds
510 * of transmissions:
511 *
512 * AP0
513 * |-----------------------| |
514 * AP1
515 * |-----------------------| |
516 * AP2
517 * |-----------------------| |
518 * AP3
519 * |-----------------------| |
520 * AP4
521 * | |-----------------------|
522 * AP5
523 * | |-----------------------|
524 * AP6
525 * | |-----------------------|
526 * AP7
527 * | |-----------------------|
528 *
529 * We double the transmission channel width again. We will have eight rounds
530 * of transmissions:
531 *
532 * AP0
533 * |-----------------------------------------------|
534 * AP1
535 * |-----------------------------------------------|
536 * AP2
537 * |-----------------------------------------------|
538 * AP3
539 * |-----------------------------------------------|
540 * AP4
541 * |-----------------------------------------------|
542 * AP5
543 * |-----------------------------------------------|
544 * AP6
545 * |-----------------------------------------------|
546 * AP7
547 * |-----------------------------------------------|
548 *
549 * The transmission channel width reached the operating channel width, we are done.
550 */
551
552 Time roundDuration = MilliSeconds (5); // upper bound on the duration of a round
553
554 // To have simultaneous transmissions on adjacent channels, just initialize
555 // nRounds to 1 and nApsPerRound to m_channelWidth / 20. Of course, the test
556 // will fail because some stations will not receive some frames due to interfence
557 for (uint16_t txChannelWidth = 20, nRounds = 2, nApsPerRound = m_channelWidth / 20 / 2;
558 txChannelWidth <= m_channelWidth;
559 txChannelWidth *= 2, nRounds *= 2, nApsPerRound /= 2)
560 {
561 nRounds = std::min<uint16_t> (nRounds, m_nBss);
562 nApsPerRound = std::max<uint16_t> (nApsPerRound, 1);
563
564 for (uint16_t round = 0; round < nRounds; round++)
565 {
566 std::set<uint8_t> txBss;
567
568 for (uint16_t i = 0; i < nApsPerRound; i++)
569 {
570 uint16_t ap = round + i * nRounds;
571 txBss.insert (ap);
572 Simulator::Schedule (m_time, &WifiPrimaryChannelsTest::SendDlSuPpdu, this,
573 ap, txChannelWidth);
574 }
575 // check that the SU frames were correctly received
576 Simulator::Schedule (m_time + roundDuration, &WifiPrimaryChannelsTest::CheckReceivedSuPpdus,
577 this, txBss, txChannelWidth);
578 m_time += roundDuration;
579 }
580 }
581
582 /*
583 * Repeat the same scheme as before with DL MU transmissions. For each transmission
584 * channel width, every round is repeated as many times as the number of ways in
585 * which we can partition the transmission channel width in equal sized RUs.
586 */
587 for (uint16_t txChannelWidth = 20, nRounds = 2, nApsPerRound = m_channelWidth / 20 / 2;
588 txChannelWidth <= m_channelWidth;
589 txChannelWidth *= 2, nRounds *= 2, nApsPerRound /= 2)
590 {
591 nRounds = std::min<uint16_t> (nRounds, m_nBss);
592 nApsPerRound = std::max<uint16_t> (nApsPerRound, 1);
593
594 for (uint16_t round = 0; round < nRounds; round++)
595 {
596 for (unsigned int type = 0; type < 7; type++)
597 {
598 HeRu::RuType ruType = static_cast <HeRu::RuType> (type);
599 std::size_t nRus = HeRu::GetNRus (txChannelWidth, ruType);
600 std::set<uint8_t> txBss;
601 if (nRus > 0)
602 {
603 for (uint16_t i = 0; i < nApsPerRound; i++)
604 {
605 uint16_t ap = round + i * nRounds;
606 txBss.insert (ap);
607 Simulator::Schedule (m_time, &WifiPrimaryChannelsTest::SendDlMuPpdu, this,
608 ap, txChannelWidth, ruType, nRus);
609 }
610 // check that the MU frame was correctly received
611 Simulator::Schedule (m_time + roundDuration, &WifiPrimaryChannelsTest::CheckReceivedMuPpdus,
612 this, txBss, txChannelWidth, ruType, nRus, /* isDlMu */ true);
613 m_time += roundDuration;
614 }
615 }
616 }
617 }
618
619 /*
620 * Repeat the same scheme as before with UL MU transmissions. For each transmission
621 * channel width, every round is repeated as many times as the number of ways in
622 * which we can partition the transmission channel width in equal sized RUs.
623 */
624 for (uint16_t txChannelWidth = 20, nRounds = 2, nApsPerRound = m_channelWidth / 20 / 2;
625 txChannelWidth <= m_channelWidth;
626 txChannelWidth *= 2, nRounds *= 2, nApsPerRound /= 2)
627 {
628 nRounds = std::min<uint16_t> (nRounds, m_nBss);
629 nApsPerRound = std::max<uint16_t> (nApsPerRound, 1);
630
631 for (uint16_t round = 0; round < nRounds; round++)
632 {
633 for (unsigned int type = 0; type < 7; type++)
634 {
635 HeRu::RuType ruType = static_cast <HeRu::RuType> (type);
636 std::size_t nRus = HeRu::GetNRus (txChannelWidth, ruType);
637 std::set<uint8_t> txBss;
638 if (nRus > 0)
639 {
640 for (uint16_t i = 0; i < nApsPerRound; i++)
641 {
642 uint16_t ap = round + i * nRounds;
643 txBss.insert (ap);
644 Simulator::Schedule (m_time, &WifiPrimaryChannelsTest::SendHeTbPpdu, this,
645 ap, txChannelWidth, ruType, nRus);
646 }
647 // check that Trigger Frames and TB PPDUs were correctly received
648 Simulator::Schedule (m_time + m_triggerTxDuration + MicroSeconds (10), /* during SIFS */
650 this, txBss, txChannelWidth);
651 Simulator::Schedule (m_time + roundDuration, &WifiPrimaryChannelsTest::CheckReceivedMuPpdus,
652 this, txBss, txChannelWidth, ruType, nRus, /* isDlMu */ false);
653 m_time += roundDuration;
654 }
655 }
656 }
657 }
658
659 // Trace PSDUs passed to the PHY on all devices
660 Config::Connect ("/NodeList/*/DeviceList/*/$ns3::WifiNetDevice/Phy/PhyTxPsduBegin",
662
663 Simulator::Stop (m_time);
664 Simulator::Run ();
665
666 Simulator::Destroy ();
667}
668
669void
670WifiPrimaryChannelsTest::SendDlSuPpdu (uint8_t bss, uint16_t txChannelWidth)
671{
672 NS_LOG_INFO ("*** BSS " << +bss << " transmits on primary " << txChannelWidth << " MHz channel");
673
674 auto apDev = DynamicCast<WifiNetDevice> (m_apDevices.Get (bss));
675 auto staDev = DynamicCast<WifiNetDevice> (m_staDevices[bss].Get (0));
676
677 uint8_t bssColor = apDev->GetHeConfiguration ()->GetBssColor ();
678 WifiTxVector txVector = WifiTxVector (HePhy::GetHeMcs8 (), 0, WIFI_PREAMBLE_HE_SU, 800, 1, 1, 0, txChannelWidth, false, false, false, bssColor);
679 WifiMacHeader hdr;
681 hdr.SetQosTid (0);
682 hdr.SetAddr1 (staDev->GetMac ()->GetAddress ());
683 hdr.SetAddr2 (apDev->GetMac ()->GetAddress ());
684 hdr.SetAddr3 (apDev->GetMac ()->GetBssid ());
685 hdr.SetSequenceNumber (1);
686 Ptr<WifiPsdu> psdu = Create<WifiPsdu> (Create<Packet> (1000), hdr);
687 apDev->GetPhy ()->Send (WifiConstPsduMap ({std::make_pair (SU_STA_ID, psdu)}), txVector);
688}
689
690void
691WifiPrimaryChannelsTest::SendDlMuPpdu (uint8_t bss, uint16_t txChannelWidth, HeRu::RuType ruType, std::size_t nRus)
692{
693 NS_LOG_INFO ("*** BSS " << +bss << " transmits on primary " << txChannelWidth
694 << " MHz channel a DL MU PPDU " << "addressed to " << nRus
695 << " stations (RU type: " << ruType << ")");
696
697 auto apDev = DynamicCast<WifiNetDevice> (m_apDevices.Get (bss));
698 uint8_t bssColor = apDev->GetHeConfiguration ()->GetBssColor ();
699
700 WifiTxVector txVector = WifiTxVector (HePhy::GetHeMcs8 (), 0, WIFI_PREAMBLE_HE_MU, 800, 1, 1, 0, txChannelWidth, false, false, false, bssColor);
701 WifiMacHeader hdr;
703 hdr.SetQosTid (0);
704 hdr.SetAddr2 (apDev->GetMac ()->GetAddress ());
705 hdr.SetAddr3 (apDev->GetMac ()->GetBssid ());
706 hdr.SetSequenceNumber (1);
707
708 WifiConstPsduMap psduMap;
709
710 for (std::size_t i = 1; i <= nRus; i++)
711 {
712 bool primary80 = !(txChannelWidth == 160 && i > nRus / 2);
713 std::size_t index = (primary80 ? i : i - nRus / 2);
714
715 auto staDev = DynamicCast<WifiNetDevice> (m_staDevices[bss].Get (i - 1));
716 uint16_t staId = DynamicCast<StaWifiMac> (staDev->GetMac ())->GetAssociationId ();
717 txVector.SetHeMuUserInfo (staId, {{ruType, index, primary80}, HePhy::GetHeMcs8 (), 1});
718 hdr.SetAddr1 (staDev->GetMac ()->GetAddress ());
719 psduMap[staId] = Create<const WifiPsdu> (Create<Packet> (1000), hdr);
720 }
721 apDev->GetPhy ()->Send (psduMap, txVector);
722}
723
724void
725WifiPrimaryChannelsTest::SendHeTbPpdu (uint8_t bss, uint16_t txChannelWidth, HeRu::RuType ruType, std::size_t nRus)
726{
727 NS_LOG_INFO ("*** BSS " << +bss << " transmits a Basic Trigger Frame");
728
729 auto apDev = DynamicCast<WifiNetDevice> (m_apDevices.Get (bss));
730
731 m_trigger->GetHeader (0).SetAddr2 (apDev->GetMac ()->GetAddress ());
732
733 apDev->GetPhy ()->Send (m_trigger, m_triggerTxVector);
734
735 // schedule the transmission of HE TB PPDUs
736 Simulator::Schedule (m_triggerTxDuration + apDev->GetPhy ()->GetSifs (),
738 bss, txChannelWidth, ruType, nRus);
739}
740
741void
742WifiPrimaryChannelsTest::DoSendHeTbPpdu (uint8_t bss, uint16_t txChannelWidth, HeRu::RuType ruType, std::size_t nRus)
743{
744 auto apDev = DynamicCast<WifiNetDevice> (m_apDevices.Get (bss));
745 uint8_t bssColor = apDev->GetHeConfiguration ()->GetBssColor ();
746
747 WifiMacHeader hdr;
749 hdr.SetQosTid (0);
750 hdr.SetAddr1 (apDev->GetMac ()->GetAddress ());
751 hdr.SetAddr3 (apDev->GetMac ()->GetBssid ());
752 hdr.SetSequenceNumber (1);
753
754 Time duration = Seconds (0);
755 uint16_t length = 0;
756 WifiTxVector trigVector (HePhy::GetHeMcs8 (), 0, WIFI_PREAMBLE_HE_TB, 3200, 1, 1, 0, txChannelWidth, false, false, false, bssColor);
757
758 for (std::size_t i = 1; i <= nRus; i++)
759 {
760 NS_LOG_INFO ("*** BSS " << +bss << " STA " << i - 1 << " transmits on primary "
761 << txChannelWidth << " MHz channel an HE TB PPDU (RU type: " << ruType << ")");
762
763 bool primary80 = !(txChannelWidth == 160 && i > nRus / 2);
764 std::size_t index = (primary80 ? i : i - nRus / 2);
765
766 auto staDev = DynamicCast<WifiNetDevice> (m_staDevices[bss].Get (i - 1));
767 uint16_t staId = DynamicCast<StaWifiMac> (staDev->GetMac ())->GetAssociationId ();
768
769 WifiTxVector txVector (HePhy::GetHeMcs8 (), 0, WIFI_PREAMBLE_HE_TB, 3200, 1, 1, 0, txChannelWidth, false, false, false, bssColor);
770 txVector.SetHeMuUserInfo (staId, {{ruType, index, primary80}, HePhy::GetHeMcs8 (), 1});
771 trigVector.SetHeMuUserInfo (staId, {{ruType, index, primary80}, HePhy::GetHeMcs8 (), 1});
772
773 hdr.SetAddr2 (staDev->GetMac ()->GetAddress ());
774 Ptr<const WifiPsdu> psdu = Create<const WifiPsdu> (Create<Packet> (1000), hdr);
775
776 if (duration.IsZero ())
777 {
778 // calculate just once
779 duration = WifiPhy::CalculateTxDuration (psdu->GetSize (), txVector,
780 staDev->GetMac ()->GetWifiPhy ()->GetPhyBand (), staId);
781 std::tie (length, duration) = HePhy::ConvertHeTbPpduDurationToLSigLength (duration, txVector,
782 staDev->GetMac ()->GetWifiPhy ()->GetPhyBand ());
783 }
784 txVector.SetLength (length);
785
786 staDev->GetPhy ()->Send (WifiConstPsduMap {{staId, psdu}}, txVector);
787 }
788
789 // AP's PHY expects to receive a TRIGVECTOR (just once)
790 trigVector.SetLength (length);
791 auto apHePhy = StaticCast<HePhy> (apDev->GetPhy ()->GetPhyEntity (WIFI_MOD_CLASS_HE));
792 apHePhy->SetTrigVector (trigVector, duration);
793}
794
795void
797{
798 for (uint8_t bss = 0; bss < m_nBss; bss++)
799 {
800 auto dev = DynamicCast<WifiNetDevice> (m_apDevices.Get (bss));
801 auto mac = DynamicCast<ApWifiMac> (dev->GetMac ());
802 NS_TEST_EXPECT_MSG_EQ (mac->GetStaList ().size (), m_nStationsPerBss,
803 "Not all the stations completed association");
804 }
805}
806
807void
808WifiPrimaryChannelsTest::CheckReceivedSuPpdus (std::set<uint8_t> txBss, uint16_t txChannelWidth)
809{
810 for (uint8_t bss = 0; bss < m_nBss; bss++)
811 {
812 if (txBss.find (bss) != txBss.end ())
813 {
814 // Every station in the BSS of an AP that transmitted the frame hears (i.e.,
815 // passes to the MAC) the frame
816 for (uint8_t sta = 0; sta < m_nStationsPerBss; sta++)
817 {
818 NS_TEST_EXPECT_MSG_EQ (m_received[bss].test (sta), true, "Station [" << +bss << "][" << +sta
819 << "] did not receive the SU frame on primary" << txChannelWidth << " channel");
820 }
821 // only the first station actually processed the frames
822 NS_TEST_EXPECT_MSG_EQ (m_processed[bss].test (0), true, "Station [" << +bss << "][0]"
823 << " did not process the SU frame on primary" << txChannelWidth << " channel");
824 for (uint8_t sta = 1; sta < m_nStationsPerBss; sta++)
825 {
826 NS_TEST_EXPECT_MSG_EQ (m_processed[bss].test (sta), false, "Station [" << +bss << "][" << +sta
827 << "] processed the SU frame on primary" << txChannelWidth << " channel");
828 }
829 }
830 else
831 {
832 // There was no transmission in this BSS. If BSS Color filtering is enabled or no frame
833 // transmission overlaps with the primary20 channel of this BSS, stations in this BSS
834 // did not hear any frame.
836 || std::none_of (txBss.begin (), txBss.end (),
837 [&](const uint8_t& txAp)
838 {
839 auto txApPhy = DynamicCast<WifiNetDevice> (m_apDevices.Get (txAp))->GetPhy ();
840 auto thisApPhy = DynamicCast<WifiNetDevice> (m_apDevices.Get (bss))->GetPhy ();
841 return txApPhy->GetOperatingChannel ().GetPrimaryChannelIndex (txChannelWidth)
842 == thisApPhy->GetOperatingChannel ().GetPrimaryChannelIndex (txChannelWidth);
843 }))
844 {
845 for (uint8_t sta = 0; sta < m_nStationsPerBss; sta++)
846 {
847 NS_TEST_EXPECT_MSG_EQ (m_received[bss].test (sta), false, "Station [" << +bss << "][" << +sta
848 << "] received the SU frame on primary" << txChannelWidth << " channel");
849 }
850 }
851 else
852 {
853 // all stations heard the frame but no station processed it
854 for (uint8_t sta = 0; sta < m_nStationsPerBss; sta++)
855 {
856 NS_TEST_EXPECT_MSG_EQ (m_received[bss].test (sta), true, "Station [" << +bss << "][" << +sta
857 << "] did not receive the SU frame on primary" << txChannelWidth << " channel");
858 NS_TEST_EXPECT_MSG_EQ (m_processed[bss].test (sta), false, "Station [" << +bss << "][" << +sta
859 << "] processed the SU frame on primary" << txChannelWidth << " channel");
860 }
861 }
862 }
863 // reset bitmaps
864 m_received[bss].reset ();
865 m_processed[bss].reset ();
866 }
867}
868
869void
870WifiPrimaryChannelsTest::CheckReceivedMuPpdus (std::set<uint8_t> txBss, uint16_t txChannelWidth,
871 HeRu::RuType ruType, std::size_t nRus, bool isDlMu)
872{
873 for (uint8_t bss = 0; bss < m_nBss; bss++)
874 {
875 if (txBss.find (bss) != txBss.end ())
876 {
877 // There was a transmission in this BSS.
878 // [DL] Due to AID filtering, only stations that are addressed by the MU PPDU do hear the frame
879 // [UL] The AP hears a TB PPDU sent by all and only the solicited stations
880 for (uint8_t sta = 0; sta < nRus; sta++)
881 {
882 NS_TEST_EXPECT_MSG_EQ (m_received[bss].test (sta), true,
883 (isDlMu ? "A DL MU PPDU transmitted to" : "An HE TB PPDU transmitted by")
884 << " station [" << +bss << "][" << +sta << "] on primary"
885 << txChannelWidth << " channel, RU type " << ruType
886 << " was not received");
887 }
888 for (uint8_t sta = nRus; sta < m_nStationsPerBss; sta++)
889 {
890 NS_TEST_EXPECT_MSG_EQ (m_received[bss].test (sta), false,
891 (isDlMu ? "A DL MU PPDU" : "An HE TB PPDU")
892 << " transmitted on primary" << txChannelWidth
893 << " channel, RU type " << ruType << " was received "
894 << (isDlMu ? "by" : "from") << " station [" << +bss << "]["
895 << +sta << "]");
896 }
897 // [DL] Only the addressed stations actually processed the frames
898 // [UL] The AP processed the frames sent by all and only the addressed stations
899 for (uint8_t sta = 0; sta < nRus; sta++)
900 {
901 NS_TEST_EXPECT_MSG_EQ (m_processed[bss].test (sta), true,
902 (isDlMu ? "A DL MU PPDU transmitted to" : "An HE TB PPDU transmitted by")
903 << " station [" << +bss << "][" << +sta << "] on primary"
904 << txChannelWidth << " channel, RU type " << ruType
905 << " was not processed");
906 }
907 for (uint8_t sta = nRus; sta < m_nStationsPerBss; sta++)
908 {
909 NS_TEST_EXPECT_MSG_EQ (m_processed[bss].test (sta), false,
910 (isDlMu ? "A DL MU PPDU" : "An HE TB PPDU")
911 << " transmitted on primary" << txChannelWidth
912 << " channel, RU type " << ruType << " was received "
913 << (isDlMu ? "by" : "from") << " station [" << +bss << "]["
914 << +sta << "] and processed");
915 }
916 }
917 else
918 {
919 // There was no transmission in this BSS.
920 // [DL] If BSS Color filtering is enabled or no frame transmission overlaps with
921 // the primary20 channel of this BSS, stations in this BSS did not hear any frame.
922 // [UL] The AP did not hear any TB PPDU because no TRIGVECTOR was passed to the PHY
923 if (!isDlMu || m_useDistinctBssColors
924 || std::none_of (txBss.begin (), txBss.end (),
925 [&](const uint8_t& txAp)
926 {
927 auto txApPhy = DynamicCast<WifiNetDevice> (m_apDevices.Get (txAp))->GetPhy ();
928 auto thisApPhy = DynamicCast<WifiNetDevice> (m_apDevices.Get (bss))->GetPhy ();
929 return txApPhy->GetOperatingChannel ().GetPrimaryChannelIndex (txChannelWidth)
930 == thisApPhy->GetOperatingChannel ().GetPrimaryChannelIndex (txChannelWidth);
931 }))
932 {
933 for (uint8_t sta = 0; sta < m_nStationsPerBss; sta++)
934 {
935 NS_TEST_EXPECT_MSG_EQ (m_received[bss].test (sta), false,
936 (isDlMu ? "A DL MU PPDU" : "An HE TB PPDU")
937 << " transmitted on primary" << txChannelWidth
938 << " channel, RU type " << ruType << " was received "
939 << (isDlMu ? "by" : "from") << " station [" << +bss << "]["
940 << +sta << "]");
941 }
942 }
943 else
944 {
945 // [DL] Stations having the same AID of the stations addressed by the MU PPDU received the frame
946 for (uint8_t sta = 0; sta < nRus; sta++)
947 {
948 NS_TEST_EXPECT_MSG_EQ (m_received[bss].test (sta), true,
949 (isDlMu ? "A DL MU PPDU transmitted to" : "An HE TB PPDU transmitted by")
950 << " station [" << +bss << "][" << +sta << "] on primary"
951 << txChannelWidth << " channel, RU type " << ruType
952 << " was not received");
953 }
954 for (uint8_t sta = nRus; sta < m_nStationsPerBss; sta++)
955 {
956 NS_TEST_EXPECT_MSG_EQ (m_received[bss].test (sta), false,
957 (isDlMu ? "A DL MU PPDU" : "An HE TB PPDU")
958 << " transmitted on primary" << txChannelWidth
959 << " channel, RU type " << ruType << " was received "
960 << (isDlMu ? "by" : "from") << " station [" << +bss << "]["
961 << +sta << "]");
962 }
963 // no station processed the frame
964 for (uint8_t sta = 0; sta < m_nStationsPerBss; sta++)
965 {
966 NS_TEST_EXPECT_MSG_EQ (m_processed[bss].test (sta), false,
967 (isDlMu ? "A DL MU PPDU" : "An HE TB PPDU")
968 << " transmitted on primary" << txChannelWidth
969 << " channel, RU type " << ruType << " was received "
970 << (isDlMu ? "by" : "from") << " station [" << +bss << "]["
971 << +sta << "] and processed");
972 }
973 }
974 }
975 // reset bitmaps
976 m_received[bss].reset ();
977 m_processed[bss].reset ();
978 }
979}
980
981void
982WifiPrimaryChannelsTest::CheckReceivedTriggerFrames (std::set<uint8_t> txBss, uint16_t txChannelWidth)
983{
984 for (uint8_t bss = 0; bss < m_nBss; bss++)
985 {
986 if (txBss.find (bss) != txBss.end ())
987 {
988 // Every station in the BSS of an AP that transmitted the Trigger Frame hears (i.e.,
989 // passes to the MAC) and processes the frame
990 for (uint8_t sta = 0; sta < m_nStationsPerBss; sta++)
991 {
992 NS_TEST_EXPECT_MSG_EQ (m_received[bss].test (sta), true, "Station [" << +bss << "][" << +sta
993 << "] did not receive the Trigger Frame soliciting a transmission on primary"
994 << txChannelWidth << " channel");
995 NS_TEST_EXPECT_MSG_EQ (m_processed[bss].test (sta), true, "Station [" << +bss << "][" << +sta
996 << "] did not process the Trigger Frame soliciting a transmission on primary"
997 << txChannelWidth << " channel");
998 }
999 }
1000 else
1001 {
1002 // Given that a Trigger Frame is transmitted on the primary20 channel and all the
1003 // primary20 channels are distinct, stations in other BSSes did not hear the frame
1004 for (uint8_t sta = 0; sta < m_nStationsPerBss; sta++)
1005 {
1006 NS_TEST_EXPECT_MSG_EQ (m_received[bss].test (sta), false, "Station [" << +bss << "][" << +sta
1007 << "] received the Trigger Frame soliciting a transmission on primary"
1008 << txChannelWidth << " channel");
1009 }
1010 }
1011 // reset bitmaps
1012 m_received[bss].reset ();
1013 m_processed[bss].reset ();
1014 }
1015}
1016
1017
1025{
1026public:
1028};
1029
1031 : TestSuite ("wifi-primary-channels", UNIT)
1032{
1033 // Test cases for 20 MHz can be added, but are not that useful (there would be a single BSS)
1034 AddTestCase (new WifiPrimaryChannelsTest (40, true), TestCase::QUICK);
1035 AddTestCase (new WifiPrimaryChannelsTest (40, false), TestCase::QUICK);
1036 AddTestCase (new WifiPrimaryChannelsTest (80, true), TestCase::EXTENSIVE);
1037 AddTestCase (new WifiPrimaryChannelsTest (80, false), TestCase::EXTENSIVE);
1038 AddTestCase (new WifiPrimaryChannelsTest (160, true), TestCase::TAKES_FOREVER);
1039 AddTestCase (new WifiPrimaryChannelsTest (160, false), TestCase::TAKES_FOREVER);
1040}
1041
Test transmissions under different primary channel settings.
void ReceiveDl(uint8_t bss, uint8_t station, Ptr< WifiPsdu > psdu, RxSignalInfo rxSignalInfo, WifiTxVector txVector, std::vector< bool > perMpduStatus)
Callback invoked when a station receives a DL PPDU.
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
void ReceiveUl(uint8_t bss, Ptr< WifiPsdu > psdu, RxSignalInfo rxSignalInfo, WifiTxVector txVector, std::vector< bool > perMpduStatus)
Callback invoked when an AP receives an UL PPDU.
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 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 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:103
bool IsZero(void) const
Exactly equivalent to t == 0.
Definition: nstime.h:300
AttributeValue implementation for Time.
Definition: nstime.h:1308
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
helps to create WifiNetDevice objects
Definition: wifi-helper.h:323
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:832
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:319
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 SetLength(uint16_t length)
Set the LENGTH field of the L-SIG.
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:205
#define NS_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
Definition: log.h:281
#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:1260
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1244
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1252
@ 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.
@ WIFI_MAC_CTL_TRIGGER
@ WIFI_MAC_QOSDATA
Callback< R, Ts... > MakeCallback(R(T::*memPtr)(Ts...), OBJ objPtr)
Build Callbacks for class method members which take varying numbers of arguments and potentially retu...
Definition: callback.h:1648
mac
Definition: third.py:96
wifi
Definition: third.py:99
mobility
Definition: third.py:107
wifiStaNodes
Definition: third.py:88
phy
Definition: third.py:93
RxSignalInfo structure containing info on the received signal.
Definition: phy-entity.h:67
#define SU_STA_ID
Definition: wifi-mode.h:32
static WifiPrimaryChannelsTestSuite g_wifiPrimaryChannelsTestSuite
the test suite