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  *          Mathieu Lacage <mathieu.lacage@sophia.inria.fr> (for logic ported from wifi-phy)
21  */
22 
23 #include "phy-entity.h"
24 #include "spectrum-wifi-phy.h"
25 #include "wifi-psdu.h"
26 #include "preamble-detection-model.h"
27 #include "frame-capture-model.h"
28 #include "wifi-utils.h"
29 #include "wifi-spectrum-signal-parameters.h"
30 #include "ns3/packet.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 ("PhyEntity");
39 
operator <<(std::ostream & os,const PhyEntity::PhyRxFailureAction & action)40 std::ostream & operator << (std::ostream &os, const PhyEntity::PhyRxFailureAction &action)
41 {
42   switch (action)
43     {
44       case PhyEntity::DROP:
45         return (os << "DROP");
46       case PhyEntity::ABORT:
47         return (os << "ABORT");
48       case PhyEntity::IGNORE:
49         return (os << "IGNORE");
50       default:
51         NS_FATAL_ERROR ("Unknown action");
52         return (os << "unknown");
53     }
54 }
55 
operator <<(std::ostream & os,const PhyEntity::PhyFieldRxStatus & status)56 std::ostream & operator << (std::ostream &os, const PhyEntity::PhyFieldRxStatus &status)
57 {
58   if (status.isSuccess)
59     {
60       return os << "success";
61     }
62   else
63     {
64       return os << "failure (" << status.reason << "/" << status.actionIfFailure << ")";
65     }
66 }
67 
68 /*******************************************************
69  *       Abstract base class for PHY entities
70  *******************************************************/
71 
72 uint64_t PhyEntity::m_globalPpduUid = 0;
73 
~PhyEntity()74 PhyEntity::~PhyEntity ()
75 {
76   NS_LOG_FUNCTION (this);
77   m_modeList.clear ();
78   CancelAllEvents ();
79 }
80 
81 void
SetOwner(Ptr<WifiPhy> wifiPhy)82 PhyEntity::SetOwner (Ptr<WifiPhy> wifiPhy)
83 {
84   NS_LOG_FUNCTION (this << wifiPhy);
85   m_wifiPhy = wifiPhy;
86   m_state = m_wifiPhy->m_state;
87 }
88 
89 bool
IsModeSupported(WifiMode mode) const90 PhyEntity::IsModeSupported (WifiMode mode) const
91 {
92   for (const auto & m : m_modeList)
93     {
94       if (m == mode)
95         {
96           return true;
97         }
98     }
99   return false;
100 }
101 
102 uint8_t
GetNumModes(void) const103 PhyEntity::GetNumModes (void) const
104 {
105   return m_modeList.size ();
106 }
107 
108 WifiMode
GetMcs(uint8_t) const109 PhyEntity::GetMcs (uint8_t /* index */) const
110 {
111   NS_ABORT_MSG ("This method should be used only for HtPhy and child classes. Use GetMode instead.");
112   return WifiMode ();
113 }
114 
115 bool
IsMcsSupported(uint8_t) const116 PhyEntity::IsMcsSupported (uint8_t /* index */) const
117 {
118   NS_ABORT_MSG ("This method should be used only for HtPhy and child classes. Use IsModeSupported instead.");
119   return false;
120 }
121 
122 bool
HandlesMcsModes(void) const123 PhyEntity::HandlesMcsModes (void) const
124 {
125   return false;
126 }
127 
128 std::list<WifiMode>::const_iterator
begin(void) const129 PhyEntity::begin (void) const
130 {
131   return m_modeList.begin ();
132 }
133 
134 std::list<WifiMode>::const_iterator
end(void) const135 PhyEntity::end (void) const
136 {
137   return m_modeList.end ();
138 }
139 
140 WifiMode
GetSigMode(WifiPpduField field,const WifiTxVector & txVector) const141 PhyEntity::GetSigMode (WifiPpduField field, const WifiTxVector& txVector) const
142 {
143   NS_FATAL_ERROR ("PPDU field is not a SIG field (no sense in retrieving the signaled mode) or is unsupported: " << field);
144   return WifiMode (); //should be overloaded
145 }
146 
147 WifiPpduField
GetNextField(WifiPpduField currentField,WifiPreamble preamble) const148 PhyEntity::GetNextField (WifiPpduField currentField, WifiPreamble preamble) const
149 {
150   auto ppduFormats = GetPpduFormats ();
151   const auto itPpdu = ppduFormats.find (preamble);
152   if (itPpdu != ppduFormats.end ())
153     {
154       const auto itField = std::find (itPpdu->second.begin (), itPpdu->second.end (), currentField);
155       if (itField != itPpdu->second.end ())
156         {
157           const auto itNextField = std::next (itField, 1);
158           if (itNextField != itPpdu->second.end ())
159             {
160               return *(itNextField);
161             }
162           NS_FATAL_ERROR ("No field after " << currentField << " for " << preamble << " for the provided PPDU formats");
163         }
164       else
165         {
166           NS_FATAL_ERROR ("Unsupported PPDU field " << currentField << " for " << preamble << " for the provided PPDU formats");
167         }
168     }
169   else
170     {
171       NS_FATAL_ERROR ("Unsupported preamble " << preamble << " for the provided PPDU formats");
172     }
173 }
174 
175 Time
GetDuration(WifiPpduField field,const WifiTxVector & txVector) const176 PhyEntity::GetDuration (WifiPpduField field, const WifiTxVector& txVector) const
177 {
178   if (field > WIFI_PPDU_FIELD_SIG_B)
179     {
180       NS_FATAL_ERROR ("Unsupported PPDU field");
181     }
182   return MicroSeconds (0); //should be overloaded
183 }
184 
185 Time
CalculatePhyPreambleAndHeaderDuration(const WifiTxVector & txVector) const186 PhyEntity::CalculatePhyPreambleAndHeaderDuration (const WifiTxVector& txVector) const
187 {
188   Time duration = MicroSeconds (0);
189   for (uint8_t field = WIFI_PPDU_FIELD_PREAMBLE; field < WIFI_PPDU_FIELD_DATA; ++field)
190     {
191       duration += GetDuration (static_cast<WifiPpduField> (field), txVector);
192     }
193   return duration;
194 }
195 
196 WifiConstPsduMap
GetWifiConstPsduMap(Ptr<const WifiPsdu> psdu,const WifiTxVector & txVector) const197 PhyEntity::GetWifiConstPsduMap (Ptr<const WifiPsdu> psdu, const WifiTxVector& txVector) const
198 {
199   return WifiConstPsduMap ({std::make_pair (SU_STA_ID, psdu)});
200 }
201 
202 Ptr<const WifiPsdu>
GetAddressedPsduInPpdu(Ptr<const WifiPpdu> ppdu) const203 PhyEntity::GetAddressedPsduInPpdu (Ptr<const WifiPpdu> ppdu) const
204 {
205   return ppdu->GetPsdu ();
206 }
207 
208 PhyEntity::PhyHeaderSections
GetPhyHeaderSections(const WifiTxVector & txVector,Time ppduStart) const209 PhyEntity::GetPhyHeaderSections (const WifiTxVector& txVector, Time ppduStart) const
210 {
211   PhyHeaderSections map;
212   WifiPpduField field = WIFI_PPDU_FIELD_PREAMBLE; //preamble always present
213   Time start = ppduStart;
214 
215   while (field != WIFI_PPDU_FIELD_DATA)
216     {
217       Time duration = GetDuration (field, txVector);
218       map[field] = std::make_pair (std::make_pair (start, start + duration),
219                                    GetSigMode (field, txVector));
220       //Move to next field
221       start += duration;
222       field = GetNextField (field, txVector.GetPreambleType ());
223     }
224   return map;
225 }
226 
227 Ptr<WifiPpdu>
BuildPpdu(const WifiConstPsduMap & psdus,const WifiTxVector & txVector,Time)228 PhyEntity::BuildPpdu (const WifiConstPsduMap & psdus, const WifiTxVector& txVector, Time /* ppduDuration */)
229 {
230   NS_LOG_FUNCTION (this << psdus << txVector);
231   NS_FATAL_ERROR ("This method is unsupported for the base PhyEntity class. Use the overloaded version in the amendment-specific subclasses instead!");
232   return Create<WifiPpdu> (psdus.begin ()->second, txVector); //should be overloaded
233 }
234 
235 Time
GetDurationUpToField(WifiPpduField field,const WifiTxVector & txVector) const236 PhyEntity::GetDurationUpToField (WifiPpduField field, const WifiTxVector& txVector) const
237 {
238   if (field == WIFI_PPDU_FIELD_DATA) //this field is not in the map returned by GetPhyHeaderSections
239     {
240       return CalculatePhyPreambleAndHeaderDuration (txVector);
241     }
242   const auto & sections = GetPhyHeaderSections (txVector, NanoSeconds (0));
243   auto it = sections.find (field);
244   NS_ASSERT (it != sections.end ());
245   const auto & startStopTimes = it->second.first;
246   return startStopTimes.first; //return the start time of field relatively to the beginning of the PPDU
247 }
248 
249 PhyEntity::SnrPer
GetPhyHeaderSnrPer(WifiPpduField field,Ptr<Event> event) const250 PhyEntity::GetPhyHeaderSnrPer (WifiPpduField field, Ptr<Event> event) const
251 {
252   uint16_t measurementChannelWidth = GetMeasurementChannelWidth (event->GetPpdu ());
253   return m_wifiPhy->m_interference.CalculatePhyHeaderSnrPer (event, measurementChannelWidth, m_wifiPhy->GetPrimaryBand (measurementChannelWidth),
254                                                              field);
255 }
256 
257 void
StartReceiveField(WifiPpduField field,Ptr<Event> event)258 PhyEntity::StartReceiveField (WifiPpduField field, Ptr<Event> event)
259 {
260   NS_LOG_FUNCTION (this << field << *event);
261   NS_ASSERT (m_wifiPhy); //no sense if no owner WifiPhy instance
262   NS_ASSERT (m_wifiPhy->m_endPhyRxEvent.IsExpired ());
263   NS_ABORT_MSG_IF (field == WIFI_PPDU_FIELD_PREAMBLE, "Use the StartReceivePreamble method for preamble reception");
264   //Handle special cases of data reception
265   if (field == WIFI_PPDU_FIELD_DATA)
266     {
267       StartReceivePayload (event);
268       return;
269     }
270 
271   bool supported = DoStartReceiveField (field, event);
272   NS_ABORT_MSG_IF (!supported, "Unknown field " << field << " for this PHY entity"); //TODO see what to do if not supported
273   Time duration = GetDuration (field, event->GetTxVector ());
274   m_wifiPhy->m_endPhyRxEvent = Simulator::Schedule (duration, &PhyEntity::EndReceiveField, this, field, event);
275   m_state->SwitchMaybeToCcaBusy (duration); //keep in CCA busy state up to reception of Data (will then switch to RX)
276 }
277 
278 void
EndReceiveField(WifiPpduField field,Ptr<Event> event)279 PhyEntity::EndReceiveField (WifiPpduField field, Ptr<Event> event)
280 {
281   NS_LOG_FUNCTION (this << field << *event);
282   NS_ASSERT (m_wifiPhy); //no sense if no owner WifiPhy instance
283   NS_ASSERT (m_wifiPhy->m_endPhyRxEvent.IsExpired ());
284   PhyFieldRxStatus status = DoEndReceiveField (field, event);
285   WifiTxVector txVector = event->GetTxVector ();
286   if (status.isSuccess) //move to next field if reception succeeded
287     {
288       StartReceiveField (GetNextField (field, txVector.GetPreambleType ()), event);
289     }
290   else
291     {
292       Ptr<const WifiPpdu> ppdu = event->GetPpdu ();
293       switch (status.actionIfFailure)
294         {
295           case ABORT:
296             //Abort reception, but consider medium as busy
297             AbortCurrentReception (status.reason);
298             if (event->GetEndTime () > (Simulator::Now () + m_state->GetDelayUntilIdle ()))
299               {
300                 m_wifiPhy->SwitchMaybeToCcaBusy (GetMeasurementChannelWidth (ppdu));
301               }
302             break;
303           case DROP:
304             //Notify drop, keep in CCA busy, and perform same processing as IGNORE case
305             if (status.reason == FILTERED)
306               {
307                 //PHY-RXSTART is immediately followed by PHY-RXEND (Filtered)
308                 m_wifiPhy->m_phyRxPayloadBeginTrace (txVector, NanoSeconds (0)); //this callback (equivalent to PHY-RXSTART primitive) is also triggered for filtered PPDUs
309               }
310             m_wifiPhy->NotifyRxDrop (GetAddressedPsduInPpdu (ppdu), status.reason);
311             m_state->SwitchMaybeToCcaBusy (GetRemainingDurationAfterField (ppdu, field)); //keep in CCA busy state till the end
312           //no break
313           case IGNORE:
314             //Keep in Rx state and reset at end
315             m_endRxPayloadEvents.push_back (Simulator::Schedule (GetRemainingDurationAfterField (ppdu, field),
316                                                                  &PhyEntity::ResetReceive, this, event));
317             break;
318           default:
319             NS_FATAL_ERROR ("Unknown action in case of failure");
320         }
321     }
322 }
323 
324 Time
GetRemainingDurationAfterField(Ptr<const WifiPpdu> ppdu,WifiPpduField field) const325 PhyEntity::GetRemainingDurationAfterField (Ptr<const WifiPpdu> ppdu, WifiPpduField field) const
326 {
327   const WifiTxVector& txVector = ppdu->GetTxVector ();
328   return ppdu->GetTxDuration () - (GetDurationUpToField (field, txVector) + GetDuration (field, txVector));
329 }
330 
331 bool
DoStartReceiveField(WifiPpduField field,Ptr<Event> event)332 PhyEntity::DoStartReceiveField (WifiPpduField field, Ptr<Event> event)
333 {
334   NS_LOG_FUNCTION (this << field << *event);
335   NS_ASSERT (field != WIFI_PPDU_FIELD_PREAMBLE && field != WIFI_PPDU_FIELD_DATA); //handled apart for the time being
336   auto ppduFormats = GetPpduFormats ();
337   auto itFormat = ppduFormats.find (event->GetPpdu ()->GetPreamble ());
338   if (itFormat != ppduFormats.end ())
339     {
340       auto itField = std::find (itFormat->second.begin (), itFormat->second.end (), field);
341       if (itField != itFormat->second.end ())
342         {
343           return true; //supported field so we can start receiving
344         }
345     }
346   return false; //unsupported otherwise
347 }
348 
349 PhyEntity::PhyFieldRxStatus
DoEndReceiveField(WifiPpduField field,Ptr<Event> event)350 PhyEntity::DoEndReceiveField (WifiPpduField field, Ptr<Event> event)
351 {
352   NS_LOG_FUNCTION (this << field << *event);
353   NS_ASSERT (field != WIFI_PPDU_FIELD_DATA); //handled apart for the time being
354   if (field == WIFI_PPDU_FIELD_PREAMBLE)
355     {
356       return DoEndReceivePreamble (event);
357     }
358   return PhyFieldRxStatus (false); //failed reception by default
359 }
360 
361 void
StartReceivePreamble(Ptr<WifiPpdu> ppdu,RxPowerWattPerChannelBand & rxPowersW,Time)362 PhyEntity::StartReceivePreamble (Ptr<WifiPpdu> ppdu, RxPowerWattPerChannelBand& rxPowersW,
363                                  Time /* rxDuration */)
364 {
365   //The total RX power corresponds to the maximum over all the bands
366   auto it = std::max_element (rxPowersW.begin (), rxPowersW.end (),
367                               [] (const std::pair<WifiSpectrumBand, double> &p1, const std::pair<WifiSpectrumBand, double> &p2) {
368                                 return p1.second < p2.second;
369                               });
370   NS_LOG_FUNCTION (this << ppdu << it->second);
371   Time rxDuration = ppdu->GetTxDuration (); //the actual duration of the PPDU should be considered
372 
373   Ptr<Event> event = DoGetEvent (ppdu, rxPowersW);
374   if (event == nullptr)
375     {
376       //PPDU should be simply considered as interference (once it has been accounted for in InterferenceHelper)
377       return;
378     }
379 
380   Time endRx = Simulator::Now () + rxDuration;
381   if (m_state->GetState () == WifiPhyState::OFF)
382     {
383       NS_LOG_DEBUG ("Cannot start RX because device is OFF");
384       if (endRx > (Simulator::Now () + m_state->GetDelayUntilIdle ()))
385         {
386           m_wifiPhy->SwitchMaybeToCcaBusy (m_wifiPhy->GetMeasurementChannelWidth (nullptr));
387         }
388       return;
389     }
390 
391   if (ppdu->IsTruncatedTx ())
392     {
393       NS_LOG_DEBUG ("Packet reception stopped because transmitter has been switched off");
394       if (endRx > (Simulator::Now () + m_state->GetDelayUntilIdle ()))
395         {
396           m_wifiPhy->SwitchMaybeToCcaBusy (GetMeasurementChannelWidth (ppdu));
397         }
398       return;
399     }
400 
401   switch (m_state->GetState ())
402     {
403       case WifiPhyState::SWITCHING:
404         NS_LOG_DEBUG ("Drop packet because of channel switching");
405         /*
406          * Packets received on the upcoming channel are added to the event list
407          * during the switching state. This way the medium can be correctly sensed
408          * when the device listens to the channel for the first time after the
409          * switching e.g. after channel switching, the channel may be sensed as
410          * busy due to other devices' transmissions started before the end of
411          * the switching.
412          */
413         DropPreambleEvent (ppdu, CHANNEL_SWITCHING, endRx, m_wifiPhy->GetMeasurementChannelWidth (ppdu));
414         break;
415       case WifiPhyState::RX:
416         if (m_wifiPhy->m_frameCaptureModel != 0
417             && m_wifiPhy->m_frameCaptureModel->IsInCaptureWindow (m_wifiPhy->m_timeLastPreambleDetected)
418             && m_wifiPhy->m_frameCaptureModel->CaptureNewFrame (m_wifiPhy->m_currentEvent, event))
419           {
420             AbortCurrentReception (FRAME_CAPTURE_PACKET_SWITCH);
421             NS_LOG_DEBUG ("Switch to new packet");
422             StartPreambleDetectionPeriod (event);
423           }
424         else
425           {
426             NS_LOG_DEBUG ("Drop packet because already in Rx");
427             DropPreambleEvent (ppdu, RXING, endRx, m_wifiPhy->GetMeasurementChannelWidth (ppdu));
428             if (m_wifiPhy->m_currentEvent == 0)
429               {
430                 /*
431                  * We are here because the non-legacy PHY header has not been successfully received.
432                  * The PHY is kept in RX state for the duration of the PPDU, but EndReceive function is
433                  * not called when the reception of the PPDU is finished, which is responsible to clear
434                  * m_currentPreambleEvents. As a result, m_currentPreambleEvents should be cleared here.
435                  */
436                 m_wifiPhy->m_currentPreambleEvents.clear ();
437               }
438           }
439         break;
440       case WifiPhyState::TX:
441         NS_LOG_DEBUG ("Drop packet because already in Tx");
442         DropPreambleEvent (ppdu, TXING, endRx, m_wifiPhy->GetMeasurementChannelWidth (ppdu));
443         break;
444       case WifiPhyState::CCA_BUSY:
445         if (m_wifiPhy->m_currentEvent != 0)
446           {
447             if (m_wifiPhy->m_frameCaptureModel != 0
448                 && m_wifiPhy->m_frameCaptureModel->IsInCaptureWindow (m_wifiPhy->m_timeLastPreambleDetected)
449                 && m_wifiPhy->m_frameCaptureModel->CaptureNewFrame (m_wifiPhy->m_currentEvent, event))
450               {
451                 AbortCurrentReception (FRAME_CAPTURE_PACKET_SWITCH);
452                 NS_LOG_DEBUG ("Switch to new packet");
453                 StartPreambleDetectionPeriod (event);
454               }
455             else
456               {
457                 NS_LOG_DEBUG ("Drop packet because already decoding preamble");
458                 DropPreambleEvent (ppdu, BUSY_DECODING_PREAMBLE, endRx, m_wifiPhy->GetMeasurementChannelWidth (ppdu));
459               }
460           }
461         else
462           {
463             StartPreambleDetectionPeriod (event);
464           }
465         break;
466       case WifiPhyState::IDLE:
467         NS_ASSERT (m_wifiPhy->m_currentEvent == 0);
468         StartPreambleDetectionPeriod (event);
469         break;
470       case WifiPhyState::SLEEP:
471         NS_LOG_DEBUG ("Drop packet because in sleep mode");
472         DropPreambleEvent (ppdu, SLEEPING, endRx, m_wifiPhy->GetMeasurementChannelWidth (nullptr));
473         break;
474       default:
475         NS_FATAL_ERROR ("Invalid WifiPhy state.");
476         break;
477     }
478 }
479 
480 void
DropPreambleEvent(Ptr<const WifiPpdu> ppdu,WifiPhyRxfailureReason reason,Time endRx,uint16_t measurementChannelWidth)481 PhyEntity::DropPreambleEvent (Ptr<const WifiPpdu> ppdu, WifiPhyRxfailureReason reason, Time endRx, uint16_t measurementChannelWidth)
482 {
483   NS_LOG_FUNCTION (this << ppdu << reason << endRx << measurementChannelWidth);
484   m_wifiPhy->NotifyRxDrop (GetAddressedPsduInPpdu (ppdu), reason);
485   auto it = m_wifiPhy->m_currentPreambleEvents.find (std::make_pair (ppdu->GetUid (), ppdu->GetPreamble ()));
486   if (it != m_wifiPhy->m_currentPreambleEvents.end ())
487     {
488       m_wifiPhy->m_currentPreambleEvents.erase (it);
489     }
490   if (endRx > (Simulator::Now () + m_state->GetDelayUntilIdle ()))
491     {
492       //that PPDU will be noise _after_ the end of the current event.
493       m_wifiPhy->SwitchMaybeToCcaBusy (measurementChannelWidth);
494     }
495 }
496 
497 void
ErasePreambleEvent(Ptr<const WifiPpdu> ppdu,Time rxDuration)498 PhyEntity::ErasePreambleEvent (Ptr<const WifiPpdu> ppdu, Time rxDuration)
499 {
500   NS_LOG_FUNCTION (this << ppdu << rxDuration);
501   auto it = m_wifiPhy->m_currentPreambleEvents.find (std::make_pair (ppdu->GetUid (), ppdu->GetPreamble ()));
502   if (it != m_wifiPhy->m_currentPreambleEvents.end ())
503     {
504       m_wifiPhy->m_currentPreambleEvents.erase (it);
505     }
506   if (m_wifiPhy->m_currentPreambleEvents.empty ())
507     {
508       m_wifiPhy->Reset ();
509     }
510 
511   if (rxDuration > m_state->GetDelayUntilIdle ())
512     {
513       //this PPDU will be noise _after_ the completion of the current event
514       m_wifiPhy->SwitchMaybeToCcaBusy (GetMeasurementChannelWidth (ppdu));
515     }
516 }
517 
518 uint16_t
GetStaId(const Ptr<const WifiPpdu>) const519 PhyEntity::GetStaId (const Ptr<const WifiPpdu> /* ppdu */) const
520 {
521   return SU_STA_ID;
522 }
523 
524 void
StartReceivePayload(Ptr<Event> event)525 PhyEntity::StartReceivePayload (Ptr<Event> event)
526 {
527   NS_LOG_FUNCTION (this << *event);
528   NS_ASSERT (m_wifiPhy->m_endPhyRxEvent.IsExpired ());
529   const WifiTxVector& txVector = event->GetTxVector ();
530   Time payloadDuration = event->GetPpdu ()->GetTxDuration () - CalculatePhyPreambleAndHeaderDuration (txVector);
531 
532   //TODO: Add method in WifiPhy to clear all other PHYs (since this one is starting Rx)
533   m_state->SwitchToRx (payloadDuration);
534   m_wifiPhy->m_phyRxPayloadBeginTrace (txVector, payloadDuration); //this callback (equivalent to PHY-RXSTART primitive) is triggered only if headers have been correctly decoded and that the mode within is supported
535 
536   DoStartReceivePayload (event);
537 }
538 
539 void
DoStartReceivePayload(Ptr<Event> event)540 PhyEntity::DoStartReceivePayload (Ptr<Event> event)
541 {
542   NS_LOG_FUNCTION (this << *event);
543   Ptr<const WifiPpdu> ppdu = event->GetPpdu ();
544   NS_LOG_DEBUG ("Receiving PSDU");
545   uint16_t staId = GetStaId (ppdu);
546   m_signalNoiseMap.insert ({std::make_pair (ppdu->GetUid (), staId), SignalNoiseDbm ()});
547   m_statusPerMpduMap.insert ({std::make_pair (ppdu->GetUid (), staId), std::vector<bool> ()});
548   ScheduleEndOfMpdus (event);
549   m_endRxPayloadEvents.push_back (Simulator::Schedule (ppdu->GetTxDuration () - CalculatePhyPreambleAndHeaderDuration (event->GetTxVector ()),
550                                                        &PhyEntity::EndReceivePayload, this, event));
551 }
552 
553 void
ScheduleEndOfMpdus(Ptr<Event> event)554 PhyEntity::ScheduleEndOfMpdus (Ptr<Event> event)
555 {
556   NS_LOG_FUNCTION (this << *event);
557   Ptr<const WifiPpdu> ppdu = event->GetPpdu ();
558   Ptr<const WifiPsdu> psdu = GetAddressedPsduInPpdu (ppdu);
559   const WifiTxVector& txVector = event->GetTxVector ();
560   uint16_t staId = GetStaId (ppdu);
561   Time endOfMpduDuration = NanoSeconds (0);
562   Time relativeStart = NanoSeconds (0);
563   Time psduDuration = ppdu->GetTxDuration () - CalculatePhyPreambleAndHeaderDuration (txVector);
564   Time remainingAmpduDuration = psduDuration;
565   size_t nMpdus = psdu->GetNMpdus ();
566   MpduType mpduType = (nMpdus > 1) ? FIRST_MPDU_IN_AGGREGATE : (psdu->IsSingle () ? SINGLE_MPDU : NORMAL_MPDU);
567   uint32_t totalAmpduSize = 0;
568   double totalAmpduNumSymbols = 0.0;
569   auto mpdu = psdu->begin ();
570   for (size_t i = 0; i < nMpdus && mpdu != psdu->end (); ++mpdu)
571     {
572       uint32_t size = (mpduType == NORMAL_MPDU) ? psdu->GetSize () : psdu->GetAmpduSubframeSize (i);
573       Time mpduDuration = m_wifiPhy->GetPayloadDuration (size, txVector,
574                                                          m_wifiPhy->GetPhyBand (), mpduType, true, totalAmpduSize,
575                                                          totalAmpduNumSymbols, staId);
576 
577       remainingAmpduDuration -= mpduDuration;
578       if (i == (nMpdus - 1) && !remainingAmpduDuration.IsZero ()) //no more MPDUs coming
579         {
580           if (remainingAmpduDuration < NanoSeconds (txVector.GetGuardInterval ())) //enables to ignore padding
581             {
582               mpduDuration += remainingAmpduDuration; //apply a correction just in case rounding had induced slight shift
583             }
584         }
585 
586       endOfMpduDuration += mpduDuration;
587       NS_LOG_INFO ("Schedule end of MPDU #" << i << " in " << endOfMpduDuration.As (Time::NS) <<
588                    " (relativeStart=" << relativeStart.As (Time::NS) << ", mpduDuration=" << mpduDuration.As (Time::NS) <<
589                    ", remainingAmdpuDuration=" << remainingAmpduDuration.As (Time::NS) << ")");
590       m_endOfMpduEvents.push_back (Simulator::Schedule (endOfMpduDuration, &PhyEntity::EndOfMpdu, this, event, Create<WifiPsdu> (*mpdu, false), i, relativeStart, mpduDuration));
591 
592       //Prepare next iteration
593       ++i;
594       relativeStart += mpduDuration;
595       mpduType = (i == (nMpdus - 1)) ? LAST_MPDU_IN_AGGREGATE : MIDDLE_MPDU_IN_AGGREGATE;
596     }
597 }
598 
599 void
EndOfMpdu(Ptr<Event> event,Ptr<const WifiPsdu> psdu,size_t mpduIndex,Time relativeStart,Time mpduDuration)600 PhyEntity::EndOfMpdu (Ptr<Event> event, Ptr<const WifiPsdu> psdu, size_t mpduIndex, Time relativeStart, Time mpduDuration)
601 {
602   NS_LOG_FUNCTION (this << *event << mpduIndex << relativeStart << mpduDuration);
603   Ptr<const WifiPpdu> ppdu = event->GetPpdu ();
604   WifiTxVector txVector = event->GetTxVector ();
605   uint16_t staId = GetStaId (ppdu);
606 
607   std::pair<bool, SignalNoiseDbm> rxInfo = GetReceptionStatus (psdu, event, staId, relativeStart, mpduDuration);
608   NS_LOG_DEBUG ("Extracted MPDU #" << mpduIndex << ": duration: " << mpduDuration.As (Time::NS) <<
609                 ", correct reception: " << rxInfo.first << ", Signal/Noise: " << rxInfo.second.signal << "/" << rxInfo.second.noise << "dBm");
610 
611   auto signalNoiseIt = m_signalNoiseMap.find (std::make_pair (ppdu->GetUid (), staId));
612   NS_ASSERT (signalNoiseIt != m_signalNoiseMap.end ());
613   signalNoiseIt->second = rxInfo.second;
614 
615   RxSignalInfo rxSignalInfo;
616   rxSignalInfo.snr = rxInfo.second.signal / rxInfo.second.noise;
617   rxSignalInfo.rssi = rxInfo.second.signal;
618 
619   auto statusPerMpduIt = m_statusPerMpduMap.find (std::make_pair (ppdu->GetUid (), staId));
620   NS_ASSERT (statusPerMpduIt != m_statusPerMpduMap.end ());
621   statusPerMpduIt->second.push_back (rxInfo.first);
622 
623   if (rxInfo.first && GetAddressedPsduInPpdu (ppdu)->GetNMpdus () > 1)
624     {
625       //only done for correct MPDU that is part of an A-MPDU
626       m_state->ContinueRxNextMpdu (Copy (psdu), rxSignalInfo, txVector);
627     }
628 }
629 
630 void
EndReceivePayload(Ptr<Event> event)631 PhyEntity::EndReceivePayload (Ptr<Event> event)
632 {
633   Ptr<const WifiPpdu> ppdu = event->GetPpdu ();
634   WifiTxVector txVector = event->GetTxVector ();
635   Time psduDuration = ppdu->GetTxDuration () - CalculatePhyPreambleAndHeaderDuration (txVector);
636   NS_LOG_FUNCTION (this << *event << psduDuration);
637   NS_ASSERT (event->GetEndTime () == Simulator::Now ());
638   uint16_t staId = GetStaId (ppdu);
639   const auto & channelWidthAndBand = GetChannelWidthAndBand (event->GetTxVector (), staId);
640   double snr = m_wifiPhy->m_interference.CalculateSnr (event, channelWidthAndBand.first, txVector.GetNss (staId), channelWidthAndBand.second);
641 
642   Ptr<const WifiPsdu> psdu = GetAddressedPsduInPpdu (ppdu);
643   m_wifiPhy->NotifyRxEnd (psdu);
644 
645   auto signalNoiseIt = m_signalNoiseMap.find (std::make_pair (ppdu->GetUid (), staId));
646   NS_ASSERT (signalNoiseIt != m_signalNoiseMap.end ());
647   auto statusPerMpduIt = m_statusPerMpduMap.find (std::make_pair (ppdu->GetUid (), staId));
648   NS_ASSERT (statusPerMpduIt != m_statusPerMpduMap.end ());
649 
650   if (std::count (statusPerMpduIt->second.begin (), statusPerMpduIt->second.end (), true))
651     {
652       //At least one MPDU has been successfully received
653       m_wifiPhy->NotifyMonitorSniffRx (psdu, m_wifiPhy->GetFrequency (), txVector, signalNoiseIt->second, statusPerMpduIt->second, staId);
654       RxSignalInfo rxSignalInfo;
655       rxSignalInfo.snr = snr;
656       rxSignalInfo.rssi = signalNoiseIt->second.signal; //same information for all MPDUs
657       m_state->SwitchFromRxEndOk (Copy (psdu), rxSignalInfo, txVector, staId, statusPerMpduIt->second);
658       m_wifiPhy->m_previouslyRxPpduUid = ppdu->GetUid (); //store UID only if reception is successful (because otherwise trigger won't be read by MAC layer)
659     }
660   else
661     {
662       m_state->SwitchFromRxEndError (Copy (psdu), snr);
663     }
664 
665   DoEndReceivePayload (ppdu);
666   m_wifiPhy->SwitchMaybeToCcaBusy (GetMeasurementChannelWidth (ppdu));
667 }
668 
669 void
DoEndReceivePayload(Ptr<const WifiPpdu> ppdu)670 PhyEntity::DoEndReceivePayload (Ptr<const WifiPpdu> ppdu)
671 {
672   NS_LOG_FUNCTION (this << ppdu);
673   NS_ASSERT (m_wifiPhy->GetLastRxEndTime () == Simulator::Now ());
674   NotifyInterferenceRxEndAndClear (false); //don't reset WifiPhy
675 
676   m_wifiPhy->m_currentEvent = 0;
677   m_wifiPhy->m_currentPreambleEvents.clear ();
678   m_endRxPayloadEvents.clear ();
679 }
680 
681 std::pair<bool, SignalNoiseDbm>
GetReceptionStatus(Ptr<const WifiPsdu> psdu,Ptr<Event> event,uint16_t staId,Time relativeMpduStart,Time mpduDuration)682 PhyEntity::GetReceptionStatus (Ptr<const WifiPsdu> psdu, Ptr<Event> event, uint16_t staId,
683                                Time relativeMpduStart, Time mpduDuration)
684 {
685   NS_LOG_FUNCTION (this << *psdu << *event << staId << relativeMpduStart << mpduDuration);
686   const auto & channelWidthAndBand = GetChannelWidthAndBand (event->GetTxVector (), staId);
687   SnrPer snrPer = m_wifiPhy->m_interference.CalculatePayloadSnrPer (event, channelWidthAndBand.first, channelWidthAndBand.second, staId,
688                                                                     std::make_pair (relativeMpduStart, relativeMpduStart + mpduDuration));
689 
690   WifiMode mode = event->GetTxVector ().GetMode (staId);
691   NS_LOG_DEBUG ("rate=" << (mode.GetDataRate (event->GetTxVector (), staId)) <<
692                 ", SNR(dB)=" << RatioToDb (snrPer.snr) << ", PER=" << snrPer.per << ", size=" << psdu->GetSize () <<
693                 ", relativeStart = " << relativeMpduStart.As (Time::NS) << ", duration = " << mpduDuration.As (Time::NS));
694 
695   // There are two error checks: PER and receive error model check.
696   // PER check models is typical for Wi-Fi and is based on signal modulation;
697   // Receive error model is optional, if we have an error model and
698   // it indicates that the packet is corrupt, drop the packet.
699   SignalNoiseDbm signalNoise;
700   signalNoise.signal = WToDbm (event->GetRxPowerW (channelWidthAndBand.second));
701   signalNoise.noise = WToDbm (event->GetRxPowerW (channelWidthAndBand.second) / snrPer.snr);
702   if (GetRandomValue () > snrPer.per
703       && !(m_wifiPhy->m_postReceptionErrorModel && m_wifiPhy->m_postReceptionErrorModel->IsCorrupt (psdu->GetPacket ()->Copy ())))
704     {
705       NS_LOG_DEBUG ("Reception succeeded: " << psdu);
706       return std::make_pair (true, signalNoise);
707     }
708   else
709     {
710       NS_LOG_DEBUG ("Reception failed: " << psdu);
711       return std::make_pair (false, signalNoise);
712     }
713 }
714 
715 std::pair<uint16_t, WifiSpectrumBand>
GetChannelWidthAndBand(const WifiTxVector & txVector,uint16_t) const716 PhyEntity::GetChannelWidthAndBand (const WifiTxVector& txVector, uint16_t /* staId */) const
717 {
718   uint16_t channelWidth = GetRxChannelWidth (txVector);
719   return std::make_pair (channelWidth, m_wifiPhy->GetPrimaryBand (channelWidth));
720 }
721 
722 const std::map <std::pair<uint64_t, WifiPreamble>, Ptr<Event> > &
GetCurrentPreambleEvents(void) const723 PhyEntity::GetCurrentPreambleEvents (void) const
724 {
725   return m_wifiPhy->m_currentPreambleEvents;
726 }
727 
728 void
AddPreambleEvent(Ptr<Event> event)729 PhyEntity::AddPreambleEvent (Ptr<Event> event)
730 {
731   NS_LOG_FUNCTION (this << *event);
732   Ptr<const WifiPpdu> ppdu = event->GetPpdu ();
733   m_wifiPhy->m_currentPreambleEvents.insert ({std::make_pair (ppdu->GetUid (), ppdu->GetPreamble ()), event});
734 }
735 
736 Ptr<Event>
DoGetEvent(Ptr<const WifiPpdu> ppdu,RxPowerWattPerChannelBand & rxPowersW)737 PhyEntity::DoGetEvent (Ptr<const WifiPpdu> ppdu, RxPowerWattPerChannelBand& rxPowersW)
738 {
739   Ptr<Event> event = CreateInterferenceEvent (ppdu, ppdu->GetTxVector (), ppdu->GetTxDuration (), rxPowersW);
740 
741   //We store all incoming preamble events, and a decision is made at the end of the preamble detection window.
742   auto uidPreamblePair = std::make_pair (ppdu->GetUid (), ppdu->GetPreamble ());
743   NS_ASSERT (m_wifiPhy->m_currentPreambleEvents.find (uidPreamblePair) == m_wifiPhy->m_currentPreambleEvents.end ());
744   m_wifiPhy->m_currentPreambleEvents.insert ({uidPreamblePair, event});
745   return event;
746 }
747 
748 Ptr<Event>
CreateInterferenceEvent(Ptr<const WifiPpdu> ppdu,const WifiTxVector & txVector,Time duration,RxPowerWattPerChannelBand & rxPower,bool isStartOfdmaRxing)749 PhyEntity::CreateInterferenceEvent (Ptr<const WifiPpdu> ppdu, const WifiTxVector& txVector, Time duration, RxPowerWattPerChannelBand& rxPower, bool isStartOfdmaRxing /* = false */)
750 {
751   return m_wifiPhy->m_interference.Add (ppdu, txVector, duration, rxPower, isStartOfdmaRxing);
752 }
753 
754 void
UpdateInterferenceEvent(Ptr<Event> event,const RxPowerWattPerChannelBand & rxPower)755 PhyEntity::UpdateInterferenceEvent (Ptr<Event> event, const RxPowerWattPerChannelBand& rxPower)
756 {
757   m_wifiPhy->m_interference.UpdateEvent (event, rxPower);
758 }
759 
760 void
NotifyInterferenceRxEndAndClear(bool reset)761 PhyEntity::NotifyInterferenceRxEndAndClear (bool reset)
762 {
763   m_wifiPhy->m_interference.NotifyRxEnd (Simulator::Now ());
764   m_signalNoiseMap.clear ();
765   m_statusPerMpduMap.clear ();
766   for (const auto & endOfMpduEvent : m_endOfMpduEvents)
767     {
768       NS_ASSERT (endOfMpduEvent.IsExpired ());
769     }
770   m_endOfMpduEvents.clear ();
771   if (reset)
772     {
773       m_wifiPhy->Reset ();
774     }
775 }
776 
777 PhyEntity::PhyFieldRxStatus
DoEndReceivePreamble(Ptr<Event> event)778 PhyEntity::DoEndReceivePreamble (Ptr<Event> event)
779 {
780   NS_LOG_FUNCTION (this << *event);
781   NS_ASSERT (m_wifiPhy->m_currentPreambleEvents.size () == 1); //Synched on one after detection period
782   return PhyFieldRxStatus (true); //always consider that preamble has been correctly received if preamble detection was OK
783 }
784 
785 void
StartPreambleDetectionPeriod(Ptr<Event> event)786 PhyEntity::StartPreambleDetectionPeriod (Ptr<Event> event)
787 {
788   NS_LOG_FUNCTION (this << *event);
789   NS_LOG_DEBUG ("Sync to signal (power=" << WToDbm (GetRxPowerWForPpdu (event)) << "dBm)");
790   m_wifiPhy->m_interference.NotifyRxStart (); //We need to notify it now so that it starts recording events
791   m_endPreambleDetectionEvents.push_back (Simulator::Schedule (m_wifiPhy->GetPreambleDetectionDuration (), &PhyEntity::EndPreambleDetectionPeriod, this, event));
792 }
793 
794 void
EndPreambleDetectionPeriod(Ptr<Event> event)795 PhyEntity::EndPreambleDetectionPeriod (Ptr<Event> event)
796 {
797   NS_LOG_FUNCTION (this << *event);
798   NS_ASSERT (!m_wifiPhy->IsStateRx ());
799   NS_ASSERT (m_wifiPhy->m_endPhyRxEvent.IsExpired ()); //since end of preamble reception is scheduled by this method upon success
800 
801   //calculate PER on the measurement channel for PHY headers
802   uint16_t measurementChannelWidth = GetMeasurementChannelWidth (event->GetPpdu ());
803   auto measurementBand = m_wifiPhy->GetPrimaryBand (measurementChannelWidth);
804   double maxRxPowerW = -1; //in case current event may not be sent on measurement channel (rxPowerW would be equal to 0)
805   Ptr<Event> maxEvent;
806   NS_ASSERT (!m_wifiPhy->m_currentPreambleEvents.empty ());
807   for (auto preambleEvent : m_wifiPhy->m_currentPreambleEvents)
808     {
809       double rxPowerW = preambleEvent.second->GetRxPowerW (measurementBand);
810       if (rxPowerW > maxRxPowerW)
811         {
812           maxRxPowerW = rxPowerW;
813           maxEvent = preambleEvent.second;
814         }
815     }
816 
817   NS_ASSERT (maxEvent != 0);
818   if (maxEvent != event)
819     {
820       NS_LOG_DEBUG ("Receiver got a stronger packet with UID " << maxEvent->GetPpdu ()->GetUid () << " during preamble detection: drop packet with UID " << event->GetPpdu ()->GetUid ());
821       m_wifiPhy->NotifyRxDrop (GetAddressedPsduInPpdu (event->GetPpdu ()), BUSY_DECODING_PREAMBLE);
822       auto it = m_wifiPhy->m_currentPreambleEvents.find (std::make_pair (event->GetPpdu ()->GetUid (), event->GetPpdu ()->GetPreamble ()));
823       m_wifiPhy->m_currentPreambleEvents.erase (it);
824       //This is needed to cleanup the m_firstPowerPerBand so that the first power corresponds to the power at the start of the PPDU
825       m_wifiPhy->m_interference.NotifyRxEnd (maxEvent->GetStartTime ());
826       //Make sure InterferenceHelper keeps recording events
827       m_wifiPhy->m_interference.NotifyRxStart ();
828       return;
829     }
830 
831   m_wifiPhy->m_currentEvent = event;
832 
833   double snr = m_wifiPhy->m_interference.CalculateSnr (m_wifiPhy->m_currentEvent, measurementChannelWidth, 1, measurementBand);
834   NS_LOG_DEBUG ("SNR(dB)=" << RatioToDb (snr) << " at end of preamble detection period");
835 
836   if ((!m_wifiPhy->m_preambleDetectionModel && maxRxPowerW > 0.0)
837       || (m_wifiPhy->m_preambleDetectionModel && m_wifiPhy->m_preambleDetectionModel->IsPreambleDetected (m_wifiPhy->m_currentEvent->GetRxPowerW (measurementBand), snr, measurementChannelWidth)))
838     {
839       //A bit convoluted but it enables to sync all PHYs
840       for (auto & it : m_wifiPhy->m_phyEntities)
841         {
842           it.second->CancelRunningEndPreambleDetectionEvents (true);
843         }
844 
845       for (auto it = m_wifiPhy->m_currentPreambleEvents.begin (); it != m_wifiPhy->m_currentPreambleEvents.end (); )
846         {
847           if (it->second != m_wifiPhy->m_currentEvent)
848             {
849               NS_LOG_DEBUG ("Drop packet with UID " << it->first.first << " and preamble " << it->first.second << " arrived at time " << it->second->GetStartTime ());
850               WifiPhyRxfailureReason reason;
851               if (m_wifiPhy->m_currentEvent->GetPpdu ()->GetUid () > it->first.first)
852                 {
853                   reason = PREAMBLE_DETECTION_PACKET_SWITCH;
854                   //This is needed to cleanup the m_firstPowerPerBand so that the first power corresponds to the power at the start of the PPDU
855                   m_wifiPhy->m_interference.NotifyRxEnd (m_wifiPhy->m_currentEvent->GetStartTime ());
856                 }
857               else
858                 {
859                   reason = BUSY_DECODING_PREAMBLE;
860                 }
861               m_wifiPhy->NotifyRxDrop (GetAddressedPsduInPpdu (it->second->GetPpdu ()), reason);
862               it = m_wifiPhy->m_currentPreambleEvents.erase (it);
863             }
864           else
865             {
866               ++it;
867             }
868         }
869 
870       //Make sure InterferenceHelper keeps recording events
871       m_wifiPhy->m_interference.NotifyRxStart ();
872 
873       m_wifiPhy->NotifyRxBegin (GetAddressedPsduInPpdu (m_wifiPhy->m_currentEvent->GetPpdu ()), m_wifiPhy->m_currentEvent->GetRxPowerWPerBand ());
874       m_wifiPhy->m_timeLastPreambleDetected = Simulator::Now ();
875 
876       //Continue receiving preamble
877       Time durationTillEnd = GetDuration (WIFI_PPDU_FIELD_PREAMBLE, event->GetTxVector ()) - m_wifiPhy->GetPreambleDetectionDuration ();
878       m_state->SwitchMaybeToCcaBusy (durationTillEnd); //will be prolonged by next field
879       m_wifiPhy->m_endPhyRxEvent = Simulator::Schedule (durationTillEnd, &PhyEntity::EndReceiveField, this, WIFI_PPDU_FIELD_PREAMBLE, event);
880     }
881   else
882     {
883       NS_LOG_DEBUG ("Drop packet because PHY preamble detection failed");
884       // Like CCA-SD, CCA-ED is governed by the 4 us CCA window to flag CCA-BUSY
885       // for any received signal greater than the CCA-ED threshold.
886       DropPreambleEvent (m_wifiPhy->m_currentEvent->GetPpdu (), PREAMBLE_DETECT_FAILURE, m_wifiPhy->m_currentEvent->GetEndTime (), m_wifiPhy->GetMeasurementChannelWidth (m_wifiPhy->m_currentEvent->GetPpdu ()));
887       if (m_wifiPhy->m_currentPreambleEvents.empty ())
888         {
889           //Do not erase events if there are still pending preamble events to be processed
890           m_wifiPhy->m_interference.NotifyRxEnd (Simulator::Now ());
891         }
892       m_wifiPhy->m_currentEvent = 0;
893       //Cancel preamble reception
894       m_wifiPhy->m_endPhyRxEvent.Cancel ();
895     }
896 }
897 
898 bool
IsConfigSupported(Ptr<const WifiPpdu> ppdu) const899 PhyEntity::IsConfigSupported (Ptr<const WifiPpdu> ppdu) const
900 {
901   WifiMode txMode = ppdu->GetTxVector ().GetMode ();
902   if (!IsModeSupported (txMode))
903     {
904       NS_LOG_DEBUG ("Drop packet because it was sent using an unsupported mode (" << txMode << ")");
905       return false;
906     }
907   return true;
908 }
909 
910 void
CancelAllEvents(void)911 PhyEntity::CancelAllEvents (void)
912 {
913   NS_LOG_FUNCTION (this);
914   for (auto & endPreambleDetectionEvent : m_endPreambleDetectionEvents)
915     {
916       endPreambleDetectionEvent.Cancel ();
917     }
918   m_endPreambleDetectionEvents.clear ();
919   for (auto & endRxPayloadEvent : m_endRxPayloadEvents)
920     {
921       endRxPayloadEvent.Cancel ();
922     }
923   m_endRxPayloadEvents.clear ();
924 }
925 
926 bool
NoEndPreambleDetectionEvents(void) const927 PhyEntity::NoEndPreambleDetectionEvents (void) const
928 {
929   return m_endPreambleDetectionEvents.empty ();
930 }
931 
932 void
CancelRunningEndPreambleDetectionEvents(bool clear)933 PhyEntity::CancelRunningEndPreambleDetectionEvents (bool clear /* = false */)
934 {
935   NS_LOG_FUNCTION (this << clear);
936   for (auto & endPreambleDetectionEvent : m_endPreambleDetectionEvents)
937     {
938       if (endPreambleDetectionEvent.IsRunning ())
939         {
940           endPreambleDetectionEvent.Cancel ();
941         }
942     }
943   if (clear)
944     {
945       m_endPreambleDetectionEvents.clear ();
946     }
947 }
948 
949 void
AbortCurrentReception(WifiPhyRxfailureReason reason)950 PhyEntity::AbortCurrentReception (WifiPhyRxfailureReason reason)
951 {
952   NS_LOG_FUNCTION (this << reason);
953   DoAbortCurrentReception (reason);
954   m_wifiPhy->AbortCurrentReception (reason);
955 }
956 
957 void
DoAbortCurrentReception(WifiPhyRxfailureReason reason)958 PhyEntity::DoAbortCurrentReception (WifiPhyRxfailureReason reason)
959 {
960   NS_LOG_FUNCTION (this << reason);
961   if (m_wifiPhy->m_currentEvent) //Otherwise abort has already been called just before
962     {
963       for (auto & endMpduEvent : m_endOfMpduEvents)
964         {
965           endMpduEvent.Cancel ();
966         }
967       m_endOfMpduEvents.clear ();
968     }
969 }
970 
971 void
ResetReceive(Ptr<Event> event)972 PhyEntity::ResetReceive (Ptr<Event> event)
973 {
974   NS_LOG_FUNCTION (this << *event);
975   DoResetReceive (event);
976   NS_ASSERT (m_endRxPayloadEvents.size () == 1 && m_endRxPayloadEvents.front ().IsExpired ());
977   m_endRxPayloadEvents.clear ();
978   m_wifiPhy->ResetReceive (event);
979 }
980 
981 void
DoResetReceive(Ptr<Event> event)982 PhyEntity::DoResetReceive (Ptr<Event> event)
983 {
984   NS_LOG_FUNCTION (this << *event);
985   NS_ASSERT (event->GetEndTime () == Simulator::Now ());
986 }
987 
988 double
GetRandomValue(void) const989 PhyEntity::GetRandomValue (void) const
990 {
991   return m_wifiPhy->m_random->GetValue ();
992 }
993 
994 double
GetRxPowerWForPpdu(Ptr<Event> event) const995 PhyEntity::GetRxPowerWForPpdu (Ptr<Event> event) const
996 {
997   return event->GetRxPowerW (m_wifiPhy->GetPrimaryBand (GetMeasurementChannelWidth (event->GetPpdu ())));
998 }
999 
1000 Ptr<const Event>
GetCurrentEvent(void) const1001 PhyEntity::GetCurrentEvent (void) const
1002 {
1003   return m_wifiPhy->m_currentEvent;
1004 }
1005 
1006 uint16_t
GetMeasurementChannelWidth(const Ptr<const WifiPpdu> ppdu) const1007 PhyEntity::GetMeasurementChannelWidth (const Ptr<const WifiPpdu> ppdu) const
1008 {
1009   return GetRxChannelWidth (ppdu->GetTxVector ());
1010 }
1011 
1012 uint16_t
GetRxChannelWidth(const WifiTxVector & txVector) const1013 PhyEntity::GetRxChannelWidth (const WifiTxVector& txVector) const
1014 {
1015   return std::min (m_wifiPhy->GetChannelWidth (), txVector.GetChannelWidth ());
1016 }
1017 
1018 uint64_t
ObtainNextUid(const WifiTxVector &)1019 PhyEntity::ObtainNextUid (const WifiTxVector& /* txVector */)
1020 {
1021   NS_LOG_FUNCTION (this);
1022   return m_globalPpduUid++;
1023 }
1024 
1025 uint16_t
GetCenterFrequencyForChannelWidth(const WifiTxVector & txVector) const1026 PhyEntity::GetCenterFrequencyForChannelWidth (const WifiTxVector& txVector) const
1027 {
1028   NS_LOG_FUNCTION (this << txVector);
1029 
1030   return m_wifiPhy->GetOperatingChannel ().GetPrimaryChannelCenterFrequency (txVector.GetChannelWidth ());
1031 }
1032 
1033 void
StartTx(Ptr<WifiPpdu> ppdu)1034 PhyEntity::StartTx (Ptr<WifiPpdu> ppdu)
1035 {
1036   NS_LOG_FUNCTION (this << ppdu);
1037   Transmit (ppdu->GetTxDuration (), ppdu, "transmission");
1038 }
1039 
1040 void
Transmit(Time txDuration,Ptr<WifiPpdu> ppdu,std::string type)1041 PhyEntity::Transmit (Time txDuration, Ptr<WifiPpdu> ppdu, std::string type)
1042 {
1043   NS_LOG_FUNCTION (this << txDuration << ppdu << type);
1044   double txPowerWatts = DbmToW (m_wifiPhy->GetTxPowerForTransmission (ppdu) + m_wifiPhy->GetTxGain ());
1045   NS_LOG_DEBUG ("Start " << type << ": signal power before antenna gain=" << WToDbm (txPowerWatts) << "dBm");
1046   Ptr<SpectrumValue> txPowerSpectrum = GetTxPowerSpectralDensity (txPowerWatts, ppdu);
1047   Ptr<WifiSpectrumSignalParameters> txParams = Create<WifiSpectrumSignalParameters> ();
1048   txParams->duration = txDuration;
1049   txParams->psd = txPowerSpectrum;
1050   txParams->ppdu = ppdu;
1051   NS_LOG_DEBUG ("Starting " << type << " with power " << WToDbm (txPowerWatts) << " dBm on channel " << +m_wifiPhy->GetChannelNumber () << " for " << txParams->duration.As (Time::MS));
1052   NS_LOG_DEBUG ("Starting " << type << " with integrated spectrum power " << WToDbm (Integral (*txPowerSpectrum)) << " dBm; spectrum model Uid: " << txPowerSpectrum->GetSpectrumModel ()->GetUid ());
1053   auto spectrumWifiPhy = DynamicCast<SpectrumWifiPhy> (m_wifiPhy);
1054   NS_ASSERT (spectrumWifiPhy);
1055   spectrumWifiPhy->Transmit (txParams);
1056 }
1057 
1058 uint16_t
GetGuardBandwidth(uint16_t currentChannelWidth) const1059 PhyEntity::GetGuardBandwidth (uint16_t currentChannelWidth) const
1060 {
1061   return m_wifiPhy->GetGuardBandwidth (currentChannelWidth);
1062 }
1063 
1064 std::tuple<double, double, double>
GetTxMaskRejectionParams(void) const1065 PhyEntity::GetTxMaskRejectionParams (void) const
1066 {
1067   return m_wifiPhy->GetTxMaskRejectionParams ();
1068 }
1069 
1070 Time
CalculateTxDuration(WifiConstPsduMap psduMap,const WifiTxVector & txVector,WifiPhyBand band) const1071 PhyEntity::CalculateTxDuration (WifiConstPsduMap psduMap, const WifiTxVector& txVector, WifiPhyBand band) const
1072 {
1073   NS_ASSERT (psduMap.size () == 1);
1074   const auto & it = psduMap.begin ();
1075   return WifiPhy::CalculateTxDuration (it->second->GetSize (), txVector, band, it->first);
1076 }
1077 
1078 } //namespace ns3
1079