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 "wifi-phy-state-helper.h"
22 #include "wifi-tx-vector.h"
23 #include "ns3/log.h"
24 #include "ns3/simulator.h"
25 #include "ns3/packet.h"
26 #include <algorithm>
27 
28 namespace ns3 {
29 
30 NS_LOG_COMPONENT_DEFINE ("WifiPhyStateHelper");
31 
32 NS_OBJECT_ENSURE_REGISTERED (WifiPhyStateHelper);
33 
34 TypeId
36 {
37  static TypeId tid = TypeId ("ns3::WifiPhyStateHelper")
38  .SetParent<Object> ()
39  .SetGroupName ("Wifi")
40  .AddConstructor<WifiPhyStateHelper> ()
41  .AddTraceSource ("State",
42  "The state of the PHY layer",
44  "ns3::WifiPhyStateHelper::StateTracedCallback")
45  .AddTraceSource ("RxOk",
46  "A packet has been received successfully.",
48  "ns3::WifiPhyStateHelper::RxOkTracedCallback")
49  .AddTraceSource ("RxError",
50  "A packet has been received unsuccessfully.",
52  "ns3::WifiPhyStateHelper::RxEndErrorTracedCallback")
53  .AddTraceSource ("Tx", "Packet transmission is starting.",
55  "ns3::WifiPhyStateHelper::TxTracedCallback")
56  ;
57  return tid;
58 }
59 
61  : m_rxing (false),
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_rxing)
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  */
360  m_rxing = false;
362  m_endRx = now;
363  break;
365  {
366  Time ccaStart = Max (m_endRx, m_endTx);
367  ccaStart = Max (ccaStart, m_startCcaBusy);
368  ccaStart = Max (ccaStart, m_endSwitching);
369  m_stateLogger (ccaStart, now - ccaStart, WifiPhyState::CCA_BUSY);
370  } break;
371  case WifiPhyState::IDLE:
373  break;
374  default:
375  NS_FATAL_ERROR ("Invalid WifiPhy state.");
376  break;
377  }
378  m_stateLogger (now, txDuration, WifiPhyState::TX);
380  m_endTx = now + txDuration;
381  m_startTx = now;
382  NotifyTxStart (txDuration, txPowerDbm);
383 }
384 
385 void
387 {
388  NS_LOG_FUNCTION (this << rxDuration);
390  NS_ASSERT (!m_rxing);
391  Time now = Simulator::Now ();
392  switch (GetState ())
393  {
394  case WifiPhyState::IDLE:
396  break;
398  {
399  Time ccaStart = Max (m_endRx, m_endTx);
400  ccaStart = Max (ccaStart, m_startCcaBusy);
401  ccaStart = Max (ccaStart, m_endSwitching);
402  m_stateLogger (ccaStart, now - ccaStart, WifiPhyState::CCA_BUSY);
403  } break;
404  default:
405  NS_FATAL_ERROR ("Invalid WifiPhy state.");
406  break;
407  }
409  m_rxing = true;
410  m_startRx = now;
411  m_endRx = now + rxDuration;
412  NotifyRxStart (rxDuration);
413  NS_ASSERT (IsStateRx ());
414 }
415 
416 void
418 {
419  NS_LOG_FUNCTION (this << switchingDuration);
420  Time now = Simulator::Now ();
421  switch (GetState ())
422  {
423  case WifiPhyState::RX:
424  /* The packet which is being received as well
425  * as its endRx event are cancelled by the caller.
426  */
427  m_rxing = false;
429  m_endRx = now;
430  break;
432  {
433  Time ccaStart = Max (m_endRx, m_endTx);
434  ccaStart = Max (ccaStart, m_startCcaBusy);
435  ccaStart = Max (ccaStart, m_endSwitching);
436  m_stateLogger (ccaStart, now - ccaStart, WifiPhyState::CCA_BUSY);
437  } break;
438  case WifiPhyState::IDLE:
440  break;
441  default:
442  NS_FATAL_ERROR ("Invalid WifiPhy state.");
443  break;
444  }
445 
446  if (now < m_endCcaBusy)
447  {
448  m_endCcaBusy = now;
449  }
450 
451  m_stateLogger (now, switchingDuration, WifiPhyState::SWITCHING);
453  m_startSwitching = now;
454  m_endSwitching = now + switchingDuration;
455  NotifySwitchingStart (switchingDuration);
457 }
458 
459 void
461 {
462  NS_LOG_FUNCTION (this << packet << snr << txVector);
463  m_rxOkTrace (packet, snr, txVector.GetMode (), txVector.GetPreambleType ());
464  NotifyRxEndOk ();
465  DoSwitchFromRx ();
466  if (!m_rxOkCallback.IsNull ())
467  {
468  m_rxOkCallback (packet, snr, txVector);
469  }
470 
471 }
472 
473 void
475 {
476  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, snr);
483  }
484 }
485 
486 void
488 {
489  NS_LOG_FUNCTION (this);
490  NS_ASSERT (IsStateRx ());
491  NS_ASSERT (m_rxing);
492 
493  Time now = Simulator::Now ();
496  m_rxing = false;
497 
499 }
500 
501 void
503 {
504  NS_LOG_FUNCTION (this << duration);
505  NotifyMaybeCcaBusyStart (duration);
506  Time now = Simulator::Now ();
507  switch (GetState ())
508  {
509  case WifiPhyState::IDLE:
511  break;
512  default:
513  break;
514  }
516  {
517  m_startCcaBusy = now;
518  }
519  m_endCcaBusy = std::max (m_endCcaBusy, now + duration);
520 }
521 
522 void
524 {
525  NS_LOG_FUNCTION (this);
526  Time now = Simulator::Now ();
527  switch (GetState ())
528  {
529  case WifiPhyState::IDLE:
531  break;
533  {
534  Time ccaStart = Max (m_endRx, m_endTx);
535  ccaStart = Max (ccaStart, m_startCcaBusy);
536  ccaStart = Max (ccaStart, m_endSwitching);
537  m_stateLogger (ccaStart, now - ccaStart, WifiPhyState::CCA_BUSY);
538  } break;
539  default:
540  NS_FATAL_ERROR ("Invalid WifiPhy state.");
541  break;
542  }
544  m_sleeping = true;
545  m_startSleep = now;
546  NotifySleep ();
547  NS_ASSERT (IsStateSleep ());
548 }
549 
550 void
552 {
553  NS_LOG_FUNCTION (this << duration);
554  NS_ASSERT (IsStateSleep ());
555  Time now = Simulator::Now ();
558  m_sleeping = false;
559  NotifyWakeup ();
560  //update m_endCcaBusy after the sleep period
561  m_endCcaBusy = std::max (m_endCcaBusy, now + duration);
562  if (m_endCcaBusy > now)
563  {
565  }
566 }
567 
568 void
570 {
571  NS_LOG_FUNCTION (this);
572  NS_ASSERT (IsStateRx ());
573  NS_ASSERT (m_rxing);
574  m_endRx = Simulator::Now ();
575  DoSwitchFromRx ();
576  NS_ASSERT (!IsStateRx ());
577 }
578 
579 void
581 {
582  NS_LOG_FUNCTION (this);
583  Time now = Simulator::Now ();
584  switch (GetState ())
585  {
586  case WifiPhyState::RX:
587  /* The packet which is being received as well
588  * as its endRx event are cancelled by the caller.
589  */
590  m_rxing = false;
592  m_endRx = now;
593  break;
594  case WifiPhyState::TX:
595  /* The packet which is being transmitted as well
596  * as its endTx event are cancelled by the caller.
597  */
599  m_endTx = now;
600  break;
601  case WifiPhyState::IDLE:
603  break;
605  {
606  Time ccaStart = Max (m_endRx, m_endTx);
607  ccaStart = Max (ccaStart, m_startCcaBusy);
608  ccaStart = Max (ccaStart, m_endSwitching);
609  m_stateLogger (ccaStart, now - ccaStart, WifiPhyState::CCA_BUSY);
610  } break;
611  default:
612  NS_FATAL_ERROR ("Invalid WifiPhy state.");
613  break;
614  }
616  m_isOff = true;
617  NotifyOff ();
618  NS_ASSERT (IsStateOff ());
619 }
620 
621 void
623 {
624  NS_LOG_FUNCTION (this << duration);
625  NS_ASSERT (IsStateOff ());
626  Time now = Simulator::Now ();
628  m_isOff = false;
629  NotifyOn ();
630  //update m_endCcaBusy after the off period
631  m_endCcaBusy = std::max (m_endCcaBusy, now + duration);
632  if (m_endCcaBusy > now)
633  {
635  }
636 }
637 
638 } //namespace ns3
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 "...
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
bool IsStateIdle(void) const
Check whether the current state is IDLE.
void SwitchToOff(void)
Switch to off mode.
bool IsNull(void) const
Check for null implementation.
Definition: callback.h:1270
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:201
void SwitchFromRxAbort(void)
Abort current reception.
#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
void SwitchFromSleep(Time duration)
Switch from sleep mode.
uint8_t GetTxPowerLevel(void) const
Ptr< const TraceSourceAccessor > MakeTraceSourceAccessor(T a)
Create a TraceSourceAccessor which will control access to the underlying trace source.
void NotifySleep(void)
Notify all WifiPhyListener that we are going to sleep.
bool IsStateOff(void) const
Check whether the current state is OFF.
Time m_endSwitching
end switching
#define max(a, b)
Definition: 80211b.c:45
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...
bool IsStateSleep(void) const
Check whether the current state is SLEEP.
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
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
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.
bool IsStateTx(void) const
Check whether the current state is TX.
Time m_startSwitching
start switching
bool IsStateSwitching(void) const
Check whether the current state is SWITCHING.
void SetReceiveOkCallback(RxOkCallback callback)
Set a callback for a successful reception.
WifiPhyState GetState(void) const
Return the current state of WifiPhy.
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:249
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.
WifiPreamble GetPreambleType(void) const
This objects implements the PHY state machine of the Wifi device.
The PHY layer is sending a packet.
bool IsStateRx(void) const
Check whether the current state is RX.
void SwitchFromRxEndOk(Ptr< Packet > packet, double snr, WifiTxVector txVector)
Switch from RX after the reception was successful.
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:1007
The PHY layer is receiving a packet.
void SetReceiveErrorCallback(RxErrorCallback callback)
Set a callback for a failed reception.
The PHY layer is switched off.
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.
Time GetLastRxStartTime(void) const
Return the time the last RX start.
bool IsStateCcaBusy(void) const
Check whether the current state is CCA busy.
WifiMode GetMode(void) const
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:914
void RegisterListener(WifiPhyListener *listener)
Register WifiPhyListener to this WifiPhyStateHelper.
Time GetDelayUntilIdle(void) const
Return the time before the state is back to IDLE.
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.