From e4bc5ff26009901637b1cfb89f260b5b56ebf8fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Deronne?= Date: Thu, 8 Aug 2019 12:41:42 +0200 Subject: [PATCH] wifi: PHY logic changes to handle HE TB PPDUs reception --- src/wifi/model/interference-helper.cc | 32 ++- src/wifi/model/interference-helper.h | 8 +- src/wifi/model/spectrum-wifi-phy.cc | 32 ++- src/wifi/model/wifi-phy-state-helper.cc | 8 +- src/wifi/model/wifi-phy.cc | 320 +++++++++++++++++------- src/wifi/model/wifi-phy.h | 19 +- src/wifi/model/wifi-ppdu.cc | 7 +- src/wifi/model/wifi-ppdu.h | 2 +- 8 files changed, 299 insertions(+), 129 deletions(-) diff --git a/src/wifi/model/interference-helper.cc b/src/wifi/model/interference-helper.cc index 39516a63d..0781e287c 100644 --- a/src/wifi/model/interference-helper.cc +++ b/src/wifi/model/interference-helper.cc @@ -181,10 +181,10 @@ InterferenceHelper::~InterferenceHelper () } Ptr -InterferenceHelper::Add (Ptr ppdu, WifiTxVector txVector, Time duration, RxPowerWattPerChannelBand rxPowerW) +InterferenceHelper::Add (Ptr ppdu, WifiTxVector txVector, Time duration, RxPowerWattPerChannelBand rxPowerW, bool isStartOfdmaRxing) { Ptr event = Create (ppdu, txVector, duration, rxPowerW); - AppendEvent (event); + AppendEvent (event, isStartOfdmaRxing); return event; } @@ -265,9 +265,9 @@ InterferenceHelper::GetEnergyDuration (double energyW, WifiSpectrumBand band) } void -InterferenceHelper::AppendEvent (Ptr event) +InterferenceHelper::AppendEvent (Ptr event, bool isStartOfdmaRxing) { - NS_LOG_FUNCTION (this << event); + NS_LOG_FUNCTION (this << event << isStartOfdmaRxing); RxPowerWattPerChannelBand rxPowerWattPerChannelBand = event->GetRxPowerWPerBand (); for (auto const& it : rxPowerWattPerChannelBand) { @@ -284,6 +284,13 @@ InterferenceHelper::AppendEvent (Ptr event) // Always leave the first zero power noise event in the list ni_it->second.erase (++(ni_it->second.begin ()), GetNextPosition (event->GetStartTime (), band)); } + else if (isStartOfdmaRxing) + { + //When the first UL-OFDMA payload is received, we need to set m_firstPowerPerBand + //so that it takes into account interferences that arrived between the start of the + //UL MU transmission and the start of UL-OFDMA payload. + m_firstPowerPerBand.find (band)->second = previousPowerStart; + } auto first = AddNiChangeEvent (event->GetStartTime (), NiChange (previousPowerStart, event), band); auto last = AddNiChangeEvent (event->GetEndTime (), NiChange (previousPowerEnd, event), band); for (auto i = first; i != last; ++i) @@ -406,10 +413,19 @@ InterferenceHelper::CalculatePayloadPer (Ptr event, uint16_t channe Time previous = j->first; WifiMode payloadMode = txVector.GetMode (staId); WifiPreamble preamble = txVector.GetPreambleType (); - Time phyHeaderStart = j->first + WifiPhy::GetPhyPreambleDuration (txVector); //PPDU start time + preamble - Time phyHtSigHeaderStart = phyHeaderStart + WifiPhy::GetPhyHeaderDuration (txVector); //PPDU start time + preamble + L-SIG - Time phyTrainingSymbolsStart = phyHtSigHeaderStart + WifiPhy::GetPhyHtSigHeaderDuration (preamble) + WifiPhy::GetPhySigA1Duration (preamble) + WifiPhy::GetPhySigA2Duration (preamble); //PPDU start time + preamble + L-SIG + HT-SIG or SIG-A - Time phyPayloadStart = phyTrainingSymbolsStart + WifiPhy::GetPhyTrainingSymbolDuration (txVector) + WifiPhy::GetPhySigBDuration (txVector); //PPDU start time + preamble + L-SIG + HT-SIG or SIG-A + Training + SIG-B + Time phyPayloadStart; + if (!event->GetPpdu ()->IsUlMu ()) + { + Time phyHeaderStart = j->first + WifiPhy::GetPhyPreambleDuration (txVector); //PPDU start time + preamble + Time phyHtSigHeaderStart = phyHeaderStart + WifiPhy::GetPhyHeaderDuration (txVector); //PPDU start time + preamble + L-SIG + Time phyTrainingSymbolsStart = phyHtSigHeaderStart + WifiPhy::GetPhyHtSigHeaderDuration (preamble) + WifiPhy::GetPhySigA1Duration (preamble) + WifiPhy::GetPhySigA2Duration (preamble); //PPDU start time + preamble + L-SIG + HT-SIG or SIG-A + phyPayloadStart = phyTrainingSymbolsStart + WifiPhy::GetPhyTrainingSymbolDuration (txVector) + WifiPhy::GetPhySigBDuration (txVector); //PPDU start time + preamble + L-SIG + HT-SIG or SIG-A + Training + SIG-B + } + else + { + //j->first corresponds to the start of the UL-OFDMA payload + phyPayloadStart = j->first; + } Time windowStart = phyPayloadStart + window.first; Time windowEnd = phyPayloadStart + window.second; double noiseInterferenceW = m_firstPowerPerBand.find (band)->second; diff --git a/src/wifi/model/interference-helper.h b/src/wifi/model/interference-helper.h index 3704dd6f4..d17e98efd 100644 --- a/src/wifi/model/interference-helper.h +++ b/src/wifi/model/interference-helper.h @@ -211,10 +211,11 @@ public: * \param txVector the TXVECTOR * \param duration the PPDU duration * \param rxPower received power per band (W) + * \param isStartOfdmaRxing flag whether the event corresponds to the start of the OFDMA payload reception (only used for UL-OFDMA) * * \return Event */ - Ptr Add (Ptr ppdu, WifiTxVector txVector, Time duration, RxPowerWattPerChannelBand rxPower); + Ptr Add (Ptr ppdu, WifiTxVector txVector, Time duration, RxPowerWattPerChannelBand rxPower, bool isStartOfdmaRxing = false); /** * Add a non-Wifi signal to interference helper. @@ -373,9 +374,10 @@ private: /** * Append the given Event. * - * \param event + * \param event the event to be appended + * \param isStartOfdmaRxing flag whether event corresponds to the start of the OFDMA payload reception (only used for UL-OFDMA) */ - void AppendEvent (Ptr event); + void AppendEvent (Ptr event, bool isStartOfdmaRxing); /** * Calculate noise and interference power in W. diff --git a/src/wifi/model/spectrum-wifi-phy.cc b/src/wifi/model/spectrum-wifi-phy.cc index e012e8683..a4d57dad7 100644 --- a/src/wifi/model/spectrum-wifi-phy.cc +++ b/src/wifi/model/spectrum-wifi-phy.cc @@ -34,8 +34,6 @@ #include "wifi-utils.h" #include "wifi-ppdu.h" #include "wifi-psdu.h" -#include "ap-wifi-mac.h" -#include "wifi-net-device.h" namespace ns3 { @@ -360,19 +358,33 @@ SpectrumWifiPhy::StartRx (Ptr rxParams) NS_LOG_INFO ("Received Wi-Fi signal"); Ptr ppdu = Copy (wifiRxParams->ppdu); if (ppdu->GetTxVector ().GetPreambleType () == WIFI_PREAMBLE_HE_TB - && wifiRxParams->txPsdFlag == PSD_HE_TB_OFDMA_PORTION - && m_currentHeTbPpduUid == ppdu->GetUid ()) - { - Ptr device = DynamicCast (GetDevice ()); - bool isAp = (DynamicCast (device->GetMac ()) != 0); - if (isAp) + && wifiRxParams->txPsdFlag == PSD_HE_TB_OFDMA_PORTION) + { + if (m_currentHeTbPpduUid == ppdu->GetUid () && m_currentEvent != 0) { + //AP and STA already received non-OFDMA part, handle OFDMA payload reception StartReceiveOfdmaPayload (ppdu, rxPowerW); } else { - NS_LOG_INFO ("Ignore UL-OFDMA since device is not AP"); - m_currentPreambleEvents.clear (); + //PHY receives the OFDMA payload while having dropped the preamble + NS_LOG_INFO ("Consider UL-OFDMA part of the HE TB PPDU as interference since device dropped the preamble"); + m_interference.Add (ppdu, ppdu->GetTxVector (), rxDuration, rxPowerW); + auto it = m_currentPreambleEvents.find (std::make_pair(ppdu->GetUid (), ppdu->GetPreamble ())); + if (it != m_currentPreambleEvents.end ()) + { + m_currentPreambleEvents.erase (it); + } + if (m_currentPreambleEvents.empty ()) + { + Reset (); + } + + if (rxDuration > m_state->GetDelayUntilIdle ()) + { + //that packet will be noise _after_ the completion of the OFDMA part of the HE TB PPDUs + SwitchMaybeToCcaBusy (); + } } } else diff --git a/src/wifi/model/wifi-phy-state-helper.cc b/src/wifi/model/wifi-phy-state-helper.cc index c55a0c2fc..9d5943a60 100644 --- a/src/wifi/model/wifi-phy-state-helper.cc +++ b/src/wifi/model/wifi-phy-state-helper.cc @@ -477,10 +477,11 @@ WifiPhyStateHelper::ContinueRxNextMpdu (Ptr psdu, double snr, WifiTxVe void WifiPhyStateHelper::SwitchFromRxEndOk (Ptr psdu, double snr, WifiTxVector txVector, uint16_t staId, std::vector statusPerMpdu) { - NS_LOG_FUNCTION (this << *psdu << snr << txVector << statusPerMpdu.size () << + NS_LOG_FUNCTION (this << *psdu << snr << txVector << staId << statusPerMpdu.size () << std::all_of(statusPerMpdu.begin(), statusPerMpdu.end(), [](bool v) { return v; })); //returns true if all true NS_ASSERT (statusPerMpdu.size () != 0); - NS_ASSERT (m_endRx == Simulator::Now ()); + NS_ASSERT (Abs (m_endRx - Simulator::Now ()) < MicroSeconds (1)); //1us corresponds to the maximum propagation delay (delay spread) + //TODO: a better fix would be to call the function once all HE TB PPDUs are received m_rxOkTrace (psdu->GetPacket (), snr, txVector.GetMode (staId), txVector.GetPreambleType ()); NotifyRxEndOk (); DoSwitchFromRx (); @@ -494,7 +495,8 @@ void WifiPhyStateHelper::SwitchFromRxEndError (Ptr psdu, double snr) { NS_LOG_FUNCTION (this << *psdu << snr); - NS_ASSERT (m_endRx == Simulator::Now ()); + NS_ASSERT (Abs (m_endRx - Simulator::Now ()) < MicroSeconds (1)); //1us corresponds to the maximum propagation delay (delay spread) + //TODO: a better fix would be to call the function once all HE TB PPDUs are received m_rxErrorTrace (psdu->GetPacket (), snr); NotifyRxEndError (); DoSwitchFromRx (); diff --git a/src/wifi/model/wifi-phy.cc b/src/wifi/model/wifi-phy.cc index cb00d7692..8d6a229be 100644 --- a/src/wifi/model/wifi-phy.cc +++ b/src/wifi/model/wifi-phy.cc @@ -39,6 +39,7 @@ #include "he-configuration.h" #include "mpdu-aggregator.h" #include "wifi-psdu.h" +#include "ap-wifi-mac.h" namespace ns3 { @@ -508,9 +509,9 @@ WifiPhy::GetTypeId (void) WifiPhy::WifiPhy () : m_txMpduReferenceNumber (0xffffffff), m_rxMpduReferenceNumber (0xffffffff), - m_endRxEvent (), m_endPhyRxEvent (), m_endTxEvent (), + m_currentEvent (0), m_previouslyRxPpduUid (UINT64_MAX), m_currentHeTbPpduUid (UINT64_MAX), m_standard (WIFI_PHY_STANDARD_UNSPECIFIED), @@ -531,9 +532,9 @@ WifiPhy::WifiPhy () m_rxSpatialStreams (0), m_channelNumber (0), m_initialChannelNumber (0), - m_currentEvent (0), m_wifiRadioEnergyModel (0), - m_timeLastPreambleDetected (Seconds (0)) + m_timeLastPreambleDetected (Seconds (0)), + m_ofdmaStarted (false) { NS_LOG_FUNCTION (this); m_random = CreateObject (); @@ -550,8 +551,12 @@ WifiPhy::DoDispose (void) { NS_LOG_FUNCTION (this); m_endTxEvent.Cancel (); - m_endRxEvent.Cancel (); m_endPhyRxEvent.Cancel (); + for (auto & endRxEvent : m_endRxEvents) + { + endRxEvent.Cancel (); + } + m_endRxEvents.clear (); for (auto & endPreambleDetectionEvent : m_endPreambleDetectionEvents) { endPreambleDetectionEvent.Cancel (); @@ -1697,7 +1702,11 @@ WifiPhy::DoChannelSwitch (uint8_t nch) case WifiPhyState::RX: NS_LOG_DEBUG ("drop packet because of channel switching while reception"); m_endPhyRxEvent.Cancel (); - m_endRxEvent.Cancel (); + for (auto & endRxEvent : m_endRxEvents) + { + endRxEvent.Cancel (); + } + m_endRxEvents.clear (); for (auto & endPreambleDetectionEvent : m_endPreambleDetectionEvents) { endPreambleDetectionEvent.Cancel (); @@ -1717,7 +1726,11 @@ WifiPhy::DoChannelSwitch (uint8_t nch) endPreambleDetectionEvent.Cancel (); } m_endPreambleDetectionEvents.clear (); - m_endRxEvent.Cancel (); + for (auto & endRxEvent : m_endRxEvents) + { + endRxEvent.Cancel (); + } + m_endRxEvents.clear (); } goto switchChannel; break; @@ -1766,7 +1779,11 @@ WifiPhy::DoFrequencySwitch (uint16_t frequency) case WifiPhyState::RX: NS_LOG_DEBUG ("drop packet because of channel/frequency switching while reception"); m_endPhyRxEvent.Cancel (); - m_endRxEvent.Cancel (); + for (auto & endRxEvent : m_endRxEvents) + { + endRxEvent.Cancel (); + } + m_endRxEvents.clear (); for (auto & endPreambleDetectionEvent : m_endPreambleDetectionEvents) { endPreambleDetectionEvent.Cancel (); @@ -1785,7 +1802,11 @@ WifiPhy::DoFrequencySwitch (uint16_t frequency) endPreambleDetectionEvent.Cancel (); } m_endPreambleDetectionEvents.clear (); - m_endRxEvent.Cancel (); + for (auto & endRxEvent : m_endRxEvents) + { + endRxEvent.Cancel (); + } + m_endRxEvents.clear (); goto switchFrequency; break; case WifiPhyState::SLEEP: @@ -1854,8 +1875,12 @@ WifiPhy::SetOffMode (void) m_powerRestricted = false; m_channelAccessRequested = false; m_endPhyRxEvent.Cancel (); - m_endRxEvent.Cancel (); m_endTxEvent.Cancel (); + for (auto & endRxEvent : m_endRxEvents) + { + endRxEvent.Cancel (); + } + m_endRxEvents.clear (); for (auto & endPreambleDetectionEvent : m_endPreambleDetectionEvents) { endPreambleDetectionEvent.Cancel (); @@ -2936,6 +2961,7 @@ WifiPhy::Reset (void) NS_LOG_FUNCTION (this); m_currentPreambleEvents.clear (); m_currentEvent = 0; + m_ofdmaStarted = false; } void @@ -2945,10 +2971,12 @@ WifiPhy::StartReceiveHeader (Ptr event) NS_ASSERT (!IsStateRx ()); NS_ASSERT (m_endPhyRxEvent.IsExpired ()); + //calculate PER on the 20 MHz primary channel for PHY headers uint16_t primaryChannelWidth = GetChannelWidth () >= 40 ? 20 : GetChannelWidth (); auto primaryBand = GetBand (primaryChannelWidth); double maxRxPowerW = 0; Ptr maxEvent; + NS_ASSERT (!m_currentPreambleEvents.empty ()); for (auto preambleEvent : m_currentPreambleEvents) { double rxPowerW = preambleEvent.second->GetRxPowerW (primaryBand); @@ -2974,24 +3002,13 @@ WifiPhy::StartReceiveHeader (Ptr event) } m_currentEvent = event; - - uint16_t channelWidth; - if (m_currentEvent->GetTxVector ().GetChannelWidth () >= 40) - { - channelWidth = 20; //calculate PER on the 20 MHz primary channel for PHY headers - } - else - { - channelWidth = m_currentEvent->GetTxVector ().GetChannelWidth (); - } - auto band = GetBand (channelWidth); - InterferenceHelper::SnrPer snrPer = m_interference.CalculateNonHtPhyHeaderSnrPer (m_currentEvent, band); - double snr = snrPer.snr; - NS_LOG_DEBUG ("snr(dB)=" << RatioToDb (snrPer.snr)); + + double snr = m_interference.CalculateSnr (m_currentEvent, primaryChannelWidth, 1, primaryBand); + NS_LOG_DEBUG ("SNR(dB)=" << RatioToDb (snr) << " at start of legacy PHY header"); Time headerPayloadDuration = m_currentEvent->GetStartTime () + m_currentEvent->GetPpdu ()->GetTxDuration () - Simulator::Now (); - if (!m_preambleDetectionModel || (m_preambleDetectionModel->IsPreambleDetected (m_currentEvent->GetRxPowerW (band), snr, m_channelWidth))) + if (!m_preambleDetectionModel || (m_preambleDetectionModel->IsPreambleDetected (m_currentEvent->GetRxPowerW (primaryBand), snr, primaryChannelWidth))) { for (auto & endPreambleDetectionEvent : m_endPreambleDetectionEvents) { @@ -3079,7 +3096,7 @@ WifiPhy::ContinueReceiveHeader (Ptr event) } InterferenceHelper::SnrPer snrPer = m_interference.CalculateNonHtPhyHeaderSnrPer (event, GetBand (channelWidth)); - NS_LOG_DEBUG ("snr(dB)=" << RatioToDb (snrPer.snr) << ", per=" << snrPer.per); + NS_LOG_DEBUG ("SNR(dB)=" << RatioToDb (snrPer.snr) << ", PER=" << snrPer.per); if (m_random->GetValue () > snrPer.per) //non-HT PHY header reception succeeded { NS_LOG_DEBUG ("Received non-HT PHY header"); @@ -3303,13 +3320,28 @@ WifiPhy::StartReceiveOfdmaPayload (Ptr ppdu, RxPowerWattPerChannelBand return p1.second < p2.second; }); NS_LOG_FUNCTION (this << *ppdu << it->second); - WifiTxVector txVector = ppdu->GetTxVector (); Time payloadDuration = ppdu->GetTxDuration () - CalculatePhyPreambleAndHeaderDuration (txVector); - Ptr event = m_interference.Add (ppdu, txVector, payloadDuration, rxPowersW); - - NS_ASSERT (m_endRxEvent.IsExpired ()); - m_endRxEvent = Simulator::Schedule (payloadDuration, &WifiPhy::EndReceive, this, event); + Ptr event = m_interference.Add (ppdu, txVector, payloadDuration, rxPowersW, !m_ofdmaStarted); + m_ofdmaStarted = true; + Ptr device = DynamicCast (GetDevice ()); + bool isAp = (DynamicCast (device->GetMac ()) != 0); + if (isAp) + { + Ptr psdu = GetAddressedPsduInPpdu (ppdu); + if (psdu->GetNMpdus () > 1) + { + ScheduleEndOfMpdus (event); + } + m_endRxEvents.push_back (Simulator::Schedule (payloadDuration, &WifiPhy::EndReceive, this, event)); + m_signalNoiseMap.insert ({std::make_pair (ppdu->GetUid (), ppdu->GetStaId ()), SignalNoiseDbm ()}); + m_statusPerMpduMap.insert ({std::make_pair (ppdu->GetUid (), ppdu->GetStaId ()), std::vector ()}); + } + else + { + //Don't do anything special for STAs since ResetReceive has already been scheduled by StartReceivePayload + NS_ASSERT (m_endRxEvents.size () == 1 && m_endRxEvents.front ().IsRunning ()); + } } void @@ -3317,17 +3349,17 @@ WifiPhy::StartReceivePayload (Ptr event) { NS_LOG_FUNCTION (this << *event); NS_ASSERT (m_endPhyRxEvent.IsExpired ()); - NS_ASSERT (m_endRxEvent.IsExpired ()); bool canReceivePayload = false; Ptr ppdu = event->GetPpdu (); WifiModulationClass modulation = ppdu->GetModulation (); //calculate PER on the primary 20 MHz channel for PHY headers uint16_t primaryChannelWidth = std::min (event->GetTxVector ().GetChannelWidth (), static_cast (20)); auto primaryBand = GetBand (primaryChannelWidth); + if (modulation >= WIFI_MOD_CLASS_HT) { InterferenceHelper::SnrPer snrPer = m_interference.CalculateHtPhyHeaderSnrPer (event, primaryBand); - NS_LOG_DEBUG ("snr(dB)=" << RatioToDb (snrPer.snr) << ", per=" << snrPer.per); + NS_LOG_DEBUG ("SNR(dB)=" << RatioToDb (snrPer.snr) << ", PER=" << snrPer.per); canReceivePayload = (m_random->GetValue () > snrPer.per); } else @@ -3357,6 +3389,7 @@ WifiPhy::StartReceivePayload (Ptr event) } } } + if (nss > GetMaxSupportedRxSpatialStreams ()) { NS_LOG_DEBUG ("Packet reception could not be started because not enough RX antennas"); @@ -3369,23 +3402,37 @@ WifiPhy::StartReceivePayload (Ptr event) } else if (IsModeSupported (txMode) || IsMcsSupported (txMode)) { - m_statusPerMpdu.clear(); - if (psdu->GetNMpdus () > 1) - { - ScheduleEndOfMpdus (event); - } m_state->SwitchToRx (payloadDuration); m_phyRxPayloadBeginTrace (txVector, payloadDuration); //this callback (equivalent to PHY-RXSTART primitive) is triggered only if headers have been correctly decoded and that the mode within is supported - success = true; - NS_LOG_DEBUG ("Receiving PSDU"); - if (txVector.GetPreambleType () == WIFI_PREAMBLE_HE_TB) + + Ptr device = DynamicCast (GetDevice ()); + bool isAp = device != 0 && (DynamicCast (device->GetMac ()) != 0); + if (txVector.GetPreambleType () == WIFI_PREAMBLE_HE_TB && !isAp) { + NS_LOG_DEBUG ("Ignore UL-OFDMA (OFDMA part of HE TB PPDU) received by STA but keep state in Rx"); m_currentHeTbPpduUid = ppdu->GetUid (); - //EndReceive is scheduled by StartReceiveOfdmaPayload + //ResetReceive is scheduled below at end of PSDU } else { - m_endRxEvent = Simulator::Schedule (payloadDuration, &WifiPhy::EndReceive, this, event); + success = true; + NS_LOG_DEBUG ("Receiving PSDU"); + m_signalNoiseMap.insert ({std::make_pair (ppdu->GetUid (), staId), SignalNoiseDbm ()}); + m_statusPerMpduMap.insert ({std::make_pair (ppdu->GetUid (), staId), std::vector ()}); + if (txVector.GetPreambleType () == WIFI_PREAMBLE_HE_TB) + { + //for HE TB PPDUs, ScheduleEndOfMpdus and EndReceive are scheduled by StartReceiveOfdmaPayload + NS_ASSERT (isAp); + m_currentHeTbPpduUid = ppdu->GetUid (); + } + else + { + if (psdu->GetNMpdus () > 1) + { + ScheduleEndOfMpdus (event); + } + m_endRxEvents.push_back (Simulator::Schedule (payloadDuration, &WifiPhy::EndReceive, this, event)); + } } } else //mode is not allowed @@ -3418,7 +3465,7 @@ WifiPhy::StartReceivePayload (Ptr event) { if (payloadDuration.IsStrictlyPositive ()) { - m_endRxEvent = Simulator::Schedule (payloadDuration, &WifiPhy::ResetReceive, this, event); + m_endRxEvents.push_back (Simulator::Schedule (payloadDuration, &WifiPhy::ResetReceive, this, event)); } else { @@ -3436,7 +3483,9 @@ WifiPhy::ScheduleEndOfMpdus (Ptr event) { NS_LOG_FUNCTION (this << *event); Ptr ppdu = event->GetPpdu (); + Ptr psdu = GetAddressedPsduInPpdu (ppdu); WifiTxVector txVector = event->GetTxVector (); + uint16_t staId = GetStaId (ppdu); Time endOfMpduDuration = NanoSeconds (0); Time relativeStart = NanoSeconds (0); Time psduDuration = ppdu->GetTxDuration () - CalculatePhyPreambleAndHeaderDuration (txVector); @@ -3444,9 +3493,7 @@ WifiPhy::ScheduleEndOfMpdus (Ptr event) MpduType mpdutype = FIRST_MPDU_IN_AGGREGATE; uint32_t totalAmpduSize = 0; double totalAmpduNumSymbols = 0.0; - Ptr psdu = GetAddressedPsduInPpdu (ppdu); size_t nMpdus = psdu->GetNMpdus (); - uint16_t staId = SU_STA_ID; auto mpdu = psdu->begin (); for (size_t i = 0; i < nMpdus && mpdu != psdu->end (); ++mpdu) { @@ -3476,49 +3523,10 @@ WifiPhy::EndOfMpdu (Ptr event, Ptr psdu, size_t mpduIndex { NS_LOG_FUNCTION (this << *event << mpduIndex << relativeStart << mpduDuration); Ptr ppdu = event->GetPpdu (); - uint16_t staId = GetStaId (ppdu); WifiTxVector txVector = event->GetTxVector (); - uint16_t channelWidth = std::min (GetChannelWidth (), txVector.GetChannelWidth ()); - double snr = m_interference.CalculateSnr (event, channelWidth, txVector.GetNss (staId), GetBand (channelWidth)); - - std::pair rxInfo = GetReceptionStatus (psdu, event, staId, relativeStart, mpduDuration); - NS_LOG_DEBUG ("Extracted MPDU #" << mpduIndex << ": duration: " << mpduDuration.GetNanoSeconds () << "ns" << - ", correct reception: " << rxInfo.first << ", Signal/Noise: " << rxInfo.second.signal << "/" << rxInfo.second.noise << "dBm"); - - m_signalNoise = rxInfo.second; - m_statusPerMpdu.push_back (rxInfo.first); - - if (rxInfo.first) - { - m_state->ContinueRxNextMpdu (Copy (psdu), snr, event->GetTxVector ()); - } -} - -void -WifiPhy::EndReceive (Ptr event) -{ - Time psduDuration = event->GetEndTime () - event->GetStartTime (); - NS_LOG_FUNCTION (this << *event << psduDuration); - Ptr ppdu = event->GetPpdu (); - if (!ppdu->IsUlMu ()) - { - NS_ASSERT (GetLastRxEndTime () == Simulator::Now ()); - } - NS_ASSERT (event->GetEndTime () == Simulator::Now ()); - uint16_t staId = GetStaId (ppdu); - Ptr psdu = GetAddressedPsduInPpdu (ppdu); - if (psdu->GetNMpdus () == 1) - { - //We do not enter here for A-MPDU since this is done in WifiPhy::EndOfMpdu - std::pair rxInfo = GetReceptionStatus (psdu, event, staId, NanoSeconds (0), psduDuration); - m_signalNoise = rxInfo.second; - m_statusPerMpdu.push_back (rxInfo.first); - } - NotifyRxEnd (psdu); - WifiTxVector txVector = event->GetTxVector (); - uint16_t channelWidth = std::min (GetChannelWidth (), txVector.GetChannelWidth ()); + uint16_t channelWidth = std::min (GetChannelWidth (), event->GetTxVector ().GetChannelWidth ()); WifiSpectrumBand band; if (txVector.IsMu ()) { @@ -3530,12 +3538,72 @@ WifiPhy::EndReceive (Ptr event) band = GetBand (channelWidth); } double snr = m_interference.CalculateSnr (event, channelWidth, txVector.GetNss (staId), band); - if (std::count (m_statusPerMpdu.begin (), m_statusPerMpdu.end (), true)) + + std::pair rxInfo = GetReceptionStatus (psdu, event, staId, relativeStart, mpduDuration); + NS_LOG_DEBUG ("Extracted MPDU #" << mpduIndex << ": duration: " << mpduDuration.GetNanoSeconds () << "ns" << + ", correct reception: " << rxInfo.first << ", Signal/Noise: " << rxInfo.second.signal << "/" << rxInfo.second.noise << "dBm"); + + auto signalNoiseIt = m_signalNoiseMap.find (std::make_pair (ppdu->GetUid (), staId)); + NS_ASSERT (signalNoiseIt != m_signalNoiseMap.end ()); + signalNoiseIt->second = rxInfo.second; + + auto statusPerMpduIt = m_statusPerMpduMap.find (std::make_pair (ppdu->GetUid (), staId)); + NS_ASSERT (statusPerMpduIt != m_statusPerMpduMap.end ()); + statusPerMpduIt->second.push_back (rxInfo.first); + + if (rxInfo.first) { + m_state->ContinueRxNextMpdu (Copy (psdu), snr, txVector); + } +} + +void +WifiPhy::EndReceive (Ptr event) +{ + Ptr ppdu = event->GetPpdu (); + WifiTxVector txVector = event->GetTxVector (); + Time psduDuration = ppdu->GetTxDuration () - CalculatePhyPreambleAndHeaderDuration (txVector); + NS_LOG_FUNCTION (this << *event << psduDuration); + if (!ppdu->IsUlMu ()) + { + NS_ASSERT (GetLastRxEndTime () == Simulator::Now ()); + } + NS_ASSERT (event->GetEndTime () == Simulator::Now ()); + + uint16_t staId = GetStaId (ppdu); + WifiSpectrumBand band; + uint16_t channelWidth = std::min (GetChannelWidth (), txVector.GetChannelWidth ()); + if (txVector.IsMu ()) + { + band = GetRuBand (txVector, staId); + channelWidth = HeRu::GetBandwidth (txVector.GetRu (staId).ruType); + } + else + { + band = GetBand (channelWidth); + } + double snr = m_interference.CalculateSnr (event, channelWidth, txVector.GetNss (staId), band); + + Ptr psdu = GetAddressedPsduInPpdu (ppdu); + NotifyRxEnd (psdu); + + auto signalNoiseIt = m_signalNoiseMap.find (std::make_pair (ppdu->GetUid (), staId)); + NS_ASSERT (signalNoiseIt != m_signalNoiseMap.end ()); + auto statusPerMpduIt = m_statusPerMpduMap.find (std::make_pair (ppdu->GetUid (), staId)); + NS_ASSERT (statusPerMpduIt != m_statusPerMpduMap.end ()); + if (psdu->GetNMpdus () == 1) + { + //We do not enter here for A-MPDU since this is done in WifiPhy::EndOfMpdu + std::pair rxInfo = GetReceptionStatus (psdu, event, staId, NanoSeconds (0), psduDuration); + signalNoiseIt->second = rxInfo.second; + statusPerMpduIt->second.push_back (rxInfo.first); + } + + if (std::count (statusPerMpduIt->second.begin (), statusPerMpduIt->second.end (), true)) + { //At least one MPDU has been successfully received - WifiTxVector txVector = event->GetTxVector (); - NotifyMonitorSniffRx (psdu, GetFrequency (), txVector, m_signalNoise, m_statusPerMpdu, staId); - m_state->SwitchFromRxEndOk (Copy (psdu), snr, txVector, staId, m_statusPerMpdu); + NotifyMonitorSniffRx (psdu, GetFrequency (), txVector, signalNoiseIt->second, statusPerMpduIt->second, staId); + m_state->SwitchFromRxEndOk (Copy (psdu), snr, txVector, staId, statusPerMpduIt->second); m_previouslyRxPpduUid = event->GetPpdu ()->GetUid (); //store UID only if reception is successful (because otherwise trigger won't be read by MAC layer) } else @@ -3543,9 +3611,48 @@ WifiPhy::EndReceive (Ptr event) m_state->SwitchFromRxEndError (Copy (psdu), snr); } - m_interference.NotifyRxEnd (Simulator::Now ()); - m_currentEvent = 0; - m_currentPreambleEvents.clear (); + if (ppdu->IsUlMu ()) + { + for (auto it = m_endRxEvents.begin (); it != m_endRxEvents.end (); ) + { + if (it->IsExpired ()) + { + it = m_endRxEvents.erase (it); + } + else + { + it++; + } + } + if (m_endRxEvents.empty ()) + { + //We got the last PPDU of the UL-OFDMA transmission + m_interference.NotifyRxEnd (Simulator::Now ()); + m_signalNoiseMap.clear (); + m_statusPerMpduMap.clear (); + for (const auto & endOfMpduEvent : m_endOfMpduEvents) + { + NS_ASSERT (endOfMpduEvent.IsExpired ()); + } + m_endOfMpduEvents.clear (); + Reset (); + } + } + else + { + m_interference.NotifyRxEnd (Simulator::Now ()); + MaybeCcaBusyDuration (); + m_currentEvent = 0; + m_currentPreambleEvents.clear (); + m_endRxEvents.clear (); + m_signalNoiseMap.clear (); + m_statusPerMpduMap.clear (); + for (const auto & endOfMpduEvent : m_endOfMpduEvents) + { + NS_ASSERT (endOfMpduEvent.IsExpired ()); + } + m_endOfMpduEvents.clear (); + } MaybeCcaBusyDuration (); } @@ -3570,7 +3677,7 @@ WifiPhy::GetReceptionStatus (Ptr psdu, Ptr event, uint16_ WifiMode mode = event->GetTxVector ().GetMode (staId); NS_LOG_DEBUG ("rate=" << (mode.GetDataRate (event->GetTxVector (), staId)) << - ", snr(dB)=" << RatioToDb (snrPer.snr) << ", per=" << snrPer.per << ", size=" << psdu->GetSize () << + ", SNR(dB)=" << RatioToDb (snrPer.snr) << ", PER=" << snrPer.per << ", size=" << psdu->GetSize () << ", relativeStart = " << relativeMpduStart.As (Time::NS) << ", duration = " << mpduDuration.As (Time::NS)); // There are two error checks: PER and receive error model check. @@ -3635,6 +3742,8 @@ WifiPhy::ResetReceive (Ptr event) NS_ASSERT (event->GetEndTime () == Simulator::Now ()); } NS_ASSERT (!IsStateRx ()); + NS_ASSERT (m_endRxEvents.size () == 1 && m_endRxEvents.front ().IsExpired ()); + m_endRxEvents.clear (); m_interference.NotifyRxEnd (Simulator::Now ()); m_currentEvent = 0; m_currentPreambleEvents.clear (); @@ -4907,10 +5016,11 @@ WifiPhy::AbortCurrentReception (WifiPhyRxfailureReason reason) { m_endPhyRxEvent.Cancel (); } - if (m_endRxEvent.IsRunning ()) + for (auto & endRxEvent : m_endRxEvents) { - m_endRxEvent.Cancel (); + endRxEvent.Cancel (); } + m_endRxEvents.clear (); m_interference.NotifyRxEnd (Simulator::Now ()); if (!m_currentEvent) { @@ -4979,11 +5089,27 @@ Ptr WifiPhy::GetAddressedPsduInPpdu (Ptr ppdu) const { Ptr psdu; - if (!ppdu->IsDlMu ()) + if (!ppdu->IsMu ()) { psdu = ppdu->GetPsdu (); } - else + else if (ppdu->IsUlMu ()) + { + uint8_t bssColor = 0; + Ptr device = DynamicCast (GetDevice ()); + if (device) + { + Ptr heConfiguration = device->GetHeConfiguration (); + if (heConfiguration) + { + UintegerValue bssColorAttribute; + heConfiguration->GetAttribute ("BssColor", bssColorAttribute); + bssColor = bssColorAttribute.Get (); + } + } + psdu = ppdu->GetPsdu (bssColor); + } + else //DL MU { uint8_t bssColor = 0; Ptr device = DynamicCast (GetDevice ()); diff --git a/src/wifi/model/wifi-phy.h b/src/wifi/model/wifi-phy.h index 45c7569ed..ad36198eb 100644 --- a/src/wifi/model/wifi-phy.h +++ b/src/wifi/model/wifi-phy.h @@ -1864,11 +1864,12 @@ protected: uint32_t m_txMpduReferenceNumber; //!< A-MPDU reference number to identify all transmitted subframes belonging to the same received A-MPDU uint32_t m_rxMpduReferenceNumber; //!< A-MPDU reference number to identify all received subframes belonging to the same received A-MPDU - EventId m_endRxEvent; //!< the end of receive event EventId m_endPhyRxEvent; //!< the end of PHY receive event EventId m_endTxEvent; //!< the end of transmit event + std::vector m_endRxEvents; //!< the end of receive events (only one unless UL MU reception) std::vector m_endPreambleDetectionEvents; //!< the end of preamble detection events + Ptr m_currentEvent; //!< Hold the current event std::map , Ptr > m_currentPreambleEvents; //!< store event associated to a PPDU (that has a unique ID and preamble combination) whose preamble is being received uint64_t m_previouslyRxPpduUid; //!< UID of the previously received PPDU (reused by HE TB PPDUs), reset to UINT64_MAX upon transmission @@ -2236,17 +2237,25 @@ private: Ptr m_device; //!< Pointer to the device Ptr m_mobility; //!< Pointer to the mobility model - Ptr m_currentEvent; //!< Hold the current event Ptr m_frameCaptureModel; //!< Frame capture model Ptr m_preambleDetectionModel; //!< Preamble detection model Ptr m_wifiRadioEnergyModel; //!< Wifi radio energy model Ptr m_postReceptionErrorModel; //!< Error model for receive packet events Time m_timeLastPreambleDetected; //!< Record the time the last preamble was detected - std::vector m_statusPerMpdu; //!< current reception status per MPDU that is filled in as long as MPDUs are being processed by the PHY in case of an A-MPDU - SignalNoiseDbm m_signalNoise; //!< latest signal power and noise power in dBm (noise power includes the noise figure) + std::vector m_endOfMpduEvents; //!< the end of MPDU events (only used for A-MPDUs) - Callback m_capabilitiesChangedCallback; //!< Callback when PHY capabilities changed + /** + * A pair of a UID and STA_ID + */ + typedef std::pair UidStaIdPair; + + std::map > m_statusPerMpduMap; //!< Map of the current reception status per MPDU that is filled in as long as MPDUs are being processed by the PHY in case of an A-MPDU + std::map m_signalNoiseMap; //!< Map of the latest signal power and noise power in dBm (noise power includes the noise figure) + + bool m_ofdmaStarted; //!< Flag whether the reception of the OFDMA part has started (only used for UL-OFDMA) + + Callback m_capabilitiesChangedCallback; //!< Callback when PHY capabilities changed }; } //namespace ns3 diff --git a/src/wifi/model/wifi-ppdu.cc b/src/wifi/model/wifi-ppdu.cc index 5d5a0209a..35be7d833 100644 --- a/src/wifi/model/wifi-ppdu.cc +++ b/src/wifi/model/wifi-ppdu.cc @@ -382,11 +382,14 @@ WifiPpdu::GetPsdu (uint8_t bssColor, uint16_t staId) const else if (IsUlMu ()) { NS_ASSERT (m_psdus.size () == 1); - return m_psdus.begin ()->second; + if (bssColor == 0 || (bssColor == m_heSig.GetBssColor ())) + { + return m_psdus.begin ()->second; + } } else { - if (bssColor == m_heSig.GetBssColor ()) + if (bssColor == 0 || (bssColor == m_heSig.GetBssColor ())) { auto it = m_psdus.find (staId); if (it != m_psdus.end ()) diff --git a/src/wifi/model/wifi-ppdu.h b/src/wifi/model/wifi-ppdu.h index 6f237fb2a..8d2a25773 100644 --- a/src/wifi/model/wifi-ppdu.h +++ b/src/wifi/model/wifi-ppdu.h @@ -79,7 +79,7 @@ public: * \param staId the staId of the PHY calling this function. * \return the PSDU */ - Ptr GetPsdu (uint8_t bssColor = 64, uint16_t staId = SU_STA_ID) const; + Ptr GetPsdu (uint8_t bssColor = 0, uint16_t staId = SU_STA_ID) const; /** * Return true if the PPDU's transmission was aborted due to transmitter switch off