A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
phy-entity.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2020 Orange Labs
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 * Authors: Rediet <getachew.redieteab@orange.com>
7 * Sébastien Deronne <sebastien.deronne@gmail.com> (for logic ported from wifi-phy and
8 * spectrum-wifi-phy)
9 * Mathieu Lacage <mathieu.lacage@sophia.inria.fr> (for logic ported from wifi-phy)
10 */
11
12#include "phy-entity.h"
13
14#include "frame-capture-model.h"
15#include "interference-helper.h"
17#include "spectrum-wifi-phy.h"
18#include "wifi-psdu.h"
20#include "wifi-utils.h"
21
22#include "ns3/assert.h"
23#include "ns3/data-rate.h"
24#include "ns3/log.h"
25#include "ns3/packet.h"
26#include "ns3/simulator.h"
27
28#include <algorithm>
29
30#undef NS_LOG_APPEND_CONTEXT
31#define NS_LOG_APPEND_CONTEXT WIFI_PHY_NS_LOG_APPEND_CONTEXT(m_wifiPhy)
32
33namespace ns3
34{
35
36NS_LOG_COMPONENT_DEFINE("PhyEntity");
37
38std::ostream&
39operator<<(std::ostream& os, const PhyEntity::PhyRxFailureAction& action)
40{
41 switch (action)
42 {
43 case PhyEntity::DROP:
44 return (os << "DROP");
46 return (os << "ABORT");
48 return (os << "IGNORE");
49 default:
50 NS_FATAL_ERROR("Unknown action");
51 return (os << "unknown");
52 }
53}
54
55std::ostream&
56operator<<(std::ostream& os, const PhyEntity::PhyFieldRxStatus& status)
57{
58 if (status.isSuccess)
59 {
60 return os << "success";
61 }
62 else
63 {
64 return os << "failure (" << status.reason << "/" << status.actionIfFailure << ")";
65 }
66}
67
68/*******************************************************
69 * Abstract base class for PHY entities
70 *******************************************************/
71
73
80
81void
83{
84 NS_LOG_FUNCTION(this << wifiPhy);
85 m_wifiPhy = wifiPhy;
87}
88
89bool
91{
92 for (const auto& m : m_modeList)
93 {
94 if (m == mode)
95 {
96 return true;
97 }
98 }
99 return false;
100}
101
102uint8_t
104{
105 return m_modeList.size();
106}
107
109PhyEntity::GetMcs(uint8_t /* index */) const
110{
112 "This method should be used only for HtPhy and child classes. Use GetMode instead.");
113 return WifiMode();
114}
115
116bool
117PhyEntity::IsMcsSupported(uint8_t /* index */) const
118{
119 NS_ABORT_MSG("This method should be used only for HtPhy and child classes. Use IsModeSupported "
120 "instead.");
121 return false;
122}
123
124bool
126{
127 return false;
128}
129
130std::list<WifiMode>::const_iterator
132{
133 return m_modeList.begin();
134}
135
136std::list<WifiMode>::const_iterator
138{
139 return m_modeList.end();
140}
141
144{
145 NS_FATAL_ERROR("PPDU field is not a SIG field (no sense in retrieving the signaled mode) or is "
146 "unsupported: "
147 << field);
148 return WifiMode(); // should be overloaded
149}
150
153{
154 const auto& ppduFormats = GetPpduFormats();
155 const auto itPpdu = ppduFormats.find(preamble);
156 if (itPpdu != ppduFormats.end())
157 {
158 const auto itField = std::find(itPpdu->second.begin(), itPpdu->second.end(), currentField);
159 if (itField != itPpdu->second.end())
160 {
161 const auto itNextField = std::next(itField, 1);
162 if (itNextField != itPpdu->second.end())
163 {
164 return *(itNextField);
165 }
166 NS_FATAL_ERROR("No field after " << currentField << " for " << preamble
167 << " for the provided PPDU formats");
168 }
169 else
170 {
171 NS_FATAL_ERROR("Unsupported PPDU field " << currentField << " for " << preamble
172 << " for the provided PPDU formats");
173 }
174 }
175 else
176 {
177 NS_FATAL_ERROR("Unsupported preamble " << preamble << " for the provided PPDU formats");
178 }
179 return WifiPpduField::WIFI_PPDU_FIELD_PREAMBLE; // Silence compiler warning
180}
181
182Time
184{
185 if (field > WIFI_PPDU_FIELD_EHT_SIG)
186 {
187 NS_FATAL_ERROR("Unsupported PPDU field");
188 }
189 return Time(); // should be overloaded
190}
191
192Time
194{
195 Time duration;
196 for (uint8_t field = WIFI_PPDU_FIELD_PREAMBLE; field < WIFI_PPDU_FIELD_DATA; ++field)
197 {
198 duration += GetDuration(static_cast<WifiPpduField>(field), txVector);
199 }
200 return duration;
201}
202
205{
206 return WifiConstPsduMap({{SU_STA_ID, psdu}});
207}
208
211{
212 return ppdu->GetPsdu();
213}
214
216PhyEntity::GetPhyHeaderSections(const WifiTxVector& txVector, Time ppduStart) const
217{
219 WifiPpduField field = WIFI_PPDU_FIELD_PREAMBLE; // preamble always present
220 Time start = ppduStart;
221
222 while (field != WIFI_PPDU_FIELD_DATA)
223 {
224 Time duration = GetDuration(field, txVector);
225 map[field] = {{start, start + duration}, GetSigMode(field, txVector)};
226 // Move to next field
227 start += duration;
228 field = GetNextField(field, txVector.GetPreambleType());
229 }
230 return map;
231}
232
234PhyEntity::BuildPpdu(const WifiConstPsduMap& psdus, const WifiTxVector& txVector, Time ppduDuration)
235{
236 NS_LOG_FUNCTION(this << psdus << txVector << ppduDuration);
237 NS_FATAL_ERROR("This method is unsupported for the base PhyEntity class. Use the overloaded "
238 "version in the amendment-specific subclasses instead!");
239 return Create<WifiPpdu>(psdus.begin()->second,
240 txVector,
241 m_wifiPhy->GetOperatingChannel()); // should be overloaded
242}
243
244Time
246{
247 if (field ==
248 WIFI_PPDU_FIELD_DATA) // this field is not in the map returned by GetPhyHeaderSections
249 {
251 }
252 const auto& sections = GetPhyHeaderSections(txVector, Time());
253 auto it = sections.find(field);
254 NS_ASSERT(it != sections.end());
255 const auto& startStopTimes = it->second.first;
256 return startStopTimes
257 .first; // return the start time of field relatively to the beginning of the PPDU
258}
259
262{
263 const auto measurementChannelWidth = GetMeasurementChannelWidth(event->GetPpdu());
264 return m_wifiPhy->m_interference->CalculatePhyHeaderSnrPer(
265 event,
266 measurementChannelWidth,
267 GetPrimaryBand(measurementChannelWidth),
268 field);
269}
270
271void
273{
274 NS_LOG_FUNCTION(this << field << *event);
275 NS_ASSERT(m_wifiPhy); // no sense if no owner WifiPhy instance
278 "Use the StartReceivePreamble method for preamble reception");
279 // Handle special cases of data reception
280 if (field == WIFI_PPDU_FIELD_DATA)
281 {
282 StartReceivePayload(event);
283 return;
284 }
285
286 bool supported = DoStartReceiveField(field, event);
287 NS_ABORT_MSG_IF(!supported,
288 "Unknown field "
289 << field << " for this PHY entity"); // TODO see what to do if not supported
290 Time duration = GetDuration(field, event->GetPpdu()->GetTxVector());
292 Simulator::Schedule(duration, &PhyEntity::EndReceiveField, this, field, event);
294 event->GetPpdu(),
295 duration); // keep in CCA busy state up to reception of Data (will then switch to RX)
296}
297
298void
300{
301 NS_LOG_FUNCTION(this << field << *event);
302 NS_ASSERT(m_wifiPhy); // no sense if no owner WifiPhy instance
304 PhyFieldRxStatus status = DoEndReceiveField(field, event);
305 const auto& txVector = event->GetPpdu()->GetTxVector();
306 if (status.isSuccess) // move to next field if reception succeeded
307 {
308 StartReceiveField(GetNextField(field, txVector.GetPreambleType()), event);
309 }
310 else
311 {
312 Ptr<const WifiPpdu> ppdu = event->GetPpdu();
313 switch (status.actionIfFailure)
314 {
315 case ABORT:
316 // Abort reception, but consider medium as busy
318 if (event->GetEndTime() > (Simulator::Now() + m_state->GetDelayUntilIdle()))
319 {
321 }
322 break;
323 case DROP:
324 // Notify drop, keep in CCA busy, and perform same processing as IGNORE case
325 if (status.reason == FILTERED)
326 {
327 // PHY-RXSTART is immediately followed by PHY-RXEND (Filtered)
329 txVector,
330 NanoSeconds(0)); // this callback (equivalent to PHY-RXSTART primitive) is also
331 // triggered for filtered PPDUs
332 }
333 m_wifiPhy->NotifyRxPpduDrop(ppdu, status.reason);
335 // no break
336 case IGNORE:
337 // Keep in Rx state and reset at end
338 m_endRxPayloadEvents.push_back(
341 this,
342 event));
343 break;
344 default:
345 NS_FATAL_ERROR("Unknown action in case of failure");
346 }
347 }
348}
349
350Time
352{
353 const auto& txVector = ppdu->GetTxVector();
354 return ppdu->GetTxDuration() -
355 (GetDurationUpToField(field, txVector) + GetDuration(field, txVector));
356}
357
358bool
360{
361 NS_LOG_FUNCTION(this << field << *event);
363 field != WIFI_PPDU_FIELD_DATA); // handled apart for the time being
364 const auto& ppduFormats = GetPpduFormats();
365 auto itFormat = ppduFormats.find(event->GetPpdu()->GetPreamble());
366 if (itFormat != ppduFormats.end())
367 {
368 auto itField = std::find(itFormat->second.begin(), itFormat->second.end(), field);
369 if (itField != itFormat->second.end())
370 {
371 return true; // supported field so we can start receiving
372 }
373 }
374 return false; // unsupported otherwise
375}
376
379{
380 NS_LOG_FUNCTION(this << field << *event);
381 NS_ASSERT(field != WIFI_PPDU_FIELD_DATA); // handled apart for the time being
382 if (field == WIFI_PPDU_FIELD_PREAMBLE)
383 {
384 return DoEndReceivePreamble(event);
385 }
386 return PhyFieldRxStatus(false); // failed reception by default
387}
388
389void
391 RxPowerWattPerChannelBand& rxPowersW,
392 Time rxDuration)
393{
394 // The total RX power corresponds to the maximum over all the bands
395 auto it =
396 std::max_element(rxPowersW.begin(), rxPowersW.end(), [](const auto& p1, const auto& p2) {
397 return p1.second < p2.second;
398 });
399 NS_LOG_FUNCTION(this << ppdu << it->second);
400
401 auto event = DoGetEvent(ppdu, rxPowersW);
402 if (!event)
403 {
404 // PPDU should be simply considered as interference (once it has been accounted for in
405 // InterferenceHelper)
406 return;
407 }
408
409 Time endRx = Simulator::Now() + rxDuration;
410 if (ppdu->IsTruncatedTx())
411 {
412 NS_LOG_DEBUG("Packet reception stopped because transmitter has been switched off");
413 if (endRx > (Simulator::Now() + m_state->GetDelayUntilIdle()))
414 {
416 }
418 return;
419 }
420
421 switch (m_state->GetState())
422 {
424 NS_LOG_DEBUG("Drop packet because of channel switching");
425 /*
426 * Packets received on the upcoming channel are added to the event list
427 * during the switching state. This way the medium can be correctly sensed
428 * when the device listens to the channel for the first time after the
429 * switching e.g. after channel switching, the channel may be sensed as
430 * busy due to other devices' transmissions started before the end of
431 * the switching.
432 */
434 break;
435 case WifiPhyState::RX:
437 m_wifiPhy->m_frameCaptureModel->IsInCaptureWindow(
439 m_wifiPhy->m_frameCaptureModel->CaptureNewFrame(m_wifiPhy->m_currentEvent, event))
440 {
442 NS_LOG_DEBUG("Switch to new packet");
444 }
445 else
446 {
447 NS_LOG_DEBUG("Drop packet because already in Rx");
448 DropPreambleEvent(ppdu, RXING, endRx);
450 {
451 /*
452 * We are here because the non-legacy PHY header has not been successfully received.
453 * The PHY is kept in RX state for the duration of the PPDU, but EndReceive function
454 * is not called when the reception of the PPDU is finished, which is responsible to
455 * clear m_currentPreambleEvents. As a result, m_currentPreambleEvents should be
456 * cleared here.
457 */
459 }
460 }
461 break;
462 case WifiPhyState::TX:
463 NS_LOG_DEBUG("Drop packet because already in Tx");
464 DropPreambleEvent(ppdu, TXING, endRx);
465 break;
468 {
470 m_wifiPhy->m_frameCaptureModel->IsInCaptureWindow(
472 m_wifiPhy->m_frameCaptureModel->CaptureNewFrame(m_wifiPhy->m_currentEvent, event))
473 {
475 NS_LOG_DEBUG("Switch to new packet");
477 }
478 else
479 {
480 NS_LOG_DEBUG("Drop packet because already decoding preamble");
482 }
483 }
484 else
485 {
487 }
488 break;
492 break;
494 NS_LOG_DEBUG("Drop packet because in sleep mode");
495 DropPreambleEvent(ppdu, SLEEPING, endRx);
496 break;
498 NS_LOG_DEBUG("Drop packet because in switched off");
500 break;
501 default:
502 NS_FATAL_ERROR("Invalid WifiPhy state.");
503 break;
504 }
505}
506
507void
509{
510 NS_LOG_FUNCTION(this << ppdu << reason << endRx);
511 m_wifiPhy->NotifyRxPpduDrop(ppdu, reason);
512 auto it = m_wifiPhy->m_currentPreambleEvents.find({ppdu->GetUid(), ppdu->GetPreamble()});
513 if (it != m_wifiPhy->m_currentPreambleEvents.end())
514 {
516 }
518 (endRx > (Simulator::Now() + m_state->GetDelayUntilIdle())))
519 {
520 // that PPDU will be noise _after_ the end of the current event.
522 }
523}
524
525void
527{
528 NS_LOG_FUNCTION(this << ppdu << rxDuration);
529 auto it = m_wifiPhy->m_currentPreambleEvents.find({ppdu->GetUid(), ppdu->GetPreamble()});
530 if (it != m_wifiPhy->m_currentPreambleEvents.end())
531 {
533 }
535 {
536 m_wifiPhy->Reset();
537 }
538
539 if (rxDuration > m_state->GetDelayUntilIdle())
540 {
541 // this PPDU will be noise _after_ the completion of the current event
543 }
544}
545
546uint16_t
548{
549 return SU_STA_ID;
550}
551
552void
554{
555 NS_LOG_FUNCTION(this << *event);
557
558 Time payloadDuration = DoStartReceivePayload(event);
559 m_state->SwitchToRx(payloadDuration);
560}
561
562Time
564{
565 NS_LOG_FUNCTION(this << *event);
566 Ptr<const WifiPpdu> ppdu = event->GetPpdu();
567 NS_LOG_DEBUG("Receiving PSDU");
568 uint16_t staId = GetStaId(ppdu);
569 m_signalNoiseMap.insert({{ppdu->GetUid(), staId}, SignalNoiseDbm()});
570 m_statusPerMpduMap.insert({{ppdu->GetUid(), staId}, std::vector<bool>()});
571 ScheduleEndOfMpdus(event);
572 const auto& txVector = event->GetPpdu()->GetTxVector();
573 Time payloadDuration = ppdu->GetTxDuration() - CalculatePhyPreambleAndHeaderDuration(txVector);
575 txVector,
576 payloadDuration); // this callback (equivalent to PHY-RXSTART primitive) is triggered only
577 // if headers have been correctly decoded and that the mode within is
578 // supported
579 m_endRxPayloadEvents.push_back(
580 Simulator::Schedule(payloadDuration, &PhyEntity::EndReceivePayload, this, event));
581 return payloadDuration;
582}
583
584void
586{
587 NS_LOG_FUNCTION(this << *event);
588 Ptr<const WifiPpdu> ppdu = event->GetPpdu();
590 const auto& txVector = event->GetPpdu()->GetTxVector();
591 uint16_t staId = GetStaId(ppdu);
592 Time endOfMpduDuration;
593 Time relativeStart;
594 Time psduDuration = ppdu->GetTxDuration() - CalculatePhyPreambleAndHeaderDuration(txVector);
595 Time remainingAmpduDuration = psduDuration;
596 size_t nMpdus = psdu->GetNMpdus();
597 MpduType mpduType =
598 (nMpdus > 1) ? FIRST_MPDU_IN_AGGREGATE : (psdu->IsSingle() ? SINGLE_MPDU : NORMAL_MPDU);
599 uint32_t totalAmpduSize = 0;
600 double totalAmpduNumSymbols = 0.0;
601 auto mpdu = psdu->begin();
602 for (size_t i = 0; i < nMpdus && mpdu != psdu->end(); ++mpdu)
603 {
605 {
606 // calculate MAC header size (including A-MPDU subframe header, if present)
607 auto macHdrSize =
608 (*mpdu)->GetHeader().GetSerializedSize() + (mpduType == NORMAL_MPDU ? 0 : 4);
609 // calculate the (approximate) duration of the MAC header TX
610 auto macHdrDuration = DataRate(txVector.GetMode(staId).GetDataRate(txVector, staId))
611 .CalculateBytesTxTime(macHdrSize);
612 const auto widthBand = GetChannelWidthAndBand(txVector, staId);
613 const auto snrPer = m_wifiPhy->m_interference->CalculatePayloadSnrPer(
614 event,
615 widthBand.first,
616 widthBand.second,
617 staId,
618 {relativeStart, relativeStart + macHdrDuration});
619 if (GetRandomValue() > snrPer.per)
620 {
621 // interference level should permit to correctly decode the MAC header
622 m_endOfMacHdrEvents.push_back(
623 Simulator::Schedule(endOfMpduDuration + macHdrDuration, [=, this]() {
624 m_wifiPhy->m_phyRxMacHeaderEndTrace((*mpdu)->GetHeader(),
625 txVector,
626 remainingAmpduDuration -
627 macHdrDuration);
628 }));
629 }
630 }
631
632 uint32_t size = (mpduType == NORMAL_MPDU) ? psdu->GetSize() : psdu->GetAmpduSubframeSize(i);
633 Time mpduDuration = m_wifiPhy->GetPayloadDuration(size,
634 txVector,
636 mpduType,
637 true,
638 totalAmpduSize,
639 totalAmpduNumSymbols,
640 staId);
641
642 remainingAmpduDuration -= mpduDuration;
643 if (i == (nMpdus - 1) && !remainingAmpduDuration.IsZero()) // no more MPDUs coming
644 {
645 if (remainingAmpduDuration < txVector.GetGuardInterval()) // enables to ignore padding
646 {
647 mpduDuration += remainingAmpduDuration; // apply a correction just in case rounding
648 // had induced slight shift
649 }
650 }
651
652 endOfMpduDuration += mpduDuration;
653 NS_LOG_INFO("Schedule end of MPDU #"
654 << i << " in " << endOfMpduDuration.As(Time::NS) << " (relativeStart="
655 << relativeStart.As(Time::NS) << ", mpduDuration=" << mpduDuration.As(Time::NS)
656 << ", remainingAmdpuDuration=" << remainingAmpduDuration.As(Time::NS) << ")");
657 m_endOfMpduEvents.push_back(Simulator::Schedule(endOfMpduDuration,
659 this,
660 event,
661 *mpdu,
662 i,
663 relativeStart,
664 mpduDuration));
665
666 // Prepare next iteration
667 ++i;
668 relativeStart += mpduDuration;
669 mpduType = (i == (nMpdus - 1)) ? LAST_MPDU_IN_AGGREGATE : MIDDLE_MPDU_IN_AGGREGATE;
670 }
671}
672
673void
675 Ptr<WifiMpdu> mpdu,
676 size_t mpduIndex,
677 Time relativeStart,
678 Time mpduDuration)
679{
680 NS_LOG_FUNCTION(this << *event << mpduIndex << relativeStart << mpduDuration);
681 const auto ppdu = event->GetPpdu();
682 const auto& txVector = ppdu->GetTxVector();
683 uint16_t staId = GetStaId(ppdu);
684
685 std::pair<bool, SignalNoiseDbm> rxInfo =
686 GetReceptionStatus(mpdu, event, staId, relativeStart, mpduDuration);
687 NS_LOG_DEBUG("Extracted MPDU #" << mpduIndex << ": duration: " << mpduDuration.As(Time::NS)
688 << ", correct reception: " << rxInfo.first << ", Signal/Noise: "
689 << rxInfo.second.signal << "/" << rxInfo.second.noise << "dBm");
690
691 auto signalNoiseIt = m_signalNoiseMap.find({ppdu->GetUid(), staId});
692 NS_ASSERT(signalNoiseIt != m_signalNoiseMap.end());
693 signalNoiseIt->second = rxInfo.second;
694
695 RxSignalInfo rxSignalInfo;
696 rxSignalInfo.snr = DbToRatio(rxInfo.second.signal - rxInfo.second.noise);
697 rxSignalInfo.rssi = rxInfo.second.signal;
698
699 auto statusPerMpduIt = m_statusPerMpduMap.find({ppdu->GetUid(), staId});
700 NS_ASSERT(statusPerMpduIt != m_statusPerMpduMap.end());
701 statusPerMpduIt->second.push_back(rxInfo.first);
702
703 if (rxInfo.first && GetAddressedPsduInPpdu(ppdu)->GetNMpdus() > 1)
704 {
705 // only done for correct MPDU that is part of an A-MPDU
706 m_state->NotifyRxMpdu(Create<const WifiPsdu>(mpdu, false), rxSignalInfo, txVector);
707 }
708}
709
710void
712{
713 const auto ppdu = event->GetPpdu();
714 const auto& txVector = ppdu->GetTxVector();
716 this << *event << ppdu->GetTxDuration() - CalculatePhyPreambleAndHeaderDuration(txVector));
717 NS_ASSERT(event->GetEndTime() == Simulator::Now());
718 const auto staId = GetStaId(ppdu);
719 const auto channelWidthAndBand = GetChannelWidthAndBand(txVector, staId);
720 const auto snr = m_wifiPhy->m_interference->CalculateSnr(event,
721 channelWidthAndBand.first,
722 txVector.GetNss(staId),
723 channelWidthAndBand.second);
724
726 m_wifiPhy->NotifyRxEnd(psdu);
727
728 auto signalNoiseIt = m_signalNoiseMap.find({ppdu->GetUid(), staId});
729 NS_ASSERT(signalNoiseIt != m_signalNoiseMap.end());
730 auto statusPerMpduIt = m_statusPerMpduMap.find({ppdu->GetUid(), staId});
731 NS_ASSERT(statusPerMpduIt != m_statusPerMpduMap.end());
732 // store per-MPDU status, which is cleared by the call to DoEndReceivePayload below
733 auto statusPerMpdu = statusPerMpduIt->second;
734
735 RxSignalInfo rxSignalInfo;
736 bool success;
737
738 if (std::count(statusPerMpdu.cbegin(), statusPerMpdu.cend(), true))
739 {
740 // At least one MPDU has been successfully received
743 txVector,
744 signalNoiseIt->second,
745 statusPerMpdu,
746 staId);
747 rxSignalInfo.snr = snr;
748 rxSignalInfo.rssi = signalNoiseIt->second.signal; // same information for all MPDUs
749 RxPayloadSucceeded(psdu, rxSignalInfo, txVector, staId, statusPerMpdu);
751 ppdu->GetUid(); // store UID only if reception is successful (because otherwise trigger
752 // won't be read by MAC layer)
753 success = true;
754 }
755 else
756 {
757 RxPayloadFailed(psdu, snr, txVector);
758 success = false;
759 }
760
761 m_state->NotifyRxPpduOutcome(ppdu, rxSignalInfo, txVector, staId, statusPerMpduIt->second);
764
765 // notify the MAC through the PHY state helper as the last action. Indeed, the notification
766 // of the RX end may lead the MAC to request a PHY state change (e.g., channel switch, sleep).
767 // Hence, all actions the PHY has to perform when RX ends should be completed before
768 // notifying the MAC.
769 success ? m_state->NotifyRxPsduSucceeded(psdu, rxSignalInfo, txVector, staId, statusPerMpdu)
770 : m_state->NotifyRxPsduFailed(psdu, snr);
771}
772
773void
775 RxSignalInfo rxSignalInfo,
776 const WifiTxVector& txVector,
777 uint16_t staId,
778 const std::vector<bool>& statusPerMpdu)
779{
780 NS_LOG_FUNCTION(this << *psdu << txVector);
781 m_state->SwitchFromRxEndOk();
782}
783
784void
786{
787 NS_LOG_FUNCTION(this << *psdu << txVector << snr);
788 m_state->SwitchFromRxEndError();
789}
790
791void
802
803std::pair<bool, SignalNoiseDbm>
805 Ptr<Event> event,
806 uint16_t staId,
807 Time relativeMpduStart,
808 Time mpduDuration)
809{
810 NS_LOG_FUNCTION(this << *mpdu << *event << staId << relativeMpduStart << mpduDuration);
811 const auto channelWidthAndBand = GetChannelWidthAndBand(event->GetPpdu()->GetTxVector(), staId);
812 SnrPer snrPer = m_wifiPhy->m_interference->CalculatePayloadSnrPer(
813 event,
814 channelWidthAndBand.first,
815 channelWidthAndBand.second,
816 staId,
817 {relativeMpduStart, relativeMpduStart + mpduDuration});
818
819 WifiMode mode = event->GetPpdu()->GetTxVector().GetMode(staId);
820 NS_LOG_DEBUG("rate=" << (mode.GetDataRate(event->GetPpdu()->GetTxVector(), staId))
821 << ", SNR(dB)=" << RatioToDb(snrPer.snr) << ", PER=" << snrPer.per
822 << ", size=" << mpdu->GetSize()
823 << ", relativeStart = " << relativeMpduStart.As(Time::NS)
824 << ", duration = " << mpduDuration.As(Time::NS));
825
826 // There are two error checks: PER and receive error model check.
827 // PER check models is typical for Wi-Fi and is based on signal modulation;
828 // Receive error model is optional, if we have an error model and
829 // it indicates that the packet is corrupt, drop the packet.
830 SignalNoiseDbm signalNoise;
831 signalNoise.signal = WToDbm(event->GetRxPower(channelWidthAndBand.second));
832 signalNoise.noise = WToDbm(event->GetRxPower(channelWidthAndBand.second) / snrPer.snr);
833 if (GetRandomValue() > snrPer.per &&
835 m_wifiPhy->m_postReceptionErrorModel->IsCorrupt(mpdu->GetPacket()->Copy())))
836 {
837 NS_LOG_DEBUG("Reception succeeded: " << *mpdu);
838 return {true, signalNoise};
839 }
840 else
841 {
842 NS_LOG_DEBUG("Reception failed: " << *mpdu);
843 return {false, signalNoise};
844 }
845}
846
847std::pair<MHz_u, WifiSpectrumBandInfo>
848PhyEntity::GetChannelWidthAndBand(const WifiTxVector& txVector, uint16_t /* staId */) const
849{
850 const auto channelWidth = GetRxChannelWidth(txVector);
851 return {channelWidth, GetPrimaryBand(channelWidth)};
852}
853
854const std::map<std::pair<uint64_t, WifiPreamble>, Ptr<Event>>&
859
860void
862{
863 NS_LOG_FUNCTION(this << *event);
864 Ptr<const WifiPpdu> ppdu = event->GetPpdu();
865 m_wifiPhy->m_currentPreambleEvents.insert({{ppdu->GetUid(), ppdu->GetPreamble()}, event});
866}
867
870{
871 // We store all incoming preamble events, and a decision is made at the end of the preamble
872 // detection window.
873 const auto& currentPreambleEvents = GetCurrentPreambleEvents();
874 const auto it = currentPreambleEvents.find({ppdu->GetUid(), ppdu->GetPreamble()});
875 if (it != currentPreambleEvents.cend())
876 {
877 // received another signal with the same content
878 NS_LOG_DEBUG("Received another PPDU for UID " << ppdu->GetUid());
879 const auto foundEvent = it->second;
880 HandleRxPpduWithSameContent(foundEvent, ppdu, rxPowersW);
881 return nullptr;
882 }
883
884 auto event = CreateInterferenceEvent(ppdu, ppdu->GetTxDuration(), rxPowersW);
885 AddPreambleEvent(event);
886 return event;
887}
888
891 Time duration,
893 bool isStartHePortionRxing /* = false */)
894{
895 return m_wifiPhy->m_interference->Add(ppdu,
896 duration,
897 rxPower,
899 isStartHePortionRxing);
900}
901
902void
906{
907 if (const auto maxDelay =
908 m_wifiPhy->GetPhyEntityForPpdu(ppdu)->GetMaxDelayPpduSameUid(ppdu->GetTxVector());
909 Simulator::Now() - event->GetStartTime() > maxDelay)
910 {
911 // This PPDU arrived too late to be decoded properly. The PPDU is dropped and added as
912 // interference
913 event = CreateInterferenceEvent(ppdu, ppdu->GetTxDuration(), rxPower);
914 NS_LOG_DEBUG("Drop PPDU that arrived too late");
916 return;
917 }
918
919 // Update received power and TXVECTOR of the event associated to that transmission upon
920 // reception of a signal adding up constructively (in case of a UL MU PPDU or non-HT duplicate
921 // PPDU)
922 m_wifiPhy->m_interference->UpdateEvent(event, rxPower);
923 const auto& txVector = ppdu->GetTxVector();
924 const auto& eventTxVector = event->GetPpdu()->GetTxVector();
925 auto updatedTxVector{eventTxVector};
926 updatedTxVector.SetChannelWidth(
927 std::max(eventTxVector.GetChannelWidth(), txVector.GetChannelWidth()));
928 if (updatedTxVector.GetChannelWidth() != eventTxVector.GetChannelWidth())
929 {
930 event->UpdatePpdu(ppdu);
931 }
932}
933
934void
936{
938 m_signalNoiseMap.clear();
939 m_statusPerMpduMap.clear();
940 for (const auto& endOfMpduEvent : m_endOfMpduEvents)
941 {
942 NS_ASSERT(endOfMpduEvent.IsExpired());
943 }
944 m_endOfMpduEvents.clear();
945 for (const auto& endOfMacHdrEvent : m_endOfMacHdrEvents)
946 {
947 NS_ASSERT(endOfMacHdrEvent.IsExpired());
948 }
949 m_endOfMacHdrEvents.clear();
950 if (reset)
951 {
952 m_wifiPhy->Reset();
953 }
954}
955
958{
959 NS_LOG_FUNCTION(this << *event);
961 1); // Synched on one after detection period
962 return PhyFieldRxStatus(true); // always consider that preamble has been correctly received if
963 // preamble detection was OK
964}
965
966void
968{
969 NS_LOG_FUNCTION(this << *event);
970 const auto rxPower = GetRxPowerForPpdu(event);
971 NS_LOG_DEBUG("Sync to signal (power=" << (rxPower > 0.0
972 ? std::to_string(WToDbm(rxPower)) + "dBm)"
973 : std::to_string(rxPower) + "W)"));
974 m_wifiPhy->m_interference->NotifyRxStart(
975 m_wifiPhy->GetCurrentFrequencyRange()); // We need to notify it now so that it starts
976 // recording events
980 this,
981 event));
982}
983
984void
986{
987 NS_LOG_FUNCTION(this << *event);
989 NS_ASSERT(m_wifiPhy->m_endPhyRxEvent.IsExpired()); // since end of preamble reception is
990 // scheduled by this method upon success
991
992 // calculate PER on the measurement channel for PHY headers
993 const auto measurementChannelWidth = GetMeasurementChannelWidth(event->GetPpdu());
994 auto measurementBand = GetPrimaryBand(measurementChannelWidth);
995 std::optional<Watt_u>
996 maxRxPower; // in case current event may not be sent on measurement channel
997 Ptr<Event> maxEvent;
999 for (auto preambleEvent : m_wifiPhy->m_currentPreambleEvents)
1000 {
1001 const auto rxPower = preambleEvent.second->GetRxPower(measurementBand);
1002 if (!maxRxPower || (rxPower > *maxRxPower))
1003 {
1004 maxRxPower = rxPower;
1005 maxEvent = preambleEvent.second;
1006 }
1007 }
1008
1009 NS_ASSERT(maxEvent);
1010 if (maxEvent != event)
1011 {
1012 NS_LOG_DEBUG("Receiver got a stronger packet with UID "
1013 << maxEvent->GetPpdu()->GetUid()
1014 << " during preamble detection: drop packet with UID "
1015 << event->GetPpdu()->GetUid());
1017
1018 auto it = m_wifiPhy->m_currentPreambleEvents.find(
1019 {event->GetPpdu()->GetUid(), event->GetPpdu()->GetPreamble()});
1021 // This is needed to cleanup the m_firstPowerPerBand so that the first power corresponds to
1022 // the power at the start of the PPDU
1023 m_wifiPhy->m_interference->NotifyRxEnd(maxEvent->GetStartTime(),
1025 // Make sure InterferenceHelper keeps recording events
1027 return;
1028 }
1029
1030 m_wifiPhy->m_currentEvent = event;
1031
1032 const auto snr = m_wifiPhy->m_interference->CalculateSnr(m_wifiPhy->m_currentEvent,
1033 measurementChannelWidth,
1034 1,
1035 measurementBand);
1036 NS_LOG_DEBUG("SNR(dB)=" << RatioToDb(snr) << " at end of preamble detection period");
1037
1038 if (const auto power = m_wifiPhy->m_currentEvent->GetRxPower(measurementBand);
1039 (!m_wifiPhy->m_preambleDetectionModel && maxRxPower && (*maxRxPower > 0.0)) ||
1040 (m_wifiPhy->m_preambleDetectionModel && power > 0.0 &&
1041 m_wifiPhy->m_preambleDetectionModel->IsPreambleDetected(WToDbm(power),
1042 snr,
1043 measurementChannelWidth)))
1044 {
1045 // A bit convoluted but it enables to sync all PHYs
1046 for (auto& it : m_wifiPhy->m_phyEntities)
1047 {
1048 it.second->CancelRunningEndPreambleDetectionEvents();
1049 }
1050
1051 for (auto it = m_wifiPhy->m_currentPreambleEvents.begin();
1052 it != m_wifiPhy->m_currentPreambleEvents.end();)
1053 {
1054 if (it->second != m_wifiPhy->m_currentEvent)
1055 {
1056 NS_LOG_DEBUG("Drop packet with UID " << it->first.first << " and preamble "
1057 << it->first.second << " arrived at time "
1058 << it->second->GetStartTime());
1060 if (m_wifiPhy->m_currentEvent->GetPpdu()->GetUid() > it->first.first)
1061 {
1063 // This is needed to cleanup the m_firstPowerPerBand so that the first power
1064 // corresponds to the power at the start of the PPDU
1065 m_wifiPhy->m_interference->NotifyRxEnd(
1066 m_wifiPhy->m_currentEvent->GetStartTime(),
1068 }
1069 else
1070 {
1071 reason = BUSY_DECODING_PREAMBLE;
1072 }
1073 m_wifiPhy->NotifyRxPpduDrop(it->second->GetPpdu(), reason);
1074
1075 it = m_wifiPhy->m_currentPreambleEvents.erase(it);
1076 }
1077 else
1078 {
1079 ++it;
1080 }
1081 }
1082
1083 // Make sure InterferenceHelper keeps recording events
1085
1087 m_wifiPhy->m_currentEvent->GetRxPowerPerBand());
1089
1090 // Continue receiving preamble
1091 const auto durationTillEnd =
1092 GetDuration(WIFI_PPDU_FIELD_PREAMBLE, event->GetPpdu()->GetTxVector()) -
1094 m_wifiPhy->NotifyCcaBusy(event->GetPpdu(),
1095 durationTillEnd); // will be prolonged by next field
1098 this,
1100 event);
1101 }
1102 else
1103 {
1104 NS_LOG_DEBUG("Drop packet because PHY preamble detection failed");
1105 // Like CCA-SD, CCA-ED is governed by the 4 us CCA window to flag CCA-BUSY
1106 // for any received signal greater than the CCA-ED threshold.
1109 m_wifiPhy->m_currentEvent->GetEndTime());
1111 {
1112 // Do not erase events if there are still pending preamble events to be processed
1113 m_wifiPhy->m_interference->NotifyRxEnd(Simulator::Now(),
1115 }
1116 m_wifiPhy->m_currentEvent = nullptr;
1117 // Cancel preamble reception
1119 }
1120}
1121
1122bool
1124{
1125 WifiMode txMode = ppdu->GetTxVector().GetMode();
1126 if (!IsModeSupported(txMode))
1127 {
1128 NS_LOG_DEBUG("Drop packet because it was sent using an unsupported mode (" << txMode
1129 << ")");
1130 return false;
1131 }
1132 return true;
1133}
1134
1135void
1137{
1138 NS_LOG_FUNCTION(this);
1140 for (auto& endRxPayloadEvent : m_endRxPayloadEvents)
1141 {
1142 endRxPayloadEvent.Cancel();
1143 }
1144 m_endRxPayloadEvents.clear();
1145 for (auto& endMpduEvent : m_endOfMpduEvents)
1146 {
1147 endMpduEvent.Cancel();
1148 }
1149 m_endOfMpduEvents.clear();
1150 for (auto& endMacHdrEvent : m_endOfMacHdrEvents)
1151 {
1152 endMacHdrEvent.Cancel();
1153 }
1154 m_endOfMacHdrEvents.clear();
1155}
1156
1157bool
1162
1163void
1165{
1166 NS_LOG_FUNCTION(this);
1167 for (auto& endPreambleDetectionEvent : m_endPreambleDetectionEvents)
1168 {
1169 endPreambleDetectionEvent.Cancel();
1170 }
1172}
1173
1174void
1181
1182void
1184{
1185 NS_LOG_FUNCTION(this << reason);
1186 if (m_wifiPhy->m_currentEvent) // Otherwise abort has already been called just before
1187 {
1188 for (auto& endMpduEvent : m_endOfMpduEvents)
1189 {
1190 endMpduEvent.Cancel();
1191 }
1192 m_endOfMpduEvents.clear();
1193 for (auto& endMacHdrEvent : m_endOfMacHdrEvents)
1194 {
1195 endMacHdrEvent.Cancel();
1196 }
1197 m_endOfMacHdrEvents.clear();
1198 }
1199}
1200
1201void
1203{
1204 NS_LOG_FUNCTION(this << *event);
1205 DoResetReceive(event);
1208 NS_ASSERT(m_endRxPayloadEvents.size() == 1 && m_endRxPayloadEvents.front().IsExpired());
1209 m_endRxPayloadEvents.clear();
1210 m_wifiPhy->m_currentEvent = nullptr;
1212 m_wifiPhy->SwitchMaybeToCcaBusy(event->GetPpdu());
1213}
1214
1215void
1217{
1218 NS_LOG_FUNCTION(this << *event);
1219 NS_ASSERT(event->GetEndTime() == Simulator::Now());
1220}
1221
1222double
1224{
1225 return m_wifiPhy->m_random->GetValue();
1226}
1227
1228Watt_u
1230{
1231 return event->GetRxPower(GetPrimaryBand(GetMeasurementChannelWidth(event->GetPpdu())));
1232}
1233
1236{
1237 return m_wifiPhy->m_currentEvent;
1238}
1239
1242{
1243 if (static_cast<uint16_t>(m_wifiPhy->GetChannelWidth()) % 20 != 0)
1244 {
1245 return m_wifiPhy->GetBand(bandWidth);
1246 }
1247 return m_wifiPhy->GetBand(bandWidth,
1249}
1250
1253{
1255 return m_wifiPhy->GetBand(bandWidth,
1257}
1258
1259MHz_u
1261{
1262 return std::min(m_wifiPhy->GetChannelWidth(), txVector.GetChannelWidth());
1263}
1264
1265dBm_u
1267 WifiChannelListType /*channelType*/) const
1268{
1270}
1271
1272Time
1274{
1275 return m_wifiPhy->m_interference->GetEnergyDuration(DbmToW(threshold), band);
1276}
1277
1278void
1280{
1281 // We are here because we have received the first bit of a packet and we are
1282 // not going to be able to synchronize on it
1283 // In this model, CCA becomes busy when the aggregation of all signals as
1284 // tracked by the InterferenceHelper class is higher than the CcaBusyThreshold
1285 const auto ccaIndication = GetCcaIndication(ppdu);
1286 if (ccaIndication.has_value())
1287 {
1288 NS_LOG_DEBUG("CCA busy for " << ccaIndication.value().second << " during "
1289 << ccaIndication.value().first.As(Time::S));
1290 m_state->SwitchMaybeToCcaBusy(ccaIndication.value().first,
1291 ccaIndication.value().second,
1292 {});
1293 return;
1294 }
1295 if (ppdu)
1296 {
1297 SwitchMaybeToCcaBusy(nullptr);
1298 }
1299}
1300
1303{
1304 const auto channelWidth = GetMeasurementChannelWidth(ppdu);
1305 NS_LOG_FUNCTION(this << channelWidth);
1306 const auto ccaThreshold = GetCcaThreshold(ppdu, WIFI_CHANLIST_PRIMARY);
1307 const Time delayUntilCcaEnd = GetDelayUntilCcaEnd(ccaThreshold, GetPrimaryBand(channelWidth));
1308 if (delayUntilCcaEnd.IsStrictlyPositive())
1309 {
1310 return std::make_pair(delayUntilCcaEnd, WIFI_CHANLIST_PRIMARY);
1311 }
1312 return std::nullopt;
1313}
1314
1315void
1317 Time duration,
1318 WifiChannelListType channelType)
1319{
1320 NS_LOG_FUNCTION(this << duration << channelType);
1321 NS_LOG_DEBUG("CCA busy for " << channelType << " during " << duration.As(Time::S));
1322 m_state->SwitchMaybeToCcaBusy(duration, channelType, {});
1323}
1324
1325uint64_t
1327{
1328 NS_LOG_FUNCTION(this);
1329 return m_globalPpduUid++;
1330}
1331
1332Time
1334{
1335 return Seconds(0);
1336}
1337
1338void
1339PhyEntity::NotifyPayloadBegin(const WifiTxVector& txVector, const Time& payloadDuration)
1340{
1341 m_wifiPhy->m_phyRxPayloadBeginTrace(txVector, payloadDuration);
1342}
1343
1344void
1346{
1347 NS_LOG_FUNCTION(this << ppdu);
1348 auto txPowerDbm = m_wifiPhy->GetTxPowerForTransmission(ppdu) + m_wifiPhy->GetTxGain();
1349 auto txVector = ppdu->GetTxVector();
1350 auto txPowerSpectrum = GetTxPowerSpectralDensity(DbmToW(txPowerDbm), ppdu);
1351 Transmit(ppdu->GetTxDuration(), ppdu, txPowerDbm, txPowerSpectrum, "transmission");
1352}
1353
1354void
1357 dBm_u txPower,
1358 Ptr<SpectrumValue> txPowerSpectrum,
1359 const std::string& type)
1360{
1361 NS_LOG_FUNCTION(this << txDuration << ppdu << txPower << type);
1362 NS_LOG_DEBUG("Start " << type << ": signal power before antenna gain=" << txPower << "dBm");
1363 auto txParams = Create<WifiSpectrumSignalParameters>();
1364 txParams->duration = txDuration;
1365 txParams->psd = txPowerSpectrum;
1366 txParams->ppdu = ppdu;
1367 NS_LOG_DEBUG("Starting " << type << " with power " << txPower << " dBm on channel "
1368 << +m_wifiPhy->GetChannelNumber() << " for "
1369 << txParams->duration.As(Time::MS));
1370 NS_LOG_DEBUG("Starting " << type << " with integrated spectrum power "
1371 << WToDbm(Integral(*txPowerSpectrum)) << " dBm; spectrum model Uid: "
1372 << txPowerSpectrum->GetSpectrumModel()->GetUid());
1373 auto spectrumWifiPhy = DynamicCast<SpectrumWifiPhy>(m_wifiPhy);
1374 NS_ASSERT(spectrumWifiPhy);
1375 spectrumWifiPhy->Transmit(txParams);
1376}
1377
1378MHz_u
1379PhyEntity::GetGuardBandwidth(MHz_u currentChannelWidth) const
1380{
1381 return m_wifiPhy->GetGuardBandwidth(currentChannelWidth);
1382}
1383
1384std::tuple<dBr_u, dBr_u, dBr_u>
1389
1390Time
1392 const WifiTxVector& txVector,
1393 WifiPhyBand band) const
1394{
1395 NS_ASSERT(psduMap.size() == 1);
1396 const auto& it = psduMap.begin();
1397 return WifiPhy::CalculateTxDuration(it->second->GetSize(), txVector, band, it->first);
1398}
1399
1400bool
1402{
1403 // The PHY shall not issue a PHY-RXSTART.indication primitive in response to a PPDU that does
1404 // not overlap the primary channel
1405 const auto channelWidth = m_wifiPhy->GetChannelWidth();
1406 const auto primaryWidth = ((static_cast<uint16_t>(channelWidth) % 20 == 0)
1407 ? 20
1408 : channelWidth); // if the channel width is a multiple of 20 MHz,
1409 // then we consider the primary20 channel
1410 const auto p20CenterFreq =
1412 const uint16_t p20MinFreq = p20CenterFreq - (primaryWidth / 2);
1413 const uint16_t p20MaxFreq = p20CenterFreq + (primaryWidth / 2);
1414 const auto txChannelWidth = (ppdu->GetTxChannelWidth() / ppdu->GetTxCenterFreqs().size());
1415 for (auto txCenterFreq : ppdu->GetTxCenterFreqs())
1416 {
1417 const uint16_t minTxFreq = txCenterFreq - txChannelWidth / 2;
1418 const uint16_t maxTxFreq = txCenterFreq + txChannelWidth / 2;
1419 if ((p20MinFreq >= minTxFreq) && (p20MaxFreq <= maxTxFreq))
1420 {
1421 return true;
1422 }
1423 }
1424 return false;
1425}
1426
1429{
1430 return ppdu;
1431}
1432
1433} // namespace ns3
Class for representing data rates.
Definition data-rate.h:78
Time CalculateBytesTxTime(uint32_t bytes) const
Calculate transmission time.
Definition data-rate.cc:220
void Cancel()
This method is syntactic sugar for the ns3::Simulator::Cancel method.
Definition event-id.cc:44
bool IsExpired() const
This method is syntactic sugar for the ns3::Simulator::IsExpired method.
Definition event-id.cc:58
void NotifyPayloadBegin(const WifiTxVector &txVector, const Time &payloadDuration)
Fire the trace indicating that the PHY is starting to receive the payload of a PPDU.
virtual void HandleRxPpduWithSameContent(Ptr< Event > event, Ptr< const WifiPpdu > ppdu, RxPowerWattPerChannelBand &rxPower)
Handle reception of a PPDU that carries the same content of another PPDU.
void DropPreambleEvent(Ptr< const WifiPpdu > ppdu, WifiPhyRxfailureReason reason, Time endRx)
Drop the PPDU and the corresponding preamble detection event, but keep CCA busy state after the compl...
std::list< WifiMode >::const_iterator end() const
Return a const iterator to past-the-last WifiMode.
void EndOfMpdu(Ptr< Event > event, Ptr< WifiMpdu > mpdu, size_t mpduIndex, Time relativeStart, Time mpduDuration)
The last symbol of an MPDU in an A-MPDU has arrived.
MHz_u GetGuardBandwidth(MHz_u currentChannelWidth) const
virtual void RxPayloadSucceeded(Ptr< const WifiPsdu > psdu, RxSignalInfo rxSignalInfo, const WifiTxVector &txVector, uint16_t staId, const std::vector< bool > &statusPerMpdu)
Perform amendment-specific actions when the payload is successfully received.
virtual PhyFieldRxStatus DoEndReceivePreamble(Ptr< Event > event)
End receiving the preamble, perform amendment-specific actions, and provide the status of the recepti...
Ptr< WifiPhyStateHelper > m_state
Pointer to WifiPhyStateHelper of the WifiPhy (to make it reachable for child classes)
Definition phy-entity.h:940
virtual void RxPayloadFailed(Ptr< const WifiPsdu > psdu, double snr, const WifiTxVector &txVector)
Perform amendment-specific actions when the payload is unsuccessfuly received.
void EndPreambleDetectionPeriod(Ptr< Event > event)
End the preamble detection period.
virtual void NotifyCcaBusy(const Ptr< const WifiPpdu > ppdu, Time duration, WifiChannelListType channelType)
Notify PHY state helper to switch to CCA busy state,.
virtual Ptr< WifiPpdu > BuildPpdu(const WifiConstPsduMap &psdus, const WifiTxVector &txVector, Time ppduDuration)
Build amendment-specific PPDU.
virtual Time GetDuration(WifiPpduField field, const WifiTxVector &txVector) const
Get the duration of the PPDU field (or group of fields) used by this entity for the given transmissio...
virtual uint64_t ObtainNextUid(const WifiTxVector &txVector)
Obtain the next UID for the PPDU to transmit.
virtual Time DoStartReceivePayload(Ptr< Event > event)
Start receiving the PSDU (i.e.
virtual void StartReceivePreamble(Ptr< const WifiPpdu > ppdu, RxPowerWattPerChannelBand &rxPowersW, Time rxDuration)
Start receiving the PHY preamble of a PPDU (i.e.
bool NoEndPreambleDetectionEvents() const
virtual bool HandlesMcsModes() const
Check if the WifiModes handled by this PHY are MCSs.
void Transmit(Time txDuration, Ptr< const WifiPpdu > ppdu, dBm_u txPower, Ptr< SpectrumValue > txPowerSpectrum, const std::string &type)
This function prepares most of the WifiSpectrumSignalParameters parameters and invokes SpectrumWifiPh...
const std::map< std::pair< uint64_t, WifiPreamble >, Ptr< Event > > & GetCurrentPreambleEvents() const
Get the map of current preamble events (stored in WifiPhy).
std::map< UidStaIdPair, SignalNoiseDbm > m_signalNoiseMap
Map of the latest signal power and noise power in dBm (noise power includes the noise figure)
Definition phy-entity.h:961
Watt_u GetRxPowerForPpdu(Ptr< Event > event) const
Obtain the received power for a given band.
Ptr< WifiPhy > m_wifiPhy
Pointer to the owning WifiPhy.
Definition phy-entity.h:939
std::pair< bool, SignalNoiseDbm > GetReceptionStatus(Ptr< WifiMpdu > mpdu, Ptr< Event > event, uint16_t staId, Time relativeMpduStart, Time mpduDuration)
Get the reception status for the provided MPDU and notify.
std::optional< std::pair< Time, WifiChannelListType > > CcaIndication
CCA end time and its corresponding channel list type (can be std::nullopt if IDLE)
Definition phy-entity.h:924
std::vector< EventId > m_endOfMpduEvents
the end of MPDU events (only used for A-MPDUs)
Definition phy-entity.h:946
virtual MHz_u GetRxChannelWidth(const WifiTxVector &txVector) const
Return the channel width used in the reception spectrum model.
virtual ~PhyEntity()
Destructor for PHY entity.
Definition phy-entity.cc:74
virtual const PpduFormats & GetPpduFormats() const =0
Return the PPDU formats of the PHY.
virtual uint8_t GetNumModes() const
virtual bool DoStartReceiveField(WifiPpduField field, Ptr< Event > event)
Start receiving a given field, perform amendment-specific actions, and signify if it is supported.
void SetOwner(Ptr< WifiPhy > wifiPhy)
Set the WifiPhy owning this PHY entity.
Definition phy-entity.cc:82
std::list< WifiMode >::const_iterator begin() const
Return a const iterator to the first WifiMode.
virtual void CancelAllEvents()
Cancel and clear all running events.
virtual Time CalculateTxDuration(const WifiConstPsduMap &psduMap, const WifiTxVector &txVector, WifiPhyBand band) const
virtual void DoAbortCurrentReception(WifiPhyRxfailureReason reason)
Perform amendment-specific actions before aborting the current reception.
void AbortCurrentReception(WifiPhyRxfailureReason reason)
Abort the current reception.
void EndReceivePayload(Ptr< Event > event)
The last symbol of the PPDU has arrived.
virtual std::pair< MHz_u, WifiSpectrumBandInfo > GetChannelWidthAndBand(const WifiTxVector &txVector, uint16_t staId) const
Get the channel width and band to use (will be overloaded by child classes).
static uint64_t m_globalPpduUid
Global counter of the PPDU UID.
Definition phy-entity.h:964
PhyHeaderSections GetPhyHeaderSections(const WifiTxVector &txVector, Time ppduStart) const
Return a map of PHY header chunk information per PPDU field.
virtual Ptr< SpectrumValue > GetTxPowerSpectralDensity(Watt_u txPower, Ptr< const WifiPpdu > ppdu) const =0
virtual bool IsMcsSupported(uint8_t index) const
Check if the WifiMode corresponding to the given MCS index is supported.
void StartReceivePayload(Ptr< Event > event)
Start receiving the PSDU (i.e.
std::vector< EventId > m_endRxPayloadEvents
the end of receive events (only one unless UL MU reception)
Definition phy-entity.h:950
virtual void DoResetReceive(Ptr< Event > event)
Perform amendment-specific actions before resetting PHY at the end of the PPDU under reception after ...
void EndReceiveField(WifiPpduField field, Ptr< Event > event)
End receiving a given field.
virtual Ptr< Event > DoGetEvent(Ptr< const WifiPpdu > ppdu, RxPowerWattPerChannelBand &rxPowersW)
Get the event corresponding to the incoming PPDU.
virtual WifiMode GetSigMode(WifiPpduField field, const WifiTxVector &txVector) const
Get the WifiMode for the SIG field specified by the PPDU field.
WifiSpectrumBandInfo GetPrimaryBand(MHz_u bandWidth) const
If the operating channel width is a multiple of 20 MHz, return the info corresponding to the primary ...
WifiPpduField GetNextField(WifiPpduField currentField, WifiPreamble preamble) const
Return the field following the provided one.
void CancelRunningEndPreambleDetectionEvents()
Cancel all end preamble detection events.
Time GetDelayUntilCcaEnd(dBm_u threshold, const WifiSpectrumBandInfo &band)
Return the delay until CCA busy is ended for a given sensitivity threshold and a given band.
std::map< WifiPpduField, PhyHeaderChunkInfo > PhyHeaderSections
A map of PhyHeaderChunkInfo elements per PPDU field.
Definition phy-entity.h:294
virtual void SwitchMaybeToCcaBusy(const Ptr< const WifiPpdu > ppdu)
Check if PHY state should move to CCA busy state based on current state of interference tracker.
Time CalculatePhyPreambleAndHeaderDuration(const WifiTxVector &txVector) const
void NotifyInterferenceRxEndAndClear(bool reset)
Notify WifiPhy's InterferenceHelper of the end of the reception, clear maps and end of MPDU event,...
void StartPreambleDetectionPeriod(Ptr< Event > event)
Start the preamble detection period.
Time GetDurationUpToField(WifiPpduField field, const WifiTxVector &txVector) const
Get the duration of the PPDU up to (but excluding) the given field.
std::map< UidStaIdPair, std::vector< bool > > m_statusPerMpduMap
Map of the current reception status per MPDU that is filled in as long as MPDUs are being processed b...
Definition phy-entity.h:958
virtual bool CanStartRx(Ptr< const WifiPpdu > ppdu) const
Determine whether the PHY shall issue a PHY-RXSTART.indication primitive in response to a given PPDU.
virtual void StartTx(Ptr< const WifiPpdu > ppdu)
This function is called by SpectrumWifiPhy to send the PPDU while performing amendment-specific actio...
virtual dBm_u GetCcaThreshold(const Ptr< const WifiPpdu > ppdu, WifiChannelListType channelType) const
Return the CCA threshold for a given channel type.
Time GetRemainingDurationAfterField(Ptr< const WifiPpdu > ppdu, WifiPpduField field) const
Get the remaining duration of the PPDU after the end of the given field.
virtual uint16_t GetStaId(const Ptr< const WifiPpdu > ppdu) const
Return the STA ID that has been assigned to the station this PHY belongs to.
void StartReceiveField(WifiPpduField field, Ptr< Event > event)
Start receiving a given field.
std::vector< EventId > m_endOfMacHdrEvents
the end of MAC header events
Definition phy-entity.h:947
virtual bool IsModeSupported(WifiMode mode) const
Check if the WifiMode is supported.
Definition phy-entity.cc:90
void ResetReceive(Ptr< Event > event)
Reset PHY at the end of the PPDU under reception after it has failed the PHY header.
virtual CcaIndication GetCcaIndication(const Ptr< const WifiPpdu > ppdu)
Get CCA end time and its corresponding channel list type when a new signal has been received by the P...
std::list< WifiMode > m_modeList
the list of supported modes
Definition phy-entity.h:943
virtual Time GetMaxDelayPpduSameUid(const WifiTxVector &txVector)
Obtain the maximum time between two PPDUs with the same UID to consider they are identical and their ...
Ptr< const Event > GetCurrentEvent() const
Get the pointer to the current event (stored in WifiPhy).
double GetRandomValue() const
Obtain a random value from the WifiPhy's generator.
std::vector< EventId > m_endPreambleDetectionEvents
the end of preamble detection events
Definition phy-entity.h:945
virtual Ptr< const WifiPsdu > GetAddressedPsduInPpdu(Ptr< const WifiPpdu > ppdu) const
Get the PSDU addressed to that PHY in a PPDU (useful for MU PPDU).
SnrPer GetPhyHeaderSnrPer(WifiPpduField field, Ptr< Event > event) const
Obtain the SNR and PER of the PPDU field from the WifiPhy's InterferenceHelper class.
void ErasePreambleEvent(Ptr< const WifiPpdu > ppdu, Time rxDuration)
Erase the event corresponding to the PPDU from the list of preamble events, but consider it as noise ...
virtual Ptr< const WifiPpdu > GetRxPpduFromTxPpdu(Ptr< const WifiPpdu > ppdu)
The WifiPpdu from the TX PHY is received by each RX PHY attached to the same channel.
virtual WifiMode GetMcs(uint8_t index) const
Get the WifiMode corresponding to the given MCS index.
void AddPreambleEvent(Ptr< Event > event)
Add an entry to the map of current preamble events (stored in WifiPhy).
virtual void DoEndReceivePayload(Ptr< const WifiPpdu > ppdu)
Perform amendment-specific actions at the end of the reception of the payload.
std::tuple< dBr_u, dBr_u, dBr_u > GetTxMaskRejectionParams() const
virtual MHz_u GetMeasurementChannelWidth(const Ptr< const WifiPpdu > ppdu) const =0
Return the channel width used to measure the RSSI.
virtual WifiConstPsduMap GetWifiConstPsduMap(Ptr< const WifiPsdu > psdu, const WifiTxVector &txVector) const
Get a WifiConstPsduMap from a PSDU and the TXVECTOR to use to send the PSDU.
virtual bool IsConfigSupported(Ptr< const WifiPpdu > ppdu) const
Checks if the signaled configuration (excluding bandwidth) is supported by the PHY.
Ptr< Event > CreateInterferenceEvent(Ptr< const WifiPpdu > ppdu, Time duration, RxPowerWattPerChannelBand &rxPower, bool isStartHePortionRxing=false)
Create an event using WifiPhy's InterferenceHelper class.
PhyRxFailureAction
Action to perform in case of RX failure.
Definition phy-entity.h:70
@ DROP
drop PPDU and set CCA_BUSY
Definition phy-entity.h:71
@ IGNORE
ignore the reception
Definition phy-entity.h:73
@ ABORT
abort reception of PPDU
Definition phy-entity.h:72
WifiSpectrumBandInfo GetSecondaryBand(MHz_u bandWidth) const
If the channel bonding is used, return the info corresponding to the secondary channel of the given b...
virtual PhyFieldRxStatus DoEndReceiveField(WifiPpduField field, Ptr< Event > event)
End receiving a given field, perform amendment-specific actions, and provide the status of the recept...
void ScheduleEndOfMpdus(Ptr< Event > event)
Schedule end of MPDUs events.
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
bool IsStrictlyPositive() const
Exactly equivalent to t > 0.
Definition nstime.h:340
@ MS
millisecond
Definition nstime.h:106
@ S
second
Definition nstime.h:105
@ NS
nanosecond
Definition nstime.h:108
bool IsZero() const
Exactly equivalent to t == 0.
Definition nstime.h:304
represent a single transmission mode
Definition wifi-mode.h:40
uint64_t GetDataRate(MHz_u channelWidth, Time guardInterval, uint8_t nss) const
Definition wifi-mode.cc:111
Ptr< WifiPhyStateHelper > m_state
Pointer to WifiPhyStateHelper.
Definition wifi-phy.h:1325
Ptr< UniformRandomVariable > m_random
Provides uniform random variables.
Definition wifi-phy.h:1324
dB_u GetTxGain() const
Return the transmission gain.
Definition wifi-phy.cc:603
void NotifyCcaBusy(const Ptr< const WifiPpdu > ppdu, Time duration)
Notify PHY state helper to switch to CCA busy state,.
Definition wifi-phy.cc:2207
static Time GetPayloadDuration(uint32_t size, const WifiTxVector &txVector, WifiPhyBand band, MpduType mpdutype=NORMAL_MPDU, uint16_t staId=SU_STA_ID)
Definition wifi-phy.cc:1525
std::map< std::pair< uint64_t, WifiPreamble >, Ptr< Event > > m_currentPreambleEvents
store event associated to a PPDU (that has a unique ID and preamble combination) whose preamble is be...
Definition wifi-phy.h:1337
EventId m_endPhyRxEvent
the end of PHY receive event
Definition wifi-phy.h:1332
bool IsStateRx() const
Definition wifi-phy.cc:2152
bool m_notifyRxMacHeaderEnd
whether the PHY is capable of notifying MAC header RX end
Definition wifi-phy.h:1631
MHz_u GetFrequency() const
Definition wifi-phy.cc:1081
static Time GetPreambleDetectionDuration()
Definition wifi-phy.cc:1513
void AbortCurrentReception(WifiPhyRxfailureReason reason)
Due to newly arrived signal, the current reception cannot be continued and has to be aborted.
Definition wifi-phy.cc:2214
Ptr< FrameCaptureModel > m_frameCaptureModel
Frame capture model.
Definition wifi-phy.h:1626
void NotifyRxBegin(Ptr< const WifiPsdu > psdu, const RxPowerWattPerChannelBand &rxPowersW)
Public method used to fire a PhyRxBegin trace.
Definition wifi-phy.cc:1649
bool IsStateOff() const
Definition wifi-phy.cc:2176
static Time CalculateTxDuration(uint32_t size, const WifiTxVector &txVector, WifiPhyBand band, uint16_t staId=SU_STA_ID)
Definition wifi-phy.cc:1572
dBm_u GetCcaEdThreshold() const
Return the CCA energy detection threshold.
Definition wifi-phy.cc:527
virtual MHz_u GetGuardBandwidth(MHz_u currentChannelWidth) const =0
virtual std::tuple< dBr_u, dBr_u, dBr_u > GetTxMaskRejectionParams() const =0
std::map< WifiModulationClass, Ptr< PhyEntity > > m_phyEntities
This map holds the supported PHY entities.
Definition wifi-phy.h:1360
void NotifyRxPpduDrop(Ptr< const WifiPpdu > ppdu, WifiPhyRxfailureReason reason)
Public method used to fire a PhyRxPpduDrop trace.
Definition wifi-phy.cc:1685
Ptr< ErrorModel > m_postReceptionErrorModel
Error model for receive packet events.
Definition wifi-phy.h:1629
WifiPhyBand GetPhyBand() const
Get the configured Wi-Fi band.
Definition wifi-phy.cc:1063
Ptr< Event > m_currentEvent
Hold the current event.
Definition wifi-phy.h:1335
uint8_t GetChannelNumber() const
Return current channel number.
Definition wifi-phy.cc:1087
uint64_t m_previouslyRxPpduUid
UID of the previously received PPDU, reset to UINT64_MAX upon transmission.
Definition wifi-phy.h:1340
Ptr< PreambleDetectionModel > m_preambleDetectionModel
Preamble detection model.
Definition wifi-phy.h:1627
void NotifyRxEnd(Ptr< const WifiPsdu > psdu)
Public method used to fire a PhyRxEnd trace.
Definition wifi-phy.cc:1661
MHz_u GetChannelWidth() const
Definition wifi-phy.cc:1093
bool IsStateSleep() const
Definition wifi-phy.cc:2170
virtual FrequencyRange GetCurrentFrequencyRange() const =0
Get the frequency range of the current RF interface.
void SwitchMaybeToCcaBusy(const Ptr< const WifiPpdu > ppdu=nullptr)
Check if PHY state should move to CCA busy state based on current state of interference tracker.
Definition wifi-phy.cc:2200
Ptr< InterferenceHelper > m_interference
Pointer to a helper responsible for interference computations.
Definition wifi-phy.h:1322
dBm_u GetTxPowerForTransmission(Ptr< const WifiPpdu > ppdu) const
Compute the transmit power for the next transmission.
Definition wifi-phy.cc:2287
Ptr< PhyEntity > GetPhyEntityForPpdu(const Ptr< const WifiPpdu > ppdu) const
Get the supported PHY entity to use for a received PPDU.
Definition wifi-phy.cc:775
void Reset()
Reset data upon end of TX or RX.
Definition wifi-phy.cc:1939
TracedCallback< WifiTxVector, Time > m_phyRxPayloadBeginTrace
The trace source fired when the reception of the PHY payload (PSDU) begins.
Definition wifi-phy.h:1502
Time GetLastRxEndTime() const
Return the end time of the last received packet.
Definition wifi-phy.cc:2194
TracedCallback< const WifiMacHeader &, const WifiTxVector &, Time > m_phyRxMacHeaderEndTrace
The trace source fired when the reception of a MAC header ends.
Definition wifi-phy.h:1513
void NotifyMonitorSniffRx(Ptr< const WifiPsdu > psdu, MHz_u channelFreq, WifiTxVector txVector, SignalNoiseDbm signalNoise, std::vector< bool > statusPerMpdu, uint16_t staId=SU_STA_ID)
Public method used to fire a MonitorSniffer trace for a wifi PSDU being received.
Definition wifi-phy.cc:1692
Time m_timeLastPreambleDetected
Record the time the last preamble was detected.
Definition wifi-phy.h:1630
virtual WifiSpectrumBandInfo GetBand(MHz_u bandWidth, uint8_t bandIndex=0)=0
Get the info of a given band.
const WifiPhyOperatingChannel & GetOperatingChannel() const
Get a const reference to the operating channel.
Definition wifi-phy.cc:1075
dBm_u GetCcaSensitivityThreshold() const
Return the CCA sensitivity threshold.
Definition wifi-phy.cc:540
uint8_t GetSecondaryChannelIndex(MHz_u secondaryChannelWidth) const
If the operating channel width is made of a multiple of 20 MHz, return the index of the secondary cha...
uint8_t GetPrimaryChannelIndex(MHz_u primaryChannelWidth) const
If the operating channel width is a multiple of 20 MHz, return the index of the primary channel of th...
MHz_u GetPrimaryChannelCenterFrequency(MHz_u primaryChannelWidth) const
Get the center frequency of the primary channel of the given width.
This class mimics the TXVECTOR which is to be passed to the PHY in order to define the parameters whi...
WifiPreamble GetPreambleType() const
MHz_u GetChannelWidth() const
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition assert.h:55
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
#define NS_ABORT_MSG(msg)
Unconditional abnormal program termination with a message.
Definition abort.h:38
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
Definition abort.h:97
#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 > Create(Ts &&... args)
Create class instances by constructors with varying numbers of arguments and return them by Ptr.
Definition ptr.h:436
Time NanoSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1344
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition nstime.h:1308
WifiPhyRxfailureReason
Enumeration of the possible reception failure reasons.
WifiPreamble
The type of preamble to be used by an IEEE 802.11 transmission.
WifiPhyBand
Identifies the PHY band.
WifiChannelListType
Enumeration of the possible channel-list parameter elements defined in Table 8-5 of IEEE 802....
WifiPpduField
The type of PPDU field (grouped for convenience)
MpduType
The type of an MPDU.
Definition wifi-types.h:41
@ PREAMBLE_DETECT_FAILURE
@ FRAME_CAPTURE_PACKET_SWITCH
@ CHANNEL_SWITCHING
@ BUSY_DECODING_PREAMBLE
@ PPDU_TOO_LATE
@ PREAMBLE_DETECTION_PACKET_SWITCH
@ WIFI_CHANLIST_PRIMARY
@ WIFI_PPDU_FIELD_EHT_SIG
EHT-SIG field.
@ WIFI_PPDU_FIELD_PREAMBLE
SYNC + SFD fields for DSSS or ERP, shortSYNC + shortSFD fields for HR/DSSS or ERP,...
@ WIFI_PPDU_FIELD_DATA
data field
@ LAST_MPDU_IN_AGGREGATE
The MPDU is the last aggregate in an A-MPDU with multiple MPDUs.
Definition wifi-types.h:53
@ NORMAL_MPDU
The MPDU is not part of an A-MPDU.
Definition wifi-types.h:43
@ FIRST_MPDU_IN_AGGREGATE
The MPDU is the first aggregate in an A-MPDU with multiple MPDUs, but is not the last aggregate.
Definition wifi-types.h:48
@ SINGLE_MPDU
The MPDU is a single MPDU.
Definition wifi-types.h:45
@ MIDDLE_MPDU_IN_AGGREGATE
The MPDU is part of an A-MPDU with multiple MPDUs, but is neither the first nor the last aggregate.
Definition wifi-types.h:51
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.
@ SWITCHING
The PHY layer is switching to other channel.
@ TX
The PHY layer is sending a packet.
@ OFF
The PHY layer is switched off.
@ IDLE
The PHY layer is IDLE.
@ CCA_BUSY
The PHY layer has sense the medium busy through the CCA mechanism.
@ SLEEP
The PHY layer is sleeping.
@ RX
The PHY layer is receiving a packet.
dB_u RatioToDb(double ratio)
Convert from ratio to dB.
Definition wifi-utils.cc:44
std::ostream & operator<<(std::ostream &os, const Angles &a)
Definition angles.cc:148
double Integral(const SpectrumValue &arg)
dBm_u WToDbm(Watt_u val)
Convert from Watts to dBm.
Definition wifi-utils.cc:37
double MHz_u
MHz weak type.
Definition wifi-units.h:31
Ptr< T1 > DynamicCast(const Ptr< T2 > &p)
Cast a Ptr.
Definition ptr.h:580
std::map< WifiSpectrumBandInfo, Watt_u > RxPowerWattPerChannelBand
A map of the received power for each band.
Definition phy-entity.h:45
double dBm_u
dBm weak type
Definition wifi-units.h:27
double DbToRatio(dB_u val)
Convert from dB to ratio.
Definition wifi-utils.cc:25
Watt_u DbmToW(dBm_u val)
Convert from dBm to Watts.
Definition wifi-utils.cc:31
static constexpr uint16_t SU_STA_ID
STA_ID to identify a single user (SU)
Definition wifi-mode.h:24
double Watt_u
Watt weak type.
Definition wifi-units.h:25
Declaration of:
Status of the reception of the PPDU field.
Definition phy-entity.h:80
WifiPhyRxfailureReason reason
failure reason
Definition phy-entity.h:82
PhyRxFailureAction actionIfFailure
action to perform in case of failure
Definition phy-entity.h:83
bool isSuccess
outcome (true if success) of the reception
Definition phy-entity.h:81
A struct for both SNR and PER.
Definition phy-entity.h:115
double snr
SNR in linear scale.
Definition phy-entity.h:116
RxSignalInfo structure containing info on the received signal.
Definition wifi-types.h:72
double snr
SNR in linear scale.
Definition wifi-types.h:73
dBm_u rssi
RSSI.
Definition wifi-types.h:74
SignalNoiseDbm structure.
Definition wifi-types.h:58
dBm_u noise
noise power
Definition wifi-types.h:60
dBm_u signal
signal strength
Definition wifi-types.h:59
WifiSpectrumBandInfo structure containing info about a spectrum band.