wifi: Add preamble and payload handling in PhyEntity

Tx path will be refactored in subsequent commits.
Please note that there are 7 crashing wifi test suites. They're solved in the next commit.
This commit is contained in:
Rediet
2021-02-15 16:58:22 +01:00
parent c4f2be8346
commit 8225cb7e78
5 changed files with 1080 additions and 67 deletions

View File

@@ -26,11 +26,13 @@
#include "he-configuration.h"
#include "wifi-net-device.h"
#include "sta-wifi-mac.h"
#include "ap-wifi-mac.h"
#include "wifi-utils.h"
#include "ns3/uinteger.h"
#include "ns3/simulator.h"
#include "ns3/log.h"
#include "ns3/assert.h"
#include <algorithm>
namespace ns3 {
@@ -245,7 +247,7 @@ HePhy::GetSigBDuration (WifiTxVector txVector) const
}
uint16_t
HePhy::ConvertHeTbPpduDurationToLSigLength (Time ppduDuration, WifiPhyBand band) const
HePhy::ConvertHeTbPpduDurationToLSigLength (Time ppduDuration, WifiPhyBand band)
{
uint8_t sigExtension = 0;
if (band == WIFI_PHY_BAND_2_4GHZ)
@@ -258,11 +260,11 @@ HePhy::ConvertHeTbPpduDurationToLSigLength (Time ppduDuration, WifiPhyBand band)
}
Time
HePhy::ConvertLSigLengthToHeTbPpduDuration (uint16_t length, WifiTxVector txVector, WifiPhyBand band) const
HePhy::ConvertLSigLengthToHeTbPpduDuration (uint16_t length, WifiTxVector txVector, WifiPhyBand band)
{
NS_ABORT_IF (txVector.GetPreambleType () != WIFI_PREAMBLE_HE_TB);
Time tSymbol = NanoSeconds (12800 + txVector.GetGuardInterval ());
Time preambleDuration = CalculatePhyPreambleAndHeaderDuration (txVector);
Time preambleDuration = WifiPhy::GetStaticPhyEntity (WIFI_MOD_CLASS_HE)->CalculatePhyPreambleAndHeaderDuration (txVector); //this is quite convoluted but only way of keeping the method static
uint8_t sigExtension = 0;
if (band == WIFI_PHY_BAND_2_4GHZ)
{
@@ -307,6 +309,144 @@ HePhy::BuildPpdu (const WifiConstPsduMap & psdus, WifiTxVector txVector,
return Create<HePpdu> (psdus, txVector, ppduDuration, band, uid);
}
void
HePhy::StartReceivePreamble (Ptr<WifiPpdu> ppdu, RxPowerWattPerChannelBand rxPowersW,
Time rxDuration, TxPsdFlag psdFlag)
{
NS_LOG_FUNCTION (this << ppdu << rxDuration << psdFlag);
WifiTxVector txVector = ppdu->GetTxVector ();
if (txVector.GetPreambleType () == WIFI_PREAMBLE_HE_TB
&& psdFlag == PSD_HE_TB_OFDMA_PORTION)
{
if (m_currentHeTbPpduUid == ppdu->GetUid ()
&& GetCurrentEvent () != 0)
{
//AP or STA has already received non-OFDMA part, switch to OFDMA part, and schedule reception of payload (will be canceled for STAs by StartPayload)
bool ofdmaStarted = !m_beginOfdmaPayloadRxEvents.empty ();
NS_LOG_INFO ("Switch to OFDMA part (already started? " << (ofdmaStarted ? "Y" : "N") << ") " <<
"and schedule OFDMA payload reception in " << GetDuration (WIFI_PPDU_FIELD_TRAINING, txVector).As (Time::NS));
Ptr<Event> event = CreateInterferenceEvent (ppdu, txVector, rxDuration, rxPowersW, !ofdmaStarted);
uint16_t staId = GetStaId (ppdu);
NS_ASSERT (m_beginOfdmaPayloadRxEvents.find (staId) == m_beginOfdmaPayloadRxEvents.end ());
m_beginOfdmaPayloadRxEvents[staId] = Simulator::Schedule (GetDuration (WIFI_PPDU_FIELD_TRAINING, txVector),
&HePhy::StartReceiveOfdmaPayload, this, event);
}
else
{
//PHY receives the OFDMA payload while having dropped the preamble
NS_LOG_INFO ("Consider OFDMA part of the HE TB PPDU as interference since device dropped the preamble");
CreateInterferenceEvent (ppdu, txVector, rxDuration, rxPowersW);
//the OFDMA part of the HE TB PPDUs will be noise _after_ the completion of the current event
ErasePreambleEvent (ppdu, rxDuration);
}
}
else
{
PhyEntity::StartReceivePreamble (ppdu, rxPowersW, rxDuration, psdFlag);
}
}
void
HePhy::CancelAllEvents (void)
{
NS_LOG_FUNCTION (this);
for (auto & beginOfdmaPayloadRxEvent : m_beginOfdmaPayloadRxEvents)
{
beginOfdmaPayloadRxEvent.second.Cancel ();
}
m_beginOfdmaPayloadRxEvents.clear ();
PhyEntity::CancelAllEvents ();
}
void
HePhy::DoAbortCurrentReception (WifiPhyRxfailureReason reason)
{
NS_LOG_FUNCTION (this << reason);
if (reason != OBSS_PD_CCA_RESET)
{
for (auto & endMpduEvent : m_endOfMpduEvents)
{
endMpduEvent.Cancel ();
}
m_endOfMpduEvents.clear ();
}
else
{
PhyEntity::DoAbortCurrentReception (reason);
}
}
void
HePhy::DoResetReceive (Ptr<Event> event)
{
NS_LOG_FUNCTION (this << *event);
if (event->GetPpdu ()->GetType () != WIFI_PPDU_TYPE_UL_MU)
{
NS_ASSERT (event->GetEndTime () == Simulator::Now ());
}
for (auto & beginOfdmaPayloadRxEvent : m_beginOfdmaPayloadRxEvents)
{
beginOfdmaPayloadRxEvent.second.Cancel ();
}
m_beginOfdmaPayloadRxEvents.clear ();
}
Ptr<Event>
HePhy::DoGetEvent (Ptr<const WifiPpdu> ppdu, RxPowerWattPerChannelBand rxPowersW)
{
Ptr<Event> event;
//We store all incoming preamble events, and a decision is made at the end of the preamble detection window.
//If a preamble is received after the preamble detection window, it is stored anyway because this is needed for HE TB PPDUs in
//order to properly update the received power in InterferenceHelper. The map is cleaned anyway at the end of the current reception.
if (ppdu->GetType () == WIFI_PPDU_TYPE_UL_MU)
{
auto uidPreamblePair = std::make_pair (ppdu->GetUid (), ppdu->GetPreamble ());
WifiTxVector txVector = ppdu->GetTxVector ();
Time rxDuration = CalculateNonOfdmaDurationForHeTb (txVector); //the OFDMA part of the transmission will be added later on
const auto & currentPreambleEvents = GetCurrentPreambleEvents ();
auto it = currentPreambleEvents.find (uidPreamblePair);
if (it != currentPreambleEvents.end ())
{
NS_LOG_DEBUG ("Received another HE TB PPDU for UID " << ppdu->GetUid () << " from STA-ID " << ppdu->GetStaId () << " and BSS color " << +txVector.GetBssColor ());
event = it->second;
if (Simulator::Now () - event->GetStartTime () > NanoSeconds (400))
{
//Section 27.3.14.3 from 802.11ax Draft 4.0: Pre-correction accuracy requirements.
//A STA that transmits an HE TB PPDU, non-HT PPDU, or non-HT duplicate PPDU in response to a triggering PPDU
//shall ensure that the transmission start time of the HE TB PPDU, non-HT PPDU, or non-HT duplicate PPDU is
//within ±0.4 µs + 16 µs from the end, at the STAs antenna connector, of the last OFDM symbol of the triggering
//PPDU (if it contains no PE field) or of the PE field of the triggering PPDU (if the PE field is present).
//As a result, if an HE TB PPDU arrives later than 0.4 µs, it is added as an interference but PPDU is dropped.
event = CreateInterferenceEvent (ppdu, txVector, rxDuration, rxPowersW);
NS_LOG_DEBUG ("Drop packet because not received within the 400ns window");
m_wifiPhy->NotifyRxDrop (GetAddressedPsduInPpdu (ppdu), HE_TB_PPDU_TOO_LATE);
}
else
{
//Update received power of the event associated to that UL MU transmission
UpdateInterferenceEvent (event, rxPowersW);
}
if ((GetCurrentEvent () != 0) && (GetCurrentEvent ()->GetPpdu ()->GetUid () != ppdu->GetUid ()))
{
NS_LOG_DEBUG ("Drop packet because already receiving another HE TB PPDU");
m_wifiPhy->NotifyRxDrop (GetAddressedPsduInPpdu (ppdu), RXING);
}
return nullptr;
}
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 = CreateInterferenceEvent (ppdu, txVector, rxDuration, rxPowersW);
AddPreambleEvent (event);
}
}
else
{
event = PhyEntity::DoGetEvent (ppdu, rxPowersW);
}
return event;
}
Ptr<const WifiPsdu>
HePhy::GetAddressedPsduInPpdu (Ptr<const WifiPpdu> ppdu) const
{
@@ -340,8 +480,23 @@ HePhy::GetBssColor (void) const
uint16_t
HePhy::GetStaId (const Ptr<const WifiPpdu> ppdu) const
{
//TODO Move HE-specific logic here
return m_wifiPhy->GetStaId (ppdu);
if (ppdu->GetType () == WIFI_PPDU_TYPE_UL_MU)
{
return ppdu->GetStaId ();
}
else if (ppdu->GetType () == WIFI_PPDU_TYPE_DL_MU)
{
Ptr<WifiNetDevice> device = DynamicCast<WifiNetDevice> (m_wifiPhy->GetDevice ());
if (device)
{
Ptr<StaWifiMac> mac = DynamicCast<StaWifiMac> (device->GetMac ());
if (mac && mac->IsAssociated ())
{
return mac->GetAssociationId ();
}
}
}
return PhyEntity::GetStaId (ppdu);
}
PhyEntity::PhyFieldRxStatus
@@ -434,6 +589,159 @@ HePhy::IsConfigSupported (Ptr<const WifiPpdu> ppdu) const
return true;
}
void
HePhy::DoStartReceivePayload (Ptr<Event> event)
{
NS_LOG_FUNCTION (this << *event);
WifiTxVector txVector = event->GetTxVector ();
Ptr<const WifiPpdu> ppdu = event->GetPpdu ();
if (txVector.GetPreambleType () == WIFI_PREAMBLE_HE_TB)
{
Ptr<WifiNetDevice> device = DynamicCast<WifiNetDevice> (m_wifiPhy->GetDevice ());
bool isAp = device != 0 && (DynamicCast<ApWifiMac> (device->GetMac ()) != 0);
if (!isAp)
{
NS_LOG_DEBUG ("Ignore HE TB PPDU payload received by STA but keep state in Rx");
m_endRxPayloadEvents.push_back (Simulator::Schedule (ppdu->GetTxDuration () - CalculatePhyPreambleAndHeaderDuration (txVector),
&PhyEntity::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
{
NS_LOG_DEBUG ("Receiving PSDU in HE TB PPDU");
uint16_t staId = GetStaId (ppdu);
m_signalNoiseMap.insert ({std::make_pair (ppdu->GetUid (), staId), SignalNoiseDbm ()});
m_statusPerMpduMap.insert ({std::make_pair (ppdu->GetUid (), staId), std::vector<bool> ()});
if (txVector.GetPreambleType () == WIFI_PREAMBLE_HE_TB)
{
//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
{
PhyEntity::DoStartReceivePayload (event);
}
}
void
HePhy::DoEndReceivePayload (Ptr<const WifiPpdu> ppdu)
{
NS_LOG_FUNCTION (this << ppdu);
if (ppdu->GetType () == WIFI_PPDU_TYPE_UL_MU)
{
for (auto it = m_endRxPayloadEvents.begin (); it != m_endRxPayloadEvents.end (); )
{
if (it->IsExpired ())
{
it = m_endRxPayloadEvents.erase (it);
}
else
{
it++;
}
}
if (m_endRxPayloadEvents.empty ())
{
//We've got the last PPDU of the UL-OFDMA transmission
NotifyInterferenceRxEndAndClear (true); //reset WifiPhy
}
}
else
{
NS_ASSERT (m_wifiPhy->GetLastRxEndTime () == Simulator::Now ());
PhyEntity::DoEndReceivePayload (ppdu);
}
}
void
HePhy::StartReceiveOfdmaPayload (Ptr<Event> event)
{
Ptr<const WifiPpdu> 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<WifiSpectrumBand, double> &p1, const std::pair<WifiSpectrumBand, double> &p2) {
return p1.second < p2.second;
});
NS_LOG_FUNCTION (this << *event << it->second);
NS_ASSERT (GetCurrentEvent () != 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<const WifiPsdu> psdu = GetAddressedPsduInPpdu (ppdu);
ScheduleEndOfMpdus (event);
m_endRxPayloadEvents.push_back (Simulator::Schedule (payloadDuration, &PhyEntity::EndReceivePayload, 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<bool> ()});
}
std::pair<uint16_t, WifiSpectrumBand>
HePhy::GetChannelWidthAndBand (WifiTxVector txVector, uint16_t staId) const
{
if (txVector.IsMu ())
{
return std::make_pair (HeRu::GetBandwidth (txVector.GetRu (staId).ruType),
GetRuBand (txVector, staId));
}
else
{
return PhyEntity::GetChannelWidthAndBand (txVector, staId);
}
}
WifiSpectrumBand
HePhy::GetRuBand (WifiTxVector txVector, uint16_t staId) const
{
NS_ASSERT (txVector.IsMu ());
WifiSpectrumBand band;
HeRu::RuSpec ru = txVector.GetRu (staId);
uint16_t channelWidth = txVector.GetChannelWidth ();
NS_ASSERT (channelWidth <= m_wifiPhy->GetChannelWidth ());
HeRu::SubcarrierGroup group = HeRu::GetSubcarrierGroup (channelWidth, ru.ruType, ru.index);
HeRu::SubcarrierRange range = std::make_pair (group.front ().first, group.back ().second);
band = m_wifiPhy->ConvertHeRuSubcarriers (channelWidth, range);
return band;
}
WifiSpectrumBand
HePhy::GetNonOfdmaBand (WifiTxVector txVector, uint16_t staId) const
{
NS_ASSERT (txVector.GetPreambleType () == WIFI_PREAMBLE_HE_TB);
uint16_t channelWidth = txVector.GetChannelWidth ();
NS_ASSERT (channelWidth <= m_wifiPhy->GetChannelWidth ());
HeRu::RuSpec ru = txVector.GetRu (staId);
uint16_t ruWidth = HeRu::GetBandwidth (ru.ruType);
uint16_t nonOfdmaWidth = ruWidth < 20 ? 20 : ruWidth;
// Find the RU that encompasses the non-OFDMA part of the HE TB PPDU for the STA-ID
HeRu::RuSpec nonOfdmaRu = HeRu::FindOverlappingRu (channelWidth, ru, HeRu::GetRuType (nonOfdmaWidth));
HeRu::SubcarrierGroup groupPreamble = HeRu::GetSubcarrierGroup (channelWidth, nonOfdmaRu.ruType, nonOfdmaRu.index);
HeRu::SubcarrierRange range = std::make_pair (groupPreamble.front ().first, groupPreamble.back ().second);
return m_wifiPhy->ConvertHeRuSubcarriers (channelWidth, range);
}
uint64_t
HePhy::GetCurrentHeTbPpduUid (void) const
{

View File

@@ -74,28 +74,23 @@ public:
virtual Ptr<WifiPpdu> BuildPpdu (const WifiConstPsduMap & psdus, WifiTxVector txVector,
Time ppduDuration, WifiPhyBand band, uint64_t uid) const override;
Ptr<const WifiPsdu> GetAddressedPsduInPpdu (Ptr<const WifiPpdu> ppdu) const override;
void StartReceivePreamble (Ptr<WifiPpdu> ppdu, RxPowerWattPerChannelBand rxPowersW,
Time rxDuration, TxPsdFlag psdFlag) override;
void CancelAllEvents (void) override;
virtual uint16_t GetStaId (const Ptr<const WifiPpdu> 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<const WifiPpdu> ppdu) const;
/**
* \param ppduDuration the duration of the HE TB PPDU
* \param band the frequency band being used
*
* \return the L-SIG length value corresponding to that HE TB PPDU duration.
*/
uint16_t ConvertHeTbPpduDurationToLSigLength (Time ppduDuration, WifiPhyBand band) const;
static uint16_t ConvertHeTbPpduDurationToLSigLength (Time ppduDuration, WifiPhyBand band);
/**
* \param length the L-SIG length value
* \param txVector the TXVECTOR used for the transmission of this HE TB PPDU
@@ -103,7 +98,7 @@ public:
*
* \return the duration of the HE TB PPDU corresponding to that L-SIG length value.
*/
Time ConvertLSigLengthToHeTbPpduDuration (uint16_t length, WifiTxVector txVector, WifiPhyBand band) const;
static Time ConvertLSigLengthToHeTbPpduDuration (uint16_t length, WifiTxVector txVector, WifiPhyBand band);
/**
* \param txVector the transmission parameters used for the HE TB PPDU
*
@@ -111,6 +106,25 @@ public:
*/
Time CalculateNonOfdmaDurationForHeTb (WifiTxVector txVector) 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) const;
/**
* Get the band used to transmit the non-OFDMA part of an HE TB PPDU.
*
* \param txVector the TXVECTOR used for the transmission
* \param staId the STA-ID of the station taking part of the UL MU
*
* \return the spectrum band used to transmit the non-OFDMA part of an HE TB PPDU
*/
WifiSpectrumBand GetNonOfdmaBand (WifiTxVector txVector, uint16_t staId) const;
/**
* \return the UID of the HE TB PPDU being received
*/
@@ -206,10 +220,26 @@ protected:
// Inherited
PhyFieldRxStatus ProcessSigA (Ptr<Event> event, PhyFieldRxStatus status) override;
PhyFieldRxStatus ProcessSigB (Ptr<Event> event, PhyFieldRxStatus status) override;
Ptr<Event> DoGetEvent (Ptr<const WifiPpdu> ppdu, RxPowerWattPerChannelBand rxPowersW) override;
virtual bool IsConfigSupported (Ptr<const WifiPpdu> ppdu) const override;
virtual void DoStartReceivePayload (Ptr<Event> event) override;
std::pair<uint16_t, WifiSpectrumBand> GetChannelWidthAndBand (WifiTxVector txVector, uint16_t staId) const override;
void DoEndReceivePayload (Ptr<const WifiPpdu> ppdu) override;
void DoResetReceive (Ptr<Event> event) override;
void DoAbortCurrentReception (WifiPhyRxfailureReason reason) override;
/**
* 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 event the event holding incoming OFDMA part of the PPDU's information
*/
void StartReceiveOfdmaPayload (Ptr<Event> event);
uint64_t m_currentHeTbPpduUid; //!< UID of the HE TB PPDU being received
std::map <uint16_t /* STA-ID */, EventId> m_beginOfdmaPayloadRxEvents; //!< the beginning of the OFDMA payload reception events (indexed by STA-ID)
private:
// Inherited
virtual void BuildModeList (void) override;

View File

@@ -24,7 +24,9 @@
#include "wifi-phy.h"
#include "wifi-psdu.h"
#include "preamble-detection-model.h"
#include "frame-capture-model.h"
#include "wifi-utils.h"
#include "ns3/packet.h"
#include "ns3/simulator.h"
#include "ns3/log.h"
#include "ns3/assert.h"
@@ -68,7 +70,9 @@ std::ostream & operator << (std::ostream &os, const PhyEntity::PhyFieldRxStatus
PhyEntity::~PhyEntity ()
{
NS_LOG_FUNCTION (this);
m_modeList.clear ();
CancelAllEvents ();
}
void
@@ -246,20 +250,12 @@ PhyEntity::StartReceiveField (WifiPpduField field, Ptr<Event> 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;
}
NS_ASSERT (m_wifiPhy->m_endPhyRxEvent.IsExpired ());
NS_ABORT_MSG_IF (field == WIFI_PPDU_FIELD_PREAMBLE, "Use the StartReceivePreamble method for preamble reception");
//Handle special cases of data reception
if (field == WIFI_PPDU_FIELD_DATA)
{
//TODO improve this logic later on
//Hand over to WifiPhy for data processing
m_wifiPhy->StartReceivePayload (event);
StartReceivePayload (event);
return;
}
@@ -304,10 +300,11 @@ PhyEntity::EndReceiveField (WifiPpduField field, Ptr<Event> event)
//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
//no break
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));
m_endRxPayloadEvents.push_back (Simulator::Schedule (GetRemainingDurationAfterField (ppdu, field),
&PhyEntity::ResetReceive, this, event));
break;
default:
NS_FATAL_ERROR ("Unknown action in case of failure");
@@ -352,13 +349,423 @@ PhyEntity::DoEndReceiveField (WifiPpduField field, Ptr<Event> event)
return PhyFieldRxStatus (false); //failed reception by default
}
bool
PhyEntity::DoStartReceivePreamble (Ptr<Event> event)
void
PhyEntity::StartReceivePreamble (Ptr<WifiPpdu> ppdu, RxPowerWattPerChannelBand rxPowersW,
Time /* rxDuration */, TxPsdFlag /* psdFlag */)
{
//The total RX power corresponds to the maximum over all the bands
auto it = std::max_element (rxPowersW.begin (), rxPowersW.end (),
[] (const std::pair<WifiSpectrumBand, double> &p1, const std::pair<WifiSpectrumBand, double> &p2) {
return p1.second < p2.second;
});
NS_LOG_FUNCTION (this << ppdu << it->second);
WifiTxVector txVector = ppdu->GetTxVector ();
Time rxDuration = ppdu->GetTxDuration (); //the actual duration of the PPDU should be considered
Ptr<Event> event = DoGetEvent (ppdu, rxPowersW);
if (event == nullptr)
{
//PPDU should be simply considered as interference (once it has been accounted for in InterferenceHelper)
return;
}
Time endRx = Simulator::Now () + rxDuration;
if (m_state->GetState () == WifiPhyState::OFF)
{
NS_LOG_DEBUG ("Cannot start RX because device is OFF");
if (endRx > (Simulator::Now () + m_state->GetDelayUntilIdle ()))
{
m_wifiPhy->MaybeCcaBusyDuration (m_wifiPhy->GetMeasurementChannelWidth (nullptr));
}
return;
}
if (ppdu->IsTruncatedTx ())
{
NS_LOG_DEBUG ("Packet reception stopped because transmitter has been switched off");
if (endRx > (Simulator::Now () + m_state->GetDelayUntilIdle ()))
{
m_wifiPhy->MaybeCcaBusyDuration (m_wifiPhy->GetMeasurementChannelWidth (ppdu));
}
return;
}
switch (m_state->GetState ())
{
case WifiPhyState::SWITCHING:
NS_LOG_DEBUG ("Drop packet because of channel switching");
/*
* Packets received on the upcoming channel are added to the event list
* during the switching state. This way the medium can be correctly sensed
* when the device listens to the channel for the first time after the
* switching e.g. after channel switching, the channel may be sensed as
* busy due to other devices' transmissions started before the end of
* the switching.
*/
DropPreambleEvent (ppdu, CHANNEL_SWITCHING, endRx, m_wifiPhy->GetMeasurementChannelWidth (ppdu));
break;
case WifiPhyState::RX:
if (m_wifiPhy->m_frameCaptureModel != 0
&& m_wifiPhy->m_frameCaptureModel->IsInCaptureWindow (m_wifiPhy->m_timeLastPreambleDetected)
&& m_wifiPhy->m_frameCaptureModel->CaptureNewFrame (m_wifiPhy->m_currentEvent, event))
{
AbortCurrentReception (FRAME_CAPTURE_PACKET_SWITCH);
NS_LOG_DEBUG ("Switch to new packet");
StartPreambleDetectionPeriod (event);
}
else
{
NS_LOG_DEBUG ("Drop packet because already in Rx");
DropPreambleEvent (ppdu, RXING, endRx, m_wifiPhy->GetMeasurementChannelWidth (ppdu));
if (m_wifiPhy->m_currentEvent == 0)
{
/*
* We are here because the non-legacy PHY header has not been successfully received.
* The PHY is kept in RX state for the duration of the PPDU, but EndReceive function is
* not called when the reception of the PPDU is finished, which is responsible to clear
* m_currentPreambleEvents. As a result, m_currentPreambleEvents should be cleared here.
*/
m_wifiPhy->m_currentPreambleEvents.clear ();
}
}
break;
case WifiPhyState::TX:
NS_LOG_DEBUG ("Drop packet because already in Tx");
DropPreambleEvent (ppdu, TXING, endRx, m_wifiPhy->GetMeasurementChannelWidth (ppdu));
break;
case WifiPhyState::CCA_BUSY:
if (m_wifiPhy->m_currentEvent != 0)
{
if (m_wifiPhy->m_frameCaptureModel != 0
&& m_wifiPhy->m_frameCaptureModel->IsInCaptureWindow (m_wifiPhy->m_timeLastPreambleDetected)
&& m_wifiPhy->m_frameCaptureModel->CaptureNewFrame (m_wifiPhy->m_currentEvent, event))
{
AbortCurrentReception (FRAME_CAPTURE_PACKET_SWITCH);
NS_LOG_DEBUG ("Switch to new packet");
StartPreambleDetectionPeriod (event);
}
else
{
NS_LOG_DEBUG ("Drop packet because already decoding preamble");
DropPreambleEvent (ppdu, BUSY_DECODING_PREAMBLE, endRx, m_wifiPhy->GetMeasurementChannelWidth (ppdu));
}
}
else
{
StartPreambleDetectionPeriod (event);
}
break;
case WifiPhyState::IDLE:
NS_ASSERT (m_wifiPhy->m_currentEvent == 0);
StartPreambleDetectionPeriod (event);
break;
case WifiPhyState::SLEEP:
NS_LOG_DEBUG ("Drop packet because in sleep mode");
DropPreambleEvent (ppdu, SLEEPING, endRx, m_wifiPhy->GetMeasurementChannelWidth (nullptr));
break;
default:
NS_FATAL_ERROR ("Invalid WifiPhy state.");
break;
}
}
void
PhyEntity::DropPreambleEvent (Ptr<const WifiPpdu> ppdu, WifiPhyRxfailureReason reason, Time endRx, uint16_t measurementChannelWidth)
{
NS_LOG_FUNCTION (this << ppdu << reason << endRx << measurementChannelWidth);
m_wifiPhy->NotifyRxDrop (GetAddressedPsduInPpdu (ppdu), reason);
auto it = m_wifiPhy->m_currentPreambleEvents.find (std::make_pair (ppdu->GetUid (), ppdu->GetPreamble ()));
if (it != m_wifiPhy->m_currentPreambleEvents.end ())
{
m_wifiPhy->m_currentPreambleEvents.erase (it);
}
if (endRx > (Simulator::Now () + m_state->GetDelayUntilIdle ()))
{
//that PPDU will be noise _after_ the end of the current event.
m_wifiPhy->MaybeCcaBusyDuration (measurementChannelWidth);
}
}
void
PhyEntity::ErasePreambleEvent (Ptr<const WifiPpdu> ppdu, Time rxDuration)
{
NS_LOG_FUNCTION (this << ppdu << rxDuration);
auto it = m_wifiPhy->m_currentPreambleEvents.find (std::make_pair (ppdu->GetUid (), ppdu->GetPreamble ()));
if (it != m_wifiPhy->m_currentPreambleEvents.end ())
{
m_wifiPhy->m_currentPreambleEvents.erase (it);
}
if (m_wifiPhy->m_currentPreambleEvents.empty ())
{
m_wifiPhy->Reset ();
}
if (rxDuration > m_state->GetDelayUntilIdle ())
{
//this PPDU will be noise _after_ the completion of the current event
m_wifiPhy->SwitchMaybeToCcaBusy (m_wifiPhy->GetMeasurementChannelWidth (ppdu));
}
}
uint16_t
PhyEntity::GetStaId (const Ptr<const WifiPpdu> /* ppdu */) const
{
return SU_STA_ID;
}
void
PhyEntity::StartReceivePayload (Ptr<Event> event)
{
NS_LOG_FUNCTION (this << *event);
//TODO handle special cases in WifiPhy::StartReceivePreamble
StartPreambleDetectionPeriod (event);
return true;
NS_ASSERT (m_wifiPhy->m_endPhyRxEvent.IsExpired ());
WifiTxVector txVector = event->GetTxVector ();
Time payloadDuration = event->GetPpdu ()->GetTxDuration () - CalculatePhyPreambleAndHeaderDuration (txVector);
//TODO: Add method in WifiPhy to clear all other PHYs (since this one is starting Rx)
m_state->SwitchToRx (payloadDuration);
m_wifiPhy->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
DoStartReceivePayload (event);
}
void
PhyEntity::DoStartReceivePayload (Ptr<Event> event)
{
NS_LOG_FUNCTION (this << *event);
Ptr<const WifiPpdu> ppdu = event->GetPpdu ();
NS_LOG_DEBUG ("Receiving PSDU");
uint16_t staId = GetStaId (ppdu);
m_signalNoiseMap.insert ({std::make_pair (ppdu->GetUid (), staId), SignalNoiseDbm ()});
m_statusPerMpduMap.insert ({std::make_pair (ppdu->GetUid (), staId), std::vector<bool> ()});
ScheduleEndOfMpdus (event);
m_endRxPayloadEvents.push_back (Simulator::Schedule (ppdu->GetTxDuration () - CalculatePhyPreambleAndHeaderDuration (event->GetTxVector ()),
&PhyEntity::EndReceivePayload, this, event));
}
void
PhyEntity::ScheduleEndOfMpdus (Ptr<Event> event)
{
NS_LOG_FUNCTION (this << *event);
Ptr<const WifiPpdu> ppdu = event->GetPpdu ();
Ptr<const WifiPsdu> 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);
Time remainingAmpduDuration = psduDuration;
size_t nMpdus = psdu->GetNMpdus ();
MpduType mpduType = (nMpdus > 1) ? FIRST_MPDU_IN_AGGREGATE : (psdu->IsSingle () ? SINGLE_MPDU : NORMAL_MPDU);
uint32_t totalAmpduSize = 0;
double totalAmpduNumSymbols = 0.0;
auto mpdu = psdu->begin ();
for (size_t i = 0; i < nMpdus && mpdu != psdu->end (); ++mpdu)
{
uint32_t size = (mpduType == NORMAL_MPDU) ? psdu->GetSize () : psdu->GetAmpduSubframeSize (i);
Time mpduDuration = m_wifiPhy->GetPayloadDuration (size, txVector,
m_wifiPhy->GetPhyBand (), mpduType, true, totalAmpduSize,
totalAmpduNumSymbols, staId);
remainingAmpduDuration -= mpduDuration;
if (i == (nMpdus - 1) && !remainingAmpduDuration.IsZero ()) //no more MPDUs coming
{
if (remainingAmpduDuration < NanoSeconds (txVector.GetGuardInterval ())) //enables to ignore padding
{
mpduDuration += remainingAmpduDuration; //apply a correction just in case rounding had induced slight shift
}
}
endOfMpduDuration += mpduDuration;
NS_LOG_INFO ("Schedule end of MPDU #" << i << " in " << endOfMpduDuration.As (Time::NS) <<
" (relativeStart=" << relativeStart.As (Time::NS) << ", mpduDuration=" << mpduDuration.As (Time::NS) <<
", remainingAmdpuDuration=" << remainingAmpduDuration.As (Time::NS) << ")");
m_endOfMpduEvents.push_back (Simulator::Schedule (endOfMpduDuration, &PhyEntity::EndOfMpdu, this, event, Create<WifiPsdu> (*mpdu, false), i, relativeStart, mpduDuration));
//Prepare next iteration
++i;
relativeStart += mpduDuration;
mpduType = (i == (nMpdus - 1)) ? LAST_MPDU_IN_AGGREGATE : MIDDLE_MPDU_IN_AGGREGATE;
}
}
void
PhyEntity::EndOfMpdu (Ptr<Event> event, Ptr<const WifiPsdu> psdu, size_t mpduIndex, Time relativeStart, Time mpduDuration)
{
NS_LOG_FUNCTION (this << *event << mpduIndex << relativeStart << mpduDuration);
Ptr<const WifiPpdu> ppdu = event->GetPpdu ();
WifiTxVector txVector = event->GetTxVector ();
uint16_t staId = GetStaId (ppdu);
const auto & channelWidthAndBand = GetChannelWidthAndBand (event->GetTxVector (), staId);
double snr = m_wifiPhy->m_interference.CalculateSnr (event, channelWidthAndBand.first, txVector.GetNss (staId), channelWidthAndBand.second);
std::pair<bool, SignalNoiseDbm> rxInfo = GetReceptionStatus (psdu, event, staId, relativeStart, mpduDuration);
NS_LOG_DEBUG ("Extracted MPDU #" << mpduIndex << ": duration: " << mpduDuration.As (Time::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;
RxSignalInfo rxSignalInfo;
rxSignalInfo.snr = snr;
rxSignalInfo.rssi = rxInfo.second.signal;
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 && GetAddressedPsduInPpdu (ppdu)->GetNMpdus () > 1)
{
//only done for correct MPDU that is part of an A-MPDU
m_state->ContinueRxNextMpdu (Copy (psdu), rxSignalInfo, txVector);
}
}
void
PhyEntity::EndReceivePayload (Ptr<Event> event)
{
Ptr<const WifiPpdu> ppdu = event->GetPpdu ();
WifiTxVector txVector = event->GetTxVector ();
Time psduDuration = ppdu->GetTxDuration () - CalculatePhyPreambleAndHeaderDuration (txVector);
NS_LOG_FUNCTION (this << *event << psduDuration);
NS_ASSERT (event->GetEndTime () == Simulator::Now ());
uint16_t staId = GetStaId (ppdu);
const auto & channelWidthAndBand = GetChannelWidthAndBand (event->GetTxVector (), staId);
double snr = m_wifiPhy->m_interference.CalculateSnr (event, channelWidthAndBand.first, txVector.GetNss (staId), channelWidthAndBand.second);
Ptr<const WifiPsdu> psdu = GetAddressedPsduInPpdu (ppdu);
m_wifiPhy->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 (std::count (statusPerMpduIt->second.begin (), statusPerMpduIt->second.end (), true))
{
//At least one MPDU has been successfully received
m_wifiPhy->NotifyMonitorSniffRx (psdu, m_wifiPhy->GetFrequency (), txVector, signalNoiseIt->second, statusPerMpduIt->second, staId);
RxSignalInfo rxSignalInfo;
rxSignalInfo.snr = snr;
rxSignalInfo.rssi = signalNoiseIt->second.signal; //same information for all MPDUs
m_state->SwitchFromRxEndOk (Copy (psdu), rxSignalInfo, txVector, staId, statusPerMpduIt->second);
m_wifiPhy->m_previouslyRxPpduUid = event->GetPpdu ()->GetUid (); //store UID only if reception is successful (because otherwise trigger won't be read by MAC layer)
}
else
{
m_state->SwitchFromRxEndError (Copy (psdu), snr);
}
DoEndReceivePayload (ppdu);
m_wifiPhy->MaybeCcaBusyDuration (m_wifiPhy->GetMeasurementChannelWidth (ppdu));
}
void
PhyEntity::DoEndReceivePayload (Ptr<const WifiPpdu> ppdu)
{
NS_LOG_FUNCTION (this << ppdu);
NS_ASSERT (m_wifiPhy->GetLastRxEndTime () == Simulator::Now ());
NotifyInterferenceRxEndAndClear (false); //don't reset WifiPhy
m_wifiPhy->m_currentEvent = 0;
m_wifiPhy->m_currentPreambleEvents.clear ();
m_endRxPayloadEvents.clear ();
}
std::pair<bool, SignalNoiseDbm>
PhyEntity::GetReceptionStatus (Ptr<const WifiPsdu> psdu, Ptr<Event> event, uint16_t staId,
Time relativeMpduStart, Time mpduDuration)
{
NS_LOG_FUNCTION (this << *psdu << *event << staId << relativeMpduStart << mpduDuration);
const auto & channelWidthAndBand = GetChannelWidthAndBand (event->GetTxVector (), staId);
SnrPer snrPer = m_wifiPhy->m_interference.CalculatePayloadSnrPer (event, channelWidthAndBand.first, channelWidthAndBand.second, staId,
std::make_pair (relativeMpduStart, relativeMpduStart + mpduDuration));
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 () <<
", relativeStart = " << relativeMpduStart.As (Time::NS) << ", duration = " << mpduDuration.As (Time::NS));
// There are two error checks: PER and receive error model check.
// PER check models is typical for Wi-Fi and is based on signal modulation;
// Receive error model is optional, if we have an error model and
// it indicates that the packet is corrupt, drop the packet.
SignalNoiseDbm signalNoise;
signalNoise.signal = WToDbm (event->GetRxPowerW (channelWidthAndBand.second));
signalNoise.noise = WToDbm (event->GetRxPowerW (channelWidthAndBand.second) / snrPer.snr);
if (GetRandomValue () > snrPer.per
&& !(m_wifiPhy->m_postReceptionErrorModel && m_wifiPhy->m_postReceptionErrorModel->IsCorrupt (psdu->GetPacket ()->Copy ())))
{
NS_LOG_DEBUG ("Reception succeeded: " << psdu);
return std::make_pair (true, signalNoise);
}
else
{
NS_LOG_DEBUG ("Reception failed: " << psdu);
return std::make_pair (false, signalNoise);
}
}
std::pair<uint16_t, WifiSpectrumBand>
PhyEntity::GetChannelWidthAndBand (WifiTxVector txVector, uint16_t /* staId */) const
{
uint16_t channelWidth = std::min (m_wifiPhy->GetChannelWidth (), txVector.GetChannelWidth ());
return std::make_pair (channelWidth, m_wifiPhy->GetBand (channelWidth));
}
const std::map <std::pair<uint64_t, WifiPreamble>, Ptr<Event> > &
PhyEntity::GetCurrentPreambleEvents (void) const
{
return m_wifiPhy->m_currentPreambleEvents;
}
void
PhyEntity::AddPreambleEvent (Ptr<Event> event)
{
NS_LOG_FUNCTION (this << *event);
Ptr<const WifiPpdu> ppdu = event->GetPpdu ();
m_wifiPhy->m_currentPreambleEvents.insert ({std::make_pair (ppdu->GetUid (), ppdu->GetPreamble ()), event});
}
Ptr<Event>
PhyEntity::DoGetEvent (Ptr<const WifiPpdu> ppdu, RxPowerWattPerChannelBand rxPowersW)
{
Ptr<Event> event = CreateInterferenceEvent (ppdu, ppdu->GetTxVector (), ppdu->GetTxDuration (), rxPowersW);
//We store all incoming preamble events, and a decision is made at the end of the preamble detection window.
auto uidPreamblePair = std::make_pair (ppdu->GetUid (), ppdu->GetPreamble ());
NS_ASSERT (m_wifiPhy->m_currentPreambleEvents.find (uidPreamblePair) == m_wifiPhy->m_currentPreambleEvents.end ());
m_wifiPhy->m_currentPreambleEvents.insert ({uidPreamblePair, event});
return event;
}
Ptr<Event>
PhyEntity::CreateInterferenceEvent (Ptr<const WifiPpdu> ppdu, WifiTxVector txVector, Time duration, RxPowerWattPerChannelBand rxPower, bool isStartOfdmaRxing /* = false */)
{
return m_wifiPhy->m_interference.Add (ppdu, txVector, duration, rxPower, isStartOfdmaRxing);
}
void
PhyEntity::UpdateInterferenceEvent (Ptr<Event> event, RxPowerWattPerChannelBand rxPower)
{
m_wifiPhy->m_interference.UpdateEvent (event, rxPower);
}
void
PhyEntity::NotifyInterferenceRxEndAndClear (bool reset)
{
m_wifiPhy->m_interference.NotifyRxEnd (Simulator::Now ());
m_signalNoiseMap.clear ();
m_statusPerMpduMap.clear ();
for (const auto & endOfMpduEvent : m_endOfMpduEvents)
{
NS_ASSERT (endOfMpduEvent.IsExpired ());
}
m_endOfMpduEvents.clear ();
if (reset)
{
m_wifiPhy->Reset ();
}
}
PhyEntity::PhyFieldRxStatus
@@ -375,8 +782,7 @@ PhyEntity::StartPreambleDetectionPeriod (Ptr<Event> 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));
m_endPreambleDetectionEvents.push_back (Simulator::Schedule (m_wifiPhy->GetPreambleDetectionDuration (), &PhyEntity::EndPreambleDetectionPeriod, this, event));
}
void
@@ -424,11 +830,11 @@ PhyEntity::EndPreambleDetectionPeriod (Ptr<Event> event)
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)
//A bit convoluted but it enables to sync all PHYs
for (auto & it : m_wifiPhy->m_phyEntities)
{
endPreambleDetectionEvent.Cancel ();
it.second->CancelRunningEndPreambleDetectionEvents (true);
}
m_wifiPhy->m_endPreambleDetectionEvents.clear ();
for (auto it = m_wifiPhy->m_currentPreambleEvents.begin (); it != m_wifiPhy->m_currentPreambleEvents.end (); )
{
@@ -471,7 +877,7 @@ PhyEntity::EndPreambleDetectionPeriod (Ptr<Event> event)
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 ()));
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
@@ -495,22 +901,84 @@ PhyEntity::IsConfigSupported (Ptr<const WifiPpdu> ppdu) const
return true;
}
void
PhyEntity::CancelAllEvents (void)
{
NS_LOG_FUNCTION (this);
for (auto & endPreambleDetectionEvent : m_endPreambleDetectionEvents)
{
endPreambleDetectionEvent.Cancel ();
}
m_endPreambleDetectionEvents.clear ();
for (auto & endRxPayloadEvent : m_endRxPayloadEvents)
{
endRxPayloadEvent.Cancel ();
}
m_endRxPayloadEvents.clear ();
}
bool
PhyEntity::NoEndPreambleDetectionEvents (void) const
{
return m_endPreambleDetectionEvents.empty ();
}
void
PhyEntity::CancelRunningEndPreambleDetectionEvents (bool clear /* = false */)
{
NS_LOG_FUNCTION (this << clear);
for (auto & endPreambleDetectionEvent : m_endPreambleDetectionEvents)
{
if (endPreambleDetectionEvent.IsRunning ())
{
endPreambleDetectionEvent.Cancel ();
}
}
if (clear)
{
m_endPreambleDetectionEvents.clear ();
}
}
void
PhyEntity::AbortCurrentReception (WifiPhyRxfailureReason reason)
{
NS_LOG_FUNCTION (this << reason);
//TODO cancel some events here later on
DoAbortCurrentReception (reason);
m_wifiPhy->AbortCurrentReception (reason);
}
void
PhyEntity::DoAbortCurrentReception (WifiPhyRxfailureReason reason)
{
NS_LOG_FUNCTION (this << reason);
if (m_wifiPhy->m_currentEvent) //Otherwise abort has already been called just before with FILTERED reason
{
for (auto & endMpduEvent : m_endOfMpduEvents)
{
endMpduEvent.Cancel ();
}
m_endOfMpduEvents.clear ();
}
}
void
PhyEntity::ResetReceive (Ptr<Event> event)
{
NS_LOG_FUNCTION (this << *event);
NS_ASSERT (event->GetEndTime () == Simulator::Now ()); //TODO: overload for UL MU
DoResetReceive (event);
NS_ASSERT (m_endRxPayloadEvents.size () == 1 && m_endRxPayloadEvents.front ().IsExpired ());
m_endRxPayloadEvents.clear ();
m_wifiPhy->ResetReceive (event);
}
void
PhyEntity::DoResetReceive (Ptr<Event> event)
{
NS_LOG_FUNCTION (this << *event);
NS_ASSERT (event->GetEndTime () == Simulator::Now ());
}
double
PhyEntity::GetRandomValue (void) const
{
@@ -523,4 +991,10 @@ PhyEntity::GetRxPowerWForPpdu (Ptr<Event> event) const
return event->GetRxPowerW (m_wifiPhy->GetBand (m_wifiPhy->GetMeasurementChannelWidth (event->GetPpdu ())));
}
Ptr<const Event>
PhyEntity::GetCurrentEvent (void) const
{
return m_wifiPhy->m_currentEvent;
}
} //namespace ns3

