From c6351e547132a83cd2e04a7ddd85f0adcc76147e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Deronne?= Date: Mon, 16 Sep 2024 19:05:38 +0200 Subject: [PATCH] wifi: Fill Punctured Channel Information field in U-SIG header of EHT MU PPDUs --- src/wifi/model/eht/eht-ppdu.cc | 72 +++++++++++++++++++++++++++++++++- src/wifi/model/eht/eht-ppdu.h | 36 +++++++++++------ 2 files changed, 96 insertions(+), 12 deletions(-) diff --git a/src/wifi/model/eht/eht-ppdu.cc b/src/wifi/model/eht/eht-ppdu.cc index d5ce9cb28..f2fdd323a 100644 --- a/src/wifi/model/eht/eht-ppdu.cc +++ b/src/wifi/model/eht/eht-ppdu.cc @@ -14,6 +14,7 @@ #include "ns3/wifi-phy-operating-channel.h" #include "ns3/wifi-psdu.h" +#include #include 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(&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& inactiveSubchannels, + uint8_t ehtPpduType, + std::optional 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 EhtPpdu::Copy() const { diff --git a/src/wifi/model/eht/eht-ppdu.h b/src/wifi/model/eht/eht-ppdu.h index 50b279bb0..b8b2c518f 100644 --- a/src/wifi/model/eht/eht-ppdu.h +++ b/src/wifi/model/eht/eht-ppdu.h @@ -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& inactiveSubchannels, + uint8_t ehtPpduType, + std::optional isLow80MHz); + private: bool IsDlMu() const override; bool IsUlMu() const override;