diff --git a/src/wifi/model/eht/default-emlsr-manager.cc b/src/wifi/model/eht/default-emlsr-manager.cc index 1e3f59af5..01062ff96 100644 --- a/src/wifi/model/eht/default-emlsr-manager.cc +++ b/src/wifi/model/eht/default-emlsr-manager.cc @@ -229,9 +229,9 @@ DefaultEmlsrManager::DoNotifyTxopEnd(uint8_t linkId) } void -DefaultEmlsrManager::SwitchMainPhyIfTxopGainedByAuxPhy(uint8_t linkId) +DefaultEmlsrManager::SwitchMainPhyIfTxopGainedByAuxPhy(uint8_t linkId, AcIndex aci) { - NS_LOG_FUNCTION(this << linkId); + NS_LOG_FUNCTION(this << linkId << aci); NS_ASSERT_MSG(!m_auxPhyTxCapable, "This function should only be called if aux PHY is not TX capable"); @@ -239,9 +239,12 @@ DefaultEmlsrManager::SwitchMainPhyIfTxopGainedByAuxPhy(uint8_t linkId) // the aux PHY is not TX capable; check if main PHY has to switch to the aux PHY's link auto mainPhy = GetStaMac()->GetDevice()->GetPhy(m_mainPhyId); - // if the main PHY is idle, check whether the remaining backoff counter on at least an AC with - // queued packets is greater than the main PHY channel switch delay - auto backoffGreaterThanSwitchDelay = false; + // if the main PHY is idle, switch main PHY if we expect the main PHY to get channel access on + // this link more quicky, i.e., if ALL the ACs with queued frames and with priority higher than + // or equal to that of the AC for which Aux PHY gained TXOP have their backoff counter greater + // than the channel switch delay plus PIFS + + auto requestSwitch = false; if (mainPhy->IsStateIdle()) { @@ -255,19 +258,23 @@ DefaultEmlsrManager::SwitchMainPhyIfTxopGainedByAuxPhy(uint8_t linkId) Txop::HAD_FRAMES_TO_TRANSMIT, Txop::CHECK_MEDIUM_BUSY); - for (const auto& [aci, ac] : wifiAcList) + for (const auto& [acIndex, ac] : wifiAcList) { - if (auto edca = GetStaMac()->GetQosTxop(aci); edca->HasFramesToTransmit(linkId)) + if (auto edca = GetStaMac()->GetQosTxop(acIndex); + acIndex >= aci && edca->HasFramesToTransmit(linkId)) { + requestSwitch = true; + auto backoffEnd = GetStaMac()->GetChannelAccessManager(*mainPhyLinkId)->GetBackoffEndFor(edca); - NS_LOG_DEBUG("Backoff end for " << aci + NS_LOG_DEBUG("Backoff end for " << acIndex << " on primary link: " << backoffEnd.As(Time::US)); - if (backoffEnd > Simulator::Now() + mainPhy->GetChannelSwitchDelay() + - GetStaMac()->GetWifiPhy(linkId)->GetPifs()) + if (backoffEnd <= Simulator::Now() + mainPhy->GetChannelSwitchDelay() + + GetStaMac()->GetWifiPhy(linkId)->GetPifs() && + edca->HasFramesToTransmit(*mainPhyLinkId)) { - backoffGreaterThanSwitchDelay = true; + requestSwitch = false; break; } } @@ -275,7 +282,7 @@ DefaultEmlsrManager::SwitchMainPhyIfTxopGainedByAuxPhy(uint8_t linkId) } if ((mainPhy->IsStateCcaBusy() && !mainPhy->IsReceivingPhyHeader()) || - (mainPhy->IsStateIdle() && backoffGreaterThanSwitchDelay)) + (mainPhy->IsStateIdle() && requestSwitch)) { // switch main PHY SwitchMainPhy(linkId, false, RESET_BACKOFF, REQUEST_ACCESS); diff --git a/src/wifi/model/eht/default-emlsr-manager.h b/src/wifi/model/eht/default-emlsr-manager.h index 6ae1c2c06..e3a81fe45 100644 --- a/src/wifi/model/eht/default-emlsr-manager.h +++ b/src/wifi/model/eht/default-emlsr-manager.h @@ -37,7 +37,7 @@ class DefaultEmlsrManager : public EmlsrManager uint8_t GetLinkToSendEmlOmn() override; std::optional ResendNotification(Ptr mpdu) override; Time DoGetDelayUntilAccessRequest(uint8_t linkId) override; - void SwitchMainPhyIfTxopGainedByAuxPhy(uint8_t linkId) override; + void SwitchMainPhyIfTxopGainedByAuxPhy(uint8_t linkId, AcIndex aci) override; Time GetDelayUnlessMainPhyTakesOverUlTxop(uint8_t linkId) override; /** diff --git a/src/wifi/model/eht/eht-frame-exchange-manager.cc b/src/wifi/model/eht/eht-frame-exchange-manager.cc index 9c71b0b8b..4d364446f 100644 --- a/src/wifi/model/eht/eht-frame-exchange-manager.cc +++ b/src/wifi/model/eht/eht-frame-exchange-manager.cc @@ -279,7 +279,9 @@ EhtFrameExchangeManager::StartTransmission(Ptr edca, MHz_u allowedWidth) const auto mainPhySwitching = mainPhy->IsStateSwitching(); // let EMLSR manager decide whether to prevent or allow this UL TXOP - if (auto delay = emlsrManager->GetDelayUntilAccessRequest(m_linkId); + if (auto delay = emlsrManager->GetDelayUntilAccessRequest( + m_linkId, + DynamicCast(edca)->GetAccessCategory()); delay.IsStrictlyPositive()) { NotifyChannelReleased(edca); diff --git a/src/wifi/model/eht/emlsr-manager.cc b/src/wifi/model/eht/emlsr-manager.cc index f468dd631..cc097588a 100644 --- a/src/wifi/model/eht/emlsr-manager.cc +++ b/src/wifi/model/eht/emlsr-manager.cc @@ -409,7 +409,7 @@ EmlsrManager::NotifyIcfReceived(uint8_t linkId) } Time -EmlsrManager::GetDelayUntilAccessRequest(uint8_t linkId) +EmlsrManager::GetDelayUntilAccessRequest(uint8_t linkId, AcIndex aci) { auto phy = m_staMac->GetWifiPhy(linkId); NS_ASSERT_MSG(phy, "No PHY operating on link " << +linkId); @@ -432,7 +432,7 @@ EmlsrManager::GetDelayUntilAccessRequest(uint8_t linkId) // whether the aux PHY is TX capable or not if (!m_auxPhyTxCapable) { - SwitchMainPhyIfTxopGainedByAuxPhy(linkId); + SwitchMainPhyIfTxopGainedByAuxPhy(linkId, aci); // if the aux PHY is not TX capable, we don't have to request channel access: if the main // PHY switches link, the UL TXOP will be started; if the main PHY does not switch, it is // because it is going to start an UL TXOP on another link and this link will be restarted diff --git a/src/wifi/model/eht/emlsr-manager.h b/src/wifi/model/eht/emlsr-manager.h index 49f9a3bad..aa6e521cf 100644 --- a/src/wifi/model/eht/emlsr-manager.h +++ b/src/wifi/model/eht/emlsr-manager.h @@ -142,14 +142,15 @@ class EmlsrManager : public Object bool GetCamStateReset() const; /** - * Notify that an UL TXOP is gained on the given link. This method has to determine whether to - * start the UL TXOP or release the channel. + * Notify that an UL TXOP is gained on the given link by the given AC. This method has to + * determine whether to start the UL TXOP or release the channel. * * \param linkId the ID of the given link + * \param aci the index of the given AC * \return zero, if the UL TXOP can be started, or the delay after which the EMLSR client * restarts channel access, otherwise */ - Time GetDelayUntilAccessRequest(uint8_t linkId); + Time GetDelayUntilAccessRequest(uint8_t linkId, AcIndex aci); /** * Set the member variable indicating whether Aux PHYs are capable of transmitting PPDUs. @@ -363,13 +364,14 @@ class EmlsrManager : public Object /** * Subclasses have to provide an implementation for this method, that is called by the base - * class when the EMLSR client gets channel access on the given link, on which an aux PHY that - * is not TX capable is operating. This method has to request the main PHY to switch to the - * given link to take over the TXOP, unless it is decided to give up the TXOP. + * class when the given AC of the EMLSR client gets channel access on the given link, on which + * an aux PHY that is not TX capable is operating. This method has to request the main PHY to + * switch to the given link to take over the TXOP, unless it is decided to give up the TXOP. * * \param linkId the ID of the given link + * \param aci the index of the given AC */ - virtual void SwitchMainPhyIfTxopGainedByAuxPhy(uint8_t linkId) = 0; + virtual void SwitchMainPhyIfTxopGainedByAuxPhy(uint8_t linkId, AcIndex aci) = 0; /** * Subclasses have to provide an implementation for this method, that is called by the base