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