From 2fa6f9bb15bc118712d10826c1152cc77e3bdb2c Mon Sep 17 00:00:00 2001 From: Rediet Date: Mon, 15 Feb 2021 18:19:46 +0100 Subject: [PATCH] wifi: Add preamble detection and header field handling in PhyEntity Preamble reception is still in WifiPhy (will be addressed in subsequent commits). HE TB PPDU related actions in SpectrumWifiPhy should also be moved in following commits. Payload reception part is also to be moved later on --- src/wifi/model/dsss-phy.cc | 37 ++++ src/wifi/model/dsss-phy.h | 12 ++ src/wifi/model/he-phy.cc | 142 +++++++++++++- src/wifi/model/he-phy.h | 28 +++ src/wifi/model/ht-phy.cc | 73 +++++++- src/wifi/model/ht-phy.h | 14 ++ src/wifi/model/ofdm-phy.cc | 62 ++++++- src/wifi/model/ofdm-phy.h | 30 +++ src/wifi/model/phy-entity.cc | 350 +++++++++++++++++++++++++++++++++++ src/wifi/model/phy-entity.h | 230 ++++++++++++++++++++++- src/wifi/model/vht-phy.cc | 94 ++++++++++ src/wifi/model/vht-phy.h | 44 +++++ src/wifi/model/wifi-phy.cc | 1 + src/wifi/model/wifi-phy.h | 6 +- 14 files changed, 1115 insertions(+), 8 deletions(-) diff --git a/src/wifi/model/dsss-phy.cc b/src/wifi/model/dsss-phy.cc index ef991cbba..dfd53d9a6 100644 --- a/src/wifi/model/dsss-phy.cc +++ b/src/wifi/model/dsss-phy.cc @@ -24,6 +24,8 @@ #include "dsss-ppdu.h" #include "wifi-psdu.h" #include "wifi-phy.h" //only used for static mode constructor +#include "wifi-utils.h" +#include "ns3/simulator.h" #include "ns3/log.h" namespace ns3 { @@ -160,6 +162,41 @@ DsssPhy::BuildPpdu (const WifiConstPsduMap & psdus, WifiTxVector txVector, return Create (psdus.begin ()->second, txVector, ppduDuration, uid); } +PhyEntity::PhyFieldRxStatus +DsssPhy::DoEndReceiveField (WifiPpduField field, Ptr event) +{ + NS_LOG_FUNCTION (this << field << *event); + if (field == WIFI_PPDU_FIELD_NON_HT_HEADER) + { + return EndReceiveHeader (event); //PHY header or short PHY header + } + return PhyEntity::DoEndReceiveField (field, event); +} + +PhyEntity::PhyFieldRxStatus +DsssPhy::EndReceiveHeader (Ptr event) +{ + NS_LOG_FUNCTION (this << *event); + SnrPer snrPer = GetPhyHeaderSnrPer (WIFI_PPDU_FIELD_NON_HT_HEADER, event); + NS_LOG_DEBUG ("Long/Short PHY header: SNR(dB)=" << RatioToDb (snrPer.snr) << ", PER=" << snrPer.per); + PhyFieldRxStatus status (GetRandomValue () > snrPer.per); + if (status.isSuccess) + { + NS_LOG_DEBUG ("Received long/short PHY header"); + if (!IsConfigSupported (event->GetPpdu ())) + { + status = PhyFieldRxStatus (false, UNSUPPORTED_SETTINGS, DROP); + } + } + else + { + NS_LOG_DEBUG ("Abort reception because long/short PHY header reception failed"); + status.reason = L_SIG_FAILURE; + status.actionIfFailure = ABORT; + } + return status; +} + void DsssPhy::InitializeModes (void) { diff --git a/src/wifi/model/dsss-phy.h b/src/wifi/model/dsss-phy.h index 951a7c4f2..ccf949285 100644 --- a/src/wifi/model/dsss-phy.h +++ b/src/wifi/model/dsss-phy.h @@ -110,6 +110,9 @@ public: static WifiMode GetDsssRate11Mbps (void); private: + // Inherited + PhyFieldRxStatus DoEndReceiveField (WifiPpduField field, Ptr event) override; + /** * \param txVector the transmission parameters * \return the WifiMode used for the PHY header field @@ -129,6 +132,15 @@ private: */ Time GetHeaderDuration (WifiTxVector txVector) const; + /** + * End receiving the header, perform DSSS-specific actions, and + * provide the status of the reception. + * + * \param event the event holding incoming PPDU's information + * \return status of the reception of the header + */ + PhyFieldRxStatus EndReceiveHeader (Ptr event); + static const PpduFormats m_dsssPpduFormats; //!< DSSS and HR/DSSS PPDU formats }; //class DsssPhy diff --git a/src/wifi/model/he-phy.cc b/src/wifi/model/he-phy.cc index 2e9810458..0da23d546 100644 --- a/src/wifi/model/he-phy.cc +++ b/src/wifi/model/he-phy.cc @@ -22,7 +22,13 @@ #include "he-phy.h" #include "he-ppdu.h" #include "wifi-psdu.h" -#include "wifi-phy.h" //only used for static mode constructor +#include "wifi-phy.h" +#include "he-configuration.h" +#include "wifi-net-device.h" +#include "sta-wifi-mac.h" +#include "wifi-utils.h" +#include "ns3/uinteger.h" +#include "ns3/simulator.h" #include "ns3/log.h" #include "ns3/assert.h" @@ -67,6 +73,7 @@ HePhy::HePhy (bool buildModeList /* = true */) m_bssMembershipSelector = HE_PHY; m_maxMcsIndexPerSs = 11; m_maxSupportedMcsIndexPerSs = m_maxMcsIndexPerSs; + m_currentHeTbPpduUid = UINT64_MAX; if (buildModeList) { BuildModeList (); @@ -300,6 +307,139 @@ HePhy::BuildPpdu (const WifiConstPsduMap & psdus, WifiTxVector txVector, return Create (psdus, txVector, ppduDuration, band, uid); } +Ptr +HePhy::GetAddressedPsduInPpdu (Ptr ppdu) const +{ + if (ppdu->GetType () == WIFI_PPDU_TYPE_DL_MU || ppdu->GetType () == WIFI_PPDU_TYPE_UL_MU) + { + auto hePpdu = DynamicCast (ppdu); + NS_ASSERT (hePpdu); + return hePpdu->GetPsdu (GetBssColor (), GetStaId (ppdu)); + } + return PhyEntity::GetAddressedPsduInPpdu (ppdu); +} + +uint8_t +HePhy::GetBssColor (void) const +{ + uint8_t bssColor = 0; + Ptr device = DynamicCast (m_wifiPhy->GetDevice ()); + if (device) + { + Ptr heConfiguration = device->GetHeConfiguration (); + if (heConfiguration) + { + UintegerValue bssColorAttribute; + heConfiguration->GetAttribute ("BssColor", bssColorAttribute); + bssColor = bssColorAttribute.Get (); + } + } + return bssColor; +} + +uint16_t +HePhy::GetStaId (const Ptr ppdu) const +{ + //TODO Move HE-specific logic here + return m_wifiPhy->GetStaId (ppdu); +} + +PhyEntity::PhyFieldRxStatus +HePhy::ProcessSigA (Ptr event, PhyFieldRxStatus status) +{ + NS_LOG_FUNCTION (this << *event << status); + //Notify end of SIG-A (in all cases) + HeSigAParameters params; + params.rssiW = GetRxPowerWForPpdu (event); + params.bssColor = event->GetTxVector ().GetBssColor (); + Simulator::ScheduleNow (&WifiPhy::NotifyEndOfHeSigA, GetPointer (m_wifiPhy), params); + + if (status.isSuccess) + { + Ptr ppdu = event->GetPpdu (); + if (event->GetTxVector ().GetPreambleType () == WIFI_PREAMBLE_HE_TB) + { + m_currentHeTbPpduUid = ppdu->GetUid (); //to be able to correctly schedule start of OFDMA payload + } + + //Check if PPDU is filtered only if the SIG-A content is supported + if (ppdu->GetType () == WIFI_PPDU_TYPE_DL_MU) //Final decision on content of DL MU is reported to end of SIG-B (unless the PPDU is filtered) + { + uint8_t bssColor = GetBssColor (); + if (bssColor != 0 && bssColor != event->GetTxVector ().GetBssColor ()) + { + NS_LOG_DEBUG ("The BSS color of this DL MU PPDU does not match the device's. The PPDU is filtered."); + return PhyFieldRxStatus (false, FILTERED, ABORT); + } + } + else if (GetAddressedPsduInPpdu (ppdu)) + { + //We are here because the SU or UL MU is addressed to the PPDU, so keep status to success + } + else + { + NS_ASSERT (ppdu->GetType () == WIFI_PPDU_TYPE_UL_MU); + NS_LOG_DEBUG ("No PSDU addressed to that PHY in the received MU PPDU. The PPDU is filtered."); + return PhyFieldRxStatus (false, FILTERED, ABORT); + } + } + return status; +} + +PhyEntity::PhyFieldRxStatus +HePhy::ProcessSigB (Ptr event, PhyFieldRxStatus status) +{ + NS_LOG_FUNCTION (this << *event << status); + if (status.isSuccess) + { + //Check if PPDU is filtered only if the SIG-B content is supported (not explicitly stated but assumed based on behavior for SIG-A) + if (!GetAddressedPsduInPpdu (event->GetPpdu ())) + { + NS_LOG_DEBUG ("No PSDU addressed to that PHY in the received MU PPDU. The PPDU is filtered."); + return PhyFieldRxStatus (false, FILTERED, ABORT); + } + } + return status; +} + +bool +HePhy::IsConfigSupported (Ptr ppdu) const +{ + WifiTxVector txVector = ppdu->GetTxVector (); + uint16_t staId = GetStaId (ppdu); + WifiMode txMode = txVector.GetMode (staId); + uint8_t nss = txVector.GetNssMax (); + if (txVector.GetPreambleType () == WIFI_PREAMBLE_HE_MU) + { + for (auto info : txVector.GetHeMuUserInfoMap ()) + { + if (info.first == staId) + { + nss = info.second.nss; //no need to look at other PSDUs + break; + } + } + } + + if (nss > m_wifiPhy->GetMaxSupportedRxSpatialStreams ()) + { + NS_LOG_DEBUG ("Packet reception could not be started because not enough RX antennas"); + return false; + } + if (!IsModeSupported (txMode)) + { + NS_LOG_DEBUG ("Drop packet because it was sent using an unsupported mode (" << txVector.GetMode () << ")"); + return false; + } + return true; +} + +uint64_t +HePhy::GetCurrentHeTbPpduUid (void) const +{ + return m_currentHeTbPpduUid; +} + void HePhy::InitializeModes (void) { diff --git a/src/wifi/model/he-phy.h b/src/wifi/model/he-phy.h index 8aaf6f865..23eb7d446 100644 --- a/src/wifi/model/he-phy.h +++ b/src/wifi/model/he-phy.h @@ -73,6 +73,21 @@ public: Time GetSigBDuration (WifiTxVector txVector) const override; virtual Ptr BuildPpdu (const WifiConstPsduMap & psdus, WifiTxVector txVector, Time ppduDuration, WifiPhyBand band, uint64_t uid) const override; + Ptr GetAddressedPsduInPpdu (Ptr ppdu) const override; + + /** + * \return the BSS color of this PHY. + */ + uint8_t GetBssColor (void) const; + + /** + * Return the STA ID that has been assigned to the station this PHY belongs to. + * This is typically called for MU PPDUs, in order to pick the correct PSDU. + * + * \param ppdu the PPDU for which the STA ID is requested + * \return the STA ID + */ + uint16_t GetStaId (const Ptr ppdu) const; /** * \param ppduDuration the duration of the HE TB PPDU @@ -96,6 +111,11 @@ public: */ Time CalculateNonOfdmaDurationForHeTb (WifiTxVector txVector) const; + /** + * \return the UID of the HE TB PPDU being received + */ + uint64_t GetCurrentHeTbPpduUid (void) const; + /** * Initialize all HE modes. */ @@ -182,6 +202,14 @@ public: */ static WifiMode GetHeMcs11 (void); +protected: + // Inherited + PhyFieldRxStatus ProcessSigA (Ptr event, PhyFieldRxStatus status) override; + PhyFieldRxStatus ProcessSigB (Ptr event, PhyFieldRxStatus status) override; + virtual bool IsConfigSupported (Ptr ppdu) const override; + + uint64_t m_currentHeTbPpduUid; //!< UID of the HE TB PPDU being received + private: // Inherited virtual void BuildModeList (void) override; diff --git a/src/wifi/model/ht-phy.cc b/src/wifi/model/ht-phy.cc index 30cb5cc66..044279887 100644 --- a/src/wifi/model/ht-phy.cc +++ b/src/wifi/model/ht-phy.cc @@ -22,7 +22,8 @@ #include "ht-phy.h" #include "ht-ppdu.h" #include "wifi-psdu.h" -#include "wifi-phy.h" //only used for static mode constructor +#include "wifi-phy.h" +#include "wifi-utils.h" #include "ns3/log.h" #include "ns3/assert.h" @@ -370,6 +371,76 @@ HtPhy::BuildPpdu (const WifiConstPsduMap & psdus, WifiTxVector txVector, Time pp return Create (psdus.begin ()->second, txVector, ppduDuration, band, uid); } +PhyEntity::PhyFieldRxStatus +HtPhy::DoEndReceiveField (WifiPpduField field, Ptr event) +{ + NS_LOG_FUNCTION (this << field << *event); + switch (field) + { + case WIFI_PPDU_FIELD_HT_SIG: + return EndReceiveHtSig (event); + case WIFI_PPDU_FIELD_TRAINING: + return PhyFieldRxStatus (true); //always consider that training has been correctly received + case WIFI_PPDU_FIELD_NON_HT_HEADER: + NS_ASSERT (event->GetTxVector ().GetPreambleType () != WIFI_PREAMBLE_HT_GF); + //no break so as to go to OfdmPhy for processing + default: + return OfdmPhy::DoEndReceiveField (field, event); + } +} + +PhyEntity::PhyFieldRxStatus +HtPhy::EndReceiveHtSig (Ptr event) +{ + NS_LOG_FUNCTION (this << *event); + NS_ASSERT (IsHt (event->GetTxVector ().GetPreambleType ())); + SnrPer snrPer = GetPhyHeaderSnrPer (WIFI_PPDU_FIELD_HT_SIG, event); + NS_LOG_DEBUG ("HT-SIG: SNR(dB)=" << RatioToDb (snrPer.snr) << ", PER=" << snrPer.per); + PhyFieldRxStatus status (GetRandomValue () > snrPer.per); + if (status.isSuccess) + { + NS_LOG_DEBUG ("Received HT-SIG"); + if (!IsAllConfigSupported (WIFI_PPDU_FIELD_HT_SIG, event->GetPpdu ())) + { + status = PhyFieldRxStatus (false, UNSUPPORTED_SETTINGS, DROP); + } + } + else + { + NS_LOG_DEBUG ("Drop packet because HT-SIG reception failed"); + status.reason = HT_SIG_FAILURE; + status.actionIfFailure = DROP; + } + return status; +} + +bool +HtPhy::IsAllConfigSupported (WifiPpduField field, Ptr ppdu) const +{ + if (field == WIFI_PPDU_FIELD_NON_HT_HEADER) + { + return true; //wait till reception of HT-SIG (or SIG-A) to make decision + } + return OfdmPhy::IsAllConfigSupported (field, ppdu); +} + +bool +HtPhy::IsConfigSupported (Ptr ppdu) const +{ + WifiTxVector txVector = ppdu->GetTxVector (); + if (txVector.GetNss () > m_wifiPhy->GetMaxSupportedRxSpatialStreams ()) + { + NS_LOG_DEBUG ("Packet reception could not be started because not enough RX antennas"); + return false; + } + if (!IsModeSupported (txVector.GetMode ())) + { + NS_LOG_DEBUG ("Drop packet because it was sent using an unsupported mode (" << txVector.GetMode () << ")"); + return false; + } + return true; +} + void HtPhy::InitializeModes (void) { diff --git a/src/wifi/model/ht-phy.h b/src/wifi/model/ht-phy.h index 34ad01099..d01a604c7 100644 --- a/src/wifi/model/ht-phy.h +++ b/src/wifi/model/ht-phy.h @@ -343,6 +343,11 @@ public: static WifiMode GetHtMcs31 (void); protected: + // Inherited + virtual PhyFieldRxStatus DoEndReceiveField (WifiPpduField field, Ptr event) override; + virtual bool IsAllConfigSupported (WifiPpduField field, Ptr ppdu) const override; + virtual bool IsConfigSupported (Ptr ppdu) const override; + /** * Build mode list. * Should be redone whenever the maximum MCS index per spatial stream @@ -367,6 +372,15 @@ protected: uint8_t m_bssMembershipSelector; //!< the BSS membership selector private: + /** + * End receiving the HT-SIG, perform HT-specific actions, and + * provide the status of the reception. + * + * \param event the event holding incoming PPDU's information + * \return status of the reception of the HT-SIG + */ + PhyFieldRxStatus EndReceiveHtSig (Ptr event); + uint8_t m_maxSupportedNss; //!< Maximum supported number of spatial streams (used to build HT MCS indices) static const PpduFormats m_htPpduFormats; //!< HT PPDU formats diff --git a/src/wifi/model/ofdm-phy.cc b/src/wifi/model/ofdm-phy.cc index cbf400def..eb7850a22 100644 --- a/src/wifi/model/ofdm-phy.cc +++ b/src/wifi/model/ofdm-phy.cc @@ -23,9 +23,10 @@ #include "ofdm-phy.h" #include "ofdm-ppdu.h" #include "wifi-psdu.h" -#include "wifi-phy.h" //only used for static mode constructor +#include "wifi-phy.h" +#include "wifi-utils.h" +#include "ns3/simulator.h" #include "ns3/log.h" -#include "ns3/assert.h" namespace ns3 { @@ -236,6 +237,63 @@ OfdmPhy::BuildPpdu (const WifiConstPsduMap & psdus, WifiTxVector txVector, return Create (psdus.begin ()->second, txVector, band, uid); } +PhyEntity::PhyFieldRxStatus +OfdmPhy::DoEndReceiveField (WifiPpduField field, Ptr event) +{ + NS_LOG_FUNCTION (this << field << *event); + if (field == WIFI_PPDU_FIELD_NON_HT_HEADER) + { + return EndReceiveHeader (event); //L-SIG + } + return PhyEntity::DoEndReceiveField (field, event); +} + +PhyEntity::PhyFieldRxStatus +OfdmPhy::EndReceiveHeader (Ptr event) +{ + NS_LOG_FUNCTION (this << *event); + SnrPer snrPer = GetPhyHeaderSnrPer (WIFI_PPDU_FIELD_NON_HT_HEADER, event); + NS_LOG_DEBUG ("L-SIG: SNR(dB)=" << RatioToDb (snrPer.snr) << ", PER=" << snrPer.per); + PhyFieldRxStatus status (GetRandomValue () > snrPer.per); + if (status.isSuccess) + { + NS_LOG_DEBUG ("Received non-HT PHY header"); + if (!IsAllConfigSupported (WIFI_PPDU_FIELD_NON_HT_HEADER, event->GetPpdu ())) + { + status = PhyFieldRxStatus (false, UNSUPPORTED_SETTINGS, DROP); + } + } + else + { + NS_LOG_DEBUG ("Abort reception because non-HT PHY header reception failed"); + status.reason = L_SIG_FAILURE; + status.actionIfFailure = ABORT; + } + return status; +} + +bool +OfdmPhy::IsChannelWidthSupported (Ptr ppdu) const +{ + uint16_t channelWidth = ppdu->GetTxVector ().GetChannelWidth (); + if ((channelWidth >= 40) && (channelWidth > m_wifiPhy->GetChannelWidth ())) + { + NS_LOG_DEBUG ("Packet reception could not be started because not enough channel width (" << channelWidth << " vs " << m_wifiPhy->GetChannelWidth () << ")"); + return false; + } + return true; +} + +bool +OfdmPhy::IsAllConfigSupported (WifiPpduField /* field */, Ptr ppdu) const +{ + if (!IsChannelWidthSupported (ppdu)) + { + return false; + } + return IsConfigSupported (ppdu); +} + void OfdmPhy::InitializeModes (void) { diff --git a/src/wifi/model/ofdm-phy.h b/src/wifi/model/ofdm-phy.h index 6c6d88b95..f848b7426 100644 --- a/src/wifi/model/ofdm-phy.h +++ b/src/wifi/model/ofdm-phy.h @@ -258,11 +258,15 @@ public: static WifiMode GetOfdmRate13_5MbpsBW5MHz (void); protected: + // Inherited + virtual PhyFieldRxStatus DoEndReceiveField (WifiPpduField field, Ptr event) override; + /** * \param txVector the transmission parameters * \return the WifiMode used for the SIGNAL field */ virtual WifiMode GetHeaderMode (WifiTxVector txVector) const; + /** * \param txVector the transmission parameters * \return the duration of the preamble field @@ -286,6 +290,32 @@ protected: */ Time GetSignalExtension (WifiPhyBand band) const; + /** + * End receiving the header, perform OFDM-specific actions, and + * provide the status of the reception. + * + * \param event the event holding incoming PPDU's information + * \return status of the reception of the header + */ + PhyFieldRxStatus EndReceiveHeader (Ptr event); + + /** + * Checks if the PPDU's bandwidth is supported by the PHY. + * + * \param ppdu the received PPDU + * \return \c true if supported, \c false otherwise + */ + virtual bool IsChannelWidthSupported (Ptr ppdu) const; + /** + * Checks if the signaled configuration (including bandwidth) + * is supported by the PHY. + * + * \param field the current PPDU field (SIG used for checking config) + * \param ppdu the received PPDU + * \return \c true if supported, \c false otherwise + */ + virtual bool IsAllConfigSupported (WifiPpduField field, Ptr ppdu) const; + private: static const PpduFormats m_ofdmPpduFormats; //!< OFDM PPDU formats }; //class OfdmPhy diff --git a/src/wifi/model/phy-entity.cc b/src/wifi/model/phy-entity.cc index 494844f94..e3ae05c19 100644 --- a/src/wifi/model/phy-entity.cc +++ b/src/wifi/model/phy-entity.cc @@ -21,7 +21,11 @@ */ #include "phy-entity.h" +#include "wifi-phy.h" #include "wifi-psdu.h" +#include "preamble-detection-model.h" +#include "wifi-utils.h" +#include "ns3/simulator.h" #include "ns3/log.h" #include "ns3/assert.h" #include @@ -30,6 +34,34 @@ namespace ns3 { NS_LOG_COMPONENT_DEFINE ("PhyEntity"); +std::ostream & operator << (std::ostream &os, const PhyEntity::PhyRxFailureAction &action) +{ + switch (action) + { + case PhyEntity::DROP: + return (os << "DROP"); + case PhyEntity::ABORT: + return (os << "ABORT"); + case PhyEntity::IGNORE: + return (os << "IGNORE"); + default: + NS_FATAL_ERROR ("Unknown action"); + return (os << "unknown"); + } +} + +std::ostream & operator << (std::ostream &os, const PhyEntity::PhyFieldRxStatus &status) +{ + if (status.isSuccess) + { + return os << "success"; + } + else + { + return os << "failure (" << status.reason << "/" << status.actionIfFailure << ")"; + } +} + /******************************************************* * Abstract base class for PHY entities *******************************************************/ @@ -39,6 +71,14 @@ PhyEntity::~PhyEntity () m_modeList.clear (); } +void +PhyEntity::SetOwner (Ptr wifiPhy) +{ + NS_LOG_FUNCTION (this << wifiPhy); + m_wifiPhy = wifiPhy; + m_state = m_wifiPhy->m_state; +} + bool PhyEntity::IsModeSupported (WifiMode mode) const { @@ -146,6 +186,12 @@ PhyEntity::CalculatePhyPreambleAndHeaderDuration (WifiTxVector txVector) const return duration; } +Ptr +PhyEntity::GetAddressedPsduInPpdu (Ptr ppdu) const +{ + return ppdu->GetPsdu (); +} + PhyEntity::PhyHeaderSections PhyEntity::GetPhyHeaderSections (WifiTxVector txVector, Time ppduStart) const { @@ -173,4 +219,308 @@ PhyEntity::BuildPpdu (const WifiConstPsduMap & psdus, WifiTxVector txVector, return Create (psdus.begin ()->second, txVector); //should be overloaded } +Time +PhyEntity::GetDurationUpToField (WifiPpduField field, WifiTxVector txVector) const +{ + if (field == WIFI_PPDU_FIELD_DATA) //this field is not in the map returned by GetPhyHeaderSections + { + return CalculatePhyPreambleAndHeaderDuration (txVector); + } + const auto & sections = GetPhyHeaderSections (txVector, NanoSeconds (0)); + auto it = sections.find (field); + NS_ASSERT (it != sections.end ()); + const auto & startStopTimes = it->second.first; + return startStopTimes.first; //return the start time of field relatively to the beginning of the PPDU +} + +PhyEntity::SnrPer +PhyEntity::GetPhyHeaderSnrPer (WifiPpduField field, Ptr event) const +{ + uint16_t measurementChannelWidth = m_wifiPhy->GetMeasurementChannelWidth (event->GetPpdu ()); + return m_wifiPhy->m_interference.CalculatePhyHeaderSnrPer (event, measurementChannelWidth, m_wifiPhy->GetBand (measurementChannelWidth), + field); +} + +void +PhyEntity::StartReceiveField (WifiPpduField field, Ptr event) +{ + NS_LOG_FUNCTION (this << field << *event); + NS_ASSERT (m_wifiPhy); //no sense if no owner WifiPhy instance + NS_ASSERT (m_wifiPhy->m_endPhyRxEvent.IsExpired () + || m_wifiPhy->m_currentPreambleEvents.size () > 1); //TODO find a better way of handling multiple preambles until synching on one after detection period + + //Handle special cases of preamble and data reception (TODO improve this logic later on) + if (field == WIFI_PPDU_FIELD_PREAMBLE) + { + DoStartReceivePreamble (event); + return; + } + if (field == WIFI_PPDU_FIELD_DATA) + { + //TODO improve this logic later on + //Hand over to WifiPhy for data processing + m_wifiPhy->StartReceivePayload (event); + return; + } + + bool supported = DoStartReceiveField (field, event); + NS_ABORT_MSG_IF (!supported, "Unknown field " << field << " for this PHY entity"); //TODO see what to do if not supported + Time duration = GetDuration (field, event->GetTxVector ()); + m_wifiPhy->m_endPhyRxEvent = Simulator::Schedule (duration, &PhyEntity::EndReceiveField, this, field, event); + m_state->SwitchMaybeToCcaBusy (duration); //keep in CCA busy state up to reception of Data (will then switch to RX) +} + +void +PhyEntity::EndReceiveField (WifiPpduField field, Ptr event) +{ + NS_LOG_FUNCTION (this << field << *event); + NS_ASSERT (m_wifiPhy); //no sense if no owner WifiPhy instance + NS_ASSERT (m_wifiPhy->m_endPhyRxEvent.IsExpired ()); + PhyFieldRxStatus status = DoEndReceiveField (field, event); + WifiTxVector txVector = event->GetTxVector (); + if (status.isSuccess) //move to next field if reception succeeded + { + StartReceiveField (GetNextField (field, txVector.GetPreambleType ()), event); + } + else + { + Ptr ppdu = event->GetPpdu (); + switch (status.actionIfFailure) + { + case ABORT: + //Abort reception, but consider medium as busy + if (status.reason == FILTERED) + { + //PHY-RXSTART is immediately followed by PHY-RXEND (Filtered) + m_wifiPhy->m_phyRxPayloadBeginTrace (txVector, NanoSeconds (0)); //this callback (equivalent to PHY-RXSTART primitive) is also triggered for filtered PPDUs + } + AbortCurrentReception (status.reason); + if (event->GetEndTime () > (Simulator::Now () + m_state->GetDelayUntilIdle ())) + { + m_wifiPhy->MaybeCcaBusyDuration (m_wifiPhy->GetMeasurementChannelWidth (ppdu)); + } + break; + case DROP: + //Notify drop, keep in CCA busy, and perform same processing as IGNORE case + m_wifiPhy->NotifyRxDrop (GetAddressedPsduInPpdu (ppdu), status.reason); + m_state->SwitchMaybeToCcaBusy (GetRemainingDurationAfterField (ppdu, field)); //keep in CCA busy state till the end + case IGNORE: + //Keep in Rx state and reset at end + m_wifiPhy->m_endRxEvents.push_back (Simulator::Schedule (GetRemainingDurationAfterField (ppdu, field), + &PhyEntity::ResetReceive, this, event)); + break; + default: + NS_FATAL_ERROR ("Unknown action in case of failure"); + } + } +} + +Time +PhyEntity::GetRemainingDurationAfterField (Ptr ppdu, WifiPpduField field) const +{ + WifiTxVector txVector = ppdu->GetTxVector (); + return ppdu->GetTxDuration () - (GetDurationUpToField (field, txVector) + GetDuration (field, txVector)); +} + +bool +PhyEntity::DoStartReceiveField (WifiPpduField field, Ptr event) +{ + NS_LOG_FUNCTION (this << field << *event); + NS_ASSERT (field != WIFI_PPDU_FIELD_PREAMBLE && field != WIFI_PPDU_FIELD_DATA); //handled apart for the time being + auto ppduFormats = GetPpduFormats (); + auto itFormat = ppduFormats.find (event->GetPpdu ()->GetPreamble ()); + if (itFormat != ppduFormats.end ()) + { + auto itField = std::find (itFormat->second.begin (), itFormat->second.end (), field); + if (itField != itFormat->second.end ()) + { + return true; //supported field so we can start receiving + } + } + return false; //unsupported otherwise +} + +PhyEntity::PhyFieldRxStatus +PhyEntity::DoEndReceiveField (WifiPpduField field, Ptr event) +{ + NS_LOG_FUNCTION (this << field << *event); + NS_ASSERT (field != WIFI_PPDU_FIELD_DATA); //handled apart for the time being + if (field == WIFI_PPDU_FIELD_PREAMBLE) + { + return DoEndReceivePreamble (event); + } + return PhyFieldRxStatus (false); //failed reception by default +} + +bool +PhyEntity::DoStartReceivePreamble (Ptr event) +{ + NS_LOG_FUNCTION (this << *event); + //TODO handle special cases in WifiPhy::StartReceivePreamble + StartPreambleDetectionPeriod (event); + return true; +} + +PhyEntity::PhyFieldRxStatus +PhyEntity::DoEndReceivePreamble (Ptr event) +{ + NS_LOG_FUNCTION (this << *event); + NS_ASSERT (m_wifiPhy->m_currentPreambleEvents.size () == 1); //Synched on one after detection period + return PhyFieldRxStatus (true); //always consider that preamble has been correctly received if preamble detection was OK +} + +void +PhyEntity::StartPreambleDetectionPeriod (Ptr event) +{ + NS_LOG_FUNCTION (this << *event); + NS_LOG_DEBUG ("Sync to signal (power=" << GetRxPowerWForPpdu (event) << "W)"); + m_wifiPhy->m_interference.NotifyRxStart (); //We need to notify it now so that it starts recording events + //TODO see if preamble detection events cannot be ported here + m_wifiPhy->m_endPreambleDetectionEvents.push_back (Simulator::Schedule (m_wifiPhy->GetPreambleDetectionDuration (), &PhyEntity::EndPreambleDetectionPeriod, this, event)); +} + +void +PhyEntity::EndPreambleDetectionPeriod (Ptr event) +{ + NS_LOG_FUNCTION (this << *event); + NS_ASSERT (!m_wifiPhy->IsStateRx ()); + NS_ASSERT (m_wifiPhy->m_endPhyRxEvent.IsExpired ()); //since end of preamble reception is scheduled by this method upon success + + //calculate PER on the measurement channel for PHY headers + uint16_t measurementChannelWidth = m_wifiPhy->GetMeasurementChannelWidth (event->GetPpdu ()); + auto measurementBand = m_wifiPhy->GetBand (measurementChannelWidth); + double maxRxPowerW = -1; //in case current event may not be sent on measurement channel (rxPowerW would be equal to 0) + Ptr maxEvent; + NS_ASSERT (!m_wifiPhy->m_currentPreambleEvents.empty ()); + for (auto preambleEvent : m_wifiPhy->m_currentPreambleEvents) + { + double rxPowerW = preambleEvent.second->GetRxPowerW (measurementBand); + if (rxPowerW > maxRxPowerW) + { + maxRxPowerW = rxPowerW; + maxEvent = preambleEvent.second; + } + } + + NS_ASSERT (maxEvent != 0); + if (maxEvent != event) + { + NS_LOG_DEBUG ("Receiver got a stronger packet with UID " << maxEvent->GetPpdu ()->GetUid () << " during preamble detection: drop packet with UID " << event->GetPpdu ()->GetUid ()); + m_wifiPhy->NotifyRxDrop (GetAddressedPsduInPpdu (event->GetPpdu ()), BUSY_DECODING_PREAMBLE); + auto it = m_wifiPhy->m_currentPreambleEvents.find (std::make_pair (event->GetPpdu ()->GetUid (), event->GetPpdu ()->GetPreamble ())); + m_wifiPhy->m_currentPreambleEvents.erase (it); + //This is needed to cleanup the m_firstPowerPerBand so that the first power corresponds to the power at the start of the PPDU + m_wifiPhy->m_interference.NotifyRxEnd (maxEvent->GetStartTime ()); + //Make sure InterferenceHelper keeps recording events + m_wifiPhy->m_interference.NotifyRxStart (); + return; + } + + m_wifiPhy->m_currentEvent = event; + + double snr = m_wifiPhy->m_interference.CalculateSnr (m_wifiPhy->m_currentEvent, measurementChannelWidth, 1, measurementBand); + NS_LOG_DEBUG ("SNR(dB)=" << RatioToDb (snr) << " at end of preamble detection period"); + + if ((!m_wifiPhy->m_preambleDetectionModel && maxRxPowerW > 0.0) + || (m_wifiPhy->m_preambleDetectionModel && m_wifiPhy->m_preambleDetectionModel->IsPreambleDetected (m_wifiPhy->m_currentEvent->GetRxPowerW (measurementBand), snr, measurementChannelWidth))) + { + for (auto & endPreambleDetectionEvent : m_wifiPhy->m_endPreambleDetectionEvents) + { + endPreambleDetectionEvent.Cancel (); + } + m_wifiPhy->m_endPreambleDetectionEvents.clear (); + + for (auto it = m_wifiPhy->m_currentPreambleEvents.begin (); it != m_wifiPhy->m_currentPreambleEvents.end (); ) + { + if (it->second != m_wifiPhy->m_currentEvent) + { + NS_LOG_DEBUG ("Drop packet with UID " << it->first.first << " and preamble " << it->first.second << " arrived at time " << it->second->GetStartTime ()); + WifiPhyRxfailureReason reason; + if (m_wifiPhy->m_currentEvent->GetPpdu ()->GetUid () > it->first.first) + { + reason = PREAMBLE_DETECTION_PACKET_SWITCH; + //This is needed to cleanup the m_firstPowerPerBand so that the first power corresponds to the power at the start of the PPDU + m_wifiPhy->m_interference.NotifyRxEnd (m_wifiPhy->m_currentEvent->GetStartTime ()); + } + else + { + reason = BUSY_DECODING_PREAMBLE; + } + m_wifiPhy->NotifyRxDrop (GetAddressedPsduInPpdu (it->second->GetPpdu ()), reason); + it = m_wifiPhy->m_currentPreambleEvents.erase (it); + } + else + { + ++it; + } + } + + //Make sure InterferenceHelper keeps recording events + m_wifiPhy->m_interference.NotifyRxStart (); + + m_wifiPhy->NotifyRxBegin (GetAddressedPsduInPpdu (m_wifiPhy->m_currentEvent->GetPpdu ()), m_wifiPhy->m_currentEvent->GetRxPowerWPerBand ()); + m_wifiPhy->m_timeLastPreambleDetected = Simulator::Now (); + + //Continue receiving preamble + Time durationTillEnd = GetDuration (WIFI_PPDU_FIELD_PREAMBLE, event->GetTxVector ()) - m_wifiPhy->GetPreambleDetectionDuration (); + m_state->SwitchMaybeToCcaBusy (durationTillEnd); //will be prolonged by next field + m_wifiPhy->m_endPhyRxEvent = Simulator::Schedule (durationTillEnd, &PhyEntity::EndReceiveField, this, WIFI_PPDU_FIELD_PREAMBLE, event); + } + else + { + NS_LOG_DEBUG ("Drop packet because PHY preamble detection failed"); + // Like CCA-SD, CCA-ED is governed by the 4 us CCA window to flag CCA-BUSY + // for any received signal greater than the CCA-ED threshold. + m_wifiPhy->DropPreambleEvent (m_wifiPhy->m_currentEvent->GetPpdu (), PREAMBLE_DETECT_FAILURE, m_wifiPhy->m_currentEvent->GetEndTime (), m_wifiPhy->GetMeasurementChannelWidth (m_wifiPhy->m_currentEvent->GetPpdu ())); + if (m_wifiPhy->m_currentPreambleEvents.empty ()) + { + //Do not erase events if there are still pending preamble events to be processed + m_wifiPhy->m_interference.NotifyRxEnd (Simulator::Now ()); + } + m_wifiPhy->m_currentEvent = 0; + //Cancel preamble reception + m_wifiPhy->m_endPhyRxEvent.Cancel (); + } +} + +bool +PhyEntity::IsConfigSupported (Ptr ppdu) const +{ + WifiMode txMode = ppdu->GetTxVector ().GetMode (); + if (!IsModeSupported (txMode)) + { + NS_LOG_DEBUG ("Drop packet because it was sent using an unsupported mode (" << txMode << ")"); + return false; + } + return true; +} + +void +PhyEntity::AbortCurrentReception (WifiPhyRxfailureReason reason) +{ + NS_LOG_FUNCTION (this << reason); + //TODO cancel some events here later on + m_wifiPhy->AbortCurrentReception (reason); +} + +void +PhyEntity::ResetReceive (Ptr event) +{ + NS_LOG_FUNCTION (this << *event); + NS_ASSERT (event->GetEndTime () == Simulator::Now ()); //TODO: overload for UL MU + m_wifiPhy->ResetReceive (event); +} + +double +PhyEntity::GetRandomValue (void) const +{ + return m_wifiPhy->m_random->GetValue (); +} + +double +PhyEntity::GetRxPowerWForPpdu (Ptr event) const +{ + return event->GetRxPowerW (m_wifiPhy->GetBand (m_wifiPhy->GetMeasurementChannelWidth (event->GetPpdu ()))); +} + } //namespace ns3 diff --git a/src/wifi/model/phy-entity.h b/src/wifi/model/phy-entity.h index 9ecd9893b..3954a3a06 100644 --- a/src/wifi/model/phy-entity.h +++ b/src/wifi/model/phy-entity.h @@ -24,10 +24,13 @@ #define PHY_ENTITY_H #include "wifi-mpdu-type.h" +#include "wifi-tx-vector.h" #include "wifi-phy-band.h" #include "wifi-ppdu.h" +#include "ns3/event-id.h" #include "ns3/simple-ref-count.h" #include "ns3/nstime.h" +#include #include /** @@ -39,6 +42,12 @@ namespace ns3 { class WifiPsdu; +class WifiPhy; +class InterferenceHelper; +class Event; +class WifiPhyStateHelper; +class WifiPsdu; +class WifiPpdu; /** * \brief Abstract class for PHY entities @@ -51,6 +60,43 @@ class WifiPsdu; class PhyEntity : public SimpleRefCount { public: + + /** + * Action to perform in case of RX failure. + */ + enum PhyRxFailureAction + { + DROP = 0, //!< drop PPDU and set CCA_BUSY + ABORT, //!< abort reception of PPDU + IGNORE //!< ignore the reception + }; + + /** + * Status of the reception of the PPDU field. + */ + struct PhyFieldRxStatus + { + /* *NS_CHECK_STYLE_OFF* */ + bool isSuccess {true}; //!< outcome (\c true if success) of the reception + WifiPhyRxfailureReason reason {UNKNOWN}; //!< failure reason + PhyRxFailureAction actionIfFailure {DROP}; //!< action to perform in case of failure \see PhyRxFailureAction + /** + * Constructor setting outcome of reception. + * + * \param s \c true if success + */ + PhyFieldRxStatus (bool s) : isSuccess (s) {}; + /** + * Constructor. + * + * \param s \c true if success + * \param r reason of failure + * \param a action to perform in case of failure + */ + PhyFieldRxStatus (bool s, WifiPhyRxfailureReason r, PhyRxFailureAction a) : isSuccess (s), reason (r), actionIfFailure (a) {}; + /* *NS_CHECK_STYLE_ON* */ + }; + /** * A struct for both SNR and PER */ @@ -76,6 +122,13 @@ public: */ virtual ~PhyEntity (); + /** + * Set the WifiPhy owning this PHY entity. + * + * \param wifiPhy the WifiPhy owning this PHY entity + */ + void SetOwner (Ptr wifiPhy); + /** * Check if the WifiMode is supported. * @@ -229,6 +282,59 @@ public: virtual Ptr BuildPpdu (const WifiConstPsduMap & psdus, WifiTxVector txVector, Time ppduDuration, WifiPhyBand band, uint64_t uid) const; + /** + * Get the duration of the PPDU up to (but excluding) the given field. + * + * \param field the considered PPDU field + * \param txVector the transmission parameters + * \return the duration from the beginning of the PPDU up to the field + */ + Time GetDurationUpToField (WifiPpduField field, WifiTxVector txVector) const; + /** + * Get the remaining duration of the PPDU after the end of the given field. + * + * \param field the considered PPDU field + * \param ppdu the received PPDU + * \return the remaining duration of the PPDU after the end of to the field + */ + Time GetRemainingDurationAfterField (Ptr ppdu, WifiPpduField field) const; + + /** + * Get the PSDU addressed to that PHY in a PPDU (useful for MU PPDU). + * + * \param ppdu the PPDU to extract the PSDU from + * \return the PSDU addressed to that PHY + */ + virtual Ptr GetAddressedPsduInPpdu (Ptr ppdu) const; + + /** + * Start receiving a given field. + * + * This method will call the DoStartReceiveField (which will should + * be overridden by child classes). + * EndReceiveField is also scheduled after the duration of the field + * (except for the special case of preambles \see DoStartReceivePreamble). + * The PHY is kept in CCA busy during the reception of the field (except for + * data field which should be in RX). + * + * \param field the starting PPDU field + * \param event the event holding incoming PPDU's information + */ + void StartReceiveField (WifiPpduField field, Ptr event); + /** + * End receiving a given field. + * + * This method will call the DoEndReceiveField (which will should + * be overridden by child classes) to obtain the outcome of the reception. + * In case of success, reception of the next field is triggered. + * In case of failure, the indications in the returned \see PhyFieldRxStatus + * are performed. + * + * \param field the ending PPDU field + * \param event the event holding incoming PPDU's information + */ + void EndReceiveField (WifiPpduField field, Ptr event); + protected: /** * A map of PPDU field elements per preamble type. @@ -246,9 +352,131 @@ protected: */ virtual const PpduFormats & GetPpduFormats (void) const = 0; - std::list m_modeList; //!< the list of supported modes + /** + * Start receiving a given field, perform amendment-specific actions, and + * signify if it is supported. + * + * \param field the starting PPDU field + * \param event the event holding incoming PPDU's information + * \return \c true if the field is supported, \c false otherwise + */ + virtual bool DoStartReceiveField (WifiPpduField field, Ptr event); + /** + * End receiving a given field, perform amendment-specific actions, and + * provide the status of the reception. + * + * \param field the ending PPDU field + * \param event the event holding incoming PPDU's information + * \return status of the reception of the PPDU field + */ + virtual PhyFieldRxStatus DoEndReceiveField (WifiPpduField field, Ptr event); + + /** + * Start receiving the preamble, perform amendment-specific actions, and + * signify if it is supported. + * + * This method triggers the start of the preamble detection period (\see + * StartPreambleDetectionPeriod). + * + * \param event the event holding incoming PPDU's information + * \return \c true if the preamble is supported, \c false otherwise + */ + virtual bool DoStartReceivePreamble (Ptr event); + /** + * End receiving the preamble, perform amendment-specific actions, and + * provide the status of the reception. + * + * \param event the event holding incoming PPDU's information + * \return status of the reception of the preamble + */ + virtual PhyFieldRxStatus DoEndReceivePreamble (Ptr event); + /** + * Start the preamble detection period. + * + * \param event the event holding incoming PPDU's information + */ + void StartPreambleDetectionPeriod (Ptr event); + /** + * End the preamble detection period. + * + * The PHY will focus on the strongest PPDU and drop others. + * In addition, in case of successful detection, the end of the + * preamble reception is triggered (\see DoEndReceivePreamble). + * + * \param event the event holding incoming PPDU's information + */ + void EndPreambleDetectionPeriod (Ptr event); + + /** + * Checks if the signaled configuration (excluding bandwidth) + * is supported by the PHY. + * + * \param ppdu the received PPDU + * \return \c true if supported, \c false otherwise + */ + virtual bool IsConfigSupported (Ptr ppdu) const; + + /** + * Abort the current reception. + * + * \param reason the reason the reception is aborted + */ + void AbortCurrentReception (WifiPhyRxfailureReason reason); + /** + * Reset PHY at the end of the PPDU under reception after it has failed the PHY header. + * + * \param event the event holding incoming PPDU's information + */ + void ResetReceive (Ptr event); + + /** + * Obtain a random value from the WifiPhy's generator. + * Wrapper used by child classes. + * + * \return a uniform random value + */ + double GetRandomValue (void) const; + /** + * Obtain the SNR and PER of the PPDU field from the WifiPhy's InterferenceHelper class. + * Wrapper used by child classes. + * + * \param field the PPDU field + * \param event the event holding incoming PPDU's information + * \return the SNR and PER + */ + SnrPer GetPhyHeaderSnrPer (WifiPpduField field, Ptr event) const; + /** + * Obtain the received power (W) for a given band. + * Wrapper used by child classes. + * + * \param event the event holding incoming PPDU's information + * \return the received power (W) for the event over a given band + */ + double GetRxPowerWForPpdu (Ptr event) const; + + Ptr m_wifiPhy; //!< Pointer to the owning WifiPhy + Ptr m_state; //!< Pointer to WifiPhyStateHelper of the WifiPhy (to make it reachable for child classes) + + std::list m_modeList; //!< the list of supported modes }; //class PhyEntity +/** + * \brief Stream insertion operator. + * + * \param os the stream + * \param action the action to perform in case of failure + * \returns a reference to the stream + */ +std::ostream& operator<< (std::ostream& os, const PhyEntity::PhyRxFailureAction &action); +/** + * \brief Stream insertion operator. + * + * \param os the stream + * \param status the status of the reception of a PPDU field + * \returns a reference to the stream + */ +std::ostream& operator<< (std::ostream& os, const PhyEntity::PhyFieldRxStatus &status); + } //namespace ns3 #endif /* PHY_ENTITY_H */ diff --git a/src/wifi/model/vht-phy.cc b/src/wifi/model/vht-phy.cc index 31f282dea..667a061bc 100644 --- a/src/wifi/model/vht-phy.cc +++ b/src/wifi/model/vht-phy.cc @@ -23,6 +23,7 @@ #include "vht-ppdu.h" #include "wifi-psdu.h" #include "wifi-phy.h" //only used for static mode constructor +#include "wifi-utils.h" #include "ns3/log.h" #include "ns3/assert.h" @@ -220,6 +221,99 @@ VhtPhy::BuildPpdu (const WifiConstPsduMap & psdus, WifiTxVector txVector, return Create (psdus.begin ()->second, txVector, ppduDuration, band, uid); } +PhyEntity::PhyFieldRxStatus +VhtPhy::DoEndReceiveField (WifiPpduField field, Ptr event) +{ + NS_LOG_FUNCTION (this << field << *event); + switch (field) + { + case WIFI_PPDU_FIELD_SIG_A: + return EndReceiveSigA (event); + case WIFI_PPDU_FIELD_SIG_B: + return EndReceiveSigB (event); + default: + return HtPhy::DoEndReceiveField (field, event); + } +} + +PhyEntity::PhyFieldRxStatus +VhtPhy::EndReceiveSigA (Ptr event) +{ + NS_LOG_FUNCTION (this << *event); + NS_ASSERT (event->GetTxVector ().GetPreambleType () >= WIFI_PREAMBLE_VHT_SU); + SnrPer snrPer = GetPhyHeaderSnrPer (WIFI_PPDU_FIELD_SIG_A, event); + NS_LOG_DEBUG ("SIG-A: SNR(dB)=" << RatioToDb (snrPer.snr) << ", PER=" << snrPer.per); + PhyFieldRxStatus status (GetRandomValue () > snrPer.per); + if (status.isSuccess) + { + NS_LOG_DEBUG ("Received SIG-A"); + if (!IsAllConfigSupported (WIFI_PPDU_FIELD_SIG_A, event->GetPpdu ())) + { + status = PhyFieldRxStatus (false, UNSUPPORTED_SETTINGS, DROP); + } + status = ProcessSigA (event, status); + } + else + { + NS_LOG_DEBUG ("Drop packet because SIG-A reception failed"); + status.reason = SIG_A_FAILURE; + status.actionIfFailure = DROP; + } + return status; +} + +PhyEntity::PhyFieldRxStatus +VhtPhy::ProcessSigA (Ptr event, PhyFieldRxStatus status) +{ + NS_LOG_FUNCTION (this << *event << status); + //TODO see if something should be done here once MU-MIMO is supported + return status; //nothing special for VHT +} + +PhyEntity::PhyFieldRxStatus +VhtPhy::EndReceiveSigB (Ptr event) +{ + NS_LOG_FUNCTION (this << *event); + NS_ASSERT (event->GetPpdu ()->GetType () == WIFI_PPDU_TYPE_DL_MU); + SnrPer snrPer = GetPhyHeaderSnrPer (WIFI_PPDU_FIELD_SIG_B, event); + NS_LOG_DEBUG ("SIG-B: SNR(dB)=" << RatioToDb (snrPer.snr) << ", PER=" << snrPer.per); + PhyFieldRxStatus status (GetRandomValue () > snrPer.per); + if (status.isSuccess) + { + NS_LOG_DEBUG ("Received SIG-B"); + if (!IsAllConfigSupported (WIFI_PPDU_FIELD_SIG_A, event->GetPpdu ())) + { + status = PhyFieldRxStatus (false, UNSUPPORTED_SETTINGS, DROP); + } + status = ProcessSigB (event, status); + } + else + { + NS_LOG_DEBUG ("Drop reception because SIG-B reception failed"); + status.reason = SIG_B_FAILURE; + status.actionIfFailure = DROP; + } + return status; +} + +PhyEntity::PhyFieldRxStatus +VhtPhy::ProcessSigB (Ptr event, PhyFieldRxStatus status) +{ + NS_LOG_FUNCTION (this << *event << status); + //TODO see if something should be done here once MU-MIMO is supported + return status; //nothing special for VHT +} + +bool +VhtPhy::IsAllConfigSupported (WifiPpduField field, Ptr ppdu) const +{ + if (ppdu->GetType () == WIFI_PPDU_TYPE_DL_MU && field == WIFI_PPDU_FIELD_SIG_A) + { + return IsChannelWidthSupported (ppdu); //perform the full check after SIG-B + } + return HtPhy::IsAllConfigSupported (field, ppdu); +} + void VhtPhy::InitializeModes (void) { diff --git a/src/wifi/model/vht-phy.h b/src/wifi/model/vht-phy.h index 8240cd484..8c528403b 100644 --- a/src/wifi/model/vht-phy.h +++ b/src/wifi/model/vht-phy.h @@ -171,6 +171,50 @@ protected: WifiMode GetHtSigMode (void) const override; Time GetHtSigDuration (void) const override; virtual uint8_t GetNumberBccEncoders (WifiTxVector txVector) const override; + virtual PhyFieldRxStatus DoEndReceiveField (WifiPpduField field, Ptr event) override; + virtual bool IsAllConfigSupported (WifiPpduField field, Ptr ppdu) const override; + + /** + * End receiving the SIG-A, perform VHT-specific actions, and + * provide the status of the reception. + * + * Child classes can perform amendment-specific actions by specializing + * \see ProcessSigA. + * + * \param event the event holding incoming PPDU's information + * \return status of the reception of the SIG-A + */ + PhyFieldRxStatus EndReceiveSigA (Ptr event); + /** + * End receiving the SIG-B, perform VHT-specific actions, and + * provide the status of the reception. + * + * Child classes can perform amendment-specific actions by specializing + * \see ProcessSigB. + * + * \param event the event holding incoming PPDU's information + * \return status of the reception of the SIG-B + */ + PhyFieldRxStatus EndReceiveSigB (Ptr event); + + /** + * Process SIG-A, perform amendment-specific actions, and + * provide an updated status of the reception. + * + * \param event the event holding incoming PPDU's information + * \param status the status of the reception of the correctly received SIG-A after the configuration support check + * \return the updated status of the reception of the SIG-A + */ + virtual PhyFieldRxStatus ProcessSigA (Ptr event, PhyFieldRxStatus status); + /** + * Process SIG-B, perform amendment-specific actions, and + * provide an updated status of the reception. + * + * \param event the event holding incoming PPDU's information + * \param status the status of the reception of the correctly received SIG-B after the configuration support check + * \return the updated status of the reception of the SIG-B + */ + virtual PhyFieldRxStatus ProcessSigB (Ptr event, PhyFieldRxStatus status); private: // Inherited diff --git a/src/wifi/model/wifi-phy.cc b/src/wifi/model/wifi-phy.cc index 39ed60c10..887e1c7f2 100644 --- a/src/wifi/model/wifi-phy.cc +++ b/src/wifi/model/wifi-phy.cc @@ -1012,6 +1012,7 @@ WifiPhy::AddPhyEntity (WifiModulationClass modulation, Ptr phyEntity) NS_LOG_FUNCTION (this << modulation); NS_ABORT_MSG_IF (m_staticPhyEntities.find (modulation) == m_staticPhyEntities.end (), "Cannot add an unimplemented PHY to supported list. Update the former first."); NS_ASSERT_MSG (m_phyEntities.find (modulation) == m_phyEntities.end (), "The PHY entity has already been added. The setting should only be done once per modulation class"); + phyEntity->SetOwner (this); m_phyEntities[modulation] = phyEntity; } diff --git a/src/wifi/model/wifi-phy.h b/src/wifi/model/wifi-phy.h index ae05de5d2..9a26172f4 100644 --- a/src/wifi/model/wifi-phy.h +++ b/src/wifi/model/wifi-phy.h @@ -22,7 +22,6 @@ #ifndef WIFI_PHY_H #define WIFI_PHY_H -#include "ns3/event-id.h" #include "ns3/error-model.h" #include "wifi-standards.h" #include "interference-helper.h" @@ -79,6 +78,7 @@ struct RxSignalInfo class WifiPhy : public Object { public: + friend class PhyEntity; /** * \brief Get the type ID. * \return the object TypeId @@ -1187,7 +1187,7 @@ protected: * \param channelWidth the channel width in MHz used for RSSI measurement */ void SwitchMaybeToCcaBusy (uint16_t channelWidth); - +public: //TODO find a better way (robust enough for OfdmaSpectrumWifiPhy overload) /** * Return the STA ID that has been assigned to the station this PHY belongs to. * This is typically called for MU PPDUs, in order to pick the correct PSDU. @@ -1196,7 +1196,7 @@ protected: * \return the STA ID */ virtual uint16_t GetStaId (const Ptr ppdu) const; - +protected: /** * Return the channel width used to measure the RSSI. * This corresponds to the primary channel unless it corresponds to the