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("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(Time{0}),
74 m_endRx(Time{0}),
75 m_endCcaBusy(Time{0}),
76 m_endSwitching(Time{0}),
77 m_endSleep(Time{0}),
78 m_endOff(Time{0}),
79 m_endIdle(Time{0}),
80 m_startTx(Time{0}),
81 m_startRx(Time{0}),
82 m_startCcaBusy(Time{0}),
83 m_startSwitching(Time{0}),
84 m_startSleep(Time{0}),
85 m_startOff(Time{0}),
86 m_previousStateChangeTime(Time{0})
87{
88 NS_LOG_FUNCTION(this);
89}
90
91void
93{
94 m_rxOkCallback = callback;
95}
96
97void
99{
100 m_rxErrorCallback = callback;
101}
102
103void
104WifiPhyStateHelper::RegisterListener(const std::shared_ptr<WifiPhyListener>& listener)
105{
106 m_listeners.emplace_back(listener);
107}
108
109void
110WifiPhyStateHelper::UnregisterListener(const std::shared_ptr<WifiPhyListener>& listener)
111{
112 m_listeners.remove_if([&listener](auto&& weakPtr) { return weakPtr.lock() == listener; });
113}
114
115bool
117{
118 return (GetState() == WifiPhyState::IDLE);
119}
120
121bool
123{
124 return (GetState() == WifiPhyState::CCA_BUSY);
125}
126
127bool
129{
130 return (GetState() == WifiPhyState::RX);
131}
132
133bool
135{
136 return (GetState() == WifiPhyState::TX);
137}
138
139bool
141{
142 return (GetState() == WifiPhyState::SWITCHING);
143}
144
145bool
147{
148 return (GetState() == WifiPhyState::SLEEP);
149}
150
151bool
153{
154 return (GetState() == WifiPhyState::OFF);
155}
156
157Time
159{
160 Time retval;
161
162 switch (GetState())
163 {
164 case WifiPhyState::RX:
165 retval = m_endRx - Simulator::Now();
166 break;
167 case WifiPhyState::TX:
168 retval = m_endTx - Simulator::Now();
169 break;
171 retval = m_endCcaBusy - Simulator::Now();
172 break;
174 retval = m_endSwitching - Simulator::Now();
175 break;
179 retval = Seconds(0);
180 break;
181 default:
182 NS_FATAL_ERROR("Invalid WifiPhy state.");
183 retval = Seconds(0);
184 break;
185 }
186 retval = Max(retval, Seconds(0));
187 return retval;
188}
189
190Time
192{
193 return m_startRx;
194}
195
196Time
198{
199 return m_endRx;
200}
201
202Time
203WifiPhyStateHelper::GetLastTime(std::initializer_list<WifiPhyState> states) const
204{
205 Time last{0};
206 auto currentState = GetState();
207
208 for (auto state : states)
209 {
210 if (state == currentState)
211 {
212 return Simulator::Now();
213 }
214
215 switch (state)
216 {
217 case WifiPhyState::RX:
218 last = std::max(last, m_endRx);
219 break;
220 case WifiPhyState::TX:
221 last = std::max(last, m_endTx);
222 break;
224 last = std::max(last, m_endCcaBusy);
225 break;
227 last = std::max(last, m_endSwitching);
228 break;
230 last = std::max(last, m_endSleep);
231 break;
233 last = std::max(last, m_endOff);
234 break;
236 last = std::max(last, m_endIdle);
237 break;
238 default:
239 NS_FATAL_ERROR("Invalid WifiPhy state " << state);
240 }
241 }
242 NS_ASSERT(last <= Simulator::Now());
243 return last;
244}
245
248{
249 const auto now = Simulator::Now();
250 if (m_isOff)
251 {
252 return WifiPhyState::OFF;
253 }
254 if (m_sleeping)
255 {
256 return WifiPhyState::SLEEP;
257 }
258 else if (m_endTx > now)
259 {
260 return WifiPhyState::TX;
261 }
262 else if (m_endRx > now)
263 {
264 return WifiPhyState::RX;
265 }
266 else if (m_endSwitching > now)
267 {
269 }
270 else if (m_endCcaBusy > now)
271 {
273 }
274 else
275 {
276 return WifiPhyState::IDLE;
277 }
278}
279
280void
282{
283 NS_LOG_FUNCTION(this);
284 const auto now = Simulator::Now();
285 WifiPhyState state = GetState();
286 if (state == WifiPhyState::CCA_BUSY)
287 {
288 m_endCcaBusy = now;
289 const auto ccaStart =
291 m_stateLogger(ccaStart, now - ccaStart, WifiPhyState::CCA_BUSY);
292 }
293 else if (state == WifiPhyState::IDLE)
294 {
295 m_endIdle = now;
296 const auto endAllButCcaBusy =
298 const auto idleStart = std::max(m_endCcaBusy, endAllButCcaBusy);
299 NS_ASSERT(idleStart <= now);
300 if (m_endCcaBusy > endAllButCcaBusy)
301 {
302 const auto ccaBusyStart = std::max(m_startCcaBusy, endAllButCcaBusy);
303 if (const auto ccaBusyDuration = idleStart - ccaBusyStart;
304 ccaBusyDuration.IsStrictlyPositive())
305 {
306 m_stateLogger(ccaBusyStart, ccaBusyDuration, WifiPhyState::CCA_BUSY);
307 }
308 }
309 if (const auto idleDuration = now - idleStart; idleDuration.IsStrictlyPositive())
310 {
311 m_stateLogger(idleStart, idleDuration, WifiPhyState::IDLE);
312 }
313 }
314}
315
316void
318 WifiConstPsduMap psdus,
319 double txPowerDbm,
320 const WifiTxVector& txVector)
321{
322 NS_LOG_FUNCTION(this << txDuration << psdus << txPowerDbm << txVector);
323 if (!m_txTrace.IsEmpty())
324 {
325 for (const auto& psdu : psdus)
326 {
327 m_txTrace(psdu.second->GetPacket(),
328 txVector.GetMode(psdu.first),
329 txVector.GetPreambleType(),
330 txVector.GetTxPowerLevel());
331 }
332 }
333 Time now = Simulator::Now();
334 switch (GetState())
335 {
336 case WifiPhyState::RX:
337 /* The packet which is being received as well
338 * as its endRx event are cancelled by the caller.
339 */
341 m_endRx = now;
342 break;
344 [[fallthrough]];
347 break;
348 default:
349 NS_FATAL_ERROR("Invalid WifiPhy state.");
350 break;
351 }
352 m_stateLogger(now, txDuration, WifiPhyState::TX);
354 m_endTx = now + txDuration;
355 m_startTx = now;
356 NotifyListeners(&WifiPhyListener::NotifyTxStart, txDuration, txPowerDbm);
357}
358
359void
361{
362 NS_LOG_FUNCTION(this << rxDuration);
364 Time now = Simulator::Now();
365 switch (GetState())
366 {
368 [[fallthrough]];
371 break;
372 default:
373 NS_FATAL_ERROR("Invalid WifiPhy state " << GetState());
374 break;
375 }
377 m_startRx = now;
378 m_endRx = now + rxDuration;
381}
382
383void
385{
386 NS_LOG_FUNCTION(this << switchingDuration);
387 Time now = Simulator::Now();
388 switch (GetState())
389 {
390 case WifiPhyState::RX:
391 /* The packet which is being received as well
392 * as its endRx event are cancelled by the caller.
393 */
395 m_endRx = now;
396 break;
398 [[fallthrough]];
401 break;
402 default:
403 NS_FATAL_ERROR("Invalid WifiPhy state.");
404 break;
405 }
406
407 m_endCcaBusy = std::min(now, m_endCcaBusy);
408 m_stateLogger(now, switchingDuration, WifiPhyState::SWITCHING);
410 m_startSwitching = now;
411 m_endSwitching = now + switchingDuration;
413 NS_ASSERT(switchingDuration.IsZero() || IsStateSwitching());
414}
415
416void
418 RxSignalInfo rxSignalInfo,
419 const WifiTxVector& txVector)
420{
421 NS_LOG_FUNCTION(this << *psdu << rxSignalInfo << txVector);
422 if (!m_rxOkCallback.IsNull())
423 {
424 m_rxOkCallback(psdu, rxSignalInfo, txVector, {});
425 }
426}
427
428void
430 RxSignalInfo rxSignalInfo,
431 const WifiTxVector& txVector,
432 uint16_t staId,
433 const std::vector<bool>& statusPerMpdu)
434{
435 NS_LOG_FUNCTION(this << *psdu << rxSignalInfo << txVector << staId << statusPerMpdu.size()
436 << std::all_of(statusPerMpdu.begin(), statusPerMpdu.end(), [](bool v) {
437 return v;
438 })); // returns true if all true
439 NS_ASSERT(!statusPerMpdu.empty());
440 if (!m_rxOkTrace.IsEmpty())
441 {
442 m_rxOkTrace(psdu->GetPacket(),
443 rxSignalInfo.snr,
444 txVector.GetMode(staId),
445 txVector.GetPreambleType());
446 }
447 if (!m_rxOkCallback.IsNull())
448 {
449 m_rxOkCallback(psdu, rxSignalInfo, txVector, statusPerMpdu);
450 }
451}
452
453void
455{
456 NS_LOG_FUNCTION(this << *psdu << snr);
457 if (!m_rxErrorTrace.IsEmpty())
458 {
459 m_rxErrorTrace(psdu->GetPacket(), snr);
460 }
462 {
463 m_rxErrorCallback(psdu);
464 }
465}
466
467void
469{
470 NS_LOG_FUNCTION(this);
474}
475
476void
478{
479 NS_LOG_FUNCTION(this);
483}
484
485void
487{
488 NS_LOG_FUNCTION(this);
489 Time now = Simulator::Now();
494}
495
496void
498 WifiChannelListType channelType,
499 const std::vector<Time>& per20MhzDurations)
500{
501 NS_LOG_FUNCTION(this << duration << channelType);
502 if (GetState() == WifiPhyState::RX)
503 {
504 return;
505 }
506 NotifyListeners(&WifiPhyListener::NotifyCcaBusyStart, duration, channelType, per20MhzDurations);
507 if (channelType != WIFI_CHANLIST_PRIMARY)
508 {
509 // WifiPhyStateHelper only updates CCA start and end durations for the primary channel
510 return;
511 }
512 Time now = Simulator::Now();
514 {
516 }
518 {
519 m_startCcaBusy = now;
520 }
521 m_endCcaBusy = std::max(m_endCcaBusy, now + duration);
522}
523
524void
526{
527 NS_LOG_FUNCTION(this);
528 Time now = Simulator::Now();
529 switch (GetState())
530 {
532 [[fallthrough]];
535 break;
536 default:
537 NS_FATAL_ERROR("Invalid WifiPhy state.");
538 break;
539 }
541 m_sleeping = true;
542 m_startSleep = now;
545}
546
547void
549{
550 NS_LOG_FUNCTION(this);
552 Time now = Simulator::Now();
555 m_sleeping = false;
556 m_endSleep = now;
558}
559
560void
562{
563 NS_LOG_FUNCTION(this << operatingWidth);
564 NS_ASSERT(IsStateCcaBusy()); // abort is called (with OBSS_PD_CCA_RESET reason) before RX is set
565 // by payload start
569 std::vector<Time> per20MhzDurations;
570 if (operatingWidth >= 40)
571 {
572 std::fill_n(std::back_inserter(per20MhzDurations), (operatingWidth / 20), Seconds(0));
573 }
575 Seconds(0),
577 per20MhzDurations);
579}
580
581void
583{
584 NS_LOG_FUNCTION(this);
585 Time now = Simulator::Now();
586 switch (GetState())
587 {
588 case WifiPhyState::RX:
589 /* The packet which is being received as well
590 * as its endRx event are cancelled by the caller.
591 */
593 m_endRx = now;
594 break;
595 case WifiPhyState::TX:
596 /* The packet which is being transmitted as well
597 * as its endTx event are cancelled by the caller.
598 */
600 m_endTx = now;
601 break;
603 [[fallthrough]];
606 break;
607 default:
608 NS_FATAL_ERROR("Invalid WifiPhy state.");
609 break;
610 }
612 m_isOff = true;
613 m_startOff = now;
616}
617
618void
620{
621 NS_LOG_FUNCTION(this);
623 Time now = Simulator::Now();
625 m_isOff = false;
626 m_endOff = now;
628}
629
630} // 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.
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
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