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