A Discrete-Event Network Simulator
API
wifi-phy-state-helper.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2005,2006 INRIA
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation;
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program; if not, write to the Free Software
15  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16  *
17  * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
18  */
19 
20 #include "wifi-phy-state-helper.h"
21 
22 #include "wifi-phy-listener.h"
23 #include "wifi-phy.h"
24 #include "wifi-psdu.h"
25 #include "wifi-tx-vector.h"
26 
27 #include "ns3/log.h"
28 #include "ns3/packet.h"
29 #include "ns3/simulator.h"
30 
31 #include <algorithm>
32 #include <functional>
33 #include <iterator>
34 
35 namespace ns3
36 {
37 
38 NS_LOG_COMPONENT_DEFINE("WifiPhyStateHelper");
39 
40 NS_OBJECT_ENSURE_REGISTERED(WifiPhyStateHelper);
41 
42 TypeId
44 {
45  static TypeId tid =
46  TypeId("ns3::WifiPhyStateHelper")
47  .SetParent<Object>()
48  .SetGroupName("Wifi")
49  .AddConstructor<WifiPhyStateHelper>()
50  .AddTraceSource("State",
51  "The state of the PHY layer",
53  "ns3::WifiPhyStateHelper::StateTracedCallback")
54  .AddTraceSource("RxOk",
55  "A packet has been received successfully.",
57  "ns3::WifiPhyStateHelper::RxOkTracedCallback")
58  .AddTraceSource("RxError",
59  "A packet has been received unsuccessfuly.",
61  "ns3::WifiPhyStateHelper::RxEndErrorTracedCallback")
62  .AddTraceSource("Tx",
63  "Packet transmission is starting.",
65  "ns3::WifiPhyStateHelper::TxTracedCallback");
66  return tid;
67 }
68 
70  : NS_LOG_TEMPLATE_DEFINE("WifiPhyStateHelper"),
71  m_sleeping(false),
72  m_isOff(false),
73  m_endTx(Seconds(0)),
74  m_endRx(Seconds(0)),
75  m_endCcaBusy(Seconds(0)),
76  m_endSwitching(Seconds(0)),
77  m_startTx(Seconds(0)),
78  m_startRx(Seconds(0)),
79  m_startCcaBusy(Seconds(0)),
80  m_startSwitching(Seconds(0)),
81  m_startSleep(Seconds(0)),
82  m_previousStateChangeTime(Seconds(0))
83 {
84  NS_LOG_FUNCTION(this);
85 }
86 
87 void
89 {
90  m_rxOkCallback = callback;
91 }
92 
93 void
95 {
96  m_rxErrorCallback = callback;
97 }
98 
99 void
100 WifiPhyStateHelper::RegisterListener(const std::shared_ptr<WifiPhyListener>& listener)
101 {
102  m_listeners.emplace_back(listener);
103 }
104 
105 void
106 WifiPhyStateHelper::UnregisterListener(const std::shared_ptr<WifiPhyListener>& listener)
107 {
108  m_listeners.remove_if([&listener](auto&& weakPtr) { return weakPtr.lock() == listener; });
109 }
110 
111 bool
113 {
114  return (GetState() == WifiPhyState::IDLE);
115 }
116 
117 bool
119 {
120  return (GetState() == WifiPhyState::CCA_BUSY);
121 }
122 
123 bool
125 {
126  return (GetState() == WifiPhyState::RX);
127 }
128 
129 bool
131 {
132  return (GetState() == WifiPhyState::TX);
133 }
134 
135 bool
137 {
138  return (GetState() == WifiPhyState::SWITCHING);
139 }
140 
141 bool
143 {
144  return (GetState() == WifiPhyState::SLEEP);
145 }
146 
147 bool
149 {
150  return (GetState() == WifiPhyState::OFF);
151 }
152 
153 Time
155 {
156  Time retval;
157 
158  switch (GetState())
159  {
160  case WifiPhyState::RX:
161  retval = m_endRx - Simulator::Now();
162  break;
163  case WifiPhyState::TX:
164  retval = m_endTx - Simulator::Now();
165  break;
167  retval = m_endCcaBusy - Simulator::Now();
168  break;
170  retval = m_endSwitching - Simulator::Now();
171  break;
172  case WifiPhyState::IDLE:
173  case WifiPhyState::SLEEP:
174  case WifiPhyState::OFF:
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 
192 Time
194 {
195  return m_endRx;
196 }
197 
200 {
201  if (m_isOff)
202  {
203  return WifiPhyState::OFF;
204  }
205  if (m_sleeping)
206  {
207  return WifiPhyState::SLEEP;
208  }
209  else if (m_endTx > Simulator::Now())
210  {
211  return WifiPhyState::TX;
212  }
213  else if (m_endRx > Simulator::Now())
214  {
215  return WifiPhyState::RX;
216  }
217  else if (m_endSwitching > Simulator::Now())
218  {
220  }
221  else if (m_endCcaBusy > Simulator::Now())
222  {
223  return WifiPhyState::CCA_BUSY;
224  }
225  else
226  {
227  return WifiPhyState::IDLE;
228  }
229 }
230 
231 void
233 {
234  NS_LOG_FUNCTION(this);
235  Time now = Simulator::Now();
236  WifiPhyState state = GetState();
237  if (state == WifiPhyState::CCA_BUSY)
238  {
240  m_stateLogger(ccaStart, now - ccaStart, WifiPhyState::CCA_BUSY);
241  }
242  else if (state == WifiPhyState::IDLE)
243  {
245  NS_ASSERT(idleStart <= now);
247  {
249  Time ccaBusyDuration = idleStart - ccaBusyStart;
250  if (ccaBusyDuration.IsStrictlyPositive())
251  {
252  m_stateLogger(ccaBusyStart, ccaBusyDuration, WifiPhyState::CCA_BUSY);
253  }
254  }
255  Time idleDuration = now - idleStart;
256  if (idleDuration.IsStrictlyPositive())
257  {
258  m_stateLogger(idleStart, idleDuration, WifiPhyState::IDLE);
259  }
260  }
261 }
262 
263 void
265  WifiConstPsduMap psdus,
266  double txPowerDbm,
267  const WifiTxVector& txVector)
268 {
269  NS_LOG_FUNCTION(this << txDuration << psdus << txPowerDbm << txVector);
270  if (!m_txTrace.IsEmpty())
271  {
272  for (const auto& psdu : psdus)
273  {
274  m_txTrace(psdu.second->GetPacket(),
275  txVector.GetMode(psdu.first),
276  txVector.GetPreambleType(),
277  txVector.GetTxPowerLevel());
278  }
279  }
280  Time now = Simulator::Now();
281  switch (GetState())
282  {
283  case WifiPhyState::RX:
284  /* The packet which is being received as well
285  * as its endRx event are cancelled by the caller.
286  */
288  m_endRx = now;
289  break;
291  [[fallthrough]];
292  case WifiPhyState::IDLE:
294  break;
295  default:
296  NS_FATAL_ERROR("Invalid WifiPhy state.");
297  break;
298  }
299  m_stateLogger(now, txDuration, WifiPhyState::TX);
301  m_endTx = now + txDuration;
302  m_startTx = now;
303  NotifyListeners(&WifiPhyListener::NotifyTxStart, txDuration, txPowerDbm);
304 }
305 
306 void
308 {
309  NS_LOG_FUNCTION(this << rxDuration);
311  Time now = Simulator::Now();
312  switch (GetState())
313  {
314  case WifiPhyState::IDLE:
315  [[fallthrough]];
318  break;
319  default:
320  NS_FATAL_ERROR("Invalid WifiPhy state " << GetState());
321  break;
322  }
324  m_startRx = now;
325  m_endRx = now + rxDuration;
327  NS_ASSERT(IsStateRx());
328 }
329 
330 void
332 {
333  NS_LOG_FUNCTION(this << switchingDuration);
334  Time now = Simulator::Now();
335  switch (GetState())
336  {
337  case WifiPhyState::RX:
338  /* The packet which is being received as well
339  * as its endRx event are cancelled by the caller.
340  */
342  m_endRx = now;
343  break;
345  [[fallthrough]];
346  case WifiPhyState::IDLE:
348  break;
349  default:
350  NS_FATAL_ERROR("Invalid WifiPhy state.");
351  break;
352  }
353 
355  m_stateLogger(now, switchingDuration, WifiPhyState::SWITCHING);
357  m_startSwitching = now;
358  m_endSwitching = now + switchingDuration;
360  NS_ASSERT(switchingDuration.IsZero() || IsStateSwitching());
361 }
362 
363 void
365  RxSignalInfo rxSignalInfo,
366  const WifiTxVector& txVector)
367 {
368  NS_LOG_FUNCTION(this << *psdu << rxSignalInfo << txVector);
369  if (!m_rxOkCallback.IsNull())
370  {
371  m_rxOkCallback(psdu, rxSignalInfo, txVector, {});
372  }
373 }
374 
375 void
377  RxSignalInfo rxSignalInfo,
378  const WifiTxVector& txVector,
379  uint16_t staId,
380  const std::vector<bool>& statusPerMpdu)
381 {
382  NS_LOG_FUNCTION(this << *psdu << rxSignalInfo << txVector << staId << statusPerMpdu.size()
383  << std::all_of(statusPerMpdu.begin(), statusPerMpdu.end(), [](bool v) {
384  return v;
385  })); // returns true if all true
386  NS_ASSERT(!statusPerMpdu.empty());
387  if (!m_rxOkTrace.IsEmpty())
388  {
389  m_rxOkTrace(psdu->GetPacket(),
390  rxSignalInfo.snr,
391  txVector.GetMode(staId),
392  txVector.GetPreambleType());
393  }
394  if (!m_rxOkCallback.IsNull())
395  {
396  m_rxOkCallback(psdu, rxSignalInfo, txVector, statusPerMpdu);
397  }
398 }
399 
400 void
402 {
403  NS_LOG_FUNCTION(this << *psdu << snr);
404  if (!m_rxErrorTrace.IsEmpty())
405  {
406  m_rxErrorTrace(psdu->GetPacket(), snr);
407  }
408  if (!m_rxErrorCallback.IsNull())
409  {
410  m_rxErrorCallback(psdu);
411  }
412 }
413 
414 void
416 {
417  NS_LOG_FUNCTION(this);
420  DoSwitchFromRx();
421 }
422 
423 void
425 {
426  NS_LOG_FUNCTION(this);
429  DoSwitchFromRx();
430 }
431 
432 void
434 {
435  NS_LOG_FUNCTION(this);
436  Time now = Simulator::Now();
441 }
442 
443 void
445  WifiChannelListType channelType,
446  const std::vector<Time>& per20MhzDurations)
447 {
448  NS_LOG_FUNCTION(this << duration << channelType);
449  if (GetState() == WifiPhyState::RX)
450  {
451  return;
452  }
453  NotifyListeners(&WifiPhyListener::NotifyCcaBusyStart, duration, channelType, per20MhzDurations);
454  if (channelType != WIFI_CHANLIST_PRIMARY)
455  {
456  // WifiPhyStateHelper only updates CCA start and end durations for the primary channel
457  return;
458  }
459  Time now = Simulator::Now();
460  if (GetState() == WifiPhyState::IDLE)
461  {
463  }
465  {
466  m_startCcaBusy = now;
467  }
468  m_endCcaBusy = std::max(m_endCcaBusy, now + duration);
469 }
470 
471 void
473 {
474  NS_LOG_FUNCTION(this);
475  Time now = Simulator::Now();
476  switch (GetState())
477  {
478  case WifiPhyState::IDLE:
479  [[fallthrough]];
482  break;
483  default:
484  NS_FATAL_ERROR("Invalid WifiPhy state.");
485  break;
486  }
488  m_sleeping = true;
489  m_startSleep = now;
492 }
493 
494 void
496 {
497  NS_LOG_FUNCTION(this);
499  Time now = Simulator::Now();
502  m_sleeping = false;
504 }
505 
506 void
508 {
509  NS_LOG_FUNCTION(this << operatingWidth);
510  NS_ASSERT(IsStateCcaBusy()); // abort is called (with OBSS_PD_CCA_RESET reason) before RX is set
511  // by payload start
513  DoSwitchFromRx();
515  std::vector<Time> per20MhzDurations;
516  if (operatingWidth >= 40)
517  {
518  std::fill_n(std::back_inserter(per20MhzDurations), (operatingWidth / 20), Seconds(0));
519  }
521  Seconds(0),
523  per20MhzDurations);
525 }
526 
527 void
529 {
530  NS_LOG_FUNCTION(this);
531  Time now = Simulator::Now();
532  switch (GetState())
533  {
534  case WifiPhyState::RX:
535  /* The packet which is being received as well
536  * as its endRx event are cancelled by the caller.
537  */
539  m_endRx = now;
540  break;
541  case WifiPhyState::TX:
542  /* The packet which is being transmitted as well
543  * as its endTx event are cancelled by the caller.
544  */
546  m_endTx = now;
547  break;
548  case WifiPhyState::IDLE:
549  [[fallthrough]];
552  break;
553  default:
554  NS_FATAL_ERROR("Invalid WifiPhy state.");
555  break;
556  }
558  m_isOff = true;
561 }
562 
563 void
565 {
566  NS_LOG_FUNCTION(this);
568  Time now = Simulator::Now();
570  m_isOff = false;
572 }
573 
574 } // namespace ns3
#define min(a, b)
Definition: 80211b.c:41
#define max(a, b)
Definition: 80211b.c:42
bool IsNull() const
Check for null implementation.
Definition: callback.h:569
A base class which provides memory management and object aggregation.
Definition: object.h:89
static Time Now()
Return the current simulation virtual time.
Definition: simulator.cc:208
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:105
bool IsStrictlyPositive() const
Exactly equivalent to t > 0.
Definition: nstime.h:351
bool IsZero() const
Exactly equivalent to t == 0.
Definition: nstime.h:315
a unique identifier for an interface.
Definition: type-id.h:59
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:931
virtual void NotifyRxEndError()=0
We have received the last bit of a packet for which NotifyRxStart was invoked first and,...
virtual void NotifySwitchingStart(Time duration)=0
virtual void NotifyCcaBusyStart(Time duration, WifiChannelListType channelType, const std::vector< Time > &per20MhzDurations)=0
virtual void NotifyOff()=0
Notify listeners that we went to switch off.
virtual void NotifyRxEndOk()=0
We have received the last bit of a packet for which NotifyRxStart was invoked first and,...
virtual void NotifySleep()=0
Notify listeners that we went to sleep.
virtual void NotifyOn()=0
Notify listeners that we went to switch on.
virtual void NotifyTxStart(Time duration, double txPowerDbm)=0
virtual void NotifyRxStart(Time duration)=0
virtual void NotifyWakeup()=0
Notify listeners that we woke up.
This objects implements the PHY state machine of the Wifi device.
bool IsStateSwitching() const
Check whether the current state is SWITCHING.
void SwitchToRx(Time rxDuration)
Switch state to RX for the given duration.
bool IsStateCcaBusy() const
Check whether the current state is CCA busy.
Time GetDelayUntilIdle() const
Return the time before the state is back to IDLE.
bool IsStateIdle() const
Check whether the current state is IDLE.
Time GetLastRxStartTime() const
Return the time the last RX start.
void DoSwitchFromRx()
Switch the state from RX.
void SwitchFromRxEndOk()
Switch from RX after the reception was successful.
Time m_previousStateChangeTime
previous state change time
void SwitchToChannelSwitching(Time switchingDuration)
Switch state to channel switching for the given duration.
void SwitchToOff()
Switch to off mode.
void NotifyRxMpdu(Ptr< const WifiPsdu > psdu, RxSignalInfo rxSignalInfo, const WifiTxVector &txVector)
Notify the reception of an MPDU included in an A-MPDU.
TracedCallback< Ptr< const Packet >, WifiMode, WifiPreamble, uint8_t > m_txTrace
transmit trace callback
Time m_endSwitching
end switching
void SwitchToTx(Time txDuration, WifiConstPsduMap psdus, double txPowerDbm, const WifiTxVector &txVector)
Switch state to TX for the given duration.
Time m_startSwitching
start switching
void UnregisterListener(const std::shared_ptr< WifiPhyListener > &listener)
Remove WifiPhyListener from this WifiPhyStateHelper.
TracedCallback< Time, Time, WifiPhyState > m_stateLogger
The trace source fired when state is changed.
void NotifyListeners(FUNC f, Ts &&... args)
Notify all WifiPhyListener objects of the given PHY event.
void LogPreviousIdleAndCcaBusyStates()
Log the idle and CCA busy states.
static TypeId GetTypeId()
Get the type ID.
RxOkCallback m_rxOkCallback
receive OK callback
TracedCallback< Ptr< const Packet >, double, WifiMode, WifiPreamble > m_rxOkTrace
receive OK trace callback
void NotifyRxPsduFailed(Ptr< const WifiPsdu > psdu, double snr)
Handle the unsuccessful reception of a PSDU.
bool IsStateOff() const
Check whether the current state is OFF.
void SwitchFromRxAbort(uint16_t operatingWidth)
Abort current reception following a CCA reset request.
WifiPhyState GetState() const
Return the current state of WifiPhy.
RxErrorCallback m_rxErrorCallback
receive error callback
void SwitchToSleep()
Switch to sleep mode.
void SwitchMaybeToCcaBusy(Time duration, WifiChannelListType channelType, const std::vector< Time > &per20MhzDurations)
Switch to CCA busy.
TracedCallback< Ptr< const Packet >, double > m_rxErrorTrace
receive error trace callback
bool IsStateTx() const
Check whether the current state is TX.
void SwitchFromOff()
Switch from off mode.
Time m_startCcaBusy
start CCA busy
Listeners m_listeners
listeners
Time GetLastRxEndTime() const
Return the time the last RX end.
void SwitchFromRxEndError()
Switch from RX after the reception failed.
void SetReceiveOkCallback(RxOkCallback callback)
Set a callback for a successful reception.
void SwitchFromSleep()
Switch from sleep mode.
bool IsStateSleep() const
Check whether the current state is SLEEP.
bool IsStateRx() const
Check whether the current state is RX.
void SetReceiveErrorCallback(RxErrorCallback callback)
Set a callback for a failed reception.
void NotifyRxPsduSucceeded(Ptr< const WifiPsdu > psdu, RxSignalInfo rxSignalInfo, const WifiTxVector &txVector, uint16_t staId, const std::vector< bool > &statusPerMpdu)
Handle the successful reception of a PSDU.
void RegisterListener(const std::shared_ptr< WifiPhyListener > &listener)
Register WifiPhyListener to this WifiPhyStateHelper.
Ptr< const Packet > GetPacket() const
Get the PSDU as a single packet.
Definition: wifi-psdu.cc:89
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.
WifiPreamble GetPreambleType() const
uint8_t GetTxPowerLevel() 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:66
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
Definition: fatal-error.h:179
int64x64_t Max(const int64x64_t &a, const int64x64_t &b)
Maximum.
Definition: int64x64.h:243
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:202
#define NS_LOG_TEMPLATE_DEFINE(name)
Initialize a reference to a Log component.
Definition: log.h:236
#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:46
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1326
Ptr< const TraceSourceAccessor > MakeTraceSourceAccessor(T a)
Create a TraceSourceAccessor which will control access to the underlying trace source.
WifiChannelListType
Enumeration of the possible channel-list parameter elements defined in Table 8-5 of IEEE 802....
@ WIFI_CHANLIST_PRIMARY
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:69
double snr
SNR in linear scale.
Definition: phy-entity.h:70
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.