A Discrete-Event Network Simulator
API
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 
41 using namespace ns3;
42 
43 NS_LOG_COMPONENT_DEFINE("WifiPrimaryChannelsTest");
44 
62 {
63  public:
70  WifiPrimaryChannelsTest(uint16_t channelWidth, bool useDistinctBssColors);
71  ~WifiPrimaryChannelsTest() override;
72 
82  void Transmit(std::string context,
83  WifiConstPsduMap psduMap,
84  WifiTxVector txVector,
85  double txPowerW);
93  void SendDlSuPpdu(uint8_t bss, uint16_t txChannelWidth);
103  void SendDlMuPpdu(uint8_t bss, uint16_t txChannelWidth, HeRu::RuType ruType, std::size_t nRus);
114  void SendHeTbPpdu(uint8_t bss, uint16_t txChannelWidth, HeRu::RuType ruType, std::size_t nRus);
124  void DoSendHeTbPpdu(uint8_t bss,
125  uint16_t txChannelWidth,
126  HeRu::RuType ruType,
127  std::size_t nRus);
138  void ReceiveDl(uint8_t bss,
139  uint8_t station,
140  Ptr<const WifiPsdu> psdu,
141  RxSignalInfo rxSignalInfo,
142  WifiTxVector txVector,
143  std::vector<bool> perMpduStatus);
153  void ReceiveUl(uint8_t bss,
154  Ptr<const WifiPsdu> psdu,
155  RxSignalInfo rxSignalInfo,
156  WifiTxVector txVector,
157  std::vector<bool> perMpduStatus);
161  void CheckAssociation();
172  void CheckReceivedSuPpdus(std::set<uint8_t> txBss, uint16_t txChannelWidth);
186  void CheckReceivedMuPpdus(std::set<uint8_t> txBss,
187  uint16_t txChannelWidth,
188  HeRu::RuType ruType,
189  std::size_t nRus,
190  bool isDlMu);
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;
208  uint8_t m_nBss;
210  std::vector<NetDeviceContainer> m_staDevices;
212  std::vector<std::bitset<74>> m_received;
214  std::vector<std::bitset<74>> m_processed;
220 };
221 
222 WifiPrimaryChannelsTest::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 
233 void
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 
255 void
257  uint8_t station,
258  Ptr<const WifiPsdu> psdu,
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
271  NS_TEST_EXPECT_MSG_EQ(m_received[bss].test(station),
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  {
281  NS_TEST_EXPECT_MSG_EQ(m_processed[bss].test(station),
282  false,
283  "Station [" << +bss << "][" << +station
284  << "] processed a frame twice");
285  m_processed[bss].set(station);
286  }
287  }
288  }
289 }
290 
291 void
293  Ptr<const WifiPsdu> psdu,
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
309  NS_TEST_EXPECT_MSG_EQ(m_received[bss].test(station),
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  {
317  NS_TEST_EXPECT_MSG_EQ(m_processed[bss].test(station),
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 
326 void
328 {
329  RngSeedManager::SetSeed(1);
330  RngSeedManager::SetRun(40);
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:
339  m_nStationsPerBss = 9;
340  channelNum = 36;
341  break;
342  case 40:
343  m_nStationsPerBss = 18;
344  channelNum = 38;
345  break;
346  case 80:
347  m_nStationsPerBss = 37;
348  channelNum = 42;
349  break;
350  case 160:
351  m_nStationsPerBss = 74;
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  {
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 
381  wifi.SetStandard(WIFI_STANDARD_80211ax);
382  wifi.SetRemoteStationManager("ns3::ConstantRateWifiManager");
383 
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 
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;
460  hdr.SetAddr1(Mac48Address::GetBroadcast());
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 
469  m_triggerTxVector = WifiTxVector(OfdmPhy::GetOfdmRate6Mbps(),
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 
482  m_triggerTxDuration = WifiPhy::CalculateTxDuration(m_trigger->GetSize(),
484  apDev->GetMac()->GetWifiPhy()->GetPhyBand());
485 }
486 
487 void
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
493  Ptr<WifiNetDevice> dev;
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));
504  Simulator::Schedule(i * MicroSeconds(102400),
505  &WifiMac::SetSsid,
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 
518  Simulator::Schedule((m_nStationsPerBss - 1) * MicroSeconds(102400),
519  &ApWifiMac::SetBeaconInterval,
520  mac,
521  MicroSeconds(1024 * 65535));
522  }
523 
524  m_time = (m_nStationsPerBss + 1) * MicroSeconds(102400);
525 
526  Simulator::Schedule(m_time, &WifiPrimaryChannelsTest::CheckAssociation, this);
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));
535  Simulator::Schedule(
536  m_time,
537  &WifiPhy::SetReceiveOkCallback,
538  dev->GetPhy(),
539  MakeCallback(&WifiPrimaryChannelsTest::ReceiveDl, this).Bind(bss, i));
540  }
541  auto dev = DynamicCast<WifiNetDevice>(m_apDevices.Get(bss));
542  Simulator::Schedule(m_time,
543  &WifiPhy::SetReceiveOkCallback,
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);
636  Simulator::Schedule(m_time,
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);
677  Simulator::Schedule(m_time,
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);
725  Simulator::Schedule(m_time,
727  this,
728  ap,
729  txChannelWidth,
730  ruType,
731  nRus);
732  }
733  // check that Trigger Frames and TB PPDUs were correctly received
734  Simulator::Schedule(m_time + m_triggerTxDuration +
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 
758  Simulator::Stop(m_time);
759  Simulator::Run();
760 
761  Simulator::Destroy();
762 }
763 
764 void
765 WifiPrimaryChannelsTest::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();
773  WifiTxVector txVector = WifiTxVector(HePhy::GetHeMcs8(),
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 
796 void
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 
809  WifiTxVector txVector = WifiTxVector(HePhy::GetHeMcs8(),
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  }
841  txVector.SetSigBMode(VhtPhy::GetVhtMcs5());
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 
853 void
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 
877 void
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 
920  WifiTxVector txVector(HePhy::GetHeMcs8(),
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 
961 void
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 
974 void
975 WifiPrimaryChannelsTest::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  {
985  NS_TEST_EXPECT_MSG_EQ(m_received[bss].test(sta),
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
992  NS_TEST_EXPECT_MSG_EQ(m_processed[bss].test(0),
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  {
999  NS_TEST_EXPECT_MSG_EQ(m_processed[bss].test(sta),
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.
1011  if (m_useDistinctBssColors ||
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  {
1021  NS_TEST_EXPECT_MSG_EQ(m_received[bss].test(sta),
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  {
1033  NS_TEST_EXPECT_MSG_EQ(m_received[bss].test(sta),
1034  true,
1035  "Station [" << +bss << "][" << +sta
1036  << "] did not receive the SU frame on primary"
1037  << txChannelWidth << " channel");
1038  NS_TEST_EXPECT_MSG_EQ(m_processed[bss].test(sta),
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 
1052 void
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  {
1077  NS_TEST_EXPECT_MSG_EQ(m_received[bss].test(sta),
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  {
1098  NS_TEST_EXPECT_MSG_EQ(m_processed[bss].test(sta),
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  {
1123  NS_TEST_EXPECT_MSG_EQ(m_received[bss].test(sta),
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  {
1148  NS_TEST_EXPECT_MSG_EQ(m_received[bss].test(sta),
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  {
1159  NS_TEST_EXPECT_MSG_EQ(m_processed[bss].test(sta),
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 
1175 void
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  {
1187  NS_TEST_EXPECT_MSG_EQ(m_received[bss].test(sta),
1188  true,
1189  "Station [" << +bss << "][" << +sta
1190  << "] did not receive the Trigger Frame "
1191  "soliciting a transmission on primary"
1192  << txChannelWidth << " channel");
1193  NS_TEST_EXPECT_MSG_EQ(m_processed[bss].test(sta),
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 
1230 {
1231  public:
1236  ~Wifi20MHzChannelIndicesTest() override = default;
1237 
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 
1260 };
1261 
1263  : TestCase("Check computation of primary and secondary channel indices")
1264 {
1265 }
1266 
1267 void
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 
1329 void
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 
1367 {
1368  public:
1370 };
1371 
1373  : TestSuite("wifi-primary-channels", 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::QUICK);
1377  AddTestCase(new WifiPrimaryChannelsTest(40, false), TestCase::QUICK);
1378 #if 0
1379  // Tests disabled until issue #776 resolved
1380  AddTestCase(new WifiPrimaryChannelsTest(80, true), TestCase::EXTENSIVE);
1381  AddTestCase(new WifiPrimaryChannelsTest(80, false), TestCase::EXTENSIVE);
1382  AddTestCase(new WifiPrimaryChannelsTest(160, true), TestCase::TAKES_FOREVER);
1383  AddTestCase(new WifiPrimaryChannelsTest(160, false), TestCase::TAKES_FOREVER);
1384 #endif
1385  AddTestCase(new Wifi20MHzChannelIndicesTest(), TestCase::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
Headers for Trigger frames.
Definition: ctrl-headers.h:942
void SetType(TriggerFrameType type)
Set the Trigger frame type.
RuType
The different HE Resource Unit (RU) types.
Definition: he-ru.h:41
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:268
Make it easy to create and manage PHY objects for the spectrum model.
The IEEE 802.11 SSID Information Element.
Definition: ssid.h:36
encapsulates test code
Definition: test.h:1060
void AddTestCase(TestCase *testCase, TestDuration duration=QUICK)
Add an individual child TestCase to this test suite.
Definition: test.cc:301
A suite of tests to run.
Definition: test.h:1256
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:105
bool IsZero() const
Exactly equivalent to t == 0.
Definition: nstime.h:315
Hold objects of type std::tuple<Args...>.
Definition: tuple.h:69
void Set(const result_type &value)
Set the stored values.
Definition: tuple.h:318
Hold an unsigned integer type.
Definition: uinteger.h:45
helps to create WifiNetDevice objects
Definition: wifi-helper.h:324
Implements the IEEE 802.11 MAC header.
Mac48Address GetAddr3() const
Return the address in the Address 3 field.
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:458
Ptr< WifiMac > GetMac() const
Ptr< WifiPhy > GetPhy() const
std::tuple< uint8_t, uint16_t, WifiPhyBand, uint8_t > ChannelTuple
Tuple identifying an operating channel.
Definition: wifi-phy.h:891
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
std::size_t GetNMpdus() const
Return the number of MPDUs constituting the PSDU.
Definition: wifi-psdu.cc:327
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:974
#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:144
#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:251
Time MicroSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1350
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1326
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1338
@ 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
NLOHMANN_BASIC_JSON_TPL_DECLARATION std::string to_string(const NLOHMANN_BASIC_JSON_TPL &j)
user-defined to_string function for JSON values
Definition: json.h:25255
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:704
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
mac
Definition: third.py:92
wifi
Definition: third.py:95
mobility
Definition: third.py:105
wifiStaNodes
Definition: third.py:84
phy
Definition: third.py:89
RxSignalInfo structure containing info on the received signal.
Definition: phy-entity.h:69
static WifiPrimaryChannelsTestSuite g_wifiPrimaryChannelsTestSuite
the test suite