A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
channel-access-manager.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 "txop.h"
12#include "wifi-mac-queue.h"
13#include "wifi-phy-listener.h"
14#include "wifi-phy.h"
15
16#include "ns3/eht-frame-exchange-manager.h"
17#include "ns3/log.h"
18#include "ns3/simulator.h"
19
20#include <sstream>
21
22#undef NS_LOG_APPEND_CONTEXT
23#define NS_LOG_APPEND_CONTEXT std::clog << "[link=" << +m_linkId << "] "
24
25namespace ns3
26{
27
28NS_LOG_COMPONENT_DEFINE("ChannelAccessManager");
29
30NS_OBJECT_ENSURE_REGISTERED(ChannelAccessManager);
31
33
34/**
35 * Listener for PHY events. Forwards to ChannelAccessManager.
36 * The ChannelAccessManager may handle multiple PHY listeners connected to distinct PHYs,
37 * but only one listener at a time can be active. Notifications from inactive listeners are
38 * ignored by the ChannelAccessManager, except for the channel switch notification.
39 * Inactive PHY listeners are typically configured by 11be EMLSR clients.
40 */
42{
43 public:
44 /**
45 * Create a PhyListener for the given ChannelAccessManager.
46 *
47 * @param cam the ChannelAccessManager
48 */
50 : m_cam(cam),
51 m_active(true)
52 {
53 }
54
55 ~PhyListener() override
56 {
57 }
58
59 /**
60 * Set this listener to be active or not.
61 *
62 * @param active whether this listener is active or not
63 */
64 void SetActive(bool active)
65 {
66 m_active = active;
67 }
68
69 /**
70 * @return whether this listener is active or not
71 */
72 bool IsActive() const
73 {
74 return m_active;
75 }
76
77 void NotifyRxStart(Time duration) override
78 {
79 if (m_active)
80 {
81 m_cam->NotifyRxStartNow(duration);
82 }
83 }
84
85 void NotifyRxEndOk() override
86 {
87 if (m_active)
88 {
90 }
91 }
92
93 void NotifyRxEndError(const WifiTxVector& txVector) override
94 {
95 if (m_active)
96 {
97 m_cam->NotifyRxEndErrorNow(txVector);
98 }
99 }
100
101 void NotifyTxStart(Time duration, dBm_u txPower) override
102 {
103 if (m_active)
104 {
105 m_cam->NotifyTxStartNow(duration);
106 }
107 }
108
110 WifiChannelListType channelType,
111 const std::vector<Time>& per20MhzDurations) override
112 {
113 if (m_active)
114 {
115 m_cam->NotifyCcaBusyStartNow(duration, channelType, per20MhzDurations);
116 }
117 }
118
119 void NotifySwitchingStart(Time duration) override
120 {
121 m_cam->NotifySwitchingStartNow(this, duration);
122 }
123
124 void NotifySleep() override
125 {
126 if (m_active)
127 {
129 }
130 }
131
132 void NotifyOff() override
133 {
134 if (m_active)
135 {
137 }
138 }
139
140 void NotifyWakeup() override
141 {
142 if (m_active)
143 {
145 }
146 }
147
148 void NotifyOn() override
149 {
150 if (m_active)
151 {
153 }
154 }
155
156 private:
157 ns3::ChannelAccessManager* m_cam; //!< ChannelAccessManager to forward events to
158 bool m_active; //!< whether this PHY listener is active
159};
160
161/****************************************************************
162 * Implement the channel access manager of all Txop holders
163 ****************************************************************/
164
165TypeId
167{
168 static TypeId tid =
169 TypeId("ns3::ChannelAccessManager")
171 .SetGroupName("Wifi")
172 .AddConstructor<ChannelAccessManager>()
173 .AddAttribute("GenerateBackoffIfTxopWithoutTx",
174 "Specify whether the backoff should be invoked when the AC gains the "
175 "right to start a TXOP but it does not transmit any frame "
176 "(e.g., due to constraints associated with EMLSR operations), "
177 "provided that the queue is not actually empty.",
178 BooleanValue(false),
182 .AddAttribute("ProactiveBackoff",
183 "Specify whether a new backoff value is generated when a CCA busy "
184 "period starts, the backoff counter is zero and the station is not a "
185 "TXOP holder. This is useful to generate a new backoff value when, "
186 "e.g., the backoff counter reaches zero, the station does not transmit "
187 "and subsequently the medium becomes busy.",
188 BooleanValue(false),
191 .AddAttribute("ResetBackoffThreshold",
192 "If no PHY operates on this link for a period greater than this "
193 "threshold, all the backoffs are reset.",
194 TimeValue(Time{0}),
197 .AddAttribute("NSlotsLeft",
198 "The NSlotsLeftAlert trace source is fired when the number of remaining "
199 "backoff slots for any AC is equal to or less than the value of this "
200 "attribute. Note that the trace source is fired only if the AC for which "
201 "the previous condition is met has requested channel access. Also, if "
202 "the value of this attribute is zero, the trace source is never fired.",
203 UintegerValue(0),
206 .AddAttribute("NSlotsLeftMinDelay",
207 "The minimum gap between the end of a medium busy event and the time "
208 "the NSlotsLeftAlert trace source can be fired.",
212 .AddTraceSource("NSlotsLeftAlert",
213 "The number of remaining backoff slots for the AC with the given index "
214 "reached the threshold set through the NSlotsLeft attribute.",
216 "ns3::ChannelAccessManager::NSlotsLeftCallback");
217 return tid;
218}
219
221 : m_lastAckTimeoutEnd(0),
222 m_lastCtsTimeoutEnd(0),
223 m_lastNavEnd(0),
224 m_lastRx({MicroSeconds(0), MicroSeconds(0)}),
225 m_lastRxReceivedOk(true),
226 m_lastTxEnd(0),
227 m_lastSwitchingEnd(0),
228 m_lastSleepEnd(0),
229 m_lastOffEnd(0),
230 m_linkId(0)
231{
232 NS_LOG_FUNCTION(this);
233 InitLastBusyStructs();
234}
235
240
241void
247
248void
250{
251 NS_LOG_FUNCTION(this);
252 for (Ptr<Txop> i : m_txops)
253 {
254 i->Dispose();
255 i = nullptr;
256 }
257 m_phy = nullptr;
258 m_feManager = nullptr;
259 m_phyListeners.clear();
260}
261
262std::shared_ptr<PhyListener>
264{
265 if (auto listenerIt = m_phyListeners.find(phy); listenerIt != m_phyListeners.end())
266 {
267 return listenerIt->second;
268 }
269 return nullptr;
270}
271
272void
274{
275 NS_LOG_FUNCTION(this << phy);
276
277 const auto now = Simulator::Now();
278 auto phyListener = GetPhyListener(phy);
279
280 if (phyListener)
281 {
282 // a PHY listener for the given PHY already exists, it must be inactive
283 NS_ASSERT_MSG(!phyListener->IsActive(),
284 "There is already an active listener registered for given PHY");
285 NS_ASSERT_MSG(!m_phy, "Cannot reactivate a listener if another PHY is active");
286 phyListener->SetActive(true);
287 // if a PHY listener already exists, the PHY was disconnected and now reconnected to the
288 // channel access manager; unregister the listener and register again (below) to get
289 // updated CCA busy information
290 phy->UnregisterListener(phyListener);
291 // we expect that the PHY is reconnected immediately after the other PHY left the link:
292 // reset the start of m_lastNoPhy so as to ignore this event
296 }
297 else
298 {
299 phyListener = std::make_shared<PhyListener>(this);
300 m_phyListeners.emplace(phy, phyListener);
301 if (m_phy)
302 {
304 }
305 else
306 {
307 // no PHY operating on this link and no previous PHY listener to reactivate
308 m_lastSwitchingEnd = now;
309 m_lastNoPhy.end = now;
311 {
313 }
314 }
315 }
316
317 m_phy = phy; // this is the new active PHY
319 phy->RegisterListener(phyListener);
320}
321
322void
324{
325 NS_LOG_FUNCTION(this << phy);
326 if (auto phyListener = GetPhyListener(phy))
327 {
328 phy->UnregisterListener(phyListener);
329 m_phyListeners.erase(phy);
330 // reset m_phy if we are removing listener registered for the active PHY
331 if (m_phy == phy)
332 {
335 m_phy = nullptr;
337 }
338 }
339}
340
341void
343{
344 NS_LOG_FUNCTION(this << phy);
345 if (auto listener = GetPhyListener(phy))
346 {
347 listener->SetActive(false);
348 }
349}
350
351void
353 const WifiPhyOperatingChannel& channel,
354 uint8_t linkId)
355{
356 NS_LOG_FUNCTION(this << phy << channel << linkId);
358 "The given PHY is already expected to switch channel");
359 m_switchingEmlsrLinks.emplace(phy, EmlsrLinkSwitchInfo{channel, linkId});
360}
361
362void
364{
365 NS_LOG_FUNCTION(this << +linkId);
366 m_linkId = linkId;
367}
368
369void
371{
372 NS_LOG_FUNCTION(this << feManager);
373 m_feManager = feManager;
374 m_feManager->SetChannelAccessManager(this);
375}
376
377Time
379{
380 if (m_phy)
381 {
383 }
384 return m_cachedSlot;
385}
386
387Time
389{
390 if (m_phy)
391 {
393 }
394 return m_cachedSifs;
395}
396
397Time
402
403void
405{
406 NS_LOG_FUNCTION(this << txop);
407 m_txops.push_back(txop);
408}
409
410void
412{
413 NS_LOG_FUNCTION(this);
414 const auto now = Simulator::Now();
415
417 m_lastIdle.emplace(WIFI_CHANLIST_PRIMARY, Timespan{now, now});
418
419 const auto width = m_phy ? m_phy->GetChannelWidth() : MHz_u{0};
420 std::size_t size = (width > MHz_u{20} && m_phy->GetStandard() >= WIFI_STANDARD_80211ax)
421 ? Count20MHzSubchannels(width)
422 : 0;
423 m_lastPer20MHzBusyEnd.resize(size, now);
424
426 {
427 return;
428 }
429
430 if (width >= MHz_u{40})
431 {
433 m_lastIdle.emplace(WIFI_CHANLIST_SECONDARY, Timespan{now, now});
434 }
435 else
436 {
439 }
440
441 if (width >= MHz_u{80})
442 {
445 }
446 else
447 {
450 }
451
452 if (width >= MHz_u{160})
453 {
456 }
457 else
458 {
461 }
462
463 // TODO Add conditions for new channel widths as they get supported
464}
465
466void
468{
469 NS_LOG_FUNCTION(this);
470 Time now = Simulator::Now();
471
473
474 // reset all values
475 for (auto& [chType, time] : m_lastBusyEnd)
476 {
477 time = now;
478 }
479
480 for (auto& [chType, timeSpan] : m_lastIdle)
481 {
482 timeSpan = Timespan{now, now};
483 }
484
485 for (auto& time : m_lastPer20MHzBusyEnd)
486 {
487 time = now;
488 }
489}
490
491bool
493{
494 NS_LOG_FUNCTION(this);
495 Time now = Simulator::Now();
496 return (m_lastRx.end > now) // RX
497 || (m_lastTxEnd > now) // TX
498 || (m_lastNavEnd > now) // NAV busy
499 // an EDCA TXOP is obtained based solely on activity of the primary channel
500 // (Sec. 10.23.2.5 of IEEE 802.11-2020)
501 || (m_lastBusyEnd.at(WIFI_CHANLIST_PRIMARY) > now); // CCA busy
502}
503
504bool
506 bool hadFramesToTransmit,
507 bool checkMediumBusy)
508{
509 NS_LOG_FUNCTION(this << txop << hadFramesToTransmit << checkMediumBusy);
510
511 // No backoff needed if in sleep mode or off. Checking if m_phy is nullptr is a workaround
512 // needed for EMLSR and may be removed in the future
513 if (!m_phy || m_phy->IsStateSleep() || m_phy->IsStateOff())
514 {
515 return false;
516 }
517
518 // the Txop might have a stale value of remaining backoff slots
520
521 /*
522 * From section 10.3.4.2 "Basic access" of IEEE 802.11-2016:
523 *
524 * A STA may transmit an MPDU when it is operating under the DCF access
525 * method, either in the absence of a PC, or in the CP of the PCF access
526 * method, when the STA determines that the medium is idle when a frame is
527 * queued for transmission, and remains idle for a period of a DIFS, or an
528 * EIFS (10.3.2.3.7) from the end of the immediately preceding medium-busy
529 * event, whichever is the greater, and the backoff timer is zero. Otherwise
530 * the random backoff procedure described in 10.3.4.3 shall be followed.
531 *
532 * From section 10.22.2.2 "EDCA backoff procedure" of IEEE 802.11-2016:
533 *
534 * The backoff procedure shall be invoked by an EDCAF when any of the following
535 * events occurs:
536 * a) An MA-UNITDATA.request primitive is received that causes a frame with that AC
537 * to be queued for transmission such that one of the transmit queues associated
538 * with that AC has now become non-empty and any other transmit queues
539 * associated with that AC are empty; the medium is busy on the primary channel
540 */
541 if (!hadFramesToTransmit && txop->HasFramesToTransmit(m_linkId) &&
542 txop->GetAccessStatus(m_linkId) != Txop::GRANTED && txop->GetBackoffSlots(m_linkId) == 0)
543 {
544 if (checkMediumBusy && !IsBusy())
545 {
546 // medium idle. If this is a DCF, use immediate access (we can transmit
547 // in a DIFS if the medium remains idle). If this is an EDCAF, update
548 // the backoff start time kept by the EDCAF to the current time in order
549 // to correctly align the backoff start time at the next slot boundary
550 // (performed by the next call to ChannelAccessManager::RequestAccess())
551 Time delay =
552 (txop->IsQosTxop() ? Seconds(0) : GetSifs() + txop->GetAifsn(m_linkId) * GetSlot());
553 txop->UpdateBackoffSlotsNow(0, Simulator::Now() + delay, m_linkId);
554 }
555 else
556 {
557 // medium busy, backoff is needed
558 return true;
559 }
560 }
561 return false;
562}
563
564void
566{
567 NS_LOG_FUNCTION(this << txop);
568 if (m_phy && txop->HasFramesToTransmit(m_linkId))
569 {
571 }
572 // Deny access if in sleep mode or off. Checking if m_phy is nullptr is a workaround
573 // needed for EMLSR and may be removed in the future
574 if (!m_phy || m_phy->IsStateSleep() || m_phy->IsStateOff())
575 {
576 return;
577 }
578 /*
579 * EDCAF operations shall be performed at slot boundaries (Sec. 10.22.2.4 of 802.11-2016)
580 */
581 Time accessGrantStart = GetAccessGrantStart() + (txop->GetAifsn(m_linkId) * GetSlot());
582
583 if (txop->IsQosTxop() && txop->GetBackoffStart(m_linkId) > accessGrantStart)
584 {
585 // The backoff start time reported by the EDCAF is more recent than the last
586 // time the medium was busy plus an AIFS, hence we need to align it to the
587 // next slot boundary.
588 Time diff = txop->GetBackoffStart(m_linkId) - accessGrantStart;
589 uint32_t nIntSlots = (diff / GetSlot()).GetHigh() + 1;
590 txop->UpdateBackoffSlotsNow(0, accessGrantStart + (nIntSlots * GetSlot()), m_linkId);
591 }
592
594 NS_ASSERT(txop->GetAccessStatus(m_linkId) != Txop::REQUESTED);
595 txop->NotifyAccessRequested(m_linkId);
598}
599
600void
602{
603 NS_LOG_FUNCTION(this);
604 uint32_t k = 0;
605 const auto now = Simulator::Now();
606 const auto accessGrantStart = GetAccessGrantStart();
607 for (auto i = m_txops.begin(); i != m_txops.end(); k++)
608 {
609 Ptr<Txop> txop = *i;
610 if (txop->GetAccessStatus(m_linkId) == Txop::REQUESTED &&
611 (!txop->IsQosTxop() || !StaticCast<QosTxop>(txop)->EdcaDisabled(m_linkId)) &&
612 GetBackoffEndFor(txop, accessGrantStart) <= now)
613 {
614 /**
615 * This is the first Txop we find with an expired backoff and which
616 * needs access to the medium. i.e., it has data to send.
617 */
618 NS_LOG_DEBUG("dcf " << k << " needs access. backoff expired. access granted. slots="
619 << txop->GetBackoffSlots(m_linkId));
620 i++; // go to the next item in the list.
621 k++;
622 std::vector<Ptr<Txop>> internalCollisionTxops;
623 for (auto j = i; j != m_txops.end(); j++, k++)
624 {
625 Ptr<Txop> otherTxop = *j;
626 if (otherTxop->GetAccessStatus(m_linkId) == Txop::REQUESTED &&
627 GetBackoffEndFor(otherTxop, accessGrantStart) <= now)
628 {
630 "dcf " << k << " needs access. backoff expired. internal collision. slots="
631 << otherTxop->GetBackoffSlots(m_linkId));
632 /**
633 * all other Txops with a lower priority whose backoff
634 * has expired and which needed access to the medium
635 * must be notified that we did get an internal collision.
636 */
637 internalCollisionTxops.push_back(otherTxop);
638 }
639 }
640
641 /**
642 * Now, we notify all of these changes in one go if the EDCAF winning
643 * the contention actually transmitted a frame. It is necessary to
644 * perform first the calculations of which Txops are colliding and then
645 * only apply the changes because applying the changes through notification
646 * could change the global state of the manager, and, thus, could change
647 * the result of the calculations.
648 */
650 // If we are operating on an OFDM channel wider than 20 MHz, find the largest
651 // idle primary channel and pass its width to the FrameExchangeManager, so that
652 // the latter can transmit PPDUs of the appropriate width (see Section 10.23.2.5
653 // of IEEE 802.11-2020).
654 auto interval = (m_phy->GetPhyBand() == WIFI_PHY_BAND_2_4GHZ)
655 ? GetSifs() + 2 * GetSlot()
656 : m_phy->GetPifs();
657 auto width =
659 ? GetLargestIdlePrimaryChannel(interval, now)
661 if (m_feManager->StartTransmission(txop, width))
662 {
663 for (auto& collidingTxop : internalCollisionTxops)
664 {
665 m_feManager->NotifyInternalCollision(collidingTxop);
666 }
667 break;
668 }
669 else
670 {
671 // this TXOP did not transmit anything, make sure that backoff counter starts
672 // decreasing in a slot again
673 txop->UpdateBackoffSlotsNow(0, now, m_linkId);
674 // reset the current state to the EDCAF that won the contention
675 // but did not transmit anything
676 i--;
677 k = std::distance(m_txops.begin(), i);
678 }
679 }
680 i++;
681 }
682}
683
684void
699
700std::multimap<Time, WifiExpectedAccessReason>
702{
703 NS_LOG_FUNCTION(this << ignoreNav);
704 const auto now = Simulator::Now();
705
706 std::multimap<Time, WifiExpectedAccessReason> ret;
707
708 // an EDCA TXOP is obtained based solely on activity of the primary channel
709 // (Sec. 10.23.2.5 of IEEE 802.11-2020)
710 const auto busyAccessStart = m_lastBusyEnd.at(WIFI_CHANLIST_PRIMARY);
711 ret.emplace(busyAccessStart, WifiExpectedAccessReason::BUSY_END);
712
713 auto rxAccessStart = m_lastRx.end;
714 if ((m_lastRx.end <= now) && !m_lastRxReceivedOk)
715 {
716 rxAccessStart += GetEifsNoDifs();
717 }
718 ret.emplace(rxAccessStart, WifiExpectedAccessReason::RX_END);
719
721
722 const auto navAccessStart = ignoreNav ? Time{0} : m_lastNavEnd;
723 ret.emplace(navAccessStart, WifiExpectedAccessReason::NAV_END);
724
728
729 const auto noPhyStart = m_phy ? m_lastNoPhy.end : now;
730 ret.emplace(noPhyStart, WifiExpectedAccessReason::NO_PHY_END);
731
734
735 NS_LOG_INFO("rx access start=" << rxAccessStart.As(Time::US)
736 << ", busy access start=" << busyAccessStart.As(Time::US)
737 << ", tx access start=" << m_lastTxEnd.As(Time::US)
738 << ", nav access start=" << navAccessStart.As(Time::US)
739 << ", switching access start=" << m_lastSwitchingEnd.As(Time::US)
740 << ", no PHY start=" << noPhyStart.As(Time::US)
741 << ", sleep access start=" << m_lastSleepEnd.As(Time::US)
742 << ", off access start=" << m_lastOffEnd.As(Time::US));
743 return ret;
744}
745
746Time
748{
749 NS_LOG_FUNCTION(this << ignoreNav);
750
751 auto timeReasonMap = DoGetAccessGrantStart(ignoreNav);
752 NS_ASSERT(!timeReasonMap.empty());
753 const auto accessGrantedStart = timeReasonMap.crbegin()->first;
754 NS_LOG_INFO("access grant start=" << accessGrantedStart.As(Time::US));
755
756 return accessGrantedStart + GetSifs();
757}
758
759Time
764
765Time
767{
768 NS_LOG_FUNCTION(this << txop << accessGrantStart.As(Time::S));
769 const auto mostRecentEvent =
770 std::max({txop->GetBackoffStart(m_linkId),
771 accessGrantStart + (txop->GetAifsn(m_linkId) * GetSlot())});
772 NS_LOG_DEBUG("Backoff start for " << txop->GetWifiMacQueue()->GetAc() << ": "
773 << mostRecentEvent.As(Time::US));
774
775 return mostRecentEvent;
776}
777
778Time
783
784Time
786{
787 NS_LOG_FUNCTION(this << txop);
788 Time backoffEnd =
789 GetBackoffStartFor(txop, accessGrantStart) + (txop->GetBackoffSlots(m_linkId) * GetSlot());
790 NS_LOG_DEBUG("Backoff end for " << txop->GetWifiMacQueue()->GetAc() << ": "
791 << backoffEnd.As(Time::US));
792
793 return backoffEnd;
794}
795
798{
799 NS_LOG_FUNCTION(this << delay.As(Time::US));
800
801 const auto now = Simulator::Now();
802 const auto deadline = now + delay;
803 const auto timeReasonMap = DoGetAccessGrantStart(false);
804 NS_ASSERT(!timeReasonMap.empty());
805 auto accessGrantStart = timeReasonMap.crbegin()->first;
806
807 if (accessGrantStart >= deadline)
808 {
809 // return the earliest reason for which access cannot be granted in time
810 for (const auto& [time, reason] : timeReasonMap)
811 {
812 if (time >= deadline)
813 {
818 NS_LOG_DEBUG("Access grant start (" << accessGrantStart.As(Time::US)
819 << ") too late for reason " << reason);
820 return reason;
821 }
822 }
823 NS_ABORT_MSG("No reason found that exceeds the deadline!");
824 }
825
826 accessGrantStart += GetSifs();
828
829 for (auto txop : m_txops)
830 {
831 if (txop->GetAccessStatus(m_linkId) != Txop::REQUESTED)
832 {
833 continue;
834 }
835
836 if (!txop->HasFramesToTransmit(m_linkId))
837 {
839 {
841 }
842 continue;
843 }
844
846 const auto backoffEnd = GetBackoffEndFor(txop, accessGrantStart);
847
848 if (backoffEnd >= now && backoffEnd <= deadline)
849 {
850 NS_LOG_DEBUG("Backoff end for " << txop->GetWifiMacQueue()->GetAc() << " on link "
851 << +m_linkId << ": " << backoffEnd.As(Time::US));
853 }
854 }
855
856 NS_LOG_DEBUG("Access grant not expected for reason: " << reason);
857 return reason;
858}
859
860Time
862{
863 return m_lastNavEnd;
864}
865
866void
868{
869 NS_LOG_FUNCTION(this);
870 uint32_t k = 0;
871 const auto accessGrantStart = GetAccessGrantStart();
872 for (auto txop : m_txops)
873 {
874 Time backoffStart = GetBackoffStartFor(txop, accessGrantStart);
875 if (backoffStart <= Simulator::Now())
876 {
877 uint32_t nIntSlots = ((Simulator::Now() - backoffStart) / GetSlot()).GetHigh();
878 /*
879 * EDCA behaves slightly different to DCA. For EDCA we
880 * decrement once at the slot boundary at the end of AIFS as
881 * well as once at the end of each clear slot
882 * thereafter. For DCA we only decrement at the end of each
883 * clear slot after DIFS. We account for the extra backoff
884 * by incrementing the slot count here in the case of
885 * EDCA. The if statement whose body we are in has confirmed
886 * that a minimum of AIFS has elapsed since last busy
887 * medium.
888 */
889 if (txop->IsQosTxop())
890 {
891 nIntSlots++;
892 }
893 uint32_t n = std::min(nIntSlots, txop->GetBackoffSlots(m_linkId));
894 NS_LOG_DEBUG("dcf " << k << " dec backoff slots=" << n);
895 Time backoffUpdateBound = backoffStart + (n * GetSlot());
896 txop->UpdateBackoffSlotsNow(n, backoffUpdateBound, m_linkId);
897 }
898 ++k;
899 }
900}
901
902void
904{
905 NS_LOG_FUNCTION(this);
906 /**
907 * Is there a Txop which needs to access the medium, and,
908 * if there is one, how many slots for AIFS+backoff does it require ?
909 */
910 Ptr<Txop> nextTxop;
911 auto expectedBackoffEnd = Simulator::GetMaximumSimulationTime();
912 const auto accessGrantStart = GetAccessGrantStart();
913 const auto now = Simulator::Now();
914 for (auto txop : m_txops)
915 {
916 if (txop->GetAccessStatus(m_linkId) == Txop::REQUESTED)
917 {
918 if (auto backoffEnd = GetBackoffEndFor(txop, accessGrantStart);
919 backoffEnd > now && backoffEnd < expectedBackoffEnd)
920 {
921 expectedBackoffEnd = backoffEnd;
922 nextTxop = txop;
923 }
924 }
925 }
926 NS_LOG_DEBUG("Access timeout needed: " << (nextTxop != nullptr));
927 if (nextTxop)
928 {
929 const auto aci = nextTxop->GetWifiMacQueue()->GetAc();
930 NS_LOG_DEBUG("expected backoff end=" << expectedBackoffEnd << " by " << aci);
931 auto expectedBackoffDelay = expectedBackoffEnd - now;
932
933 if (m_nSlotsLeft > 0)
934 {
935 const auto expectedNotifyTime =
936 Max(expectedBackoffEnd - m_nSlotsLeft * GetSlot(),
937 accessGrantStart - GetSifs() + m_nSlotsLeftMinDelay);
938
939 if (expectedNotifyTime > now)
940 {
941 // make the timer expire when it's time to notify that the given slots are left
942 expectedBackoffDelay = expectedNotifyTime - now;
943 }
944 else
945 {
946 // notify that a number of slots less than or equal to the specified value are left
947 m_nSlotsLeftCallback(m_linkId, aci, expectedBackoffDelay);
948 }
949 }
950
952 Simulator::GetDelayLeft(m_accessTimeout) > expectedBackoffDelay)
953 {
955 }
957 {
958 m_accessTimeout = Simulator::Schedule(expectedBackoffDelay,
960 this);
961 }
962 }
963}
964
965MHz_u
967{
968 NS_LOG_FUNCTION(this << interval.As(Time::US) << end.As(Time::S));
969
970 // If the medium is busy or it just became idle, UpdateLastIdlePeriod does
971 // nothing. This allows us to call this method, e.g., at the end of a frame
972 // reception and check the busy/idle status of the channel before the start
973 // of the frame reception (last idle period was last updated at the start of
974 // the frame reception).
975 // If the medium has been idle for some time, UpdateLastIdlePeriod updates
976 // the last idle period. This is normally what we want because this method may
977 // also be called before starting a TXOP gained through EDCA.
979
980 MHz_u width{0};
981
982 // we iterate over the different types of channels in the same order as they
983 // are listed in WifiChannelListType
984 for (const auto& lastIdle : m_lastIdle)
985 {
986 if (lastIdle.second.start <= end - interval && lastIdle.second.end >= end)
987 {
988 // channel idle, update width
989 width = (width == MHz_u{0}) ? MHz_u{20} : (2 * width);
990 }
991 else
992 {
993 break;
994 }
995 }
996 return width;
997}
998
999bool
1000ChannelAccessManager::GetPer20MHzBusy(const std::set<uint8_t>& indices) const
1001{
1002 const auto now = Simulator::Now();
1003
1004 if (m_phy->GetChannelWidth() < MHz_u{40})
1005 {
1006 NS_ASSERT_MSG(indices.size() == 1 && *indices.cbegin() == 0,
1007 "Index 0 only can be specified if the channel width is less than 40 MHz");
1008 return m_lastBusyEnd.at(WIFI_CHANLIST_PRIMARY) > now;
1009 }
1010
1011 for (const auto index : indices)
1012 {
1013 NS_ASSERT(index < m_lastPer20MHzBusyEnd.size());
1014 if (m_lastPer20MHzBusyEnd.at(index) > now)
1015 {
1016 NS_LOG_DEBUG("20 MHz channel with index " << +index << " is busy");
1017 return true;
1018 }
1019 }
1020 return false;
1021}
1022
1023void
1025{
1026 NS_LOG_FUNCTION(this << qosTxop << duration);
1027 NS_ASSERT(qosTxop->IsQosTxop());
1028 UpdateBackoff();
1029 Time resume = Simulator::Now() + duration;
1030 NS_LOG_DEBUG("Backoff will resume at time " << resume << " with "
1031 << qosTxop->GetBackoffSlots(m_linkId)
1032 << " remaining slot(s)");
1033 qosTxop->UpdateBackoffSlotsNow(0, resume, m_linkId);
1035}
1036
1037void
1039{
1040 NS_LOG_FUNCTION(this << enable);
1041 m_generateBackoffOnNoTx = enable;
1042}
1043
1044bool
1049
1050void
1052{
1053 NS_LOG_FUNCTION(this << duration);
1054 NS_LOG_DEBUG("rx start for=" << duration);
1055 UpdateBackoff();
1058 m_lastRx.end = m_lastRx.start + duration;
1059 m_lastRxReceivedOk = true;
1060}
1061
1062void
1070
1071void
1073{
1074 NS_LOG_FUNCTION(this);
1075 NS_LOG_DEBUG("rx end error");
1076 // we expect the PHY to notify us of the start of a CCA busy period, if needed
1078 m_lastRxReceivedOk = false;
1080}
1081
1082void
1084{
1085 NS_LOG_FUNCTION(this << duration);
1086 m_lastRxReceivedOk = true;
1087 Time now = Simulator::Now();
1088 if (m_lastRx.end > now)
1089 {
1090 // this may be caused only if PHY has started to receive a packet
1091 // inside SIFS, so, we check that lastRxStart was maximum a SIFS ago
1092 NS_ASSERT(now - m_lastRx.start <= GetSifs());
1093 m_lastRx.end = now;
1094 }
1095 else
1096 {
1098 }
1099 NS_LOG_DEBUG("tx start for " << duration);
1100 UpdateBackoff();
1101 m_lastTxEnd = now + duration;
1102}
1103
1104void
1106 WifiChannelListType channelType,
1107 const std::vector<Time>& per20MhzDurations)
1108{
1109 NS_LOG_FUNCTION(this << duration << channelType);
1110 UpdateBackoff();
1112 auto lastBusyEndIt = m_lastBusyEnd.find(channelType);
1113 NS_ASSERT(lastBusyEndIt != m_lastBusyEnd.end());
1114 Time now = Simulator::Now();
1115 lastBusyEndIt->second = now + duration;
1116 NS_ASSERT_MSG(per20MhzDurations.size() == m_lastPer20MHzBusyEnd.size(),
1117 "Size of received vector (" << per20MhzDurations.size()
1118 << ") differs from the expected size ("
1119 << m_lastPer20MHzBusyEnd.size() << ")");
1120 for (std::size_t chIdx = 0; chIdx < per20MhzDurations.size(); ++chIdx)
1121 {
1122 if (per20MhzDurations[chIdx].IsStrictlyPositive())
1123 {
1124 m_lastPer20MHzBusyEnd[chIdx] = now + per20MhzDurations[chIdx];
1125 }
1126 }
1127
1129 {
1130 // have all EDCAFs that are not carrying out a TXOP and have the backoff counter set to
1131 // zero proactively generate a new backoff value
1132 for (auto txop : m_txops)
1133 {
1134 if (txop->GetAccessStatus(m_linkId) != Txop::GRANTED &&
1135 txop->GetBackoffSlots(m_linkId) == 0)
1136 {
1137 NS_LOG_DEBUG("Generate backoff for " << txop->GetWifiMacQueue()->GetAc());
1138 txop->GenerateBackoff(m_linkId);
1139 }
1140 }
1141 }
1142}
1143
1144void
1146{
1147 NS_LOG_FUNCTION(this << phyListener << duration);
1148
1149 Time now = Simulator::Now();
1150 NS_ASSERT(m_lastTxEnd <= now);
1151
1152 if (phyListener) // to make tests happy
1153 {
1154 // check if the PHY switched channel to operate on another EMLSR link
1155
1156 for (const auto& [phyRef, listener] : m_phyListeners)
1157 {
1158 Ptr<WifiPhy> phy = phyRef;
1159 auto emlsrInfoIt = m_switchingEmlsrLinks.find(phy);
1160
1161 if (listener.get() == phyListener && emlsrInfoIt != m_switchingEmlsrLinks.cend() &&
1162 phy->GetOperatingChannel() == emlsrInfoIt->second.channel)
1163 {
1164 // the PHY associated with the given PHY listener switched channel to
1165 // operate on another EMLSR link as expected. We don't need this listener
1166 // anymore. The MAC will connect a new listener to the ChannelAccessManager
1167 // instance associated with the link the PHY is now operating on
1168 RemovePhyListener(phy);
1170 NS_ASSERT(ehtFem);
1171 ehtFem->NotifySwitchingEmlsrLink(phy, emlsrInfoIt->second.linkId, duration);
1172 m_switchingEmlsrLinks.erase(emlsrInfoIt);
1173 return;
1174 }
1175 }
1176 }
1177
1178 ResetState();
1179
1180 // Cancel timeout
1182 {
1184 }
1185
1186 // Reset backoffs
1187 for (const auto& txop : m_txops)
1188 {
1189 ResetBackoff(txop);
1190 }
1191
1192 // Notify the FEM, which will in turn notify the MAC
1193 m_feManager->NotifySwitchingStartNow(duration);
1194
1195 NS_LOG_DEBUG("switching start for " << duration);
1196 m_lastSwitchingEnd = now + duration;
1197}
1198
1199void
1201{
1202 NS_LOG_FUNCTION(this);
1203
1204 Time now = Simulator::Now();
1205 m_lastRxReceivedOk = true;
1207 m_lastRx.end = std::min(m_lastRx.end, now);
1208 m_lastNavEnd = std::min(m_lastNavEnd, now);
1211 m_lastNoPhy.end = std::min(m_lastNoPhy.end, now);
1212
1214}
1215
1216void
1218{
1219 NS_LOG_FUNCTION(this << txop);
1220
1221 uint32_t remainingSlots = txop->GetBackoffSlots(m_linkId);
1222 if (remainingSlots > 0)
1223 {
1224 txop->UpdateBackoffSlotsNow(remainingSlots, Simulator::Now(), m_linkId);
1225 NS_ASSERT(txop->GetBackoffSlots(m_linkId) == 0);
1226 }
1227 txop->ResetCw(m_linkId);
1228 txop->GetLink(m_linkId).access = Txop::NOT_REQUESTED;
1229}
1230
1231void
1233{
1234 NS_LOG_FUNCTION(this);
1235
1236 for (const auto& txop : m_txops)
1237 {
1238 ResetBackoff(txop);
1239 }
1241}
1242
1243void
1245{
1246 NS_LOG_FUNCTION(this);
1247 // Reset backoffs
1249 m_feManager->NotifySleepNow();
1250 for (auto txop : m_txops)
1251 {
1252 txop->NotifySleep(m_linkId);
1253 }
1254}
1255
1256void
1258{
1259 NS_LOG_FUNCTION(this);
1260 // Cancel timeout
1262 {
1264 }
1265
1266 // Reset backoffs
1267 for (auto txop : m_txops)
1268 {
1269 txop->NotifyOff();
1270 }
1271}
1272
1273void
1275{
1276 NS_LOG_FUNCTION(this);
1278 for (auto txop : m_txops)
1279 {
1280 ResetBackoff(txop);
1281 txop->NotifyWakeUp(m_linkId);
1282 }
1283}
1284
1285void
1287{
1288 NS_LOG_FUNCTION(this);
1290 for (auto txop : m_txops)
1291 {
1292 ResetBackoff(txop);
1293 txop->NotifyOn();
1294 }
1295}
1296
1297void
1299{
1300 NS_LOG_FUNCTION(this << duration);
1301
1302 if (!m_phy)
1303 {
1304 NS_LOG_DEBUG("Do not reset NAV, CTS may have been missed due to the main PHY switching "
1305 "to another link to take over a TXOP while receiving the CTS");
1306 return;
1307 }
1308
1309 NS_LOG_DEBUG("nav reset for=" << duration);
1310 UpdateBackoff();
1311 m_lastNavEnd = Simulator::Now() + duration;
1312 /**
1313 * If the NAV reset indicates an end-of-NAV which is earlier
1314 * than the previous end-of-NAV, the expected end of backoff
1315 * might be later than previously thought so, we might need
1316 * to restart a new access timeout.
1317 */
1319}
1320
1321void
1323{
1324 NS_LOG_FUNCTION(this << duration);
1325 NS_LOG_DEBUG("nav start for=" << duration);
1326 UpdateBackoff();
1327 m_lastNavEnd = std::max(m_lastNavEnd, Simulator::Now() + duration);
1328}
1329
1330void
1337
1338void
1345
1346void
1348{
1349 NS_LOG_FUNCTION(this << duration);
1350 m_lastCtsTimeoutEnd = Simulator::Now() + duration;
1351}
1352
1353void
1360
1361void
1363{
1364 NS_LOG_FUNCTION(this);
1365 Time idleStart = std::max({m_lastTxEnd,
1366 m_lastRx.end,
1370 m_lastOffEnd});
1371 Time now = Simulator::Now();
1372
1373 if (idleStart >= now)
1374 {
1375 // No new idle period
1376 return;
1377 }
1378
1379 for (const auto& busyEnd : m_lastBusyEnd)
1380 {
1381 if (busyEnd.second < now)
1382 {
1383 auto lastIdleIt = m_lastIdle.find(busyEnd.first);
1384 NS_ASSERT(lastIdleIt != m_lastIdle.end());
1385 lastIdleIt->second = {std::max(idleStart, busyEnd.second), now};
1386 NS_LOG_DEBUG("New idle period (" << lastIdleIt->second.start.As(Time::S) << ", "
1387 << lastIdleIt->second.end.As(Time::S)
1388 << ") on channel " << lastIdleIt->first);
1389 }
1390 }
1391}
1392
1393std::ostream&
1394operator<<(std::ostream& os, const WifiExpectedAccessReason& reason)
1395{
1396 switch (reason)
1397 {
1399 return (os << "ACCESS EXPECTED");
1401 return (os << "NOT_REQUESTED");
1403 return (os << "NOTHING_TO_TX");
1405 return (os << "RX_END");
1407 return (os << "BUSY_END");
1409 return (os << "TX_END");
1411 return (os << "NAV_END");
1413 return (os << "ACK_TIMER_END");
1415 return (os << "CTS_TIMER_END");
1417 return (os << "SWITCHING_END");
1419 return (os << "NO_PHY_END");
1421 return (os << "SLEEP_END");
1423 return (os << "OFF_END");
1425 return (os << "BACKOFF_END");
1426 default:
1427 NS_ABORT_MSG("Unknown expected access reason");
1428 return (os << "Unknown");
1429 }
1430}
1431
1432} // namespace ns3
#define Max(a, b)
AttributeValue implementation for Boolean.
Definition boolean.h:26
Manage a set of ns3::Txop.
bool m_proactiveBackoff
whether a new backoff value is generated when a CCA busy period starts and the backoff counter is zer...
std::vector< Time > m_lastPer20MHzBusyEnd
the last busy end time per 20 MHz channel (HE stations and channel width > 20 MHz only)
bool IsBusy() const
Check if the device is busy sending or receiving, or NAV or CCA busy.
void ResetBackoff(Ptr< Txop > txop)
Reset the backoff for the given DCF/EDCAF.
void NotifySwitchingStartNow(PhyListener *phyListener, Time duration)
NSlotsLeftTracedCallback m_nSlotsLeftCallback
traced callback for NSlotsLeft alerts
Time GetBackoffStartFor(Ptr< Txop > txop) const
Return the time when the backoff procedure started for the given Txop.
void ResetState()
Reset the state variables of this channel access manager.
void NotifySwitchingEmlsrLink(Ptr< WifiPhy > phy, const WifiPhyOperatingChannel &channel, uint8_t linkId)
Notify that the given PHY is about to switch to the given operating channel, which is used by the giv...
void ResetAllBackoffs()
Reset the backoff for all the DCF/EDCAF.
void NotifyWakeupNow()
Notify the Txop that the device has been resumed from sleep mode.
bool m_lastRxReceivedOk
the last receive OK
std::unordered_map< Ptr< WifiPhy >, EmlsrLinkSwitchInfo > m_switchingEmlsrLinks
Store information about the PHY objects that are going to operate on another EMLSR link.
std::map< WifiChannelListType, Timespan > m_lastIdle
the last idle start and end time for each channel type
Ptr< WifiPhy > m_phy
pointer to the unique active PHY
void NotifyAckTimeoutResetNow()
Notify that ack timer has reset.
void SetGenerateBackoffOnNoTx(bool enable)
Set the member variable indicating whether the backoff should be invoked when an AC gains the right t...
void NotifyRxEndOkNow()
Notify the Txop that a packet reception was just completed successfully.
virtual Time GetEifsNoDifs() const
Return the EIFS duration minus a DIFS.
uint8_t m_linkId
the ID of the link this object is associated with
uint8_t m_nSlotsLeft
fire the NSlotsLeftAlert trace source when the backoff counter with the minimum value among all ACs r...
void NotifyCcaBusyStartNow(Time duration, WifiChannelListType channelType, const std::vector< Time > &per20MhzDurations)
Time m_lastAckTimeoutEnd
the last Ack timeout end time
Timespan m_lastNoPhy
the last start and end time no PHY was operating on the link
Time m_cachedSlot
cached value for slot, to be only used without a PHY
Time m_eifsNoDifs
EIFS no DIFS time.
virtual Time GetSlot() const
Return the slot duration for this PHY.
Time m_nSlotsLeftMinDelay
the minimum gap between the end of a medium busy event and the time the NSlotsLeftAlert trace source ...
void NotifyAckTimeoutStartNow(Time duration)
Notify that ack timer has started for the given duration.
void AccessTimeout()
Called when access timeout should occur (e.g.
Time GetBackoffEndFor(Ptr< Txop > txop) const
Return the time when the backoff procedure ended (or will end) for the given Txop.
void UpdateBackoff()
Update backoff slots for all Txops.
void DeactivatePhyListener(Ptr< WifiPhy > phy)
Deactivate current registered listener for PHY events on the given PHY.
void SetLinkId(uint8_t linkId)
Set the ID of the link this Channel Access Manager is associated with.
void SetupFrameExchangeManager(Ptr< FrameExchangeManager > feManager)
Set up the Frame Exchange Manager.
bool NeedBackoffUponAccess(Ptr< Txop > txop, bool hadFramesToTransmit, bool checkMediumBusy)
Determine if a new backoff needs to be generated as per letter a) of Section 10.23....
void NotifyCtsTimeoutStartNow(Time duration)
Notify that CTS timer has started for the given duration.
void RequestAccess(Ptr< Txop > txop)
Time m_lastSwitchingEnd
the last switching end time
Timespan m_lastRx
the last receive start and end time
Time m_lastSleepEnd
the last sleep end time
std::map< WifiChannelListType, Time > m_lastBusyEnd
the last busy end time for each channel type
void RemovePhyListener(Ptr< WifiPhy > phy)
Remove current registered listener for PHY events on the given PHY.
bool m_generateBackoffOnNoTx
whether the backoff should be invoked when the AC gains the right to start a TXOP but it does not tra...
Time m_lastTxEnd
the last transmit end time
void SetupPhyListener(Ptr< WifiPhy > phy)
Set up (or reactivate) listener for PHY events on the given PHY.
Time m_lastCtsTimeoutEnd
the last CTS timeout end time
MHz_u GetLargestIdlePrimaryChannel(Time interval, Time end)
Return the width of the largest primary channel that has been idle for the given time interval before...
void DoDispose() override
Destructor implementation.
WifiExpectedAccessReason GetExpectedAccessWithin(const Time &delay) const
Check whether channel access is expected to be granted within the given delay.
void NotifySleepNow()
Notify the Txop that the device has been put in sleep mode.
Ptr< FrameExchangeManager > m_feManager
pointer to the Frame Exchange Manager
void NotifyRxEndErrorNow(const WifiTxVector &txVector)
Notify the Txop that a packet reception was just completed unsuccessfuly.
void UpdateLastIdlePeriod()
This method determines whether the medium has been idle during a period (of non-null duration) immedi...
void DisableEdcaFor(Ptr< Txop > qosTxop, Time duration)
void DoInitialize() override
Initialize() implementation.
Time m_lastOffEnd
the last off end time
Txops m_txops
the vector of managed Txops
std::multimap< Time, WifiExpectedAccessReason > DoGetAccessGrantStart(bool ignoreNav) const
Return a map containing (Time, WifiExpectedAccessReason) pairs sorted in increasing order of times.
bool GetPer20MHzBusy(const std::set< uint8_t > &indices) const
static TypeId GetTypeId()
Get the type ID.
void DoGrantDcfAccess()
Grant access to Txop using DCF/EDCF contention rules.
void ResizeLastBusyStructs()
Resize the structures holding busy end times per channel type (primary, secondary,...
std::shared_ptr< PhyListener > GetPhyListener(Ptr< WifiPhy > phy) const
Get current registered listener for PHY events on the given PHY.
Time m_lastNavEnd
the last NAV end time
void NotifyCtsTimeoutResetNow()
Notify that CTS timer has reset.
void NotifyOffNow()
Notify the Txop that the device has been put in off mode.
Time GetAccessGrantStart(bool ignoreNav=false) const
Access will never be granted to the medium before the time returned by this method.
Time m_cachedSifs
cached value for SIFS, to be only used without a PHY
void NotifyOnNow()
Notify the Txop that the device has been resumed from off mode.
PhyListenerMap m_phyListeners
the PHY listeners
virtual Time GetSifs() const
Return the Short Interframe Space (SIFS) for this PHY.
static const Time DEFAULT_N_SLOTS_LEFT_MIN_DELAY
default value for the NSlotsLeftMinDelay attribute, corresponds to a PIFS in 5GHz/6GHz bands
Time m_resetBackoffThreshold
if no PHY operates on a link for a period greater than this threshold, the backoff on that link is re...
EventId m_accessTimeout
the access timeout ID
void InitLastBusyStructs()
Initialize the structures holding busy end times per channel type (primary, secondary,...
void Cancel()
This method is syntactic sugar for the ns3::Simulator::Cancel method.
Definition event-id.cc:44
bool IsPending() const
This method is syntactic sugar for !IsExpired().
Definition event-id.cc:65
bool IsExpired() const
This method is syntactic sugar for the ns3::Simulator::IsExpired method.
Definition event-id.cc:58
A base class which provides memory management and object aggregation.
Definition object.h:78
Listener for PHY events.
bool m_active
whether this PHY listener is active
PhyListener(ns3::ChannelAccessManager *cam)
Create a PhyListener for the given ChannelAccessManager.
void NotifyOff() override
Notify listeners that we went to switch off.
void NotifySleep() override
Notify listeners that we went to sleep.
ns3::ChannelAccessManager * m_cam
ChannelAccessManager to forward events to.
void NotifyRxStart(Time duration) override
void NotifyOn() override
Notify listeners that we went to switch on.
void NotifySwitchingStart(Time duration) override
void SetActive(bool active)
Set this listener to be active or not.
void NotifyRxEndOk() override
We have received the last bit of a packet for which NotifyRxStart was invoked first and,...
void NotifyWakeup() override
Notify listeners that we woke up.
void NotifyCcaBusyStart(Time duration, WifiChannelListType channelType, const std::vector< Time > &per20MhzDurations) override
void NotifyRxEndError(const WifiTxVector &txVector) override
void NotifyTxStart(Time duration, dBm_u txPower) override
Smart pointer class similar to boost::intrusive_ptr.
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition simulator.h:561
static Time Now()
Return the current simulation virtual time.
Definition simulator.cc:197
static Time GetMaximumSimulationTime()
Get the maximum representable simulation time.
Definition simulator.cc:300
static Time GetDelayLeft(const EventId &id)
Get the remaining time until this event will execute.
Definition simulator.cc:206
Simulation virtual time values and global simulation resolution.
Definition nstime.h:94
TimeWithUnit As(const Unit unit=Time::AUTO) const
Attach a unit to a Time, to facilitate output in a specific unit.
Definition time.cc:403
@ US
microsecond
Definition nstime.h:107
@ S
second
Definition nstime.h:105
AttributeValue implementation for Time.
Definition nstime.h:1432
@ GRANTED
Definition txop.h:79
@ NOT_REQUESTED
Definition txop.h:77
@ REQUESTED
Definition txop.h:78
a unique identifier for an interface.
Definition type-id.h:49
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition type-id.cc:1001
Hold an unsigned integer type.
Definition uinteger.h:34
Time GetSlot() const
Return the slot duration for this PHY.
Definition wifi-phy.cc:849
Time GetSifs() const
Return the Short Interframe Space (SIFS) for this PHY.
Definition wifi-phy.cc:837
bool IsStateOff() const
Definition wifi-phy.cc:2187
WifiPhyBand GetPhyBand() const
Get the configured Wi-Fi band.
Definition wifi-phy.cc:1057
Time GetPifs() const
Return the PCF Interframe Space (PIFS) for this PHY.
Definition wifi-phy.cc:861
MHz_u GetChannelWidth() const
Definition wifi-phy.cc:1087
bool IsStateSleep() const
Definition wifi-phy.cc:2181
WifiStandard GetStandard() const
Get the configured Wi-Fi standard.
Definition wifi-phy.cc:1063
void NotifyChannelAccessRequested()
Notify the PHY that an access to the channel was requested.
Definition wifi-phy.cc:2013
const WifiPhyOperatingChannel & GetOperatingChannel() const
Get a const reference to the operating channel.
Definition wifi-phy.cc:1069
receive notifications about PHY events.
Class that keeps track of all information about the current PHY operating channel.
bool IsOfdm() const
Return whether the operating channel is an OFDM channel.
This class mimics the TXVECTOR which is to be passed to the PHY in order to define the parameters whi...
#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_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
Definition assert.h:75
Ptr< const AttributeChecker > MakeBooleanChecker()
Definition boolean.cc:113
Ptr< const AttributeAccessor > MakeBooleanAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition boolean.h:70
Ptr< const AttributeAccessor > MakeTimeAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition nstime.h:1433
Ptr< const AttributeChecker > MakeTimeChecker()
Helper to make an unbounded Time checker.
Definition nstime.h:1453
Ptr< const AttributeChecker > MakeUintegerChecker()
Definition uinteger.h:85
Ptr< const AttributeAccessor > MakeUintegerAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition uinteger.h:35
#define NS_ABORT_MSG(msg)
Unconditional abnormal program termination with a message.
Definition abort.h:38
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition log.h:191
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition log.h:257
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
Definition log.h:264
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition object-base.h:35
Time MicroSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1369
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition nstime.h:1345
Ptr< const TraceSourceAccessor > MakeTraceSourceAccessor(T a)
Create a TraceSourceAccessor which will control access to the underlying trace source.
WifiExpectedAccessReason
Enumeration values for the outcome of the check whether channel access is expected to be gained withi...
WifiChannelListType
Enumeration of the possible channel-list parameter elements defined in Table 8-5 of IEEE 802....
@ WIFI_STANDARD_80211ax
@ WIFI_PHY_BAND_2_4GHZ
The 2.4 GHz band.
@ WIFI_CHANLIST_PRIMARY
@ WIFI_CHANLIST_SECONDARY40
@ WIFI_CHANLIST_SECONDARY
@ WIFI_CHANLIST_SECONDARY80
Every class exported by the ns3 library is enclosed in the ns3 namespace.
std::ostream & operator<<(std::ostream &os, const Angles &a)
Definition angles.cc:148
double MHz_u
MHz weak type.
Definition wifi-units.h:31
Ptr< T1 > DynamicCast(const Ptr< T2 > &p)
Cast a Ptr.
Definition ptr.h:580
Time GetEstimatedAckTxTime(const WifiTxVector &txVector)
std::size_t Count20MHzSubchannels(MHz_u channelWidth)
Return the number of 20 MHz subchannels covering the channel width.
Definition wifi-utils.h:136
Ptr< T1 > StaticCast(const Ptr< T2 > &p)
Cast a Ptr.
Definition ptr.h:587
Structure defining start time and end time for a given state.