A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
wifi-tx-stats-helper-test.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2024 Huazhong University of Science and Technology
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 * Author: Muyuan Shen <muyuan@uw.edu>
7 */
8
9#include "ns3/ap-wifi-mac.h"
10#include "ns3/boolean.h"
11#include "ns3/config.h"
12#include "ns3/eht-configuration.h"
13#include "ns3/log.h"
14#include "ns3/mobility-helper.h"
15#include "ns3/multi-model-spectrum-channel.h"
16#include "ns3/packet-socket-client.h"
17#include "ns3/packet-socket-helper.h"
18#include "ns3/packet-socket-server.h"
19#include "ns3/packet.h"
20#include "ns3/pointer.h"
21#include "ns3/qos-txop.h"
22#include "ns3/qos-utils.h"
23#include "ns3/rng-seed-manager.h"
24#include "ns3/single-model-spectrum-channel.h"
25#include "ns3/spectrum-wifi-helper.h"
26#include "ns3/string.h"
27#include "ns3/test.h"
28#include "ns3/wifi-mac-header.h"
29#include "ns3/wifi-mac.h"
30#include "ns3/wifi-net-device.h"
31#include "ns3/wifi-ppdu.h"
32#include "ns3/wifi-psdu.h"
33#include "ns3/wifi-tx-stats-helper.h"
34
35#include <vector>
36
37using namespace ns3;
38
39NS_LOG_COMPONENT_DEFINE("WifiTxStatsHelperTest");
40
41/**
42 * @ingroup wifi-test
43 * @brief Implements a test case to evaluate the transmission process of multiple Wi-Fi
44 * MAC Layer MPDUs. The testcase has two options.
45 * 1) SINGLE_LINK_NON_QOS: test the handling of regular ACKs.
46 * 2) MULTI_LINK_QOS: test the handling of MPDU aggregation, Block ACKs, and Multi-Link Operation.
47 *
48 * To observe the operation of WifiTxStatsHelper, the test can be run from the command line as
49 * follows:
50 * @code
51 * NS_LOG="WifiTxStatsHelper=level_info|prefix_all" ./ns3 run 'test-runner
52 * --suite=wifi-tx-stats-helper'
53 * @endcode
54 */
56{
57 public:
58 /**
59 * Option for the test
60 */
66
67 /**
68 * Constructor
69 * @param testName Test name
70 * @param option Test option
71 */
72 WifiTxStatsHelperTest(const std::string& testName, TestOption option);
73
74 /**
75 * Callback invoked when PHY starts transmission of a PSDU, used to record TX start
76 * time and TX duration.
77 *
78 * @param context the context
79 * @param psduMap the PSDU map
80 * @param txVector the TX vector
81 * @param txPower the tx power in Watts
82 */
83 void Transmit(std::string context,
84 WifiConstPsduMap psduMap,
85 WifiTxVector txVector,
87
88 private:
89 TestOption m_option; //!< Test option
90 NodeContainer m_wifiApNode; //!< NodeContainer for AP
91 NodeContainer m_wifiStaNodes; //!< NodeContainer for STAs
92 int64_t m_streamNumber; //!< Random variable stream number
93 Time m_sifs; //!< SIFS time
94 Time m_slot; //!< slot time
95
96 Time m_difs; //!< DIFS time (for SINGLE_LINK_NON_QOS case only)
97 std::map<uint8_t, std::vector<Time>> m_txStartTimes; //!< Map of independently obtain vector of
98 //!< PhyTxBegin trace, indexed per link
99 std::map<uint8_t, std::vector<Time>>
100 m_durations; //!< Map of vector of MPDU durations, indexed per link
101 std::map<uint8_t, uint32_t> m_cwMins; //!< Map of CW Mins, indexed per link
102 std::map<uint8_t, uint32_t>
103 m_aifsns; //!< Map of AIFSNs, indexed per link (for MULTI_LINK_QOS case only)
104 std::map<uint8_t, Time>
105 m_aifss; //!< Map of AIFSs, indexed per link (for MULTI_LINK_QOS case only)
106
107 void DoSetup() override;
108 void DoRun() override;
109 /**
110 * Check correctness of test
111 * @param wifiTxStats Reference to the helper
112 */
114};
115
117 : TestCase(testName),
118 m_option(option),
119 m_streamNumber(100)
120{
121}
122
123void
125 WifiConstPsduMap psduMap,
126 WifiTxVector txVector,
128{
129 const auto linkId = atoi(context.c_str());
130 if (linkId == 0)
131 {
132 m_txStartTimes[0].push_back(Simulator::Now());
133 m_durations[0].push_back(
135 }
136 else if (linkId == 1)
137 {
138 m_txStartTimes[1].push_back(Simulator::Now());
139 m_durations[1].push_back(
141 }
142}
143
144void
146{
149
152
153 MobilityHelper mobility;
155 positionAlloc->Add(Vector(0.0, 0.0, 0.0));
156 positionAlloc->Add(Vector(1.0, 0.0, 0.0));
157 mobility.SetPositionAllocator(positionAlloc);
158 mobility.SetMobilityModel("ns3::ConstantPositionMobilityModel");
159 mobility.Install(m_wifiApNode);
160 mobility.Install(m_wifiStaNodes);
161
165}
166
167void
169{
170 std::string dataMode;
171 std::string ackMode;
173 {
174 dataMode = "OfdmRate12Mbps";
175 ackMode = "OfdmRate6Mbps";
176 }
177 else
178 {
179 dataMode = "EhtMcs6";
180 ackMode = "OfdmRate54Mbps";
181 }
182
183 WifiHelper wifi;
184 NetDeviceContainer staDevices;
185 NetDeviceContainer apDevices;
187 {
188 wifi.SetStandard(WIFI_STANDARD_80211a);
189 wifi.SetRemoteStationManager("ns3::ConstantRateWifiManager",
190 "DataMode",
191 StringValue(dataMode),
192 "ControlMode",
196 spectrumChannel->AddPropagationLossModel(lossModel);
198 spectrumChannel->SetPropagationDelayModel(delayModel);
199
201 phy.SetChannel(spectrumChannel);
202
203 WifiMacHelper mac;
204 mac.SetType("ns3::StaWifiMac",
205 "QosSupported",
206 BooleanValue(false),
207 "Ssid",
208 SsidValue(Ssid("test-ssid")));
209 staDevices = wifi.Install(phy, mac, m_wifiStaNodes);
210
211 mac.SetType("ns3::ApWifiMac",
212 "QosSupported",
213 BooleanValue(false),
214 "Ssid",
215 SsidValue(Ssid("test-ssid")),
216 "BeaconInterval",
217 TimeValue(MicroSeconds(102400)),
218 "EnableBeaconJitter",
219 BooleanValue(false));
220 apDevices = wifi.Install(phy, mac, m_wifiApNode);
221 }
222 else
223 {
224 wifi.SetStandard(WIFI_STANDARD_80211be);
225 // Get channel string for MLD STA
226 std::array<std::string, 2> mldChannelStr;
227 uint32_t frequency = 5;
229 for (auto freq : {frequency, frequency2})
230 {
231 NS_TEST_ASSERT_MSG_EQ((freq == 5 || freq == 6), true, "Unsupported frequency for BSS");
232 if (freq == 6)
233 {
234 mldChannelStr[1] = "{0, 20, BAND_6GHZ, 0}";
235 wifi.SetRemoteStationManager(static_cast<uint8_t>(1),
236 "ns3::ConstantRateWifiManager",
237 "DataMode",
238 StringValue(dataMode),
239 "ControlMode",
241 }
242 else
243 {
244 mldChannelStr[0] = "{0, 20, BAND_5GHZ, 0}";
245 wifi.SetRemoteStationManager(static_cast<uint8_t>(0),
246 "ns3::ConstantRateWifiManager",
247 "DataMode",
248 StringValue(dataMode),
249 "ControlMode",
251 }
252 }
253
255
258 spectrumChannel1->AddPropagationLossModel(lossModel);
260 spectrumChannel2->AddPropagationLossModel(lossModel);
261
262 phy.AddChannel(spectrumChannel1, WIFI_SPECTRUM_5_GHZ);
263 phy.AddChannel(spectrumChannel2, WIFI_SPECTRUM_6_GHZ);
264
265 for (uint8_t linkId = 0; linkId < 2; ++linkId)
266 {
267 phy.Set(linkId, "ChannelSettings", StringValue(mldChannelStr[linkId]));
268 }
269
270 WifiMacHelper mac;
271 mac.SetType("ns3::StaWifiMac",
272 "QosSupported",
273 BooleanValue(true),
274 "Ssid",
275 SsidValue(Ssid("test-ssid")));
276 staDevices = wifi.Install(phy, mac, m_wifiStaNodes);
277
278 mac.SetType("ns3::ApWifiMac",
279 "QosSupported",
280 BooleanValue(true),
281 "Ssid",
282 SsidValue(Ssid("test-ssid")),
283 "BeaconInterval",
284 TimeValue(MicroSeconds(102400)),
285 "EnableBeaconJitter",
286 BooleanValue(false));
287 apDevices = wifi.Install(phy, mac, m_wifiApNode);
288 }
289
290 m_sifs = DynamicCast<WifiNetDevice>(apDevices.Get(0))->GetPhy()->GetSifs();
291 m_slot = DynamicCast<WifiNetDevice>(apDevices.Get(0))->GetPhy()->GetSlot();
293 {
294 m_difs = m_sifs + 2 * m_slot;
296 DynamicCast<WifiNetDevice>(apDevices.Get(0))->GetMac()->GetTxop()->GetMinCw();
297 }
298 else
299 {
300 // Use TID-to-link Mapping to tx TID=3 pkts (BE) only on link 0,
301 // TID=4 pkts (VI) only on link 1
302 m_cwMins[0] = 15;
303 m_cwMins[1] = 7;
304 m_aifsns[0] = 3;
305 m_aifsns[1] = 2;
306 m_aifss[0] = m_aifsns[0] * m_slot + m_sifs;
307 m_aifss[1] = m_aifsns[1] * m_slot + m_sifs;
308 std::string mldMappingStr = "3 0; 4 1";
309 DynamicCast<WifiNetDevice>(staDevices.Get(0))
310 ->GetMac()
311 ->GetEhtConfiguration()
312 ->SetAttribute("TidToLinkMappingUl", StringValue(mldMappingStr));
313 }
314
316 NS_ASSERT_MSG(streamsUsed < 100, "Need to increment by larger quantity");
317 WifiHelper::AssignStreams(staDevices, m_streamNumber + 100);
318
319 // UL traffic (TX statistics will be installed at STA side)
320 PacketSocketAddress socket;
321 socket.SetSingleDevice(staDevices.Get(0)->GetIfIndex());
322 socket.SetPhysicalAddress(apDevices.Get(0)->GetAddress());
323 auto server = CreateObject<PacketSocketServer>();
324 server->SetLocal(socket);
325 m_wifiApNode.Get(0)->AddApplication(server);
326 server->SetStartTime(Seconds(0.0));
327 server->SetStopTime(Seconds(1.0));
329 {
330 auto client = CreateObject<PacketSocketClient>();
331 client->SetAttribute("PacketSize", UintegerValue(1500));
332 client->SetAttribute("MaxPackets", UintegerValue(3));
333 client->SetAttribute("Interval", TimeValue(MicroSeconds(0)));
334 client->SetRemote(socket);
336 client->SetStartTime(MicroSeconds(210000));
337 client->SetStopTime(Seconds(1.0));
338 }
339 else
340 {
342 clientBe->SetAttribute("Priority", UintegerValue(3));
343 clientBe->SetAttribute("PacketSize", UintegerValue(1500));
344 clientBe->SetAttribute("MaxPackets", UintegerValue(3));
345 clientBe->SetAttribute("Interval", TimeValue(MicroSeconds(0)));
346 clientBe->SetRemote(socket);
348 clientBe->SetStartTime(MicroSeconds(200000));
349 clientBe->SetStopTime(Seconds(1.0));
350
352 clientVi->SetAttribute("Priority", UintegerValue(4));
353 clientVi->SetAttribute("PacketSize", UintegerValue(1500));
354 clientVi->SetAttribute("MaxPackets", UintegerValue(3));
355 clientVi->SetAttribute("Interval", TimeValue(MicroSeconds(0)));
356 clientVi->SetRemote(socket);
358 clientVi->SetStartTime(MicroSeconds(300000));
359 clientVi->SetStopTime(Seconds(1.0));
360 }
361
362 // Add AP side receiver corruption
364 {
365 // We corrupt AP side reception so that:
366 // 1) the 2nd data frame is retransmitted and succeeds (1 failure, 1 success)
367 // 2) the 3rd data frame is transmitted 7 times (=FrameRetryLimit) and finally fails (7
368 // failures, 0 success)
369 //
370 // No. of pkt | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
371 // No. recvd by AP | | | 0 | | | 1 | | 2 | | AP's
372 // pkts | Bea | Bea | | Ack | AsRes | | Bea | | Ack1 |
373 // STA's pkts | | | AsReq | | | Ack | | Data1 | |
374 //
375 // No. of pkt | 9 | 10 | 11 | 12 | 13 | ... | 18 | 19 | ...
376 // No. recvd by AP | 3 (x) | 4 | | 5 (x) | 6 (x) | ... |11 (x) | | ...
377 // AP's pkts | | | Ack2 | | | ... | | Bea | ...
378 // STA's pkts | Data2 | Data2 | | Data3 | Data3 | ... | Data3 | | ...
379 //
380 // Legend:
381 // Bea = Beacon, AsReq = Association Request, AsRes = Association Response
382 // AP side corruption is indicated with (x)
383
385 apPem->SetList({3, 5, 6, 7, 8, 9, 10, 11});
386 DynamicCast<WifiNetDevice>(apDevices.Get(0))
387 ->GetMac()
388 ->GetWifiPhy()
389 ->SetPostReceptionErrorModel(apPem);
390 }
391 else
392 {
393 // We corrupt AP side reception so that:
394 // On Link 0 (contains uplink data with TID = 3):
395 // 1) the 2nd data frame is retransmitted once and succeeds (retransmission = 1)
396 // 2) the 3rd data frame is transmitted 2 times within A-MPDU and 7 times alone
397 // (WifiMac::FrameRetryLimit) and finally fails (retransmission = 8)
398 //
399 // No. of PSDU | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
400 // No. recvd by AP | | | 0 | | 1 | | 2 | | 3 |
401 // AP's pkts | Bea | Bea | | Ack | | AsRes | | CfEnd | |
402 // STA's pkts | | | AsReq | | CfEnd | | Ack | | ABReq
403 // |
404 //
405 // No. of PSDU | 9 | 10 | 11 | 12 | 12 | 12 | 13 | 14 | 14 |
406 // No. recvd by AP | | | 4 | 5 | 6(x) | 7(x) | | 8 | 9(x) |
407 // AP's pkts | Ack | ABRes | | | | | BAck | | |
408 // STA's pkts | | | Ack | Data1 | Data2 | Data3 | | Data2 | Data3
409 // |
410 //
411 // No. of PSDU | 15 | 16 | ... | | ... | 23 | 24 | 25 | ...
412 // No. recvd by AP | | 10(x) | ... | | ... | 16(x) | 17 | | ...
413 // AP's pkts | BAck | | ... | Bea | ... | | | BAck | ...
414 // STA's pkts | | Data3 | ... | | ... | Data3 | Bar | | ...
415 //
416 // On Link 1 (contains uplink data with TID = 4):
417 // 1) the 2nd data frame is transmitted 2 times within A-MPDU and 7 times alone
418 // (=WifiMac::FrameRetryLimit) and finally fails (retransmission = 8)
419 // 2) the 3rd data frame is
420 // retransmitted once and succeeds (retransmission = 1)
421 //
422 // No. of PSDU | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
423 // No. recvd by AP | | | 0 | | | 1 | | 2 | | AP's
424 // pkts | Bea | Bea | | Ack | Bea | | Ack | | ABRes |
425 // STA's pkts | | | Null | | | ABReq | | CfEnd | |
426 //
427 // No. of PSDU | 9 | 10 | 11 | 11 | 11 | 12 | 13 | 13 | 14 |
428 // No. recvd by AP | 3 | | 4 | 5(x) | 6(x) | | 7(x) | 8 | | AP's
429 // pkts | | CfEnd | | | | BAck | | | BAck |
430 // STA's pkts | Ack | | Data1 | Data2 | Data3 | | Data2 | Data3 | |
431 //
432 // No. of PSDU | 15 | ... | 21 | 22 | 23 | 24 | ...
433 // No. recvd by AP | 9(x) | ... | 15(x) | 16 | | 17 | ...
434 // AP's pkts | | ... | | | BAck | | ...
435 // STA's pkts | Data2 | ... | Data2 | Bar | | CfEnd | ...
436 //
437 // Legend:
438 // Bea = Beacon, AsReq = Association Request, AsRes = Association Response
439 // ABReq = Add Block ACK Request, ABRes = Add Block ACK Response
440 // Bar = Block ACK Request (used to notify the discarded MPDU)
441 // CfEnd = CF-End, BAck = Block ACK (Response), Null = Null function
442 // AP side corruption is indicated with (x)
443
444 // Force drops on link 0 at AP
446 apPem0->SetList({6, 7, 9, 10, 11, 12, 13, 14, 15, 16});
447 DynamicCast<WifiNetDevice>(apDevices.Get(0))
448 ->GetMac()
449 ->GetWifiPhy(0)
450 ->SetPostReceptionErrorModel(apPem0);
451
452 // Force drops on link 1 at AP
454 apPem1->SetList({5, 6, 7, 9, 10, 11, 12, 13, 14, 15});
455 DynamicCast<WifiNetDevice>(apDevices.Get(0))
456 ->GetMac()
457 ->GetWifiPhy(1)
458 ->SetPostReceptionErrorModel(apPem1);
459 }
460
462 allNetDev.Add(apDevices);
463 allNetDev.Add(staDevices);
466 wifiTxStats.Start(Seconds(0));
467 wifiTxStats.Stop(Seconds(1));
468
469 // Trace PSDU TX at both AP and STA to get start times and durations, including acks
471 {
472 for (auto it = allNetDev.Begin(); it != allNetDev.End(); ++it)
473 {
474 auto dev = DynamicCast<WifiNetDevice>(*it);
475 dev->GetPhy()->TraceConnect("PhyTxPsduBegin",
476 std::to_string(SINGLE_LINK_OP_ID),
477 // "0"
479 }
480 }
481 else
482 {
483 for (auto it = allNetDev.Begin(); it != allNetDev.End(); ++it)
484 {
485 auto dev = DynamicCast<WifiNetDevice>(*it);
486 dev->GetPhy(0)->TraceConnect("PhyTxPsduBegin",
487 "0",
489 dev->GetPhy(1)->TraceConnect("PhyTxPsduBegin",
490 "1",
492 }
493 }
494
499}
500
501void
503{
504 const auto tolerance = NanoSeconds(50); // due to propagation delay
505 // Check both variants of GetSuccesses...()
506 const auto successMap = wifiTxStats.GetSuccessesByNodeDevice();
507 const auto successMapPerNodeDeviceLink = wifiTxStats.GetSuccessesByNodeDeviceLink();
508 const auto failureMap = wifiTxStats.GetFailuresByNodeDevice();
509 const auto retransmissionMap = wifiTxStats.GetRetransmissionsByNodeDevice();
510 const auto totalSuccesses = wifiTxStats.GetSuccesses();
511 const auto totalFailures = wifiTxStats.GetFailures();
512 const auto totalRetransmissions = wifiTxStats.GetRetransmissions();
513 const auto& successRecords = wifiTxStats.GetSuccessRecords();
514 const auto& failureRecords = wifiTxStats.GetFailureRecords();
515
516 uint32_t nodeId = 1;
517 uint32_t deviceId = 0;
518 auto nodeDeviceTuple = std::make_tuple(nodeId, deviceId);
519 auto nodeDeviceLink0Tuple = std::make_tuple(nodeId, deviceId, 0);
520 auto nodeDeviceLink1Tuple = std::make_tuple(nodeId, deviceId, 1);
521
523 {
524 const auto totalFailuresDrop =
525 wifiTxStats.GetFailures(WifiMacDropReason::WIFI_MAC_DROP_REACHED_RETRY_LIMIT);
526 const auto totalFailuresDropMap = wifiTxStats.GetFailuresByNodeDevice(
527 WifiMacDropReason::WIFI_MAC_DROP_REACHED_RETRY_LIMIT);
528
530 2,
531 "Number of success packets should be 2");
533 2,
534 "Number of success packets should be 2");
535 NS_TEST_ASSERT_MSG_EQ(totalSuccesses, 2, "Number of success packets should be 2");
536
538 1,
539 "Number of retransmitted successful packets should be 1");
541 1,
542 "Number of retransmitted successful packets should be 1");
543
545 1,
546 "Number of failed packets should be 1");
547 NS_TEST_ASSERT_MSG_EQ(totalFailures, 1, "Number of failed packets (aggregate) should be 1");
550 1,
551 "Number of dropped packets (aggregate) due to retry limit reached should be 1");
554 1,
555 "Number of dropped packets (aggregate) due to retry limit reached should be 1");
556
559 1,
560 "Source node ID of the 1st successful data packet should be 1");
561 std::advance(successRecordIt, 1);
563 1,
564 "Source node ID of the 2nd successful data packet should be 1");
567 1,
568 "Source node ID of the failed data packet should be 1");
569
572 successRecordIt->m_retransmissions,
573 0,
574 "The retransmission count of the 1st successful data packet should be 0");
575 std::advance(successRecordIt, 1);
577 successRecordIt->m_retransmissions,
578 1,
579 "The retransmission count of the 2nd successful data packet should be 1");
580 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_retransmissions,
581 6,
582 "The retransmission count of the failed data packet should be 6");
583
585 NS_TEST_ASSERT_MSG_EQ(successRecordIt->m_txStartTime.IsStrictlyPositive(),
586 true,
587 "The 1st successful data packet should have been TXed");
588 std::advance(successRecordIt, 1);
589 NS_TEST_ASSERT_MSG_EQ(successRecordIt->m_txStartTime.IsStrictlyPositive(),
590 true,
591 "The 2nd successful data packet should have been TXed");
592 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_txStartTime.IsStrictlyPositive(),
593 true,
594 "The failed data packet should have been TXed");
595
597 NS_TEST_ASSERT_MSG_EQ(successRecordIt->m_ackTime.IsStrictlyPositive(),
598 true,
599 "The 1st successful data packet should have been acked");
600 std::advance(successRecordIt, 1);
601 NS_TEST_ASSERT_MSG_EQ(successRecordIt->m_ackTime.IsStrictlyPositive(),
602 true,
603 "The 2nd successful data packet should have been acked");
604 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_ackTime.IsStrictlyPositive(),
605 false,
606 "The failed data packet should not have been acked");
607
609 NS_TEST_ASSERT_MSG_EQ(successRecordIt->m_ackTime.IsStrictlyPositive(),
610 true,
611 "The 1st successful data packet should have been dequeued");
612 std::advance(successRecordIt, 1);
613 NS_TEST_ASSERT_MSG_EQ(successRecordIt->m_ackTime.IsStrictlyPositive(),
614 true,
615 "The 2nd successful data packet should have been dequeued");
616 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_dropTime.has_value() &&
617 failureRecordIt->m_dropTime.value().IsStrictlyPositive(),
618 true,
619 "The failed data packet should have been dequeued");
620
623 std::advance(successRecordItNext, 1);
625 successRecordItNext->m_enqueueTime,
626 "Three packets should be enqueued at the same time");
628 failureRecordIt->m_enqueueTime,
629 "Three packets should be enqueued at the same time");
630
633 successRecordIt->m_enqueueTime,
634 "Packets should be TXed after enqueued");
636 successRecordIt->m_enqueueTime + tolerance +
638 "Packet backoff slots should not exceed cwMin");
639 // Packet start time 7 corresponds to first data packet (prior to this, beacons and assoc)
642 "Wrong TX start time");
647 "Wrong Ack reception time");
652 "Wrong Ack reception time");
653 std::advance(successRecordIt, 1);
657 "Packets should be TXed after enqueued");
662 "Packet backoff slots should not exceed cwMin");
665 "Wrong TX start time");
670 "Wrong Ack reception time");
672 successRecordIt->m_ackTime,
675 ((m_cwMins[SINGLE_LINK_OP_ID] + 1) * 2 - 1) * m_slot + 2 * tolerance,
676 "Wrong Ack reception time");
677
681 "Packets should be TXed after enqueued");
686 "Packet backoff slots should not exceed cwMin");
689 "Wrong TX start time");
690 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_dropTime.has_value() &&
691 failureRecordIt->m_dropReason.has_value(),
692 true,
693 "Missing drop time or reason");
697 "Wrong Dequeue time for failed packet");
702 "Wrong Dequeue time for failed packet");
703 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_dropReason.value(),
704 WifiMacDropReason::WIFI_MAC_DROP_REACHED_RETRY_LIMIT,
705 "Wrong drop reason");
706 }
707 else
708 {
709 const auto totalFailuresQos =
710 wifiTxStats.GetFailures(WifiMacDropReason::WIFI_MAC_DROP_QOS_OLD_PACKET);
711 const auto totalFailuresQosMap =
712 wifiTxStats.GetFailuresByNodeDevice(WifiMacDropReason::WIFI_MAC_DROP_QOS_OLD_PACKET);
713
714 for (std::vector<Time>::size_type i = 0; i < m_txStartTimes[0].size(); ++i)
715 {
716 NS_LOG_INFO("link 0 pkt " << i << " start tx at " << m_txStartTimes[0][i].As(Time::US));
717 }
718 for (std::vector<Time>::size_type i = 0; i < m_txStartTimes[1].size(); ++i)
719 {
720 NS_LOG_INFO("link 1 pkt " << i << " start tx at " << m_txStartTimes[1][i].As(Time::US));
721 }
722
724 2,
725 "Number of success packets on link 0 should be 2");
727 2,
728 "Number of success packets on link 1 should be 2");
730 4,
731 "Number of success packets should be 4");
732 NS_TEST_ASSERT_MSG_EQ(totalSuccesses, 4, "Number of success packets should be 4");
733
735 2,
736 "Number of retransmitted successful packets should be 2");
738 2,
739 "Number of retransmitted successful packets (aggregate) should be 2");
741 2,
742 "Number of failed packets should be 2");
743 NS_TEST_ASSERT_MSG_EQ(totalFailures, 2, "Number of failed packets (aggregate) should be 2");
745 2,
746 "Number of dropped packets (aggregate) by QosTxop should be 2");
748 2,
749 "Number of dropped packets (aggregate) by QosTxop should be 2");
750
753 successRecordLink0It->m_nodeId,
754 1,
755 "Source node ID of the 1st successful data packet on link 0 should be 1");
756 std::advance(successRecordLink0It, 1);
758 successRecordLink0It->m_nodeId,
759 1,
760 "Source node ID of the 2nd successful data packet on link 0 should be 1");
763 successRecordLink1It->m_nodeId,
764 1,
765 "Source node ID of the 1st successful data packet on link 0 should be 1");
766 std::advance(successRecordLink1It, 1);
768 successRecordLink1It->m_nodeId,
769 1,
770 "Source node ID of the 2nd successful data packet on link 0 should be 1");
773 1,
774 "Source node ID of the failed data packet on link 0 should be 1");
775 std::advance(failureRecordIt, 1);
777 1,
778 "Source node ID of the failed data packet on link 1 should be 1");
779
782 0,
783 "Device ID of the 1st successful data packet on link 0 should be 0");
784 std::advance(successRecordLink0It, 1);
786 0,
787 "Device ID of the 2nd successful data packet on link 0 should be 0");
790 0,
791 "Device ID of the 1st successful data packet on link 0 should be 0");
792 std::advance(successRecordLink1It, 1);
794 0,
795 "Device ID of the 2nd successful data packet on link 1 should be 0");
798 0,
799 "Device ID of the failed data packet on link 1 should be 0");
800 std::advance(failureRecordIt, 1);
802 0,
803 "Device ID of the failed data packet on link 1 should be 0");
804
807 *successRecordLink0It->m_successLinkIdSet.begin(),
808 0,
809 "Successful link ID of the 1st successful data packet on link 0 should be 0");
810 std::advance(successRecordLink0It, 1);
812 *successRecordLink0It->m_successLinkIdSet.begin(),
813 0,
814 "Successful link ID of the 2nd successful data packet on link 0 should be 0");
817 *successRecordLink1It->m_successLinkIdSet.begin(),
818 1,
819 "Successful link ID of the 1st successful data packet on link 1 should be 1");
820 std::advance(successRecordLink1It, 1);
822 *successRecordLink1It->m_successLinkIdSet.begin(),
823 1,
824 "Successful link ID of the 2nd successful data packet on link 1 should be 1");
827 failureRecordIt->m_successLinkIdSet.empty(),
828 true,
829 "Successful link ID set of the failed data packet on link 0 should be empty");
830 std::advance(failureRecordIt, 1);
832 failureRecordIt->m_successLinkIdSet.empty(),
833 true,
834 "Successful link ID set of the failed data packet on link 1 should be empty");
835
838 successRecordLink0It->m_retransmissions,
839 0,
840 "The 1st successful data packet on link 0 should have no retransmissions");
841 std::advance(successRecordLink0It, 1);
843 successRecordLink0It->m_retransmissions,
844 1,
845 "The 2nd successful data packet on link 0 should have 1 retransmission");
848 successRecordLink1It->m_retransmissions,
849 0,
850 "The 1st successful data packet on link 1 should have no retransmissions");
851 std::advance(successRecordLink1It, 1);
853 successRecordLink1It->m_retransmissions,
854 1,
855 "The 2nd successful data packet on link 1 should have 1 retransmission");
857 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_retransmissions,
858 8,
859 "The failed data packet on link 0 should have 8 retransmissions");
860 std::advance(failureRecordIt, 1);
861 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_retransmissions,
862 8,
863 "The failed data packet on link 1 should have 8 retransmissions");
864
867 3,
868 "The 1st successful data packet on link 0 should have a TID of 3");
869 std::advance(successRecordLink0It, 1);
871 3,
872 "The 2nd successful data packet on link 0 should have a TID of 3");
875 4,
876 "The 1st successful data packet on link 1 should have a TID of 4");
877 std::advance(successRecordLink1It, 1);
879 4,
880 "The 2nd successful data packet on link 1 should have a TID of 4");
883 3,
884 "The failed data packet on link 0 should have a TID of 3");
885 std::advance(failureRecordIt, 1);
887 4,
888 "The failed data packet on link 1 should have a TID of 4");
889
892 successRecordLink0It->m_mpduSeqNum,
893 0,
894 "The 1st successful data packet on link 0 should have a Seq Num of 0");
895 std::advance(successRecordLink0It, 1);
897 successRecordLink0It->m_mpduSeqNum,
898 1,
899 "The 2nd successful data packet on link 0 should have a Seq Num of 1");
902 successRecordLink1It->m_mpduSeqNum,
903 0,
904 "The 1st successful data packet on link 1 should have a Seq Num of 0");
905 std::advance(successRecordLink1It, 1);
907 successRecordLink1It->m_mpduSeqNum,
908 2,
909 "The 2nd successful data packet on link 1 should have a Seq Num of 2");
912 2,
913 "The failed data packet on link 0 should have a Seq Num of 2");
914 std::advance(failureRecordIt, 1);
916 1,
917 "The failed data packet on link 1 should have a Seq Num of 1");
918
920 NS_TEST_ASSERT_MSG_EQ(successRecordLink0It->m_txStartTime.IsStrictlyPositive(),
921 true,
922 "The 1st successful data packet on link 0 should have been TXed");
923 std::advance(successRecordLink0It, 1);
924 NS_TEST_ASSERT_MSG_EQ(successRecordLink0It->m_txStartTime.IsStrictlyPositive(),
925 true,
926 "The 2nd successful data packet on link 0 should have been TXed");
928 NS_TEST_ASSERT_MSG_EQ(successRecordLink1It->m_txStartTime.IsStrictlyPositive(),
929 true,
930 "The 1st successful data packet on link 1 should have been TXed");
931 std::advance(successRecordLink1It, 1);
932 NS_TEST_ASSERT_MSG_EQ(successRecordLink1It->m_txStartTime.IsStrictlyPositive(),
933 true,
934 "The 2nd successful data packet on link 1 should have been TXed");
936 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_txStartTime.IsStrictlyPositive(),
937 true,
938 "The failed data packet on link 0 should have been TXed");
939 std::advance(failureRecordIt, 1);
940 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_txStartTime.IsStrictlyPositive(),
941 true,
942 "The failed data packet on link 1 should have been TXed");
943
945 NS_TEST_ASSERT_MSG_EQ(successRecordLink0It->m_ackTime.IsStrictlyPositive(),
946 true,
947 "The 1st successful data packet on link 0 should have been acked");
948 std::advance(successRecordLink0It, 1);
949 NS_TEST_ASSERT_MSG_EQ(successRecordLink0It->m_ackTime.IsStrictlyPositive(),
950 true,
951 "The 2nd successful data packet on link 0 should have been acked");
953 NS_TEST_ASSERT_MSG_EQ(successRecordLink1It->m_ackTime.IsStrictlyPositive(),
954 true,
955 "The 1st successful data packet on link 1 should have been acked");
956 std::advance(successRecordLink1It, 1);
957 NS_TEST_ASSERT_MSG_EQ(successRecordLink1It->m_ackTime.IsStrictlyPositive(),
958 true,
959 "The 2nd successful data packet on link 1 should have been acked");
961 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_ackTime.IsStrictlyPositive(),
962 false,
963 "The failed data packet on link 0 should not have been acked");
964 std::advance(failureRecordIt, 1);
965 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_ackTime.IsStrictlyPositive(),
966 false,
967 "The failed data packet on link 1 should not have been acked");
968
970 NS_TEST_ASSERT_MSG_EQ(successRecordLink0It->m_ackTime.IsStrictlyPositive(),
971 true,
972 "The 1st successful data packet on link 0 should have been dequeued");
973 std::advance(successRecordLink0It, 1);
974 NS_TEST_ASSERT_MSG_EQ(successRecordLink0It->m_ackTime.IsStrictlyPositive(),
975 true,
976 "The 2nd successful data packet on link 0 should have been dequeued");
978 NS_TEST_ASSERT_MSG_EQ(successRecordLink1It->m_ackTime.IsStrictlyPositive(),
979 true,
980 "The 1st successful data packet on link 1 should have been dequeued");
981 std::advance(successRecordLink1It, 1);
982 NS_TEST_ASSERT_MSG_EQ(successRecordLink1It->m_ackTime.IsStrictlyPositive(),
983 true,
984 "The 2nd successful data packet on link 1 should have been dequeued");
986 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_dropTime.has_value() &&
987 failureRecordIt->m_dropReason.has_value(),
988 true,
989 "Missing drop time or reason");
990 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_dropTime.value().IsStrictlyPositive(),
991 true,
992 "The failed data packet on link 0 should have been dequeued");
993 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_dropReason.value(),
994 WifiMacDropReason::WIFI_MAC_DROP_QOS_OLD_PACKET,
995 "Wrong drop reason");
996 std::advance(failureRecordIt, 1);
997 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_dropTime.has_value() &&
998 failureRecordIt->m_dropReason.has_value(),
999 true,
1000 "Missing drop time or reason");
1001 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_dropTime.value().IsStrictlyPositive(),
1002 true,
1003 "The failed data packet on link 1 should have been dequeued");
1004 NS_TEST_ASSERT_MSG_EQ(failureRecordIt->m_dropReason.value(),
1005 WifiMacDropReason::WIFI_MAC_DROP_QOS_OLD_PACKET,
1006 "Wrong drop reason");
1007
1010 std::advance(successRecordLink0ItNext, 1);
1013 successRecordLink0ItNext->m_enqueueTime,
1014 "Packets on link 0 should be enqueued at the same time");
1016 failureRecordIt->m_enqueueTime,
1017 "Packets on link 0 should be enqueued at the same time");
1020 std::advance(successRecordLink1ItNext, 1);
1021 std::advance(failureRecordIt, 1);
1023 successRecordLink1ItNext->m_enqueueTime,
1024 "Packets on link 1 should be enqueued at the same time");
1026 failureRecordIt->m_enqueueTime,
1027 "Packets on link 1 should be enqueued at the same time");
1028
1031 successRecordLink0It->m_enqueueTime,
1032 "The 1st data packet on link 0 should be TXed after enqueued");
1033 std::advance(successRecordLink0It, 1);
1035 successRecordLink0It->m_enqueueTime,
1036 "The 2nd data packet on link 0 should be TXed after enqueued");
1039 successRecordLink1It->m_enqueueTime,
1040 "The 1st data packet on link 1 should be TXed after enqueued");
1041 std::advance(successRecordLink1It, 1);
1043 successRecordLink1It->m_enqueueTime,
1044 "The 2nd data packet on link 1 should be TXed after enqueued");
1047 failureRecordIt->m_enqueueTime,
1048 "The 3rd data packet on link 0 should be TXed after enqueued");
1049 std::advance(failureRecordIt, 1);
1051 failureRecordIt->m_enqueueTime,
1052 "The 3rd data packet on link 1 should be TXed after enqueued");
1053
1056 m_txStartTimes[0][11] + m_durations[0][11] + m_aifss[0],
1057 "link 0 pkt first tx should be after the 11th packet on link");
1059 m_txStartTimes[0][11] + m_durations[0][11] + m_aifss[0] +
1060 tolerance + m_cwMins[0] * m_slot,
1061 "link 0 pkt first backoff should not exceed cwMin");
1063 std::advance(successRecordLink0ItNext, 1);
1066 successRecordLink0ItNext->m_txStartTime,
1067 "3 pkts of link 0 should tx at the same time");
1069 failureRecordIt->m_txStartTime,
1070 "3 pkts of link 0 should tx at the same time");
1071
1074 m_txStartTimes[1][10] + m_durations[1][10] + m_aifss[1],
1075 "link 1 pkt first tx should be after the 10th packet on link");
1077 m_txStartTimes[1][10] + m_durations[1][10] + m_aifss[1] +
1078 tolerance + m_cwMins[1] * m_slot,
1079 "link 1 pkt first backoff should not exceed cwMin");
1081 std::advance(successRecordLink1ItNext, 1);
1083 std::advance(failureRecordIt, 1);
1085 successRecordLink1ItNext->m_txStartTime,
1086 "3 pkts of link 1 should tx at the same time");
1088 failureRecordIt->m_txStartTime,
1089 "3 pkts of link 1 should tx at the same time");
1090
1093 m_txStartTimes[0][12] + m_durations[0][12] + m_sifs +
1094 m_durations[0][13],
1095 "Wrong first Block Ack reception time on link 0");
1097 m_txStartTimes[0][12] + m_durations[0][12] + m_sifs +
1098 m_durations[0][13] + 2 * tolerance,
1099 "Wrong first Block Ack reception time on link 0");
1102 m_txStartTimes[1][11] + m_durations[1][11] + m_sifs +
1103 m_durations[1][12],
1104 "Wrong first Block Ack reception time on link 1");
1106 m_txStartTimes[1][11] + m_durations[1][11] + m_sifs +
1107 m_durations[1][12] + 2 * tolerance,
1108 "Wrong first Block Ack reception time on link 1");
1109
1111 std::advance(successRecordLink0It, 1);
1113 m_txStartTimes[0][14] + m_durations[0][14] + m_sifs +
1114 m_durations[0][15],
1115 "Wrong second Block Ack reception time on link 0");
1117 m_txStartTimes[0][14] + m_durations[0][14] + m_sifs +
1118 m_durations[0][15] + 2 * tolerance,
1119 "Wrong second Block Ack reception time on link 0");
1121 std::advance(successRecordLink1It, 1);
1123 m_txStartTimes[1][13] + m_durations[1][13] + m_sifs +
1124 m_durations[1][14],
1125 "Wrong second Block Ack reception time on link 1");
1127 m_txStartTimes[1][13] + m_durations[1][13] + m_sifs +
1128 m_durations[1][14] + 2 * tolerance,
1129 "Wrong second Block Ack reception time on link 1");
1130 }
1131}
1132
1133/**
1134 * @ingroup wifi-test
1135 * @ingroup tests
1136 *
1137 * @brief WifiTxStatsHelper Test Suite
1138 */
1140{
1141 public:
1143};
1144
1146 : TestSuite("wifi-tx-stats-helper", Type::UNIT)
1147{
1148 // A test case to evaluate the transmission process of multiple Wi-Fi MAC Layer MPDUs in
1149 // a single link device. This testcase uses .11a to test the handling of regular ACKs.
1150 //
1151 // This class tests the WifiTxStatsHelper output by creating three transmission cases:
1152 // 1) packet is sent successfully on the first try
1153 // 2) packet is lost on the first try but successfully transmitted on the second try
1154 // 3) packet is lost on all seven tries and a failure is logged
1155 // The MPDU losses are forced by the use of WifiPhy post-reception error model.
1156 //
1157 // This test also connects to the PHY trace PhyTxPsduBegin and records the sequence of
1158 // transmission times and packet durations observed at the PHY layer, to cross-check against
1159 // the times recorded in the WifiTxStatsHelper record (traced at the MAC layer).
1160 // The testcase also checks the various fields in this helper's output records for correctness.
1161 AddTestCase(new WifiTxStatsHelperTest("Check single link non-QoS configuration",
1163 TestCase::Duration::QUICK);
1164
1165 // A test case to evaluate the transmission process of multiple Wi-Fi MAC Layer MPDUs in
1166 // a multi link device. This testcase, unlike the previous, uses .11be to test the
1167 // handling of MPDU aggregation, Block ACKs, and Multi-Link Operation.
1168 //
1169 // This class tests the WifiTxStatsHelper output by creating three transmission cases:
1170 // 1) packet is sent successfully on the first try
1171 // 2) packet is lost on the first try (in an A-MPDU) but successfully transmitted on the
1172 // second try (also in an A-MPDU)
1173 // 3) packet is lost on all 9 tries (first 2 in A-MPDU, other 7 alone) and a failure is logged
1174 // The MPDU losses are forced by the use of WifiPhy post-reception error model.
1175 //
1176 // This test also connects to the PHY trace PhyTxPsduBegin and records the sequence of
1177 // transmission times and packet durations observed at the PHY layer, to cross-check against
1178 // the times recorded in the WifiTxStatsHelper record (traced at the MAC layer).
1179 // The testcase also checks the various fields in this helper's output records for correctness.
1180 AddTestCase(new WifiTxStatsHelperTest("Check multi-link QoS configuration",
1182 TestCase::Duration::QUICK);
1183}
1184
Implements a test case to evaluate the transmission process of multiple Wi-Fi MAC Layer MPDUs.
void DoRun() override
Implementation to actually run this TestCase.
void CheckResults(const WifiTxStatsHelper &wifiTxStats)
Check correctness of test.
int64_t m_streamNumber
Random variable stream number.
NodeContainer m_wifiStaNodes
NodeContainer for STAs.
std::map< uint8_t, Time > m_aifss
Map of AIFSs, indexed per link (for MULTI_LINK_QOS case only)
std::map< uint8_t, std::vector< Time > > m_durations
Map of vector of MPDU durations, indexed per link.
std::map< uint8_t, std::vector< Time > > m_txStartTimes
Map of independently obtain vector of PhyTxBegin trace, indexed per link.
WifiTxStatsHelperTest(const std::string &testName, TestOption option)
Constructor.
std::map< uint8_t, uint32_t > m_cwMins
Map of CW Mins, indexed per link.
std::map< uint8_t, uint32_t > m_aifsns
Map of AIFSNs, indexed per link (for MULTI_LINK_QOS case only)
NodeContainer m_wifiApNode
NodeContainer for AP.
Time m_difs
DIFS time (for SINGLE_LINK_NON_QOS case only)
void Transmit(std::string context, WifiConstPsduMap psduMap, WifiTxVector txVector, Watt_u txPower)
Callback invoked when PHY starts transmission of a PSDU, used to record TX start time and TX duration...
TestOption m_option
Test option.
void DoSetup() override
Implementation to do any local setup required for this TestCase.
WifiTxStatsHelper Test Suite.
AttributeValue implementation for Boolean.
Definition boolean.h:26
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.
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.
uint32_t AddApplication(Ptr< Application > application)
Associate an Application to this Node.
Definition node.cc:153
an address for a packet socket
void SetPhysicalAddress(const Address address)
Set the destination address.
void SetSingleDevice(uint32_t device)
Set the address to match only a specified NetDevice.
Give ns3::PacketSocket powers to ns3::Node.
void Install(Ptr< Node > node) const
Aggregate an instance of a ns3::PacketSocketFactory onto the provided node.
static void SetRun(uint64_t run)
Set the run number of simulation.
static void SetSeed(uint32_t seed)
Set the seed.
static void Destroy()
Execute the events scheduled with ScheduleDestroy().
Definition simulator.cc:131
static Time Now()
Return the current simulation virtual time.
Definition simulator.cc:197
static void Run()
Run the simulation.
Definition simulator.cc:167
static void Stop()
Tell the Simulator the calling event should be the last one executed.
Definition simulator.cc:175
Make it easy to create and manage PHY objects for the spectrum model.
The IEEE 802.11 SSID Information Element.
Definition ssid.h:25
AttributeValue implementation for Ssid.
Definition ssid.h:85
Hold variables of type string.
Definition string.h:45
encapsulates test code
Definition test.h:1050
void AddTestCase(TestCase *testCase, Duration duration=Duration::QUICK)
Add an individual child TestCase to this test suite.
Definition test.cc:292
A suite of tests to run.
Definition test.h:1267
Type
Type of test.
Definition test.h:1274
Simulation virtual time values and global simulation resolution.
Definition nstime.h:94
@ US
microsecond
Definition nstime.h:107
AttributeValue implementation for Time.
Definition nstime.h:1431
Hold an unsigned integer type.
Definition uinteger.h:34
helps to create WifiNetDevice objects
static int64_t AssignStreams(NetDeviceContainer c, int64_t stream)
Assign a fixed random variable stream number to the random variables used by the PHY and MAC aspects ...
create MAC layers for a ns3::WifiNetDevice.
static Time CalculateTxDuration(uint32_t size, const WifiTxVector &txVector, WifiPhyBand band, uint16_t staId=SU_STA_ID)
Definition wifi-phy.cc:1587
Statistics helper for tracking outcomes of data MPDU transmissions.
void Enable(const NodeContainer &nodes)
Enables trace collection for all nodes and WifiNetDevices in the specified NodeContainer.
This class mimics the TXVECTOR which is to be passed to the PHY in order to define the parameters whi...
#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:75
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition log.h:191
#define NS_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
Definition log.h:264
Ptr< T > Create(Ts &&... args)
Create class instances by constructors with varying numbers of arguments and return them by Ptr.
Definition ptr.h:436
#define NS_TEST_ASSERT_MSG_EQ(actual, limit, msg)
Test that an actual and expected (limit) value are equal and report and abort if not.
Definition test.h:134
#define NS_TEST_ASSERT_MSG_LT_OR_EQ(actual, limit, msg)
Test that an actual value is less than or equal to a limit and report and abort if not.
Definition test.h:740
#define NS_TEST_ASSERT_MSG_GT_OR_EQ(actual, limit, msg)
Test that an actual value is greater than or equal to a limit and report and abort if not.
Definition test.h:905
Time MicroSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1368
Time NanoSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1380
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition nstime.h:1344
@ WIFI_STANDARD_80211a
@ WIFI_STANDARD_80211be
@ WIFI_PHY_BAND_6GHZ
The 6 GHz band.
@ WIFI_PHY_BAND_5GHZ
The 5 GHz band.
Every class exported by the ns3 library is enclosed in the ns3 namespace.
constexpr FrequencyRange WIFI_SPECTRUM_6_GHZ
Identifier for the frequency range covering the wifi spectrum in the 6 GHz band.
std::unordered_map< uint16_t, Ptr< const WifiPsdu > > WifiConstPsduMap
Map of const PSDUs indexed by STA-ID.
Definition wifi-ppdu.h:38
Callback< R, Args... > MakeCallback(R(T::*memPtr)(Args...), OBJ objPtr)
Build Callbacks for class method members which take varying numbers of arguments and potentially retu...
Definition callback.h:684
static constexpr uint8_t SINGLE_LINK_OP_ID
Link ID for single link operations (helps tracking places where correct link ID is to be used to supp...
Definition wifi-utils.h:272
constexpr FrequencyRange WIFI_SPECTRUM_5_GHZ
Identifier for the frequency range covering the wifi spectrum in the 5 GHz band.
static WifiTxStatsHelperTestSuite g_wifiTxStatsHelperTestSuite
the test suite