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 
41 using namespace ns3;
42 
43 NS_LOG_COMPONENT_DEFINE ("WifiPrimaryChannelsTest");
44 
62 {
63 public:
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 
186 private:
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 
206 WifiPrimaryChannelsTest::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 
217 void
218 WifiPrimaryChannelsTest::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 
237 void
238 WifiPrimaryChannelsTest::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 
266 void
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 
294 void
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:
307  m_nStationsPerBss = 9;
308  channelNum = 36;
309  break;
310  case 40:
311  m_nStationsPerBss = 18;
312  channelNum = 38;
313  break;
314  case 80:
315  m_nStationsPerBss = 37;
316  channelNum = 42;
317  break;
318  case 160:
319  m_nStationsPerBss = 74;
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 
435 void
437 {
438  // schedule association requests at different times
439  Ptr<WifiNetDevice> dev;
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 
669 void
670 WifiPrimaryChannelsTest::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 
690 void
691 WifiPrimaryChannelsTest::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 
724 void
725 WifiPrimaryChannelsTest::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 
741 void
742 WifiPrimaryChannelsTest::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 
795 void
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 
807 void
808 WifiPrimaryChannelsTest::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 
869 void
870 WifiPrimaryChannelsTest::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 
981 void
982 WifiPrimaryChannelsTest::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 {
1026 public:
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.
Definition: ssid.h:105
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:274
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:833
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
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.
@ 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:99
wifi
Definition: third.py:96
mobility
Definition: third.py:108
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