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 * 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
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
35namespace ns3
36{
37
38NS_LOG_COMPONENT_DEFINE("WifiPhyStateHelper");
39
40NS_OBJECT_ENSURE_REGISTERED(WifiPhyStateHelper);
41
42TypeId
44{
45 static TypeId tid =
46 TypeId("ns3::WifiPhyStateHelper")
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(
59 "RxOutcome",
60 "The outcome of the decoding of the PPDU, including MPDU decoding status",
62 "ns3::WifiPhyStateHelper::RxOutcomeTracedCallback")
63 .AddTraceSource("RxError",
64 "A packet has been received unsuccessfuly.",
66 "ns3::WifiPhyStateHelper::RxEndErrorTracedCallback")
67 .AddTraceSource("Tx",
68 "Packet transmission is starting.",
70 "ns3::WifiPhyStateHelper::TxTracedCallback");
71 return tid;
72}
73
75 : NS_LOG_TEMPLATE_DEFINE("WifiPhyStateHelper"),
76 m_sleeping(false),
77 m_isOff(false),
78 m_endTx(Time{0}),
79 m_endRx(Time{0}),
80 m_endCcaBusy(Time{0}),
81 m_endSwitching(Time{0}),
82 m_endSleep(Time{0}),
83 m_endOff(Time{0}),
84 m_endIdle(Time{0}),
85 m_startTx(Time{0}),
86 m_startRx(Time{0}),
87 m_startCcaBusy(Time{0}),
88 m_startSwitching(Time{0}),
89 m_startSleep(Time{0}),
90 m_startOff(Time{0}),
91 m_previousStateChangeTime(Time{0})
92{
93 NS_LOG_FUNCTION(this);
94}
95
96void
98{
99 m_rxOkCallback = callback;
100}
101
102void
104{
105 m_rxErrorCallback = callback;
106}
107
108void
109WifiPhyStateHelper::RegisterListener(const std::shared_ptr<WifiPhyListener>& listener)
110{
111 m_listeners.emplace_back(listener);
112}
113
114void
115WifiPhyStateHelper::UnregisterListener(const std::shared_ptr<WifiPhyListener>& listener)
116{
117 m_listeners.remove_if([&listener](auto&& weakPtr) { return weakPtr.lock() == listener; });
118}
119
120bool
122{
123 return (GetState() == WifiPhyState::IDLE);
124}
125
126bool
128{
129 return (GetState() == WifiPhyState::CCA_BUSY);
130}
131
132bool
134{
135 return (GetState() == WifiPhyState::RX);
136}
137
138bool
140{
141 return (GetState() == WifiPhyState::TX);
142}
143
144bool
146{
147 return (GetState() == WifiPhyState::SWITCHING);
148}
149
150bool
152{
153 return (GetState() == WifiPhyState::SLEEP);
154}
155
156bool
158{
159 return (GetState() == WifiPhyState::OFF);
160}
161
162Time
164{
165 Time retval;
166
167 switch (GetState())
168 {
169 case WifiPhyState::RX:
170 retval = m_endRx - Simulator::Now();
171 break;
172 case WifiPhyState::TX:
173 retval = m_endTx - Simulator::Now();
174 break;
176 retval = m_endCcaBusy - Simulator::Now();
177 break;
179 retval = m_endSwitching - Simulator::Now();
180 break;
184 retval = Seconds(0);
185 break;
186 default:
187 NS_FATAL_ERROR("Invalid WifiPhy state.");
188 retval = Seconds(0);
189 break;
190 }
191 retval = Max(retval, Seconds(0));
192 return retval;
193}
194
195Time
197{
198 return m_startRx;
199}
200
201Time
203{
204 return m_endRx;
205}
206
207Time
208WifiPhyStateHelper::GetLastTime(std::initializer_list<WifiPhyState> states) const
209{
210 Time last{0};
211 auto currentState = GetState();
212
213 for (auto state : states)
214 {
215 if (state == currentState)
216 {
217 return Simulator::Now();
218 }
219
220 switch (state)
221 {
222 case WifiPhyState::RX:
223 last = std::max(last, m_endRx);
224 break;
225 case WifiPhyState::TX:
226 last = std::max(last, m_endTx);
227 break;
229 last = std::max(last, m_endCcaBusy);
230 break;
232 last = std::max(last, m_endSwitching);
233 break;
235 last = std::max(last, m_endSleep);
236 break;
238 last = std::max(last, m_endOff);
239 break;
241 last = std::max(last, m_endIdle);
242 break;
243 default:
244 NS_FATAL_ERROR("Invalid WifiPhy state " << state);
245 }
246 }
247 NS_ASSERT(last <= Simulator::Now());
248 return last;
249}
250
253{
254 const auto now = Simulator::Now();
255 if (m_isOff)
256 {
257 return WifiPhyState::OFF;
258 }
259 if (m_sleeping)
260 {
261 return WifiPhyState::SLEEP;
262 }
263 else if (m_endTx > now)
264 {
265 return WifiPhyState::TX;
266 }
267 else if (m_endRx > now)
268 {
269 return WifiPhyState::RX;
270 }
271 else if (m_endSwitching > now)
272 {
274 }
275 else if (m_endCcaBusy > now)
276 {
278 }
279 else
280 {
281 return WifiPhyState::IDLE;
282 }
283}
284
285void
287{
288 NS_LOG_FUNCTION(this);
289 const auto now = Simulator::Now();
290 WifiPhyState state = GetState();
291 if (state == WifiPhyState::CCA_BUSY)
292 {
293 m_endCcaBusy = now;
294 const auto ccaStart =
296 m_stateLogger(ccaStart, now - ccaStart, WifiPhyState::CCA_BUSY);
297 }
298 else if (state == WifiPhyState::IDLE)
299 {
300 m_endIdle = now;
301 const auto endAllButCcaBusy =
303 const auto idleStart = std::max(m_endCcaBusy, endAllButCcaBusy);
304 NS_ASSERT(idleStart <= now);
305 if (m_endCcaBusy > endAllButCcaBusy)
306 {
307 const auto ccaBusyStart = std::max(m_startCcaBusy, endAllButCcaBusy);
308 if (const auto ccaBusyDuration = idleStart - ccaBusyStart;
309 ccaBusyDuration.IsStrictlyPositive())
310 {
311 m_stateLogger(ccaBusyStart, ccaBusyDuration, WifiPhyState::CCA_BUSY);
312 }
313 }
314 if (const auto idleDuration = now - idleStart; idleDuration.IsStrictlyPositive())
315 {
316 m_stateLogger(idleStart, idleDuration, WifiPhyState::IDLE);
317 }
318 }
319}
320
321void
323 WifiConstPsduMap psdus,
324 double txPowerDbm,
325 const WifiTxVector& txVector)
326{
327 NS_LOG_FUNCTION(this << txDuration << psdus << txPowerDbm << txVector);
328 if (!m_txTrace.IsEmpty())
329 {
330 for (const auto& psdu : psdus)
331 {
332 m_txTrace(psdu.second->GetPacket(),
333 txVector.GetMode(psdu.first),
334 txVector.GetPreambleType(),
335 txVector.GetTxPowerLevel());
336 }
337 }
338 Time now = Simulator::Now();
339 switch (GetState())
340 {
341 case WifiPhyState::RX:
342 /* The packet which is being received as well
343 * as its endRx event are cancelled by the caller.
344 */
346 m_endRx = now;
347 break;
349 [[fallthrough]];
352 break;
353 default:
354 NS_FATAL_ERROR("Invalid WifiPhy state.");
355 break;
356 }
357 m_stateLogger(now, txDuration, WifiPhyState::TX);
359 m_endTx = now + txDuration;
360 m_startTx = now;
361 NotifyListeners(&WifiPhyListener::NotifyTxStart, txDuration, txPowerDbm);
362}
363
364void
366{
367 NS_LOG_FUNCTION(this << rxDuration);
369 Time now = Simulator::Now();
370 switch (GetState())
371 {
373 [[fallthrough]];
376 break;
377 default:
378 NS_FATAL_ERROR("Invalid WifiPhy state " << GetState());
379 break;
380 }
382 m_startRx = now;
383 m_endRx = now + rxDuration;
386}
387
388void
390{
391 NS_LOG_FUNCTION(this << switchingDuration);
392 Time now = Simulator::Now();
393 switch (GetState())
394 {
395 case WifiPhyState::RX:
396 /* The packet which is being received as well
397 * as its endRx event are cancelled by the caller.
398 */
400 m_endRx = now;
401 break;
403 [[fallthrough]];
406 break;
407 default:
408 NS_FATAL_ERROR("Invalid WifiPhy state.");
409 break;
410 }
411
412 m_endCcaBusy = std::min(now, m_endCcaBusy);
413 m_stateLogger(now, switchingDuration, WifiPhyState::SWITCHING);
415 m_startSwitching = now;
416 m_endSwitching = now + switchingDuration;
418 NS_ASSERT(switchingDuration.IsZero() || IsStateSwitching());
419}
420
421void
423 RxSignalInfo rxSignalInfo,
424 const WifiTxVector& txVector)
425{
426 NS_LOG_FUNCTION(this << *psdu << rxSignalInfo << txVector);
427 if (!m_rxOkCallback.IsNull())
428 {
429 m_rxOkCallback(psdu, rxSignalInfo, txVector, {});
430 }
431}
432
433void
435 RxSignalInfo rxSignalInfo,
436 const WifiTxVector& txVector,
437 uint16_t staId,
438 const std::vector<bool>& statusPerMpdu)
439{
440 NS_LOG_FUNCTION(this << *psdu << rxSignalInfo << txVector << staId << statusPerMpdu.size()
441 << std::all_of(statusPerMpdu.begin(), statusPerMpdu.end(), [](bool v) {
442 return v;
443 })); // returns true if all true
444 NS_ASSERT(!statusPerMpdu.empty());
445 if (!m_rxOkTrace.IsEmpty())
446 {
447 m_rxOkTrace(psdu->GetPacket(),
448 rxSignalInfo.snr,
449 txVector.GetMode(staId),
450 txVector.GetPreambleType());
451 }
452 if (!m_rxOkCallback.IsNull())
453 {
454 m_rxOkCallback(psdu, rxSignalInfo, txVector, statusPerMpdu);
455 }
456}
457
458void
460{
461 NS_LOG_FUNCTION(this << *psdu << snr);
462 if (!m_rxErrorTrace.IsEmpty())
463 {
464 m_rxErrorTrace(psdu->GetPacket(), snr);
465 }
467 {
468 m_rxErrorCallback(psdu);
469 }
470}
471
472void
474 RxSignalInfo rxSignalInfo,
475 const WifiTxVector& txVector,
476 uint16_t staId,
477 const std::vector<bool>& statusPerMpdu)
478{
479 m_rxOutcomeTrace(ppdu, rxSignalInfo, txVector, statusPerMpdu);
480}
481
482void
484{
485 NS_LOG_FUNCTION(this);
489}
490
491void
493{
494 NS_LOG_FUNCTION(this);
498}
499
500void
502{
503 NS_LOG_FUNCTION(this);
504 Time now = Simulator::Now();
509}
510
511void
513 WifiChannelListType channelType,
514 const std::vector<Time>& per20MhzDurations)
515{
516 NS_LOG_FUNCTION(this << duration << channelType);
517 if (GetState() == WifiPhyState::RX)
518 {
519 return;
520 }
521 NotifyListeners(&WifiPhyListener::NotifyCcaBusyStart, duration, channelType, per20MhzDurations);
522 if (channelType != WIFI_CHANLIST_PRIMARY)
523 {
524 // WifiPhyStateHelper only updates CCA start and end durations for the primary channel
525 return;
526 }
527 Time now = Simulator::Now();
529 {
531 }
533 {
534 m_startCcaBusy = now;
535 }
536 m_endCcaBusy = std::max(m_endCcaBusy, now + duration);
537}
538
539void
541{
542 NS_LOG_FUNCTION(this);
543 Time now = Simulator::Now();
544 switch (GetState())
545 {
547 [[fallthrough]];
550 break;
551 default:
552 NS_FATAL_ERROR("Invalid WifiPhy state.");
553 break;
554 }
556 m_sleeping = true;
557 m_startSleep = now;
560}
561
562void
564{
565 NS_LOG_FUNCTION(this);
567 Time now = Simulator::Now();
570 m_sleeping = false;
571 m_endSleep = now;
573}
574
575void
577{
578 NS_LOG_FUNCTION(this << operatingWidth);
579 NS_ASSERT(IsStateCcaBusy()); // abort is called (with OBSS_PD_CCA_RESET reason) before RX is set
580 // by payload start
584 std::vector<Time> per20MhzDurations;
585 if (operatingWidth >= 40)
586 {
587 std::fill_n(std::back_inserter(per20MhzDurations), (operatingWidth / 20), Seconds(0));
588 }
590 Seconds(0),
592 per20MhzDurations);
594}
595
596void
598{
599 NS_LOG_FUNCTION(this);
600 Time now = Simulator::Now();
601 switch (GetState())
602 {
603 case WifiPhyState::RX:
604 /* The packet which is being received as well
605 * as its endRx event are cancelled by the caller.
606 */
608 m_endRx = now;
609 break;
610 case WifiPhyState::TX:
611 /* The packet which is being transmitted as well
612 * as its endTx event are cancelled by the caller.
613 */
615 m_endTx = now;
616 break;
618 [[fallthrough]];
621 break;
622 default:
623 NS_FATAL_ERROR("Invalid WifiPhy state.");
624 break;
625 }
627 m_isOff = true;
628 m_startOff = now;
631}
632
633void
635{
636 NS_LOG_FUNCTION(this);
638 Time now = Simulator::Now();
640 m_isOff = false;
641 m_endOff = now;
643}
644
645} // namespace ns3
#define Max(a, b)
bool IsNull() const
Check for null implementation.
Definition: callback.h:571
A base class which provides memory management and object aggregation.
Definition: object.h:89
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:77
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 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:932
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.
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 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_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
Time GetLastTime(std::initializer_list< WifiPhyState > states) const
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.
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
#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:1319
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.
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.
RxSignalInfo structure containing info on the received signal.
Definition: phy-entity.h:69
double snr
SNR in linear scale.
Definition: phy-entity.h:70