wifi: Implement CCA logic when channel bonding is used
This commit is contained in:
@@ -776,6 +776,47 @@ HtPhy::GetMaxPsduSize (void) const
|
||||
return 65535;
|
||||
}
|
||||
|
||||
PhyEntity::CcaIndication
|
||||
HtPhy::GetCcaIndication (const Ptr<const WifiPpdu> ppdu)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
if (m_wifiPhy->GetChannelWidth () < 40)
|
||||
{
|
||||
return PhyEntity::GetCcaIndication (ppdu);
|
||||
}
|
||||
double ccaThresholdDbm = GetCcaThreshold (ppdu, WIFI_CHANLIST_PRIMARY);
|
||||
Time delayUntilCcaEnd = GetDelayUntilCcaEnd (ccaThresholdDbm, GetPrimaryBand (20));
|
||||
if (delayUntilCcaEnd.IsStrictlyPositive ())
|
||||
{
|
||||
return std::make_pair (delayUntilCcaEnd, WIFI_CHANLIST_PRIMARY); //if Primary is busy, ignore CCA for Secondary
|
||||
}
|
||||
if (ppdu != nullptr)
|
||||
{
|
||||
const uint16_t primaryWidth = 20;
|
||||
uint16_t p20MinFreq =
|
||||
m_wifiPhy->GetOperatingChannel ().GetPrimaryChannelCenterFrequency (primaryWidth) - (primaryWidth / 2);
|
||||
uint16_t p20MaxFreq =
|
||||
m_wifiPhy->GetOperatingChannel ().GetPrimaryChannelCenterFrequency (primaryWidth) + (primaryWidth / 2);
|
||||
if (ppdu->DoesOverlapChannel (p20MinFreq, p20MaxFreq))
|
||||
{
|
||||
/*
|
||||
* PPDU occupies primary 20 MHz channel, hence we skip CCA sensitivity rules
|
||||
* for signals not occupying the primary 20 MHz channel.
|
||||
*/
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
ccaThresholdDbm = GetCcaThreshold (ppdu, WIFI_CHANLIST_SECONDARY);
|
||||
delayUntilCcaEnd = GetDelayUntilCcaEnd (ccaThresholdDbm, GetSecondaryBand (20));
|
||||
if (delayUntilCcaEnd.IsStrictlyPositive ())
|
||||
{
|
||||
return std::make_pair (delayUntilCcaEnd, WIFI_CHANLIST_SECONDARY);
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
} //namespace ns3
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -451,6 +451,7 @@ protected:
|
||||
bool IsConfigSupported (Ptr<const WifiPpdu> ppdu) const override;
|
||||
Ptr<SpectrumValue> GetTxPowerSpectralDensity (double txPowerW, Ptr<const WifiPpdu> ppdu) const override;
|
||||
uint32_t GetMaxPsduSize (void) const override;
|
||||
CcaIndication GetCcaIndication (const Ptr<const WifiPpdu> ppdu) override;
|
||||
|
||||
/**
|
||||
* Build mode list.
|
||||
|
||||
@@ -1062,6 +1062,12 @@ PhyEntity::GetCcaThreshold (const Ptr<const WifiPpdu> ppdu, WifiChannelListType
|
||||
return (ppdu == nullptr) ? m_wifiPhy->GetCcaEdThreshold () : m_wifiPhy->GetCcaSensitivityThreshold ();
|
||||
}
|
||||
|
||||
Time
|
||||
PhyEntity::GetDelayUntilCcaEnd (double thresholdDbm, WifiSpectrumBand band)
|
||||
{
|
||||
return m_wifiPhy->m_interference->GetEnergyDuration (DbmToW (thresholdDbm), band);
|
||||
}
|
||||
|
||||
void
|
||||
PhyEntity::SwitchMaybeToCcaBusy (const Ptr<const WifiPpdu> ppdu)
|
||||
{
|
||||
@@ -1069,15 +1075,31 @@ PhyEntity::SwitchMaybeToCcaBusy (const Ptr<const WifiPpdu> ppdu)
|
||||
//not going to be able to synchronize on it
|
||||
//In this model, CCA becomes busy when the aggregation of all signals as
|
||||
//tracked by the InterferenceHelper class is higher than the CcaBusyThreshold
|
||||
const auto ccaIndication = GetCcaIndication (ppdu);
|
||||
if (ccaIndication.has_value ())
|
||||
{
|
||||
NS_LOG_DEBUG ("CCA busy for " << ccaIndication.value ().second << " during " << ccaIndication.value ().first.As (Time::S));
|
||||
m_state->SwitchMaybeToCcaBusy (ccaIndication.value ().first, ccaIndication.value ().second, {});
|
||||
return;
|
||||
}
|
||||
if (ppdu != nullptr)
|
||||
{
|
||||
SwitchMaybeToCcaBusy (nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
PhyEntity::CcaIndication
|
||||
PhyEntity::GetCcaIndication (const Ptr<const WifiPpdu> ppdu)
|
||||
{
|
||||
const uint16_t channelWidth = GetMeasurementChannelWidth (ppdu);
|
||||
NS_LOG_FUNCTION (this << channelWidth);
|
||||
double ccaThresholdW = DbmToW (GetCcaThreshold (ppdu, WIFI_CHANLIST_PRIMARY));
|
||||
const Time delayUntilCcaEnd = m_wifiPhy->m_interference->GetEnergyDuration (ccaThresholdW, GetPrimaryBand (channelWidth));
|
||||
const double ccaThresholdDbm = GetCcaThreshold (ppdu, WIFI_CHANLIST_PRIMARY);
|
||||
const Time delayUntilCcaEnd = GetDelayUntilCcaEnd (ccaThresholdDbm, GetPrimaryBand (channelWidth));
|
||||
if (delayUntilCcaEnd.IsStrictlyPositive ())
|
||||
{
|
||||
NS_LOG_DEBUG ("Calling SwitchMaybeToCcaBusy for " << delayUntilCcaEnd.As (Time::S));
|
||||
m_state->SwitchMaybeToCcaBusy (delayUntilCcaEnd);
|
||||
return std::make_pair (delayUntilCcaEnd, WIFI_CHANLIST_PRIMARY);
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
uint64_t
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include <map>
|
||||
#include <tuple>
|
||||
#include <optional>
|
||||
#include <utility>
|
||||
#include "wifi-mpdu-type.h"
|
||||
#include "wifi-tx-vector.h"
|
||||
#include "wifi-phy-band.h"
|
||||
@@ -832,6 +833,15 @@ protected:
|
||||
*/
|
||||
virtual uint16_t GetRxChannelWidth (const WifiTxVector& txVector) const;
|
||||
|
||||
/**
|
||||
* Return the delay until CCA busy is ended for a given sensitivity threshold (in dBm) and a given band.
|
||||
*
|
||||
* \param thresholdDbm the CCA sensitivity threshold in dBm
|
||||
* \param band identify the requested band
|
||||
* \return the delay until CCA busy is ended
|
||||
*/
|
||||
Time GetDelayUntilCcaEnd (double thresholdDbm, WifiSpectrumBand band);
|
||||
|
||||
/**
|
||||
* \param currentChannelWidth channel width of the current transmission (MHz)
|
||||
* \return the width of the guard band (MHz)
|
||||
@@ -850,6 +860,17 @@ protected:
|
||||
*/
|
||||
std::tuple<double, double, double> GetTxMaskRejectionParams (void) const;
|
||||
|
||||
using CcaIndication = std::optional<std::pair<Time, WifiChannelListType>>; //!< CCA end time and its corresponding channel list type (can be std::nullopt if IDLE)
|
||||
|
||||
/**
|
||||
* Get CCA end time and its corresponding channel list type when a new signal has been received by the PHY.
|
||||
*
|
||||
* \param ppdu the incoming PPDU or nullptr for any signal
|
||||
* \return CCA end time and its corresponding channel list type when a new signal has been received by the PHY,
|
||||
* or std::nullopt if all channel list types are IDLE.
|
||||
*/
|
||||
virtual CcaIndication GetCcaIndication (const Ptr<const WifiPpdu> ppdu);
|
||||
|
||||
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)
|
||||
|
||||
|
||||
@@ -70,6 +70,9 @@ const VhtPhy::NesExceptionMap VhtPhy::m_exceptionsMap {
|
||||
{ std::make_tuple (160, 7, 9), 12 } //instead of 10
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief map a given channel list type to the corresponding scaling factor in dBm
|
||||
*/
|
||||
const std::map<WifiChannelListType, double> channelTypeToScalingFactorDbm {
|
||||
{WIFI_CHANLIST_PRIMARY, 0.0},
|
||||
{WIFI_CHANLIST_SECONDARY, 0.0},
|
||||
@@ -77,6 +80,15 @@ const std::map<WifiChannelListType, double> channelTypeToScalingFactorDbm {
|
||||
{WIFI_CHANLIST_SECONDARY80, 6.0}
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief map a given secondary channel width to its channel list type
|
||||
*/
|
||||
const std::map<uint16_t, WifiChannelListType> secondaryChannels {
|
||||
{20, WIFI_CHANLIST_SECONDARY},
|
||||
{40, WIFI_CHANLIST_SECONDARY40},
|
||||
{80, WIFI_CHANLIST_SECONDARY80}
|
||||
};
|
||||
|
||||
/* *NS_CHECK_STYLE_ON* */
|
||||
|
||||
VhtPhy::VhtPhy (bool buildModeList /* = true */)
|
||||
@@ -576,6 +588,80 @@ VhtPhy::GetCcaThreshold (const Ptr<const WifiPpdu> ppdu, WifiChannelListType cha
|
||||
}
|
||||
}
|
||||
|
||||
PhyEntity::CcaIndication
|
||||
VhtPhy::GetCcaIndication (const Ptr<const WifiPpdu> ppdu)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
|
||||
if (m_wifiPhy->GetChannelWidth () < 80)
|
||||
{
|
||||
return HtPhy::GetCcaIndication (ppdu);
|
||||
}
|
||||
|
||||
double ccaThresholdDbm = GetCcaThreshold (ppdu, WIFI_CHANLIST_PRIMARY);
|
||||
Time delayUntilCcaEnd = GetDelayUntilCcaEnd (ccaThresholdDbm, GetPrimaryBand (20));
|
||||
if (delayUntilCcaEnd.IsStrictlyPositive ())
|
||||
{
|
||||
return std::make_pair (delayUntilCcaEnd, WIFI_CHANLIST_PRIMARY); //if Primary is busy, ignore CCA for Secondary
|
||||
}
|
||||
|
||||
if (ppdu != nullptr)
|
||||
{
|
||||
const uint16_t primaryWidth = 20;
|
||||
uint16_t p20MinFreq =
|
||||
m_wifiPhy->GetOperatingChannel ().GetPrimaryChannelCenterFrequency (primaryWidth) - (primaryWidth / 2);
|
||||
uint16_t p20MaxFreq =
|
||||
m_wifiPhy->GetOperatingChannel ().GetPrimaryChannelCenterFrequency (primaryWidth) + (primaryWidth / 2);
|
||||
if (ppdu->DoesOverlapChannel (p20MinFreq, p20MaxFreq))
|
||||
{
|
||||
/*
|
||||
* PPDU occupies primary 20 MHz channel, hence we skip CCA sensitivity rules
|
||||
* for signals not occupying the primary 20 MHz channel.
|
||||
*/
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<uint16_t> secondaryWidthsToCheck;
|
||||
if (ppdu != nullptr)
|
||||
{
|
||||
for (const auto& secondaryChannel : secondaryChannels)
|
||||
{
|
||||
uint16_t secondaryWidth = secondaryChannel.first;
|
||||
uint16_t secondaryMinFreq =
|
||||
m_wifiPhy->GetOperatingChannel ().GetSecondaryChannelCenterFrequency (secondaryWidth) - (secondaryWidth / 2);
|
||||
uint16_t secondaryMaxFreq =
|
||||
m_wifiPhy->GetOperatingChannel ().GetSecondaryChannelCenterFrequency (secondaryWidth) + (secondaryWidth / 2);
|
||||
if ((m_wifiPhy->GetChannelWidth () > secondaryWidth) && ppdu->DoesOverlapChannel (secondaryMinFreq, secondaryMaxFreq))
|
||||
{
|
||||
secondaryWidthsToCheck.push_back (secondaryWidth);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
secondaryWidthsToCheck.push_back (20);
|
||||
secondaryWidthsToCheck.push_back (40);
|
||||
if (m_wifiPhy->GetChannelWidth () > 80)
|
||||
{
|
||||
secondaryWidthsToCheck.push_back (80);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto secondaryWidth : secondaryWidthsToCheck)
|
||||
{
|
||||
auto channelType = secondaryChannels.at (secondaryWidth);
|
||||
ccaThresholdDbm = GetCcaThreshold (ppdu, channelType);
|
||||
delayUntilCcaEnd = GetDelayUntilCcaEnd (ccaThresholdDbm, GetSecondaryBand (secondaryWidth));
|
||||
if (delayUntilCcaEnd.IsStrictlyPositive ())
|
||||
{
|
||||
return std::make_pair (delayUntilCcaEnd, channelType);
|
||||
}
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
} //namespace ns3
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -271,6 +271,7 @@ protected:
|
||||
PhyFieldRxStatus DoEndReceiveField (WifiPpduField field, Ptr<Event> event) override;
|
||||
bool IsAllConfigSupported (WifiPpduField field, Ptr<const WifiPpdu> ppdu) const override;
|
||||
uint32_t GetMaxPsduSize (void) const override;
|
||||
CcaIndication GetCcaIndication (const Ptr<const WifiPpdu> ppdu) override;
|
||||
|
||||
/**
|
||||
* End receiving the SIG-A, perform VHT-specific actions, and
|
||||
|
||||
@@ -2887,7 +2887,7 @@ TestUlOfdmaPhyTransmission::RunOne (void)
|
||||
|
||||
Simulator::Schedule (delay + MicroSeconds (50), &TestUlOfdmaPhyTransmission::GenerateInterference, this, interferencePsdRu2, MilliSeconds (100));
|
||||
ScheduleTest (delay, true,
|
||||
WifiPhyState::CCA_BUSY, //PHY should move to CCA_BUSY since measurement channel encompasses total channel width
|
||||
(m_channelWidth >= 40) ? WifiPhyState::IDLE : WifiPhyState::CCA_BUSY, //PHY should move to CCA_BUSY if interference is generated in its primary channel
|
||||
1, 0, 1000, //One PSDU of 1000 bytes should have been successfully received from STA 1
|
||||
0, 1, 0); //Reception of the PSDU from STA 2 should have failed (since interference occupies RU 2)
|
||||
delay += Seconds (1.0);
|
||||
@@ -2966,7 +2966,7 @@ TestUlOfdmaPhyTransmission::RunOne (void)
|
||||
bytes = 0;
|
||||
}
|
||||
ScheduleTest (delay, true,
|
||||
WifiPhyState::CCA_BUSY, //PHY should move to CCA_BUSY instead of IDLE due to the interference on measurement channel width
|
||||
(m_channelWidth >= 40) ? WifiPhyState::IDLE : WifiPhyState::CCA_BUSY, //PHY should move to CCA_BUSY instead of IDLE if HE TB PPDU on primary channel
|
||||
succ, fail, bytes,
|
||||
0, 1, 0); //Reception of the PSDU from STA 2 should have failed (since interference from STA 3 on same 20 MHz channel)
|
||||
delay += Seconds (1.0);
|
||||
|
||||
Reference in New Issue
Block a user