A Discrete-Event Network Simulator
API
eht-ppdu.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2021 DERONNE SOFTWARE ENGINEERING
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation;
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program; if not, write to the Free Software
15  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16  *
17  * Author: Sébastien Deronne <sebastien.deronne@gmail.com>
18  */
19 
20 #include "eht-ppdu.h"
21 
22 #include "eht-phy.h"
23 
24 #include "ns3/log.h"
25 #include "ns3/wifi-phy-operating-channel.h"
26 #include "ns3/wifi-psdu.h"
27 
28 #include <numeric>
29 
30 namespace ns3
31 {
32 
33 NS_LOG_COMPONENT_DEFINE("EhtPpdu");
34 
36  const WifiTxVector& txVector,
38  Time ppduDuration,
39  uint64_t uid,
40  TxPsdFlag flag)
41  : HePpdu(psdus, txVector, channel, ppduDuration, uid, flag)
42 {
43  NS_LOG_FUNCTION(this << psdus << txVector << channel << ppduDuration << uid << flag);
44  SetPhyHeaders(txVector, ppduDuration);
45 }
46 
47 void
48 EhtPpdu::SetPhyHeaders(const WifiTxVector& txVector, Time ppduDuration)
49 {
50  NS_LOG_FUNCTION(this << txVector << ppduDuration);
51  SetEhtPhyHeader(txVector);
52 }
53 
54 void
56 {
57  const auto bssColor = txVector.GetBssColor();
58  NS_ASSERT(bssColor < 64);
60  {
61  const auto p20Index = m_operatingChannel.GetPrimaryChannelIndex(20);
64  .m_bssColor = bssColor,
65  .m_ppduType = txVector.GetEhtPpduType(),
66  .m_ehtSigMcs = txVector.GetSigBMode().GetMcsValue(),
67  .m_giLtfSize = GetGuardIntervalAndNltfEncoding(txVector.GetGuardInterval(),
68  2 /*NLTF currently unused*/),
69  /* See section 36.3.12.8.2 of IEEE 802.11be D3.0 (EHT-SIG content channels):
70  * In non-OFDMA transmission, the Common field of the EHT-SIG content channel does not
71  * contain the RU Allocation subfield. For non-OFDMA transmission except for EHT
72  * sounding NDP, the Common field of the EHT-SIG content channel is encoded together
73  * with the first User field and this encoding block contains a CRC and Tail, referred
74  * to as a common encoding block. */
75  .m_ruAllocationA =
76  txVector.IsMu() ? std::optional{txVector.GetRuAllocation(p20Index)} : std::nullopt,
77  // TODO: RU Allocation-B not supported yet
78  .m_contentChannels = GetEhtSigContentChannels(txVector, p20Index)});
79  }
80  else if (ns3::IsUlMu(m_preamble))
81  {
84  .m_bssColor = bssColor,
85  .m_ppduType = txVector.GetEhtPpduType()});
86  }
87 }
88 
91 {
92  if (m_psdus.count(SU_STA_ID) > 0)
93  {
94  return WIFI_PPDU_TYPE_SU;
95  }
96  switch (m_preamble)
97  {
99  return WIFI_PPDU_TYPE_DL_MU;
101  return WIFI_PPDU_TYPE_UL_MU;
102  default:
103  NS_ASSERT_MSG(false, "invalid preamble " << m_preamble);
104  return WIFI_PPDU_TYPE_SU;
105  }
106 }
107 
108 bool
110 {
111  return (m_preamble == WIFI_PREAMBLE_EHT_MU) && (m_psdus.count(SU_STA_ID) == 0);
112 }
113 
114 bool
116 {
117  return (m_preamble == WIFI_PREAMBLE_EHT_TB) && (m_psdus.count(SU_STA_ID) == 0);
118 }
119 
120 void
122 {
123  txVector.SetLength(m_lSig.GetLength());
124  txVector.SetAggregation(m_psdus.size() > 1 || m_psdus.begin()->second->IsAggregate());
125  if (ns3::IsDlMu(m_preamble))
126  {
127  auto ehtPhyHeader = std::get_if<EhtMuPhyHeader>(&m_ehtPhyHeader);
128  NS_ASSERT(ehtPhyHeader);
129  txVector.SetChannelWidth(GetChannelWidthMhzFromEncoding(ehtPhyHeader->m_bandwidth));
130  txVector.SetBssColor(ehtPhyHeader->m_bssColor);
131  txVector.SetEhtPpduType(ehtPhyHeader->m_ppduType);
132  txVector.SetSigBMode(HePhy::GetVhtMcs(ehtPhyHeader->m_ehtSigMcs));
133  txVector.SetGuardInterval(GetGuardIntervalFromEncoding(ehtPhyHeader->m_giLtfSize));
134  const auto ruAllocation = ehtPhyHeader->m_ruAllocationA; // RU Allocation-B not supported
135  // yet
136  if (const auto p20Index = m_operatingChannel.GetPrimaryChannelIndex(20);
137  ruAllocation.has_value())
138  {
139  txVector.SetRuAllocation(ruAllocation.value(), p20Index);
140  const auto isMuMimo = (ehtPhyHeader->m_ppduType == 2);
141  const auto muMimoUsers =
142  isMuMimo
143  ? std::accumulate(ehtPhyHeader->m_contentChannels.cbegin(),
144  ehtPhyHeader->m_contentChannels.cend(),
145  0,
146  [](uint8_t prev, const auto& cc) { return prev + cc.size(); })
147  : 0;
148  SetHeMuUserInfos(txVector,
149  ruAllocation.value(),
150  ehtPhyHeader->m_contentChannels,
151  ehtPhyHeader->m_ppduType == 2,
152  muMimoUsers);
153  }
154  if (ehtPhyHeader->m_ppduType == 1) // EHT SU
155  {
156  NS_ASSERT(ehtPhyHeader->m_contentChannels.size() == 1 &&
157  ehtPhyHeader->m_contentChannels.front().size() == 1);
158  txVector.SetMode(
159  EhtPhy::GetEhtMcs(ehtPhyHeader->m_contentChannels.front().front().mcs));
160  txVector.SetNss(ehtPhyHeader->m_contentChannels.front().front().nss);
161  }
162  }
163  else if (ns3::IsUlMu(m_preamble))
164  {
165  auto ehtPhyHeader = std::get_if<EhtTbPhyHeader>(&m_ehtPhyHeader);
166  NS_ASSERT(ehtPhyHeader);
167  txVector.SetChannelWidth(GetChannelWidthMhzFromEncoding(ehtPhyHeader->m_bandwidth));
168  txVector.SetBssColor(ehtPhyHeader->m_bssColor);
169  txVector.SetEhtPpduType(ehtPhyHeader->m_ppduType);
170  }
171 }
172 
173 std::pair<std::size_t, std::size_t>
175  uint8_t ehtPpduType,
176  const RuAllocation& ruAllocation,
177  bool compression,
178  std::size_t numMuMimoUsers)
179 {
180  if (ehtPpduType == 1)
181  {
182  return {1, 0};
183  }
184  return HePpdu::GetNumRusPerHeSigBContentChannel(channelWidth,
185  ruAllocation,
186  compression,
187  numMuMimoUsers);
188 }
189 
191 EhtPpdu::GetEhtSigContentChannels(const WifiTxVector& txVector, uint8_t p20Index)
192 {
193  if (txVector.GetEhtPpduType() == 1)
194  {
195  // according to spec the TXVECTOR shall have a correct STA-ID even for SU transmission,
196  // but this is not set by the MAC for simplification, so set to 0 for now.
197  return HeSigBContentChannels{{{0, txVector.GetNss(), txVector.GetMode().GetMcsValue()}}};
198  }
199  return HePpdu::GetHeSigBContentChannels(txVector, p20Index);
200 }
201 
202 uint32_t
203 EhtPpdu::GetEhtSigFieldSize(uint16_t channelWidth,
204  const RuAllocation& ruAllocation,
205  uint8_t ehtPpduType,
206  bool compression,
207  std::size_t numMuMimoUsers)
208 {
209  // FIXME: EHT-SIG is not implemented yet, hence this is a copy of HE-SIG-B
210  uint32_t commonFieldSize = 0;
211  if (!compression)
212  {
213  commonFieldSize = 4 /* CRC */ + 6 /* tail */;
214  if (channelWidth <= 40)
215  {
216  commonFieldSize += 8; // only one allocation subfield
217  }
218  else
219  {
220  commonFieldSize +=
221  8 * (channelWidth / 40) /* one allocation field per 40 MHz */ + 1 /* center RU */;
222  }
223  }
224 
225  auto numRusPerContentChannel = GetNumRusPerEhtSigBContentChannel(channelWidth,
226  ehtPpduType,
227  ruAllocation,
228  compression,
229  numMuMimoUsers);
230  auto maxNumRusPerContentChannel =
231  std::max(numRusPerContentChannel.first, numRusPerContentChannel.second);
232  auto maxNumUserBlockFields = maxNumRusPerContentChannel /
233  2; // handle last user block with single user, if any, further down
234  std::size_t userSpecificFieldSize =
235  maxNumUserBlockFields * (2 * 21 /* user fields (2 users) */ + 4 /* tail */ + 6 /* CRC */);
236  if (maxNumRusPerContentChannel % 2 != 0)
237  {
238  userSpecificFieldSize += 21 /* last user field */ + 4 /* CRC */ + 6 /* tail */;
239  }
240 
241  return commonFieldSize + userSpecificFieldSize;
242 }
243 
246 {
247  return Ptr<WifiPpdu>(new EhtPpdu(*this), false);
248 }
249 
250 } // namespace ns3
#define max(a, b)
Definition: 80211b.c:42
static WifiMode GetEhtMcs(uint8_t index)
Return the EHT MCS corresponding to the provided index.
Definition: eht-phy.cc:240
static std::pair< std::size_t, std::size_t > GetNumRusPerEhtSigBContentChannel(uint16_t channelWidth, uint8_t ehtPpduType, const std::vector< uint8_t > &ruAllocation, bool compression, std::size_t numMuMimoUsers)
Get the number of RUs per EHT-SIG-B content channel.
Definition: eht-ppdu.cc:174
static HeSigBContentChannels GetEhtSigContentChannels(const WifiTxVector &txVector, uint8_t p20Index)
Get the EHT-SIG content channels for a given PPDU IEEE 802.11be-D3.1 36.3.12.8.2 EHT-SIG content chan...
Definition: eht-ppdu.cc:191
bool IsDlMu() const override
Return true if the PPDU is a DL MU PPDU.
Definition: eht-ppdu.cc:109
static uint32_t GetEhtSigFieldSize(uint16_t channelWidth, const std::vector< uint8_t > &ruAllocation, uint8_t ehtPpduType, bool compression, std::size_t numMuMimoUsers)
Get variable length EHT-SIG field size.
Definition: eht-ppdu.cc:203
bool IsUlMu() const override
Return true if the PPDU is an UL MU PPDU.
Definition: eht-ppdu.cc:115
void SetEhtPhyHeader(const WifiTxVector &txVector)
Fill in the EHT PHY header.
Definition: eht-ppdu.cc:55
Ptr< WifiPpdu > Copy() const override
Copy this instance.
Definition: eht-ppdu.cc:245
void SetTxVectorFromPhyHeaders(WifiTxVector &txVector) const override
Fill in the TXVECTOR from PHY headers.
Definition: eht-ppdu.cc:121
void SetPhyHeaders(const WifiTxVector &txVector, Time ppduDuration)
Fill in the PHY headers.
Definition: eht-ppdu.cc:48
WifiPpduType GetType() const override
Return the PPDU type (.
Definition: eht-ppdu.cc:90
EhtPhyHeader m_ehtPhyHeader
the EHT PHY header
Definition: eht-ppdu.h:170
EhtPpdu(const WifiConstPsduMap &psdus, const WifiTxVector &txVector, const WifiPhyOperatingChannel &channel, Time ppduDuration, uint64_t uid, TxPsdFlag flag)
Create an EHT PPDU, storing a map of PSDUs.
Definition: eht-ppdu.cc:35
HE PPDU (11ax)
Definition: he-ppdu.h:50
std::vector< std::vector< HeSigBUserSpecificField > > HeSigBContentChannels
HE SIG-B Content Channels.
Definition: he-ppdu.h:61
static uint16_t GetGuardIntervalFromEncoding(uint8_t giAndNltfSize)
Convert guard interval (in ns) from its encoding in HE-SIG-A.
Definition: he-ppdu.cc:758
static uint16_t GetChannelWidthMhzFromEncoding(uint8_t bandwidth)
Convert channel width expressed in MHz from bandwidth field encoding in HE-SIG-A.
Definition: he-ppdu.cc:716
TxPsdFlag
The transmit power spectral density flag, namely used to correctly build PSDs for pre-HE and HE porti...
Definition: he-ppdu.h:115
static std::pair< std::size_t, std::size_t > GetNumRusPerHeSigBContentChannel(uint16_t channelWidth, const RuAllocation &ruAllocation, bool sigBCompression, uint8_t numMuMimoUsers)
Get the number of STAs per HE-SIG-B content channel.
Definition: he-ppdu.cc:486
static HeSigBContentChannels GetHeSigBContentChannels(const WifiTxVector &txVector, uint8_t p20Index)
Get the HE SIG-B content channels for a given PPDU IEEE 802.11ax-2021 27.3.11.8.2 HE-SIG-B content ch...
Definition: he-ppdu.cc:554
void SetHeMuUserInfos(WifiTxVector &txVector, const RuAllocation &ruAllocation, const HeSigBContentChannels &contentChannels, bool sigBCompression, uint8_t numMuMimoUsers) const
Reconstruct HeMuUserInfoMap from HE-SIG-B header.
Definition: he-ppdu.cc:225
static uint8_t GetGuardIntervalAndNltfEncoding(uint16_t gi, uint8_t nltf)
Convert guard interval (in ns) and NLTF to its encoding in HE-SIG-A.
Definition: he-ppdu.cc:737
static uint8_t GetChannelWidthEncodingFromMhz(uint16_t channelWidth)
Convert channel width expressed in MHz to bandwidth field encoding in HE-SIG-A.
Definition: he-ppdu.cc:695
uint16_t GetLength() const
Return the LENGTH field of L-SIG (in bytes).
Definition: ofdm-ppdu.cc:210
LSigHeader m_lSig
the L-SIG PHY header
Definition: ofdm-ppdu.h:110
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:77
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:105
static WifiMode GetVhtMcs(uint8_t index)
Return the VHT MCS corresponding to the provided index.
Definition: vht-phy.cc:342
uint8_t GetMcsValue() const
Definition: wifi-mode.cc:163
Class that keeps track of all information about the current PHY operating channel.
uint8_t GetPrimaryChannelIndex(uint16_t primaryChannelWidth) const
If the operating channel width is a multiple of 20 MHz, return the index of the primary channel of th...
const WifiPhyOperatingChannel & m_operatingChannel
the operating channel of the PHY
Definition: wifi-ppdu.h:210
WifiPreamble m_preamble
the PHY preamble
Definition: wifi-ppdu.h:202
WifiConstPsduMap m_psdus
the PSDUs contained in this PPDU
Definition: wifi-ppdu.h:204
This class mimics the TXVECTOR which is to be passed to the PHY in order to define the parameters whi...
void SetRuAllocation(const RuAllocation &ruAlloc, uint8_t p20Index)
Set RU_ALLOCATION field.
void SetEhtPpduType(uint8_t type)
Set the EHT_PPDU_TYPE parameter.
uint16_t GetGuardInterval() const
void SetChannelWidth(uint16_t channelWidth)
Sets the selected channelWidth (in MHz)
uint8_t GetBssColor() const
Get the BSS color.
const RuAllocation & GetRuAllocation(uint8_t p20Index) const
Get RU_ALLOCATION field.
void SetGuardInterval(uint16_t guardInterval)
Sets the guard interval duration (in nanoseconds)
WifiMode GetMode(uint16_t staId=SU_STA_ID) const
If this TX vector is associated with an SU PPDU, return the selected payload transmission mode.
void SetAggregation(bool aggregation)
Sets if PSDU contains A-MPDU.
uint8_t GetEhtPpduType() const
Get the EHT_PPDU_TYPE parameter.
uint8_t GetNss(uint16_t staId=SU_STA_ID) const
If this TX vector is associated with an SU PPDU, return the number of spatial streams.
void SetLength(uint16_t length)
Set the LENGTH field of the L-SIG.
void SetSigBMode(const WifiMode &mode)
Set the MCS used for SIG-B.
void SetBssColor(uint8_t color)
Set the BSS color.
uint16_t GetChannelWidth() const
void SetMode(WifiMode mode)
Sets the selected payload transmission mode.
WifiMode GetSigBMode() const
Get MCS used for SIG-B.
void SetNss(uint8_t nss)
Sets the number of Nss.
Declaration of ns3::EhtPhy class.
Declaration of ns3::EhtPpdu class.
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition: assert.h:66
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
Definition: assert.h:86
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:202
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
WifiPpduType
The type of PPDU (SU, DL MU, or UL MU)
@ WIFI_PREAMBLE_EHT_TB
@ WIFI_PREAMBLE_EHT_MU
@ WIFI_PPDU_TYPE_DL_MU
@ WIFI_PPDU_TYPE_UL_MU
@ WIFI_PPDU_TYPE_SU
Every class exported by the ns3 library is enclosed in the ns3 namespace.
std::unordered_map< uint16_t, Ptr< const WifiPsdu > > WifiConstPsduMap
Map of const PSDUs indexed by STA-ID.
std::vector< uint8_t > RuAllocation
8 bit RU_ALLOCATION per 20 MHz
bool IsDlMu(WifiPreamble preamble)
Return true if a preamble corresponds to a downlink multi-user transmission.
static constexpr uint16_t SU_STA_ID
STA_ID to identify a single user (SU)
Definition: wifi-mode.h:35
bool IsUlMu(WifiPreamble preamble)
Return true if a preamble corresponds to a uplink multi-user transmission.
channel
Definition: third.py:88
PHY header for EHT MU PPDUs.
Definition: eht-ppdu.h:62
uint8_t m_bandwidth
Bandwidth field.
Definition: eht-ppdu.h:65
PHY header for EHT TB PPDUs.
Definition: eht-ppdu.h:49
uint8_t m_bandwidth
Bandwidth field.
Definition: eht-ppdu.h:52
uint32_t prev