A Discrete-Event Network Simulator
API
channel-access-manager.cc
Go to the documentation of this file.
1/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/*
3 * Copyright (c) 2005,2006 INRIA
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation;
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 *
18 * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
19 */
20
21#include "ns3/log.h"
22#include "ns3/simulator.h"
24#include "txop.h"
25#include "wifi-phy-listener.h"
26#include "wifi-phy.h"
28
29#undef NS_LOG_APPEND_CONTEXT
30#define NS_LOG_APPEND_CONTEXT std::clog << "[link=" << +m_linkId << "] "
31
32namespace ns3 {
33
34NS_LOG_COMPONENT_DEFINE ("ChannelAccessManager");
35
40{
41public:
48 : m_cam (cam)
49 {
50 }
51 virtual ~PhyListener ()
52 {
53 }
54 void NotifyRxStart (Time duration)
55 {
56 m_cam->NotifyRxStartNow (duration);
57 }
58 void NotifyRxEndOk (void)
59 {
61 }
62 void NotifyRxEndError (void)
63 {
65 }
66 void NotifyTxStart (Time duration, double txPowerDbm)
67 {
68 m_cam->NotifyTxStartNow (duration);
69 }
70 void NotifyCcaBusyStart (Time duration, WifiChannelListType channelType,
71 const std::vector<Time>& per20MhzDurations)
72 {
73 m_cam->NotifyCcaBusyStartNow (duration, channelType, per20MhzDurations);
74 }
75 void NotifySwitchingStart (Time duration)
76 {
78 }
79 void NotifySleep (void)
80 {
82 }
83 void NotifyOff (void)
84 {
86 }
87 void NotifyWakeup (void)
88 {
90 }
91 void NotifyOn (void)
92 {
94 }
95
96private:
98};
99
100
101/****************************************************************
102 * Implement the channel access manager of all Txop holders
103 ****************************************************************/
104
106 : m_lastAckTimeoutEnd (MicroSeconds (0)),
107 m_lastCtsTimeoutEnd (MicroSeconds (0)),
108 m_lastNavEnd (MicroSeconds (0)),
109 m_lastRx ({MicroSeconds (0), MicroSeconds (0)}),
110 m_lastRxReceivedOk (true),
111 m_lastTxEnd (MicroSeconds (0)),
112 m_lastSwitchingEnd (MicroSeconds (0)),
113 m_sleeping (false),
114 m_off (false),
115 m_phyListener (0),
116 m_linkId (0)
117{
118 NS_LOG_FUNCTION (this);
119 InitLastBusyStructs ();
120}
121
123{
124 NS_LOG_FUNCTION (this);
125 delete m_phyListener;
126 m_phyListener = 0;
127}
128
129void
131{
132 NS_LOG_FUNCTION (this);
133 for (Ptr<Txop> i : m_txops)
134 {
135 i->Dispose ();
136 i = 0;
137 }
138 m_phy = 0;
139 m_feManager = 0;
140}
141
142void
144{
145 NS_LOG_FUNCTION (this << phy);
147 m_phyListener = new PhyListener (this);
148 phy->RegisterListener (m_phyListener);
149 m_phy = phy;
151}
152
153void
155{
156 NS_LOG_FUNCTION (this << phy);
157 if (m_phyListener != 0)
158 {
159 phy->UnregisterListener (m_phyListener);
160 delete m_phyListener;
161 m_phyListener = 0;
162 m_phy = 0;
163 }
164}
165
166void
168{
169 NS_LOG_FUNCTION (this << +linkId);
170 m_linkId = linkId;
171}
172
173void
175{
176 NS_LOG_FUNCTION (this << feManager);
177 m_feManager = feManager;
178 m_feManager->SetChannelAccessManager (this);
179}
180
181Time
183{
184 return m_phy->GetSlot ();
185}
186
187Time
189{
190 return m_phy->GetSifs ();
191}
192
193Time
195{
196 return m_phy->GetSifs () + m_phy->GetAckTxTime ();
197}
198
199void
201{
202 NS_LOG_FUNCTION (this << txop);
203 m_txops.push_back (txop);
204}
205
206void
208{
209 NS_LOG_FUNCTION (this);
210 Time now = Simulator::Now ();
211 m_lastBusyEnd.clear ();
212 m_lastPer20MHzBusyEnd.clear ();
213 m_lastIdle.clear ();
215 m_lastIdle[WIFI_CHANLIST_PRIMARY] = {now, now};
216
217 if (!m_phy || !m_phy->GetOperatingChannel ().IsOfdm ())
218 {
219 return;
220 }
221
222 uint16_t width = m_phy->GetChannelWidth ();
223
224 if (width >= 40)
225 {
228 }
229 if (width >= 80)
230 {
233 }
234 if (width >= 160)
235 {
238 }
239 // TODO Add conditions for new channel widths as they get supported
240
241 if (m_phy->GetStandard () >= WIFI_STANDARD_80211ax && width > 20)
242 {
243 m_lastPer20MHzBusyEnd.assign (width / 20, now);
244 }
245}
246
247bool
249{
250 NS_LOG_FUNCTION (this);
251 Time now = Simulator::Now ();
252 return (m_lastRx.end > now) // RX
253 || (m_lastTxEnd > now) // TX
254 || (m_lastNavEnd > now) // NAV busy
255 // an EDCA TXOP is obtained based solely on activity of the primary channel
256 // (Sec. 10.23.2.5 of IEEE 802.11-2020)
257 || (m_lastBusyEnd.at (WIFI_CHANLIST_PRIMARY) > now); // CCA busy
258}
259
260bool
262{
263 NS_LOG_FUNCTION (this << txop);
264
265 // No backoff needed if in sleep mode or off
266 if (m_sleeping || m_off)
267 {
268 return false;
269 }
270
271 // the Txop might have a stale value of remaining backoff slots
272 UpdateBackoff ();
273
274 /*
275 * From section 10.3.4.2 "Basic access" of IEEE 802.11-2016:
276 *
277 * A STA may transmit an MPDU when it is operating under the DCF access
278 * method, either in the absence of a PC, or in the CP of the PCF access
279 * method, when the STA determines that the medium is idle when a frame is
280 * queued for transmission, and remains idle for a period of a DIFS, or an
281 * EIFS (10.3.2.3.7) from the end of the immediately preceding medium-busy
282 * event, whichever is the greater, and the backoff timer is zero. Otherwise
283 * the random backoff procedure described in 10.3.4.3 shall be followed.
284 *
285 * From section 10.22.2.2 "EDCA backoff procedure" of IEEE 802.11-2016:
286 *
287 * The backoff procedure shall be invoked by an EDCAF when any of the following
288 * events occurs:
289 * a) An MA-UNITDATA.request primitive is received that causes a frame with that AC
290 * to be queued for transmission such that one of the transmit queues associated
291 * with that AC has now become non-empty and any other transmit queues
292 * associated with that AC are empty; the medium is busy on the primary channel
293 */
295 && txop->GetBackoffSlots (m_linkId) == 0)
296 {
297 if (!IsBusy ())
298 {
299 // medium idle. If this is a DCF, use immediate access (we can transmit
300 // in a DIFS if the medium remains idle). If this is an EDCAF, update
301 // the backoff start time kept by the EDCAF to the current time in order
302 // to correctly align the backoff start time at the next slot boundary
303 // (performed by the next call to ChannelAccessManager::RequestAccess())
304 Time delay = (txop->IsQosTxop () ? Seconds (0)
305 : GetSifs () + txop->GetAifsn (m_linkId) * GetSlot ());
306 txop->UpdateBackoffSlotsNow (0, Simulator::Now () + delay, m_linkId);
307 }
308 else
309 {
310 // medium busy, backoff is needed
311 return true;
312 }
313 }
314 return false;
315}
316
317void
319{
320 NS_LOG_FUNCTION (this << txop);
321 if (m_phy)
322 {
324 }
325 //Deny access if in sleep mode or off
326 if (m_sleeping || m_off)
327 {
328 return;
329 }
330 /*
331 * EDCAF operations shall be performed at slot boundaries (Sec. 10.22.2.4 of 802.11-2016)
332 */
333 Time accessGrantStart = GetAccessGrantStart () + (txop->GetAifsn (m_linkId) * GetSlot ());
334
335 if (txop->IsQosTxop () && txop->GetBackoffStart (m_linkId) > accessGrantStart)
336 {
337 // The backoff start time reported by the EDCAF is more recent than the last
338 // time the medium was busy plus an AIFS, hence we need to align it to the
339 // next slot boundary.
340 Time diff = txop->GetBackoffStart (m_linkId) - accessGrantStart;
341 uint32_t nIntSlots = (diff / GetSlot ()).GetHigh () + 1;
342 txop->UpdateBackoffSlotsNow (0, accessGrantStart + (nIntSlots * GetSlot ()), m_linkId);
343 }
344
345 UpdateBackoff ();
350}
351
352void
354{
355 NS_LOG_FUNCTION (this);
356 uint32_t k = 0;
357 Time now = Simulator::Now ();
358 for (Txops::iterator i = m_txops.begin (); i != m_txops.end (); k++)
359 {
360 Ptr<Txop> txop = *i;
362 && (!txop->IsQosTxop () || !StaticCast<QosTxop> (txop)->EdcaDisabled (m_linkId))
363 && GetBackoffEndFor (txop) <= now)
364 {
369 NS_LOG_DEBUG ("dcf " << k << " needs access. backoff expired. access granted. slots=" << txop->GetBackoffSlots (m_linkId));
370 i++; //go to the next item in the list.
371 k++;
372 std::vector<Ptr<Txop> > internalCollisionTxops;
373 for (Txops::iterator j = i; j != m_txops.end (); j++, k++)
374 {
375 Ptr<Txop> otherTxop = *j;
376 if (otherTxop->GetAccessStatus (m_linkId) == Txop::REQUESTED
377 && GetBackoffEndFor (otherTxop) <= now)
378 {
379 NS_LOG_DEBUG ("dcf " << k << " needs access. backoff expired. internal collision. slots=" <<
380 otherTxop->GetBackoffSlots (m_linkId));
386 internalCollisionTxops.push_back (otherTxop);
387 }
388 }
389
399 // If we are operating on an OFDM channel wider than 20 MHz, find the largest
400 // idle primary channel and pass its width to the FrameExchangeManager, so that
401 // the latter can transmit PPDUs of the appropriate width (see Section 10.23.2.5
402 // of IEEE 802.11-2020).
403 auto interval = (m_phy->GetPhyBand () == WIFI_PHY_BAND_2_4GHZ)
404 ? GetSifs () + 2 * GetSlot () : m_phy->GetPifs ();
405 auto width = (m_phy->GetOperatingChannel ().IsOfdm () && m_phy->GetChannelWidth () > 20)
406 ? GetLargestIdlePrimaryChannel (interval, now) : m_phy->GetChannelWidth ();
407 if (m_feManager->StartTransmission (txop, width))
408 {
409 for (auto& collidingTxop : internalCollisionTxops)
410 {
411 m_feManager->NotifyInternalCollision (collidingTxop);
412 }
413 break;
414 }
415 else
416 {
417 // reset the current state to the EDCAF that won the contention
418 // but did not transmit anything
419 i--;
420 k = std::distance (m_txops.begin (), i);
421 }
422 }
423 i++;
424 }
425}
426
427void
429{
430 NS_LOG_FUNCTION (this);
431 UpdateBackoff ();
434}
435
436Time
438{
439 NS_LOG_FUNCTION (this);
440 const Time& sifs = GetSifs();
441 Time rxAccessStart = m_lastRx.end + sifs;
443 {
444 rxAccessStart += GetEifsNoDifs ();
445 }
446 // an EDCA TXOP is obtained based solely on activity of the primary channel
447 // (Sec. 10.23.2.5 of IEEE 802.11-2020)
448 Time busyAccessStart = m_lastBusyEnd.at (WIFI_CHANLIST_PRIMARY) + sifs;
449 Time txAccessStart = m_lastTxEnd + sifs;
450 Time navAccessStart = m_lastNavEnd + sifs;
451 Time ackTimeoutAccessStart = m_lastAckTimeoutEnd + sifs;
452 Time ctsTimeoutAccessStart = m_lastCtsTimeoutEnd + sifs;
453 Time switchingAccessStart = m_lastSwitchingEnd + sifs;
454 Time accessGrantedStart;
455 if (ignoreNav)
456 {
457 accessGrantedStart = std::max ({rxAccessStart,
458 busyAccessStart,
459 txAccessStart,
460 ackTimeoutAccessStart,
461 ctsTimeoutAccessStart,
462 switchingAccessStart}
463 );
464 }
465 else
466 {
467 accessGrantedStart = std::max ({rxAccessStart,
468 busyAccessStart,
469 txAccessStart,
470 navAccessStart,
471 ackTimeoutAccessStart,
472 ctsTimeoutAccessStart,
473 switchingAccessStart}
474 );
475 }
476 NS_LOG_INFO ("access grant start=" << accessGrantedStart <<
477 ", rx access start=" << rxAccessStart <<
478 ", busy access start=" << busyAccessStart <<
479 ", tx access start=" << txAccessStart <<
480 ", nav access start=" << navAccessStart);
481 return accessGrantedStart;
482}
483
484Time
486{
487 NS_LOG_FUNCTION (this << txop);
488 Time mostRecentEvent = std::max ({txop->GetBackoffStart (m_linkId),
489 GetAccessGrantStart () + (txop->GetAifsn (m_linkId) * GetSlot ())});
490 NS_LOG_DEBUG ("Backoff start: " << mostRecentEvent.As (Time::US));
491
492 return mostRecentEvent;
493}
494
495Time
497{
498 NS_LOG_FUNCTION (this << txop);
499 Time backoffEnd = GetBackoffStartFor (txop) + (txop->GetBackoffSlots (m_linkId) * GetSlot ());
500 NS_LOG_DEBUG ("Backoff end: " << backoffEnd.As (Time::US));
501
502 return backoffEnd;
503}
504
505void
507{
508 NS_LOG_FUNCTION (this);
509 uint32_t k = 0;
510 for (auto txop : m_txops)
511 {
512 Time backoffStart = GetBackoffStartFor (txop);
513 if (backoffStart <= Simulator::Now ())
514 {
515 uint32_t nIntSlots = ((Simulator::Now () - backoffStart) / GetSlot ()).GetHigh ();
516 /*
517 * EDCA behaves slightly different to DCA. For EDCA we
518 * decrement once at the slot boundary at the end of AIFS as
519 * well as once at the end of each clear slot
520 * thereafter. For DCA we only decrement at the end of each
521 * clear slot after DIFS. We account for the extra backoff
522 * by incrementing the slot count here in the case of
523 * EDCA. The if statement whose body we are in has confirmed
524 * that a minimum of AIFS has elapsed since last busy
525 * medium.
526 */
527 if (txop->IsQosTxop ())
528 {
529 nIntSlots++;
530 }
531 uint32_t n = std::min (nIntSlots, txop->GetBackoffSlots (m_linkId));
532 NS_LOG_DEBUG ("dcf " << k << " dec backoff slots=" << n);
533 Time backoffUpdateBound = backoffStart + (n * GetSlot ());
534 txop->UpdateBackoffSlotsNow (n, backoffUpdateBound, m_linkId);
535 }
536 ++k;
537 }
538}
539
540void
542{
543 NS_LOG_FUNCTION (this);
548 bool accessTimeoutNeeded = false;
549 Time expectedBackoffEnd = Simulator::GetMaximumSimulationTime ();
550 for (auto txop : m_txops)
551 {
552 if (txop->GetAccessStatus (m_linkId) == Txop::REQUESTED)
553 {
554 Time tmp = GetBackoffEndFor (txop);
555 if (tmp > Simulator::Now ())
556 {
557 accessTimeoutNeeded = true;
558 expectedBackoffEnd = std::min (expectedBackoffEnd, tmp);
559 }
560 }
561 }
562 NS_LOG_DEBUG ("Access timeout needed: " << accessTimeoutNeeded);
563 if (accessTimeoutNeeded)
564 {
565 NS_LOG_DEBUG ("expected backoff end=" << expectedBackoffEnd);
566 Time expectedBackoffDelay = expectedBackoffEnd - Simulator::Now ();
568 && Simulator::GetDelayLeft (m_accessTimeout) > expectedBackoffDelay)
569 {
571 }
573 {
574 m_accessTimeout = Simulator::Schedule (expectedBackoffDelay,
576 }
577 }
578}
579
580uint16_t
582{
583 NS_LOG_FUNCTION (this << interval.As (Time::US) << end.As (Time::S));
584
585 // If the medium is busy or it just became idle, UpdateLastIdlePeriod does
586 // nothing. This allows us to call this method, e.g., at the end of a frame
587 // reception and check the busy/idle status of the channel before the start
588 // of the frame reception (last idle period was last updated at the start of
589 // the frame reception).
590 // If the medium has been idle for some time, UpdateLastIdlePeriod updates
591 // the last idle period. This is normally what we want because this method may
592 // also be called before starting a TXOP gained through EDCA.
594
595 uint16_t width = 0;
596
597 // we iterate over the different types of channels in the same order as they
598 // are listed in WifiChannelListType
599 for (const auto& lastIdle : m_lastIdle)
600 {
601 if (lastIdle.second.start <= end -interval && lastIdle.second.end >= end)
602 {
603 // channel idle, update width
604 width = (width == 0) ? 20 : (2 * width);
605 }
606 else
607 {
608 break;
609 }
610 }
611 return width;
612}
613
614void
616{
617 NS_LOG_FUNCTION (this << qosTxop << duration);
618 NS_ASSERT (qosTxop->IsQosTxop ());
619 UpdateBackoff ();
620 Time resume = Simulator::Now () + duration;
621 NS_LOG_DEBUG ("Backoff will resume at time " << resume << " with "
622 << qosTxop->GetBackoffSlots (m_linkId) << " remaining slot(s)");
623 qosTxop->UpdateBackoffSlotsNow (0, resume, m_linkId);
625}
626
627void
629{
630 NS_LOG_FUNCTION (this << duration);
631 NS_LOG_DEBUG ("rx start for=" << duration);
632 UpdateBackoff ();
635 m_lastRx.end = m_lastRx.start + duration;
636 m_lastRxReceivedOk = true;
637}
638
639void
641{
642 NS_LOG_FUNCTION (this);
643 NS_LOG_DEBUG ("rx end ok");
645 m_lastRxReceivedOk = true;
646}
647
648void
650{
651 NS_LOG_FUNCTION (this);
652 NS_LOG_DEBUG ("rx end error");
653 // we expect the PHY to notify us of the start of a CCA busy period, if needed
655 m_lastRxReceivedOk = false;
656}
657
658void
660{
661 NS_LOG_FUNCTION (this << duration);
662 m_lastRxReceivedOk = true;
663 Time now = Simulator::Now ();
664 if (m_lastRx.end > now)
665 {
666 //this may be caused only if PHY has started to receive a packet
667 //inside SIFS, so, we check that lastRxStart was maximum a SIFS ago
668 NS_ASSERT (now - m_lastRx.start <= GetSifs ());
669 m_lastRx.end = now;
670 }
671 else
672 {
674 }
675 NS_LOG_DEBUG ("tx start for " << duration);
676 UpdateBackoff ();
677 m_lastTxEnd = now + duration;
678}
679
680void
682 WifiChannelListType channelType,
683 const std::vector<Time>& per20MhzDurations)
684{
685 NS_LOG_FUNCTION (this << duration << channelType);
686 UpdateBackoff ();
688 auto lastBusyEndIt = m_lastBusyEnd.find (channelType);
689 NS_ASSERT (lastBusyEndIt != m_lastBusyEnd.end ());
690 Time now = Simulator::Now ();
691 lastBusyEndIt->second = now + duration;
692 // TODO uncomment assert below when PHY passes correct parameters
693 // NS_ASSERT (per20MhzDurations.size () == m_lastPer20MHzBusyEnd.size ());
694 for (std::size_t chIdx = 0; chIdx < per20MhzDurations.size (); ++chIdx)
695 {
696 if (per20MhzDurations[chIdx].IsStrictlyPositive ())
697 {
698 m_lastPer20MHzBusyEnd[chIdx] = now + per20MhzDurations[chIdx];
699 }
700 }
701}
702
703void
705{
706 NS_LOG_FUNCTION (this << duration);
707 Time now = Simulator::Now ();
708 NS_ASSERT (m_lastTxEnd <= now);
710
711 m_lastRxReceivedOk = true;
717
718 // the new operating channel may have a different width than the previous one
720
721 //Cancel timeout
723 {
725 }
726
727 // Notify the FEM, which will in turn notify the MAC
728 m_feManager->NotifySwitchingStartNow (duration);
729
730 //Reset backoffs
731 for (auto txop : m_txops)
732 {
733 uint32_t remainingSlots = txop->GetBackoffSlots (m_linkId);
734 if (remainingSlots > 0)
735 {
736 txop->UpdateBackoffSlotsNow (remainingSlots, now, m_linkId);
737 NS_ASSERT (txop->GetBackoffSlots (m_linkId) == 0);
738 }
739 txop->ResetCw (m_linkId);
740 txop->GetLink (m_linkId).access = Txop::NOT_REQUESTED;
741 }
742
743 NS_LOG_DEBUG ("switching start for " << duration);
744 m_lastSwitchingEnd = now + duration;
745}
746
747void
749{
750 NS_LOG_FUNCTION (this);
751 m_sleeping = true;
752 //Cancel timeout
754 {
756 }
757
758 //Reset backoffs
759 for (auto txop : m_txops)
760 {
761 txop->NotifySleep (m_linkId);
762 }
763}
764
765void
767{
768 NS_LOG_FUNCTION (this);
769 m_off = true;
770 //Cancel timeout
772 {
774 }
775
776 //Reset backoffs
777 for (auto txop : m_txops)
778 {
779 txop->NotifyOff ();
780 }
781}
782
783void
785{
786 NS_LOG_FUNCTION (this);
787 m_sleeping = false;
788 for (auto txop : m_txops)
789 {
790 uint32_t remainingSlots = txop->GetBackoffSlots (m_linkId);
791 if (remainingSlots > 0)
792 {
793 txop->UpdateBackoffSlotsNow (remainingSlots, Simulator::Now (), m_linkId);
794 NS_ASSERT (txop->GetBackoffSlots (m_linkId) == 0);
795 }
796 txop->ResetCw (m_linkId);
797 txop->GetLink (m_linkId).access = Txop::NOT_REQUESTED;
798 txop->NotifyWakeUp (m_linkId);
799 }
800}
801
802void
804{
805 NS_LOG_FUNCTION (this);
806 m_off = false;
807 for (auto txop : m_txops)
808 {
809 uint32_t remainingSlots = txop->GetBackoffSlots (m_linkId);
810 if (remainingSlots > 0)
811 {
812 txop->UpdateBackoffSlotsNow (remainingSlots, Simulator::Now (), m_linkId);
813 NS_ASSERT (txop->GetBackoffSlots (m_linkId) == 0);
814 }
815 txop->ResetCw (m_linkId);
816 txop->GetLink (m_linkId).access = Txop::NOT_REQUESTED;
817 txop->NotifyOn ();
818 }
819}
820
821void
823{
824 NS_LOG_FUNCTION (this << duration);
825 NS_LOG_DEBUG ("nav reset for=" << duration);
826 UpdateBackoff ();
827 m_lastNavEnd = Simulator::Now () + duration;
835}
836
837void
839{
840 NS_LOG_FUNCTION (this << duration);
841 NS_LOG_DEBUG ("nav start for=" << duration);
842 UpdateBackoff ();
844}
845
846void
848{
849 NS_LOG_FUNCTION (this << duration);
851 m_lastAckTimeoutEnd = Simulator::Now () + duration;
852}
853
854void
856{
857 NS_LOG_FUNCTION (this);
860}
861
862void
864{
865 NS_LOG_FUNCTION (this << duration);
866 m_lastCtsTimeoutEnd = Simulator::Now () + duration;
867}
868
869void
871{
872 NS_LOG_FUNCTION (this);
875}
876
877void
879{
880 NS_LOG_FUNCTION (this);
882 Time now = Simulator::Now ();
883
884 if (idleStart >= now)
885 {
886 // No new idle period
887 return;
888 }
889
890 for (const auto& busyEnd : m_lastBusyEnd)
891 {
892 if (busyEnd.second < now)
893 {
894 auto lastIdleIt = m_lastIdle.find (busyEnd.first);
895 NS_ASSERT (lastIdleIt != m_lastIdle.end ());
896 lastIdleIt->second = {std::max (idleStart, busyEnd.second), now};
897 NS_LOG_DEBUG ("New idle period (" << lastIdleIt->second.start.As (Time::S)
898 << ", " << lastIdleIt->second.end.As (Time::S)
899 << ") on channel " << lastIdleIt->first);
900 }
901 }
902}
903
904} //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)
void AccessTimeout(void)
Called when access timeout should occur (e.g.
bool m_off
flag whether it is in off state
void NotifyRxStartNow(Time duration)
void UpdateBackoff(void)
Update backoff slots for all Txops.
Time GetBackoffEndFor(Ptr< Txop > txop)
Return the time when the backoff procedure ended (or will ended) for the given Txop.
void DoDispose(void) override
Destructor implementation.
bool m_lastRxReceivedOk
the last receive OK
void NotifyCtsTimeoutResetNow(void)
Notify that CTS timer has reset.
void NotifyOnNow(void)
Notify the Txop that the device has been resumed from off mode.
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 NotifyTxStartNow(Time duration)
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
void NotifyAckTimeoutStartNow(Time duration)
Notify that ack timer has started for the given duration.
bool m_sleeping
flag whether it is in sleeping state
void NotifyRxEndOkNow(void)
Notify the Txop that a packet reception was just completed successfully.
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)
bool IsBusy(void) const
Check if the device is busy sending or receiving, or NAV or CCA busy.
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 NotifySleepNow(void)
Notify the Txop that the device has been put in sleep mode.
void SetupPhyListener(Ptr< WifiPhy > phy)
Set up listener for PHY events.
Time m_lastCtsTimeoutEnd
the last CTS timeout end time
void NotifyWakeupNow(void)
Notify the Txop that the device has been resumed from sleep mode.
Ptr< FrameExchangeManager > m_feManager
pointer to the Frame Exchange Manager
void UpdateLastIdlePeriod(void)
This method determines whether the medium has been idle during a period (of non-null duration) immedi...
void NotifyOffNow(void)
Notify the Txop that the device has been put in off mode.
PhyListener * m_phyListener
the PHY listener
virtual Time GetSlot(void) const
Return the slot duration for this PHY.
void InitLastBusyStructs(void)
Initialize the structures holding busy end times per channel type (primary, secondary,...
void NotifySwitchingStartNow(Time duration)
void DisableEdcaFor(Ptr< Txop > qosTxop, Time duration)
void DoGrantDcfAccess(void)
Grant access to Txop using DCF/EDCF contention rules.
Txops m_txops
the vector of managed Txops
Time m_lastNavEnd
the last NAV end time
virtual Time GetSifs(void) const
Return the Short Interframe Space (SIFS) for this PHY.
void NotifyAckTimeoutResetNow(void)
Notify that ack timer has reset.
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.
virtual Time GetEifsNoDifs(void) const
Return the EIFS duration minus a DIFS.
Time GetBackoffStartFor(Ptr< Txop > txop)
Return the time when the backoff procedure started for the given Txop.
void NotifyNavStartNow(Time duration)
EventId m_accessTimeout
the access timeout ID
void NotifyRxEndErrorNow(void)
Notify the Txop that a packet reception was just completed unsuccessfully.
bool IsRunning(void) const
This method is syntactic sugar for !IsExpired().
Definition: event-id.cc:71
void Cancel(void)
This method is syntactic sugar for the ns3::Simulator::Cancel method.
Definition: event-id.cc:53
bool IsExpired(void) const
This method is syntactic sugar for the ns3::Simulator::IsExpired method.
Definition: event-id.cc:65
Listener for PHY events.
void NotifySwitchingStart(Time duration)
void NotifyRxEndError(void)
We have received the last bit of a packet for which NotifyRxStart was invoked first and,...
void NotifyOn(void)
Notify listeners that we went to switch on.
PhyListener(ns3::ChannelAccessManager *cam)
Create a PhyListener for the given ChannelAccessManager.
ns3::ChannelAccessManager * m_cam
ChannelAccessManager to forward events to.
void NotifyRxEndOk(void)
We have received the last bit of a packet for which NotifyRxStart was invoked first and,...
void NotifyCcaBusyStart(Time duration, WifiChannelListType channelType, const std::vector< Time > &per20MhzDurations)
void NotifyWakeup(void)
Notify listeners that we woke up.
void NotifyOff(void)
Notify listeners that we went to switch off.
void NotifyTxStart(Time duration, double txPowerDbm)
void NotifySleep(void)
Notify listeners that we went to sleep.
void NotifyRxStart(Time duration)
static EventId Schedule(Time const &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition: simulator.h:555
static Time GetMaximumSimulationTime(void)
Get the maximum representable simulation time.
Definition: simulator.cc:293
static Time Now(void)
Return the current simulation virtual time.
Definition: simulator.cc:195
static Time GetDelayLeft(const EventId &id)
Get the remaining time until this event will execute.
Definition: simulator.cc:204
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:104
@ US
microsecond
Definition: nstime.h:117
@ S
second
Definition: nstime.h:115
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:418
virtual ChannelAccessStatus GetAccessStatus(uint8_t linkId) const
Definition: txop.cc:546
virtual bool HasFramesToTransmit(uint8_t linkId)
Check if the Txop has frames to transmit over the given link.
Definition: txop.cc:478
@ GRANTED
Definition: txop.h:98
@ NOT_REQUESTED
Definition: txop.h:96
@ REQUESTED
Definition: txop.h:97
virtual bool IsQosTxop() const
Check for QoS TXOP.
Definition: txop.cc:627
void UpdateBackoffSlotsNow(uint32_t nSlots, Time backoffUpdateBound, uint8_t linkId)
Update backoff slots for the given link that nSlots has passed.
Definition: txop.cc:308
Time GetBackoffStart(uint8_t linkId) const
Return the time when the backoff procedure started on the given link.
Definition: txop.cc:302
virtual void NotifyAccessRequested(uint8_t linkId)
Notify that access request has been received for the given link.
Definition: txop.cc:552
uint32_t GetBackoffSlots(uint8_t linkId) const
Return the current number of backoff slots on the given link.
Definition: txop.cc:296
uint8_t GetAifsn(void) const
Return the number of slots that make up an AIFS.
Definition: txop.cc:432
const WifiPhyOperatingChannel & GetOperatingChannel(void) const
Get a const reference to the operating channel.
Definition: wifi-phy.cc:951
WifiPhyBand GetPhyBand(void) const
Get the configured Wi-Fi band.
Definition: wifi-phy.cc:938
WifiStandard GetStandard(void) const
Get the configured Wi-Fi standard.
Definition: wifi-phy.cc:945
Time GetSlot(void) const
Return the slot duration for this PHY.
Definition: wifi-phy.cc:728
Time GetPifs(void) const
Return the PCF Interframe Space (PIFS) for this PHY.
Definition: wifi-phy.cc:740
void NotifyChannelAccessRequested(void)
Notify the PHY that an access to the channel was requested.
Definition: wifi-phy.cc:1723
Time GetSifs(void) const
Return the Short Interframe Space (SIFS) for this PHY.
Definition: wifi-phy.cc:716
Time GetAckTxTime(void) const
Return the estimated Ack TX time for this PHY.
Definition: wifi-phy.cc:746
uint16_t GetChannelWidth(void) const
Definition: wifi-phy.cc:969
receive notifications about PHY events.
bool IsOfdm(void) 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:67
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:206
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition: log.h:274
#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:282
Time MicroSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1261
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1245
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:84