13#include "ns3/boolean.h" 
   14#include "ns3/channel-access-manager.h" 
   16#include "ns3/qos-txop.h" 
   17#include "ns3/wifi-mpdu.h" 
   18#include "ns3/wifi-net-device.h" 
   19#include "ns3/wifi-phy.h" 
   32        TypeId(
"ns3::DefaultEmlsrManager")
 
   36            .AddAttribute(
"SwitchAuxPhy",
 
   37                          "Whether Aux PHY should switch channel to operate on the link on which " 
   38                          "the Main PHY was operating before moving to the link of the Aux PHY. " 
   39                          "Note that, if the Aux PHY does not switch channel, the main PHY will " 
   40                          "switch back to its previous link once the TXOP terminates (otherwise, " 
   41                          "no PHY will be listening on that EMLSR link).",
 
 
   69    NS_ASSERT_MSG(linkId, 
"Link on which the main PHY is operating not found");
 
 
   78    NS_ASSERT_MSG(linkId, 
"Link on which the main PHY is operating not found");
 
 
   94    NS_LOG_FUNCTION(
this << (currLinkId ? std::to_string(*currLinkId) : 
"") << nextLinkId << auxPhy
 
  111        NS_LOG_DEBUG(
"Aux PHY (" << auxPhy << 
") operating on link " << +nextLinkId
 
  118    if (currLinkId.has_value() && currLinkId != 
GetMainPhyId())
 
  123            "There should be an aux PHY to reconnect when the main PHY leaves an auxiliary link");
 
 
  151        auto lambda = [=, 
this]() {
 
  152            if (
GetStaMac()->GetWifiPhy(currLinkId) == auxPhy)
 
  157                if (maybeIcf && extension.IsStrictlyPositive())
 
  159                    NS_LOG_DEBUG(
"Switching aux PHY to link " << +nextLinkId << 
" is postponed by " 
  165            const auto isSleeping = auxPhy->IsStateSleep();
 
  169                auxPhy->ResumeFromSleep();
 
  175                auxPhy->SetSleepMode(
true);
 
 
  191    auto phy = 
GetStaMac()->GetWifiPhy(linkId);
 
  200    return {
true, 
Time{0}}; 
 
 
  231        const auto delay = mainPhy->IsStateSwitching() ? mainPhy->GetDelayUntilIdle() : 
Time{0};
 
 
  262    if (!mainPhy->IsStateSwitching())
 
  267                      std::forward<EmlsrMainPhySwitchTrace>(traceInfo));
 
  275            if (!GetEhtFem(linkId)->UsingOtherEmlsrLink())
 
  277                SwitchMainPhy(GetMainPhyId(), false, REQUEST_ACCESS, std::move(*info));
 
 
  284DefaultEmlsrManager::SwitchMainPhyIfTxopGainedByAuxPhy(uint8_t linkId, 
AcIndex aci)
 
 
  291DefaultEmlsrManager::GetTimeToCtsEnd(uint8_t linkId)
 const 
  295    const auto stationManager = GetStaMac()->GetWifiRemoteStationManager(linkId);
 
  296    const auto bssid = GetEhtFem(linkId)->GetBssid();
 
  297    const auto allowedWidth = GetEhtFem(linkId)->GetAllowedWidth();
 
  299    return GetTimeToCtsEnd(linkId, stationManager->GetRtsTxVector(bssid, allowedWidth));
 
 
  303DefaultEmlsrManager::GetTimeToCtsEnd(uint8_t linkId, 
const WifiTxVector& rtsTxVector)
 const 
  307    auto phy = GetStaMac()->GetWifiPhy(linkId);
 
  310    const auto stationManager = GetStaMac()->GetWifiRemoteStationManager(linkId);
 
  311    const auto bssid = GetEhtFem(linkId)->GetBssid();
 
  312    const auto ctsTxVector = stationManager->GetCtsTxVector(bssid, rtsTxVector.
GetMode());
 
  314    const auto rtsTxTime =
 
  315        WifiPhy::CalculateTxDuration(
GetRtsSize(), rtsTxVector, phy->GetPhyBand());
 
  316    const auto ctsTxTime =
 
  317        WifiPhy::CalculateTxDuration(
GetCtsSize(), ctsTxVector, phy->GetPhyBand());
 
 
  325DefaultEmlsrManager::GetDelayUnlessMainPhyTakesOverUlTxop(uint8_t linkId)
 
  329    auto mainPhy = GetStaMac()->GetDevice()->GetPhy(m_mainPhyId);
 
  330    const auto timeToCtsEnd = GetTimeToCtsEnd(linkId);
 
  331    auto switchingTime = mainPhy->GetChannelSwitchDelay();
 
  333    switch (mainPhy->GetState()->GetState())
 
  335    case WifiPhyState::SWITCHING:
 
  338        switchingTime += mainPhy->GetDelayUntilIdle();
 
  340    case WifiPhyState::RX:
 
  341    case WifiPhyState::IDLE:
 
  342    case WifiPhyState::CCA_BUSY:
 
  343        if (switchingTime > timeToCtsEnd)
 
  346            NS_LOG_DEBUG(
"Not enough time for main PHY to switch link (main PHY state: " 
  347                         << mainPhy->GetState()->GetState() << 
")");
 
  349            return {
false, timeToCtsEnd};
 
  353        NS_ABORT_MSG(
"Main PHY cannot be in state " << mainPhy->GetState()->GetState());
 
  358    m_rtsStartingUlTxop[linkId] = {Simulator::Now(), 
false};
 
  360    return {
true, 
Time{0}};
 
 
  364DefaultEmlsrManager::NotifyRtsSent(uint8_t linkId,
 
  370    const auto it = m_rtsStartingUlTxop.find(linkId);
 
  372    if (it == m_rtsStartingUlTxop.cend() || it->second.first != Simulator::Now())
 
  376    it->second.second = 
true;
 
  378    auto phy = GetStaMac()->GetWifiPhy(linkId);
 
  379    auto mainPhy = GetStaMac()->GetDevice()->GetPhy(m_mainPhyId);
 
  387    const auto delay = GetTimeToCtsEnd(linkId, txVector) - mainPhy->GetChannelSwitchDelay();
 
  389                  "RTS is being sent, but not enough time for main PHY to switch");
 
  391    NS_LOG_DEBUG(
"Schedule main Phy switch in " << delay.As(Time::US));
 
  392    m_ulMainPhySwitch[linkId] = Simulator::Schedule(delay, [=, 
this]() {
 
 
  398DefaultEmlsrManager::DoNotifyProtectionCompleted(uint8_t linkId)
 
  401    m_rtsStartingUlTxop.erase(linkId);
 
 
AttributeValue implementation for Boolean.
DefaultEmlsrManager is the default EMLSR manager.
void DoNotifyMgtFrameReceived(Ptr< const WifiMpdu > mpdu, uint8_t linkId) override
Notify the subclass of the reception of a management frame addressed to us.
void NotifyEmlsrModeChanged() override
Notify subclass that EMLSR mode changed.
EventId m_auxPhySwitchEvent
event scheduled for an aux PHY to switch link
Ptr< WifiPhy > m_auxPhyToReconnect
Aux PHY the ChannelAccessManager of the link on which the main PHY is operating has to connect a list...
void DoNotifyUlTxopStart(uint8_t linkId) override
Notify the subclass of the start of an UL TXOP on the given link.
void NotifyMainPhySwitch(std::optional< uint8_t > currLinkId, uint8_t nextLinkId, Ptr< WifiPhy > auxPhy, Time duration) override
Notify subclass that the main PHY is switching channel to operate on another link.
bool m_switchAuxPhy
whether Aux PHY should switch channel to operate on the link on which the Main PHY was operating befo...
std::pair< bool, Time > DoGetDelayUntilAccessRequest(uint8_t linkId) override
Subclasses have to provide an implementation for this method, that is called by the base class when t...
std::map< uint8_t, std::pair< Time, bool > > m_rtsStartingUlTxop
link ID-indexed map indicating the time when an UL TXOP is going to start and whether it is starting ...
void DoNotifyTxopEnd(uint8_t linkId, Ptr< QosTxop > edca) override
Notify the subclass of the end of a TXOP on the given link.
static TypeId GetTypeId()
Get the type ID.
void DoNotifyDlTxopStart(uint8_t linkId) override
Notify the subclass of the reception of an initial Control frame on the given link.
std::optional< uint8_t > ResendNotification(Ptr< const WifiMpdu > mpdu) override
A previous EML Operating Mode Notification frame was dropped.
virtual void SwitchMainPhyBackToPreferredLink(uint8_t linkId, EmlsrMainPhySwitchTrace &&traceInfo)
This method can only be called when aux PHYs do not switch link.
void SwitchAuxPhyAfterMainPhy(Ptr< WifiPhy > auxPhy, uint8_t currLinkId, uint8_t nextLinkId, Time duration)
This function shall be called when the main PHY starts switching to a link on which an aux PHY that i...
~DefaultEmlsrManager() override
uint8_t GetLinkToSendEmlOmn() override
EmlsrManager is an abstract base class defining the API that EHT non-AP MLDs with EMLSR activated can...
void SwitchMainPhy(uint8_t linkId, bool noSwitchDelay, bool requestAccess, EmlsrMainPhySwitchTrace &&traceInfo)
Switch channel on the Main PHY so that it operates on the given link.
uint8_t m_mainPhyId
ID of main PHY (position in the vector of PHYs held by WifiNetDevice)
void SwitchAuxPhy(Ptr< WifiPhy > auxPhy, uint8_t currLinkId, uint8_t nextLinkId)
Switch channel on the Aux PHY operating on the given current link so that it operates on the given ne...
MainPhySwitchInfo m_mainPhySwitchInfo
main PHY switch info
static constexpr bool REQUEST_ACCESS
request channel access when PHY switch ends
Ptr< StaWifiMac > GetStaMac() const
uint8_t GetMainPhyId() const
std::pair< bool, Time > CheckPossiblyReceivingIcf(uint8_t linkId) const
Check whether a PPDU that may be an ICF is being received on the given link.
void Cancel()
This method is syntactic sugar for the ns3::Simulator::Cancel method.
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.
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.
bool IsStrictlyPositive() const
Exactly equivalent to t > 0.
a unique identifier for an interface.
TypeId SetParent(TypeId tid)
Set the parent TypeId.
This class mimics the TXVECTOR which is to be passed to the PHY in order to define the parameters whi...
WifiMode GetMode(uint16_t staId=SU_STA_ID) const
If this TX vector is associated with an SU PPDU, return the selected payload transmission mode.
#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.
#define NS_ABORT_MSG(msg)
Unconditional abnormal program termination with a message.
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, 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_NOARGS()
Output the name of the function.
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Time Seconds(double value)
Construct a Time in the indicated unit.
AcIndex
This enumeration defines the Access Categories as an enumeration with values corresponding to the AC ...
Every class exported by the ns3 library is enclosed in the ns3 namespace.
const Time MAX_PROPAGATION_DELAY
maximum propagation delay
uint32_t GetRtsSize()
Return the total RTS size (including FCS trailer).
uint32_t GetCtsSize()
Return the total CTS size (including FCS trailer).
Struct to trace that main PHY started switching after a CTS timeout occurred on the link on which an ...
Base struct for EMLSR Main PHY switch traces.
uint8_t from
ID of the link which the main PHY is/has been leaving.
Struct to trace that main PHY switched when a (DL or UL) TXOP ended.
Struct to trace that main PHY switched to start an UL TXOP after that an aux PHY transmitted an RTS.