From 35d8fc7ee9bf1ea781735149c85ae7a10e93a3e6 Mon Sep 17 00:00:00 2001 From: Rediet Date: Mon, 14 Sep 2020 09:22:51 +0200 Subject: [PATCH] wifi: Move HE-STF and HE-LTF of HE TB PPDUs to OFDMA portion --- src/wifi/model/spectrum-wifi-phy.cc | 22 +++-- src/wifi/model/wifi-phy.cc | 125 ++++++++++++++++++------ src/wifi/model/wifi-phy.h | 36 ++++--- src/wifi/test/spectrum-wifi-phy-test.cc | 2 +- src/wifi/test/wifi-phy-ofdma-test.cc | 45 ++++++++- 5 files changed, 175 insertions(+), 55 deletions(-) diff --git a/src/wifi/model/spectrum-wifi-phy.cc b/src/wifi/model/spectrum-wifi-phy.cc index 2b65cdb72..364a522e1 100644 --- a/src/wifi/model/spectrum-wifi-phy.cc +++ b/src/wifi/model/spectrum-wifi-phy.cc @@ -357,19 +357,27 @@ SpectrumWifiPhy::StartRx (Ptr rxParams) NS_LOG_INFO ("Received Wi-Fi signal"); Ptr ppdu = Copy (wifiRxParams->ppdu); - if (ppdu->GetTxVector ().GetPreambleType () == WIFI_PREAMBLE_HE_TB + WifiTxVector txVector = ppdu->GetTxVector (); + if (txVector.GetPreambleType () == WIFI_PREAMBLE_HE_TB && 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); + //AP or STA has already received non-OFDMA part, switch to OFDMA part, and schedule reception of payload (will be canceled for STAs by StartPayloadStart) + bool ofdmaStarted = !m_beginOfdmaPayloadRxEvents.empty (); + NS_LOG_INFO ("Switch to OFDMA part (already started? " << (ofdmaStarted ? "Y" : "N") << ") " + << "and schedule OFDMA payload reception in " << GetPhyTrainingSymbolDuration (txVector).As (Time::NS)); + Ptr event = m_interference.Add (ppdu, txVector, rxDuration, rxPowerW, !ofdmaStarted); + uint16_t staId = GetStaId (ppdu); + NS_ASSERT (m_beginOfdmaPayloadRxEvents.find (staId) == m_beginOfdmaPayloadRxEvents.end ()); + m_beginOfdmaPayloadRxEvents[staId] = Simulator::Schedule (GetPhyTrainingSymbolDuration (txVector), + &WifiPhy::StartReceiveOfdmaPayload, this, event); } else { //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); + NS_LOG_INFO ("Consider OFDMA part of the HE TB PPDU as interference since device dropped the preamble"); + m_interference.Add (ppdu, txVector, rxDuration, rxPowerW); auto it = m_currentPreambleEvents.find (std::make_pair(ppdu->GetUid (), ppdu->GetPreamble ())); if (it != m_currentPreambleEvents.end ()) { @@ -516,7 +524,7 @@ SpectrumWifiPhy::StartTx (Ptr ppdu) if (txVector.GetPreambleType () == WIFI_PREAMBLE_HE_TB) { //non-OFDMA part - Time nonOfdmaDuration = CalculatePhyPreambleAndHeaderDuration (txVector); //consider that HE-STF and HE-LTFs are also part of the non-OFDMA part + Time nonOfdmaDuration = CalculateNonOfdmaDurationForHeTb (txVector); Ptr txPowerSpectrum = GetTxPowerSpectralDensity (txPowerWatts, ppdu, PSD_HE_TB_NON_OFDMA_PORTION); Ptr txParams = Create (); txParams->duration = nonOfdmaDuration; @@ -555,7 +563,7 @@ SpectrumWifiPhy::StartOfdmaTx (Ptr ppdu, double txPowerWatts) Ptr txPowerSpectrum = GetTxPowerSpectralDensity (txPowerWatts, ppdu, PSD_HE_TB_OFDMA_PORTION); Ptr txParams = Create (); WifiTxVector txVector = ppdu->GetTxVector (); - txParams->duration = ppdu->GetTxDuration () - CalculatePhyPreambleAndHeaderDuration (txVector); + txParams->duration = ppdu->GetTxDuration () - CalculateNonOfdmaDurationForHeTb (txVector); txParams->psd = txPowerSpectrum; txParams->txPhy = m_wifiSpectrumPhyInterface->GetObject (); txParams->txAntenna = m_antenna; diff --git a/src/wifi/model/wifi-phy.cc b/src/wifi/model/wifi-phy.cc index fc0d54baf..9268a6d19 100644 --- a/src/wifi/model/wifi-phy.cc +++ b/src/wifi/model/wifi-phy.cc @@ -534,8 +534,7 @@ WifiPhy::WifiPhy () m_channelNumber (0), m_initialChannelNumber (0), m_wifiRadioEnergyModel (0), - m_timeLastPreambleDetected (Seconds (0)), - m_ofdmaStarted (false) + m_timeLastPreambleDetected (Seconds (0)) { NS_LOG_FUNCTION (this); m_random = CreateObject (); @@ -563,6 +562,11 @@ WifiPhy::DoDispose (void) endPreambleDetectionEvent.Cancel (); } m_endPreambleDetectionEvents.clear (); + for (auto & beginOfdmaPayloadRxEvent : m_beginOfdmaPayloadRxEvents) + { + beginOfdmaPayloadRxEvent.second.Cancel (); + } + m_beginOfdmaPayloadRxEvents.clear (); m_device = 0; m_mobility = 0; m_state = 0; @@ -1713,6 +1717,11 @@ WifiPhy::DoChannelSwitch (uint8_t nch) endPreambleDetectionEvent.Cancel (); } m_endPreambleDetectionEvents.clear (); + for (auto & beginOfdmaPayloadRxEvent : m_beginOfdmaPayloadRxEvents) + { + beginOfdmaPayloadRxEvent.second.Cancel (); + } + m_beginOfdmaPayloadRxEvents.clear (); goto switchChannel; break; case WifiPhyState::TX: @@ -1732,6 +1741,11 @@ WifiPhy::DoChannelSwitch (uint8_t nch) endRxEvent.Cancel (); } m_endRxEvents.clear (); + for (auto & beginOfdmaPayloadRxEvent : m_beginOfdmaPayloadRxEvents) + { + beginOfdmaPayloadRxEvent.second.Cancel (); + } + m_beginOfdmaPayloadRxEvents.clear (); } goto switchChannel; break; @@ -1790,6 +1804,11 @@ WifiPhy::DoFrequencySwitch (uint16_t frequency) endPreambleDetectionEvent.Cancel (); } m_endPreambleDetectionEvents.clear (); + for (auto & beginOfdmaPayloadRxEvent : m_beginOfdmaPayloadRxEvents) + { + beginOfdmaPayloadRxEvent.second.Cancel (); + } + m_beginOfdmaPayloadRxEvents.clear (); goto switchFrequency; break; case WifiPhyState::TX: @@ -1809,6 +1828,11 @@ WifiPhy::DoFrequencySwitch (uint16_t frequency) } m_endRxEvents.clear (); goto switchFrequency; + for (auto & beginOfdmaPayloadRxEvent : m_beginOfdmaPayloadRxEvents) + { + beginOfdmaPayloadRxEvent.second.Cancel (); + } + m_beginOfdmaPayloadRxEvents.clear (); break; case WifiPhyState::SLEEP: NS_LOG_DEBUG ("frequency switching ignored in sleep mode"); @@ -1887,6 +1911,11 @@ WifiPhy::SetOffMode (void) endPreambleDetectionEvent.Cancel (); } m_endPreambleDetectionEvents.clear (); + for (auto & beginOfdmaPayloadRxEvent : m_beginOfdmaPayloadRxEvents) + { + beginOfdmaPayloadRxEvent.second.Cancel (); + } + m_beginOfdmaPayloadRxEvents.clear (); m_state->SwitchToOff (); } @@ -2671,6 +2700,17 @@ WifiPhy::CalculatePhyPreambleAndHeaderDuration (WifiTxVector txVector) return duration; } +Time +WifiPhy::CalculateNonOfdmaDurationForHeTb (WifiTxVector txVector) +{ + NS_ASSERT (txVector.GetPreambleType () == WIFI_PREAMBLE_HE_TB); + Time duration = GetPhyPreambleDuration (txVector) + + GetPhyHeaderDuration (txVector) + + GetPhySigA1Duration (WIFI_PREAMBLE_HE_TB) + + GetPhySigA2Duration (WIFI_PREAMBLE_HE_TB); + return duration; +} + Time WifiPhy::CalculateTxDuration (uint32_t size, WifiTxVector txVector, WifiPhyBand band, uint16_t staId) { @@ -2961,7 +3001,11 @@ WifiPhy::Reset (void) NS_LOG_FUNCTION (this); m_currentPreambleEvents.clear (); m_currentEvent = 0; - m_ofdmaStarted = false; + for (auto & beginOfdmaPayloadRxEvent : m_beginOfdmaPayloadRxEvents) + { + beginOfdmaPayloadRxEvent.second.Cancel (); + } + m_beginOfdmaPayloadRxEvents.clear (); } void @@ -3130,6 +3174,7 @@ WifiPhy::StartReceivePreamble (Ptr ppdu, RxPowerWattPerChannelBand rxP auto uidPreamblePair = std::make_pair (ppdu->GetUid (), ppdu->GetPreamble ()); if (ppdu->IsUlMu ()) { + rxDuration = CalculateNonOfdmaDurationForHeTb (txVector); //the OFDMA part of the transmission will be added later on auto it = m_currentPreambleEvents.find (uidPreamblePair); if (it != m_currentPreambleEvents.end ()) { @@ -3162,7 +3207,7 @@ WifiPhy::StartReceivePreamble (Ptr ppdu, RxPowerWattPerChannelBand rxP else { NS_LOG_DEBUG ("Received a new HE TB PPDU for UID " << ppdu->GetUid () << " from STA-ID " << ppdu->GetStaId () << " and BSS color " << +txVector.GetBssColor ()); - event = m_interference.Add (ppdu, txVector, CalculatePhyPreambleAndHeaderDuration (txVector), rxPowersW); //the OFDMA part of the transmission will be added later on + event = m_interference.Add (ppdu, txVector, rxDuration, rxPowersW); m_currentPreambleEvents.insert ({std::make_pair (ppdu->GetUid (), ppdu->GetPreamble ()), event}); } } @@ -3305,33 +3350,32 @@ WifiPhy::MaybeCcaBusyDuration (uint16_t channelWidth) } void -WifiPhy::StartReceiveOfdmaPayload (Ptr ppdu, RxPowerWattPerChannelBand rxPowersW) +WifiPhy::StartReceiveOfdmaPayload (Ptr event) { + Ptr ppdu = event->GetPpdu (); + RxPowerWattPerChannelBand rxPowersW = event->GetRxPowerWPerBand (); //The total RX power corresponds to the maximum over all the bands auto it = std::max_element (rxPowersW.begin (), rxPowersW.end (), [] (const std::pair& p1, const std::pair& p2) { 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, !m_ofdmaStarted); - m_ofdmaStarted = true; - Ptr device = DynamicCast (GetDevice ()); - bool isAp = (DynamicCast (device->GetMac ()) != 0); - if (isAp) - { - Ptr psdu = GetAddressedPsduInPpdu (ppdu); - 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 - { - NS_LOG_INFO ("Ignore reception of OFDMA payload since device is non-AP STA"); - NS_ASSERT (m_endRxEvents.size () == 1 && m_endRxEvents.front ().IsRunning ()); - } + NS_LOG_FUNCTION (this << event << *ppdu << it->second); + NS_ASSERT (m_currentEvent != 0); + auto itEvent = m_beginOfdmaPayloadRxEvents.find (GetStaId (ppdu)); + /** + * m_beginOfdmaPayloadRxEvents should still be running only for APs, since canceled in StartReceivePayload for STAs. + * This is because SpectrumWifiPhy does not have access to the device type and thus blindly schedules things, letting + * the parent WifiPhy class take into account device type. + */ + NS_ASSERT (itEvent != m_beginOfdmaPayloadRxEvents.end () && itEvent->second.IsExpired ()); + m_beginOfdmaPayloadRxEvents.erase (itEvent); + + Time payloadDuration = ppdu->GetTxDuration () - CalculatePhyPreambleAndHeaderDuration (ppdu->GetTxVector ()); + Ptr psdu = GetAddressedPsduInPpdu (ppdu); + 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 ()}); } void @@ -3517,12 +3561,9 @@ WifiPhy::ScheduleStartReceivePayload (Ptr event, Time timeToPayloadStart) else if (IsModeSupported (txMode) || IsMcsSupported (txMode)) { NS_LOG_INFO ("SIG correctly decoded and with supported settings. Schedule start of payload."); - m_endPhyRxEvent = Simulator::Schedule (timeToPayloadStart, - &WifiPhy::StartReceivePayload, this, event); - - Ptr device = DynamicCast (GetDevice ()); - bool isAp = device != 0 && (DynamicCast (device->GetMac ()) != 0); - if (txVector.GetPreambleType () == WIFI_PREAMBLE_HE_TB && isAp) + m_state->SwitchMaybeToCcaBusy (timeToPayloadStart); + m_endPhyRxEvent = Simulator::Schedule (timeToPayloadStart, &WifiPhy::StartReceivePayload, this, event); + if (txVector.GetPreambleType () == WIFI_PREAMBLE_HE_TB) { m_currentHeTbPpduUid = ppdu->GetUid (); //to be able to correctly schedule start of OFDMA payload } @@ -3554,6 +3595,13 @@ WifiPhy::StartReceivePayload (Ptr event) NS_LOG_DEBUG ("Ignore HE TB PPDU payload received by STA but keep state in Rx"); m_endRxEvents.push_back (Simulator::Schedule (payloadDuration, &WifiPhy::ResetReceive, this, event)); + //Cancel all scheduled events for OFDMA payload reception + NS_ASSERT (!m_beginOfdmaPayloadRxEvents.empty () && m_beginOfdmaPayloadRxEvents.begin ()->second.IsRunning ()); + for (auto & beginOfdmaPayloadRxEvent : m_beginOfdmaPayloadRxEvents) + { + beginOfdmaPayloadRxEvent.second.Cancel (); + } + m_beginOfdmaPayloadRxEvents.clear (); } else { @@ -3565,6 +3613,11 @@ WifiPhy::StartReceivePayload (Ptr event) { //for HE TB PPDUs, ScheduleEndOfMpdus and EndReceive are scheduled by StartReceiveOfdmaPayload NS_ASSERT (isAp); + NS_ASSERT (!m_beginOfdmaPayloadRxEvents.empty ()); + for (auto & beginOfdmaPayloadRxEvent : m_beginOfdmaPayloadRxEvents) + { + NS_ASSERT (beginOfdmaPayloadRxEvent.second.IsRunning ()); + } } else { @@ -3862,6 +3915,11 @@ WifiPhy::ResetReceive (Ptr event) m_interference.NotifyRxEnd (Simulator::Now ()); m_currentEvent = 0; m_currentPreambleEvents.clear (); + for (auto & beginOfdmaPayloadRxEvent : m_beginOfdmaPayloadRxEvents) + { + beginOfdmaPayloadRxEvent.second.Cancel (); + } + m_beginOfdmaPayloadRxEvents.clear (); MaybeCcaBusyDuration (GetMeasurementChannelWidth (ppdu)); } @@ -5141,6 +5199,11 @@ WifiPhy::AbortCurrentReception (WifiPhyRxfailureReason reason) endRxEvent.Cancel (); } m_endRxEvents.clear (); + for (auto & beginOfdmaPayloadRxEvent : m_beginOfdmaPayloadRxEvents) + { + beginOfdmaPayloadRxEvent.second.Cancel (); + } + m_beginOfdmaPayloadRxEvents.clear (); m_interference.NotifyRxEnd (Simulator::Now ()); if (!m_currentEvent) { diff --git a/src/wifi/model/wifi-phy.h b/src/wifi/model/wifi-phy.h index 3217ef77a..3c136dc89 100644 --- a/src/wifi/model/wifi-phy.h +++ b/src/wifi/model/wifi-phy.h @@ -259,10 +259,9 @@ public: * Start receiving the PSDU (i.e. the first symbol of the PSDU has arrived) of an UL-OFDMA transmission. * This function is called upon the RX event corresponding to the OFDMA part of the UL MU PPDU. * - * \param ppdu the arriving PPDU - * \param rxPowersW the receive power in W per band + * \param event the event holding incoming OFDMA part of the PPDU's information */ - void StartReceiveOfdmaPayload (Ptr ppdu, RxPowerWattPerChannelBand rxPowersW); + void StartReceiveOfdmaPayload (Ptr event); /** * The last symbol of the PPDU has arrived. @@ -413,6 +412,12 @@ public: * \return the total amount of time this PHY will stay busy for the transmission of the PHY preamble and PHY header. */ static Time CalculatePhyPreambleAndHeaderDuration (WifiTxVector txVector); + /** + * \param txVector the transmission parameters used for the HE TB PPDU + * + * \return the duration of the non-OFDMA portion of the HE TB PPDU. + */ + static Time CalculateNonOfdmaDurationForHeTb (WifiTxVector txVector); /** * * \return the preamble detection duration, which is the time correlation needs to detect the start of an incoming frame. @@ -1798,6 +1803,16 @@ public: */ void NotifyChannelAccessRequested (void); + /** + * Get the RU band used to transmit a PSDU to a given STA in a HE MU PPDU + * + * \param txVector the TXVECTOR used for the transmission + * \param staId the STA-ID of the recipient + * + * \return the RU band used to transmit a PSDU to a given STA in a HE MU PPDU + */ + WifiSpectrumBand GetRuBand (WifiTxVector txVector, uint16_t staId); + protected: // Inherited @@ -1878,16 +1893,6 @@ protected: */ virtual WifiSpectrumBand ConvertHeRuSubcarriers (uint16_t channelWidth, HeRu::SubcarrierRange range) const; - /** - * Get the RU band used to transmit a PSDU to a given STA in a HE MU PPDU - * - * \param txVector the TXVECTOR used for the transmission - * \param staId the STA-ID of the recipient - * - * \return the RU band used to transmit a PSDU to a given STA in a HE MU PPDU - */ - WifiSpectrumBand GetRuBand (WifiTxVector txVector, uint16_t staId); - /** * Get the band used to transmit the non-OFDMA part of an HE TB PPDU. * @@ -1910,6 +1915,9 @@ protected: 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 + + std::map m_beginOfdmaPayloadRxEvents; //!< the beginning of the OFDMA payload reception events (indexed by STA-ID) + 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 @@ -2308,8 +2316,6 @@ private: 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 }; diff --git a/src/wifi/test/spectrum-wifi-phy-test.cc b/src/wifi/test/spectrum-wifi-phy-test.cc index 20cd93c21..046936a23 100644 --- a/src/wifi/test/spectrum-wifi-phy-test.cc +++ b/src/wifi/test/spectrum-wifi-phy-test.cc @@ -310,7 +310,7 @@ SpectrumWifiPhyListenerTest::DoRun (void) Simulator::Run (); NS_TEST_ASSERT_MSG_EQ (m_count, 1, "Didn't receive right number of packets"); - NS_TEST_ASSERT_MSG_EQ (m_listener->m_notifyMaybeCcaBusyStart, 2, "Didn't receive NotifyMaybeCcaBusyStart (preamble deteted + L-SIG received)"); + NS_TEST_ASSERT_MSG_EQ (m_listener->m_notifyMaybeCcaBusyStart, 3, "Didn't receive NotifyMaybeCcaBusyStart (preamble deteted + L-SIG received + common PHY header(s) received)"); NS_TEST_ASSERT_MSG_EQ (m_listener->m_notifyRxStart, 1, "Didn't receive NotifyRxStart"); NS_TEST_ASSERT_MSG_EQ (m_listener->m_notifyRxEndOk, 1, "Didn't receive NotifyRxEnd"); diff --git a/src/wifi/test/wifi-phy-ofdma-test.cc b/src/wifi/test/wifi-phy-ofdma-test.cc index 224f29495..e0e75658b 100644 --- a/src/wifi/test/wifi-phy-ofdma-test.cc +++ b/src/wifi/test/wifi-phy-ofdma-test.cc @@ -48,6 +48,7 @@ NS_LOG_COMPONENT_DEFINE ("WifiPhyOfdmaTest"); static const uint8_t DEFAULT_CHANNEL_NUMBER = 36; static const uint32_t DEFAULT_FREQUENCY = 5180; // MHz static const uint16_t DEFAULT_CHANNEL_WIDTH = 20; // MHz +static const uint16_t DEFAULT_GUARD_WIDTH = DEFAULT_CHANNEL_WIDTH; // MHz (expanded to channel width to model spectrum mask) class OfdmaSpectrumWifiPhy : public SpectrumWifiPhy { @@ -1224,6 +1225,21 @@ private: */ void RxHeTbPpdu (uint64_t uid, uint16_t staId, double txPowerWatts, size_t payloadSize); + /** + * Receive OFDMA part of HE TB PPDU function. + * Immediately schedules DoRxHeTbPpduOfdmaPart. + * + * \param rxParamsOfdma the spectrum signal parameters to send for OFDMA part + */ + void RxHeTbPpduOfdmaPart (Ptr rxParamsOfdma); + /** + * Receive OFDMA part of HE TB PPDU function. + * Actual reception call. + * + * \param rxParamsOfdma the spectrum signal parameters to send for OFDMA part + */ + void DoRxHeTbPpduOfdmaPart (Ptr rxParamsOfdma); + /** * RX dropped function * \param p the packet @@ -1327,6 +1343,8 @@ TestMultipleHeTbPreambles::RxHeTbPpdu (uint64_t uid, uint16_t staId, double txPo Time ppduDuration = m_phy->CalculateTxDuration (psdu->GetSize (), txVector, m_phy->GetPhyBand (), staId); Ptr ppdu = Create (psdus, txVector, ppduDuration, WIFI_PHY_BAND_5GHZ, uid); + //Send non-OFDMA part + Time nonOfdmaDuration = WifiPhy::CalculateNonOfdmaDurationForHeTb (txVector); uint32_t centerFrequency = m_phy->GetCenterFrequencyForNonOfdmaPart (txVector, staId); uint16_t ruWidth = HeRu::GetBandwidth (txVector.GetRu (staId).ruType); uint16_t channelWidth = ruWidth < 20 ? 20 : ruWidth; @@ -1334,11 +1352,36 @@ TestMultipleHeTbPreambles::RxHeTbPpdu (uint64_t uid, uint16_t staId, double txPo Ptr rxParams = Create (); rxParams->psd = rxPsd; rxParams->txPhy = 0; - rxParams->duration = ppduDuration; + rxParams->duration = nonOfdmaDuration; rxParams->ppdu = ppdu; rxParams->txPsdFlag = PSD_HE_TB_NON_OFDMA_PORTION; m_phy->StartRx (rxParams); + + //Schedule OFDMA part + WifiSpectrumBand band = m_phy->GetRuBand (txVector, staId); + Ptr rxPsdOfdma = WifiSpectrumValueHelper::CreateHeMuOfdmTxPowerSpectralDensity (DEFAULT_FREQUENCY, DEFAULT_CHANNEL_WIDTH, txPowerWatts, DEFAULT_GUARD_WIDTH, band); + Ptr rxParamsOfdma = Create (); + rxParamsOfdma->psd = rxPsd; + rxParamsOfdma->txPhy = 0; + rxParamsOfdma->duration = ppduDuration - nonOfdmaDuration; + rxParamsOfdma->ppdu = ppdu; + rxParamsOfdma->txPsdFlag = PSD_HE_TB_OFDMA_PORTION; + Simulator::Schedule (nonOfdmaDuration, &TestMultipleHeTbPreambles::RxHeTbPpduOfdmaPart, this, rxParamsOfdma); +} + +void +TestMultipleHeTbPreambles::RxHeTbPpduOfdmaPart (Ptr rxParamsOfdma) +{ + Simulator::ScheduleNow (&TestMultipleHeTbPreambles::DoRxHeTbPpduOfdmaPart, this, rxParamsOfdma); +} + +void +TestMultipleHeTbPreambles::DoRxHeTbPpduOfdmaPart (Ptr rxParamsOfdma) +{ + //This is needed to make sure the OFDMA part is started as the last event since HE-SIG-A should end at the exact same time as the start + //For normal WifiNetDevices, this the reception of the OFDMA part is scheduled after end of HE-SIG-A decoding. + m_phy->StartRx (rxParamsOfdma); } void