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"
26#include "wifi-tx-vector.h"
27#include "wifi-phy-listener.h"
28#include "wifi-psdu.h"
29#include "wifi-phy.h"
30
31namespace ns3 {
32
33NS_LOG_COMPONENT_DEFINE ("WifiPhyStateHelper");
34
35NS_OBJECT_ENSURE_REGISTERED (WifiPhyStateHelper);
36
37TypeId
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
80void
82{
83 m_rxOkCallback = callback;
84}
85
86void
88{
89 m_rxErrorCallback = callback;
90}
91
92void
94{
95 m_listeners.push_back (listener);
96}
97
98void
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
108bool
110{
111 return (GetState () == WifiPhyState::IDLE);
112}
113
114bool
116{
117 return (GetState () == WifiPhyState::CCA_BUSY);
118}
119
120bool
122{
123 return (GetState () == WifiPhyState::RX);
124}
125
126bool
128{
129 return (GetState () == WifiPhyState::TX);
130}
131
132bool
134{
135 return (GetState () == WifiPhyState::SWITCHING);
136}
137
138bool
140{
141 return (GetState () == WifiPhyState::SLEEP);
142}
143
144bool
146{
147 return (GetState () == WifiPhyState::OFF);
148}
149
150Time
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;
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
183Time
185{
186 return m_startRx;
187}
188
189Time
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 {
221 }
222 else
223 {
224 return WifiPhyState::IDLE;
225 }
226}
227
228void
229WifiPhyStateHelper::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
238void
240{
241 NS_LOG_FUNCTION (this);
242 for (const auto& listener : m_listeners)
243 {
244 listener->NotifyRxStart (duration);
245 }
246}
247
248void
250{
251 NS_LOG_FUNCTION (this);
252 for (const auto& listener : m_listeners)
253 {
254 listener->NotifyRxEndOk ();
255 }
256}
257
258void
260{
261 NS_LOG_FUNCTION (this);
262 for (const auto& listener : m_listeners)
263 {
264 listener->NotifyRxEndError ();
265 }
266}
267
268void
270{
271 NS_LOG_FUNCTION (this);
272 for (const auto& listener : m_listeners)
273 {
274 listener->NotifyMaybeCcaBusyStart (duration);
275 }
276}
277
278void
280{
281 NS_LOG_FUNCTION (this);
282 for (const auto& listener : m_listeners)
283 {
284 listener->NotifySwitchingStart (duration);
285 }
286}
287
288void
290{
291 NS_LOG_FUNCTION (this);
292 for (const auto& listener : m_listeners)
293 {
294 listener->NotifySleep ();
295 }
296}
297
298void
300{
301 NS_LOG_FUNCTION (this);
302 for (const auto& listener : m_listeners)
303 {
304 listener->NotifyOff ();
305 }
306}
307
308void
310{
311 NS_LOG_FUNCTION (this);
312 for (const auto& listener : m_listeners)
313 {
314 listener->NotifyWakeup ();
315 }
316}
317
318void
320{
321 NS_LOG_FUNCTION (this);
322 for (const auto& listener : m_listeners)
323 {
324 listener->NotifyOn ();
325 }
326}
327
328void
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);
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
362void
363WifiPhyStateHelper::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]];
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
400void
402{
403 NS_LOG_FUNCTION (this << rxDuration);
405 Time now = Simulator::Now ();
406 switch (GetState ())
407 {
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
424void
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]];
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
457void
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
468void
469WifiPhyStateHelper::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 ();
483 if (!m_rxOkCallback.IsNull ())
484 {
485 m_rxOkCallback (psdu, rxSignalInfo, txVector, statusPerMpdu);
486 }
487}
488
489void
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 }
502 {
503 m_rxErrorCallback (psdu);
504 }
505}
506
507void
509{
510 NS_LOG_FUNCTION (this);
511 Time now = Simulator::Now ();
516}
517
518void
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 {
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
544void
546{
547 NS_LOG_FUNCTION (this);
548 Time now = Simulator::Now ();
549 switch (GetState ())
550 {
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 ();
565}
566
567void
569{
570 NS_LOG_FUNCTION (this);
572 Time now = Simulator::Now ();
575 m_sleeping = false;
576 NotifyWakeup ();
577}
578
579void
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 ();
589}
590
591void
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;
613 [[fallthrough]];
616 break;
617 default:
618 NS_FATAL_ERROR ("Invalid WifiPhy state.");
619 break;
620 }
622 m_isOff = true;
623 NotifyOff ();
625}
626
627void
629{
630 NS_LOG_FUNCTION (this);
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.