16#include "ns3/eht-frame-exchange-manager.h" 
   18#include "ns3/simulator.h" 
   22#undef NS_LOG_APPEND_CONTEXT 
   23#define NS_LOG_APPEND_CONTEXT std::clog << "[link=" << +m_linkId << "] " 
  111                            const std::vector<Time>& per20MhzDurations)
 override 
 
 
  169        TypeId(
"ns3::ChannelAccessManager")
 
  171            .SetGroupName(
"Wifi")
 
  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.",
 
  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.",
 
  191            .AddAttribute(
"ResetBackoffThreshold",
 
  192                          "If no PHY operates on this link for a period greater than this " 
  193                          "threshold, all the backoffs are reset.",
 
  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.",
 
  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");
 
 
  221    : m_lastAckTimeoutEnd(0),
 
  222      m_lastCtsTimeoutEnd(0),
 
  225      m_lastRxReceivedOk(
true),
 
  227      m_lastSwitchingEnd(0),
 
  233    InitLastBusyStructs();
 
 
  262std::shared_ptr<PhyListener>
 
  267        return listenerIt->second;
 
 
  284                      "There is already an active listener registered for given PHY");
 
  286        phyListener->SetActive(
true);
 
  290        phy->UnregisterListener(phyListener);
 
  299        phyListener = std::make_shared<PhyListener>(
this);
 
  319    phy->RegisterListener(phyListener);
 
 
  328        phy->UnregisterListener(phyListener);
 
 
  347        listener->SetActive(
false);
 
 
  358                  "The given PHY is already expected to switch channel");
 
 
  430    if (width >= 
MHz_u{40})
 
  441    if (width >= 
MHz_u{80})
 
  452    if (width >= 
MHz_u{160})
 
  463    if (width >= 
MHz_u{320})
 
 
  517                                            bool hadFramesToTransmit,
 
  518                                            bool checkMediumBusy)
 
  520    NS_LOG_FUNCTION(
this << txop << hadFramesToTransmit << checkMediumBusy);
 
  552    if (!hadFramesToTransmit && txop->HasFramesToTransmit(
m_linkId) &&
 
  555        if (checkMediumBusy && !
IsBusy())
 
 
  594    if (txop->IsQosTxop() && txop->GetBackoffStart(
m_linkId) > accessGrantStart)
 
  599        Time diff = txop->GetBackoffStart(
m_linkId) - accessGrantStart;
 
  601        txop->UpdateBackoffSlotsNow(0, accessGrantStart + (nIntSlots * 
GetSlot()), 
m_linkId);
 
  606    txop->NotifyAccessRequested(
m_linkId);
 
 
  629            NS_LOG_DEBUG(
"dcf " << k << 
" needs access. backoff expired. access granted. slots=" 
  630                                << txop->GetBackoffSlots(
m_linkId));
 
  633            std::vector<Ptr<Txop>> internalCollisionTxops;
 
  634            for (
auto j = i; j != 
m_txops.end(); j++, k++)
 
  641                        "dcf " << k << 
" needs access. backoff expired. internal collision. slots=" 
  642                               << otherTxop->GetBackoffSlots(
m_linkId));
 
  648                    internalCollisionTxops.push_back(otherTxop);
 
  674                for (
auto& collidingTxop : internalCollisionTxops)
 
  676                    m_feManager->NotifyInternalCollision(collidingTxop);
 
  684                txop->UpdateBackoffSlotsNow(0, now, 
m_linkId);
 
  688                k = std::distance(
m_txops.begin(), i);
 
 
  711std::multimap<Time, WifiExpectedAccessReason>
 
  717    std::multimap<Time, WifiExpectedAccessReason> ret;
 
  747                                   << 
", busy access start=" << busyAccessStart.As(
Time::US)
 
  749                                   << 
", nav access start=" << navAccessStart.As(
Time::US)
 
  751                                   << 
", no PHY start=" << noPhyStart.As(
Time::US)
 
 
  764    const auto accessGrantedStart = timeReasonMap.crbegin()->first;
 
  767    return accessGrantedStart + 
