wifi: Fill Punctured Channel Information field in U-SIG header of EHT MU PPDUs
This commit is contained in:
@@ -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
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user