wifi: Fill Punctured Channel Information field in U-SIG header of EHT MU PPDUs

This commit is contained in:
Sébastien Deronne
2024-09-16 19:05:38 +02:00
parent 4a586f1ca9
commit c6351e5471
2 changed files with 96 additions and 12 deletions

View File

@@ -14,6 +14,7 @@
#include "ns3/wifi-phy-operating-channel.h"
#include "ns3/wifi-psdu.h"
#include <algorithm>
#include <numeric>
namespace ns3
@@ -52,6 +53,13 @@ EhtPpdu::SetEhtPhyHeader(const WifiTxVector& txVector)
.m_bandwidth = GetChannelWidthEncodingFromMhz(txVector.GetChannelWidth()),
.m_bssColor = bssColor,
.m_ppduType = txVector.GetEhtPpduType(),
// TODO: EHT PPDU should store U-SIG per 20 MHz band, assume it is the lowest 20 MHz
// band for now
.m_puncturedChannelInfo = GetPuncturedInfo(
txVector.GetInactiveSubchannels(),
txVector.GetEhtPpduType(),
(txVector.IsDlMu() && (txVector.GetChannelWidth() > 80)) ? std::optional{true}
: std::nullopt),
.m_ehtSigMcs = txVector.GetSigBMode().GetMcsValue(),
.m_giLtfSize = GetGuardIntervalAndNltfEncoding(txVector.GetGuardInterval(),
2 /*NLTF currently unused*/),
@@ -115,9 +123,14 @@ EhtPpdu::SetTxVectorFromPhyHeaders(WifiTxVector& txVector) const
{
auto ehtPhyHeader = std::get_if<EhtMuPhyHeader>(&m_ehtPhyHeader);
NS_ASSERT(ehtPhyHeader);
txVector.SetChannelWidth(GetChannelWidthMhzFromEncoding(ehtPhyHeader->m_bandwidth));
const auto bw = GetChannelWidthMhzFromEncoding(ehtPhyHeader->m_bandwidth);
txVector.SetChannelWidth(bw);
txVector.SetBssColor(ehtPhyHeader->m_bssColor);
txVector.SetEhtPpduType(ehtPhyHeader->m_ppduType);
if (bw > 80)
{
// TODO: use punctured channel information
}
txVector.SetSigBMode(HePhy::GetVhtMcs(ehtPhyHeader->m_ehtSigMcs));
txVector.SetGuardInterval(GetGuardIntervalFromEncoding(ehtPhyHeader->m_giLtfSize));
const auto ruAllocation = ehtPhyHeader->m_ruAllocationA; // RU Allocation-B not supported
@@ -230,6 +243,63 @@ EhtPpdu::GetEhtSigFieldSize(MHz_u channelWidth,
return commonFieldSize + userSpecificFieldSize;
}
uint8_t
EhtPpdu::GetPuncturedInfo(const std::vector<bool>& inactiveSubchannels,
uint8_t ehtPpduType,
std::optional<bool> isLow80MHz)
{
if (inactiveSubchannels.size() < 4)
{
// no puncturing if less than 80 MHz
return 0;
}
NS_ASSERT_MSG(inactiveSubchannels.size() <= 8,
"Puncturing over more than 160 MHz is not supported");
if (ehtPpduType == 0)
{
// IEEE 802.11be D5.0 Table 36-28
NS_ASSERT(inactiveSubchannels.size() <= 4 || isLow80MHz.has_value());
const auto startIndex = (inactiveSubchannels.size() <= 4) ? 0 : (*isLow80MHz ? 0 : 4);
const auto stopIndex =
(inactiveSubchannels.size() <= 4) ? inactiveSubchannels.size() : (*isLow80MHz ? 4 : 8);
uint8_t puncturedInfoField = 0;
for (std::size_t i = startIndex; i < stopIndex; ++i)
{
if (!inactiveSubchannels.at(i))
{
puncturedInfoField |= 1 << (i / 4);
}
}
return puncturedInfoField;
}
// IEEE 802.11be D5.0 Table 36-30
const auto numPunctured = std::count_if(inactiveSubchannels.cbegin(),
inactiveSubchannels.cend(),
[](bool punctured) { return punctured; });
if (numPunctured == 0)
{
// no puncturing
return 0;
}
const auto firstPunctured = std::find_if(inactiveSubchannels.cbegin(),
inactiveSubchannels.cend(),
[](bool punctured) { return punctured; });
const auto firstIndex = std::distance(inactiveSubchannels.cbegin(), firstPunctured);
switch (numPunctured)
{
case 1:
return firstIndex + 1;
case 2:
NS_ASSERT_MSG(((firstIndex % 2) == 0) && inactiveSubchannels.at(firstIndex + 1),
"invalid 40 MHz puncturing pattern");
return 9 + (firstIndex / 2);
default:
break;
}
NS_ASSERT_MSG(false, "invalid puncturing pattern");
return 0;
}
Ptr<WifiPpdu>
EhtPpdu::Copy() const
{

View File

@@ -37,12 +37,11 @@ class EhtPpdu : public HePpdu
struct EhtTbPhyHeader
{
// U-SIG fields
uint8_t m_phyVersionId{0}; ///< PHY Version Identifier field
uint8_t m_bandwidth{0}; ///< Bandwidth field
uint8_t m_bssColor{0}; ///< BSS color field
uint8_t m_ppduType{0}; ///< PPDU Type And Compressed Mode field
}; // struct EhtTbPhyHeader
uint8_t m_phyVersionId : 3 {0}; ///< PHY Version Identifier field
uint8_t m_bandwidth : 3 {0}; ///< Bandwidth field
uint8_t m_bssColor : 6 {0}; ///< BSS color field
uint8_t m_ppduType : 2 {0}; ///< PPDU Type And Compressed Mode field
}; // struct EhtTbPhyHeader
/**
* PHY header for EHT MU PPDUs
@@ -50,11 +49,12 @@ class EhtPpdu : public HePpdu
struct EhtMuPhyHeader
{
// U-SIG fields
uint8_t m_phyVersionId{0}; ///< PHY Version Identifier field
uint8_t m_bandwidth{0}; ///< Bandwidth field
uint8_t m_bssColor{0}; ///< BSS color field
uint8_t m_ppduType{0}; ///< PPDU Type And Compressed Mode field
uint8_t m_ehtSigMcs{0}; ///< EHT-SIG-B MCS
uint8_t m_phyVersionId : 3 {0}; ///< PHY Version Identifier field
uint8_t m_bandwidth : 3 {0}; ///< Bandwidth field
uint8_t m_bssColor : 6 {0}; ///< BSS color field
uint8_t m_ppduType : 2 {0}; ///< PPDU Type And Compressed Mode field
uint8_t m_puncturedChannelInfo : 5 {0}; ///< Punctured Channel Information field
uint8_t m_ehtSigMcs : 2 {0}; ///< EHT-SIG-B MCS
// EHT-SIG fields
uint8_t m_giLtfSize{0}; ///< GI+LTF Size field
@@ -136,6 +136,20 @@ class EhtPpdu : public HePpdu
bool compression,
std::size_t numMuMimoUsers);
/**
* Get the Punctured Channel Information field in the U-SIG
* \param inactiveSubchannels the bitmap indexed by the 20 MHz subchannels in ascending order,
* where each bit indicates whether the corresponding 20 MHz subchannel is punctured or not
* within the transmission bandwidth
* \param ehtPpduType the EHT_PPDU_TYPE used by the PPDU
* \param isLow80MHz flag whether the 80 MHz frequency subblock where U-SIG processing is
* performed is the lowest in frequency (if OFDMA and if channel width is larger than 80 MHz)
* \return the value of the Punctured Channel Information field
*/
static uint8_t GetPuncturedInfo(const std::vector<bool>& inactiveSubchannels,
uint8_t ehtPpduType,
std::optional<bool> isLow80MHz);
private:
bool IsDlMu() const override;
bool IsUlMu() const override;