GetSifs();
 
 
  780    const auto mostRecentEvent =
 
  781        std::max({txop->GetBackoffStart(
m_linkId),
 
  783    NS_LOG_DEBUG(
"Backoff start for " << txop->GetWifiMacQueue()->GetAc() << 
": " 
  786    return mostRecentEvent;
 
 
  801    NS_LOG_DEBUG(
"Backoff end for " << txop->GetWifiMacQueue()->GetAc() << 
": " 
 
  813    const auto deadline = now + delay;
 
  816    auto accessGrantStart = timeReasonMap.crbegin()->first;
 
  818    if (accessGrantStart >= deadline)
 
  821        for (
const auto& [time, reason] : timeReasonMap)
 
  823            if (time >= deadline)
 
  830                                                    << 
") too late for reason " << reason);
 
  834        NS_ABORT_MSG(
"No reason found that exceeds the deadline!");
 
  847        if (!txop->HasFramesToTransmit(
m_linkId))
 
  859        if (backoffEnd >= now && backoffEnd <= deadline)
 
  861            NS_LOG_DEBUG(
"Backoff end for " << txop->GetWifiMacQueue()->GetAc() << 
" on link " 
  867    NS_LOG_DEBUG(
"Access grant not expected for reason: " << reason);
 
 
  900            if (txop->IsQosTxop())
 
  905            NS_LOG_DEBUG(
"dcf " << k << 
" dec backoff slots=" << n);
 
  906            Time backoffUpdateBound = backoffStart + (n * 
GetSlot());
 
  907            txop->UpdateBackoffSlotsNow(n, backoffUpdateBound, 
m_linkId);
 
 
  930                backoffEnd > now && backoffEnd < expectedBackoffEnd)
 
  932                expectedBackoffEnd = backoffEnd;
 
  937    NS_LOG_DEBUG(
"Access timeout needed: " << (nextTxop != 
nullptr));
 
  940        const auto aci = nextTxop->GetWifiMacQueue()->GetAc();
 
  941        NS_LOG_DEBUG(
"expected backoff end=" << expectedBackoffEnd << 
" by " << aci);
 
  942        auto expectedBackoffDelay = expectedBackoffEnd - now;
 
  946            const auto expectedNotifyTime =
 
  950            if (expectedNotifyTime > now)
 
  953                expectedBackoffDelay = expectedNotifyTime - now;
 
 
  997        if (lastIdle.second.start <= end - interval && lastIdle.second.end >= end)
 
 1000            width = (width == 
MHz_u{0}) ? 
MHz_u{20} : (2 * width);
 
 
 1017        NS_ASSERT_MSG(indices.size() == 1 && *indices.cbegin() == 0,
 
 1018                      "Index 0 only can be specified if the channel width is less than 40 MHz");
 
 1022    for (
const auto index : indices)
 
 1027            NS_LOG_DEBUG(
"20 MHz channel with index " << +index << 
" is busy");
 
 
 1041    NS_LOG_DEBUG(
"Backoff will resume at time " << resume << 
" with " 
 1042                                                << qosTxop->GetBackoffSlots(
m_linkId)
 
 1043                                                << 
" remaining slot(s)");
 
 1044    qosTxop->UpdateBackoffSlotsNow(0, resume, 
m_linkId);
 
 
 1118                                            const std::vector<Time>& per20MhzDurations)
 
 1126    lastBusyEndIt->second = now + duration;
 
 1128                  "Size of received vector (" << per20MhzDurations.size()
 
 1129                                              << 
") differs from the expected size (" 
 1131    for (std::size_t chIdx = 0; chIdx < per20MhzDurations.size(); ++chIdx)
 
 1133        if (per20MhzDurations[chIdx].IsStrictlyPositive())
 
 1146                txop->GetBackoffSlots(
m_linkId) == 0)
 
 1148                NS_LOG_DEBUG(
"Generate backoff for " << txop->GetWifiMacQueue()->GetAc());
 
 
 1173                phy->GetOperatingChannel() == emlsrInfoIt->second.channel)
 
 1182                ehtFem->NotifySwitchingEmlsrLink(phy, emlsrInfoIt->second.linkId, duration);
 
 1198    for (
const auto& txop : 
m_txops)
 
 
 1233    if (remainingSlots > 0)
 
 
 1247    for (
const auto& txop : 
m_txops)
 
 
 1315        NS_LOG_DEBUG(
"Do not reset NAV, CTS may have been missed due to the main PHY switching " 
 1316                     "to another link to take over a TXOP while receiving the CTS");
 
 
 1384    if (idleStart >= now)
 
 1392        if (busyEnd.second < now)
 
 1394            auto lastIdleIt = 
