wifi: Make CCA PHY indication more reusable over PHY entities

This commit is contained in:
Sébastien Deronne
2024-10-05 08:45:10 +02:00
parent dd5ce2e037
commit 176e382b41
6 changed files with 119 additions and 111 deletions

View File

@@ -1186,7 +1186,7 @@ HePhy::GetPer20MHzDurations(const Ptr<const WifiPpdu> ppdu)
* aCCATime after the signal starts and shall continue to indicate the 20 MHz subchannel is
* busy while the threshold continues to be exceeded.
*/
dBm_u ccaThreshold = -62;
auto ccaThreshold = m_wifiPhy->GetCcaEdThreshold();
auto delayUntilCcaEnd = GetDelayUntilCcaEnd(ccaThreshold, band);
if (ppdu)

View File

@@ -540,6 +540,18 @@ class HePhy : public VhtPhy
*/
static uint16_t GetUsableSubcarriers(MHz_u channelWidth);
/**
* Compute the per-20 MHz CCA durations vector that indicates
* for how long each 20 MHz subchannel (corresponding to the
* index of the element in the vector) is busy and where a zero duration
* indicates that the subchannel is idle. The vector is non-empty if the
* operational channel width is larger than 20 MHz.
*
* @param ppdu the incoming PPDU or nullptr for any signal
* @return the per-20 MHz CCA durations vector
*/
virtual std::vector<Time> GetPer20MHzDurations(const Ptr<const WifiPpdu> ppdu);
uint64_t m_previouslyTxPpduUid; //!< UID of the previously sent PPDU, used by AP to recognize
//!< response HE TB PPDUs
uint64_t m_currentMuPpduUid; //!< UID of the HE MU or HE TB PPDU being received
@@ -595,18 +607,6 @@ class HePhy : public VhtPhy
WifiChannelListType channelType,
const std::vector<Time>& per20MHzDurations);
/**
* Compute the per-20 MHz CCA durations vector that indicates
* for how long each 20 MHz subchannel (corresponding to the
* index of the element in the vector) is busy and where a zero duration
* indicates that the subchannel is idle. The vector is non-empty if the
* operational channel width is larger than 20 MHz.
*
* @param ppdu the incoming PPDU or nullptr for any signal
* @return the per-20 MHz CCA durations vector
*/
std::vector<Time> GetPer20MHzDurations(const Ptr<const WifiPpdu> ppdu);
/**
* Given a PPDU duration value, the TXVECTOR used to transmit the PPDU and
* the PHY band, compute a valid PPDU duration considering the number and

View File

@@ -40,6 +40,13 @@ const PhyEntity::PpduFormats HtPhy::m_htPpduFormats {
WIFI_PPDU_FIELD_DATA } }
};
/**
* \brief map a given secondary channel width to its channel list type
*/
const std::map<MHz_u, WifiChannelListType> htSecondaryChannels {
{20, WIFI_CHANLIST_SECONDARY},
};
// clang-format on
HtPhy::HtPhy(uint8_t maxNss /* = 1 */, bool buildModeList /* = true */)
@@ -813,6 +820,71 @@ HtPhy::GetMaxPsduSize() const
return 65535;
}
const std::map<MHz_u, WifiChannelListType>&
HtPhy::GetCcaSecondaryChannels() const
{
return htSecondaryChannels;
}
std::vector<MHz_u>
HtPhy::GetCcaSecondaryWidths(const Ptr<const WifiPpdu> ppdu) const
{
std::vector<MHz_u> secondaryWidthsToCheck{};
if (ppdu)
{
for (const auto& secondaryChannel : GetCcaSecondaryChannels())
{
const auto secondaryWidth = secondaryChannel.first;
if (secondaryWidth >= m_wifiPhy->GetChannelWidth())
{
break;
}
const MHz_u secondaryMinFreq =
m_wifiPhy->GetOperatingChannel().GetSecondaryChannelCenterFrequency(
secondaryWidth) -
(secondaryWidth / 2);
const MHz_u secondaryMaxFreq =
m_wifiPhy->GetOperatingChannel().GetSecondaryChannelCenterFrequency(
secondaryWidth) +
(secondaryWidth / 2);
if (ppdu->DoesOverlapChannel(secondaryMinFreq, secondaryMaxFreq))
{
secondaryWidthsToCheck.push_back(secondaryWidth);
}
}
}
else
{
for (MHz_u secondaryWidth = 20; secondaryWidth < m_wifiPhy->GetChannelWidth();
secondaryWidth *= 2)
{
secondaryWidthsToCheck.push_back(secondaryWidth);
}
}
return secondaryWidthsToCheck;
}
PhyEntity::CcaIndication
HtPhy::GetCcaIndicationOnSecondary(const Ptr<const WifiPpdu> ppdu)
{
const auto& secondaryChannels = GetCcaSecondaryChannels();
const auto secondaryWidthsToCheck = GetCcaSecondaryWidths(ppdu);
for (auto secondaryWidth : secondaryWidthsToCheck)
{
const auto channelType = secondaryChannels.at(secondaryWidth);
const auto ccaThreshold = GetCcaThreshold(ppdu, channelType);
const auto band = GetSecondaryBand(secondaryWidth);
if (const auto delayUntilCcaEnd = GetDelayUntilCcaEnd(ccaThreshold, band);
delayUntilCcaEnd.IsStrictlyPositive())
{
return std::make_pair(delayUntilCcaEnd, channelType);
}
}
return std::nullopt;
}
PhyEntity::CcaIndication
HtPhy::GetCcaIndication(const Ptr<const WifiPpdu> ppdu)
{
@@ -820,6 +892,7 @@ HtPhy::GetCcaIndication(const Ptr<const WifiPpdu> ppdu)
{
return OfdmPhy::GetCcaIndication(ppdu);
}
auto ccaThreshold = GetCcaThreshold(ppdu, WIFI_CHANLIST_PRIMARY);
auto delayUntilCcaEnd = GetDelayUntilCcaEnd(ccaThreshold, GetPrimaryBand(MHz_u{20}));
if (delayUntilCcaEnd.IsStrictlyPositive())
@@ -828,6 +901,7 @@ HtPhy::GetCcaIndication(const Ptr<const WifiPpdu> ppdu)
delayUntilCcaEnd,
WIFI_CHANLIST_PRIMARY); // if Primary is busy, ignore CCA for Secondary
}
if (ppdu)
{
const MHz_u primaryWidth{20};
@@ -847,24 +921,7 @@ HtPhy::GetCcaIndication(const Ptr<const WifiPpdu> ppdu)
}
}
const MHz_u secondaryWidth{20};
const MHz_u s20MinFreq =
m_wifiPhy->GetOperatingChannel().GetSecondaryChannelCenterFrequency(secondaryWidth) -
(secondaryWidth / 2);
const MHz_u s20MaxFreq =
m_wifiPhy->GetOperatingChannel().GetSecondaryChannelCenterFrequency(secondaryWidth) +
(secondaryWidth / 2);
if (!ppdu || ppdu->DoesOverlapChannel(s20MinFreq, s20MaxFreq))
{
ccaThreshold = GetCcaThreshold(ppdu, WIFI_CHANLIST_SECONDARY);
delayUntilCcaEnd = GetDelayUntilCcaEnd(ccaThreshold, GetSecondaryBand(MHz_u{20}));
if (delayUntilCcaEnd.IsStrictlyPositive())
{
return std::make_pair(delayUntilCcaEnd, WIFI_CHANLIST_SECONDARY);
}
}
return std::nullopt;
return GetCcaIndicationOnSecondary(ppdu);
}
} // namespace ns3

