1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3 * Copyright (c) 2020 Orange Labs
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation;
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 *
18 * Authors: Rediet <getachew.redieteab@orange.com>
19 * Sébastien Deronne <sebastien.deronne@gmail.com> (for logic ported from wifi-phy and spectrum-wifi-phy)
20 */
21
22 #include "he-phy.h"
23 #include "he-ppdu.h"
24 #include "ns3/wifi-psdu.h"
25 #include "ns3/wifi-phy.h"
26 #include "he-configuration.h"
27 #include "ns3/wifi-net-device.h"
28 #include "ns3/sta-wifi-mac.h"
29 #include "ns3/ap-wifi-mac.h"
30 #include "ns3/wifi-utils.h"
31 #include "ns3/simulator.h"
32 #include "ns3/log.h"
33 #include "ns3/assert.h"
34 #include <algorithm>
35
36 namespace ns3 {
37
38 NS_LOG_COMPONENT_DEFINE ("HePhy");
39
40 /*******************************************************
41 * HE PHY (P802.11ax/D4.0, clause 27)
42 *******************************************************/
43
44 /* *NS_CHECK_STYLE_OFF* */
45 const PhyEntity::PpduFormats HePhy::m_hePpduFormats { //Ignoring PE (Packet Extension)
46 { WIFI_PREAMBLE_HE_SU, { WIFI_PPDU_FIELD_PREAMBLE, //L-STF + L-LTF
47 WIFI_PPDU_FIELD_NON_HT_HEADER, //L-SIG + RL-SIG
48 WIFI_PPDU_FIELD_SIG_A, //HE-SIG-A
49 WIFI_PPDU_FIELD_TRAINING, //HE-STF + HE-LTFs
50 WIFI_PPDU_FIELD_DATA } },
51 { WIFI_PREAMBLE_HE_MU, { WIFI_PPDU_FIELD_PREAMBLE, //L-STF + L-LTF
52 WIFI_PPDU_FIELD_NON_HT_HEADER, //L-SIG + RL-SIG
53 WIFI_PPDU_FIELD_SIG_A, //HE-SIG-A
54 WIFI_PPDU_FIELD_SIG_B, //HE-SIG-B
55 WIFI_PPDU_FIELD_TRAINING, //HE-STF + HE-LTFs
56 WIFI_PPDU_FIELD_DATA } },
57 { WIFI_PREAMBLE_HE_TB, { WIFI_PPDU_FIELD_PREAMBLE, //L-STF + L-LTF
58 WIFI_PPDU_FIELD_NON_HT_HEADER, //L-SIG + RL-SIG
59 WIFI_PPDU_FIELD_SIG_A, //HE-SIG-A
60 WIFI_PPDU_FIELD_TRAINING, //HE-STF + HE-LTFs
61 WIFI_PPDU_FIELD_DATA } },
62 { WIFI_PREAMBLE_HE_ER_SU, { WIFI_PPDU_FIELD_PREAMBLE, //L-STF + L-LTF
63 WIFI_PPDU_FIELD_NON_HT_HEADER, //L-SIG + RL-SIG
64 WIFI_PPDU_FIELD_SIG_A, //HE-SIG-A
65 WIFI_PPDU_FIELD_TRAINING, //HE-STF + HE-LTFs
66 WIFI_PPDU_FIELD_DATA } }
67 };
68 /* *NS_CHECK_STYLE_ON* */
69
HePhy(bool buildModeList)70 HePhy::HePhy (bool buildModeList /* = true */)
71 : VhtPhy (false) //don't add VHT modes to list
72 {
73 NS_LOG_FUNCTION (this << buildModeList);
74 m_bssMembershipSelector = HE_PHY;
75 m_maxMcsIndexPerSs = 11;
76 m_maxSupportedMcsIndexPerSs = m_maxMcsIndexPerSs;
77 m_currentHeTbPpduUid = UINT64_MAX;
78 m_previouslyTxPpduUid = UINT64_MAX;
79 if (buildModeList)
80 {
81 BuildModeList ();
82 }
83 }
84
~HePhy()85 HePhy::~HePhy ()
86 {
87 NS_LOG_FUNCTION (this);
88 }
89
90 void
BuildModeList(void)91 HePhy::BuildModeList (void)
92 {
93 NS_LOG_FUNCTION (this);
94 NS_ASSERT (m_modeList.empty ());
95 NS_ASSERT (m_bssMembershipSelector == HE_PHY);
96 for (uint8_t index = 0; index <= m_maxSupportedMcsIndexPerSs; ++index)
97 {
98 NS_LOG_LOGIC ("Add HeMcs" << +index << " to list");
99 m_modeList.emplace_back (CreateHeMcs (index));
100 }
101 }
102
103 WifiMode
GetSigMode(WifiPpduField field,const WifiTxVector & txVector) const104 HePhy::GetSigMode (WifiPpduField field, const WifiTxVector& txVector) const
105 {
106 switch (field)
107 {
108 case WIFI_PPDU_FIELD_TRAINING: //consider SIG-A (SIG-B) mode for training for the time being for SU/ER-SU/TB (MU) (useful for InterferenceHelper)
109 if (txVector.IsDlMu ())
110 {
111 NS_ASSERT (txVector.GetModulationClass () == WIFI_MOD_CLASS_HE);
112 //Training comes after SIG-B
113 return GetSigBMode (txVector);
114 }
115 else
116 {
117 //Training comes after SIG-A
118 return GetSigAMode ();
119 }
120 default:
121 return VhtPhy::GetSigMode (field, txVector);
122 }
123 }
124
125 WifiMode
GetSigAMode(void) const126 HePhy::GetSigAMode (void) const
127 {
128 return GetVhtMcs0 (); //same number of data tones as VHT for 20 MHz (i.e. 52)
129 }
130
131 WifiMode
GetSigBMode(const WifiTxVector & txVector) const132 HePhy::GetSigBMode (const WifiTxVector& txVector) const
133 {
134 NS_ABORT_MSG_IF (!txVector.IsDlMu () || (txVector.GetModulationClass () != WIFI_MOD_CLASS_HE), "HE-SIG-B only available for HE MU");
135 /**
136 * Get smallest HE MCS index among station's allocations and use the
137 * VHT version of the index. This enables to have 800 ns GI, 52 data
138 * tones, and 312.5 kHz spacing while ensuring that MCS will be decoded
139 * by all stations.
140 */
141 uint8_t smallestMcs = 5; //maximum MCS for HE-SIG-B
142 for (auto & info : txVector.GetHeMuUserInfoMap ())
143 {
144 smallestMcs = std::min (smallestMcs, info.second.mcs.GetMcsValue ());
145 }
146 switch (smallestMcs) //GetVhtMcs (mcs) is not static
147 {
148 case 0:
149 return GetVhtMcs0 ();
150 case 1:
151 return GetVhtMcs1 ();
152 case 2:
153 return GetVhtMcs2 ();
154 case 3:
155 return GetVhtMcs3 ();
156 case 4:
157 return GetVhtMcs4 ();
158 case 5:
159 default:
160 return GetVhtMcs5 ();
161 }
162 }
163
164 const PhyEntity::PpduFormats &
GetPpduFormats(void) const165 HePhy::GetPpduFormats (void) const
166 {
167 return m_hePpduFormats;
168 }
169
170 Time
GetLSigDuration(WifiPreamble) const171 HePhy::GetLSigDuration (WifiPreamble /* preamble */) const
172 {
173 return MicroSeconds (8); //L-SIG + RL-SIG
174 }
175
176 Time
GetTrainingDuration(const WifiTxVector & txVector,uint8_t nDataLtf,uint8_t nExtensionLtf) const177 HePhy::GetTrainingDuration (const WifiTxVector& txVector,
178 uint8_t nDataLtf, uint8_t nExtensionLtf /* = 0 */) const
179 {
180 Time ltfDuration = MicroSeconds (8); //TODO extract from TxVector when available
181 Time stfDuration;
182 if (txVector.IsUlMu ())
183 {
184 NS_ASSERT (txVector.GetModulationClass () == WIFI_MOD_CLASS_HE);
185 stfDuration = MicroSeconds (8);
186 }
187 else
188 {
189 stfDuration = MicroSeconds (4);
190 }
191 NS_ABORT_MSG_IF (nDataLtf > 8, "Unsupported number of LTFs " << +nDataLtf << " for HE");
192 NS_ABORT_MSG_IF (nExtensionLtf > 0, "No extension LTFs expected for HE");
193 return stfDuration + ltfDuration * nDataLtf; //HE-STF + HE-LTFs
194 }
195
196 Time
GetSigADuration(WifiPreamble preamble) const197 HePhy::GetSigADuration (WifiPreamble preamble) const
198 {
199 return (preamble == WIFI_PREAMBLE_HE_ER_SU) ? MicroSeconds (16) : MicroSeconds (8); //HE-SIG-A (first and second symbol)
200 }
201
202 Time
GetSigBDuration(const WifiTxVector & txVector) const203 HePhy::GetSigBDuration (const WifiTxVector& txVector) const
204 {
205 if (txVector.IsDlMu ()) //See section 27.3.10.8 of IEEE 802.11ax draft 4.0.
206 {
207 NS_ASSERT (txVector.GetModulationClass () == WIFI_MOD_CLASS_HE);
208 /*
209 * Compute the number of bits used by common field.
210 * Assume that compression bit in HE-SIG-A is not set (i.e. not
211 * full band MU-MIMO); the field is present.
212 */
213 uint16_t bw = txVector.GetChannelWidth ();
214 std::size_t commonFieldSize = 4 /* CRC */ + 6 /* tail */;
215 if (bw <= 40)
216 {
217 commonFieldSize += 8; //only one allocation subfield
218 }
219 else
220 {
221 commonFieldSize += 8 * (bw / 40) /* one allocation field per 40 MHz */ + 1 /* center RU */;
222 }
223
224 /*
225 * Compute the number of bits used by user-specific field.
226 * MU-MIMO is not supported; only one station per RU.
227 * The user-specific field is composed of N user block fields
228 * spread over each corresponding HE-SIG-B content channel.
229 * Each user block field contains either two or one users' data
230 * (the latter being for odd number of stations per content channel).
231 * Padding will be handled further down in the code.
232 */
233 std::pair<std::size_t, std::size_t> numStaPerContentChannel = txVector.GetNumRusPerHeSigBContentChannel ();
234 std::size_t maxNumStaPerContentChannel = std::max (numStaPerContentChannel.first, numStaPerContentChannel.second);
235 std::size_t maxNumUserBlockFields = maxNumStaPerContentChannel / 2; //handle last user block with single user, if any, further down
236 std::size_t userSpecificFieldSize = maxNumUserBlockFields * (2 * 21 /* user fields (2 users) */ + 4 /* tail */ + 6 /* CRC */);
237 if (maxNumStaPerContentChannel % 2 != 0)
238 {
239 userSpecificFieldSize += 21 /* last user field */ + 4 /* CRC */ + 6 /* tail */;
240 }
241
242 /*
243 * Compute duration of HE-SIG-B considering that padding
244 * is added up to the next OFDM symbol.
245 * Nss = 1 and GI = 800 ns for HE-SIG-B.
246 */
247 Time symbolDuration = MicroSeconds (4);
248 double numDataBitsPerSymbol = GetSigBMode (txVector).GetDataRate (20, 800, 1) * symbolDuration.GetNanoSeconds () / 1e9;
249 double numSymbols = ceil ((commonFieldSize + userSpecificFieldSize) / numDataBitsPerSymbol);
250
251 return FemtoSeconds (static_cast<uint64_t> (numSymbols * symbolDuration.GetFemtoSeconds ()));
252 }
253 else
254 {
255 // no SIG-B
256 return MicroSeconds (0);
257 }
258 }
259
260 uint16_t
ConvertHeTbPpduDurationToLSigLength(Time ppduDuration,WifiPhyBand band)261 HePhy::ConvertHeTbPpduDurationToLSigLength (Time ppduDuration, WifiPhyBand band)
262 {
263 uint8_t sigExtension = 0;
264 if (band == WIFI_PHY_BAND_2_4GHZ)
265 {
266 sigExtension = 6;
267 }
268 uint8_t m = 2; //HE TB PPDU so m is set to 2
269 uint16_t length = ((ceil ((static_cast<double> (ppduDuration.GetNanoSeconds () - (20 * 1000) - (sigExtension * 1000)) / 1000) / 4.0) * 3) - 3 - m);
270 return length;
271 }
272
273 Time
ConvertLSigLengthToHeTbPpduDuration(uint16_t length,const WifiTxVector & txVector,WifiPhyBand band)274 HePhy::ConvertLSigLengthToHeTbPpduDuration (uint16_t length, const WifiTxVector& txVector, WifiPhyBand band)
275 {
276 NS_ABORT_IF (!txVector.IsUlMu () || (txVector.GetModulationClass () != WIFI_MOD_CLASS_HE));
277 Time tSymbol = NanoSeconds (12800 + txVector.GetGuardInterval ());
278 Time preambleDuration = WifiPhy::GetStaticPhyEntity (WIFI_MOD_CLASS_HE)->CalculatePhyPreambleAndHeaderDuration (txVector); //this is quite convoluted but only way of keeping the method static
279 uint8_t sigExtension = 0;
280 if (band == WIFI_PHY_BAND_2_4GHZ)
281 {
282 sigExtension = 6;
283 }
284 uint8_t m = 2; //HE TB PPDU so m is set to 2
285 //Equation 27-11 of IEEE P802.11ax/D4.0
286 Time calculatedDuration = MicroSeconds (((ceil (static_cast<double> (length + 3 + m) / 3)) * 4) + 20 + sigExtension);
287 uint32_t nSymbols = floor (static_cast<double> ((calculatedDuration - preambleDuration).GetNanoSeconds () - (sigExtension * 1000)) / tSymbol.GetNanoSeconds ());
288 Time ppduDuration = preambleDuration + (nSymbols * tSymbol) + MicroSeconds (sigExtension);
289 return ppduDuration;
290 }
291
292 Time
CalculateNonOfdmaDurationForHeTb(const WifiTxVector & txVector) const293 HePhy::CalculateNonOfdmaDurationForHeTb (const WifiTxVector& txVector) const
294 {
295 NS_ABORT_IF (!txVector.IsUlMu () || (txVector.GetModulationClass () != WIFI_MOD_CLASS_HE));
296 Time duration = GetDuration (WIFI_PPDU_FIELD_PREAMBLE, txVector)
297 + GetDuration (WIFI_PPDU_FIELD_NON_HT_HEADER, txVector)
298 + GetDuration (WIFI_PPDU_FIELD_SIG_A, txVector);
299 return duration;
300 }
301
302 uint8_t
GetNumberBccEncoders(const WifiTxVector &) const303 HePhy::GetNumberBccEncoders (const WifiTxVector& /* txVector */) const
304 {
305 return 1; //only 1 BCC encoder for HE since higher rates are obtained using LDPC
306 }
307
308 Time
GetSymbolDuration(const WifiTxVector & txVector) const309 HePhy::GetSymbolDuration (const WifiTxVector& txVector) const
310 {
311 uint16_t gi = txVector.GetGuardInterval ();
312 NS_ASSERT (gi == 800 || gi == 1600 || gi == 3200);
313 return NanoSeconds (12800 + gi);
314 }
315
316 Ptr<WifiPpdu>
BuildPpdu(const WifiConstPsduMap & psdus,const WifiTxVector & txVector,Time ppduDuration)317 HePhy::BuildPpdu (const WifiConstPsduMap & psdus, const WifiTxVector& txVector, Time ppduDuration)
318 {
319 NS_LOG_FUNCTION (this << psdus << txVector << ppduDuration);
320 HePpdu::TxPsdFlag flag;
321 if (txVector.IsUlMu ())
322 {
323 NS_ASSERT (txVector.GetModulationClass () == WIFI_MOD_CLASS_HE);
324 flag = HePpdu::PSD_HE_TB_NON_OFDMA_PORTION;
325 }
326 else
327 {
328 flag = HePpdu::PSD_NON_HE_TB;
329 }
330 return Create<HePpdu> (psdus, txVector, ppduDuration, m_wifiPhy->GetPhyBand (),
331 ObtainNextUid (txVector), flag);
332 }
333
334 void
StartReceivePreamble(Ptr<WifiPpdu> ppdu,RxPowerWattPerChannelBand & rxPowersW,Time rxDuration)335 HePhy::StartReceivePreamble (Ptr<WifiPpdu> ppdu, RxPowerWattPerChannelBand& rxPowersW,
336 Time rxDuration)
337 {
338 NS_LOG_FUNCTION (this << ppdu << rxDuration);
339 const WifiTxVector& txVector = ppdu->GetTxVector ();
340 auto hePpdu = DynamicCast<HePpdu> (ppdu);
341 NS_ASSERT (hePpdu);
342 HePpdu::TxPsdFlag psdFlag = hePpdu->GetTxPsdFlag ();
343 if (txVector.IsUlMu () && psdFlag == HePpdu::PSD_HE_TB_OFDMA_PORTION)
344 {
345 NS_ASSERT (txVector.GetModulationClass () == WIFI_MOD_CLASS_HE);
346 if (m_currentHeTbPpduUid == ppdu->GetUid ()
347 && GetCurrentEvent () != 0)
348 {
349 //AP or STA has already received non-OFDMA part, switch to OFDMA part, and schedule reception of payload (will be canceled for STAs by StartPayload)
350 bool ofdmaStarted = !m_beginOfdmaPayloadRxEvents.empty ();
351 NS_LOG_INFO ("Switch to OFDMA part (already started? " << (ofdmaStarted ? "Y" : "N") << ") " <<
352 "and schedule OFDMA payload reception in " << GetDuration (WIFI_PPDU_FIELD_TRAINING, txVector).As (Time::NS));
353 Ptr<Event> event = CreateInterferenceEvent (ppdu, txVector, rxDuration, rxPowersW, !ofdmaStarted);
354 uint16_t staId = GetStaId (ppdu);
355 NS_ASSERT (m_beginOfdmaPayloadRxEvents.find (staId) == m_beginOfdmaPayloadRxEvents.end ());
356 m_beginOfdmaPayloadRxEvents[staId] = Simulator::Schedule (GetDuration (WIFI_PPDU_FIELD_TRAINING, txVector),
357 &HePhy::StartReceiveOfdmaPayload, this, event);
358 }
359 else
360 {
361 //PHY receives the OFDMA payload while having dropped the preamble
362 NS_LOG_INFO ("Consider OFDMA part of the HE TB PPDU as interference since device dropped the preamble");
363 CreateInterferenceEvent (ppdu, txVector, rxDuration, rxPowersW);
364 //the OFDMA part of the HE TB PPDUs will be noise _after_ the completion of the current event
365 ErasePreambleEvent (ppdu, rxDuration);
366 }
367 }
368 else
369 {
370 PhyEntity::StartReceivePreamble (ppdu, rxPowersW, rxDuration);
371 }
372 }
373
374 void
CancelAllEvents(void)375 HePhy::CancelAllEvents (void)
376 {
377 NS_LOG_FUNCTION (this);
378 for (auto & beginOfdmaPayloadRxEvent : m_beginOfdmaPayloadRxEvents)
379 {
380 beginOfdmaPayloadRxEvent.second.Cancel ();
381 }
382 m_beginOfdmaPayloadRxEvents.clear ();
383 PhyEntity::CancelAllEvents ();
384 }
385
386 void
DoAbortCurrentReception(WifiPhyRxfailureReason reason)387 HePhy::DoAbortCurrentReception (WifiPhyRxfailureReason reason)
388 {
389 NS_LOG_FUNCTION (this << reason);
390 if (reason != OBSS_PD_CCA_RESET)
391 {
392 for (auto & endMpduEvent : m_endOfMpduEvents)
393 {
394 endMpduEvent.Cancel ();
395 }
396 m_endOfMpduEvents.clear ();
397 }
398 else
399 {
400 PhyEntity::DoAbortCurrentReception (reason);
401 }
402 }
403
404 void
DoResetReceive(Ptr<Event> event)405 HePhy::DoResetReceive (Ptr<Event> event)
406 {
407 NS_LOG_FUNCTION (this << *event);
408 if (event->GetPpdu ()->GetType () != WIFI_PPDU_TYPE_UL_MU)
409 {
410 NS_ASSERT (event->GetEndTime () == Simulator::Now ());
411 }
412 for (auto & beginOfdmaPayloadRxEvent : m_beginOfdmaPayloadRxEvents)
413 {
414 beginOfdmaPayloadRxEvent.second.Cancel ();
415 }
416 m_beginOfdmaPayloadRxEvents.clear ();
417 }
418
419 Ptr<Event>
DoGetEvent(Ptr<const WifiPpdu> ppdu,RxPowerWattPerChannelBand & rxPowersW)420 HePhy::DoGetEvent (Ptr<const WifiPpdu> ppdu, RxPowerWattPerChannelBand& rxPowersW)
421 {
422 Ptr<Event> event;
423 //We store all incoming preamble events, and a decision is made at the end of the preamble detection window.
424 //If a preamble is received after the preamble detection window, it is stored anyway because this is needed for HE TB PPDUs in
425 //order to properly update the received power in InterferenceHelper. The map is cleaned anyway at the end of the current reception.
426 if (ppdu->GetType () == WIFI_PPDU_TYPE_UL_MU)
427 {
428 auto uidPreamblePair = std::make_pair (ppdu->GetUid (), ppdu->GetPreamble ());
429 const WifiTxVector& txVector = ppdu->GetTxVector ();
430 Time rxDuration = CalculateNonOfdmaDurationForHeTb (txVector); //the OFDMA part of the transmission will be added later on
431 const auto & currentPreambleEvents = GetCurrentPreambleEvents ();
432 auto it = currentPreambleEvents.find (uidPreamblePair);
433 if (it != currentPreambleEvents.end ())
434 {
435 NS_LOG_DEBUG ("Received another HE TB PPDU for UID " << ppdu->GetUid () << " from STA-ID " << ppdu->GetStaId () << " and BSS color " << +txVector.GetBssColor ());
436 event = it->second;
437 if (Simulator::Now () - event->GetStartTime () > NanoSeconds (400))
438 {
439 //Section 27.3.14.3 from 802.11ax Draft 4.0: Pre-correction accuracy requirements.
440 //A STA that transmits an HE TB PPDU, non-HT PPDU, or non-HT duplicate PPDU in response to a triggering PPDU
441 //shall ensure that the transmission start time of the HE TB PPDU, non-HT PPDU, or non-HT duplicate PPDU is
442 //within ±0.4 µs + 16 µs from the end, at the STA’s antenna connector, of the last OFDM symbol of the triggering
443 //PPDU (if it contains no PE field) or of the PE field of the triggering PPDU (if the PE field is present).
444 //As a result, if an HE TB PPDU arrives later than 0.4 µs, it is added as an interference but PPDU is dropped.
445 event = CreateInterferenceEvent (ppdu, txVector, rxDuration, rxPowersW);
446 NS_LOG_DEBUG ("Drop packet because not received within the 400ns window");
447 m_wifiPhy->NotifyRxDrop (GetAddressedPsduInPpdu (ppdu), HE_TB_PPDU_TOO_LATE);
448 }
449 else
450 {
451 //Update received power of the event associated to that UL MU transmission
452 UpdateInterferenceEvent (event, rxPowersW);
453 }
454 if ((GetCurrentEvent () != 0) && (GetCurrentEvent ()->GetPpdu ()->GetUid () != ppdu->GetUid ()))
455 {
456 NS_LOG_DEBUG ("Drop packet because already receiving another HE TB PPDU");
457 m_wifiPhy->NotifyRxDrop (GetAddressedPsduInPpdu (ppdu), RXING);
458 }
459 return nullptr;
460 }
461 else
462 {
463 NS_LOG_DEBUG ("Received a new HE TB PPDU for UID " << ppdu->GetUid () << " from STA-ID " << ppdu->GetStaId () << " and BSS color " << +txVector.GetBssColor ());
464 event = CreateInterferenceEvent (ppdu, txVector, rxDuration, rxPowersW);
465 AddPreambleEvent (event);
466 }
467 }
468 else
469 {
470 event = PhyEntity::DoGetEvent (ppdu, rxPowersW);
471 }
472 return event;
473 }
474
475 Ptr<const WifiPsdu>
GetAddressedPsduInPpdu(Ptr<const WifiPpdu> ppdu) const476 HePhy::GetAddressedPsduInPpdu (Ptr<const WifiPpdu> ppdu) const
477 {
478 if (ppdu->GetType () == WIFI_PPDU_TYPE_DL_MU || ppdu->GetType () == WIFI_PPDU_TYPE_UL_MU)
479 {
480 auto hePpdu = DynamicCast<const HePpdu> (ppdu);
481 NS_ASSERT (hePpdu);
482 return hePpdu->GetPsdu (GetBssColor (), GetStaId (ppdu));
483 }
484 return PhyEntity::GetAddressedPsduInPpdu (ppdu);
485 }
486
487 uint8_t
GetBssColor(void) const488 HePhy::GetBssColor (void) const
489 {
490 uint8_t bssColor = 0;
491 Ptr<WifiNetDevice> device = DynamicCast<WifiNetDevice> (m_wifiPhy->GetDevice ());
492 if (device)
493 {
494 Ptr<HeConfiguration> heConfiguration = device->GetHeConfiguration ();
495 if (heConfiguration)
496 {
497 bssColor = heConfiguration->GetBssColor ();
498 }
499 }
500 return bssColor;
501 }
502
503 uint16_t
GetStaId(const Ptr<const WifiPpdu> ppdu) const504 HePhy::GetStaId (const Ptr<const WifiPpdu> ppdu) const
505 {
506 if (ppdu->GetType () == WIFI_PPDU_TYPE_UL_MU)
507 {
508 return ppdu->GetStaId ();
509 }
510 else if (ppdu->GetType () == WIFI_PPDU_TYPE_DL_MU)
511 {
512 Ptr<WifiNetDevice> device = DynamicCast<WifiNetDevice> (m_wifiPhy->GetDevice ());
513 if (device)
514 {
515 Ptr<StaWifiMac> mac = DynamicCast<StaWifiMac> (device->GetMac ());
516 if (mac && mac->IsAssociated ())
517 {
518 return mac->GetAssociationId ();
519 }
520 }
521 }
522 return PhyEntity::GetStaId (ppdu);
523 }
524
525 PhyEntity::PhyFieldRxStatus
ProcessSigA(Ptr<Event> event,PhyFieldRxStatus status)526 HePhy::ProcessSigA (Ptr<Event> event, PhyFieldRxStatus status)
527 {
528 NS_LOG_FUNCTION (this << *event << status);
529 //Notify end of SIG-A (in all cases)
530 WifiTxVector txVector = event->GetTxVector ();
531 HeSigAParameters params;
532 params.rssiW = GetRxPowerWForPpdu (event);
533 params.bssColor = txVector.GetBssColor ();
534 NotifyEndOfHeSigA (params); //if OBSS_PD CCA_RESET, set power restriction first and wait till field is processed before switching to IDLE
535
536 if (status.isSuccess)
537 {
538 //Check if PPDU is filtered based on the BSS color
539 uint8_t myBssColor = GetBssColor ();
540 uint8_t rxBssColor = txVector.GetBssColor ();
541 if (myBssColor != 0 && rxBssColor != 0 && myBssColor != rxBssColor)
542 {
543 NS_LOG_DEBUG ("The BSS color of this PPDU (" << +rxBssColor << ") does not match the device's (" << +myBssColor << "). The PPDU is filtered.");
544 return PhyFieldRxStatus (false, FILTERED, DROP);
545 }
546
547 Ptr<const WifiPpdu> ppdu = event->GetPpdu ();
548 if (txVector.IsUlMu ())
549 {
550 NS_ASSERT (txVector.GetModulationClass () == WIFI_MOD_CLASS_HE);
551 m_currentHeTbPpduUid = ppdu->GetUid (); //to be able to correctly schedule start of OFDMA payload
552 }
553
554 if (ppdu->GetType () != WIFI_PPDU_TYPE_DL_MU && !GetAddressedPsduInPpdu (ppdu)) //Final decision on STA-ID correspondence of DL MU is delayed to end of SIG-B
555 {
556 NS_ASSERT (ppdu->GetType () == WIFI_PPDU_TYPE_UL_MU);
557 NS_LOG_DEBUG ("No PSDU addressed to that PHY in the received MU PPDU. The PPDU is filtered.");
558 return PhyFieldRxStatus (false, FILTERED, DROP);
559 }
560 }
561 return status;
562 }
563
564 void
SetEndOfHeSigACallback(EndOfHeSigACallback callback)565 HePhy::SetEndOfHeSigACallback (EndOfHeSigACallback callback)
566 {
567 m_endOfHeSigACallback = callback;
568 }
569
570 void
NotifyEndOfHeSigA(HeSigAParameters params)571 HePhy::NotifyEndOfHeSigA (HeSigAParameters params)
572 {
573 if (!m_endOfHeSigACallback.IsNull ())
574 {
575 m_endOfHeSigACallback (params);
576 }
577 }
578
579 PhyEntity::PhyFieldRxStatus
ProcessSigB(Ptr<Event> event,PhyFieldRxStatus status)580 HePhy::ProcessSigB (Ptr<Event> event, PhyFieldRxStatus status)
581 {
582 NS_LOG_FUNCTION (this << *event << status);
583 if (status.isSuccess)
584 {
585 //Check if PPDU is filtered only if the SIG-B content is supported (not explicitly stated but assumed based on behavior for SIG-A)
586 if (!GetAddressedPsduInPpdu (event->GetPpdu ()))
587 {
588 NS_LOG_DEBUG ("No PSDU addressed to that PHY in the received MU PPDU. The PPDU is filtered.");
589 return PhyFieldRxStatus (false, FILTERED, DROP);
590 }
591 }
592 return status;
593 }
594
595 bool
IsConfigSupported(Ptr<const WifiPpdu> ppdu) const596 HePhy::IsConfigSupported (Ptr<const WifiPpdu> ppdu) const
597 {
598 const WifiTxVector& txVector = ppdu->GetTxVector ();
599 uint16_t staId = GetStaId (ppdu);
600 WifiMode txMode = txVector.GetMode (staId);
601 uint8_t nss = txVector.GetNssMax ();
602 if (txVector.IsDlMu ())
603 {
604 NS_ASSERT (txVector.GetModulationClass () == WIFI_MOD_CLASS_HE);
605 for (auto info : txVector.GetHeMuUserInfoMap ())
606 {
607 if (info.first == staId)
608 {
609 nss = info.second.nss; //no need to look at other PSDUs
610 break;
611 }
612 }
613 }
614
615 if (nss > m_wifiPhy->GetMaxSupportedRxSpatialStreams ())
616 {
617 NS_LOG_DEBUG ("Packet reception could not be started because not enough RX antennas");
618 return false;
619 }
620 if (!IsModeSupported (txMode))
621 {
622 NS_LOG_DEBUG ("Drop packet because it was sent using an unsupported mode (" << txVector.GetMode () << ")");
623 return false;
624 }
625 return true;
626 }
627
628 void
DoStartReceivePayload(Ptr<Event> event)629 HePhy::DoStartReceivePayload (Ptr<Event> event)
630 {
631 NS_LOG_FUNCTION (this << *event);
632 const WifiTxVector& txVector = event->GetTxVector ();
633 Ptr<const WifiPpdu> ppdu = event->GetPpdu ();
634 if (txVector.IsUlMu ())
635 {
636 NS_ASSERT (txVector.GetModulationClass () == WIFI_MOD_CLASS_HE);
637 Ptr<WifiNetDevice> device = DynamicCast<WifiNetDevice> (m_wifiPhy->GetDevice ());
638 bool isAp = device != 0 && (DynamicCast<ApWifiMac> (device->GetMac ()) != 0);
639 if (!isAp)
640 {
641 NS_LOG_DEBUG ("Ignore HE TB PPDU payload received by STA but keep state in Rx");
642 m_endRxPayloadEvents.push_back (Simulator::Schedule (ppdu->GetTxDuration () - CalculatePhyPreambleAndHeaderDuration (txVector),
643 &PhyEntity::ResetReceive, this, event));
644 //Cancel all scheduled events for OFDMA payload reception
645 NS_ASSERT (!m_beginOfdmaPayloadRxEvents.empty () && m_beginOfdmaPayloadRxEvents.begin ()->second.IsRunning ());
646 for (auto & beginOfdmaPayloadRxEvent : m_beginOfdmaPayloadRxEvents)
647 {
648 beginOfdmaPayloadRxEvent.second.Cancel ();
649 }
650 m_beginOfdmaPayloadRxEvents.clear ();
651 }
652 else
653 {
654 NS_LOG_DEBUG ("Receiving PSDU in HE TB PPDU");
655 uint16_t staId = GetStaId (ppdu);
656 m_signalNoiseMap.insert ({std::make_pair (ppdu->GetUid (), staId), SignalNoiseDbm ()});
657 m_statusPerMpduMap.insert ({std::make_pair (ppdu->GetUid (), staId), std::vector<bool> ()});
658 //for HE TB PPDUs, ScheduleEndOfMpdus and EndReceive are scheduled by StartReceiveOfdmaPayload
659 NS_ASSERT (isAp);
660 NS_ASSERT (!m_beginOfdmaPayloadRxEvents.empty ());
661 for (auto & beginOfdmaPayloadRxEvent : m_beginOfdmaPayloadRxEvents)
662 {
663 NS_ASSERT (beginOfdmaPayloadRxEvent.second.IsRunning ());
664 }
665 }
666 }
667 else
668 {
669 PhyEntity::DoStartReceivePayload (event);
670 }
671 }
672
673 void
DoEndReceivePayload(Ptr<const WifiPpdu> ppdu)674 HePhy::DoEndReceivePayload (Ptr<const WifiPpdu> ppdu)
675 {
676 NS_LOG_FUNCTION (this << ppdu);
677 if (ppdu->GetType () == WIFI_PPDU_TYPE_UL_MU)
678 {
679 for (auto it = m_endRxPayloadEvents.begin (); it != m_endRxPayloadEvents.end (); )
680 {
681 if (it->IsExpired ())
682 {
683 it = m_endRxPayloadEvents.erase (it);
684 }
685 else
686 {
687 it++;
688 }
689 }
690 if (m_endRxPayloadEvents.empty ())
691 {
692 //We've got the last PPDU of the UL-OFDMA transmission
693 NotifyInterferenceRxEndAndClear (true); //reset WifiPhy
694 }
695 }
696 else
697 {
698 NS_ASSERT (m_wifiPhy->GetLastRxEndTime () == Simulator::Now ());
699 PhyEntity::DoEndReceivePayload (ppdu);
700 }
701 }
702
703 void
StartReceiveOfdmaPayload(Ptr<Event> event)704 HePhy::StartReceiveOfdmaPayload (Ptr<Event> event)
705 {
706 Ptr<const WifiPpdu> ppdu = event->GetPpdu ();
707 const RxPowerWattPerChannelBand& rxPowersW = event->GetRxPowerWPerBand ();
708 //The total RX power corresponds to the maximum over all the bands.
709 //Only perform this computation if the result needs to be logged.
710 auto it = rxPowersW.end ();
711 if (g_log.IsEnabled (ns3::LOG_FUNCTION))
712 {
713 it = std::max_element (rxPowersW.begin (), rxPowersW.end (),
714 [] (const std::pair<WifiSpectrumBand, double> &p1, const std::pair<WifiSpectrumBand, double> &p2) {
715 return p1.second < p2.second;
716 });
717
718 }
719 NS_LOG_FUNCTION (this << *event << it->second);
720 NS_ASSERT (GetCurrentEvent () != 0);
721 auto itEvent = m_beginOfdmaPayloadRxEvents.find (GetStaId (ppdu));
722 /**
723 * m_beginOfdmaPayloadRxEvents should still be running only for APs, since canceled in StartReceivePayload for STAs.
724 * This is because SpectrumWifiPhy does not have access to the device type and thus blindly schedules things, letting
725 * the parent WifiPhy class take into account device type.
726 */
727 NS_ASSERT (itEvent != m_beginOfdmaPayloadRxEvents.end () && itEvent->second.IsExpired ());
728 m_beginOfdmaPayloadRxEvents.erase (itEvent);
729
730 Time payloadDuration = ppdu->GetTxDuration () - CalculatePhyPreambleAndHeaderDuration (ppdu->GetTxVector ());
731 Ptr<const WifiPsdu> psdu = GetAddressedPsduInPpdu (ppdu);
732 ScheduleEndOfMpdus (event);
733 m_endRxPayloadEvents.push_back (Simulator::Schedule (payloadDuration, &PhyEntity::EndReceivePayload, this, event));
734 m_signalNoiseMap.insert ({std::make_pair (ppdu->GetUid (), ppdu->GetStaId ()), SignalNoiseDbm ()});
735 m_statusPerMpduMap.insert ({std::make_pair (ppdu->GetUid (), ppdu->GetStaId ()), std::vector<bool> ()});
736 }
737
738 std::pair<uint16_t, WifiSpectrumBand>
GetChannelWidthAndBand(const WifiTxVector & txVector,uint16_t staId) const739 HePhy::GetChannelWidthAndBand (const WifiTxVector& txVector, uint16_t staId) const
740 {
741 if (txVector.IsMu ())
742 {
743 return std::make_pair (HeRu::GetBandwidth (txVector.GetRu (staId).GetRuType ()),
744 GetRuBandForRx (txVector, staId));
745 }
746 else
747 {
748 return PhyEntity::GetChannelWidthAndBand (txVector, staId);
749 }
750 }
751
752 WifiSpectrumBand
GetRuBandForTx(const WifiTxVector & txVector,uint16_t staId) const753 HePhy::GetRuBandForTx (const WifiTxVector& txVector, uint16_t staId) const
754 {
755 NS_ASSERT (txVector.IsMu ());
756 WifiSpectrumBand band;
757 HeRu::RuSpec ru = txVector.GetRu (staId);
758 uint16_t channelWidth = txVector.GetChannelWidth ();
759 NS_ASSERT (channelWidth <= m_wifiPhy->GetChannelWidth ());
760 HeRu::SubcarrierGroup group = HeRu::GetSubcarrierGroup (channelWidth, ru.GetRuType (), ru.GetPhyIndex ());
761 HeRu::SubcarrierRange range = std::make_pair (group.front ().first, group.back ().second);
762 // for a TX spectrum, the guard bandwidth is a function of the transmission channel width
763 // and the spectrum width equals the transmission channel width (hence bandIndex equals 0)
764 band = m_wifiPhy->ConvertHeRuSubcarriers (channelWidth, GetGuardBandwidth (channelWidth),
765 range, 0);
766 return band;
767 }
768
769 WifiSpectrumBand
GetRuBandForRx(const WifiTxVector & txVector,uint16_t staId) const770 HePhy::GetRuBandForRx (const WifiTxVector& txVector, uint16_t staId) const
771 {
772 NS_ASSERT (txVector.IsMu ());
773 WifiSpectrumBand band;
774 HeRu::RuSpec ru = txVector.GetRu (staId);
775 uint16_t channelWidth = txVector.GetChannelWidth ();
776 NS_ASSERT (channelWidth <= m_wifiPhy->GetChannelWidth ());
777 HeRu::SubcarrierGroup group = HeRu::GetSubcarrierGroup (channelWidth, ru.GetRuType (), ru.GetPhyIndex ());
778 HeRu::SubcarrierRange range = std::make_pair (group.front ().first, group.back ().second);
779 // for an RX spectrum, the guard bandwidth is a function of the operating channel width
780 // and the spectrum width equals the operating channel width
781 band = m_wifiPhy->ConvertHeRuSubcarriers (channelWidth, GetGuardBandwidth (m_wifiPhy->GetChannelWidth ()),
782 range, m_wifiPhy->GetOperatingChannel ().GetPrimaryChannelIndex (channelWidth));
783 return band;
784 }
785
786 WifiSpectrumBand
GetNonOfdmaBand(const WifiTxVector & txVector,uint16_t staId) const787 HePhy::GetNonOfdmaBand (const WifiTxVector& txVector, uint16_t staId) const
788 {
789 NS_ASSERT (txVector.IsUlMu () && (txVector.GetModulationClass () == WIFI_MOD_CLASS_HE));
790 uint16_t channelWidth = txVector.GetChannelWidth ();
791 NS_ASSERT (channelWidth <= m_wifiPhy->GetChannelWidth ());
792
793 HeRu::RuSpec ru = txVector.GetRu (staId);
794 uint16_t nonOfdmaWidth = GetNonOfdmaWidth (ru);
795
796 // Find the RU that encompasses the non-OFDMA part of the HE TB PPDU for the STA-ID
797 HeRu::RuSpec nonOfdmaRu = HeRu::FindOverlappingRu (channelWidth, ru, HeRu::GetRuType (nonOfdmaWidth));
798 nonOfdmaRu.SetPhyIndex (channelWidth, m_wifiPhy->GetOperatingChannel ().GetPrimaryChannelIndex (20));
799
800 HeRu::SubcarrierGroup groupPreamble = HeRu::GetSubcarrierGroup (channelWidth, nonOfdmaRu.GetRuType (), nonOfdmaRu.GetPhyIndex ());
801 HeRu::SubcarrierRange range = std::make_pair (groupPreamble.front ().first, groupPreamble.back ().second);
802 return m_wifiPhy->ConvertHeRuSubcarriers (channelWidth, GetGuardBandwidth (m_wifiPhy->GetChannelWidth ()), range,
803 m_wifiPhy->GetOperatingChannel ().GetPrimaryChannelIndex (channelWidth));
804 }
805
806 uint16_t
GetNonOfdmaWidth(HeRu::RuSpec ru) const807 HePhy::GetNonOfdmaWidth (HeRu::RuSpec ru) const
808 {
809 if (ru.GetRuType () == HeRu::RU_26_TONE && ru.GetIndex () == 19)
810 {
811 // the center 26-tone RU in an 80 MHz channel is not fully covered by
812 // any 20 MHz channel, but only by an 80 MHz channel
813 return 80;
814 }
815 return std::max<uint16_t> (HeRu::GetBandwidth (ru.GetRuType ()), 20);
816 }
817
818 uint64_t
GetCurrentHeTbPpduUid(void) const819 HePhy::GetCurrentHeTbPpduUid (void) const
820 {
821 return m_currentHeTbPpduUid;
822 }
823
824 uint16_t
GetMeasurementChannelWidth(const Ptr<const WifiPpdu> ppdu) const825 HePhy::GetMeasurementChannelWidth (const Ptr<const WifiPpdu> ppdu) const
826 {
827 uint16_t channelWidth = PhyEntity::GetMeasurementChannelWidth (ppdu);
828 /**
829 * The PHY shall not issue a PHY-RXSTART.indication primitive in response to a PPDU that does not overlap
830 * the primary channel unless the PHY at an AP receives the HE TB PPDU solicited by the AP. For the HE
831 * TB PPDU solicited by the AP, the PHY shall issue a PHY-RXSTART.indication primitive for a PPDU
832 * received in the primary or at the secondary 20 MHz channel, the secondary 40 MHz channel, or the secondary
833 * 80 MHz channel.
834 */
835 if (channelWidth >= 40 && ppdu->GetUid () != m_previouslyTxPpduUid)
836 {
837 channelWidth = 20;
838 }
839 return channelWidth;
840 }
841
842 uint64_t
ObtainNextUid(const WifiTxVector & txVector)843 HePhy::ObtainNextUid (const WifiTxVector& txVector)
844 {
845 NS_LOG_FUNCTION (this << txVector);
846 uint64_t uid;
847 if (txVector.IsUlMu ())
848 {
849 NS_ASSERT (txVector.GetModulationClass () == WIFI_MOD_CLASS_HE);
850 //Use UID of PPDU containing trigger frame to identify resulting HE TB PPDUs, since the latter should immediately follow the former
851 uid = m_wifiPhy->GetPreviouslyRxPpduUid ();
852 NS_ASSERT (uid != UINT64_MAX);
853 }
854 else
855 {
856 uid = m_globalPpduUid++;
857 }
858 m_previouslyTxPpduUid = uid; //to be able to identify solicited HE TB PPDUs
859 return uid;
860 }
861
862 Ptr<SpectrumValue>
GetTxPowerSpectralDensity(double txPowerW,Ptr<const WifiPpdu> ppdu) const863 HePhy::GetTxPowerSpectralDensity (double txPowerW, Ptr<const WifiPpdu> ppdu) const
864 {
865 const WifiTxVector& txVector = ppdu->GetTxVector ();
866 uint16_t centerFrequency = GetCenterFrequencyForChannelWidth (txVector);
867 uint16_t channelWidth = txVector.GetChannelWidth ();
868 NS_LOG_FUNCTION (this << centerFrequency << channelWidth << txPowerW);
869 auto hePpdu = DynamicCast<const HePpdu> (ppdu);
870 NS_ASSERT (hePpdu);
871 HePpdu::TxPsdFlag flag = hePpdu->GetTxPsdFlag ();
872 Ptr<SpectrumValue> v;
873 if (flag == HePpdu::PSD_HE_TB_OFDMA_PORTION)
874 {
875 WifiSpectrumBand band = GetRuBandForTx (txVector, GetStaId (hePpdu));
876 v = WifiSpectrumValueHelper::CreateHeMuOfdmTxPowerSpectralDensity (centerFrequency, channelWidth, txPowerW, GetGuardBandwidth (channelWidth), band);
877 }
878 else
879 {
880 if (flag == HePpdu::PSD_HE_TB_NON_OFDMA_PORTION)
881 {
882 //non-OFDMA portion is sent only on the 20 MHz channels covering the RU
883 uint16_t staId = GetStaId (hePpdu);
884 centerFrequency = GetCenterFrequencyForNonOfdmaPart (txVector, staId);
885 uint16_t ruWidth = HeRu::GetBandwidth (txVector.GetRu (staId).GetRuType ());
886 channelWidth = ruWidth < 20 ? 20 : ruWidth;
887 }
888 const auto & txMaskRejectionParams = GetTxMaskRejectionParams ();
889 v = WifiSpectrumValueHelper::CreateHeOfdmTxPowerSpectralDensity (centerFrequency, channelWidth, txPowerW, GetGuardBandwidth (channelWidth),
890 std::get<0> (txMaskRejectionParams), std::get<1> (txMaskRejectionParams), std::get<2> (txMaskRejectionParams));
891 }
892 return v;
893 }
894
895 uint16_t
GetCenterFrequencyForNonOfdmaPart(const WifiTxVector & txVector,uint16_t staId) const896 HePhy::GetCenterFrequencyForNonOfdmaPart (const WifiTxVector& txVector, uint16_t staId) const
897 {
898 NS_LOG_FUNCTION (this << txVector << staId);
899 NS_ASSERT (txVector.IsUlMu () && (txVector.GetModulationClass () == WIFI_MOD_CLASS_HE));
900 uint16_t centerFrequency = GetCenterFrequencyForChannelWidth (txVector);
901 uint16_t currentWidth = txVector.GetChannelWidth ();
902
903 HeRu::RuSpec ru = txVector.GetRu (staId);
904 uint16_t nonOfdmaWidth = GetNonOfdmaWidth (ru);
905 if (nonOfdmaWidth != currentWidth)
906 {
907 //Obtain the index of the non-OFDMA portion
908 HeRu::RuSpec nonOfdmaRu = HeRu::FindOverlappingRu (currentWidth, ru, HeRu::GetRuType (nonOfdmaWidth));
909 nonOfdmaRu.SetPhyIndex (currentWidth, m_wifiPhy->GetOperatingChannel ().GetPrimaryChannelIndex (20));
910
911 uint16_t startingFrequency = centerFrequency - (currentWidth / 2);
912 centerFrequency = startingFrequency + nonOfdmaWidth * (nonOfdmaRu.GetPhyIndex () - 1) + nonOfdmaWidth / 2;
913 }
914 return centerFrequency;
915 }
916
917 void
StartTx(Ptr<WifiPpdu> ppdu)918 HePhy::StartTx (Ptr<WifiPpdu> ppdu)
919 {
920 NS_LOG_FUNCTION (this << ppdu);
921 if (ppdu->GetType () == WIFI_PPDU_TYPE_UL_MU)
922 {
923 //non-OFDMA part
924 Time nonOfdmaDuration = CalculateNonOfdmaDurationForHeTb (ppdu->GetTxVector ());
925 Transmit (nonOfdmaDuration, ppdu, "non-OFDMA transmission");
926
927 //OFDMA part
928 auto hePpdu = DynamicCast<HePpdu> (ppdu->Copy ()); //since flag will be modified
929 NS_ASSERT (hePpdu);
930 hePpdu->SetTxPsdFlag (HePpdu::PSD_HE_TB_OFDMA_PORTION);
931 Time ofdmaDuration = ppdu->GetTxDuration () - nonOfdmaDuration;
932 Simulator::Schedule (nonOfdmaDuration, &PhyEntity::Transmit, this, ofdmaDuration, hePpdu, "OFDMA transmission");
933 }
934 else
935 {
936 PhyEntity::StartTx (ppdu);
937 }
938 }
939
940 Time
CalculateTxDuration(WifiConstPsduMap psduMap,const WifiTxVector & txVector,WifiPhyBand band) const941 HePhy::CalculateTxDuration (WifiConstPsduMap psduMap, const WifiTxVector& txVector, WifiPhyBand band) const
942 {
943 if (txVector.IsUlMu ())
944 {
945 NS_ASSERT (txVector.GetModulationClass () == WIFI_MOD_CLASS_HE);
946 return ConvertLSigLengthToHeTbPpduDuration (txVector.GetLength (), txVector, band);
947 }
948
949 Time maxDuration = Seconds (0);
950 for (auto & staIdPsdu : psduMap)
951 {
952 if (txVector.IsDlMu ())
953 {
954 NS_ASSERT (txVector.GetModulationClass () == WIFI_MOD_CLASS_HE);
955 WifiTxVector::HeMuUserInfoMap userInfoMap = txVector.GetHeMuUserInfoMap ();
956 NS_ABORT_MSG_IF (userInfoMap.find (staIdPsdu.first) == userInfoMap.end (), "STA-ID in psduMap (" << staIdPsdu.first << ") should be referenced in txVector");
957 }
958 Time current = WifiPhy::CalculateTxDuration (staIdPsdu.second->GetSize (), txVector, band,
959 staIdPsdu.first);
960 if (current > maxDuration)
961 {
962 maxDuration = current;
963 }
964 }
965 NS_ASSERT (maxDuration.IsStrictlyPositive ());
966 return maxDuration;
967 }
968
969 void
InitializeModes(void)970 HePhy::InitializeModes (void)
971 {
972 for (uint8_t i = 0; i < 12; ++i)
973 {
974 GetHeMcs (i);
975 }
976 }
977
978 WifiMode
GetHeMcs(uint8_t index)979 HePhy::GetHeMcs (uint8_t index)
980 {
981 #define CASE(x) \
982 case x: \
983 return GetHeMcs ## x (); \
984
985 switch (index)
986 {
987 CASE ( 0)
988 CASE ( 1)
989 CASE ( 2)
990 CASE ( 3)
991 CASE ( 4)
992 CASE ( 5)
993 CASE ( 6)
994 CASE ( 7)
995 CASE ( 8)
996 CASE ( 9)
997 CASE (10)
998 CASE (11)
999 default:
1000 NS_ABORT_MSG ("Inexistent index (" << +index << ") requested for HE");
1001 return WifiMode ();
1002 }
1003 #undef CASE
1004 }
1005
1006 #define GET_HE_MCS(x) \
1007 WifiMode \
1008 HePhy::GetHeMcs ## x (void) \
1009 { \
1010 static WifiMode mcs = CreateHeMcs (x); \
1011 return mcs; \
1012 }; \
1013
1014 GET_HE_MCS (0)
1015 GET_HE_MCS (1)
1016 GET_HE_MCS (2)
1017 GET_HE_MCS (3)
1018 GET_HE_MCS (4)
1019 GET_HE_MCS (5)
1020 GET_HE_MCS (6)
1021 GET_HE_MCS (7)
1022 GET_HE_MCS (8)
1023 GET_HE_MCS (9)
1024 GET_HE_MCS (10)
1025 GET_HE_MCS (11)
1026 #undef GET_HE_MCS
1027
1028 WifiMode
CreateHeMcs(uint8_t index)1029 HePhy::CreateHeMcs (uint8_t index)
1030 {
1031 NS_ASSERT_MSG (index <= 11, "HeMcs index must be <= 11!");
1032 return WifiModeFactory::CreateWifiMcs ("HeMcs" + std::to_string (index),
1033 index,
1034 WIFI_MOD_CLASS_HE,
1035 MakeBoundCallback (&GetCodeRate, index),
1036 MakeBoundCallback (&GetConstellationSize, index),
1037 MakeBoundCallback (&GetPhyRate, index),
1038 MakeCallback (&GetPhyRateFromTxVector),
1039 MakeBoundCallback (&GetDataRate, index),
1040 MakeCallback (&GetDataRateFromTxVector),
1041 MakeBoundCallback (&GetNonHtReferenceRate, index),
1042 MakeCallback (&IsModeAllowed));
1043 }
1044
1045 WifiCodeRate
GetCodeRate(uint8_t mcsValue)1046 HePhy::GetCodeRate (uint8_t mcsValue)
1047 {
1048 switch (mcsValue)
1049 {
1050 case 10:
1051 return WIFI_CODE_RATE_3_4;
1052 case 11:
1053 return WIFI_CODE_RATE_5_6;
1054 default:
1055 return VhtPhy::GetCodeRate (mcsValue);
1056 }
1057 }
1058
1059 uint16_t
GetConstellationSize(uint8_t mcsValue)1060 HePhy::GetConstellationSize (uint8_t mcsValue)
1061 {
1062 switch (mcsValue)
1063 {
1064 case 10:
1065 case 11:
1066 return 1024;
1067 default:
1068 return VhtPhy::GetConstellationSize (mcsValue);
1069 }
1070 }
1071
1072 uint64_t
GetPhyRate(uint8_t mcsValue,uint16_t channelWidth,uint16_t guardInterval,uint8_t nss)1073 HePhy::GetPhyRate (uint8_t mcsValue, uint16_t channelWidth, uint16_t guardInterval, uint8_t nss)
1074 {
1075 WifiCodeRate codeRate = GetCodeRate (mcsValue);
1076 uint64_t dataRate = GetDataRate (mcsValue, channelWidth, guardInterval, nss);
1077 return HtPhy::CalculatePhyRate (codeRate, dataRate);
1078 }
1079
1080 uint64_t
GetPhyRateFromTxVector(const WifiTxVector & txVector,uint16_t staId)1081 HePhy::GetPhyRateFromTxVector (const WifiTxVector& txVector, uint16_t staId /* = SU_STA_ID */)
1082 {
1083 uint16_t bw = txVector.GetChannelWidth ();
1084 if (txVector.IsMu ())
1085 {
1086 bw = HeRu::GetBandwidth (txVector.GetRu (staId).GetRuType ());
1087 }
1088 return HePhy::GetPhyRate (txVector.GetMode (staId).GetMcsValue (),
1089 bw,
1090 txVector.GetGuardInterval (),
1091 txVector.GetNss (staId));
1092 }
1093
1094 uint64_t
GetDataRateFromTxVector(const WifiTxVector & txVector,uint16_t staId)1095 HePhy::GetDataRateFromTxVector (const WifiTxVector& txVector, uint16_t staId /* = SU_STA_ID */)
1096 {
1097 uint16_t bw = txVector.GetChannelWidth ();
1098 if (txVector.IsMu ())
1099 {
1100 bw = HeRu::GetBandwidth (txVector.GetRu (staId).GetRuType ());
1101 }
1102 return HePhy::GetDataRate (txVector.GetMode (staId).GetMcsValue (),
1103 bw,
1104 txVector.GetGuardInterval (),
1105 txVector.GetNss (staId));
1106 }
1107
1108 uint64_t
GetDataRate(uint8_t mcsValue,uint16_t channelWidth,uint16_t guardInterval,uint8_t nss)1109 HePhy::GetDataRate (uint8_t mcsValue, uint16_t channelWidth, uint16_t guardInterval, uint8_t nss)
1110 {
1111 NS_ASSERT (guardInterval == 800 || guardInterval == 1600 || guardInterval == 3200);
1112 NS_ASSERT (nss <= 8);
1113 return HtPhy::CalculateDataRate (12.8, guardInterval,
1114 GetUsableSubcarriers (channelWidth),
1115 static_cast<uint16_t> (log2 (GetConstellationSize (mcsValue))),
1116 HtPhy::GetCodeRatio (GetCodeRate (mcsValue)), nss);
1117 }
1118
1119 uint16_t
GetUsableSubcarriers(uint16_t channelWidth)1120 HePhy::GetUsableSubcarriers (uint16_t channelWidth)
1121 {
1122 switch (channelWidth)
1123 {
1124 case 2: //26-tone RU
1125 return 24;
1126 case 4: //52-tone RU
1127 return 48;
1128 case 8: //106-tone RU
1129 return 102;
1130 case 20:
1131 default:
1132 return 234;
1133 case 40:
1134 return 468;
1135 case 80:
1136 return 980;
1137 case 160:
1138 return 1960;
1139 }
1140 }
1141
1142 uint64_t
GetNonHtReferenceRate(uint8_t mcsValue)1143 HePhy::GetNonHtReferenceRate (uint8_t mcsValue)
1144 {
1145 WifiCodeRate codeRate = GetCodeRate (mcsValue);
1146 uint16_t constellationSize = GetConstellationSize (mcsValue);
1147 return CalculateNonHtReferenceRate (codeRate, constellationSize);
1148 }
1149
1150 uint64_t
CalculateNonHtReferenceRate(WifiCodeRate codeRate,uint16_t constellationSize)1151 HePhy::CalculateNonHtReferenceRate (WifiCodeRate codeRate, uint16_t constellationSize)
1152 {
1153 uint64_t dataRate;
1154 switch (constellationSize)
1155 {
1156 case 1024:
1157 if (codeRate == WIFI_CODE_RATE_3_4 || codeRate == WIFI_CODE_RATE_5_6)
1158 {
1159 dataRate = 54000000;
1160 }
1161 else
1162 {
1163 NS_FATAL_ERROR ("Trying to get reference rate for a MCS with wrong combination of coding rate and modulation");
1164 }
1165 break;
1166 default:
1167 dataRate = VhtPhy::CalculateNonHtReferenceRate (codeRate, constellationSize);
1168 }
1169 return dataRate;
1170 }
1171
1172 bool
IsModeAllowed(uint16_t,uint8_t)1173 HePhy::IsModeAllowed (uint16_t /* channelWidth */, uint8_t /* nss */)
1174 {
1175 return true;
1176 }
1177
1178 WifiConstPsduMap
GetWifiConstPsduMap(Ptr<const WifiPsdu> psdu,const WifiTxVector & txVector) const1179 HePhy::GetWifiConstPsduMap (Ptr<const WifiPsdu> psdu, const WifiTxVector& txVector) const
1180 {
1181 uint16_t staId = SU_STA_ID;
1182
1183 if (txVector.IsUlMu ())
1184 {
1185 NS_ASSERT (txVector.GetHeMuUserInfoMap ().size () == 1);
1186 staId = txVector.GetHeMuUserInfoMap ().begin ()->first;
1187 }
1188
1189 return WifiConstPsduMap ({std::make_pair (staId, psdu)});
1190 }
1191
1192 uint32_t
GetMaxPsduSize(void) const1193 HePhy::GetMaxPsduSize (void) const
1194 {
1195 return 6500631;
1196 }
1197
1198 } //namespace ns3
1199
1200 namespace {
1201
1202 /**
1203 * Constructor class for HE modes
1204 */
1205 static class ConstructorHe
1206 {
1207 public:
ConstructorHe()1208 ConstructorHe ()
1209 {
1210 ns3::HePhy::InitializeModes ();
1211 ns3::WifiPhy::AddStaticPhyEntity (ns3::WIFI_MOD_CLASS_HE, ns3::Create<ns3::HePhy> ());
1212 }
1213 } g_constructor_he; ///< the constructor for HE modes
1214
1215 }
1216