A Discrete-Event Network Simulator
API
wifi-phy-state-helper.cc
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2005,2006 INRIA
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  * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
19  */
20 
21 #include <algorithm>
22 #include "ns3/log.h"
23 #include "ns3/simulator.h"
24 #include "ns3/packet.h"
25 #include "wifi-phy-state-helper.h"
26 #include "wifi-tx-vector.h"
27 #include "wifi-phy-listener.h"
28 #include "wifi-psdu.h"
29 #include "wifi-phy.h"
30 
31 namespace ns3 {
32 
33 NS_LOG_COMPONENT_DEFINE ("WifiPhyStateHelper");
34 
35 NS_OBJECT_ENSURE_REGISTERED (WifiPhyStateHelper);
36 
37 TypeId
39 {
40  static TypeId tid = TypeId ("ns3::WifiPhyStateHelper")
41  .SetParent<Object> ()
42  .SetGroupName ("Wifi")
43  .AddConstructor<WifiPhyStateHelper> ()
44  .AddTraceSource ("State",
45  "The state of the PHY layer",
47  "ns3::WifiPhyStateHelper::StateTracedCallback")
48  .AddTraceSource ("RxOk",
49  "A packet has been received successfully.",
51  "ns3::WifiPhyStateHelper::RxOkTracedCallback")
52  .AddTraceSource ("RxError",
53  "A packet has been received unsuccessfully.",
55  "ns3::WifiPhyStateHelper::RxEndErrorTracedCallback")
56  .AddTraceSource ("Tx", "Packet transmission is starting.",
58  "ns3::WifiPhyStateHelper::TxTracedCallback")
59  ;
60  return tid;
61 }
62 
64  : m_sleeping (false),
65  m_isOff (false),
66  m_endTx (Seconds (0)),
67  m_endRx (Seconds (0)),
68  m_endCcaBusy (Seconds (0)),
69  m_endSwitching (Seconds (0)),
70  m_startTx (Seconds (0)),
71  m_startRx (Seconds (0)),
72  m_startCcaBusy (Seconds (0)),
73  m_startSwitching (Seconds (0)),
74  m_startSleep (Seconds (0)),
75  m_previousStateChangeTime (Seconds (0))
76 {
77  NS_LOG_FUNCTION (this);
78 }
79 
80 void
82 {
83  m_rxOkCallback = callback;
84 }
85 
86 void
88 {
89  m_rxErrorCallback = callback;
90 }
91 
92 void
94 {
95  m_listeners.push_back (listener);
96 }
97 
98 void
100 {
101  auto it = find (m_listeners.begin (), m_listeners.end (), listener);
102  if (it != m_listeners.end ())
103  {
104  m_listeners.erase (it);
105  }
106 }
107 
108 bool
110 {
111  return (GetState () == WifiPhyState::IDLE);
112 }
113 
114 bool
116 {
117  return (GetState () == WifiPhyState::CCA_BUSY);
118 }
119 
120 bool
122 {
123  return (GetState () == WifiPhyState::RX);
124 }
125 
126 bool
128 {
129  return (GetState () == WifiPhyState::TX);
130 }
131 
132 bool
134 {
135  return (GetState () == WifiPhyState::SWITCHING);
136 }
137 
138 bool
140 {
141  return (GetState () == WifiPhyState::SLEEP);
142 }
143 
144 bool
146 {
147  return (GetState () == WifiPhyState::OFF);
148 }
149 
150 Time
152 {
153  Time retval;
154 
155  switch (GetState ())
156  {
157  case WifiPhyState::RX:
158  retval = m_endRx - Simulator::Now ();
159  break;
160  case WifiPhyState::TX:
161  retval = m_endTx - Simulator::Now ();
162  break;
164  retval = m_endCcaBusy - Simulator::Now ();
165  break;
167  retval = m_endSwitching - Simulator::Now ();
168  break;
169  case WifiPhyState::IDLE:
170  case WifiPhyState::SLEEP:
171  case WifiPhyState::OFF:
172  retval = Seconds (0);
173  break;
174  default:
175  NS_FATAL_ERROR ("Invalid WifiPhy state.");
176  retval = Seconds (0);
177  break;
178  }
179  retval = Max (retval, Seconds (0));
180  return retval;
181 }
182 
183 Time
185 {
186  return m_startRx;
187 }
188 
189 Time
191 {
192  return m_endRx;
193 }
194 
197 {
198  if (m_isOff)
199  {
200  return WifiPhyState::OFF;
201  }
202  if (m_sleeping)
203  {
204  return WifiPhyState::SLEEP;
205  }
206  else if (m_endTx > Simulator::Now ())
207  {
208  return WifiPhyState::TX;
209  }
210  else if (m_endRx > Simulator::Now ())
211  {
212  return WifiPhyState::RX;
213  }
214  else if (m_endSwitching > Simulator::Now ())
215  {
217  }
218  else if (m_endCcaBusy > Simulator::Now ())
219  {
220  return WifiPhyState::CCA_BUSY;
221  }
222  else
223  {
224  return WifiPhyState::IDLE;
225  }
226 }
227 
228 void
229 WifiPhyStateHelper::NotifyTxStart (Time duration, double txPowerDbm)
230 {
231  NS_LOG_FUNCTION (this);
232  for (const auto& listener : m_listeners)
233  {
234  listener->NotifyTxStart (duration, txPowerDbm);
235  }
236 }
237 
238 void
240 {
241  NS_LOG_FUNCTION (this);
242  for (const auto& listener : m_listeners)
243  {
244  listener->NotifyRxStart (duration);
245  }
246 }
247 
248 void
250 {
251  NS_LOG_FUNCTION (this);
252  for (const auto& listener : m_listeners)
253  {
254  listener->NotifyRxEndOk ();
255  }
256 }
257 
258 void
260 {
261  NS_LOG_FUNCTION (this);
262  for (const auto& listener : m_listeners)
263  {
264  listener->NotifyRxEndError ();
265  }
266 }
267 
268 void
270 {
271  NS_LOG_FUNCTION (this);
272  for (const auto& listener : m_listeners)
273  {
274  listener->NotifyMaybeCcaBusyStart (duration);
275  }
276 }
277 
278 void
280 {
281  NS_LOG_FUNCTION (this);
282  for (const auto& listener : m_listeners)
283  {
284  listener->NotifySwitchingStart (duration);
285  }
286 }
287 
288 void
290 {
291  NS_LOG_FUNCTION (this);
292  for (const auto& listener : m_listeners)
293  {
294  listener->NotifySleep ();
295  }
296 }
297 
298 void
300 {
301  NS_LOG_FUNCTION (this);
302  for (const auto& listener : m_listeners)
303  {
304  listener->NotifyOff ();
305  }
306 }
307 
308 void
310 {
311  NS_LOG_FUNCTION (this);
312  for (const auto& listener : m_listeners)
313  {
314  listener->NotifyWakeup ();
315  }
316 }
317 
318 void
320 {
321  NS_LOG_FUNCTION (this);
322  for (const auto& listener : m_listeners)
323  {
324  listener->NotifyOn ();
325  }
326 }
327 
328 void
330 {
331  NS_LOG_FUNCTION (this);
332  Time now = Simulator::Now ();
333  WifiPhyState state = GetState ();
334  if (state == WifiPhyState::CCA_BUSY)
335  {
337  m_stateLogger (ccaStart, now - ccaStart, WifiPhyState::CCA_BUSY);
338  }
339  else if (state == WifiPhyState::IDLE)
340  {
342  NS_ASSERT (idleStart <= now);
343  if (m_endCcaBusy > m_endRx
345  && m_endCcaBusy > m_endTx)
346  {
348  Time ccaBusyDuration = idleStart - ccaBusyStart;
349  if (ccaBusyDuration.IsStrictlyPositive ())
350  {
351  m_stateLogger (ccaBusyStart, ccaBusyDuration, WifiPhyState::CCA_BUSY);
352  }
353  }
354  Time idleDuration = now - idleStart;
355  if (idleDuration.IsStrictlyPositive ())
356  {
357  m_stateLogger (idleStart, idleDuration, WifiPhyState::IDLE);
358  }
359  }
360 }
361 
362 void
363 WifiPhyStateHelper::SwitchToTx (Time txDuration, WifiConstPsduMap psdus, double txPowerDbm, WifiTxVector txVector)
364 {
365  NS_LOG_FUNCTION (this << txDuration << psdus << txPowerDbm << txVector);
366  if (!m_txTrace.IsEmpty ())
367  {
368  for (auto const& psdu : psdus)
369  {
370  m_txTrace (psdu.second->GetPacket (), txVector.GetMode (psdu.first),
371  txVector.GetPreambleType (), txVector.GetTxPowerLevel ());
372  }
373  }
374  Time now = Simulator::Now ();
375  switch (GetState ())
376  {
377  case WifiPhyState::RX:
378  /* The packet which is being received as well
379  * as its endRx event are cancelled by the caller.
380  */
382  m_endRx = now;
383  break;
385  [[fallthrough]];
386  case WifiPhyState::IDLE:
388  break;
389  default:
390  NS_FATAL_ERROR ("Invalid WifiPhy state.");
391  break;
392  }
393  m_stateLogger (now, txDuration, WifiPhyState::TX);
395  m_endTx = now + txDuration;
396  m_startTx = now;
397  NotifyTxStart (txDuration, txPowerDbm);
398 }
399 
400 void
402 {
403  NS_LOG_FUNCTION (this << rxDuration);
405  Time now = Simulator::Now ();
406  switch (GetState ())
407  {
408  case WifiPhyState::IDLE:
409  [[fallthrough]];
412  break;
413  default:
414  NS_FATAL_ERROR ("Invalid WifiPhy state " << GetState ());
415  break;
416  }
418  m_startRx = now;
419  m_endRx = now + rxDuration;
420  NotifyRxStart (rxDuration);
421  NS_ASSERT (IsStateRx ());
422 }
423 
424 void
426 {
427  NS_LOG_FUNCTION (this << switchingDuration);
428  Time now = Simulator::Now ();
429  switch (GetState ())
430  {
431  case WifiPhyState::RX:
432  /* The packet which is being received as well
433  * as its endRx event are cancelled by the caller.
434  */
436  m_endRx = now;
437  break;
439  [[fallthrough]];
440  case WifiPhyState::IDLE:
442  break;
443  default:
444  NS_FATAL_ERROR ("Invalid WifiPhy state.");
445  break;
446  }
447 
449  m_stateLogger (now, switchingDuration, WifiPhyState::SWITCHING);
451  m_startSwitching = now;
452  m_endSwitching = now + switchingDuration;
453  NotifySwitchingStart (switchingDuration);
455 }
456 
457 void
459 {
460  NS_LOG_FUNCTION (this << *psdu << rxSignalInfo << txVector);
461  std::vector<bool> statusPerMpdu;
462  if (!m_rxOkCallback.IsNull ())
463  {
464  m_rxOkCallback (psdu, rxSignalInfo, txVector, statusPerMpdu);
465  }
466 }
467 
468 void
469 WifiPhyStateHelper::SwitchFromRxEndOk (Ptr<WifiPsdu> psdu, RxSignalInfo rxSignalInfo, WifiTxVector txVector, uint16_t staId, std::vector<bool> statusPerMpdu)
470 {
471  NS_LOG_FUNCTION (this << *psdu << rxSignalInfo << txVector << staId << statusPerMpdu.size () <<
472  std::all_of(statusPerMpdu.begin(), statusPerMpdu.end(), [](bool v) { return v; })); //returns true if all true
473  NS_ASSERT (statusPerMpdu.size () != 0);
474  NS_ASSERT (Abs (m_endRx - Simulator::Now ()) < MicroSeconds (1)); //1us corresponds to the maximum propagation delay (delay spread)
475  //TODO: a better fix would be to call the function once all HE TB PPDUs are received
476  if (!m_rxOkTrace.IsEmpty ())
477  {
478  m_rxOkTrace (psdu->GetPacket (), rxSignalInfo.snr, txVector.GetMode (staId),
479  txVector.GetPreambleType ());
480  }
481  NotifyRxEndOk ();
482  DoSwitchFromRx ();
483  if (!m_rxOkCallback.IsNull ())
484  {
485  m_rxOkCallback (psdu, rxSignalInfo, txVector, statusPerMpdu);
486  }
487 }
488 
489 void
491 {
492  NS_LOG_FUNCTION (this << *psdu << snr);
493  NS_ASSERT (Abs (m_endRx - Simulator::Now ()) < MicroSeconds (1)); //1us corresponds to the maximum propagation delay (delay spread)
494  //TODO: a better fix would be to call the function once all HE TB PPDUs are received
495  if (!m_rxErrorTrace.IsEmpty ())
496  {
497  m_rxErrorTrace (psdu->GetPacket (), snr);
498  }
499  NotifyRxEndError ();
500  DoSwitchFromRx ();
501  if (!m_rxErrorCallback.IsNull ())
502  {
503  m_rxErrorCallback (psdu);
504  }
505 }
506 
507 void
509 {
510  NS_LOG_FUNCTION (this);
511  Time now = Simulator::Now ();
514  m_endRx = Simulator::Now ();
516 }
517 
518 void
520 {
521  NS_LOG_FUNCTION (this << duration);
522  if (GetState () != WifiPhyState::RX)
523  {
524  NotifyMaybeCcaBusyStart (duration);
525  }
526  Time now = Simulator::Now ();
527  switch (GetState ())
528  {
529  case WifiPhyState::IDLE:
531  break;
532  case WifiPhyState::RX:
533  return;
534  default:
535  break;
536  }
538  {
539  m_startCcaBusy = now;
540  }
541  m_endCcaBusy = std::max (m_endCcaBusy, now + duration);
542 }
543 
544 void
546 {
547  NS_LOG_FUNCTION (this);
548  Time now = Simulator::Now ();
549  switch (GetState ())
550  {
551  case WifiPhyState::IDLE:
552  [[fallthrough]];
555  break;
556  default:
557  NS_FATAL_ERROR ("Invalid WifiPhy state.");
558  break;
559  }
561  m_sleeping = true;
562  m_startSleep = now;
563  NotifySleep ();
564  NS_ASSERT (IsStateSleep ());
565 }
566 
567 void
569 {
570  NS_LOG_FUNCTION (this);
571  NS_ASSERT (IsStateSleep ());
572  Time now = Simulator::Now ();
575  m_sleeping = false;
576  NotifyWakeup ();
577 }
578 
579 void
581 {
582  NS_LOG_FUNCTION (this);
583  NS_ASSERT (IsStateCcaBusy ()); //abort is called (with OBSS_PD_CCA_RESET reason) before RX is set by payload start
584  NotifyRxEndOk ();
585  DoSwitchFromRx ();
588  NS_ASSERT (IsStateIdle ());
589 }
590 
591 void
593 {
594  NS_LOG_FUNCTION (this);
595  Time now = Simulator::Now ();
596  switch (GetState ())
597  {
598  case WifiPhyState::RX:
599  /* The packet which is being received as well
600  * as its endRx event are cancelled by the caller.
601  */
603  m_endRx = now;
604  break;
605  case WifiPhyState::TX:
606  /* The packet which is being transmitted as well
607  * as its endTx event are cancelled by the caller.
608  */
610  m_endTx = now;
611  break;
612  case WifiPhyState::IDLE:
613  [[fallthrough]];
616  break;
617  default:
618  NS_FATAL_ERROR ("Invalid WifiPhy state.");
619  break;
620  }
622  m_isOff = true;
623  NotifyOff ();
624  NS_ASSERT (IsStateOff ());
625 }
626 
627 void
629 {
630  NS_LOG_FUNCTION (this);
631  NS_ASSERT (IsStateOff ());
632  Time now = Simulator::Now ();
634  m_isOff = false;
635  NotifyOn ();
636 }
637 
638 } //namespace ns3
#define min(a, b)
Definition: 80211b.c:42
#define max(a, b)
Definition: 80211b.c:43
bool IsNull(void) const
Check for null implementation.
Definition: callback.h:1386
A base class which provides memory management and object aggregation.
Definition: object.h:88
static Time Now(void)
Return the current simulation virtual time.
Definition: simulator.cc:195
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:103
bool IsStrictlyPositive(void) const
Exactly equivalent to t > 0.
Definition: nstime.h:332
a unique identifier for an interface.
Definition: type-id.h:59
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:922
receive notifications about PHY events.
This objects implements the PHY state machine of the Wifi device.
bool IsStateSleep(void) const
Check whether the current state is SLEEP.
void SwitchToRx(Time rxDuration)
Switch state to RX for the given duration.
bool IsStateCcaBusy(void) const
Check whether the current state is CCA busy.
void SwitchFromSleep(void)
Switch from sleep mode.
Time GetLastRxEndTime(void) const
Return the time the last RX end.
void SwitchFromRxEndOk(Ptr< WifiPsdu > psdu, RxSignalInfo rxSignalInfo, WifiTxVector txVector, uint16_t staId, std::vector< bool > statusPerMpdu)
Switch from RX after the reception was successful.
Time GetDelayUntilIdle(void) const
Return the time before the state is back to IDLE.
void DoSwitchFromRx(void)
Switch the state from RX.
Time GetLastRxStartTime(void) const
Return the time the last RX start.
WifiPhyState GetState(void) const
Return the current state of WifiPhy.
bool IsStateOff(void) const
Check whether the current state is OFF.
bool IsStateTx(void) const
Check whether the current state is TX.
void NotifyOn(void)
Notify all WifiPhyListener that we are going to switch on.
bool IsStateRx(void) const
Check whether the current state is RX.
void NotifySwitchingStart(Time duration)
Notify all WifiPhyListener that we are switching channel with the given channel switching delay.
Time m_previousStateChangeTime
previous state change time
void NotifyRxStart(Time duration)
Notify all WifiPhyListener that the reception has started for the given duration.
void SwitchToChannelSwitching(Time switchingDuration)
Switch state to channel switching for the given duration.
void NotifyRxEndOk(void)
Notify all WifiPhyListener that the reception was successful.
void SwitchFromOff(void)
Switch from off mode.
TracedCallback< Ptr< const Packet >, WifiMode, WifiPreamble, uint8_t > m_txTrace
transmit trace callback
Time m_endSwitching
end switching
Time m_startSwitching
start switching
TracedCallback< Time, Time, WifiPhyState > m_stateLogger
The trace source fired when state is changed.
void LogPreviousIdleAndCcaBusyStates(void)
Log the idle and CCA busy states.
void RegisterListener(WifiPhyListener *listener)
Register WifiPhyListener to this WifiPhyStateHelper.
void ContinueRxNextMpdu(Ptr< WifiPsdu > psdu, RxSignalInfo rxSignalInfo, WifiTxVector txVector)
Continue RX after the reception of an MPDU in an A-MPDU was successful.
void SwitchToTx(Time txDuration, WifiConstPsduMap psdus, double txPowerDbm, WifiTxVector txVector)
Switch state to TX for the given duration.
RxOkCallback m_rxOkCallback
receive OK callback
void SwitchFromRxAbort(void)
Abort current reception.
TracedCallback< Ptr< const Packet >, double, WifiMode, WifiPreamble > m_rxOkTrace
receive OK trace callback
bool IsStateSwitching(void) const
Check whether the current state is SWITCHING.
RxErrorCallback m_rxErrorCallback
receive error callback
void NotifyOff(void)
Notify all WifiPhyListener that we are going to switch off.
TracedCallback< Ptr< const Packet >, double > m_rxErrorTrace
receive error trace callback
Time m_startCcaBusy
start CCA busy
void NotifyTxStart(Time duration, double txPowerDbm)
Notify all WifiPhyListener that the transmission has started for the given duration.
Listeners m_listeners
listeners
static TypeId GetTypeId(void)
Get the type ID.
void SwitchToOff(void)
Switch to off mode.
void SwitchFromRxEndError(Ptr< WifiPsdu > psdu, double snr)
Switch from RX after the reception failed.
void SetReceiveOkCallback(RxOkCallback callback)
Set a callback for a successful reception.
void SwitchMaybeToCcaBusy(Time duration)
Switch to CCA busy.
void SwitchToSleep(void)
Switch to sleep mode.
bool IsStateIdle(void) const
Check whether the current state is IDLE.
void NotifyRxEndError(void)
Notify all WifiPhyListener that the reception was not successful.
void SetReceiveErrorCallback(RxErrorCallback callback)
Set a callback for a failed reception.
void UnregisterListener(WifiPhyListener *listener)
Remove WifiPhyListener from this WifiPhyStateHelper.
void NotifySleep(void)
Notify all WifiPhyListener that we are going to sleep.
void NotifyWakeup(void)
Notify all WifiPhyListener that we woke up.
void NotifyMaybeCcaBusyStart(Time duration)
Notify all WifiPhyListener that the CCA has started for the given duration.
Ptr< const Packet > GetPacket(void) const
Get the PSDU as a single packet.
Definition: wifi-psdu.cc:87
This class mimics the TXVECTOR which is to be passed to the PHY in order to define the parameters whi...
WifiMode GetMode(uint16_t staId=SU_STA_ID) const
If this TX vector is associated with an SU PPDU, return the selected payload transmission mode.
uint8_t GetTxPowerLevel(void) const
WifiPreamble GetPreambleType(void) const
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition: assert.h:67
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
Definition: fatal-error.h:165
int64x64_t Max(const int64x64_t &a, const int64x64_t &b)
Maximum.
Definition: int64x64.h:230
int64x64_t Abs(const int64x64_t &value)
Absolute value.
Definition: int64x64.h:205
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:205
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition: object-base.h:45
Time MicroSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1260
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1244
Ptr< const TraceSourceAccessor > MakeTraceSourceAccessor(T a)
Create a TraceSourceAccessor which will control access to the underlying trace source.
Every class exported by the ns3 library is enclosed in the ns3 namespace.
std::unordered_map< uint16_t, Ptr< const WifiPsdu > > WifiConstPsduMap
Map of const PSDUs indexed by STA-ID.
RxSignalInfo structure containing info on the received signal.
Definition: phy-entity.h:67
double snr
SNR in linear scale.
Definition: phy-entity.h:68
WifiPhyState
The state of the PHY layer.
@ CCA_BUSY
The PHY layer has sense the medium busy through the CCA mechanism.
@ SWITCHING
The PHY layer is switching to other channel.
@ RX
The PHY layer is receiving a packet.
@ TX
The PHY layer is sending a packet.
@ OFF
The PHY layer is switched off.
@ SLEEP
The PHY layer is sleeping.
@ IDLE
The PHY layer is IDLE.