View File

@@ -460,6 +460,32 @@ class HtPhy : public OfdmPhy
uint32_t GetMaxPsduSize() const override;
CcaIndication GetCcaIndication(const Ptr<const WifiPpdu> ppdu) override;
/**
* Get the secondary channel widths and their corresponding channel list types that are
* supported by the PHY entity.
*
* @return the channel list type per supported secondary channel width
*/
virtual const std::map<MHz_u, WifiChannelListType>& GetCcaSecondaryChannels() const;
/**
* Get the widths of the secondary channels to inspect for CCA indication.
*
* @param ppdu the incoming PPDU or nullptr for any signal
* @return the widths of the secondary channels to inspect for CCA indication
*/
std::vector<MHz_u> GetCcaSecondaryWidths(const Ptr<const WifiPpdu> ppdu) const;
/**
* Get CCA end time and its corresponding channel list type when a new signal not occupying the
* primary 20 MHz channel 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 or std::nullopt if all channel
* list types are IDLE
*/
virtual PhyEntity::CcaIndication GetCcaIndicationOnSecondary(const Ptr<const WifiPpdu> ppdu);
/**
* Build mode list.
* Should be redone whenever the maximum MCS index per spatial stream

View File

@@ -80,7 +80,7 @@ const std::map<WifiChannelListType, dBm_u> channelTypeToScalingFactor{
/**
* @brief map a given secondary channel width to its channel list type
*/
const std::map<MHz_u, WifiChannelListType> secondaryChannels{
const std::map<MHz_u, WifiChannelListType> vhtSecondaryChannels{
{MHz_u{20}, WIFI_CHANLIST_SECONDARY},
{MHz_u{40}, WIFI_CHANLIST_SECONDARY40},
{MHz_u{80}, WIFI_CHANLIST_SECONDARY80},
@@ -573,85 +573,10 @@ VhtPhy::GetCcaThreshold(const Ptr<const WifiPpdu> ppdu, WifiChannelListType chan
}
}
PhyEntity::CcaIndication
VhtPhy::GetCcaIndication(const Ptr<const WifiPpdu> ppdu)
const std::map<MHz_u, WifiChannelListType>&
VhtPhy::GetCcaSecondaryChannels() const
{
if (m_wifiPhy->GetChannelWidth() < 80)
{
return HtPhy::GetCcaIndication(ppdu);
}
auto ccaThreshold = GetCcaThreshold(ppdu, WIFI_CHANLIST_PRIMARY);
auto delayUntilCcaEnd = GetDelayUntilCcaEnd(ccaThreshold, GetPrimaryBand(20));
if (delayUntilCcaEnd.IsStrictlyPositive())
{
return std::make_pair(
delayUntilCcaEnd,
WIFI_CHANLIST_PRIMARY); // if Primary is busy, ignore CCA for Secondary
}
if (ppdu)
{
const MHz_u primaryWidth{20};
const MHz_u p20MinFreq =
m_wifiPhy->GetOperatingChannel().GetPrimaryChannelCenterFrequency(primaryWidth) -
(primaryWidth / 2);
const MHz_u 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<MHz_u> secondaryWidthsToCheck;
if (ppdu)
{
for (const auto& secondaryChannel : secondaryChannels)
{
const auto secondaryWidth = secondaryChannel.first;
const MHz_u secondaryMinFreq =
m_wifiPhy->GetOperatingChannel().GetSecondaryChannelCenterFrequency(
secondaryWidth) -
(secondaryWidth / 2);
const MHz_u 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);
ccaThreshold = GetCcaThreshold(ppdu, channelType);
delayUntilCcaEnd = GetDelayUntilCcaEnd(ccaThreshold, GetSecondaryBand(secondaryWidth));
if (delayUntilCcaEnd.IsStrictlyPositive())
{
return std::make_pair(delayUntilCcaEnd, channelType);
}
}
return std::nullopt;
return vhtSecondaryChannels;
}
} // namespace ns3

View File

@@ -267,7 +267,7 @@ class VhtPhy : public HtPhy
PhyFieldRxStatus DoEndReceiveField(WifiPpduField field, Ptr<Event> event) override;
bool IsAllConfigSupported(WifiPpduField field, Ptr<const WifiPpdu> ppdu) const override;
uint32_t GetMaxPsduSize() const override;
CcaIndication GetCcaIndication(const Ptr<const WifiPpdu> ppdu) override;
const std::map<MHz_u, WifiChannelListType>& GetCcaSecondaryChannels() const override;
/**
* End receiving the SIG-A or SIG-B, perform VHT-specific actions, and