A Discrete-Event Network Simulator
API
channel-access-manager.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
23#include "txop.h"
24#include "wifi-phy-listener.h"
25#include "wifi-phy.h"
26
27#include "ns3/log.h"
28#include "ns3/simulator.h"
29
30#undef NS_LOG_APPEND_CONTEXT
31#define NS_LOG_APPEND_CONTEXT std::clog << "[link=" << +m_linkId << "] "
32
33namespace ns3
34{
35
36NS_LOG_COMPONENT_DEFINE("ChannelAccessManager");
37
42{
43 public:
50 : m_cam(cam)
51 {
52 }
53
54 ~PhyListener() override
55 {
56 }
57
58 void NotifyRxStart(Time duration) override
59 {
60 m_cam->NotifyRxStartNow(duration);
61 }
62
63 void NotifyRxEndOk() override
64 {
66 }
67
68 void NotifyRxEndError() override
69 {
71 }
72
73 void NotifyTxStart(Time duration, double txPowerDbm) override
74 {
75 m_cam->NotifyTxStartNow(duration);
76 }
77
78 void NotifyCcaBusyStart(Time duration,
79 WifiChannelListType channelType,
80 const std::vector<Time>& per20MhzDurations) override
81 {
82 m_cam->NotifyCcaBusyStartNow(duration, channelType, per20MhzDurations);
83 }
84
85 void NotifySwitchingStart(Time duration) override
86 {
88 }
89
90 void NotifySleep() override
91 {
93 }
94
95 void NotifyOff() override
96 {
98 }
99
100 void NotifyWakeup() override
101 {
103 }
104
105 void NotifyOn() override
106 {
108 }
109
110 private:
112};
113
114/****************************************************************
115 * Implement the channel access manager of all Txop holders
116 ****************************************************************/
117
119 : m_lastAckTimeoutEnd(MicroSeconds(0)),
120 m_lastCtsTimeoutEnd(MicroSeconds(0)),
121 m_lastNavEnd(MicroSeconds(0)),
122 m_lastRx({MicroSeconds(0), MicroSeconds(0)}),
123 m_lastRxReceivedOk(true),
124 m_lastTxEnd(MicroSeconds(0)),
125 m_lastSwitchingEnd(MicroSeconds(0)),
126 m_sleeping(false),
127 m_off(false),
128 m_phyListener(nullptr),
129 m_linkId(0)
130{
131 NS_LOG_FUNCTION(this);
132 InitLastBusyStructs();
133}
134
136{
137 NS_LOG_FUNCTION(this);
138 delete m_phyListener;
139 m_phyListener = nullptr;
140}
141
142void
144{
145 NS_LOG_FUNCTION(this);
146 for (Ptr<Txop> i : m_txops)
147 {
148 i->Dispose();
149 i = nullptr;
150 }
151 m_phy = nullptr;
152 m_feManager = nullptr;
153}
154
155void
157{
158 NS_LOG_FUNCTION(this << phy);
159 NS_ASSERT(m_phyListener == nullptr);
160 m_phyListener = new PhyListener(this);
161 phy->RegisterListener(m_phyListener);
162 m_phy = phy;
164}
165
166void
168{
169 NS_LOG_FUNCTION(this << phy);
170 if (m_phyListener != nullptr)
171 {
172 phy->UnregisterListener(m_phyListener);
173 delete m_phyListener;
174 m_phyListener = nullptr;
175 m_phy = nullptr;
176 }
177}
178
179void
181{
182 NS_LOG_FUNCTION(this << +linkId);
183 m_linkId = linkId;
184}
185
186void
188{
189 NS_LOG_FUNCTION(this << feManager);
190 m_feManager = feManager;
191 m_feManager->SetChannelAccessManager(this);
192}
193
194Time
196{
197 return m_phy->GetSlot();
198}
199
200Time
202{
203 return m_phy->GetSifs();
204}
205
206Time
208{
209 return m_phy->GetSifs() + m_phy->GetAckTxTime();
210}
211
212void
214{
215 NS_LOG_FUNCTION(this << txop);
216 m_txops.push_back(txop);
217}
218
219void
221{
222 NS_LOG_FUNCTION(this);
223 Time now = Simulator::Now();
224 m_lastBusyEnd.clear();
225 m_lastPer20MHzBusyEnd.clear();
226 m_lastIdle.clear();
228 m_lastIdle[WIFI_CHANLIST_PRIMARY] = {now, now};
229
231 {
232 return;
233 }
234
235 uint16_t width = m_phy->GetChannelWidth();
236
237 if (width >= 40)
238 {
241 }
242 if (width >= 80)
243 {
246 }
247 if (width >= 160)
248 {
251 }
252 // TODO Add conditions for new channel widths as they get supported
253
254 if (m_phy->GetStandard() >= WIFI_STANDARD_80211ax && width > 20)
255 {
256 m_lastPer20MHzBusyEnd.assign(width / 20, now);
257 }
258}
259
260bool
262{
263 NS_LOG_FUNCTION(this);
264 Time now = Simulator::Now();
265 return (m_lastRx.end > now) // RX
266 || (m_lastTxEnd > now) // TX
267 || (m_lastNavEnd > now) // NAV busy
268 // an EDCA TXOP is obtained based solely on activity of the primary channel
269 // (Sec. 10.23.2.5 of IEEE 802.11-2020)
270 || (m_lastBusyEnd.at(WIFI_CHANLIST_PRIMARY) > now); // CCA busy
271}
272
273bool
275{
276 NS_LOG_FUNCTION(this << txop);
277
278 // No backoff needed if in sleep mode or off
279 if (m_sleeping || m_off)
280 {
281 return false;
282 }
283
284 // the Txop might have a stale value of remaining backoff slots
286
287 /*
288 * From section 10.3.4.2 "Basic access" of IEEE 802.11-2016:
289 *
290 * A STA may transmit an MPDU when it is operating under the DCF access
291 * method, either in the absence of a PC, or in the CP of the PCF access
292 * method, when the STA determines that the medium is idle when a frame is
293 * queued for transmission, and remains idle for a period of a DIFS, or an
294 * EIFS (10.3.2.3.7) from the end of the immediately preceding medium-busy
295 * event, whichever is the greater, and the backoff timer is zero. Otherwise
296 * the random backoff procedure described in 10.3.4.3 shall be followed.
297 *
298 * From section 10.22.2.2 "EDCA backoff procedure" of IEEE 802.11-2016:
299 *
300 * The backoff procedure shall be invoked by an EDCAF when any of the following
301 * events occurs:
302 * a) An MA-UNITDATA.request primitive is received that causes a frame with that AC
303 * to be queued for transmission such that one of the transmit queues associated
304 * with that AC has now become non-empty and any other transmit queues
305 * associated with that AC are empty; the medium is busy on the primary channel
306 */
308 txop->GetBackoffSlots(m_linkId) == 0)
309 {
310 if (!IsBusy())
311 {
312 // medium idle. If this is a DCF, use immediate access (we can transmit
313 // in a DIFS if the medium remains idle). If this is an EDCAF, update
314 // the backoff start time kept by the EDCAF to the current time in order
315 // to correctly align the backoff start time at the next slot boundary
316 // (performed by the next call to ChannelAccessManager::RequestAccess())
317 Time delay =
318 (txop->IsQosTxop() ? Seconds(0) : GetSifs() + txop->GetAifsn(m_linkId) * GetSlot());
319 txop->UpdateBackoffSlotsNow(0, Simulator::Now() + delay, m_linkId);
320 }
321 else
322 {
323 // medium busy, backoff is needed
324 return true;
325 }
326 }
327 return false;
328}
329
330void
332{
333 NS_LOG_FUNCTION(this << txop);
334 if (m_phy)
335 {
337 }
338 // Deny access if in sleep mode or off
339 if (m_sleeping || m_off)
340 {
341 return;
342 }
343 /*
344 * EDCAF operations shall be performed at slot boundaries (Sec. 10.22.2.4 of 802.11-2016)
345 */
346 Time accessGrantStart = GetAccessGrantStart() + (txop->GetAifsn(m_linkId) * GetSlot());
347
348 if (txop->IsQosTxop() && txop->GetBackoffStart(m_linkId) > accessGrantStart)
349 {
350 // The backoff start time reported by the EDCAF is more recent than the last
351 // time the medium was busy plus an AIFS, hence we need to align it to the
352 // next slot boundary.
353 Time diff = txop->GetBackoffStart(m_linkId) - accessGrantStart;
354 uint32_t nIntSlots = (diff / GetSlot()).GetHigh() + 1;
355 txop->UpdateBackoffSlotsNow(0, accessGrantStart + (nIntSlots * GetSlot()), m_linkId);
356 }
357
363}
364
365void
367{
368 NS_LOG_FUNCTION(this);
369 uint32_t k = 0;
370 Time now = Simulator::Now();
371 for (Txops::iterator i = m_txops.begin(); i != m_txops.end(); k++)
372 {
373 Ptr<Txop> txop = *i;
375 (!txop->IsQosTxop() || !StaticCast<QosTxop>(txop)->EdcaDisabled(m_linkId)) &&
376 GetBackoffEndFor(txop) <= now)
377 {
382 NS_LOG_DEBUG("dcf " << k << " needs access. backoff expired. access granted. slots="
383 << txop->GetBackoffSlots(m_linkId));
384 i++; // go to the next item in the list.
385 k++;
386 std::vector<Ptr<Txop>> internalCollisionTxops;
387 for (Txops::iterator j = i; j != m_txops.end(); j++, k++)
388 {
389 Ptr<Txop> otherTxop = *j;
390 if (otherTxop->GetAccessStatus(m_linkId) == Txop::REQUESTED &&
391 GetBackoffEndFor(otherTxop) <= now)
392 {
394 "dcf " << k << " needs access. backoff expired. internal collision. slots="
395 << otherTxop->GetBackoffSlots(m_linkId));
401 internalCollisionTxops.push_back(otherTxop);
402 }
403 }
404
414 // If we are operating on an OFDM channel wider than 20 MHz, find the largest
415 // idle primary channel and pass its width to the FrameExchangeManager, so that
416 // the latter can transmit PPDUs of the appropriate width (see Section 10.23.2.5
417 // of IEEE 802.11-2020).
418 auto interval = (m_phy->GetPhyBand() == WIFI_PHY_BAND_2_4GHZ)
419 ? GetSifs() + 2 * GetSlot()
420 : m_phy->GetPifs();
421 auto width = (m_phy->GetOperatingChannel().IsOfdm() && m_phy->GetChannelWidth() > 20)
422 ? GetLargestIdlePrimaryChannel(interval, now)
424 if (m_feManager->StartTransmission(txop, width))
425 {
426 for (auto& collidingTxop : internalCollisionTxops)
427 {
428 m_feManager->NotifyInternalCollision(collidingTxop);
429 }
430 break;
431 }
432 else
433 {
434 // reset the current state to the EDCAF that won the contention
435 // but did not transmit anything
436 i--;
437 k = std::distance(m_txops.begin(), i);
438 }
439 }
440 i++;
441 }
442}
443
444void
446{
447 NS_LOG_FUNCTION(this);
451}
452
453Time
455{
456 NS_LOG_FUNCTION(this);
457 const Time& sifs = GetSifs();
458 Time rxAccessStart = m_lastRx.end + sifs;
460 {
461 rxAccessStart += GetEifsNoDifs();
462 }
463 // an EDCA TXOP is obtained based solely on activity of the primary channel
464 // (Sec. 10.23.2.5 of IEEE 802.11-2020)
465 Time busyAccessStart = m_lastBusyEnd.at(WIFI_CHANLIST_PRIMARY) + sifs;
466 Time txAccessStart = m_lastTxEnd + sifs;
467 Time navAccessStart = m_lastNavEnd + sifs;
468 Time ackTimeoutAccessStart = m_lastAckTimeoutEnd + sifs;
469 Time ctsTimeoutAccessStart = m_lastCtsTimeoutEnd + sifs;
470 Time switchingAccessStart = m_lastSwitchingEnd + sifs;
471 Time accessGrantedStart;
472 if (ignoreNav)
473 {
474 accessGrantedStart = std::max({rxAccessStart,
475 busyAccessStart,
476 txAccessStart,
477 ackTimeoutAccessStart,
478 ctsTimeoutAccessStart,
479 switchingAccessStart});
480 }
481 else
482 {
483 accessGrantedStart = std::max({rxAccessStart,
484 busyAccessStart,
485 txAccessStart,
486 navAccessStart,
487 ackTimeoutAccessStart,
488 ctsTimeoutAccessStart,
489 switchingAccessStart});
490 }
491 NS_LOG_INFO("access grant start=" << accessGrantedStart << ", rx access start=" << rxAccessStart
492 << ", busy access start=" << busyAccessStart
493 << ", tx access start=" << txAccessStart
494 << ", nav access start=" << navAccessStart);
495 return accessGrantedStart;
496}
497
498Time
500{
501 NS_LOG_FUNCTION(this << txop);
502 Time mostRecentEvent =
504 GetAccessGrantStart() + (txop->GetAifsn(m_linkId) * GetSlot())});
505 NS_LOG_DEBUG("Backoff start: " << mostRecentEvent.As(Time::US));
506
507 return mostRecentEvent;
508}
509
510Time
512{
513 NS_LOG_FUNCTION(this << txop);
514 Time backoffEnd = GetBackoffStartFor(txop) + (txop->GetBackoffSlots(m_linkId) * GetSlot());
515 NS_LOG_DEBUG("Backoff end: " << backoffEnd.As(Time::US));
516
517 return backoffEnd;
518}
519
520void
522{
523 NS_LOG_FUNCTION(this);
524 uint32_t k = 0;
525 for (auto txop : m_txops)
526 {
527 Time backoffStart = GetBackoffStartFor(txop);
528 if (backoffStart <= Simulator::Now())
529 {
530 uint32_t nIntSlots = ((Simulator::Now() - backoffStart) / GetSlot()).GetHigh();
531 /*
532 * EDCA behaves slightly different to DCA. For EDCA we
533 * decrement once at the slot boundary at the end of AIFS as
534 * well as once at the end of each clear slot
535 * thereafter. For DCA we only decrement at the end of each
536 * clear slot after DIFS. We account for the extra backoff
537 * by incrementing the slot count here in the case of
538 * EDCA. The if statement whose body we are in has confirmed
539 * that a minimum of AIFS has elapsed since last busy
540 * medium.
541 */
542 if (txop->IsQosTxop())
543 {
544 nIntSlots++;
545 }
546 uint32_t n = std::min(nIntSlots, txop->GetBackoffSlots(m_linkId));
547 NS_LOG_DEBUG("dcf " << k << " dec backoff slots=" << n);
548 Time backoffUpdateBound = backoffStart + (n * GetSlot());
549 txop->UpdateBackoffSlotsNow(n, backoffUpdateBound, m_linkId);
550 }
551 ++k;
552 }
553}
554
555void
557{
558 NS_LOG_FUNCTION(this);
563 bool accessTimeoutNeeded = false;
564 Time expectedBackoffEnd = Simulator::GetMaximumSimulationTime();
565 for (auto txop : m_txops)
566 {
567 if (txop->GetAccessStatus(m_linkId) == Txop::REQUESTED)
568 {
569 Time tmp = GetBackoffEndFor(txop);
570 if (tmp > Simulator::Now())
571 {
572 accessTimeoutNeeded = true;
573 expectedBackoffEnd = std::min(expectedBackoffEnd, tmp);
574 }
575 }
576 }
577 NS_LOG_DEBUG("Access timeout needed: " << accessTimeoutNeeded);
578 if (accessTimeoutNeeded)
579 {
580 NS_LOG_DEBUG("expected backoff end=" << expectedBackoffEnd);
581 Time expectedBackoffDelay = expectedBackoffEnd - Simulator::Now();
583 Simulator::GetDelayLeft(m_accessTimeout) > expectedBackoffDelay)
584 {
586 }
588 {
589 m_accessTimeout = Simulator::Schedule(expectedBackoffDelay,
591 this);
592 }
593 }
594}
595
596uint16_t
598{
599 NS_LOG_FUNCTION(this << interval.As(Time::US) << end.As(Time::S));
600
601 // If the medium is busy or it just became idle, UpdateLastIdlePeriod does
602 // nothing. This allows us to call this method, e.g., at the end of a frame
603 // reception and check the busy/idle status of the channel before the start
604 // of the frame reception (last idle period was last updated at the start of
605 // the frame reception).
606 // If the medium has been idle for some time, UpdateLastIdlePeriod updates
607 // the last idle period. This is normally what we want because this method may
608 // also be called before starting a TXOP gained through EDCA.
610
611 uint16_t width = 0;
612
613 // we iterate over the different types of channels in the same order as they
614 // are listed in WifiChannelListType
615 for (const auto& lastIdle : m_lastIdle)
616 {
617 if (lastIdle.second.start <= end - interval && lastIdle.second.end >= end)
618 {
619 // channel idle, update width
620 width = (width == 0) ? 20 : (2 * width);
621 }
622 else
623 {
624 break;
625 }
626 }
627 return width;
628}
629
630void
632{
633 NS_LOG_FUNCTION(this << qosTxop << duration);
634 NS_ASSERT(qosTxop->IsQosTxop());
636 Time resume = Simulator::Now() + duration;
637 NS_LOG_DEBUG("Backoff will resume at time " << resume << " with "
638 << qosTxop->GetBackoffSlots(m_linkId)
639 << " remaining slot(s)");
640 qosTxop->UpdateBackoffSlotsNow(0, resume, m_linkId);
642}
643
644void
646{
647 NS_LOG_FUNCTION(this << duration);
648 NS_LOG_DEBUG("rx start for=" << duration);
652 m_lastRx.end = m_lastRx.start + duration;
653 m_lastRxReceivedOk = true;
654}
655
656void
658{
659 NS_LOG_FUNCTION(this);
660 NS_LOG_DEBUG("rx end ok");
662 m_lastRxReceivedOk = true;
663}
664
665void
667{
668 NS_LOG_FUNCTION(this);
669 NS_LOG_DEBUG("rx end error");
670 // we expect the PHY to notify us of the start of a CCA busy period, if needed
672 m_lastRxReceivedOk = false;
673}
674
675void
677{
678 NS_LOG_FUNCTION(this << duration);
679 m_lastRxReceivedOk = true;
680 Time now = Simulator::Now();
681 if (m_lastRx.end > now)
682 {
683 // this may be caused only if PHY has started to receive a packet
684 // inside SIFS, so, we check that lastRxStart was maximum a SIFS ago
685 NS_ASSERT(now - m_lastRx.start <= GetSifs());
686 m_lastRx.end = now;
687 }
688 else
689 {
691 }
692 NS_LOG_DEBUG("tx start for " << duration);
694 m_lastTxEnd = now + duration;
695}
696
697void
699 WifiChannelListType channelType,
700 const std::vector<Time>& per20MhzDurations)
701{
702 NS_LOG_FUNCTION(this << duration << channelType);
705 auto lastBusyEndIt = m_lastBusyEnd.find(channelType);
706 NS_ASSERT(lastBusyEndIt != m_lastBusyEnd.end());
707 Time now = Simulator::Now();
708 lastBusyEndIt->second = now + duration;
709 // TODO uncomment assert below when PHY passes correct parameters
710 // NS_ASSERT (per20MhzDurations.size () == m_lastPer20MHzBusyEnd.size ());
711 for (std::size_t chIdx = 0; chIdx < per20MhzDurations.size(); ++chIdx)
712 {
713 if (per20MhzDurations[chIdx].IsStrictlyPositive())
714 {
715 m_lastPer20MHzBusyEnd[chIdx] = now + per20MhzDurations[chIdx];
716 }
717 }
718}
719
720void
722{
723 NS_LOG_FUNCTION(this << duration);
724 Time now = Simulator::Now();
725 NS_ASSERT(m_lastTxEnd <= now);
727
728 m_lastRxReceivedOk = true;
734
735 // the new operating channel may have a different width than the previous one
737
738 // Cancel timeout
740 {
742 }
743
744 // Notify the FEM, which will in turn notify the MAC
745 m_feManager->NotifySwitchingStartNow(duration);
746
747 // Reset backoffs
748 for (auto txop : m_txops)
749 {
750 uint32_t remainingSlots = txop->GetBackoffSlots(m_linkId);
751 if (remainingSlots > 0)
752 {
753 txop->UpdateBackoffSlotsNow(remainingSlots, now, m_linkId);
754 NS_ASSERT(txop->GetBackoffSlots(m_linkId) == 0);
755 }
756 txop->ResetCw(m_linkId);
757 txop->GetLink(m_linkId).access = Txop::NOT_REQUESTED;
758 }
759
760 NS_LOG_DEBUG("switching start for " << duration);
761 m_lastSwitchingEnd = now + duration;
762}
763
764void
766{
767 NS_LOG_FUNCTION(this);
768 m_sleeping = true;
769 // Cancel timeout
771 {
773 }
774
775 // Reset backoffs
776 for (auto txop : m_txops)
777 {
778 txop->NotifySleep(m_linkId);
779 }
780}
781
782void
784{
785 NS_LOG_FUNCTION(this);
786 m_off = true;
787 // Cancel timeout
789 {
791 }
792
793 // Reset backoffs
794 for (auto txop : m_txops)
795 {
796 txop->NotifyOff();
797 }
798}
799
800void
802{
803 NS_LOG_FUNCTION(this);
804 m_sleeping = false;
805 for (auto txop : m_txops)
806 {
807 uint32_t remainingSlots = txop->GetBackoffSlots(m_linkId);
808 if (remainingSlots > 0)
809 {
810 txop->UpdateBackoffSlotsNow(remainingSlots, Simulator::Now(), m_linkId);
811 NS_ASSERT(txop->GetBackoffSlots(m_linkId) == 0);
812 }
813 txop->ResetCw(m_linkId);
814 txop->GetLink(m_linkId).access = Txop::NOT_REQUESTED;
815 txop->NotifyWakeUp(m_linkId);
816 }
817}
818
819void
821{
822 NS_LOG_FUNCTION(this);
823 m_off = false;
824 for (auto txop : m_txops)
825 {
826 uint32_t remainingSlots = txop->GetBackoffSlots(m_linkId);
827 if (remainingSlots > 0)
828 {
829 txop->UpdateBackoffSlotsNow(remainingSlots, Simulator::Now(), m_linkId);
830 NS_ASSERT(txop->GetBackoffSlots(m_linkId) == 0);
831 }
832 txop->ResetCw(m_linkId);
833 txop->GetLink(m_linkId).access = Txop::NOT_REQUESTED;
834 txop->NotifyOn();
835 }
836}
837
838void
840{
841 NS_LOG_FUNCTION(this << duration);
842 NS_LOG_DEBUG("nav reset for=" << duration);
844 m_lastNavEnd = Simulator::Now() + duration;
852}
853
854void
856{
857 NS_LOG_FUNCTION(this << duration);
858 NS_LOG_DEBUG("nav start for=" << duration);
861}
862
863void
865{
866 NS_LOG_FUNCTION(this << duration);
868 m_lastAckTimeoutEnd = Simulator::Now() + duration;
869}
870
871void
873{
874 NS_LOG_FUNCTION(this);
877}
878
879void
881{
882 NS_LOG_FUNCTION(this << duration);
883 m_lastCtsTimeoutEnd = Simulator::Now() + duration;
884}
885
886void
888{
889 NS_LOG_FUNCTION(this);
892}
893
894void
896{
897 NS_LOG_FUNCTION(this);
899 Time now = Simulator::Now();
900
901 if (idleStart >= now)
902 {
903 // No new idle period
904 return;
905 }
906
907 for (const auto& busyEnd : m_lastBusyEnd)
908 {
909 if (busyEnd.second < now)
910 {
911 auto lastIdleIt = m_lastIdle.find(busyEnd.first);
912 NS_ASSERT(lastIdleIt != m_lastIdle.end());
913 lastIdleIt->second = {std::max(idleStart, busyEnd.second), now};
914 NS_LOG_DEBUG("New idle period (" << lastIdleIt->second.start.As(Time::S) << ", "
915 << lastIdleIt->second.end.As(Time::S)
916 << ") on channel " << lastIdleIt->first);
917 }
918 }
919}
920
921} // namespace ns3
#define min(a, b)
Definition: 80211b.c:42
#define max(a, b)
Definition: 80211b.c:43
Manage a set of ns3::Txop.
uint16_t GetLargestIdlePrimaryChannel(Time interval, Time end)
Return the width of the largest primary channel that has been idle for the given time interval before...
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 NotifyRxEndErrorNow()
Notify the Txop that a packet reception was just completed unsuccessfully.
bool m_off
flag whether it is in off state
void NotifyRxStartNow(Time duration)
Time GetBackoffEndFor(Ptr< Txop > txop)
Return the time when the backoff procedure ended (or will ended) for the given Txop.
void NotifyWakeupNow()
Notify the Txop that the device has been resumed from sleep mode.
bool m_lastRxReceivedOk
the last receive OK
std::map< WifiChannelListType, Timespan > m_lastIdle
the last idle start and end time for each channel type
Ptr< WifiPhy > m_phy
pointer to the PHY
void NotifyAckTimeoutResetNow()
Notify that ack timer has reset.
void NotifyTxStartNow(Time duration)
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
void NotifyCcaBusyStartNow(Time duration, WifiChannelListType channelType, const std::vector< Time > &per20MhzDurations)
Time m_lastAckTimeoutEnd
the last Ack timeout end time
virtual Time GetSlot() const
Return the slot duration for this PHY.
void NotifyAckTimeoutStartNow(Time duration)
Notify that ack timer has started for the given duration.
void AccessTimeout()
Called when access timeout should occur (e.g.
void UpdateBackoff()
Update backoff slots for all Txops.
bool m_sleeping
flag whether it is in sleeping state
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.
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
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.
Time m_lastTxEnd
the last transmit end time
void SetupPhyListener(Ptr< WifiPhy > phy)
Set up listener for PHY events.
Time m_lastCtsTimeoutEnd
the last CTS timeout end time
void DoDispose() override
Destructor implementation.
void NotifySleepNow()
Notify the Txop that the device has been put in sleep mode.
Ptr< FrameExchangeManager > m_feManager
pointer to the Frame Exchange Manager
PhyListener * m_phyListener
the PHY listener
void UpdateLastIdlePeriod()
This method determines whether the medium has been idle during a period (of non-null duration) immedi...
void NotifySwitchingStartNow(Time duration)
void DisableEdcaFor(Ptr< Txop > qosTxop, Time duration)
Txops m_txops
the vector of managed Txops
void DoGrantDcfAccess()
Grant access to Txop using DCF/EDCF contention rules.
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.
void NotifyNavResetNow(Time duration)
Time GetAccessGrantStart(bool ignoreNav=false) const
Access will never be granted to the medium before the time returned by this method.
bool NeedBackoffUponAccess(Ptr< Txop > txop)
Determine if a new backoff needs to be generated when a packet is queued for transmission.
void NotifyOnNow()
Notify the Txop that the device has been resumed from off mode.
Time GetBackoffStartFor(Ptr< Txop > txop)
Return the time when the backoff procedure started for the given Txop.
virtual Time GetSifs() const
Return the Short Interframe Space (SIFS) for this PHY.
void NotifyNavStartNow(Time duration)
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:55
bool IsExpired() const
This method is syntactic sugar for the ns3::Simulator::IsExpired method.
Definition: event-id.cc:69
bool IsRunning() const
This method is syntactic sugar for !IsExpired().
Definition: event-id.cc:76
Listener for PHY events.
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 NotifyTxStart(Time duration, double txPowerDbm) override
void NotifyRxStart(Time duration) override
void NotifyRxEndError() override
We have received the last bit of a packet for which NotifyRxStart was invoked first and,...
void NotifyOn() override
Notify listeners that we went to switch on.
void NotifySwitchingStart(Time duration) override
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
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition: simulator.h:568
static Time Now()
Return the current simulation virtual time.
Definition: simulator.cc:199
static Time GetMaximumSimulationTime()
Get the maximum representable simulation time.
Definition: simulator.cc:302
static Time GetDelayLeft(const EventId &id)
Get the remaining time until this event will execute.
Definition: simulator.cc:208
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:105
@ US
microsecond
Definition: nstime.h:118
@ S
second
Definition: nstime.h:116
TimeWithUnit As(const enum Unit unit=Time::AUTO) const
Attach a unit to a Time, to facilitate output in a specific unit.
Definition: time.cc:417
virtual ChannelAccessStatus GetAccessStatus(uint8_t linkId) const
Definition: txop.cc:565
virtual bool HasFramesToTransmit(uint8_t linkId)
Check if the Txop has frames to transmit over the given link.
Definition: txop.cc:496
@ GRANTED
Definition: txop.h:102
@ NOT_REQUESTED
Definition: txop.h:100
@ REQUESTED
Definition: txop.h:101
virtual bool IsQosTxop() const
Check for QoS TXOP.
Definition: txop.cc:646
void UpdateBackoffSlotsNow(uint32_t nSlots, Time backoffUpdateBound, uint8_t linkId)
Update backoff slots for the given link that nSlots has passed.
Definition: txop.cc:324
Time GetBackoffStart(uint8_t linkId) const
Return the time when the backoff procedure started on the given link.
Definition: txop.cc:318
virtual void NotifyAccessRequested(uint8_t linkId)
Notify that access request has been received for the given link.
Definition: txop.cc:571
uint8_t GetAifsn() const
Return the number of slots that make up an AIFS.
Definition: txop.cc:450
uint32_t GetBackoffSlots(uint8_t linkId) const
Return the current number of backoff slots on the given link.
Definition: txop.cc:312
Time GetSlot() const
Return the slot duration for this PHY.
Definition: wifi-phy.cc:740
uint16_t GetChannelWidth() const
Definition: wifi-phy.cc:980
Time GetSifs() const
Return the Short Interframe Space (SIFS) for this PHY.
Definition: wifi-phy.cc:728
WifiPhyBand GetPhyBand() const
Get the configured Wi-Fi band.
Definition: wifi-phy.cc:950
Time GetPifs() const
Return the PCF Interframe Space (PIFS) for this PHY.
Definition: wifi-phy.cc:752
WifiStandard GetStandard() const
Get the configured Wi-Fi standard.
Definition: wifi-phy.cc:956
void NotifyChannelAccessRequested()
Notify the PHY that an access to the channel was requested.
Definition: wifi-phy.cc:1800
Time GetAckTxTime() const
Return the estimated Ack TX time for this PHY.
Definition: wifi-phy.cc:758
const WifiPhyOperatingChannel & GetOperatingChannel() const
Get a const reference to the operating channel.
Definition: wifi-phy.cc:962
receive notifications about PHY events.
bool IsOfdm() const
Return whether the operating channel is an OFDM channel.
#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_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:202
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition: log.h:268
#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:275
Time MicroSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1362
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1338
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.
Definition: wifi-phy-band.h:35
@ 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.
phy
Definition: third.py:82