A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
wifi-phy-rx-trace-helper.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2023 University of Washington
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 */
6
8
9#include "ns3/boolean.h"
10#include "ns3/config.h"
11#include "ns3/fatal-error.h"
12#include "ns3/frame-exchange-manager.h"
13#include "ns3/log.h"
14#include "ns3/multi-model-spectrum-channel.h"
15#include "ns3/net-device-container.h"
16#include "ns3/node-container.h"
17#include "ns3/node-list.h"
18#include "ns3/pointer.h"
19#include "ns3/simulator.h"
20#include "ns3/spectrum-wifi-phy.h"
21#include "ns3/wifi-mac-header.h"
22#include "ns3/wifi-mac-queue.h"
23#include "ns3/wifi-mac.h"
24#include "ns3/wifi-mode.h"
25#include "ns3/wifi-net-device.h"
26#include "ns3/wifi-psdu.h"
27#include "ns3/wifi-spectrum-signal-parameters.h"
28#include "ns3/yans-wifi-phy.h"
29
30#include <algorithm>
31#include <iostream>
32#include <set>
33#include <string>
34#include <utility>
35
36namespace ns3
37{
38
39NS_LOG_COMPONENT_DEFINE("WifiPhyRxTraceHelper");
40
41/**
42 * Number of places to shift WifiPpdu UID values, when generating unique IDs
43 */
44const uint32_t SHIFT = 16;
45
50
51void
57
58void
60{
61 NS_LOG_FUNCTION(this << netDevices.GetN());
63 // filter netDevice entries through a set to prevent duplicate entries in the NodeContainer
64 std::set<Ptr<Node>> nodesSeen;
65 for (uint32_t i = 0; i < netDevices.GetN(); i++)
66 {
67 auto nodePtr = netDevices.Get(i)->GetNode();
68 if (nodesSeen.count(nodePtr) == 0)
69 {
70 nodesSeen.insert(nodePtr);
71 nodes.Add(nodePtr);
72 }
73 }
75}
76
77void
79 const std::map<Mac48Address, uint32_t>& macToNodeMap)
80{
81 NS_LOG_FUNCTION(this << nodes.GetN() << macToNodeMap.size());
82 NS_ABORT_MSG_IF(m_traceSink, "A trace sink is already configured for this helper");
84 m_traceSink->SetMapMacAddressToNodeId(macToNodeMap);
85 for (uint32_t nodeId = 0; nodeId < nodes.GetN(); nodeId++)
86 {
87 for (uint32_t deviceId = 0; deviceId < nodes.Get(nodeId)->GetNDevices(); deviceId++)
88 {
89 auto wifiDevice = DynamicCast<WifiNetDevice>(nodes.Get(nodeId)->GetDevice(deviceId));
90 if (wifiDevice)
91 {
92 for (uint8_t i = 0; i < wifiDevice->GetNPhys(); i++)
93 {
94 auto phy = wifiDevice->GetPhy(i);
95 auto yansPhy = DynamicCast<YansWifiPhy>(phy);
96 auto spectrumPhy = DynamicCast<SpectrumWifiPhy>(phy);
97 NS_ASSERT_MSG(yansPhy || spectrumPhy, "Phy type not found");
98 const std::string context =
99 "/NodeList/" + std::to_string(wifiDevice->GetNode()->GetId()) +
100 "/DeviceList/" + std::to_string(wifiDevice->GetIfIndex()) + "/Phys/" +
101 std::to_string(i);
102 auto connected = false;
103 if (yansPhy)
104 {
105 connected = yansPhy->TraceConnect(
106 "SignalArrival",
107 context,
109 }
110 else if (spectrumPhy)
111 {
112 connected = spectrumPhy->TraceConnect(
113 "SignalArrival",
114 context,
116 m_traceSink));
117 }
118 else
119 {
120 NS_FATAL_ERROR("Phy type not found");
121 }
122 NS_ASSERT_MSG(connected, "Trace source not connected");
123 connected = phy->TraceConnect(
124 "SignalTransmission",
125 context,
127 NS_ASSERT_MSG(connected, "Trace source not connected");
128 // Log packet drops
129 connected = phy->TraceConnect(
130 "PhyRxPpduDrop",
131 context,
133 NS_ASSERT_MSG(connected, "Trace source not connected");
134 // Trace PHY Outcome events
135 connected = phy->GetState()->TraceConnect(
136 "RxOutcome",
137 context,
139 NS_ASSERT_MSG(connected, "Trace source not connected");
140 }
141 }
142 }
143 }
144
145 // If a map is provided use map if not populate it yourself
146 if (!macToNodeMap.empty())
147 {
148 m_traceSink->SetMapMacAddressToNodeId(macToNodeMap);
149 }
150 // A linkID in one device might not be the same link on another device, need to create a mapping
151 // from node to link
152 m_traceSink->MapNodeToLinkToChannel(nodes);
153
154 if (!m_traceSink->IsCollectionPeriodActive())
155 {
156 NS_LOG_DEBUG("Connected traces but collection period is not active");
157 }
158}
159
160void
162{
163 m_traceSink->PrintStatistics();
164}
165
166void
167WifiPhyRxTraceHelper::PrintStatistics(Ptr<Node> node, uint32_t deviceId, uint8_t linkId) const
168{
169 m_traceSink->PrintStatistics(node->GetId(), deviceId, linkId);
170}
171
172void
173WifiPhyRxTraceHelper::PrintStatistics(uint32_t nodeId, uint32_t deviceId, uint8_t linkId) const
174{
175 m_traceSink->PrintStatistics(nodeId, deviceId, linkId);
176}
177
178void
184
185void
191
192const std::vector<WifiPpduRxRecord>&
194{
195 m_traceSink->CreateVectorFromRecords();
196 return m_traceSink->GetPpduRecords();
197}
198
199std::optional<std::reference_wrapper<const std::vector<WifiPpduRxRecord>>>
200WifiPhyRxTraceHelper::GetPpduRecords(uint32_t nodeId, uint32_t deviceId, uint8_t linkId) const
201{
202 return m_traceSink->GetPpduRecords(nodeId, deviceId, linkId);
203}
204
205void
207{
208 NS_LOG_FUNCTION(this);
209 NS_LOG_INFO("Reset WifiPhyRxTraceHelper");
210 m_traceSink->Reset();
211}
212
215{
216 return m_traceSink->GetStatistics();
217}
218
220WifiPhyRxTraceHelper::GetStatistics(Ptr<Node> node, uint32_t deviceId, uint8_t linkId) const
221{
222 return m_traceSink->GetStatistics(node->GetId(), deviceId, linkId);
223}
224
226WifiPhyRxTraceHelper::GetStatistics(uint32_t nodeId, uint32_t deviceId, uint8_t linkId) const
227{
228 return m_traceSink->GetStatistics(nodeId, deviceId, linkId);
229}
230
231std::map<Mac48Address, uint32_t>
233{
234 std::map<Mac48Address, uint32_t> macAddressToNodeId;
235 for (uint32_t i = 0; i < nodes.GetN(); i++)
236 {
237 for (uint32_t device = 0; device < nodes.Get(i)->GetNDevices(); device++)
238 {
239 if (auto wdev = DynamicCast<WifiNetDevice>(nodes.Get(i)->GetDevice(device)))
240 {
241 for (uint32_t link = 0; link < wdev->GetNPhys(); link++)
242 {
243 macAddressToNodeId[Mac48Address::ConvertFrom(
244 wdev->GetMac()->GetFrameExchangeManager(link)->GetAddress())] =
245 nodes.Get(i)->GetId();
246 NS_LOG_DEBUG("NodeID: "
247 << nodes.Get(i)->GetId() << " DeviceID: " << device
248 << " LinkId: " << link << " MAC: "
249 << wdev->GetMac()->GetFrameExchangeManager(link)->GetAddress());
250 }
251 }
252 }
253 }
254 return macAddressToNodeId;
255}
256
258
259TypeId
261{
262 static TypeId tid = TypeId("ns3::WifiPhyRxTraceSink")
263 .SetParent<Object>()
264 .SetGroupName("Wifi")
265 .AddConstructor<WifiPhyRxTraceSink>();
266 return tid;
267}
268
273
274void
276 const std::map<Mac48Address, uint32_t>& MacAddressToNodeIdMap)
277{
278 m_macAddressToNodeId = MacAddressToNodeIdMap;
279}
280
282WifiPhyRxTraceSink::ContextToNodeId(std::string context) const
283{
284 const auto sub = context.substr(10);
285 const auto pos = sub.find("/Device");
286 return std::stoi(sub.substr(0, pos));
287}
288
289int
290WifiPhyRxTraceSink::ContextToLinkId(std::string context) const
291{
292 const auto pos = context.find("/Phys/");
293 const auto sub = context.substr(pos + 6);
294 const auto nextSlashPos = sub.find('/');
295 if (nextSlashPos == std::string::npos)
296 {
297 return std::stoi(sub);
298 }
299 const auto physNumberStr = sub.substr(0, nextSlashPos);
300 return std::stoi(physNumberStr);
301}
302
303int
305{
306 auto pos = context.find("/DeviceList/");
307 pos += 12;
308 const auto sub = context.substr(pos);
309 const auto nextSlashPos = sub.find('/');
310 const auto deviceIdStr = sub.substr(0, nextSlashPos);
311 return std::stoi(deviceIdStr);
312}
313
314std::string
315WifiPhyRxTraceSink::ContextToTuple(std::string context) const
316{
317 const auto str = std::to_string(ContextToNodeId(context)) + ":" +
318 std::to_string(ContextToDeviceId(context)) + ":" +
319 std::to_string(ContextToLinkId(context));
320 return str;
321}
322
323// Each WifiPpdu has a UID, but more than one trace record can exist for a unique WifiPpdu
324// This generator shifts the WifiPpdu UID leftward and combines it with a member variable
325// counter to generate more than one unique ID for each WifiPpdu UID
326uint64_t
328{
329 uint64_t tag;
330 do
331 {
332 tag = (ppduUid << SHIFT) | counter++;
333 } while (usedTags.find(tag) != usedTags.end());
334 usedTags.insert(tag);
335 NS_LOG_DEBUG("Generating tag " << tag << " from ppdu UID " << ppduUid);
336 return tag;
337}
338
339bool
341{
342 return lhs.m_rxTag == rhs.m_rxTag;
343}
344
345bool
347{
348 return !(lhs == rhs);
349}
350
351bool
352operator<(const WifiPpduRxRecord& lhs, const WifiPpduRxRecord& rhs)
353{
354 return lhs.m_rxTag < rhs.m_rxTag;
355}
356
357WifiPhyTraceStatistics
359{
363 result.m_failedPpdus = lhs.m_failedPpdus + rhs.m_failedPpdus;
366 result.m_failedMpdus = lhs.m_failedMpdus + rhs.m_failedMpdus;
367
368 // Merge map fields
369 for (const auto& pair : lhs.m_ppduDropReasons)
370 {
371 result.m_ppduDropReasons[pair.first] += pair.second;
372 }
373 for (const auto& pair : rhs.m_ppduDropReasons)
374 {
375 result.m_ppduDropReasons[pair.first] += pair.second;
376 }
377 return result;
378}
379
380bool
389
390bool
392{
393 return !(lhs == rhs);
394}
395
396void
398{
399 for (uint32_t i = 0; i < nodes.GetN(); i++)
400 {
401 for (uint32_t device = 0; device < nodes.Get(i)->GetNDevices(); device++)
402 {
403 auto wdev = DynamicCast<WifiNetDevice>(nodes.Get(i)->GetDevice(device));
404 if (wdev)
405 {
406 for (uint32_t link = 0; link < wdev->GetNPhys(); link++)
407 {
408 m_nodeToDeviceToLinkToChannelInfo[nodes.Get(i)->GetId()][wdev->GetIfIndex()]
409 [link] = std::make_pair(
410 wdev->GetPhy(link)->GetChannelNumber(),
411 wdev->GetPhy(link)->GetFrequency());
412
413 NS_LOG_DEBUG("NodeId: "
414 << nodes.Get(i)->GetId() << " DeviceID: " << wdev->GetIfIndex()
415 << " LinkId: " << link
416 << " freq: " << wdev->GetPhy(link)->GetFrequency()
417 << " ch#: " << int(wdev->GetPhy(link)->GetChannelNumber()));
418 }
419 }
420 }
421 }
422}
423
424// channel number, frequency
425std::optional<std::pair<uint8_t, uint16_t>>
426WifiPhyRxTraceSink::GetChannelInfo(uint32_t nodeId, uint32_t deviceId, int link) const
427{
428 auto nodeIter = m_nodeToDeviceToLinkToChannelInfo.find(nodeId);
429 if (nodeIter != m_nodeToDeviceToLinkToChannelInfo.end())
430 {
431 auto& deviceMap = nodeIter->second;
432 auto deviceIter = deviceMap.find(deviceId);
433 if (deviceIter != deviceMap.end())
434 {
435 auto& linkMap = deviceIter->second;
436 auto linkIter = linkMap.find(link);
437 if (linkIter != linkMap.end())
438 {
439 return std::optional<std::pair<uint8_t, uint16_t>>(linkIter->second);
440 }
441 }
442 }
443 return std::nullopt;
444}
445
446// TODO: Profile this and possibly refactor to avoid duplicates
447void
449 uint32_t deviceId,
450 uint8_t linkId)
451{
452 NS_LOG_FUNCTION(this << nodeId << deviceId << linkId);
453 // Add all overlapping packets to the list of overlapping packets for this frame arrival
454 for (const auto& it : m_nodeDeviceLinkRxRecords.at(nodeId).at(deviceId).at(linkId))
455 {
456 for (const auto& iter : m_nodeDeviceLinkRxRecords.at(nodeId).at(deviceId).at(linkId))
457 {
458 if (it != iter)
459 {
460 m_rxTagToListOfOverlappingPpduRecords[it.m_rxTag].emplace_back(iter);
461 }
462 }
463 }
464
465 // Remove duplicates
466 for (const auto& it : m_nodeDeviceLinkRxRecords.at(nodeId).at(deviceId).at(linkId))
467 {
468 // First, sort the vector to bring duplicates together
469 std::sort(m_rxTagToListOfOverlappingPpduRecords[it.m_rxTag].begin(),
470 m_rxTagToListOfOverlappingPpduRecords[it.m_rxTag].end());
471 // Use std::unique to remove duplicates (adjacent identical elements)
473 std::unique(m_rxTagToListOfOverlappingPpduRecords[it.m_rxTag].begin(),
474 m_rxTagToListOfOverlappingPpduRecords[it.m_rxTag].end()),
475 m_rxTagToListOfOverlappingPpduRecords[it.m_rxTag].end());
476 }
478 "Map of overlapping PPDU records size: " << m_rxTagToListOfOverlappingPpduRecords.size());
479}
480
481void
483{
484 NS_LOG_FUNCTION(this << nodeId << deviceId);
485 // remove from currently received (in this case transmitted) packets
486 NS_LOG_INFO("Remove transmit record at " << nodeId << ":" << deviceId << ":"
487 << +ppduRecord.m_linkId << " UID "
488 << ppduRecord.m_rxTag);
490 .at(deviceId)
491 .at(ppduRecord.m_linkId)
492 .erase(
493 std::remove(
494 m_nodeDeviceLinkRxRecords.at(nodeId).at(deviceId).at(ppduRecord.m_linkId).begin(),
495 m_nodeDeviceLinkRxRecords.at(nodeId).at(deviceId).at(ppduRecord.m_linkId).end(),
496 ppduRecord),
497 m_nodeDeviceLinkRxRecords.at(nodeId).at(deviceId).at(ppduRecord.m_linkId).end());
498 NS_LOG_INFO("Size of m_nodeDeviceLinkRxRecords: " << m_nodeDeviceLinkRxRecords.size());
499
500 // Erase the item from rxTagToPpduRecord
501 m_rxTagToPpduRecord.erase(ppduRecord.m_rxTag);
502 NS_LOG_INFO("Size of m_rxTagToPpduRecord: " << m_rxTagToPpduRecord.size());
503}
504
505void
506WifiPhyRxTraceSink::PhyRxEnd(uint32_t nodeId, uint32_t deviceId, uint64_t rxTag, uint64_t ppduUid)
507{
508 NS_LOG_FUNCTION(this << nodeId << deviceId << rxTag << ppduUid);
509 NS_ASSERT_MSG(m_rxTagToPpduRecord.contains(rxTag), "Missing PPDU at PhyRxEnd");
510 // Update the end time on the record, and reinsert to the map
511 auto ppduRecord = m_rxTagToPpduRecord[rxTag];
512 ppduRecord.m_endTime = Simulator::Now();
513 auto [it, inserted] = m_rxTagToPpduRecord.insert_or_assign(rxTag, ppduRecord);
514 NS_ASSERT_MSG(!inserted, "Did not assign successfully");
515
516 // Update the lists of overlapping PPDUs
517 UpdateCurrentlyReceivedSignal(nodeId, deviceId, ppduRecord.m_linkId);
518 for (const auto& it : m_rxTagToListOfOverlappingPpduRecords[rxTag])
519 {
520 ppduRecord.m_overlappingPpdu.emplace_back(it);
521 }
522
523 NS_LOG_INFO("Remove reception record at " << nodeId << ":" << deviceId << ":"
524 << +ppduRecord.m_linkId << " UID " << rxTag);
525 // Remove from map of active records
527 .at(deviceId)
528 .at(ppduRecord.m_linkId)
529 .erase(
530 std::remove(
531 m_nodeDeviceLinkRxRecords.at(nodeId).at(deviceId).at(ppduRecord.m_linkId).begin(),
532 m_nodeDeviceLinkRxRecords.at(nodeId).at(deviceId).at(ppduRecord.m_linkId).end(),
533 ppduRecord),
534 m_nodeDeviceLinkRxRecords.at(nodeId).at(deviceId).at(ppduRecord.m_linkId).end());
535 NS_LOG_INFO("Size of m_nodeDeviceLinkRxRecords: " << m_nodeDeviceLinkRxRecords.size());
536
537 // Erase the item from rxTagToPpduRecord
538 m_rxTagToPpduRecord.erase(rxTag);
539 NS_LOG_INFO("Size of m_rxTagToPpduRecord: " << m_rxTagToPpduRecord.size());
540
541 // checks if statistics period has been started before adding to the list of completed records
543 {
544 NS_LOG_INFO("Adding PPDU record for " << ppduRecord.m_receiverId << " " << deviceId << " "
545 << +ppduRecord.m_linkId);
546 m_completedRecords[ppduRecord.m_receiverId][deviceId][ppduRecord.m_linkId].emplace_back(
547 ppduRecord);
548 }
549 else
550 {
551 NS_LOG_DEBUG("Not adding PPDU record (statistics not started) for "
552 << ppduRecord.m_receiverId << " " << deviceId << " " << ppduRecord.m_linkId);
553 }
554}
555
556bool
561
562void
567
568void
573
574void
577 const WifiTxVector& txVector)
578{
579 NS_LOG_FUNCTION(context << ppdu << txVector);
580 uint32_t nodeId = ContextToNodeId(context);
581 uint32_t deviceId = ContextToDeviceId(context);
582 uint8_t linkId = ContextToLinkId(context);
583
584 WifiPpduRxRecord ppduRecord;
585 ppduRecord.m_startTime = Simulator::Now();
586 ppduRecord.m_endTime = Simulator::Now() + ppdu->GetTxDuration();
587 ppduRecord.m_ppdu = ppdu;
588 ppduRecord.m_senderId = nodeId;
589 ppduRecord.m_linkId = linkId;
590 ppduRecord.m_senderDeviceId = deviceId;
591
592 // Tag used to determine which packet needs to be removed from currently received packets
593 ppduRecord.m_rxTag = m_tagGenerator.GenerateUniqueTag(ppdu->GetUid());
594
595 NS_LOG_INFO("Transmit at " << ContextToTuple(context) << " insert to tagToRecord map for UID "
596 << ppduRecord.m_rxTag);
597 auto [it, inserted] = m_rxTagToPpduRecord.insert_or_assign(ppduRecord.m_rxTag, ppduRecord);
598 NS_ASSERT_MSG(inserted, "Did not insert successfully");
599 NS_LOG_INFO("Size of m_rxTagToPpduRecord: " << m_rxTagToPpduRecord.size());
600
601 /*
602 m_rxTagToPpduRecord[ppduRecord.m_rxTag] = ppduRecord;
603 */
604
605 // Use this to find who is the sender in the reception side
606 m_ppduUidToTxTag[ppduRecord.m_ppdu->GetUid()] = ppduRecord.m_rxTag;
607
608 // store record in a map, indexed by nodeId, deviceId, linkId
609 NS_LOG_INFO("Transmit at " << ContextToTuple(context)
610 << " insert to active records map for UID " << ppduRecord.m_rxTag);
611 m_nodeDeviceLinkRxRecords[nodeId][deviceId][linkId].emplace_back(ppduRecord);
612 NS_LOG_INFO("Size of active records: " << m_nodeDeviceLinkRxRecords.size());
613
614 Simulator::Schedule(ppduRecord.m_endTime - ppduRecord.m_startTime,
616 this,
617 nodeId,
618 deviceId,
619 ppduRecord);
620}
621
622void
625 uint32_t senderNodeId,
626 double rxPower,
627 Time duration)
628{
629 NS_LOG_FUNCTION(context << signal << senderNodeId << rxPower << duration);
630 const auto wifiSignal = DynamicCast<const WifiSpectrumSignalParameters>(signal);
631 const auto ppdu = wifiSignal->ppdu;
632
633 if (!wifiSignal)
634 {
635 NS_LOG_DEBUG("Non-WiFi Signal Received");
636 return;
637 }
638 PhySignalArrival(context, ppdu, rxPower, duration);
639}
640
641void
644 double rxPower,
645 Time duration)
646{
647 NS_LOG_FUNCTION(context << ppdu << rxPower << duration);
648 uint32_t nodeId = ContextToNodeId(context);
649 uint32_t deviceId = ContextToDeviceId(context);
650 uint8_t linkId = ContextToLinkId(context);
651
652 // Associate this received PPDU with a record previously stored on the transmit side, if present
653 bool hasTxTag = false;
654 WifiPpduRxRecord txPpduRecord;
655 if (m_ppduUidToTxTag.contains(ppdu->GetUid()))
656 {
657 hasTxTag = true;
658 txPpduRecord = m_rxTagToPpduRecord[m_ppduUidToTxTag[ppdu->GetUid()]];
659 NS_LOG_DEBUG("Arrival RxNodeID: " << nodeId << " SenderID: " << txPpduRecord.m_senderId
660 << " Received on LinkID: " << +linkId
661 << " Frame Sent on LinkId: " << +txPpduRecord.m_linkId);
662 }
663 else
664 {
665 NS_LOG_DEBUG("Arrival RxNodeID: " << nodeId << " Received on LinkID: " << +linkId
666 << "; no sender info");
667 }
668 if (hasTxTag)
669 {
670 auto rxInfo = GetChannelInfo(nodeId, deviceId, linkId);
671 auto txInfo = GetChannelInfo(txPpduRecord.m_senderId,
672 txPpduRecord.m_senderDeviceId,
673 txPpduRecord.m_linkId);
674 if (!txInfo.has_value())
675 {
677 "Didn't find TX record for transmission; possibly from an untraced sender");
678 }
679 else
680 {
681 if ((int(txInfo->second) != int(rxInfo->second)) ||
682 (int(txInfo->first) != int(rxInfo->first)))
683 {
685 "Received Signal on a different frequency or channel number than what was "
686 "configured for this PHY or link");
687 return;
688 }
689 }
690 }
691
692 WifiPpduRxRecord ppduRecord;
693 ppduRecord.m_startTime = Simulator::Now();
694 ppduRecord.m_endTime = Simulator::Now() + duration;
695 ppduRecord.m_ppdu = ppdu;
696 ppduRecord.m_rssi = rxPower;
697 ppduRecord.m_rxTag = m_tagGenerator.GenerateUniqueTag(ppdu->GetUid());
698 ppduRecord.m_receiverId = nodeId;
699 ppduRecord.m_linkId = linkId;
700 if (hasTxTag)
701 {
702 ppduRecord.m_senderId = txPpduRecord.m_senderId;
703 ppduRecord.m_senderDeviceId = txPpduRecord.m_senderDeviceId;
705 "Receive at " << ContextToTuple(context) << " from node " << txPpduRecord.m_senderId
706 << "; insert to active records map for UID " << ppduRecord.m_rxTag);
707 }
708 else
709 {
710 NS_LOG_INFO("Receive at " << ContextToTuple(context)
711 << "; insert to active records map for UID "
712 << ppduRecord.m_rxTag);
713 }
714
715 // Add to list of currently received frames on this node, device and specific link
716 m_nodeDeviceLinkRxRecords[nodeId][deviceId][linkId].emplace_back(ppduRecord);
717 NS_LOG_INFO("Size of active records " << m_nodeDeviceLinkRxRecords.size());
718
719 UpdateCurrentlyReceivedSignal(nodeId, deviceId, linkId);
720
721 NS_LOG_INFO("Receive at " << ContextToTuple(context) << " insert to tagToRecord map for UID "
722 << ppduRecord.m_rxTag);
723 auto [it, inserted] = m_rxTagToPpduRecord.insert_or_assign(ppduRecord.m_rxTag, ppduRecord);
724 NS_ASSERT_MSG(inserted, "Did not insert successfully");
725 NS_LOG_INFO("Size of m_rxTagToPpduRecord " << m_rxTagToPpduRecord.size());
726
727 NS_LOG_INFO("Receive at " << ContextToTuple(context) << " insert to highly nested map for UID "
728 << ppduRecord.m_rxTag);
729 m_nodeDeviceLinkPidToRxId[nodeId][deviceId][linkId][ppduRecord.m_ppdu->GetUid()] =
730 ppduRecord.m_rxTag;
731 NS_LOG_INFO("Size of highly nested map " << m_nodeDeviceLinkPidToRxId.size());
732}
733
734void
738{
739 NS_LOG_FUNCTION(this << context << ppdu << reason);
740 uint32_t nodeId = ContextToNodeId(context);
741 uint32_t deviceId = ContextToDeviceId(context);
742 uint8_t linkId = ContextToLinkId(context);
743 WifiPpduRxRecord ppduRecord =
744 m_rxTagToPpduRecord[m_nodeDeviceLinkPidToRxId[nodeId][deviceId][linkId][ppdu->GetUid()]];
745
746 if (ppduRecord.m_ppdu == nullptr)
747 {
748 NS_LOG_DEBUG("Frame being dropped was not observed on SignalArrival trace. Means it was "
749 "received on a wrong link configuration");
750 return;
751 }
752 ppduRecord.m_reason = reason;
753
754 std::vector<bool> outcome;
755 for (const auto& mpdu : *PeekPointer(ppdu->GetPsdu()))
756 {
757 mpdu->GetPacket();
758 outcome.emplace_back(false);
759 }
760 ppduRecord.m_statusPerMpdu = outcome;
761 m_rxTagToPpduRecord[ppduRecord.m_rxTag] = ppduRecord;
762
765 this,
766 nodeId,
767 deviceId,
768 ppduRecord.m_rxTag,
769 ppdu->GetUid());
770}
771
772void
775 RxSignalInfo signal,
776 const WifiTxVector& txVector,
777 const std::vector<bool>& statusMpdu)
778{
779 NS_LOG_FUNCTION(context << ppdu << signal << txVector);
780 uint32_t nodeId = ContextToNodeId(context);
781 uint32_t deviceId = ContextToDeviceId(context);
782 uint8_t linkId = ContextToLinkId(context);
783
784 WifiPpduRxRecord ppduRecord =
785 m_rxTagToPpduRecord[m_nodeDeviceLinkPidToRxId[nodeId][deviceId][linkId][ppdu->GetUid()]];
786
787 if (ppduRecord.m_ppdu)
788 {
789 NS_LOG_DEBUG("Found an expected frame in the outcome");
790 }
791 else
792 {
793 NS_LOG_DEBUG("Frame to be processed was not observed on SignalArrival trace");
794 return;
795 }
796 // Save the reception status per MPDU in the PPDU record
797 ppduRecord.m_statusPerMpdu = statusMpdu;
798
799 auto [it, inserted] = m_rxTagToPpduRecord.insert_or_assign(ppduRecord.m_rxTag, ppduRecord);
800 NS_ASSERT_MSG(!inserted, "Did not assign successfully");
801 PhyRxEnd(nodeId, deviceId, ppduRecord.m_rxTag, ppdu->GetUid());
802}
803
804void
806 const WifiPpduRxRecord& record) const
807{
808 // Check if PPDU was dropped and if any MPDU was addressed to the receiver
809 if (record.m_reason)
810 {
811 bool mpduToReceiver = false;
812 bool shouldCount = true;
814 auto it = record.m_statusPerMpdu.begin();
815 for (const auto& mpdu : *PeekPointer(record.m_ppdu->GetPsdu()))
816 {
817 p = mpdu->GetProtocolDataUnit();
818 WifiMacHeader hdr;
819 p->PeekHeader(hdr);
820 if (!(hdr.IsData() &&
821 (hdr.GetType() == WIFI_MAC_DATA || hdr.GetType() == WIFI_MAC_QOSDATA)))
822 {
823 shouldCount = false;
824 break;
825 }
826 if (!(*it) && (record.m_receiverId == m_macAddressToNodeId.at(hdr.GetAddr1())))
827 {
828 // Failed MPDU
829 statistics.m_failedMpdus++;
830 mpduToReceiver = true;
831 }
832 ++it;
833 }
834 // At least one MPDU addressed to the receiver was dropped, mark PPDU as
835 // failed
836 if (mpduToReceiver && shouldCount)
837 {
838 statistics.m_failedPpdus++;
839 // Check if PPDU Overlap
840 if (!record.m_overlappingPpdu.empty())
841 {
842 // Yes Overlap
843 statistics.m_overlappingPpdus++;
844 }
845 else
846 {
847 // No Overlap
848 statistics.m_nonOverlappingPpdus++;
849 }
850 // It is due to a drop, clarify and count the reason
851 statistics.m_ppduDropReasons[record.m_reason]++;
852 }
853 }
854 else
855 {
856 // Payload Decode Attempt (No Drop but still not certain of MPDU outcome)
857 // MPDU Level
858
860 auto it = record.m_statusPerMpdu.begin();
861 bool mpduFail = false;
862 bool shouldCount = true;
863 bool mpduToReceiver = false;
864 for (const auto& mpdu : *PeekPointer(record.m_ppdu->GetPsdu()))
865 {
866 p = mpdu->GetProtocolDataUnit();
867 WifiMacHeader hdr;
868 p->PeekHeader(hdr);
869 if (!(hdr.IsData() &&
870 (hdr.GetType() == WIFI_MAC_DATA || hdr.GetType() == WIFI_MAC_QOSDATA)))
871 {
872 shouldCount = false;
873 break;
874 }
875 if (*it && (m_macAddressToNodeId.contains(hdr.GetAddr1())) &&
876 (record.m_receiverId == m_macAddressToNodeId.at(hdr.GetAddr1())))
877 {
878 // Successful MPDU
879 statistics.m_receivedMpdus++;
880 mpduToReceiver = true;
881 }
882 else if (!(*it) && (m_macAddressToNodeId.contains(hdr.GetAddr1())) &&
883 (record.m_receiverId == m_macAddressToNodeId.at(hdr.GetAddr1())))
884 {
885 // Failed MPDU
886 statistics.m_failedMpdus++;
887 mpduFail = true;
888 mpduToReceiver = true;
889 }
890 ++it;
891 }
892 if (!mpduFail && shouldCount && mpduToReceiver)
893 {
894 // No drops or payload decode errors for all MPDUs addressed to the
895 // receiver
896 statistics.m_receivedPpdus++;
897
898 // Check if PPDU Overlap
899 if (!record.m_overlappingPpdu.empty())
900 {
901 // Yes Overlap
902 statistics.m_overlappingPpdus++;
903 }
904 else
905 {
906 // No Overlap
907 statistics.m_nonOverlappingPpdus++;
908 }
909 }
910 else if (shouldCount && mpduToReceiver)
911 {
912 // At least one MPDU addressed to the receiver failed.
913 statistics.m_failedPpdus++;
914 // Check if PPDU Overlap
915 if (!record.m_overlappingPpdu.empty())
916 {
917 // Yes Overlap
918 statistics.m_overlappingPpdus++;
919 }
920 else
921 {
922 // No Overlap
923 statistics.m_nonOverlappingPpdus++;
924 }
925 }
926 }
927}
928
931{
932 NS_LOG_FUNCTION(this);
933 WifiPhyTraceStatistics statistics;
934 for (const auto& nodeMap : m_completedRecords)
935 {
936 for (const auto& deviceMap : nodeMap.second)
937 {
938 for (const auto& linkMap : deviceMap.second)
939 {
940 for (const auto& record : linkMap.second)
941 {
942 CountStatisticsForRecord(statistics, record);
943 }
944 }
945 }
946 }
947 return statistics;
948}
949
951WifiPhyRxTraceSink::CountStatistics(uint32_t nodeId, uint32_t deviceId, uint8_t linkId) const
952{
953 NS_LOG_FUNCTION(this << nodeId << deviceId << linkId);
954 WifiPhyTraceStatistics statistics;
955 if (m_completedRecords.contains(nodeId))
956 {
957 auto mapOfDevices = m_completedRecords.at(nodeId);
958 if (mapOfDevices.contains(deviceId))
959 {
960 auto mapOfLinks = mapOfDevices.at(deviceId);
961 if (mapOfLinks.contains(linkId))
962 {
963 auto vectorOfRecords = mapOfLinks.at(linkId);
964 for (const auto& record : vectorOfRecords)
965 {
966 CountStatisticsForRecord(statistics, record);
967 }
968 }
969 }
970 }
971 return statistics;
972}
973
976{
978 return stats;
979}
980
982WifiPhyRxTraceSink::GetStatistics(uint32_t nodeId, uint32_t deviceId, uint8_t linkId) const
983{
984 WifiPhyTraceStatistics stats = CountStatistics(nodeId, deviceId, linkId);
985 return stats;
986}
987
988void
990{
992
993 std::cout << "Total PPDUs Received: " << statistics.m_receivedPpdus + statistics.m_failedPpdus
994 << std::endl;
995 std::cout << "Total Non-Overlapping PPDUs Received: " << statistics.m_nonOverlappingPpdus
996 << std::endl;
997 std::cout << "Total Overlapping PPDUs Received: " << statistics.m_overlappingPpdus << std::endl;
998
999 std::cout << "\nSuccessful PPDUs: " << statistics.m_receivedPpdus << std::endl;
1000 std::cout << "Failed PPDUs: " << statistics.m_failedPpdus << std::endl;
1001 for (auto reason : statistics.m_ppduDropReasons)
1002 {
1003 std::cout << "PPDU Dropped due to " << reason.first << ": " << reason.second << std::endl;
1004 }
1005 std::cout << "\nTotal MPDUs: " << statistics.m_failedMpdus + statistics.m_receivedMpdus
1006 << std::endl;
1007 std::cout << "Total Successful MPDUs: " << statistics.m_receivedMpdus << std::endl;
1008 std::cout << "Total Failed MPDUs: " << statistics.m_failedMpdus << std::endl;
1009}
1010
1011void
1012WifiPhyRxTraceSink::PrintStatistics(uint32_t nodeId, uint32_t deviceId, uint8_t linkId) const
1013{
1014 WifiPhyTraceStatistics statistics = CountStatistics(nodeId, deviceId, linkId);
1015 std::cout << "Total PPDUs Received: " << statistics.m_receivedPpdus + statistics.m_failedPpdus
1016 << std::endl;
1017 std::cout << "Total Non-Overlapping PPDUs Received: " << statistics.m_nonOverlappingPpdus
1018 << std::endl;
1019 std::cout << "Total Overlapping PPDUs Received: " << statistics.m_overlappingPpdus << std::endl;
1020
1021 std::cout << "\nSuccessful PPDUs: " << statistics.m_receivedPpdus << std::endl;
1022 std::cout << "Failed PPDUs: " << statistics.m_failedPpdus << std::endl;
1023 for (auto reason : statistics.m_ppduDropReasons)
1024 {
1025 std::cout << "PPDU Dropped due to " << reason.first << ": " << reason.second << std::endl;
1026 }
1027 std::cout << "\nTotal MPDUs: " << statistics.m_failedMpdus + statistics.m_receivedMpdus
1028 << std::endl;
1029 std::cout << "Total Successful MPDUs: " << statistics.m_receivedMpdus << std::endl;
1030 std::cout << "Total Failed MPDUs: " << statistics.m_failedMpdus << std::endl;
1031}
1032
1033void
1035{
1036 m_completedRecords.clear();
1037 m_records.clear();
1038}
1039
1040// Return a single vector with all completed records
1041void
1043{
1044 m_records.clear();
1045 for (const auto& nodeMap : m_completedRecords)
1046 {
1047 for (const auto& deviceMap : nodeMap.second)
1048 {
1049 for (const auto& linkMap : deviceMap.second)
1050 {
1051 for (const auto& wifiRecord : linkMap.second)
1052 {
1053 m_records.emplace_back(wifiRecord);
1054 }
1055 }
1056 }
1057 }
1058}
1059
1060const std::vector<WifiPpduRxRecord>&
1062{
1063 return m_records;
1064}
1065
1066std::optional<std::reference_wrapper<const std::vector<WifiPpduRxRecord>>>
1067WifiPhyRxTraceSink::GetPpduRecords(uint32_t nodeId, uint32_t deviceId, uint8_t linkId) const
1068{
1069 if (m_completedRecords.contains(nodeId))
1070 {
1071 if (m_completedRecords.at(nodeId).contains(deviceId))
1072 {
1073 if (m_completedRecords.at(nodeId).at(deviceId).contains(linkId))
1074 {
1075 return std::optional<std::reference_wrapper<const std::vector<WifiPpduRxRecord>>>(
1076 m_completedRecords.at(nodeId).at(deviceId).at(linkId));
1077 }
1078 }
1079 }
1080 return std::nullopt;
1081}
1082
1083} // namespace ns3
static Mac48Address ConvertFrom(const Address &address)
holds a vector of ns3::NetDevice pointers
uint32_t GetN() const
Get the number of Ptr<NetDevice> stored in this container.
Ptr< NetDevice > Get(uint32_t i) const
Get the Ptr<NetDevice> stored in this container at a given index.
keep track of a set of node pointers.
A base class which provides memory management and object aggregation.
Definition object.h:78
Smart pointer class similar to boost::intrusive_ptr.
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition simulator.h:560
static Time Now()
Return the current simulation virtual time.
Definition simulator.cc:197
Simulation virtual time values and global simulation resolution.
Definition nstime.h:94
TimeWithUnit As(const Unit unit=Time::AUTO) const
Attach a unit to a Time, to facilitate output in a specific unit.
Definition time.cc:404
@ S
second
Definition nstime.h:105
a unique identifier for an interface.
Definition type-id.h:48
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition type-id.cc:1001
Implements the IEEE 802.11 MAC header.
Mac48Address GetAddr1() const
Return the address in the Address 1 field.
virtual WifiMacType GetType() const
Return the type (WifiMacType)
bool IsData() const
Return true if the Type is DATA.
const std::vector< WifiPpduRxRecord > & GetPpduRecords() const
Accesses a vector of saved and completed PPDU reception records.
void PrintStatistics() const
Print statistics for all nodes, devices, and links during the collection period.
void Reset()
Resets the current statistics, clearing all counts and PPDU records.
Ptr< WifiPhyRxTraceSink > m_traceSink
Pointer to the current trace sink object.
void Stop(Time stopTime)
Stops the collection of statistics at a specified time.
WifiPhyTraceStatistics GetStatistics() const
Retrieves current statistics of successful and failed data PPDUs and MPDUs receptions,...
void Enable(NodeContainer nodes)
Enables trace collection for all nodes and WifiNetDevices in the specified NodeContainer.
std::map< Mac48Address, uint32_t > MapMacAddressesToNodeIds(NodeContainer nodes) const
Populates the mapping of MAC addresses to node IDs for a given set of nodes.
void Start(Time startTime)
Starts the collection of statistics from a specified start time.
std::set< uint64_t > usedTags
Set of already used tags.
uint64_t GenerateUniqueTag(uint64_t ppduUid)
Generates a unique tag for a WifiPpdu.
uint64_t counter
Counter to help generate unique tags.
Sink class for capturing and analyzing PHY layer reception events in Wi-Fi networks.
std::map< uint64_t, std::map< uint64_t, std::map< uint64_t, std::map< uint64_t, uint64_t > > > > m_nodeDeviceLinkPidToRxId
Aids in correlating PHY reception drops and outcomes with specific reception tags.
void Reset()
Resets the statistics collection, clearing all counts and discarding all fully completed PPDU records...
std::map< uint32_t, std::map< uint32_t, std::map< uint8_t, std::vector< WifiPpduRxRecord > > > > m_completedRecords
Stores records of PPDUs that have completed reception, organized by node, device, and link.
void CreateVectorFromRecords()
Creates a vector with all completed WiFi reception records to be returned by the GetPpduRecords().
void SpectrumPhySignalArrival(std::string context, Ptr< const SpectrumSignalParameters > signal, uint32_t senderNodeId, double rxPower, Time duration)
Handles the event of a PHY signal arrival from a SpectrumChannel.
const std::vector< WifiPpduRxRecord > & GetPpduRecords() const
Provides access to all saved and completed PPDU reception records across all nodes,...
bool m_statisticsCollectionPeriodStarted
Flag indicating whether to keep a record of certain statistics or events for analysis.
void Stop()
Stops the statistics collection period at a specified time.
WifiPhyTraceStatistics CountStatistics() const
Counts and aggregates PHY layer statistics including receptions, transmissions, and performance metri...
void PhyRxEnd(uint32_t nodeId, uint32_t deviceId, uint64_t rxTag, uint64_t ppduUid)
Handles the end of a PHY reception event, logging the conclusion of a reception and its associated de...
bool IsCollectionPeriodActive() const
Returns whether the collection period is active.
std::map< uint64_t, WifiPpduRxRecord > m_rxTagToPpduRecord
Maps a reception tag to the corresponding WifiPpduRxRecord.
std::map< Mac48Address, uint32_t > m_macAddressToNodeId
Maps MAC addresses to node IDs.
void PhyPpduDrop(std::string context, Ptr< const WifiPpdu > ppdu, WifiPhyRxfailureReason reason)
Logs the drop of a PPDU at the PHY layer, detailing the context and reason for the drop.
std::optional< std::pair< uint8_t, uint16_t > > GetChannelInfo(uint32_t node, uint32_t deviceId, int link) const
Retrieves the frequency and channel number used by a specific link.
std::vector< WifiPpduRxRecord > m_records
Stores a flat vector of all records of PPDUs that have completed reception.
void PhySignalTransmission(std::string context, Ptr< const WifiPpdu > ppdu, const WifiTxVector &txVector)
Handles the event of a PHY signal transmission.
void PrintStatistics() const
Prints a summary of the statistics collected, offering a concise overview of PHY layer performance an...
WifiPhyTraceStatistics GetStatistics() const
Returns statistics on the count of successful and failed PPDUs with unicast data, and their MPDUs,...
std::map< uint64_t, std::vector< WifiPpduRxRecord > > m_rxTagToListOfOverlappingPpduRecords
Maps each reception tag to a list of overlapping WifiPpduRxRecords.
std::string ContextToTuple(std::string context) const
Translate a context string to a colon-delimited tuple "0:0:0" where the first element is a node ID,...
void Start()
Starts the statistics collection period from a specified start time.
void PpduOutcome(std::string context, Ptr< const WifiPpdu > ppdu, RxSignalInfo signal, const WifiTxVector &txVector, const std::vector< bool > &statusPerMpdu)
Records the outcome of a PPDU transmission, including the signal info, and the success or failure sta...
std::map< uint32_t, std::map< uint32_t, std::map< uint32_t, std::vector< WifiPpduRxRecord > > > > m_nodeDeviceLinkRxRecords
Tracks ongoing frames being transmitted or received per node, device, and link.
void EndTx(uint32_t nodeId, uint32_t deviceId, WifiPpduRxRecord ppduRecord)
Handles the conclusion of a transmission event, facilitating the logging of transmission outcomes.
int ContextToDeviceId(std::string context) const
Translates a context string to a device ID, enabling the identification of devices involved in recept...
void CountStatisticsForRecord(WifiPhyTraceStatistics &statistics, const WifiPpduRxRecord &record) const
Update the passed-in statistics object with statistics from the passed-in record.
void PhySignalArrival(std::string context, Ptr< const WifiPpdu > ppdu, double rxPower, Time duration)
Handles the event of a Wi-Fi PPDU arrival.
UniqueTagGenerator m_tagGenerator
Instance of UniqueTagGenerator used for generating unique reception tags.
void SetMapMacAddressToNodeId(const std::map< Mac48Address, uint32_t > &MacAddressToNodeIdMap)
Provides a custom mapping of MAC addresses to intended receiver node IDs.
void UpdateCurrentlyReceivedSignal(uint32_t nodeId, uint32_t deviceId, uint8_t linkId)
Updates the information for signals currently being received by a node.
uint32_t ContextToNodeId(std::string context) const
Translates a context string to a node ID.
int ContextToLinkId(std::string context) const
Translates a context string to a link ID, facilitating the association of events with specific links ...
void MapNodeToLinkToChannel(NodeContainer nodes)
Maps nodes to links and channels, creating a structured association between network elements and thei...
std::map< uint32_t, std::map< uint32_t, std::map< int, std::pair< uint8_t, uint16_t > > > > m_nodeToDeviceToLinkToChannelInfo
Maps node IDs to device IDs and further to link IDs, associating each with a pair consisting of the c...
std::map< uint64_t, uint64_t > m_ppduUidToTxTag
Maps WifiPpdu UIDs to WifiPpduRxRecord tags stored by transmitter.
static TypeId GetTypeId()
Retrieves the TypeId of the class.
This class mimics the TXVECTOR which is to be passed to the PHY in order to define the parameters whi...
Time stopTime
#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_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
Definition abort.h:97
int64x64_t operator+(const int64x64_t &lhs, const int64x64_t &rhs)
Addition operator.
Definition int64x64.h:76
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition log.h:191
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition log.h:257
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
Definition log.h:264
Ptr< T > CreateObject(Args &&... args)
Create an object by type, with varying number of constructor parameters.
Definition object.h:619
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition object-base.h:35
WifiPhyRxfailureReason
Enumeration of the possible reception failure reasons.
NodeContainer nodes
Every class exported by the ns3 library is enclosed in the ns3 namespace.
U * PeekPointer(const Ptr< U > &p)
Definition ptr.h:443
bool operator!=(Callback< R, Args... > a, Callback< R, Args... > b)
Inequality test.
Definition callback.h:658
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
bool operator==(const EventId &a, const EventId &b)
Definition event-id.h:155
Ptr< T1 > DynamicCast(const Ptr< T2 > &p)
Cast a Ptr.
Definition ptr.h:580
bool operator<(const EventId &a, const EventId &b)
Definition event-id.h:168
@ WIFI_MAC_DATA
@ WIFI_MAC_QOSDATA
const uint32_t SHIFT
Number of places to shift WifiPpdu UID values, when generating unique IDs.
RxSignalInfo structure containing info on the received signal.
Definition wifi-types.h:72
Keeps track of PHY layer trace statistics.
std::map< WifiPhyRxfailureReason, uint64_t > m_ppduDropReasons
Counts of the drop reasons.
uint64_t m_failedMpdus
Number of failed unicast data MPDU receptions.
uint64_t m_failedPpdus
Number of failed PPDU receptions (with unicast data).
uint64_t m_receivedPpdus
Number of successfully received PPDUs (with unicast data).
uint64_t m_receivedMpdus
Number of successfully received unicast data MPDUs.
uint64_t m_overlappingPpdus
Number of PPDUs that overlapped in time with at least one other PPDU.
uint64_t m_nonOverlappingPpdus
Number of PPDUs that did not overlap in time with any other PPDU.
Structure recording a received PPDU (Physical Protocol Data Unit) in a Wi-Fi network.
Ptr< const WifiPpdu > m_ppdu
Pointer to the received PPDU.
double m_rssi
Received Signal Strength Indicator (RSSI) in dBm.
Time m_endTime
End time of the PPDU reception.
Time m_startTime
Start time of the PPDU reception.
uint8_t m_linkId
The link ID belonging to this record.
WifiPhyRxfailureReason m_reason
Reason for reception failure, if any.
uint32_t m_senderDeviceId
Device ID of Sender.
uint32_t m_senderId
Node ID of the sender.
std::vector< bool > m_statusPerMpdu
Reception status for each MPDU within the PPDU.
std::vector< WifiPpduRxRecord > m_overlappingPpdu
List of PPDUs that overlapped in time with this reception.
uint32_t m_receiverId
Node ID of the receiver.
uint64_t m_rxTag
Unique tag for the reception of this PPDU.