View File

@@ -339,6 +339,19 @@ public:
*/
virtual Ptr<const WifiPsdu> GetAddressedPsduInPpdu (Ptr<const WifiPpdu> ppdu) const;
/**
* Start receiving the PHY preamble of a PPDU (i.e. the first bit of the preamble has arrived).
*
* This method triggers the start of the preamble detection period (\see
* StartPreambleDetectionPeriod) if the PHY can process the PPDU.
*
* \param ppdu the arriving PPDU
* \param rxPowersW the receive power in W per band
* \param rxDuration the duration of the PPDU
* \param psdFlag the flag indicating the type of Tx PSD to build
*/
virtual void StartReceivePreamble (Ptr<WifiPpdu> ppdu, RxPowerWattPerChannelBand rxPowersW,
Time rxDuration, TxPsdFlag psdFlag);
/**
* Start receiving a given field.
*
@@ -367,6 +380,44 @@ public:
*/
void EndReceiveField (WifiPpduField field, Ptr<Event> event);
/**
* The last symbol of the PPDU has arrived.
*
* \param event the event holding incoming PPDU's information
*/
void EndReceivePayload (Ptr<Event> event);
/**
* 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> event);
/**
* Cancel and clear all running events.
*/
virtual void CancelAllEvents (void);
/**
* \return \c true if there is no end preamble detection event running, \c false otherwise
*/
bool NoEndPreambleDetectionEvents (void) const;
/**
* Cancel and eventually clear all end preamble detection events.
*
* \param clear whether to clear the end preamble detection events' list
*/
void CancelRunningEndPreambleDetectionEvents (bool clear = false);
/**
* 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
*/
virtual uint16_t GetStaId (const Ptr<const WifiPpdu> ppdu) const;
protected:
/**
* A map of PPDU field elements per preamble type.
@@ -404,16 +455,16 @@ protected:
virtual PhyFieldRxStatus DoEndReceiveField (WifiPpduField field, Ptr<Event> event);
/**
* Start receiving the preamble, perform amendment-specific actions, and
* signify if it is supported.
* Get the event corresponding to the incoming PPDU.
*
* This method triggers the start of the preamble detection period (\see
* StartPreambleDetectionPeriod).
* We store all incoming preamble events, perform amendment-specific actions,
* and a decision is made at the end of the preamble detection window.
*
* \param event the event holding incoming PPDU's information
* \return \c true if the preamble is supported, \c false otherwise
* \param ppdu the incoming PPDU
* \param rxPowersW the receive power in W per band
* \return the event holding the incoming PPDU's information
*/
virtual bool DoStartReceivePreamble (Ptr<Event> event);
virtual Ptr<Event> DoGetEvent (Ptr<const WifiPpdu> ppdu, RxPowerWattPerChannelBand rxPowersW);
/**
* End receiving the preamble, perform amendment-specific actions, and
* provide the status of the reception.
@@ -439,6 +490,37 @@ protected:
*/
void EndPreambleDetectionPeriod (Ptr<Event> event);
/**
* Start receiving the PSDU (i.e. the first symbol of the PSDU has arrived).
*
* \param event the event holding incoming PPDU's information
*/
void StartReceivePayload (Ptr<Event> event);
/**
* Start receiving the PSDU (i.e. the first symbol of the PSDU has arrived)
* and perform amendment-specific actions.
*
* \param event the event holding incoming PPDU's information
*/
virtual void DoStartReceivePayload (Ptr<Event> event);
/**
* Perform amendment-specific actions before resetting 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
*/
virtual void DoResetReceive (Ptr<Event> event);
/**
* Perform amendment-specific actions before aborting the
* current reception.
*
* \param reason the reason the reception is aborted
*/
virtual void DoAbortCurrentReception (WifiPhyRxfailureReason reason);
/**
* Checks if the signaled configuration (excluding bandwidth)
* is supported by the PHY.
@@ -448,18 +530,82 @@ protected:
*/
virtual bool IsConfigSupported (Ptr<const WifiPpdu> ppdu) const;
/**
* Drop the PPDU and the corresponding preamble detection event, but keep CCA busy
* state after the completion of the currently processed event.
*
* \param ppdu the incoming PPDU
* \param reason the reason the PPDU is dropped
* \param endRx the end of the incoming PPDU's reception
* \param measurementChannelWidth the measurement width (in MHz) to consider for the PPDU
*/
void DropPreambleEvent (Ptr<const WifiPpdu> ppdu, WifiPhyRxfailureReason reason, Time endRx, uint16_t measurementChannelWidth);
/**
* Erase the event corresponding to the PPDU from the list of preamble events,
* but consider it as noise after the completion of the current event.
*
* \param ppdu the incoming PPDU
* \param rxDuration the duration of the PPDU
*/
void ErasePreambleEvent (Ptr<const WifiPpdu> ppdu, Time rxDuration);
/**
* Get the reception status for the provided MPDU and notify.
*
* \param psdu the arriving MPDU formatted as a PSDU
* \param event the event holding incoming PPDU's information
* \param staId the station ID of the PSDU (only used for MU)
* \param relativeMpduStart the relative start time of the MPDU within the A-MPDU. 0 for normal MPDUs
* \param mpduDuration the duration of the MPDU
*
* \return information on MPDU reception: status, signal power (dBm), and noise power (in dBm)
*/
std::pair<bool, SignalNoiseDbm> GetReceptionStatus (Ptr<const WifiPsdu> psdu,
Ptr<Event> event, uint16_t staId,
Time relativeMpduStart,
Time mpduDuration);
/**
* The last symbol of an MPDU in an A-MPDU has arrived.
*
* \param event the event holding incoming PPDU's information
* \param psdu the arriving MPDU formatted as a PSDU containing a normal MPDU
* \param mpduIndex the index of the MPDU within the A-MPDU
* \param relativeStart the relative start time of the MPDU within the A-MPDU.
* \param mpduDuration the duration of the MPDU
*/
void EndOfMpdu (Ptr<Event> event, Ptr<const WifiPsdu> psdu, size_t mpduIndex, Time relativeStart, Time mpduDuration);
/**
* Schedule end of MPDUs events.
*
* \param event the event holding incoming PPDU's information
*/
void ScheduleEndOfMpdus (Ptr<Event> event);
/**
* Perform amendment-specific actions at the end of the reception of
* the payload.
*
* \param ppdu the incoming PPDU
*/
virtual void DoEndReceivePayload (Ptr<const WifiPpdu> ppdu);
/**
* Get the channel width and band to use (will be overloaded by child classes).
*
* \param txVector the transmission parameters
* \param staId the station ID of the PSDU
* \return a pair of channel width (MHz) and band
*/
virtual std::pair<uint16_t, WifiSpectrumBand> GetChannelWidthAndBand (WifiTxVector txVector, uint16_t staId) 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> event);
/**
* Obtain a random value from the WifiPhy's generator.
@@ -485,11 +631,68 @@ protected:
* \return the received power (W) for the event over a given band
*/
double GetRxPowerWForPpdu (Ptr<Event> event) const;
/**
* Get the pointer to the current event (stored in WifiPhy).
* Wrapper used by child classes.
*
* \return the pointer to the current event
*/
Ptr<const Event> GetCurrentEvent (void) const;
/**
* Get the map of current preamble events (stored in WifiPhy).
* Wrapper used by child classes.
*
* \return the reference to the map of current preamble events
*/
const std::map <std::pair<uint64_t, WifiPreamble>, Ptr<Event> > & GetCurrentPreambleEvents (void) const;
/**
* Add an entry to the map of current preamble events (stored in WifiPhy).
* Wrapper used by child classes.
*
* \param event the event holding incoming PPDU's information
*/
void AddPreambleEvent (Ptr<Event> event);
/**
* Create an event using WifiPhy's InterferenceHelper class.
* Wrapper used by child classes.
*
* \copydoc InterferenceHelper::Add(Ptr<const WifiPpdu>, WifiTxVector, Time, RxPowerWattPerChannelBand, bool)
*/
Ptr<Event> CreateInterferenceEvent (Ptr<const WifiPpdu> ppdu, WifiTxVector txVector, Time duration, RxPowerWattPerChannelBand rxPower, bool isStartOfdmaRxing = false);
/**
* Update an event in WifiPhy's InterferenceHelper class.
* Wrapper used by child classes.
*
* \copydoc InterferenceHelper::UpdateEvent(Ptr<Event>, RxPowerWattPerChannelBand)
*/
void UpdateInterferenceEvent (Ptr<Event> event, RxPowerWattPerChannelBand rxPower);
/**
* Notify WifiPhy's InterferenceHelper of the end of the reception,
* clear maps and end of MPDU event, and eventually reset WifiPhy.
*
* \param reset whether to reset WifiPhy
*/
void NotifyInterferenceRxEndAndClear (bool reset);
Ptr<WifiPhy> m_wifiPhy; //!< Pointer to the owning WifiPhy
Ptr<WifiPhyStateHelper> m_state; //!< Pointer to WifiPhyStateHelper of the WifiPhy (to make it reachable for child classes)
std::list<WifiMode> m_modeList; //!< the list of supported modes
std::vector <EventId> m_endPreambleDetectionEvents; //!< the end of preamble detection events
std::vector <EventId> m_endOfMpduEvents; //!< the end of MPDU events (only used for A-MPDUs)
std::vector <EventId> m_endRxPayloadEvents; //!< the end of receive events (only one unless UL MU reception)
/**
* A pair of a UID and STA_ID
*/
typedef std::pair <uint64_t /* UID */, uint16_t /* STA-ID */> UidStaIdPair;
std::map<UidStaIdPair, std::vector<bool> > m_statusPerMpduMap; //!< Map of the current reception status per MPDU that is filled in as long as MPDUs are being processed by the PHY in case of an A-MPDU
std::map<UidStaIdPair, SignalNoiseDbm> m_signalNoiseMap; //!< Map of the latest signal power and noise power in dBm (noise power includes the noise figure)
}; //class PhyEntity
/**

View File

@@ -1061,6 +1061,15 @@ public:
*/
WifiSpectrumBand GetNonOfdmaBand (WifiTxVector txVector, uint16_t staId) const;
/**
* \param channelWidth the total channel width (MHz) used for the OFDMA transmission
* \param range the subcarrier range of the HE RU
* \return the converted subcarriers
*
* This is a helper function to convert HE RU subcarriers, which are relative to the center frequency subcarrier, to the indexes used by the Spectrum model.
*/
virtual WifiSpectrumBand ConvertHeRuSubcarriers (uint16_t channelWidth, HeRu::SubcarrierRange range) const;
/**
* Add the PHY entity to the map of __implemented__ PHY entities for the
* given modulation class.
@@ -1132,7 +1141,6 @@ 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.
@@ -1141,7 +1149,6 @@ public: //TODO find a better way (robust enough for OfdmaSpectrumWifiPhy overloa
* \return the STA ID
*/
virtual uint16_t GetStaId (const Ptr<const WifiPpdu> ppdu) const;
protected:
/**
* Return the channel width used to measure the RSSI.
* This corresponds to the primary channel unless it corresponds to the
@@ -1162,15 +1169,6 @@ protected:
*/
virtual WifiSpectrumBand GetBand (uint16_t bandWidth, uint8_t bandIndex = 0);
/**
* \param channelWidth the total channel width (MHz) used for the OFDMA transmission
* \param range the subcarrier range of the HE RU
* \return the converted subcarriers
*
* This is a helper function to convert HE RU subcarriers, which are relative to the center frequency subcarrier, to the indexes used by the Spectrum model.
*/
virtual WifiSpectrumBand ConvertHeRuSubcarriers (uint16_t channelWidth, HeRu::SubcarrierRange range) const;
/**
* Add the PHY entity to the map of supported PHY entities for the
* given modulation class for the WifiPhy instance.