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