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