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 
29 namespace ns3 {
30 
31 NS_LOG_COMPONENT_DEFINE ("WifiPhyStateHelper");
32 
33 NS_OBJECT_ENSURE_REGISTERED (WifiPhyStateHelper);
34 
35 TypeId
37 {
38  static TypeId tid = TypeId ("ns3::WifiPhyStateHelper")
39  .SetParent<Object> ()
40  .SetGroupName ("Wifi")
41  .AddConstructor<WifiPhyStateHelper> ()
42  .AddTraceSource ("State",
43  "The state of the PHY layer",
45  "ns3::WifiPhyStateHelper::StateTracedCallback")
46  .AddTraceSource ("RxOk",
47  "A packet has been received successfully.",
49  "ns3::WifiPhyStateHelper::RxOkTracedCallback")
50  .AddTraceSource ("RxError",
51  "A packet has been received unsuccessfully.",
53  "ns3::WifiPhyStateHelper::RxEndErrorTracedCallback")
54  .AddTraceSource ("Tx", "Packet transmission is starting.",
56  "ns3::WifiPhyStateHelper::TxTracedCallback")
57  ;
58  return tid;
59 }
60 
62  : m_sleeping (false),
63  m_isOff (false),
64  m_endTx (Seconds (0)),
65  m_endRx (Seconds (0)),
66  m_endCcaBusy (Seconds (0)),
67  m_endSwitching (Seconds (0)),
68  m_startTx (Seconds (0)),
69  m_startRx (Seconds (0)),
70  m_startCcaBusy (Seconds (0)),
71  m_startSwitching (Seconds (0)),
72  m_startSleep (Seconds (0)),
73  m_previousStateChangeTime (Seconds (0))
74 {
75  NS_LOG_FUNCTION (this);
76 }
77 
78 void
80 {
81  m_rxOkCallback = callback;
82 }
83 
84 void
86 {
87  m_rxErrorCallback = callback;
88 }
89 
90 void
92 {
93  m_listeners.push_back (listener);
94 }
95 
96 void
98 {
99  ListenersI i = find (m_listeners.begin (), m_listeners.end (), listener);
100  if (i != m_listeners.end ())
101  {
102  m_listeners.erase (i);
103  }
104 }
105 
106 bool
108 {
109  return (GetState () == WifiPhyState::IDLE);
110 }
111 
112 bool
114 {
115  return (GetState () == WifiPhyState::CCA_BUSY);
116 }
117 
118 bool
120 {
121  return (GetState () == WifiPhyState::RX);
122 }
123 
124 bool
126 {
127  return (GetState () == WifiPhyState::TX);
128 }
129 
130 bool
132 {
133  return (GetState () == WifiPhyState::SWITCHING);
134 }
135 
136 bool
138 {
139  return (GetState () == WifiPhyState::SLEEP);
140 }
141 
142 bool
144 {
145  return (GetState () == WifiPhyState::OFF);
146 }
147 
148 Time
150 {
151  Time retval;
152 
153  switch (GetState ())
154  {
155  case WifiPhyState::RX:
156  retval = m_endRx - Simulator::Now ();
157  break;
158  case WifiPhyState::TX:
159  retval = m_endTx - Simulator::Now ();
160  break;
162  retval = m_endCcaBusy - Simulator::Now ();
163  break;
165  retval = m_endSwitching - Simulator::Now ();
166  break;
167  case WifiPhyState::IDLE:
168  retval = Seconds (0);
169  break;
170  case WifiPhyState::SLEEP:
171  NS_FATAL_ERROR ("Cannot determine when the device will wake up.");
172  retval = Seconds (0);
173  break;
174  case WifiPhyState::OFF:
175  NS_FATAL_ERROR ("Cannot determine when the device will be switched on.");
176  retval = Seconds (0);
177  break;
178  default:
179  NS_FATAL_ERROR ("Invalid WifiPhy state.");
180  retval = Seconds (0);
181  break;
182  }
183  retval = Max (retval, Seconds (0));
184  return retval;
185 }
186 
187 Time
189 {
190  return m_startRx;
191 }
192 
195 {
196  if (m_isOff)
197  {
198  return WifiPhyState::OFF;
199  }
200  if (m_sleeping)
201  {
202  return WifiPhyState::SLEEP;
203  }
204  else if (m_endTx > Simulator::Now ())
205  {
206  return WifiPhyState::TX;
207  }
208  else if (m_endRx > Simulator::Now ())
209  {
210  return WifiPhyState::RX;
211  }
212  else if (m_endSwitching > Simulator::Now ())
213  {
215  }
216  else if (m_endCcaBusy > Simulator::Now ())
217  {
218  return WifiPhyState::CCA_BUSY;
219  }
220  else
221  {
222  return WifiPhyState::IDLE;
223  }
224 }
225 
226 void
227 WifiPhyStateHelper::NotifyTxStart (Time duration, double txPowerDbm)
228 {
229  NS_LOG_FUNCTION (this);
230  for (Listeners::const_iterator i = m_listeners.begin (); i != m_listeners.end (); i++)
231  {
232  (*i)->NotifyTxStart (duration, txPowerDbm);
233  }
234 }
235 
236 void
238 {
239  NS_LOG_FUNCTION (this);
240  for (Listeners::const_iterator i = m_listeners.begin (); i != m_listeners.end (); i++)
241  {
242  (*i)->NotifyRxStart (duration);
243  }
244 }
245 
246 void
248 {
249  NS_LOG_FUNCTION (this);
250  for (Listeners::const_iterator i = m_listeners.begin (); i != m_listeners.end (); i++)
251  {
252  (*i)->NotifyRxEndOk ();
253  }
254 }
255 
256 void
258 {
259  NS_LOG_FUNCTION (this);
260  for (Listeners::const_iterator i = m_listeners.begin (); i != m_listeners.end (); i++)
261  {
262  (*i)->NotifyRxEndError ();
263  }
264 }
265 
266 void
268 {
269  NS_LOG_FUNCTION (this);
270  for (Listeners::const_iterator i = m_listeners.begin (); i != m_listeners.end (); i++)
271  {
272  (*i)->NotifyMaybeCcaBusyStart (duration);
273  }
274 }
275 
276 void
278 {
279  NS_LOG_FUNCTION (this);
280  for (Listeners::const_iterator i = m_listeners.begin (); i != m_listeners.end (); i++)
281  {
282  (*i)->NotifySwitchingStart (duration);
283  }
284 }
285 
286 void
288 {
289  NS_LOG_FUNCTION (this);
290  for (Listeners::const_iterator i = m_listeners.begin (); i != m_listeners.end (); i++)
291  {
292  (*i)->NotifySleep ();
293  }
294 }
295 
296 void
298 {
299  NS_LOG_FUNCTION (this);
300  for (Listeners::const_iterator i = m_listeners.begin (); i != m_listeners.end (); i++)
301  {
302  (*i)->NotifyOff ();
303  }
304 }
305 
306 void
308 {
309  NS_LOG_FUNCTION (this);
310  for (Listeners::const_iterator i = m_listeners.begin (); i != m_listeners.end (); i++)
311  {
312  (*i)->NotifyWakeup ();
313  }
314 }
315 
316 void
318 {
319  NS_LOG_FUNCTION (this);
320  for (Listeners::const_iterator i = m_listeners.begin (); i != m_listeners.end (); i++)
321  {
322  (*i)->NotifyOn ();
323  }
324 }
325 
326 void
328 {
329  NS_LOG_FUNCTION (this);
330  Time now = Simulator::Now ();
331  Time idleStart = Max (m_endCcaBusy, m_endRx);
332  idleStart = Max (idleStart, m_endTx);
333  idleStart = Max (idleStart, m_endSwitching);
334  NS_ASSERT (idleStart <= now);
335  if (m_endCcaBusy > m_endRx
337  && m_endCcaBusy > m_endTx)
338  {
339  Time ccaBusyStart = Max (m_endTx, m_endRx);
340  ccaBusyStart = Max (ccaBusyStart, m_startCcaBusy);
341  ccaBusyStart = Max (ccaBusyStart, m_endSwitching);
342  m_stateLogger (ccaBusyStart, idleStart - ccaBusyStart, WifiPhyState::CCA_BUSY);
343  }
344  m_stateLogger (idleStart, now - idleStart, WifiPhyState::IDLE);
345 }
346 
347 void
348 WifiPhyStateHelper::SwitchToTx (Time txDuration, Ptr<const Packet> packet, double txPowerDbm,
349  WifiTxVector txVector)
350 {
351  NS_LOG_FUNCTION (this << txDuration << packet << txPowerDbm << txVector);
352  m_txTrace (packet, txVector.GetMode (), txVector.GetPreambleType (), txVector.GetTxPowerLevel ());
353  Time now = Simulator::Now ();
354  switch (GetState ())
355  {
356  case WifiPhyState::RX:
357  /* The packet which is being received as well
358  * as its endRx event are cancelled by the caller.
359  */
361  m_endRx = now;
362  break;
364  {
365  Time ccaStart = Max (m_endRx, m_endTx);
366  ccaStart = Max (ccaStart, m_startCcaBusy);
367  ccaStart = Max (ccaStart, m_endSwitching);
368  m_stateLogger (ccaStart, now - ccaStart, WifiPhyState::CCA_BUSY);
369  } break;
370  case WifiPhyState::IDLE:
372  break;
373  default:
374  NS_FATAL_ERROR ("Invalid WifiPhy state.");
375  break;
376  }
377  m_stateLogger (now, txDuration, WifiPhyState::TX);
379  m_endTx = now + txDuration;
380  m_startTx = now;
381  NotifyTxStart (txDuration, txPowerDbm);
382 }
383 
384 void
386 {
387  NS_LOG_FUNCTION (this << rxDuration);
389  Time now = Simulator::Now ();
390  switch (GetState ())
391  {
392  case WifiPhyState::IDLE:
394  break;
396  {
397  Time ccaStart = Max (m_endRx, m_endTx);
398  ccaStart = Max (ccaStart, m_startCcaBusy);
399  ccaStart = Max (ccaStart, m_endSwitching);
400  m_stateLogger (ccaStart, now - ccaStart, WifiPhyState::CCA_BUSY);
401  } break;
402  default:
403  NS_FATAL_ERROR ("Invalid WifiPhy state " << GetState ());
404  break;
405  }
407  m_startRx = now;
408  m_endRx = now + rxDuration;
409  NotifyRxStart (rxDuration);
410  NS_ASSERT (IsStateRx ());
411 }
412 
413 void
415 {
416  NS_LOG_FUNCTION (this << switchingDuration);
417  Time now = Simulator::Now ();
418  switch (GetState ())
419  {
420  case WifiPhyState::RX:
421  /* The packet which is being received as well
422  * as its endRx event are cancelled by the caller.
423  */
425  m_endRx = now;
426  break;
428  {
429  Time ccaStart = Max (m_endRx, m_endTx);
430  ccaStart = Max (ccaStart, m_startCcaBusy);
431  ccaStart = Max (ccaStart, m_endSwitching);
432  m_stateLogger (ccaStart, now - ccaStart, WifiPhyState::CCA_BUSY);
433  } break;
434  case WifiPhyState::IDLE:
436  break;
437  default:
438  NS_FATAL_ERROR ("Invalid WifiPhy state.");
439  break;
440  }
441 
442  if (now < m_endCcaBusy)
443  {
444  m_endCcaBusy = now;
445  }
446 
447  m_stateLogger (now, switchingDuration, WifiPhyState::SWITCHING);
449  m_startSwitching = now;
450  m_endSwitching = now + switchingDuration;
451  NotifySwitchingStart (switchingDuration);
453 }
454 
455 void
456 WifiPhyStateHelper::SwitchFromRxEndOk (Ptr<Packet> packet, double snr, WifiTxVector txVector, std::vector<bool> statusPerMpdu)
457 {
458  NS_LOG_FUNCTION (this << packet << snr << txVector << statusPerMpdu.size () <<
459  std::all_of(statusPerMpdu.begin(), statusPerMpdu.end(), [](bool v) { return v; })); //returns true if all true
460  NS_ASSERT (statusPerMpdu.size () != 0);
462  m_rxOkTrace (packet, snr, txVector.GetMode (), txVector.GetPreambleType ());
463  NotifyRxEndOk ();
464  DoSwitchFromRx ();
465  if (!m_rxOkCallback.IsNull ())
466  {
467  m_rxOkCallback (packet, snr, txVector, statusPerMpdu);
468  }
469 
470 }
471 
472 void
474 {
475  NS_LOG_FUNCTION (this << packet << snr);
477  m_rxErrorTrace (packet, snr);
478  NotifyRxEndError ();
479  DoSwitchFromRx ();
480  if (!m_rxErrorCallback.IsNull ())
481  {
482  m_rxErrorCallback (packet);
483  }
484 }
485 
486 void
488 {
489  NS_LOG_FUNCTION (this);
490  Time now = Simulator::Now ();
493  m_endRx = Simulator::Now ();
495 }
496 
497 void
499 {
500  NS_LOG_FUNCTION (this << duration);
501  if (GetState () != WifiPhyState::RX)
502  {
503  NotifyMaybeCcaBusyStart (duration);
504  }
505  Time now = Simulator::Now ();
506  m_endCcaBusy = std::max (m_endCcaBusy, now + duration);
507  switch (GetState ())
508  {
509  case WifiPhyState::IDLE:
511  break;
512  case WifiPhyState::RX:
513  return;
514  default:
515  break;
516  }
518  {
519  m_startCcaBusy = now;
520  }
521  m_stateLogger (now, duration, WifiPhyState::CCA_BUSY);
522 }
523 
524 void
526 {
527  NS_LOG_FUNCTION (this);
528  Time now = Simulator::Now ();
529  switch (GetState ())
530  {
531  case WifiPhyState::IDLE:
533  break;
535  {
536  Time ccaStart = Max (m_endRx, m_endTx);
537  ccaStart = Max (ccaStart, m_startCcaBusy);
538  ccaStart = Max (ccaStart, m_endSwitching);
539  m_stateLogger (ccaStart, now - ccaStart, WifiPhyState::CCA_BUSY);
540  } break;
541  default:
542  NS_FATAL_ERROR ("Invalid WifiPhy state.");
543  break;
544  }
546  m_sleeping = true;
547  m_startSleep = now;
548  NotifySleep ();
549  NS_ASSERT (IsStateSleep ());
550 }
551 
552 void
554 {
555  NS_LOG_FUNCTION (this << duration);
556  NS_ASSERT (IsStateSleep ());
557  Time now = Simulator::Now ();
560  m_sleeping = false;
561  NotifyWakeup ();
562  //update m_endCcaBusy after the sleep period
563  m_endCcaBusy = std::max (m_endCcaBusy, now + duration);
564  if (m_endCcaBusy > now)
565  {
567  }
568 }
569 
570 void
572 {
573  NS_LOG_FUNCTION (this);
574  NS_ASSERT (IsStateRx ());
575  if (failure)
576  {
577  NotifyRxEndError ();
578  }
579  else
580  {
581  NotifyRxEndOk ();
582  }
583  DoSwitchFromRx ();
584  NS_ASSERT (!IsStateRx ());
585 }
586 
587 void
589 {
590  NS_LOG_FUNCTION (this);
591  Time now = Simulator::Now ();
592  switch (GetState ())
593  {
594  case WifiPhyState::RX:
595  /* The packet which is being received as well
596  * as its endRx event are cancelled by the caller.
597  */
599  m_endRx = now;
600  break;
601  case WifiPhyState::TX:
602  /* The packet which is being transmitted as well
603  * as its endTx event are cancelled by the caller.
604  */
606  m_endTx = now;
607  break;
608  case WifiPhyState::IDLE:
610  break;
612  {
613  Time ccaStart = Max (m_endRx, m_endTx);
614  ccaStart = Max (ccaStart, m_startCcaBusy);
615  ccaStart = Max (ccaStart, m_endSwitching);
616  m_stateLogger (ccaStart, now - ccaStart, WifiPhyState::CCA_BUSY);
617  } break;
618  default:
619  NS_FATAL_ERROR ("Invalid WifiPhy state.");
620  break;
621  }
623  m_isOff = true;
624  NotifyOff ();
625  NS_ASSERT (IsStateOff ());
626 }
627 
628 void
630 {
631  NS_LOG_FUNCTION (this << duration);
632  NS_ASSERT (IsStateOff ());
633  Time now = Simulator::Now ();
635  m_isOff = false;
636  NotifyOn ();
637  //update m_endCcaBusy after the off period
638  m_endCcaBusy = std::max (m_endCcaBusy, now + duration);
639  if (m_endCcaBusy > now)
640  {
642  }
643 }
644 
645 } //namespace ns3
bool IsStateIdle(void) const
Check whether the current state is IDLE.
Time GetLastRxStartTime(void) const
Return the time the last RX start.
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:102
void DoSwitchFromRx(void)
Switch the state from RX.
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by "...
void SwitchFromRxEndOk(Ptr< Packet > packet, double snr, WifiTxVector txVector, std::vector< bool > statusPerMpdu)
Switch from RX after the reception was successful.
This class mimics the TXVECTOR which is to be passed to the PHY in order to define the parameters whi...
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition: object-base.h:45
TracedCallback< Time, Time, WifiPhyState > m_stateLogger
The trace source fired when state is changed.
void NotifyWakeup(void)
Notify all WifiPhyListener that we woke up.
Time m_endCcaBusy
endn CCA busy
The PHY layer is sleeping.
Time m_startCcaBusy
start CCA busy
void SwitchToOff(void)
Switch to off mode.
void SwitchToChannelSwitching(Time switchingDuration)
Switch state to channel switching for the given duration.
void UnregisterListener(WifiPhyListener *listener)
Remove WifiPhyListener from this WifiPhyStateHelper.
#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
void NotifyRxEndError(void)
Notify all WifiPhyListener that the reception was not successful.
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:204
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
Definition: fatal-error.h:162
std::vector< WifiPhyListener * >::iterator ListenersI
typedef for a list of WifiPhyListeners iterator
bool IsStateRx(void) const
Check whether the current state is RX.
bool IsStateSwitching(void) const
Check whether the current state is SWITCHING.
void SwitchFromSleep(Time duration)
Switch from sleep mode.
Time GetDelayUntilIdle(void) const
Return the time before the state is back to IDLE.
Ptr< const TraceSourceAccessor > MakeTraceSourceAccessor(T a)
Create a TraceSourceAccessor which will control access to the underlying trace source.
WifiPreamble GetPreambleType(void) const
void NotifySleep(void)
Notify all WifiPhyListener that we are going to sleep.
Time m_endSwitching
end switching
#define max(a, b)
Definition: 80211b.c:43
bool IsStateSleep(void) const
Check whether the current state is SLEEP.
void NotifyOn(void)
Notify all WifiPhyListener that we are going to switch on.
receive notifications about phy events.
void NotifySwitchingStart(Time duration)
Notify all WifiPhyListener that we are switching channel with the given channel switching delay...
void SwitchFromRxEndError(Ptr< Packet > packet, double snr)
Switch from RX after the reception failed.
int64x64_t Max(const int64x64_t &a, const int64x64_t &b)
Maximum.
Definition: int64x64.h:209
WifiMode GetMode(void) const
The PHY layer has sense the medium busy through the CCA mechanism.
Time m_previousStateChangeTime
previous state change time
TracedCallback< Ptr< const Packet >, double, WifiMode, WifiPreamble > m_rxOkTrace
receive OK trace callback
void NotifyMaybeCcaBusyStart(Time duration)
Notify all WifiPhyListener that the CCA has started for the given duration.
RxErrorCallback m_rxErrorCallback
receive error callback
bool IsStateTx(void) const
Check whether the current state is TX.
void SwitchToTx(Time txDuration, Ptr< const Packet > packet, double txPowerDbm, WifiTxVector txVector)
Switch state to TX for the given duration.
void SwitchToSleep(void)
Switch to sleep mode.
Every class exported by the ns3 library is enclosed in the ns3 namespace.
The PHY layer is IDLE.
WifiPhyState
The state of the PHY layer.
Time m_startSwitching
start switching
void SetReceiveOkCallback(RxOkCallback callback)
Set a callback for a successful reception.
void SwitchFromRxAbort(bool failure)
Abort current reception.
Time m_startTx
start transmit
void NotifyTxStart(Time duration, double txPowerDbm)
Notify all WifiPhyListener that the transmission has started for the given duration.
static Time Now(void)
Return the current simulation virtual time.
Definition: simulator.cc:193
void NotifyRxEndOk(void)
Notify all WifiPhyListener that the reception was successful.
TracedCallback< Ptr< const Packet >, WifiMode, WifiPreamble, uint8_t > m_txTrace
transmit trace callback
static TypeId GetTypeId(void)
Get the type ID.
This objects implements the PHY state machine of the Wifi device.
WifiPhyState GetState(void) const
Return the current state of WifiPhy.
The PHY layer is sending a packet.
void SwitchFromOff(Time duration)
Switch from off mode.
Listeners m_listeners
listeners
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1062
The PHY layer is receiving a packet.
bool IsStateOff(void) const
Check whether the current state is OFF.
void SetReceiveErrorCallback(RxErrorCallback callback)
Set a callback for a failed reception.
The PHY layer is switched off.
uint8_t GetTxPowerLevel(void) const
TracedCallback< Ptr< const Packet >, double > m_rxErrorTrace
receive error trace callback
The PHY layer is switching to other channel.
A base class which provides memory management and object aggregation.
Definition: object.h:87
void SwitchToRx(Time rxDuration)
Switch state to RX for the given duration.
void LogPreviousIdleAndCcaBusyStates(void)
Log the ideal and CCA states.
bool IsNull(void) const
Check for null implementation.
Definition: callback.h:1270
void NotifyRxStart(Time duration)
Notify all WifiPhyListener that the reception has started for the given duration. ...
a unique identifier for an interface.
Definition: type-id.h:58
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:915
void RegisterListener(WifiPhyListener *listener)
Register WifiPhyListener to this WifiPhyStateHelper.
void SwitchMaybeToCcaBusy(Time duration)
Switch to CCA busy.
RxOkCallback m_rxOkCallback
receive OK callback
void NotifyOff(void)
Notify all WifiPhyListener that we are going to switch off.
bool IsStateCcaBusy(void) const
Check whether the current state is CCA busy.