A Discrete-Event Network Simulator
API
tx-duration-test.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2009 CTTC
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 * Authors: Nicola Baldo <nbaldo@cttc.es>
18 * Sébastien Deronne <sebastien.deronne@gmail.com>
19 */
20
21#include "ns3/dsss-phy.h"
22#include "ns3/eht-phy.h" //includes OFDM, HT, VHT and HE
23#include "ns3/erp-ofdm-phy.h"
24#include "ns3/he-ru.h"
25#include "ns3/log.h"
26#include "ns3/packet.h"
27#include "ns3/simulator.h"
28#include "ns3/test.h"
29#include "ns3/wifi-psdu.h"
30#include "ns3/yans-wifi-phy.h"
31
32#include <numeric>
33
34using namespace ns3;
35
36NS_LOG_COMPONENT_DEFINE("InterferenceHelperTxDurationTest");
37
45{
46 public:
48 ~TxDurationTest() override;
49 void DoRun() override;
50
51 private:
66 WifiMode payloadMode,
67 uint16_t channelWidth,
68 uint16_t guardInterval,
69 WifiPreamble preamble,
70 Time knownDuration);
71
85 bool CheckTxDuration(uint32_t size,
86 WifiMode payloadMode,
87 uint16_t channelWidth,
88 uint16_t guardInterval,
89 WifiPreamble preamble,
90 Time knownDuration);
91
105 static bool CheckMuTxDuration(std::list<uint32_t> sizes,
106 std::list<HeMuUserInfo> userInfos,
107 uint16_t channelWidth,
108 uint16_t guardInterval,
109 WifiPreamble preamble,
110 Time knownDuration);
111
126 static Time CalculateTxDurationUsingList(std::list<uint32_t> sizes,
127 std::list<uint16_t> staIds,
128 WifiTxVector txVector,
129 WifiPhyBand band);
130};
131
133 : TestCase("Wifi TX Duration")
134{
135}
136
138{
139}
140
141bool
143 WifiMode payloadMode,
144 uint16_t channelWidth,
145 uint16_t guardInterval,
146 WifiPreamble preamble,
147 Time knownDuration)
148{
149 WifiTxVector txVector;
150 txVector.SetMode(payloadMode);
151 txVector.SetPreambleType(preamble);
152 txVector.SetChannelWidth(channelWidth);
153 txVector.SetGuardInterval(guardInterval);
154 txVector.SetNss(1);
155 txVector.SetStbc(0);
156 txVector.SetNess(0);
157 std::list<WifiPhyBand> testedBands;
158 Ptr<YansWifiPhy> phy = CreateObject<YansWifiPhy>();
159 if (payloadMode.GetModulationClass() >= WIFI_MOD_CLASS_OFDM)
160 {
161 testedBands.push_back(WIFI_PHY_BAND_5GHZ);
162 }
163 if (payloadMode.GetModulationClass() >= WIFI_MOD_CLASS_HE)
164 {
165 testedBands.push_back(WIFI_PHY_BAND_6GHZ);
166 }
167 if (payloadMode.GetModulationClass() != WIFI_MOD_CLASS_VHT)
168 {
169 testedBands.push_back(WIFI_PHY_BAND_2_4GHZ);
170 }
171 for (auto& testedBand : testedBands)
172 {
173 if ((testedBand == WIFI_PHY_BAND_2_4GHZ) &&
174 (payloadMode.GetModulationClass() >= WIFI_MOD_CLASS_OFDM))
175 {
176 knownDuration +=
177 MicroSeconds(6); // 2.4 GHz band should be at the end of the bands to test
178 }
179 Time calculatedDuration = phy->GetPayloadDuration(size, txVector, testedBand);
180 if (calculatedDuration != knownDuration)
181 {
182 std::cerr << "size=" << size << " band=" << testedBand << " mode=" << payloadMode
183 << " channelWidth=" << channelWidth << " guardInterval=" << guardInterval
184 << " datarate=" << payloadMode.GetDataRate(channelWidth, guardInterval, 1)
185 << " known=" << knownDuration << " calculated=" << calculatedDuration
186 << std::endl;
187 return false;
188 }
189 }
190 return true;
191}
192
193bool
195 WifiMode payloadMode,
196 uint16_t channelWidth,
197 uint16_t guardInterval,
198 WifiPreamble preamble,
199 Time knownDuration)
200{
201 WifiTxVector txVector;
202 txVector.SetMode(payloadMode);
203 txVector.SetPreambleType(preamble);
204 txVector.SetChannelWidth(channelWidth);
205 txVector.SetGuardInterval(guardInterval);
206 txVector.SetNss(1);
207 txVector.SetStbc(0);
208 txVector.SetNess(0);
209 std::list<WifiPhyBand> testedBands;
210 Ptr<YansWifiPhy> phy = CreateObject<YansWifiPhy>();
211 if (payloadMode.GetModulationClass() >= WIFI_MOD_CLASS_OFDM)
212 {
213 testedBands.push_back(WIFI_PHY_BAND_5GHZ);
214 }
215 if (payloadMode.GetModulationClass() >= WIFI_MOD_CLASS_HE)
216 {
217 testedBands.push_back(WIFI_PHY_BAND_6GHZ);
218 }
219 if (payloadMode.GetModulationClass() != WIFI_MOD_CLASS_VHT)
220 {
221 testedBands.push_back(WIFI_PHY_BAND_2_4GHZ);
222 }
223 for (auto& testedBand : testedBands)
224 {
225 if ((testedBand == WIFI_PHY_BAND_2_4GHZ) &&
226 (payloadMode.GetModulationClass() >= WIFI_MOD_CLASS_OFDM))
227 {
228 knownDuration +=
229 MicroSeconds(6); // 2.4 GHz band should be at the end of the bands to test
230 }
231 Time calculatedDuration = phy->CalculateTxDuration(size, txVector, testedBand);
232 Time calculatedDurationUsingList =
233 CalculateTxDurationUsingList(std::list<uint32_t>{size},
234 std::list<uint16_t>{SU_STA_ID},
235 txVector,
236 testedBand);
237 if (calculatedDuration != knownDuration ||
238 calculatedDuration != calculatedDurationUsingList)
239 {
240 std::cerr << "size=" << size << " band=" << testedBand << " mode=" << payloadMode
241 << " channelWidth=" << +channelWidth << " guardInterval=" << guardInterval
242 << " datarate=" << payloadMode.GetDataRate(channelWidth, guardInterval, 1)
243 << " preamble=" << preamble << " known=" << knownDuration
244 << " calculated=" << calculatedDuration
245 << " calculatedUsingList=" << calculatedDurationUsingList << std::endl;
246 return false;
247 }
248 }
249 return true;
250}
251
252bool
253TxDurationTest::CheckMuTxDuration(std::list<uint32_t> sizes,
254 std::list<HeMuUserInfo> userInfos,
255 uint16_t channelWidth,
256 uint16_t guardInterval,
257 WifiPreamble preamble,
258 Time knownDuration)
259{
260 NS_ASSERT(sizes.size() == userInfos.size() && sizes.size() > 1);
262 channelWidth < std::accumulate(
263 std::begin(userInfos),
264 std::end(userInfos),
265 0,
266 [](const uint16_t prevBw, const HeMuUserInfo& info) {
267 return prevBw + HeRu::GetBandwidth(info.ru.GetRuType());
268 }),
269 "Cannot accommodate all the RUs in the provided band"); // MU-MIMO (for which allocations
270 // use the same RU) is not supported
271 WifiTxVector txVector;
272 txVector.SetPreambleType(preamble);
273 txVector.SetChannelWidth(channelWidth);
274 txVector.SetGuardInterval(guardInterval);
275 txVector.SetStbc(0);
276 txVector.SetNess(0);
277 std::list<uint16_t> staIds;
278
279 uint16_t staId = 1;
280 for (const auto& userInfo : userInfos)
281 {
282 txVector.SetHeMuUserInfo(staId, userInfo);
283 staIds.push_back(staId++);
284 }
285 txVector.SetSigBMode(VhtPhy::GetVhtMcs0());
286 txVector.SetRuAllocation({192, 192});
287
288 Ptr<YansWifiPhy> phy = CreateObject<YansWifiPhy>();
289 std::list<WifiPhyBand> testedBands{
292 WIFI_PHY_BAND_2_4GHZ}; // Durations vary depending on frequency; test also 2.4 GHz (bug
293 // 1971)
294 for (auto& testedBand : testedBands)
295 {
296 if (testedBand == WIFI_PHY_BAND_2_4GHZ)
297 {
298 knownDuration +=
299 MicroSeconds(6); // 2.4 GHz band should be at the end of the bands to test
300 }
301 Time calculatedDuration = NanoSeconds(0);
302 uint32_t longuestSize = 0;
303 auto iterStaId = staIds.begin();
304 for (auto& size : sizes)
305 {
306 Time ppduDurationForSta =
307 phy->CalculateTxDuration(size, txVector, testedBand, *iterStaId);
308 if (ppduDurationForSta > calculatedDuration)
309 {
310 calculatedDuration = ppduDurationForSta;
311 staId = *iterStaId;
312 longuestSize = size;
313 }
314 ++iterStaId;
315 }
316 Time calculatedDurationUsingList =
317 CalculateTxDurationUsingList(sizes, staIds, txVector, testedBand);
318 if (calculatedDuration != knownDuration ||
319 calculatedDuration != calculatedDurationUsingList)
320 {
321 std::cerr << "size=" << longuestSize << " band=" << testedBand << " staId=" << staId
322 << " nss=" << +txVector.GetNss(staId) << " mode=" << txVector.GetMode(staId)
323 << " channelWidth=" << channelWidth << " guardInterval=" << guardInterval
324 << " datarate="
325 << txVector.GetMode(staId).GetDataRate(channelWidth,
326 guardInterval,
327 txVector.GetNss(staId))
328 << " known=" << knownDuration << " calculated=" << calculatedDuration
329 << " calculatedUsingList=" << calculatedDurationUsingList << std::endl;
330 return false;
331 }
332 }
333 return true;
334}
335
336Time
338 std::list<uint16_t> staIds,
339 WifiTxVector txVector,
340 WifiPhyBand band)
341{
342 NS_ASSERT(sizes.size() == staIds.size());
343 WifiConstPsduMap psduMap;
344 auto itStaId = staIds.begin();
345 WifiMacHeader hdr;
346 hdr.SetType(WIFI_MAC_CTL_ACK); // so that size may not be empty while being as short as possible
347 for (auto& size : sizes)
348 {
349 // MAC header and FCS are to deduce from size
350 psduMap[*itStaId++] =
351 Create<WifiPsdu>(Create<Packet>(size - hdr.GetSerializedSize() - 4), hdr);
352 }
353 return WifiPhy::CalculateTxDuration(psduMap, txVector, band);
354}
355
356void
358{
359 bool retval = true;
360
361 // IEEE Std 802.11-2007 Table 18-2 "Example of LENGTH calculations for CCK"
362 retval = retval &&
364 DsssPhy::GetDsssRate11Mbps(),
365 22,
366 800,
368 MicroSeconds(744)) &&
370 DsssPhy::GetDsssRate11Mbps(),
371 22,
372 800,
374 MicroSeconds(745)) &&
376 DsssPhy::GetDsssRate11Mbps(),
377 22,
378 800,
380 MicroSeconds(746)) &&
382 DsssPhy::GetDsssRate11Mbps(),
383 22,
384 800,
386 MicroSeconds(747));
387
388 NS_TEST_EXPECT_MSG_EQ(retval, true, "an 802.11b CCK duration failed");
389
390 // Similar, but we add PHY preamble and header durations
391 // and we test different rates.
392 // The payload durations for modes other than 11mbb have been
393 // calculated by hand according to IEEE Std 802.11-2007 18.2.3.5
394 retval = retval &&
395 CheckTxDuration(1023,
396 DsssPhy::GetDsssRate11Mbps(),
397 22,
398 800,
400 MicroSeconds(744 + 96)) &&
401 CheckTxDuration(1024,
402 DsssPhy::GetDsssRate11Mbps(),
403 22,
404 800,
406 MicroSeconds(745 + 96)) &&
407 CheckTxDuration(1025,
408 DsssPhy::GetDsssRate11Mbps(),
409 22,
410 800,
412 MicroSeconds(746 + 96)) &&
413 CheckTxDuration(1026,
414 DsssPhy::GetDsssRate11Mbps(),
415 22,
416 800,
418 MicroSeconds(747 + 96)) &&
419 CheckTxDuration(1023,
420 DsssPhy::GetDsssRate11Mbps(),
421 22,
422 800,
424 MicroSeconds(744 + 192)) &&
425 CheckTxDuration(1024,
426 DsssPhy::GetDsssRate11Mbps(),
427 22,
428 800,
430 MicroSeconds(745 + 192)) &&
431 CheckTxDuration(1025,
432 DsssPhy::GetDsssRate11Mbps(),
433 22,
434 800,
436 MicroSeconds(746 + 192)) &&
437 CheckTxDuration(1026,
438 DsssPhy::GetDsssRate11Mbps(),
439 22,
440 800,
442 MicroSeconds(747 + 192)) &&
443 CheckTxDuration(1023,
444 DsssPhy::GetDsssRate5_5Mbps(),
445 22,
446 800,
448 MicroSeconds(1488 + 96)) &&
449 CheckTxDuration(1024,
450 DsssPhy::GetDsssRate5_5Mbps(),
451 22,
452 800,
454 MicroSeconds(1490 + 96)) &&
455 CheckTxDuration(1025,
456 DsssPhy::GetDsssRate5_5Mbps(),
457 22,
458 800,
460 MicroSeconds(1491 + 96)) &&
461 CheckTxDuration(1026,
462 DsssPhy::GetDsssRate5_5Mbps(),
463 22,
464 800,
466 MicroSeconds(1493 + 96)) &&
467 CheckTxDuration(1023,
468 DsssPhy::GetDsssRate5_5Mbps(),
469 22,
470 800,
472 MicroSeconds(1488 + 192)) &&
473 CheckTxDuration(1024,
474 DsssPhy::GetDsssRate5_5Mbps(),
475 22,
476 800,
478 MicroSeconds(1490 + 192)) &&
479 CheckTxDuration(1025,
480 DsssPhy::GetDsssRate5_5Mbps(),
481 22,
482 800,
484 MicroSeconds(1491 + 192)) &&
485 CheckTxDuration(1026,
486 DsssPhy::GetDsssRate5_5Mbps(),
487 22,
488 800,
490 MicroSeconds(1493 + 192)) &&
491 CheckTxDuration(1023,
492 DsssPhy::GetDsssRate2Mbps(),
493 22,
494 800,
496 MicroSeconds(4092 + 96)) &&
497 CheckTxDuration(1024,
498 DsssPhy::GetDsssRate2Mbps(),
499 22,
500 800,
502 MicroSeconds(4096 + 96)) &&
503 CheckTxDuration(1025,
504 DsssPhy::GetDsssRate2Mbps(),
505 22,
506 800,
508 MicroSeconds(4100 + 96)) &&
509 CheckTxDuration(1026,
510 DsssPhy::GetDsssRate2Mbps(),
511 22,
512 800,
514 MicroSeconds(4104 + 96)) &&
515 CheckTxDuration(1023,
516 DsssPhy::GetDsssRate2Mbps(),
517 22,
518 800,
520 MicroSeconds(4092 + 192)) &&
521 CheckTxDuration(1024,
522 DsssPhy::GetDsssRate2Mbps(),
523 22,
524 800,
526 MicroSeconds(4096 + 192)) &&
527 CheckTxDuration(1025,
528 DsssPhy::GetDsssRate2Mbps(),
529 22,
530 800,
532 MicroSeconds(4100 + 192)) &&
533 CheckTxDuration(1026,
534 DsssPhy::GetDsssRate2Mbps(),
535 22,
536 800,
538 MicroSeconds(4104 + 192)) &&
539 CheckTxDuration(1023,
540 DsssPhy::GetDsssRate1Mbps(),
541 22,
542 800,
544 MicroSeconds(8184 + 192)) &&
545 CheckTxDuration(1024,
546 DsssPhy::GetDsssRate1Mbps(),
547 22,
548 800,
550 MicroSeconds(8192 + 192)) &&
551 CheckTxDuration(1025,
552 DsssPhy::GetDsssRate1Mbps(),
553 22,
554 800,
556 MicroSeconds(8200 + 192)) &&
557 CheckTxDuration(1026,
558 DsssPhy::GetDsssRate1Mbps(),
559 22,
560 800,
562 MicroSeconds(8208 + 192)) &&
563 CheckTxDuration(1023,
564 DsssPhy::GetDsssRate1Mbps(),
565 22,
566 800,
568 MicroSeconds(8184 + 192)) &&
569 CheckTxDuration(1024,
570 DsssPhy::GetDsssRate1Mbps(),
571 22,
572 800,
574 MicroSeconds(8192 + 192)) &&
575 CheckTxDuration(1025,
576 DsssPhy::GetDsssRate1Mbps(),
577 22,
578 800,
580 MicroSeconds(8200 + 192)) &&
581 CheckTxDuration(1026,
582 DsssPhy::GetDsssRate1Mbps(),
583 22,
584 800,
586 MicroSeconds(8208 + 192));
587
588 // values from http://mailman.isi.edu/pipermail/ns-developers/2009-July/006226.html
589 retval = retval && CheckTxDuration(14,
590 DsssPhy::GetDsssRate1Mbps(),
591 22,
592 800,
594 MicroSeconds(304));
595
596 // values from http://www.oreillynet.com/pub/a/wireless/2003/08/08/wireless_throughput.html
597 retval = retval &&
598 CheckTxDuration(1536,
599 DsssPhy::GetDsssRate11Mbps(),
600 22,
601 800,
603 MicroSeconds(1310)) &&
605 DsssPhy::GetDsssRate11Mbps(),
606 22,
607 800,
609 MicroSeconds(248)) &&
611 DsssPhy::GetDsssRate11Mbps(),
612 22,
613 800,
615 MicroSeconds(203));
616
617 NS_TEST_EXPECT_MSG_EQ(retval, true, "an 802.11b duration failed");
618
619 // 802.11a durations
620 // values from http://www.oreillynet.com/pub/a/wireless/2003/08/08/wireless_throughput.html
621 retval = retval &&
622 CheckTxDuration(1536,
623 OfdmPhy::GetOfdmRate54Mbps(),
624 20,
625 800,
627 MicroSeconds(248)) &&
629 OfdmPhy::GetOfdmRate54Mbps(),
630 20,
631 800,
633 MicroSeconds(32)) &&
635 OfdmPhy::GetOfdmRate54Mbps(),
636 20,
637 800,
639 MicroSeconds(24));
640
641 NS_TEST_EXPECT_MSG_EQ(retval, true, "an 802.11a duration failed");
642
643 // 802.11g durations are same as 802.11a durations but with 6 us signal extension
644 retval = retval &&
645 CheckTxDuration(1536,
646 ErpOfdmPhy::GetErpOfdmRate54Mbps(),
647 20,
648 800,
650 MicroSeconds(254)) &&
652 ErpOfdmPhy::GetErpOfdmRate54Mbps(),
653 20,
654 800,
656 MicroSeconds(38)) &&
658 ErpOfdmPhy::GetErpOfdmRate54Mbps(),
659 20,
660 800,
662 MicroSeconds(30));
663
664 NS_TEST_EXPECT_MSG_EQ(retval, true, "an 802.11g duration failed");
665
666 // 802.11n durations
667 retval =
668 retval &&
669 CheckTxDuration(1536,
670 HtPhy::GetHtMcs7(),
671 20,
672 800,
674 MicroSeconds(228)) &&
675 CheckTxDuration(76, HtPhy::GetHtMcs7(), 20, 800, WIFI_PREAMBLE_HT_MF, MicroSeconds(48)) &&
676 CheckTxDuration(14, HtPhy::GetHtMcs7(), 20, 800, WIFI_PREAMBLE_HT_MF, MicroSeconds(40)) &&
677 CheckTxDuration(1536,
678 HtPhy::GetHtMcs0(),
679 20,
680 400,
682 NanoSeconds(1742400)) &&
683 CheckTxDuration(76, HtPhy::GetHtMcs0(), 20, 400, WIFI_PREAMBLE_HT_MF, MicroSeconds(126)) &&
684 CheckTxDuration(14, HtPhy::GetHtMcs0(), 20, 400, WIFI_PREAMBLE_HT_MF, NanoSeconds(57600)) &&
685 CheckTxDuration(1536,
686 HtPhy::GetHtMcs6(),
687 20,
688 400,
690 NanoSeconds(226800)) &&
691 CheckTxDuration(76, HtPhy::GetHtMcs6(), 20, 400, WIFI_PREAMBLE_HT_MF, NanoSeconds(46800)) &&
692 CheckTxDuration(14, HtPhy::GetHtMcs6(), 20, 400, WIFI_PREAMBLE_HT_MF, NanoSeconds(39600)) &&
693 CheckTxDuration(1536,
694 HtPhy::GetHtMcs7(),
695 40,
696 800,
698 MicroSeconds(128)) &&
699 CheckTxDuration(76, HtPhy::GetHtMcs7(), 40, 800, WIFI_PREAMBLE_HT_MF, MicroSeconds(44)) &&
700 CheckTxDuration(14, HtPhy::GetHtMcs7(), 40, 800, WIFI_PREAMBLE_HT_MF, MicroSeconds(40)) &&
701 CheckTxDuration(1536,
702 HtPhy::GetHtMcs7(),
703 40,
704 400,
706 NanoSeconds(118800)) &&
707 CheckTxDuration(76, HtPhy::GetHtMcs7(), 40, 400, WIFI_PREAMBLE_HT_MF, NanoSeconds(43200)) &&
708 CheckTxDuration(14, HtPhy::GetHtMcs7(), 40, 400, WIFI_PREAMBLE_HT_MF, NanoSeconds(39600));
709
710 NS_TEST_EXPECT_MSG_EQ(retval, true, "an 802.11n duration failed");
711
712 // 802.11ac durations
713 retval = retval &&
714 CheckTxDuration(1536,
715 VhtPhy::GetVhtMcs8(),
716 20,
717 800,
719 MicroSeconds(196)) &&
721 VhtPhy::GetVhtMcs8(),
722 20,
723 800,
725 MicroSeconds(48)) &&
727 VhtPhy::GetVhtMcs8(),
728 20,
729 800,
731 MicroSeconds(40)) &&
732 CheckTxDuration(1536,
733 VhtPhy::GetVhtMcs8(),
734 20,
735 400,
737 MicroSeconds(180)) &&
739 VhtPhy::GetVhtMcs8(),
740 20,
741 400,
743 NanoSeconds(46800)) &&
745 VhtPhy::GetVhtMcs8(),
746 20,
747 400,
749 NanoSeconds(39600)) &&
750 CheckTxDuration(1536,
751 VhtPhy::GetVhtMcs9(),
752 40,
753 800,
755 MicroSeconds(108)) &&
757 VhtPhy::GetVhtMcs9(),
758 40,
759 800,
761 MicroSeconds(40)) &&
763 VhtPhy::GetVhtMcs9(),
764 40,
765 800,
767 MicroSeconds(40)) &&
768 CheckTxDuration(1536,
769 VhtPhy::GetVhtMcs9(),
770 40,
771 400,
773 NanoSeconds(100800)) &&
775 VhtPhy::GetVhtMcs9(),
776 40,
777 400,
779 NanoSeconds(39600)) &&
781 VhtPhy::GetVhtMcs9(),
782 40,
783 400,
785 NanoSeconds(39600)) &&
786 CheckTxDuration(1536,
787 VhtPhy::GetVhtMcs0(),
788 80,
789 800,
791 MicroSeconds(460)) &&
793 VhtPhy::GetVhtMcs0(),
794 80,
795 800,
797 MicroSeconds(60)) &&
799 VhtPhy::GetVhtMcs0(),
800 80,
801 800,
803 MicroSeconds(44)) &&
804 CheckTxDuration(1536,
805 VhtPhy::GetVhtMcs0(),
806 80,
807 400,
809 NanoSeconds(417600)) &&
811 VhtPhy::GetVhtMcs0(),
812 80,
813 400,
815 NanoSeconds(57600)) &&
817 VhtPhy::GetVhtMcs0(),
818 80,
819 400,
821 NanoSeconds(43200)) &&
822 CheckTxDuration(1536,
823 VhtPhy::GetVhtMcs9(),
824 80,
825 800,
827 MicroSeconds(68)) &&
829 VhtPhy::GetVhtMcs9(),
830 80,
831 800,
833 MicroSeconds(40)) &&
835 VhtPhy::GetVhtMcs9(),
836 80,
837 800,
839 MicroSeconds(40)) &&
840 CheckTxDuration(1536,
841 VhtPhy::GetVhtMcs9(),
842 80,
843 400,
845 NanoSeconds(64800)) &&
847 VhtPhy::GetVhtMcs9(),
848 80,
849 400,
851 NanoSeconds(39600)) &&
853 VhtPhy::GetVhtMcs9(),
854 80,
855 400,
857 NanoSeconds(39600)) &&
858 CheckTxDuration(1536,
859 VhtPhy::GetVhtMcs8(),
860 160,
861 800,
863 MicroSeconds(56)) &&
865 VhtPhy::GetVhtMcs8(),
866 160,
867 800,
869 MicroSeconds(40)) &&
871 VhtPhy::GetVhtMcs8(),
872 160,
873 800,
875 MicroSeconds(40)) &&
876 CheckTxDuration(1536,
877 VhtPhy::GetVhtMcs8(),
878 160,
879 400,
881 MicroSeconds(54)) &&
883 VhtPhy::GetVhtMcs8(),
884 160,
885 400,
887 NanoSeconds(39600)) &&
889 VhtPhy::GetVhtMcs8(),
890 160,
891 400,
893 NanoSeconds(39600));
894
895 NS_TEST_EXPECT_MSG_EQ(retval, true, "an 802.11ac duration failed");
896
897 // 802.11ax SU durations
898 retval =
899 retval &&
900 CheckTxDuration(1536,
901 HePhy::GetHeMcs0(),
902 20,
903 800,
905 NanoSeconds(1485600)) &&
907 HePhy::GetHeMcs0(),
908 20,
909 800,
911 NanoSeconds(125600)) &&
912 CheckTxDuration(14, HePhy::GetHeMcs0(), 20, 800, WIFI_PREAMBLE_HE_SU, NanoSeconds(71200)) &&
913 CheckTxDuration(1536,
914 HePhy::GetHeMcs0(),
915 40,
916 800,
918 NanoSeconds(764800)) &&
919 CheckTxDuration(76, HePhy::GetHeMcs0(), 40, 800, WIFI_PREAMBLE_HE_SU, NanoSeconds(84800)) &&
920 CheckTxDuration(14, HePhy::GetHeMcs0(), 40, 800, WIFI_PREAMBLE_HE_SU, NanoSeconds(57600)) &&
921 CheckTxDuration(1536,
922 HePhy::GetHeMcs0(),
923 80,
924 800,
926 NanoSeconds(397600)) &&
927 CheckTxDuration(76, HePhy::GetHeMcs0(), 80, 800, WIFI_PREAMBLE_HE_SU, NanoSeconds(71200)) &&
928 CheckTxDuration(14, HePhy::GetHeMcs0(), 80, 800, WIFI_PREAMBLE_HE_SU, NanoSeconds(57600)) &&
929 CheckTxDuration(1536,
930 HePhy::GetHeMcs0(),
931 160,
932 800,
934 NanoSeconds(220800)) &&
936 HePhy::GetHeMcs0(),
937 160,
938 800,
940 NanoSeconds(57600)) &&
942 HePhy::GetHeMcs0(),
943 160,
944 800,
946 NanoSeconds(57600)) &&
947 CheckTxDuration(1536,
948 HePhy::GetHeMcs0(),
949 20,
950 1600,
952 NanoSeconds(1570400)) &&
954 HePhy::GetHeMcs0(),
955 20,
956 1600,
958 NanoSeconds(130400)) &&
960 HePhy::GetHeMcs0(),
961 20,
962 1600,
964 NanoSeconds(72800)) &&
965 CheckTxDuration(1536,
966 HePhy::GetHeMcs0(),
967 40,
968 1600,
970 NanoSeconds(807200)) &&
972 HePhy::GetHeMcs0(),
973 40,
974 1600,
976 NanoSeconds(87200)) &&
978 HePhy::GetHeMcs0(),
979 40,
980 1600,
982 NanoSeconds(58400)) &&
983 CheckTxDuration(1536,
984 HePhy::GetHeMcs0(),
985 80,
986 1600,
988 NanoSeconds(418400)) &&
990 HePhy::GetHeMcs0(),
991 80,
992 1600,
994 NanoSeconds(72800)) &&
996 HePhy::GetHeMcs0(),
997 80,
998 1600,
1000 NanoSeconds(58400)) &&
1001 CheckTxDuration(1536,
1002 HePhy::GetHeMcs0(),
1003 160,
1004 1600,
1006 NanoSeconds(231200)) &&
1007 CheckTxDuration(76,
1008 HePhy::GetHeMcs0(),
1009 160,
1010 1600,
1012 NanoSeconds(58400)) &&
1013 CheckTxDuration(14,
1014 HePhy::GetHeMcs0(),
1015 160,
1016 1600,
1018 NanoSeconds(58400)) &&
1019 CheckTxDuration(1536,
1020 HePhy::GetHeMcs0(),
1021 20,
1022 3200,
1024 MicroSeconds(1740)) &&
1025 CheckTxDuration(76, HePhy::GetHeMcs0(), 20, 3200, WIFI_PREAMBLE_HE_SU, MicroSeconds(140)) &&
1026 CheckTxDuration(14, HePhy::GetHeMcs0(), 20, 3200, WIFI_PREAMBLE_HE_SU, MicroSeconds(76)) &&
1027 CheckTxDuration(1536,
1028 HePhy::GetHeMcs0(),
1029 40,
1030 3200,
1032 MicroSeconds(892)) &&
1033 CheckTxDuration(76, HePhy::GetHeMcs0(), 40, 3200, WIFI_PREAMBLE_HE_SU, MicroSeconds(92)) &&
1034 CheckTxDuration(14, HePhy::GetHeMcs0(), 40, 3200, WIFI_PREAMBLE_HE_SU, MicroSeconds(60)) &&
1035 CheckTxDuration(1536,
1036 HePhy::GetHeMcs0(),
1037 80,
1038 3200,
1040 MicroSeconds(460)) &&
1041 CheckTxDuration(76, HePhy::GetHeMcs0(), 80, 3200, WIFI_PREAMBLE_HE_SU, MicroSeconds(76)) &&
1042 CheckTxDuration(14, HePhy::GetHeMcs0(), 80, 3200, WIFI_PREAMBLE_HE_SU, MicroSeconds(60)) &&
1043 CheckTxDuration(1536,
1044 HePhy::GetHeMcs0(),
1045 160,
1046 3200,
1048 MicroSeconds(252)) &&
1049 CheckTxDuration(76, HePhy::GetHeMcs0(), 160, 3200, WIFI_PREAMBLE_HE_SU, MicroSeconds(60)) &&
1050 CheckTxDuration(14, HePhy::GetHeMcs0(), 160, 3200, WIFI_PREAMBLE_HE_SU, MicroSeconds(60)) &&
1051 CheckTxDuration(1536,
1052 HePhy::GetHeMcs11(),
1053 20,
1054 800,
1056 NanoSeconds(139200)) &&
1057 CheckTxDuration(76,
1058 HePhy::GetHeMcs11(),
1059 20,
1060 800,
1062 NanoSeconds(57600)) &&
1063 CheckTxDuration(14,
1064 HePhy::GetHeMcs11(),
1065 20,
1066 800,
1068 NanoSeconds(57600)) &&
1069 CheckTxDuration(1536,
1070 HePhy::GetHeMcs11(),
1071 40,
1072 800,
1074 NanoSeconds(98400)) &&
1075 CheckTxDuration(76,
1076 HePhy::GetHeMcs11(),
1077 40,
1078 800,
1080 NanoSeconds(57600)) &&
1081 CheckTxDuration(14,
1082 HePhy::GetHeMcs11(),
1083 40,
1084 800,
1086 NanoSeconds(57600)) &&
1087 CheckTxDuration(1536,
1088 HePhy::GetHeMcs11(),
1089 80,
1090 800,
1092 NanoSeconds(71200)) &&
1093 CheckTxDuration(76,
1094 HePhy::GetHeMcs11(),
1095 80,
1096 800,
1098 NanoSeconds(57600)) &&
1099 CheckTxDuration(14,
1100 HePhy::GetHeMcs11(),
1101 80,
1102 800,
1104 NanoSeconds(57600)) &&
1105 CheckTxDuration(1536,
1106 HePhy::GetHeMcs11(),
1107 160,
1108 800,
1110 NanoSeconds(57600)) &&
1111 CheckTxDuration(76,
1112 HePhy::GetHeMcs11(),
1113 160,
1114 800,
1116 NanoSeconds(57600)) &&
1117 CheckTxDuration(14,
1118 HePhy::GetHeMcs11(),
1119 160,
1120 800,
1122 NanoSeconds(57600)) &&
1123 CheckTxDuration(1536,
1124 HePhy::GetHeMcs11(),
1125 20,
1126 1600,
1128 NanoSeconds(144800)) &&
1129 CheckTxDuration(76,
1130 HePhy::GetHeMcs11(),
1131 20,
1132 1600,
1134 NanoSeconds(58400)) &&
1135 CheckTxDuration(14,
1136 HePhy::GetHeMcs11(),
1137 20,
1138 1600,
1140 NanoSeconds(58400)) &&
1141 CheckTxDuration(1536,
1142 HePhy::GetHeMcs11(),
1143 40,
1144 1600,
1146 NanoSeconds(101600)) &&
1147 CheckTxDuration(76,
1148 HePhy::GetHeMcs11(),
1149 40,
1150 1600,
1152 NanoSeconds(58400)) &&
1153 CheckTxDuration(14,
1154 HePhy::GetHeMcs11(),
1155 40,
1156 1600,
1158 NanoSeconds(58400)) &&
1159 CheckTxDuration(1536,
1160 HePhy::GetHeMcs11(),
1161 80,
1162 1600,
1164 NanoSeconds(72800)) &&
1165 CheckTxDuration(76,
1166 HePhy::GetHeMcs11(),
1167 80,
1168 1600,
1170 NanoSeconds(58400)) &&
1171 CheckTxDuration(14,
1172 HePhy::GetHeMcs11(),
1173 80,
1174 1600,
1176 NanoSeconds(58400)) &&
1177 CheckTxDuration(1536,
1178 HePhy::GetHeMcs11(),
1179 160,
1180 1600,
1182 NanoSeconds(58400)) &&
1183 CheckTxDuration(76,
1184 HePhy::GetHeMcs11(),
1185 160,
1186 1600,
1188 NanoSeconds(58400)) &&
1189 CheckTxDuration(14,
1190 HePhy::GetHeMcs11(),
1191 160,
1192 1600,
1194 NanoSeconds(58400)) &&
1195 CheckTxDuration(1536,
1196 HePhy::GetHeMcs11(),
1197 20,
1198 3200,
1200 MicroSeconds(156)) &&
1201 CheckTxDuration(76, HePhy::GetHeMcs11(), 20, 3200, WIFI_PREAMBLE_HE_SU, MicroSeconds(60)) &&
1202 CheckTxDuration(14, HePhy::GetHeMcs11(), 20, 3200, WIFI_PREAMBLE_HE_SU, MicroSeconds(60)) &&
1203 CheckTxDuration(1536,
1204 HePhy::GetHeMcs11(),
1205 40,
1206 3200,
1208 MicroSeconds(108)) &&
1209 CheckTxDuration(76, HePhy::GetHeMcs11(), 40, 3200, WIFI_PREAMBLE_HE_SU, MicroSeconds(60)) &&
1210 CheckTxDuration(14, HePhy::GetHeMcs11(), 40, 3200, WIFI_PREAMBLE_HE_SU, MicroSeconds(60)) &&
1211 CheckTxDuration(1536,
1212 HePhy::GetHeMcs11(),
1213 80,
1214 3200,
1216 MicroSeconds(76)) &&
1217 CheckTxDuration(76, HePhy::GetHeMcs11(), 80, 3200, WIFI_PREAMBLE_HE_SU, MicroSeconds(60)) &&
1218 CheckTxDuration(14, HePhy::GetHeMcs11(), 80, 3200, WIFI_PREAMBLE_HE_SU, MicroSeconds(60)) &&
1219 CheckTxDuration(1536,
1220 HePhy::GetHeMcs11(),
1221 160,
1222 3200,
1224 MicroSeconds(60)) &&
1225 CheckTxDuration(76,
1226 HePhy::GetHeMcs11(),
1227 160,
1228 3200,
1230 MicroSeconds(60)) &&
1231 CheckTxDuration(14, HePhy::GetHeMcs11(), 160, 3200, WIFI_PREAMBLE_HE_SU, MicroSeconds(60));
1232
1233 NS_TEST_EXPECT_MSG_EQ(retval, true, "an 802.11ax SU duration failed");
1234
1235 // 802.11ax MU durations
1236 retval = retval &&
1238 std::list<uint32_t>{1536, 1536},
1239 std::list<HeMuUserInfo>{{{HeRu::RU_242_TONE, 1, true}, HePhy::GetHeMcs0(), 1},
1240 {{HeRu::RU_242_TONE, 2, true}, HePhy::GetHeMcs0(), 1}},
1241 40,
1242 800,
1245 1493600)) // equivalent to HE_SU for 20 MHz with 2 extra HE-SIG-B (i.e. 8 us)
1247 std::list<uint32_t>{1536, 1536},
1248 std::list<HeMuUserInfo>{{{HeRu::RU_242_TONE, 1, true}, HePhy::GetHeMcs1(), 1},
1249 {{HeRu::RU_242_TONE, 2, true}, HePhy::GetHeMcs0(), 1}},
1250 40,
1251 800,
1253 NanoSeconds(1493600)) // shouldn't change if first PSDU is shorter
1255 std::list<uint32_t>{1536, 76},
1256 std::list<HeMuUserInfo>{{{HeRu::RU_242_TONE, 1, true}, HePhy::GetHeMcs0(), 1},
1257 {{HeRu::RU_242_TONE, 2, true}, HePhy::GetHeMcs0(), 1}},
1258 40,
1259 800,
1261 NanoSeconds(1493600));
1262
1263 NS_TEST_EXPECT_MSG_EQ(retval, true, "an 802.11ax MU duration failed");
1264
1265 // 802.11be MU durations
1266 retval =
1267 retval &&
1269 std::list<uint32_t>{1536, 1536},
1270 std::list<HeMuUserInfo>{{{HeRu::RU_242_TONE, 1, true}, EhtPhy::GetEhtMcs0(), 1},
1271 {{HeRu::RU_242_TONE, 2, true}, EhtPhy::GetEhtMcs0(), 1}},
1272 40,
1273 800,
1275 NanoSeconds(1493600)) // equivalent to 802.11ax MU
1277 std::list<uint32_t>{1536, 1536},
1278 std::list<HeMuUserInfo>{{{HeRu::RU_242_TONE, 1, true}, EhtPhy::GetEhtMcs1(), 1},
1279 {{HeRu::RU_242_TONE, 2, true}, EhtPhy::GetEhtMcs0(), 1}},
1280 40,
1281 800,
1283 NanoSeconds(1493600)) // shouldn't change if first PSDU is shorter
1285 std::list<uint32_t>{1536, 76},
1286 std::list<HeMuUserInfo>{{{HeRu::RU_242_TONE, 1, true}, EhtPhy::GetEhtMcs0(), 1},
1287 {{HeRu::RU_242_TONE, 2, true}, EhtPhy::GetEhtMcs0(), 1}},
1288 40,
1289 800,
1291 NanoSeconds(1493600));
1292
1293 NS_TEST_EXPECT_MSG_EQ(retval, true, "an 802.11be MU duration failed");
1294
1295 Simulator::Destroy();
1296}
1297
1305{
1306 public:
1308 ~HeSigBDurationTest() override;
1309 void DoRun() override;
1310
1311 private:
1320 static WifiTxVector BuildTxVector(uint16_t bw, std::list<HeMuUserInfo> userInfos);
1321};
1322
1324 : TestCase("Check HE-SIG-B duration computation")
1325{
1326}
1327
1329{
1330}
1331
1333HeSigBDurationTest::BuildTxVector(uint16_t bw, std::list<HeMuUserInfo> userInfos)
1334{
1335 WifiTxVector txVector;
1337 txVector.SetChannelWidth(bw);
1338 txVector.SetGuardInterval(3200);
1339 txVector.SetStbc(0);
1340 txVector.SetNess(0);
1341 std::list<uint16_t> staIds;
1342 uint16_t staId = 1;
1343 for (const auto& userInfo : userInfos)
1344 {
1345 txVector.SetHeMuUserInfo(staId, userInfo);
1346 staIds.push_back(staId++);
1347 }
1348 return txVector;
1349}
1350
1351void
1353{
1354 const auto& hePhy = WifiPhy::GetStaticPhyEntity(WIFI_MOD_CLASS_HE);
1355
1356 // 20 MHz band
1357 std::list<HeMuUserInfo> userInfos;
1358 userInfos.push_back({{HeRu::RU_106_TONE, 1, true}, HePhy::GetHeMcs11(), 1});
1359 userInfos.push_back({{HeRu::RU_106_TONE, 2, true}, HePhy::GetHeMcs10(), 4});
1360 WifiTxVector txVector = BuildTxVector(20, userInfos);
1361 txVector.SetSigBMode(VhtPhy::GetVhtMcs5());
1362 txVector.SetRuAllocation({96});
1363 NS_TEST_EXPECT_MSG_EQ(hePhy->GetSigMode(WIFI_PPDU_FIELD_SIG_B, txVector),
1364 VhtPhy::GetVhtMcs5(),
1365 "HE-SIG-B should be sent at MCS 5");
1366 std::pair<std::size_t, std::size_t> numUsersPerCc = txVector.GetNumRusPerHeSigBContentChannel();
1367 NS_TEST_EXPECT_MSG_EQ(numUsersPerCc.first,
1368 2,
1369 "Both users should be on HE-SIG-B content channel 1");
1370 NS_TEST_EXPECT_MSG_EQ(numUsersPerCc.second,
1371 0,
1372 "Both users should be on HE-SIG-B content channel 2");
1373 NS_TEST_EXPECT_MSG_EQ(hePhy->GetDuration(WIFI_PPDU_FIELD_SIG_B, txVector),
1374 MicroSeconds(4),
1375 "HE-SIG-B should only last one OFDM symbol");
1376
1377 // 40 MHz band, even number of users per HE-SIG-B content channel
1378 userInfos.push_back({{HeRu::RU_52_TONE, 5, true}, HePhy::GetHeMcs4(), 1});
1379 userInfos.push_back({{HeRu::RU_52_TONE, 6, true}, HePhy::GetHeMcs6(), 2});
1380 userInfos.push_back({{HeRu::RU_52_TONE, 7, true}, HePhy::GetHeMcs5(), 3});
1381 userInfos.push_back({{HeRu::RU_52_TONE, 8, true}, HePhy::GetHeMcs6(), 2});
1382 txVector = BuildTxVector(40, userInfos);
1383 txVector.SetSigBMode(VhtPhy::GetVhtMcs4());
1384 txVector.SetRuAllocation({96, 112});
1385 NS_TEST_EXPECT_MSG_EQ(hePhy->GetSigMode(WIFI_PPDU_FIELD_SIG_B, txVector),
1386 VhtPhy::GetVhtMcs4(),
1387 "HE-SIG-B should be sent at MCS 4");
1388 numUsersPerCc = txVector.GetNumRusPerHeSigBContentChannel();
1389 NS_TEST_EXPECT_MSG_EQ(numUsersPerCc.first,
1390 2,
1391 "Two users should be on HE-SIG-B content channel 1");
1392 NS_TEST_EXPECT_MSG_EQ(numUsersPerCc.second,
1393 4,
1394 "Four users should be on HE-SIG-B content channel 2");
1395 NS_TEST_EXPECT_MSG_EQ(hePhy->GetDuration(WIFI_PPDU_FIELD_SIG_B, txVector),
1396 MicroSeconds(4),
1397 "HE-SIG-B should only last one OFDM symbol");
1398
1399 // 40 MHz band, odd number of users per HE-SIG-B content channel
1400 userInfos.push_back({{HeRu::RU_26_TONE, 14, true}, HePhy::GetHeMcs3(), 1});
1401 txVector = BuildTxVector(40, userInfos);
1402 txVector.SetSigBMode(VhtPhy::GetVhtMcs3());
1403 txVector.SetRuAllocation({96, 15});
1404 NS_TEST_EXPECT_MSG_EQ(hePhy->GetSigMode(WIFI_PPDU_FIELD_SIG_B, txVector),
1405 VhtPhy::GetVhtMcs3(),
1406 "HE-SIG-B should be sent at MCS 3");
1407 numUsersPerCc = txVector.GetNumRusPerHeSigBContentChannel();
1408 NS_TEST_EXPECT_MSG_EQ(numUsersPerCc.first,
1409 2,
1410 "Two users should be on HE-SIG-B content channel 1");
1411 NS_TEST_EXPECT_MSG_EQ(numUsersPerCc.second,
1412 5,
1413 "Five users should be on HE-SIG-B content channel 2");
1414 NS_TEST_EXPECT_MSG_EQ(hePhy->GetDuration(WIFI_PPDU_FIELD_SIG_B, txVector),
1415 MicroSeconds(8),
1416 "HE-SIG-B should last two OFDM symbols");
1417
1418 // 80 MHz band
1419 userInfos.push_back({{HeRu::RU_242_TONE, 3, true}, HePhy::GetHeMcs1(), 1});
1420 userInfos.push_back({{HeRu::RU_242_TONE, 4, true}, HePhy::GetHeMcs4(), 1});
1421 txVector = BuildTxVector(80, userInfos);
1422 txVector.SetSigBMode(VhtPhy::GetVhtMcs1());
1423 txVector.SetRuAllocation({96, 15, 192, 192});
1424 NS_TEST_EXPECT_MSG_EQ(hePhy->GetSigMode(WIFI_PPDU_FIELD_SIG_B, txVector),
1425 VhtPhy::GetVhtMcs1(),
1426 "HE-SIG-B should be sent at MCS 1");
1427 numUsersPerCc = txVector.GetNumRusPerHeSigBContentChannel();
1428 NS_TEST_EXPECT_MSG_EQ(numUsersPerCc.first,
1429 3,
1430 "Three users should be on HE-SIG-B content channel 1");
1431 NS_TEST_EXPECT_MSG_EQ(numUsersPerCc.second,
1432 6,
1433 "Six users should be on HE-SIG-B content channel 2");
1434 NS_TEST_EXPECT_MSG_EQ(hePhy->GetDuration(WIFI_PPDU_FIELD_SIG_B, txVector),
1435 MicroSeconds(16),
1436 "HE-SIG-B should last four OFDM symbols");
1437
1438 // 160 MHz band
1439 userInfos.push_back({{HeRu::RU_996_TONE, 1, false}, HePhy::GetHeMcs1(), 1});
1440 txVector = BuildTxVector(160, userInfos);
1441 txVector.SetSigBMode(VhtPhy::GetVhtMcs1());
1442 txVector.SetRuAllocation({96, 15, 192, 192, 208, 208, 208, 208});
1443 NS_TEST_EXPECT_MSG_EQ(hePhy->GetSigMode(WIFI_PPDU_FIELD_SIG_B, txVector),
1444 VhtPhy::GetVhtMcs1(),
1445 "HE-SIG-B should be sent at MCS 1");
1446 numUsersPerCc = txVector.GetNumRusPerHeSigBContentChannel();
1447 NS_TEST_EXPECT_MSG_EQ(numUsersPerCc.first,
1448 4,
1449 "Four users should be on HE-SIG-B content channel 1");
1450 NS_TEST_EXPECT_MSG_EQ(numUsersPerCc.second,
1451 7,
1452 "Seven users should be on HE-SIG-B content channel 2");
1453 NS_TEST_EXPECT_MSG_EQ(hePhy->GetDuration(WIFI_PPDU_FIELD_SIG_B, txVector),
1454 MicroSeconds(20),
1455 "HE-SIG-B should last five OFDM symbols");
1456}
1457
1465{
1466 public:
1468 ~PhyHeaderSectionsTest() override;
1469 void DoRun() override;
1470
1471 private:
1481};
1482
1484 : TestCase("PHY header sections consistency")
1485{
1486}
1487
1489{
1490}
1491
1492void
1495{
1496 NS_ASSERT_MSG(obtained.size() == expected.size(),
1497 "The expected map size (" << expected.size() << ") was not obtained ("
1498 << obtained.size() << ")");
1499
1500 auto itObtained = obtained.begin();
1501 auto itExpected = expected.begin();
1502 for (; itObtained != obtained.end() || itExpected != expected.end();)
1503 {
1504 WifiPpduField field = itObtained->first;
1505 auto window = itObtained->second.first;
1506 auto mode = itObtained->second.second;
1507
1508 WifiPpduField fieldRef = itExpected->first;
1509 auto windowRef = itExpected->second.first;
1510 auto modeRef = itExpected->second.second;
1511
1513 fieldRef,
1514 "The expected PPDU field (" << fieldRef << ") was not obtained ("
1515 << field << ")");
1517 windowRef.first,
1518 "The expected start time (" << windowRef.first
1519 << ") was not obtained (" << window.first
1520 << ")");
1522 windowRef.second,
1523 "The expected stop time (" << windowRef.second
1524 << ") was not obtained (" << window.second
1525 << ")");
1527 modeRef,
1528 "The expected mode (" << modeRef << ") was not obtained (" << mode
1529 << ")");
1530 ++itObtained;
1531 ++itExpected;
1532 }
1533}
1534
1535void
1537{
1538 Time ppduStart = Seconds(1.0);
1539 Ptr<PhyEntity> phyEntity;
1541 WifiTxVector txVector;
1542 WifiMode nonHtMode;
1543
1544 // ==================================================================================
1545 // 11b (HR/DSSS)
1546 phyEntity = Create<DsssPhy>();
1547 txVector.SetMode(DsssPhy::GetDsssRate1Mbps());
1548 txVector.SetChannelWidth(22);
1549
1550 // -> long PPDU format
1552 nonHtMode = DsssPhy::GetDsssRate1Mbps();
1553 sections = {{WIFI_PPDU_FIELD_PREAMBLE, {{ppduStart, ppduStart + MicroSeconds(144)}, nonHtMode}},
1555 {{ppduStart + MicroSeconds(144), ppduStart + MicroSeconds(192)}, nonHtMode}}};
1556 CheckPhyHeaderSections(phyEntity->GetPhyHeaderSections(txVector, ppduStart), sections);
1557
1558 // -> long PPDU format if data rate is 1 Mbps (even if preamble is tagged short)
1560 CheckPhyHeaderSections(phyEntity->GetPhyHeaderSections(txVector, ppduStart), sections);
1561
1562 // -> short PPDU format
1563 txVector.SetMode(DsssPhy::GetDsssRate11Mbps());
1564 nonHtMode = DsssPhy::GetDsssRate2Mbps();
1566 sections = {{WIFI_PPDU_FIELD_PREAMBLE, {{ppduStart, ppduStart + MicroSeconds(72)}, nonHtMode}},
1568 {{ppduStart + MicroSeconds(72), ppduStart + MicroSeconds(96)}, nonHtMode}}};
1569 CheckPhyHeaderSections(phyEntity->GetPhyHeaderSections(txVector, ppduStart), sections);
1570
1571 // ==================================================================================
1572 // 11a (OFDM)
1574
1575 // -> one iteration per variant: default, 10 MHz, and 5 MHz
1576 std::map<OfdmPhyVariant, std::size_t> variants{
1577 // number to use to deduce rate and BW info for each variant
1578 {OFDM_PHY_DEFAULT, 1},
1579 {OFDM_PHY_10_MHZ, 2},
1580 {OFDM_PHY_5_MHZ, 4}};
1581 for (auto variant : variants)
1582 {
1583 phyEntity = Create<OfdmPhy>(variant.first);
1584 std::size_t ratio = variant.second;
1585 uint16_t bw = 20 / ratio; // MHz
1586 txVector.SetChannelWidth(bw);
1587 txVector.SetMode(OfdmPhy::GetOfdmRate(12000000 / ratio, bw));
1588 nonHtMode = OfdmPhy::GetOfdmRate(6000000 / ratio, bw);
1589 sections = {{WIFI_PPDU_FIELD_PREAMBLE,
1590 {{ppduStart, ppduStart + MicroSeconds(16 * ratio)}, nonHtMode}},
1592 {{ppduStart + MicroSeconds(16 * ratio), ppduStart + MicroSeconds(20 * ratio)},
1593 nonHtMode}}};
1594 CheckPhyHeaderSections(phyEntity->GetPhyHeaderSections(txVector, ppduStart), sections);
1595 }
1596
1597 // ==================================================================================
1598 // 11g (ERP-OFDM)
1599 phyEntity = Create<ErpOfdmPhy>();
1600 txVector.SetChannelWidth(20);
1601 txVector.SetMode(ErpOfdmPhy::GetErpOfdmRate(54000000));
1602 nonHtMode = ErpOfdmPhy::GetErpOfdmRate6Mbps();
1603 sections = {{WIFI_PPDU_FIELD_PREAMBLE, {{ppduStart, ppduStart + MicroSeconds(16)}, nonHtMode}},
1605 {{ppduStart + MicroSeconds(16), ppduStart + MicroSeconds(20)}, nonHtMode}}};
1606 CheckPhyHeaderSections(phyEntity->GetPhyHeaderSections(txVector, ppduStart), sections);
1607
1608 // ==================================================================================
1609 // 11n (HT)
1610 phyEntity = Create<HtPhy>(4);
1611 txVector.SetChannelWidth(20);
1612 txVector.SetMode(HtPhy::GetHtMcs6());
1613 nonHtMode = OfdmPhy::GetOfdmRate6Mbps();
1614 WifiMode htSigMode = nonHtMode;
1615
1616 // -> HT-mixed format for 2 SS and no ESS
1618 txVector.SetNss(2);
1619 txVector.SetNess(0);
1620 sections = {
1621 {WIFI_PPDU_FIELD_PREAMBLE, {{ppduStart, ppduStart + MicroSeconds(16)}, nonHtMode}},
1623 {{ppduStart + MicroSeconds(16), ppduStart + MicroSeconds(20)}, nonHtMode}},
1625 {{ppduStart + MicroSeconds(20), ppduStart + MicroSeconds(28)}, htSigMode}},
1627 {{ppduStart + MicroSeconds(28), ppduStart + MicroSeconds(40)}, // 1 HT-STF + 2 HT-LTFs
1628 htSigMode}}};
1629 CheckPhyHeaderSections(phyEntity->GetPhyHeaderSections(txVector, ppduStart), sections);
1630 txVector.SetChannelWidth(20); // shouldn't have any impact
1631 CheckPhyHeaderSections(phyEntity->GetPhyHeaderSections(txVector, ppduStart), sections);
1632
1633 // -> HT-mixed format for 3 SS and 1 ESS
1634 txVector.SetNss(3);
1635 txVector.SetNess(1);
1636 sections[WIFI_PPDU_FIELD_TRAINING] = {
1637 {ppduStart + MicroSeconds(28),
1638 ppduStart + MicroSeconds(52)}, // 1 HT-STF + 5 HT-LTFs (4 data + 1 extension)
1639 htSigMode};
1640 CheckPhyHeaderSections(phyEntity->GetPhyHeaderSections(txVector, ppduStart), sections);
1641
1642 // ==================================================================================
1643 // 11ac (VHT)
1644 phyEntity = Create<VhtPhy>();
1645 txVector.SetChannelWidth(20);
1646 txVector.SetNess(0);
1647 txVector.SetMode(VhtPhy::GetVhtMcs7());
1648 WifiMode sigAMode = nonHtMode;
1649 WifiMode sigBMode = VhtPhy::GetVhtMcs0();
1650
1651 // -> VHT SU format for 5 SS
1653 txVector.SetNss(5);
1654 sections = {
1655 {WIFI_PPDU_FIELD_PREAMBLE, {{ppduStart, ppduStart + MicroSeconds(16)}, nonHtMode}},
1657 {{ppduStart + MicroSeconds(16), ppduStart + MicroSeconds(20)}, nonHtMode}},
1659 {{ppduStart + MicroSeconds(20), ppduStart + MicroSeconds(28)}, sigAMode}},
1661 {{ppduStart + MicroSeconds(28), ppduStart + MicroSeconds(56)}, // 1 VHT-STF + 6 VHT-LTFs
1662 sigAMode}}};
1663 CheckPhyHeaderSections(phyEntity->GetPhyHeaderSections(txVector, ppduStart), sections);
1664
1665 // -> VHT SU format for 7 SS
1666 txVector.SetNss(7);
1667 sections[WIFI_PPDU_FIELD_TRAINING] = {
1668 {ppduStart + MicroSeconds(28), ppduStart + MicroSeconds(64)}, // 1 VHT-STF + 8 VHT-LTFs
1669 sigAMode};
1670 CheckPhyHeaderSections(phyEntity->GetPhyHeaderSections(txVector, ppduStart), sections);
1671
1672 // -> VHT MU format for 3 SS
1674 txVector.SetNss(3);
1675 sections[WIFI_PPDU_FIELD_TRAINING] = {
1676 {ppduStart + MicroSeconds(28), ppduStart + MicroSeconds(48)}, // 1 VHT-STF + 4 VHT-LTFs
1677 sigAMode};
1678 sections[WIFI_PPDU_FIELD_SIG_B] = {{ppduStart + MicroSeconds(48), ppduStart + MicroSeconds(52)},
1679 sigBMode};
1680 CheckPhyHeaderSections(phyEntity->GetPhyHeaderSections(txVector, ppduStart), sections);
1681 txVector.SetChannelWidth(80); // shouldn't have any impact
1682 CheckPhyHeaderSections(phyEntity->GetPhyHeaderSections(txVector, ppduStart), sections);
1683
1684 // ==================================================================================
1685 // 11ax (HE)
1686 phyEntity = Create<HePhy>();
1687 txVector.SetChannelWidth(20);
1688 txVector.SetNss(2); // HE-LTF duration assumed to be always 8 us for the time being (see note in
1689 // HePhy::GetTrainingDuration)
1690 txVector.SetMode(HePhy::GetHeMcs9());
1691 std::map<uint16_t, HeMuUserInfo> userInfoMap = {
1692 {1, {{HeRu::RU_106_TONE, 1, true}, HePhy::GetHeMcs4(), 2}},
1693 {2, {{HeRu::RU_106_TONE, 1, true}, HePhy::GetHeMcs9(), 1}}};
1694 sigAMode = HePhy::GetVhtMcs0();
1695 sigBMode = HePhy::GetVhtMcs4(); // because of first user info map
1696
1697 // -> HE SU format
1699 sections = {{WIFI_PPDU_FIELD_PREAMBLE, {{ppduStart, ppduStart + MicroSeconds(16)}, nonHtMode}},
1701 {{ppduStart + MicroSeconds(16), ppduStart + MicroSeconds(24)}, // L-SIG + RL-SIG
1702 nonHtMode}},
1704 {{ppduStart + MicroSeconds(24), ppduStart + MicroSeconds(32)}, sigAMode}},
1706 {{ppduStart + MicroSeconds(32),
1707 ppduStart + MicroSeconds(52)}, // 1 HE-STF (@ 4 us) + 2 HE-LTFs (@ 8 us)
1708 sigAMode}}};
1709 CheckPhyHeaderSections(phyEntity->GetPhyHeaderSections(txVector, ppduStart), sections);
1710
1711 // -> HE ER SU format
1713 sections[WIFI_PPDU_FIELD_SIG_A] = {
1714 {ppduStart + MicroSeconds(24), ppduStart + MicroSeconds(40)}, // 16 us HE-SIG-A
1715 sigAMode};
1716 sections[WIFI_PPDU_FIELD_TRAINING] = {
1717 {ppduStart + MicroSeconds(40),
1718 ppduStart + MicroSeconds(60)}, // 1 HE-STF (@ 4 us) + 2 HE-LTFs (@ 8 us)
1719 sigAMode};
1720 CheckPhyHeaderSections(phyEntity->GetPhyHeaderSections(txVector, ppduStart), sections);
1721
1722 // -> HE TB format
1724 txVector.SetHeMuUserInfo(1, userInfoMap.at(1));
1725 txVector.SetHeMuUserInfo(2, userInfoMap.at(2));
1726 sections[WIFI_PPDU_FIELD_SIG_A] = {{ppduStart + MicroSeconds(24), ppduStart + MicroSeconds(32)},
1727 sigAMode};
1728 sections[WIFI_PPDU_FIELD_TRAINING] = {
1729 {ppduStart + MicroSeconds(32),
1730 ppduStart + MicroSeconds(56)}, // 1 HE-STF (@ 8 us) + 2 HE-LTFs (@ 8 us)
1731 sigAMode};
1732 CheckPhyHeaderSections(phyEntity->GetPhyHeaderSections(txVector, ppduStart), sections);
1733
1734 // -> HE MU format
1736 txVector.SetSigBMode(sigBMode);
1737 txVector.SetRuAllocation({96});
1738 sections[WIFI_PPDU_FIELD_SIG_A] = {{ppduStart + MicroSeconds(24), ppduStart + MicroSeconds(32)},
1739 sigAMode};
1740 sections[WIFI_PPDU_FIELD_SIG_B] = {
1741 {ppduStart + MicroSeconds(32), ppduStart + MicroSeconds(36)}, // only one symbol
1742 sigBMode};
1743 sections[WIFI_PPDU_FIELD_TRAINING] = {
1744 {ppduStart + MicroSeconds(36),
1745 ppduStart + MicroSeconds(56)}, // 1 HE-STF (@ 4 us) + 2 HE-LTFs (@ 8 us)
1746 sigBMode};
1747 CheckPhyHeaderSections(phyEntity->GetPhyHeaderSections(txVector, ppduStart), sections);
1748 txVector.SetChannelWidth(160); // shouldn't have any impact
1749 txVector.SetRuAllocation({96, 113, 113, 113, 113, 113, 113, 113});
1750
1751 CheckPhyHeaderSections(phyEntity->GetPhyHeaderSections(txVector, ppduStart), sections);
1752
1753 // ==================================================================================
1754 // 11be (EHT)
1755 sections.erase(WIFI_PPDU_FIELD_SIG_A); // FIXME: do we keep using seperate type for 11be?
1756 sections.erase(WIFI_PPDU_FIELD_SIG_B); // FIXME: do we keep using seperate type for 11be?
1757 phyEntity = Create<EhtPhy>();
1758 txVector.SetChannelWidth(20);
1759 txVector.SetNss(2); // EHT-LTF duration assumed to be always 8 us for the time being (see note
1760 // in HePhy::GetTrainingDuration)
1761 txVector.SetMode(EhtPhy::GetEhtMcs9());
1762 userInfoMap = {{1, {{HeRu::RU_106_TONE, 1, true}, EhtPhy::GetEhtMcs4(), 2}},
1763 {2, {{HeRu::RU_106_TONE, 1, true}, EhtPhy::GetEhtMcs9(), 1}}};
1764 WifiMode uSigMode = EhtPhy::GetVhtMcs0();
1765 WifiMode ehtSigMode = EhtPhy::GetVhtMcs4(); // because of first user info map
1766
1767 // -> EHT TB format
1769 txVector.SetHeMuUserInfo(1, userInfoMap.at(1));
1770 txVector.SetHeMuUserInfo(2, userInfoMap.at(2));
1771 sections[WIFI_PPDU_FIELD_U_SIG] = {{ppduStart + MicroSeconds(24), ppduStart + MicroSeconds(32)},
1772 uSigMode};
1773 sections[WIFI_PPDU_FIELD_TRAINING] = {
1774 {ppduStart + MicroSeconds(32),
1775 ppduStart + MicroSeconds(56)}, // 1 EHT-STF (@ 8 us) + 2 EHT-LTFs (@ 8 us)
1776 uSigMode};
1777 CheckPhyHeaderSections(phyEntity->GetPhyHeaderSections(txVector, ppduStart), sections);
1778
1779 // -> EHT MU format
1781 txVector.SetRuAllocation({96});
1782 sections[WIFI_PPDU_FIELD_U_SIG] = {{ppduStart + MicroSeconds(24), ppduStart + MicroSeconds(32)},
1783 uSigMode};
1784 sections[WIFI_PPDU_FIELD_EHT_SIG] = {
1785 {ppduStart + MicroSeconds(32), ppduStart + MicroSeconds(36)}, // only one symbol
1786 ehtSigMode};
1787 sections[WIFI_PPDU_FIELD_TRAINING] = {
1788 {ppduStart + MicroSeconds(36),
1789 ppduStart + MicroSeconds(56)}, // 1 HE-STF (@ 4 us) + 2 HE-LTFs (@ 8 us)
1790 ehtSigMode};
1791 CheckPhyHeaderSections(phyEntity->GetPhyHeaderSections(txVector, ppduStart), sections);
1792 txVector.SetChannelWidth(160); // shouldn't have any impact
1793 txVector.SetRuAllocation({96, 113, 113, 113, 113, 113, 113, 113});
1794
1795 CheckPhyHeaderSections(phyEntity->GetPhyHeaderSections(txVector, ppduStart), sections);
1796}
1797
1805{
1806 public:
1808};
1809
1811 : TestSuite("wifi-devices-tx-duration", UNIT)
1812{
1813 AddTestCase(new HeSigBDurationTest, TestCase::QUICK);
1814 AddTestCase(new TxDurationTest, TestCase::QUICK);
1815 AddTestCase(new PhyHeaderSectionsTest, TestCase::QUICK);
1816}
1817
HE-SIG-B duration test.
static WifiTxVector BuildTxVector(uint16_t bw, std::list< HeMuUserInfo > userInfos)
Build a TXVECTOR for HE MU with the given bandwith and user informations.
void DoRun() override
Implementation to actually run this TestCase.
~HeSigBDurationTest() override
PHY header sections consistency test.
void DoRun() override
Implementation to actually run this TestCase.
void CheckPhyHeaderSections(PhyEntity::PhyHeaderSections obtained, PhyEntity::PhyHeaderSections expected)
Check if map of PHY header sections returned by a given PHY entity corresponds to a known value.
Tx Duration Test.
~TxDurationTest() override
static Time CalculateTxDurationUsingList(std::list< uint32_t > sizes, std::list< uint16_t > staIds, WifiTxVector txVector, WifiPhyBand band)
Calculate the overall Tx duration returned by WifiPhy for list of sizes.
static bool CheckMuTxDuration(std::list< uint32_t > sizes, std::list< HeMuUserInfo > userInfos, uint16_t channelWidth, uint16_t guardInterval, WifiPreamble preamble, Time knownDuration)
Check if the overall Tx duration returned by WifiPhy for a MU PPDU corresponds to a known value.
bool CheckTxDuration(uint32_t size, WifiMode payloadMode, uint16_t channelWidth, uint16_t guardInterval, WifiPreamble preamble, Time knownDuration)
Check if the overall tx duration returned by InterferenceHelper corresponds to a known value.
bool CheckPayloadDuration(uint32_t size, WifiMode payloadMode, uint16_t channelWidth, uint16_t guardInterval, WifiPreamble preamble, Time knownDuration)
Check if the payload tx duration returned by InterferenceHelper corresponds to a known value.
void DoRun() override
Implementation to actually run this TestCase.
Tx Duration Test Suite.
RuType GetRuType() const
Get the RU type.
Definition: he-ru.cc:435
std::map< WifiPpduField, PhyHeaderChunkInfo > PhyHeaderSections
A map of PhyHeaderChunkInfo elements per PPDU field.
Definition: phy-entity.h:327
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:305
A suite of tests to run.
Definition: test.h:1256
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:105
Implements the IEEE 802.11 MAC header.
uint32_t GetSerializedSize() const override
void SetType(WifiMacType type, bool resetToDsFromDs=true)
Set Type/Subtype values with the correct values depending on the given type.
represent a single transmission mode
Definition: wifi-mode.h:50
WifiModulationClass GetModulationClass() const
Definition: wifi-mode.cc:185
uint64_t GetDataRate(uint16_t channelWidth, uint16_t guardInterval, uint8_t nss) const
Definition: wifi-mode.cc:122
This class mimics the TXVECTOR which is to be passed to the PHY in order to define the parameters whi...
void SetStbc(bool stbc)
Sets if STBC is being used.
void SetNess(uint8_t ness)
Sets the Ness number.
void SetChannelWidth(uint16_t channelWidth)
Sets the selected channelWidth (in MHz)
void SetGuardInterval(uint16_t guardInterval)
Sets the guard interval duration (in nanoseconds)
WifiMode GetMode(uint16_t staId=SU_STA_ID) const
If this TX vector is associated with an SU PPDU, return the selected payload transmission mode.
void SetHeMuUserInfo(uint16_t staId, HeMuUserInfo userInfo)
Set the HE MU user-specific transmission information for the given STA-ID.
void SetRuAllocation(const RuAllocation &ruAlloc)
Set RU Allocation of SIG-B common field.
uint8_t GetNss(uint16_t staId=SU_STA_ID) const
If this TX vector is associated with an SU PPDU, return the number of spatial streams.
void SetSigBMode(const WifiMode &mode)
Set the MCS used for SIG-B.
std::pair< std::size_t, std::size_t > GetNumRusPerHeSigBContentChannel() const
Get the number of RUs per HE-SIG-B content channel.
void SetMode(WifiMode mode)
Sets the selected payload transmission mode.
void SetNss(uint8_t nss)
Sets the number of Nss.
void SetPreambleType(WifiPreamble preamble)
Sets the preamble type.
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition: assert.h:66
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
Definition: assert.h:86
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
Definition: abort.h:108
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:202
#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:1362
Time NanoSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1374
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1338
WifiPreamble
The type of preamble to be used by an IEEE 802.11 transmission.
WifiPhyBand
Identifies the PHY band.
Definition: wifi-phy-band.h:33
WifiPpduField
The type of PPDU field (grouped for convenience)
@ WIFI_PREAMBLE_LONG
@ WIFI_PREAMBLE_EHT_TB
@ WIFI_PREAMBLE_HE_ER_SU
@ WIFI_PREAMBLE_HE_TB
@ WIFI_PREAMBLE_EHT_MU
@ WIFI_PREAMBLE_HE_MU
@ WIFI_PREAMBLE_HE_SU
@ WIFI_PREAMBLE_VHT_MU
@ WIFI_PREAMBLE_VHT_SU
@ WIFI_PREAMBLE_SHORT
@ WIFI_PREAMBLE_HT_MF
@ WIFI_PHY_BAND_6GHZ
The 6 GHz band.
Definition: wifi-phy-band.h:39
@ WIFI_PHY_BAND_2_4GHZ
The 2.4 GHz band.
Definition: wifi-phy-band.h:35
@ WIFI_PHY_BAND_5GHZ
The 5 GHz band.
Definition: wifi-phy-band.h:37
@ WIFI_MOD_CLASS_OFDM
OFDM (Clause 17)
@ WIFI_MOD_CLASS_VHT
VHT (Clause 22)
@ WIFI_MOD_CLASS_HE
HE (Clause 27)
@ OFDM_PHY_10_MHZ
Definition: ofdm-phy.h:46
@ OFDM_PHY_DEFAULT
Definition: ofdm-phy.h:45
@ OFDM_PHY_5_MHZ
Definition: ofdm-phy.h:47
@ WIFI_PPDU_FIELD_SIG_B
SIG-B field.
@ WIFI_PPDU_FIELD_TRAINING
STF + LTF fields (excluding those in preamble for HT-GF)
@ WIFI_PPDU_FIELD_NON_HT_HEADER
PHY header field for DSSS or ERP, short PHY header field for HR/DSSS or ERP, field not present for HT...
@ WIFI_PPDU_FIELD_EHT_SIG
EHT-SIG field.
@ WIFI_PPDU_FIELD_HT_SIG
HT-SIG field.
@ WIFI_PPDU_FIELD_PREAMBLE
SYNC + SFD fields for DSSS or ERP, shortSYNC + shortSFD fields for HR/DSSS or ERP,...
@ WIFI_PPDU_FIELD_U_SIG
U-SIG field.
@ WIFI_PPDU_FIELD_SIG_A
SIG-A field.
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_ACK
phy
Definition: third.py:82
HE MU specific user transmission parameters.
HeRu::RuSpec ru
RU specification.
static TxDurationTestSuite g_txDurationTestSuite
the test suite
#define SU_STA_ID
Definition: wifi-mode.h:34