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 "ns3/log.h"
23 #include "ns3/simulator.h"
24 #include <algorithm>
25 
26 namespace ns3 {
27 
28 NS_LOG_COMPONENT_DEFINE ("WifiPhyStateHelper");
29 
30 NS_OBJECT_ENSURE_REGISTERED (WifiPhyStateHelper);
31 
32 TypeId
34 {
35  static TypeId tid = TypeId ("ns3::WifiPhyStateHelper")
36  .SetParent<Object> ()
37  .SetGroupName ("Wifi")
38  .AddConstructor<WifiPhyStateHelper> ()
39  .AddTraceSource ("State",
40  "The state of the PHY layer",
42  "ns3::WifiPhyStateHelper::StateTracedCallback")
43  .AddTraceSource ("RxOk",
44  "A packet has been received successfully.",
46  "ns3::WifiPhyStateHelper::RxOkTracedCallback")
47  .AddTraceSource ("RxError",
48  "A packet has been received unsuccessfully.",
50  "ns3::WifiPhyStateHelper::RxEndErrorTracedCallback")
51  .AddTraceSource ("Tx", "Packet transmission is starting.",
53  "ns3::WifiPhyStateHelper::TxTracedCallback")
54  ;
55  return tid;
56 }
57 
59  : m_rxing (false),
60  m_sleeping (false),
61  m_endTx (Seconds (0)),
62  m_endRx (Seconds (0)),
63  m_endCcaBusy (Seconds (0)),
64  m_endSwitching (Seconds (0)),
65  m_startTx (Seconds (0)),
66  m_startRx (Seconds (0)),
67  m_startCcaBusy (Seconds (0)),
68  m_startSwitching (Seconds (0)),
69  m_startSleep (Seconds (0)),
70  m_previousStateChangeTime (Seconds (0))
71 {
72  NS_LOG_FUNCTION (this);
73 }
74 
75 void
77 {
78  m_rxOkCallback = callback;
79 }
80 
81 void
83 {
84  m_rxErrorCallback = callback;
85 }
86 
87 void
89 {
90  m_listeners.push_back (listener);
91 }
92 
93 void
95 {
96  ListenersI i = find (m_listeners.begin (), m_listeners.end (), listener);
97  if (i != m_listeners.end ())
98  {
99  m_listeners.erase (i);
100  }
101 }
102 
103 bool
105 {
106  return (GetState () == WifiPhy::IDLE);
107 }
108 
109 bool
111 {
112  return (GetState () != WifiPhy::IDLE);
113 }
114 
115 bool
117 {
118  return (GetState () == WifiPhy::CCA_BUSY);
119 }
120 
121 bool
123 {
124  return (GetState () == WifiPhy::RX);
125 }
126 
127 bool
129 {
130  return (GetState () == WifiPhy::TX);
131 }
132 
133 bool
135 {
136  return (GetState () == WifiPhy::SWITCHING);
137 }
138 
139 bool
141 {
142  return (GetState () == WifiPhy::SLEEP);
143 }
144 
145 Time
147 {
149 }
150 
151 Time
153 {
154  Time retval;
155 
156  switch (GetState ())
157  {
158  case WifiPhy::RX:
159  retval = m_endRx - Simulator::Now ();
160  break;
161  case WifiPhy::TX:
162  retval = m_endTx - Simulator::Now ();
163  break;
164  case WifiPhy::CCA_BUSY:
165  retval = m_endCcaBusy - Simulator::Now ();
166  break;
167  case WifiPhy::SWITCHING:
168  retval = m_endSwitching - Simulator::Now ();
169  break;
170  case WifiPhy::IDLE:
171  retval = Seconds (0);
172  break;
173  case WifiPhy::SLEEP:
174  NS_FATAL_ERROR ("Cannot determine when the device will wake up.");
175  retval = Seconds (0);
176  break;
177  default:
178  NS_FATAL_ERROR ("Invalid WifiPhy state.");
179  retval = Seconds (0);
180  break;
181  }
182  retval = Max (retval, Seconds (0));
183  return retval;
184 }
185 
186 Time
188 {
189  return m_startRx;
190 }
191 
194 {
195  if (m_sleeping)
196  {
197  return WifiPhy::SLEEP;
198  }
199  else if (m_endTx > Simulator::Now ())
200  {
201  return WifiPhy::TX;
202  }
203  else if (m_rxing)
204  {
205  return WifiPhy::RX;
206  }
207  else if (m_endSwitching > Simulator::Now ())
208  {
209  return WifiPhy::SWITCHING;
210  }
211  else if (m_endCcaBusy > Simulator::Now ())
212  {
213  return WifiPhy::CCA_BUSY;
214  }
215  else
216  {
217  return WifiPhy::IDLE;
218  }
219 }
220 
221 void
222 WifiPhyStateHelper::NotifyTxStart (Time duration, double txPowerDbm)
223 {
224  NS_LOG_FUNCTION (this);
225  for (Listeners::const_iterator i = m_listeners.begin (); i != m_listeners.end (); i++)
226  {
227  (*i)->NotifyTxStart (duration, txPowerDbm);
228  }
229 }
230 
231 void
233 {
234  NS_LOG_FUNCTION (this);
235  for (Listeners::const_iterator i = m_listeners.begin (); i != m_listeners.end (); i++)
236  {
237  (*i)->NotifyRxStart (duration);
238  }
239 }
240 
241 void
243 {
244  NS_LOG_FUNCTION (this);
245  for (Listeners::const_iterator i = m_listeners.begin (); i != m_listeners.end (); i++)
246  {
247  (*i)->NotifyRxEndOk ();
248  }
249 }
250 
251 void
253 {
254  NS_LOG_FUNCTION (this);
255  for (Listeners::const_iterator i = m_listeners.begin (); i != m_listeners.end (); i++)
256  {
257  (*i)->NotifyRxEndError ();
258  }
259 }
260 
261 void
263 {
264  NS_LOG_FUNCTION (this);
265  for (Listeners::const_iterator i = m_listeners.begin (); i != m_listeners.end (); i++)
266  {
267  (*i)->NotifyMaybeCcaBusyStart (duration);
268  }
269 }
270 
271 void
273 {
274  NS_LOG_FUNCTION (this);
275  for (Listeners::const_iterator i = m_listeners.begin (); i != m_listeners.end (); i++)
276  {
277  (*i)->NotifySwitchingStart (duration);
278  }
279 }
280 
281 void
283 {
284  NS_LOG_FUNCTION (this);
285  for (Listeners::const_iterator i = m_listeners.begin (); i != m_listeners.end (); i++)
286  {
287  (*i)->NotifySleep ();
288  }
289 }
290 
291 void
293 {
294  NS_LOG_FUNCTION (this);
295  for (Listeners::const_iterator i = m_listeners.begin (); i != m_listeners.end (); i++)
296  {
297  (*i)->NotifyWakeup ();
298  }
299 }
300 
301 void
303 {
304  NS_LOG_FUNCTION (this);
305  Time now = Simulator::Now ();
306  Time idleStart = Max (m_endCcaBusy, m_endRx);
307  idleStart = Max (idleStart, m_endTx);
308  idleStart = Max (idleStart, m_endSwitching);
309  NS_ASSERT (idleStart <= now);
310  if (m_endCcaBusy > m_endRx
312  && m_endCcaBusy > m_endTx)
313  {
314  Time ccaBusyStart = Max (m_endTx, m_endRx);
315  ccaBusyStart = Max (ccaBusyStart, m_startCcaBusy);
316  ccaBusyStart = Max (ccaBusyStart, m_endSwitching);
317  m_stateLogger (ccaBusyStart, idleStart - ccaBusyStart, WifiPhy::CCA_BUSY);
318  }
319  m_stateLogger (idleStart, now - idleStart, WifiPhy::IDLE);
320 }
321 
322 void
323 WifiPhyStateHelper::SwitchToTx (Time txDuration, Ptr<const Packet> packet, double txPowerDbm,
324  WifiTxVector txVector)
325 {
326  NS_LOG_FUNCTION (this << txDuration << packet << txPowerDbm << txVector);
327  m_txTrace (packet, txVector.GetMode (), txVector.GetPreambleType (), txVector.GetTxPowerLevel ());
328  Time now = Simulator::Now ();
329  switch (GetState ())
330  {
331  case WifiPhy::RX:
332  /* The packet which is being received as well
333  * as its endRx event are cancelled by the caller.
334  */
335  m_rxing = false;
337  m_endRx = now;
338  break;
339  case WifiPhy::CCA_BUSY:
340  {
341  Time ccaStart = Max (m_endRx, m_endTx);
342  ccaStart = Max (ccaStart, m_startCcaBusy);
343  ccaStart = Max (ccaStart, m_endSwitching);
344  m_stateLogger (ccaStart, now - ccaStart, WifiPhy::CCA_BUSY);
345  } break;
346  case WifiPhy::IDLE:
348  break;
349  case WifiPhy::SWITCHING:
350  case WifiPhy::SLEEP:
351  default:
352  NS_FATAL_ERROR ("Invalid WifiPhy state.");
353  break;
354  }
355  m_stateLogger (now, txDuration, WifiPhy::TX);
357  m_endTx = now + txDuration;
358  m_startTx = now;
359  NotifyTxStart (txDuration, txPowerDbm);
360 }
361 
362 void
364 {
365  NS_LOG_FUNCTION (this << rxDuration);
367  NS_ASSERT (!m_rxing);
368  Time now = Simulator::Now ();
369  switch (GetState ())
370  {
371  case WifiPhy::IDLE:
373  break;
374  case WifiPhy::CCA_BUSY:
375  {
376  Time ccaStart = Max (m_endRx, m_endTx);
377  ccaStart = Max (ccaStart, m_startCcaBusy);
378  ccaStart = Max (ccaStart, m_endSwitching);
379  m_stateLogger (ccaStart, now - ccaStart, WifiPhy::CCA_BUSY);
380  } break;
381  case WifiPhy::SWITCHING:
382  case WifiPhy::RX:
383  case WifiPhy::TX:
384  case WifiPhy::SLEEP:
385  NS_FATAL_ERROR ("Invalid WifiPhy state.");
386  break;
387  }
389  m_rxing = true;
390  m_startRx = now;
391  m_endRx = now + rxDuration;
392  NotifyRxStart (rxDuration);
393  NS_ASSERT (IsStateRx ());
394 }
395 
396 void
398 {
399  NS_LOG_FUNCTION (this << switchingDuration);
400  Time now = Simulator::Now ();
401  switch (GetState ())
402  {
403  case WifiPhy::RX:
404  /* The packet which is being received as well
405  * as its endRx event are cancelled by the caller.
406  */
407  m_rxing = false;
409  m_endRx = now;
410  break;
411  case WifiPhy::CCA_BUSY:
412  {
413  Time ccaStart = Max (m_endRx, m_endTx);
414  ccaStart = Max (ccaStart, m_startCcaBusy);
415  ccaStart = Max (ccaStart, m_endSwitching);
416  m_stateLogger (ccaStart, now - ccaStart, WifiPhy::CCA_BUSY);
417  } break;
418  case WifiPhy::IDLE:
420  break;
421  case WifiPhy::TX:
422  case WifiPhy::SWITCHING:
423  case WifiPhy::SLEEP:
424  default:
425  NS_FATAL_ERROR ("Invalid WifiPhy state.");
426  break;
427  }
428 
429  if (now < m_endCcaBusy)
430  {
431  m_endCcaBusy = now;
432  }
433 
434  m_stateLogger (now, switchingDuration, WifiPhy::SWITCHING);
436  m_startSwitching = now;
437  m_endSwitching = now + switchingDuration;
438  NotifySwitchingStart (switchingDuration);
440 }
441 
442 void
444 {
445  NS_LOG_FUNCTION (this << packet << snr << txVector);
446  m_rxOkTrace (packet, snr, txVector.GetMode (), txVector.GetPreambleType ());
447  NotifyRxEndOk ();
448  DoSwitchFromRx ();
449  if (!m_rxOkCallback.IsNull ())
450  {
451  m_rxOkCallback (packet, snr, txVector);
452  }
453 
454 }
455 
456 void
458 {
459  NS_LOG_FUNCTION (this << packet << snr);
460  m_rxErrorTrace (packet, snr);
461  NotifyRxEndError ();
462  DoSwitchFromRx ();
463  if (!m_rxErrorCallback.IsNull ())
464  {
465  m_rxErrorCallback (packet, snr);
466  }
467 }
468 
469 void
471 {
472  NS_LOG_FUNCTION (this);
473  NS_ASSERT (IsStateRx ());
474  NS_ASSERT (m_rxing);
475 
476  Time now = Simulator::Now ();
479  m_rxing = false;
480 
482 }
483 
484 void
486 {
487  NS_LOG_FUNCTION (this << duration);
488  NotifyMaybeCcaBusyStart (duration);
489  Time now = Simulator::Now ();
490  switch (GetState ())
491  {
492  case WifiPhy::SWITCHING:
493  break;
494  case WifiPhy::SLEEP:
495  break;
496  case WifiPhy::IDLE:
498  break;
499  case WifiPhy::CCA_BUSY:
500  break;
501  case WifiPhy::RX:
502  break;
503  case WifiPhy::TX:
504  break;
505  }
506  if (GetState () != WifiPhy::CCA_BUSY)
507  {
508  m_startCcaBusy = now;
509  }
510  m_endCcaBusy = std::max (m_endCcaBusy, now + duration);
511 }
512 
513 void
515 {
516  NS_LOG_FUNCTION (this);
517  Time now = Simulator::Now ();
518  switch (GetState ())
519  {
520  case WifiPhy::IDLE:
522  break;
523  case WifiPhy::CCA_BUSY:
524  {
525  Time ccaStart = Max (m_endRx, m_endTx);
526  ccaStart = Max (ccaStart, m_startCcaBusy);
527  ccaStart = Max (ccaStart, m_endSwitching);
528  m_stateLogger (ccaStart, now - ccaStart, WifiPhy::CCA_BUSY);
529  } break;
530  case WifiPhy::RX:
531  case WifiPhy::SWITCHING:
532  case WifiPhy::TX:
533  case WifiPhy::SLEEP:
534  NS_FATAL_ERROR ("Invalid WifiPhy state.");
535  break;
536  }
538  m_sleeping = true;
539  m_startSleep = now;
540  NotifySleep ();
541  NS_ASSERT (IsStateSleep ());
542 }
543 
544 void
546 {
547  NS_LOG_FUNCTION (this << duration);
548  NS_ASSERT (IsStateSleep ());
549  Time now = Simulator::Now ();
552  m_sleeping = false;
553  NotifyWakeup ();
554  //update m_endCcaBusy after the sleep period
555  m_endCcaBusy = std::max (m_endCcaBusy, now + duration);
556  if (m_endCcaBusy > now)
557  {
559  }
560 }
561 
562 void
564 {
565  NS_LOG_FUNCTION (this);
566  NS_ASSERT (IsStateRx ());
567  NS_ASSERT (m_rxing);
568  m_endRx = Simulator::Now ();
569  DoSwitchFromRx ();
570  NS_ASSERT (!IsStateRx ());
571 }
572 
573 } //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...
TracedCallback< Time, Time, WifiPhy::State > m_stateLogger
The trace source fired when state is changed.
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition: object-base.h:45
void NotifyWakeup(void)
Notify all WifiPhyListener that we woke up.
The PHY layer has sense the medium busy through the CCA mechanism.
Definition: wifi-phy.h:180
Time m_endCcaBusy
endn CCA busy
Time m_startCcaBusy
start CCA busy
bool IsStateIdle(void) const
Check whether the current state is IDLE.
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
The PHY layer is sleeping.
Definition: wifi-phy.h:196
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 SetReceiveOkCallback(WifiPhy::RxOkCallback callback)
Set a callback for a successful reception.
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.
Time m_endSwitching
end switching
#define max(a, b)
Definition: 80211b.c:45
receive notifications about phy events.
Definition: wifi-phy.h:83
void NotifySwitchingStart(Time duration)
Notify all WifiPhyListener that we are switching channel with the given channel switching delay...
The PHY layer is IDLE.
Definition: wifi-phy.h:176
Time GetStateDuration(void) const
Return the elapsed time of the current state.
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
Time m_previousStateChangeTime
previous state change time
void SetReceiveErrorCallback(WifiPhy::RxErrorCallback callback)
Set a callback for a failed reception.
The PHY layer is receiving a packet.
Definition: wifi-phy.h:188
The PHY layer is sending a packet.
Definition: wifi-phy.h:184
bool IsStateBusy(void) const
Check whether the current state is not IDLE.
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.
WifiPhy::RxErrorCallback m_rxErrorCallback
receive error callback
The PHY layer is switching to other channel.
Definition: wifi-phy.h:192
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.
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.
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.
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.
WifiPhy::State GetState(void) const
Return the current state of WifiPhy.
Listeners m_listeners
listeners
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:993
TracedCallback< Ptr< const Packet >, double > m_rxErrorTrace
receive error trace callback
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
State
The state of the PHY layer.
Definition: wifi-phy.h:171
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.
WifiPhy::RxOkCallback m_rxOkCallback
receive OK callback