A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
wifi-phy-state-helper.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2005,2006 INRIA
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
7 */
8
10
11#include "wifi-phy-listener.h"
12#include "wifi-phy.h"
13#include "wifi-psdu.h"
14#include "wifi-tx-vector.h"
15#include "wifi-utils.h"
16
17#include "ns3/log.h"
18#include "ns3/packet.h"
19#include "ns3/simulator.h"
20
21#include <algorithm>
22#include <functional>
23#include <iterator>
24
25namespace ns3
26{
27
28NS_LOG_COMPONENT_DEFINE("WifiPhyStateHelper");
29
30NS_OBJECT_ENSURE_REGISTERED(WifiPhyStateHelper);
31
32TypeId
34{
35 static TypeId tid =
36 TypeId("ns3::WifiPhyStateHelper")
38 .SetGroupName("Wifi")
39 .AddConstructor<WifiPhyStateHelper>()
40 .AddTraceSource("State",
41 "The state of the PHY layer",
43 "ns3::WifiPhyStateHelper::StateTracedCallback")
44 .AddTraceSource("RxOk",
45 "A packet has been received successfully.",
47 "ns3::WifiPhyStateHelper::RxOkTracedCallback")
48 .AddTraceSource(
49 "RxOutcome",
50 "The outcome of the decoding of the PPDU, including MPDU decoding status",
52 "ns3::WifiPhyStateHelper::RxOutcomeTracedCallback")
53 .AddTraceSource("RxError",
54 "A packet has been received unsuccessfuly.",
56 "ns3::WifiPhyStateHelper::RxEndErrorTracedCallback")
57 .AddTraceSource("Tx",
58 "Packet transmission is starting.",
60 "ns3::WifiPhyStateHelper::TxTracedCallback");
61 return tid;
62}
63
65 : NS_LOG_TEMPLATE_DEFINE("WifiPhyStateHelper"),
66 m_sleeping(false),
67 m_isOff(false),
68 m_endTx(Time{0}),
69 m_endRx(Time{0}),
70 m_endCcaBusy(Time{0}),
71 m_endSwitching(Time{0}),
72 m_endSleep(Time{0}),
73 m_endOff(Time{0}),
74 m_endIdle(Time{0}),
75 m_startTx(Time{0}),
76 m_startRx(Time{0}),
77 m_startCcaBusy(Time{0}),
78 m_startSwitching(Time{0}),
79 m_startSleep(Time{0}),
80 m_startOff(Time{0}),
81 m_previousStateChangeTime(Time{0})
82{
83 NS_LOG_FUNCTION(this);
84}
85
86void
91
92void
97
98void
99WifiPhyStateHelper::RegisterListener(const std::shared_ptr<WifiPhyListener>& listener)
100{
101 m_listeners.emplace_back(listener);
102}
103
104void
105WifiPhyStateHelper::UnregisterListener(const std::shared_ptr<WifiPhyListener>& listener)
106{
107 m_listeners.remove_if([&listener](auto&& weakPtr) { return weakPtr.lock() == listener; });
108}
109
110bool
115
116bool
121
122bool
124{
125 return (GetState() == WifiPhyState::RX);
126}
127
128bool
130{
131 return (GetState() == WifiPhyState::TX);
132}
133
134bool
139
140bool
145
146bool
148{
149 return (GetState() == WifiPhyState::OFF);
150}
151
152Time
154{
155 Time retval;
156
157 switch (GetState())
158 {
159 case WifiPhyState::RX:
160 retval = m_endRx - Simulator::Now();
161 break;
162 case WifiPhyState::TX:
163 retval = m_endTx - Simulator::Now();
164 break;
166 retval = m_endCcaBusy - Simulator::Now();
167 break;
169 retval = m_endSwitching - Simulator::Now();
170 break;
174 retval = Seconds(0);
175 break;
176 default:
177 NS_FATAL_ERROR("Invalid WifiPhy state.");
178 retval = Seconds(0);
179 break;
180 }
181 retval = Max(retval, Seconds(0));
182 return retval;
183}
184
185Time
190
191Time
193{
194 return m_endRx;
195}
196
197Time
198WifiPhyStateHelper::GetLastTime(std::initializer_list<WifiPhyState> states) const
199{
200 Time last{0};
201 auto currentState = GetState();
202
203 for (auto state : states)
204 {
205 if (state == currentState)
206 {
207 return Simulator::Now();
208 }
209
210 switch (state)
211 {
212 case WifiPhyState::RX:
213 last = std::max(last, m_endRx);
214 break;
215 case WifiPhyState::TX:
216 last = std::max(last, m_endTx);
217 break;
219 last = std::max(last, m_endCcaBusy);
220 break;
222 last = std::max(last, m_endSwitching);
223 break;
225 last = std::max(last, m_endSleep);
226 break;
228 last = std::max(last, m_endOff);
229 break;
231 last = std::max(last, m_endIdle);
232 break;
233 default:
234 NS_FATAL_ERROR("Invalid WifiPhy state " << state);
235 }
236 }
237 NS_ASSERT(last <= Simulator::Now());
238 return last;
239}
240
243{
244 const auto now = Simulator::Now();
245 if (m_isOff)
246 {
247 return WifiPhyState::OFF;
248 }
249 if (m_sleeping)
250 {
251 return WifiPhyState::SLEEP;
252 }
253 else if (m_endTx > now)
254 {
255 return WifiPhyState::TX;
256 }
257 else if (m_endRx > now)
258 {
259 return WifiPhyState::RX;
260 }
261 else if (m_endSwitching > now)
262 {
264 }
265 else if (m_endCcaBusy > now)
266 {
268 }
269 else
270 {
271 return WifiPhyState::IDLE;
272 }
273}
274
275void
277{
278 NS_LOG_FUNCTION(this);
279 const auto now = Simulator::Now();
280 WifiPhyState state = GetState();
281 if (state == WifiPhyState::CCA_BUSY)
282 {
283 m_endCcaBusy = now;
284 const auto ccaStart =
286 m_stateLogger(ccaStart, now - ccaStart, WifiPhyState::CCA_BUSY);
287 }
288 else if (state == WifiPhyState::IDLE)
289 {
290 m_endIdle = now;
291 const auto endAllButCcaBusy =
293 const auto idleStart = std::max(m_endCcaBusy, endAllButCcaBusy);
294 NS_ASSERT(idleStart <= now);
295 if (m_endCcaBusy > endAllButCcaBusy)
296 {
297 const auto ccaBusyStart = std::max(m_startCcaBusy, endAllButCcaBusy);
298 if (const auto ccaBusyDuration = idleStart - ccaBusyStart;
299 ccaBusyDuration.IsStrictlyPositive())
300 {
301 m_stateLogger(ccaBusyStart, ccaBusyDuration, WifiPhyState::CCA_BUSY);
302 }
303 }
304 if (const auto idleDuration = now - idleStart; idleDuration.IsStrictlyPositive())
305 {
306 m_stateLogger(idleStart, idleDuration, WifiPhyState::IDLE);
307 }
308 }
309}
310
311void
313 const WifiConstPsduMap& psdus,
314 dBm_u txPower,
315 const WifiTxVector& txVector)
316{
317 NS_LOG_FUNCTION(this << txDuration << psdus << txPower << txVector);
318 if (!m_txTrace.IsEmpty())
319 {
320 for (const auto& psdu : psdus)
321 {
322 m_txTrace(psdu.second->GetPacket(),
323 txVector.GetMode(psdu.first),
324 txVector.GetPreambleType(),
325 txVector.GetTxPowerLevel());
326 }
327 }
328 const auto now = Simulator::Now();
329 switch (GetState())
330 {
331 case WifiPhyState::RX:
332 /* The packet which is being received as well
333 * as its endRx event are cancelled by the caller.
334 */
336 m_endRx = now;
337 break;
339 [[fallthrough]];
342 break;
343 default:
344 NS_FATAL_ERROR("Invalid WifiPhy state.");
345 break;
346 }
347 m_stateLogger(now, txDuration, WifiPhyState::TX);
349 m_endTx = now + txDuration;
350 m_startTx = now;
351 NotifyListeners(&WifiPhyListener::NotifyTxStart, txDuration, txPower);
352}
353
354void
356{
357 NS_LOG_FUNCTION(this << rxDuration);
359 Time now = Simulator::Now();
360 switch (GetState())
361 {
363 [[fallthrough]];
366 break;
367 default:
368 NS_FATAL_ERROR("Invalid WifiPhy state " << GetState());
369 break;
370 }
372 m_startRx = now;
373 m_endRx = now + rxDuration;
376}
377
378void
380{
381 NS_LOG_FUNCTION(this << switchingDuration);
382 Time now = Simulator::Now();
383 switch (GetState())
384 {
385 case WifiPhyState::RX:
386 /* The packet which is being received as well
387 * as its endRx event are cancelled by the caller.
388 */
390 m_endRx = now;
391 break;
393 [[fallthrough]];
396 break;
398 // do nothing
399 break;
400 default:
401 NS_FATAL_ERROR("Invalid WifiPhy state.");
402 break;
403 }
404
405 m_endCcaBusy = std::min(now, m_endCcaBusy);
406 m_stateLogger(now, switchingDuration, WifiPhyState::SWITCHING);
408 m_startSwitching = now;
409 m_endSwitching = now + switchingDuration;
411 NS_ASSERT(switchingDuration.IsZero() || IsStateSwitching());
412}
413
414void
416 RxSignalInfo rxSignalInfo,
417 const WifiTxVector& txVector)
418{
419 NS_LOG_FUNCTION(this << *psdu << rxSignalInfo << txVector);
420 if (!m_rxOkCallback.IsNull())
421 {
422 m_rxOkCallback(psdu, rxSignalInfo, txVector, {});
423 }
424}
425
426void
428 RxSignalInfo rxSignalInfo,
429 const WifiTxVector& txVector,
430 uint16_t staId,
431 const std::vector<bool>& statusPerMpdu)
432{
433 NS_LOG_FUNCTION(this << *psdu << rxSignalInfo << txVector << staId << statusPerMpdu.size()
434 << std::all_of(statusPerMpdu.begin(), statusPerMpdu.end(), [](bool v) {
435 return v;
436 })); // returns true if all true
437 NS_ASSERT(!statusPerMpdu.empty());
438 if (!m_rxOkTrace.IsEmpty())
439 {
440 m_rxOkTrace(psdu->GetPacket(),
441 rxSignalInfo.snr,
442 txVector.GetMode(staId),
443 txVector.GetPreambleType());
444 }
445 if (!m_rxOkCallback.IsNull())
446 {
447 m_rxOkCallback(psdu, rxSignalInfo, txVector, statusPerMpdu);
448 }
449}
450
451void
453{
454 NS_LOG_FUNCTION(this << *psdu << snr);
455 if (!m_rxErrorTrace.IsEmpty())
456 {
457 m_rxErrorTrace(psdu->GetPacket(), snr);
458 }
460 {
461 m_rxErrorCallback(psdu);
462 }
463}
464
465void
467 RxSignalInfo rxSignalInfo,
468 const WifiTxVector& txVector,
469 uint16_t staId,
470 const std::vector<bool>& statusPerMpdu)
471{
472 m_rxOutcomeTrace(ppdu, rxSignalInfo, txVector, statusPerMpdu);
473}
474
475void
483
484void
492
493void
503
504void
506 WifiChannelListType channelType,
507 const std::vector<Time>& per20MhzDurations)
508{
509 NS_LOG_FUNCTION(this << duration << channelType);
510 if (GetState() == WifiPhyState::RX)
511 {
512 return;
513 }
514 NotifyListeners(&WifiPhyListener::NotifyCcaBusyStart, duration, channelType, per20MhzDurations);
515 if (channelType != WIFI_CHANLIST_PRIMARY)
516 {
517 // WifiPhyStateHelper only updates CCA start and end durations for the primary channel
518 return;
519 }
520 Time now = Simulator::Now();
522 {
524 }
526 {
527 m_startCcaBusy = now;
528 }
529 m_endCcaBusy = std::max(m_endCcaBusy, now + duration);
530}
531
532void
534{
535 NS_LOG_FUNCTION(this);
536 Time now = Simulator::Now();
537 switch (GetState())
538 {
540 [[fallthrough]];
543 break;
544 case WifiPhyState::RX:
546 break;
547 default:
548 NS_FATAL_ERROR("Invalid WifiPhy state: " << GetState());
549 break;
550 }
552 m_sleeping = true;
553 m_startSleep = now;
556}
557
558void
570
571void
573{
574 NS_LOG_FUNCTION(this << operatingWidth);
575 NS_ASSERT(IsStateCcaBusy()); // abort is called (with OBSS_PD_CCA_RESET reason) before RX is set
576 // by payload start
580 std::vector<Time> per20MhzDurations;
581 if (operatingWidth >= MHz_u{40})
582 {
583 std::fill_n(std::back_inserter(per20MhzDurations),
584 Count20MHzSubchannels(operatingWidth),
585 Seconds(0));
586 }
588 Seconds(0),
590 per20MhzDurations);
592}
593
594void
596{
597 NS_LOG_FUNCTION(this);
598 Time now = Simulator::Now();
599 switch (GetState())
600 {
601 case WifiPhyState::RX:
602 /* The packet which is being received as well
603 * as its endRx event are cancelled by the caller.
604 */
606 m_endRx = now;
607 break;
608 case WifiPhyState::TX:
609 /* The packet which is being transmitted as well
610 * as its endTx event are cancelled by the caller.
611 */
613 m_endTx = now;
614 break;
616 [[fallthrough]];
619 break;
620 default:
621 NS_FATAL_ERROR("Invalid WifiPhy state.");
622 break;
623 }
625 m_isOff = true;
626 m_startOff = now;
629}
630
631void
642
643} // namespace ns3
#define Max(a, b)
bool IsNull() const
Check for null implementation.
Definition callback.h:555
A base class which provides memory management and object aggregation.
Definition object.h:78
Smart pointer class similar to boost::intrusive_ptr.
static Time Now()
Return the current simulation virtual time.
Definition simulator.cc:197
Simulation virtual time values and global simulation resolution.
Definition nstime.h:94
bool IsZero() const
Exactly equivalent to t == 0.
Definition nstime.h:304
a unique identifier for an interface.
Definition type-id.h:48
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition type-id.cc:1001
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 NotifyTxStart(Time duration, dBm_u txPower)=0
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 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.
void NotifyRxPpduOutcome(Ptr< const WifiPpdu > ppdu, RxSignalInfo rxSignalInfo, const WifiTxVector &txVector, uint16_t staId, const std::vector< bool > &statusPerMpdu)
Handle the outcome of a reception of a PPDU.
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 SwitchToTx(Time txDuration, const WifiConstPsduMap &psdus, dBm_u txPower, const WifiTxVector &txVector)
Switch state to TX for the given duration.
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.
TracedCallback< Ptr< const WifiPpdu >, RxSignalInfo, const WifiTxVector &, const std::vector< bool > & > m_rxOutcomeTrace
receive OK trace callback
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_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.
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
Time GetLastTime(std::initializer_list< WifiPhyState > states) const
void SwitchFromRxAbort(MHz_u operatingWidth)
Abort current reception following a CCA reset request.
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.
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:55
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition log.h:191
#define NS_LOG_TEMPLATE_DEFINE(name)
Initialize a reference to a Log component.
Definition log.h:225
#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:35
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition nstime.h:1344
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.
WifiPhyState
The state of the PHY layer.
@ SWITCHING
The PHY layer is switching to other channel.
@ TX
The PHY layer is sending a packet.
@ OFF
The PHY layer is switched off.
@ IDLE
The PHY layer is IDLE.
@ CCA_BUSY
The PHY layer has sense the medium busy through the CCA mechanism.
@ SLEEP
The PHY layer is sleeping.
@ RX
The PHY layer is receiving a packet.
std::size_t Count20MHzSubchannels(MHz_u channelWidth)
Return the number of 20 MHz subchannels covering the channel width.
Definition wifi-utils.h:134
std::unordered_map< uint16_t, Ptr< const WifiPsdu > > WifiConstPsduMap
Map of const PSDUs indexed by STA-ID.
Definition wifi-ppdu.h:38
RxSignalInfo structure containing info on the received signal.
Definition wifi-types.h:72
double snr
SNR in linear scale.
Definition wifi-types.h:73