m_lastIdle.find(busyEnd.first);
 
 1396            lastIdleIt->second = {std::max(idleStart, busyEnd.second), now};
 
 1398                                             << lastIdleIt->second.end.As(
Time::S)
 
 1399                                             << 
") on channel " << lastIdleIt->first);
 
 
 1410        return (os << 
"ACCESS EXPECTED");
 
 1412        return (os << 
"NOT_REQUESTED");
 
 1414        return (os << 
"NOTHING_TO_TX");
 
 1416        return (os << 
"RX_END");
 
 1418        return (os << 
"BUSY_END");
 
 1420        return (os << 
"TX_END");
 
 1422        return (os << 
"NAV_END");
 
 1424        return (os << 
"ACK_TIMER_END");
 
 1426        return (os << 
"CTS_TIMER_END");
 
 1428        return (os << 
"SWITCHING_END");
 
 1430        return (os << 
"NO_PHY_END");
 
 1432        return (os << 
"SLEEP_END");
 
 1434        return (os << 
"OFF_END");
 
 1436        return (os << 
"BACKOFF_END");
 
 1439        return (os << 
"Unknown");
 
 
AttributeValue implementation for Boolean.
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 DoRestartAccessTimeoutIfNeeded()
void NotifyRxStartNow(Time duration)
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 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
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
~ChannelAccessManager() override
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.
void Add(Ptr< Txop > txop)
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...
void NotifyNavStartNow(Time duration)
EventId m_accessTimeout
the access timeout ID
bool GetGenerateBackoffOnNoTx() const
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.
bool IsPending() const
This method is syntactic sugar for !IsExpired().
bool IsExpired() const
This method is syntactic sugar for the ns3::Simulator::IsExpired method.
A base class which provides memory management and object aggregation.
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.
static Time Now()
Return the current simulation virtual time.
static Time GetMaximumSimulationTime()
Get the maximum representable simulation time.
static Time GetDelayLeft(const EventId &id)
Get the remaining time until this event will execute.
Simulation virtual time values and global simulation resolution.
TimeWithUnit As(const Unit unit=Time::AUTO) const
Attach a unit to a Time, to facilitate output in a specific unit.
AttributeValue implementation for Time.
a unique identifier for an interface.
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Hold an unsigned integer type.
Time GetSlot() const
Return the slot duration for this PHY.
Time GetSifs() const
Return the Short Interframe Space (SIFS) for this PHY.
WifiPhyBand GetPhyBand() const
Get the configured Wi-Fi band.
Time GetPifs() const
Return the PCF Interframe Space (PIFS) for this PHY.
MHz_u GetChannelWidth() const
bool IsStateSleep() const
WifiStandard GetStandard() const
Get the configured Wi-Fi standard.
void NotifyChannelAccessRequested()
Notify the PHY that an access to the channel was requested.
const WifiPhyOperatingChannel & GetOperatingChannel() const
Get a const reference to the operating channel.
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,...
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
Ptr< const AttributeChecker > MakeBooleanChecker()
Ptr< const AttributeAccessor > MakeBooleanAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Ptr< const AttributeAccessor > MakeTimeAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Ptr< const AttributeChecker > MakeTimeChecker()
Helper to make an unbounded Time checker.
Ptr< const AttributeChecker > MakeUintegerChecker()
Ptr< const AttributeAccessor > MakeUintegerAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
#define NS_ABORT_MSG(msg)
Unconditional abnormal program termination with a message.
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
#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.
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Time MicroSeconds(uint64_t value)
Construct a Time in the indicated unit.
Time Seconds(double value)
Construct a Time in the indicated unit.
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_PHY_BAND_2_4GHZ
The 2.4 GHz band.
@ WIFI_CHANLIST_SECONDARY40
@ WIFI_CHANLIST_SECONDARY
@ WIFI_CHANLIST_SECONDARY160
@ 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)
double MHz_u
MHz weak type.
Ptr< T1 > DynamicCast(const Ptr< T2 > &p)
Cast a Ptr.
Time GetEstimatedAckTxTime(const WifiTxVector &txVector)
std::size_t Count20MHzSubchannels(MHz_u channelWidth)
Return the number of 20 MHz subchannels covering the channel width.
Ptr< T1 > StaticCast(const Ptr< T2 > &p)
Cast a Ptr.
Information associated with each PHY that is going to operate on another EMLSR link.
Structure defining start time and end time for a given state.