wifi: Switch main PHY back timer starts with main PHY channel switch

Enables to interrupt the switch if appropriate events occur during the
switch.
This commit is contained in:
Stefano Avallone
2025-01-29 17:01:02 +01:00
parent cc41421320
commit 4322bdb888

View File

@@ -287,12 +287,15 @@ AdvancedEmlsrManager::ReceivedMacHdr(Ptr<WifiPhy> phy,
Simulator::ScheduleNow(&AdvancedEmlsrManager::NotifyTxopEnd, this, *linkId, false, false);
}
// if the MAC header has been received on the link on which the main PHY is operating, the
// switch main PHY back timer is running and channel access is not expected to be gained by
// the main PHY before the switch main PHY back timer expires (plus a channel switch delay),
// try to switch the main PHY back to the preferred link
if (m_switchMainPhyBackEvent.IsPending() &&
phy == GetStaMac()->GetDevice()->GetPhy(GetMainPhyId()) &&
// if the MAC header has been received on the link on which the main PHY is operating (or on
// the link the main PHY is switching to), the switch main PHY back timer is running and channel
// access is not expected to be gained by the main PHY before the switch main PHY back timer
// expires (plus a channel switch delay), try to switch the main PHY back to the preferred link
const auto mainPhyInvolved =
(phy->GetPhyId() == GetMainPhyId()) ||
(m_mainPhySwitchInfo.end >= Simulator::Now() && m_mainPhySwitchInfo.to == *linkId);
if (m_switchMainPhyBackEvent.IsPending() && mainPhyInvolved &&
!GetExpectedAccessWithinDelay(*linkId,
Simulator::GetDelayLeft(m_switchMainPhyBackEvent) +
phy->GetChannelSwitchDelay()))
@@ -426,6 +429,32 @@ AdvancedEmlsrManager::CheckNavAndCcaLastPifs(Ptr<WifiPhy> phy, uint8_t linkId, P
// check CCA on the entire channel
auto width = caManager->GetLargestIdlePrimaryChannel(pifs, Simulator::Now());
// lambda to perform the actions needed when a TXOP is not started
auto txopNotStarted = [=, this]() {
// check when access may be granted to determine whether to switch the main PHY back
// to the preferred link (if aux PHYs do not switch link)
if (!m_switchAuxPhy &&
!GetExpectedAccessWithinDelay(linkId,
Simulator::GetDelayLeft(m_switchMainPhyBackEvent) +
phy->GetChannelSwitchDelay()))
{
NS_LOG_DEBUG("No AC is expected to get backoff soon, switch main PHY back");
if (auto mainPhy = GetStaMac()->GetDevice()->GetPhy(GetMainPhyId());
!mainPhy->IsStateSwitching())
{
m_switchMainPhyBackEvent.Cancel();
SwitchMainPhyBackDelayExpired(linkId);
}
return;
}
// medium busy, restart channel access
edca->NotifyChannelReleased(linkId); // to set access to NOT_REQUESTED
edca->StartAccessAfterEvent(linkId,
Txop::DIDNT_HAVE_FRAMES_TO_TRANSMIT,
Txop::CHECK_MEDIUM_BUSY);
};
if (!isBusy && width > MHz_u{0})
{
// medium idle, start TXOP
@@ -435,55 +464,20 @@ AdvancedEmlsrManager::CheckNavAndCcaLastPifs(Ptr<WifiPhy> phy, uint8_t linkId, P
// main PHY is connected to this link in order to use the CCA information of the aux PHY.
// Schedule now the TXOP start so that we first connect the main PHY to this link.
m_ccaLastPifs = Simulator::ScheduleNow([=, this]() {
if (GetEhtFem(linkId)->HeFrameExchangeManager::StartTransmission(edca, width))
if (GetEhtFem(linkId)->StartTransmission(edca, width))
{
NotifyUlTxopStart(linkId);
}
else if (!m_switchAuxPhy)
else
{
// switch main PHY back to preferred link if SwitchAuxPhy is false
SwitchMainPhyBackToPreferredLink(linkId, EmlsrSwitchMainPhyBackTrace(true));
txopNotStarted();
}
});
}
else
{
// medium busy, check when access may be granted to determine whether to switch the
// main PHY back to the preferred link (if aux PHYs do not switch link)
if (!m_switchAuxPhy &&
!GetExpectedAccessWithinDelay(linkId,
m_switchMainPhyBackDelay + phy->GetChannelSwitchDelay()))
{
NS_LOG_DEBUG("No AC is expected to get backoff soon, switch main PHY back");
if (auto mainPhy = GetStaMac()->GetDevice()->GetPhy(GetMainPhyId());
!mainPhy->IsStateSwitching())
{
SwitchMainPhyBackDelayExpired(linkId);
}
return;
}
// medium busy, restart channel access
NS_LOG_DEBUG("Medium busy in the last PIFS interval");
edca->NotifyChannelReleased(linkId); // to set access to NOT_REQUESTED
edca->StartAccessAfterEvent(linkId,
Txop::DIDNT_HAVE_FRAMES_TO_TRANSMIT,
Txop::CHECK_MEDIUM_BUSY);
if (m_switchAuxPhy)
{
return;
}
// the main PHY must stay for some time on this link to check if it gets channel access.
// The timer is stopped if a DL or UL TXOP is started. When the timer expires, the main PHY
// switches back to the preferred link if SwitchAuxPhy is false
m_switchMainPhyBackEvent.Cancel();
m_switchMainPhyBackEvent =
Simulator::Schedule(m_switchMainPhyBackDelay,
&AdvancedEmlsrManager::SwitchMainPhyBackDelayExpired,
this,
linkId);
txopNotStarted();
}
}
@@ -739,6 +733,16 @@ AdvancedEmlsrManager::SwitchMainPhyIfTxopGainedByAuxPhy(uint8_t linkId, AcIndex
RESET_BACKOFF,
DONT_REQUEST_ACCESS,
EmlsrUlTxopAuxPhyNotTxCapableTrace(aci, Time{0}, remNav));
// the main PHY must stay for some time on this link to check if it gets channel access.
// The timer is stopped if a DL or UL TXOP is started. When the timer expires, the main PHY
// switches back to the preferred link if SwitchAuxPhy is false
m_switchMainPhyBackEvent.Cancel();
m_switchMainPhyBackEvent =
Simulator::Schedule(mainPhy->GetChannelSwitchDelay() + m_switchMainPhyBackDelay,
&AdvancedEmlsrManager::SwitchMainPhyBackDelayExpired,
this,
linkId);
return;
}
@@ -887,10 +891,27 @@ AdvancedEmlsrManager::SwitchMainPhyIfTxopToBeGainedByAuxPhy(uint8_t linkId,
DONT_REQUEST_ACCESS,
EmlsrUlTxopAuxPhyNotTxCapableTrace(aci, delay, remNav));
// the main PHY must stay for some time on this link to check if it gets channel access. The
// timer is stopped if a DL or UL TXOP is started. When the timer expires, the main PHY switches
// back to the preferred link if SwitchAuxPhy is false
m_switchMainPhyBackEvent.Cancel();
m_switchMainPhyBackEvent =
Simulator::Schedule(switchDelay + m_switchMainPhyBackDelay,
&AdvancedEmlsrManager::SwitchMainPhyBackDelayExpired,
this,
linkId);
// check expected channel access delay when switch is completed
Simulator::Schedule(switchDelay, [=, this]() {
const auto accessDelay = cam->GetBackoffEndFor(edca) - Simulator::Now();
if (!m_switchAuxPhy && !m_switchMainPhyBackEvent.IsPending())
{
// if SwitchAuxPhy is false and the switch main PHY back timer is not running, it means
// that the channel switch was interrupted, hence there is nothing to check
return;
}
if (auxPhyCcaCanBeUsed && backoffEndBeforeSwitch && accessDelay.IsNegative())
{
// backoff already counted down to zero and we used aux PHY CCA
@@ -912,30 +933,14 @@ AdvancedEmlsrManager::SwitchMainPhyIfTxopToBeGainedByAuxPhy(uint8_t linkId,
linkId,
edca);
}
else if (m_switchAuxPhy)
{
return;
}
else if (!GetExpectedAccessWithinDelay(linkId,
accessDelay + m_switchMainPhyBackDelay +
else if (!m_switchAuxPhy &&
!GetExpectedAccessWithinDelay(linkId,
Simulator::GetDelayLeft(m_switchMainPhyBackEvent) +
mainPhy->GetChannelSwitchDelay()))
{
NS_LOG_DEBUG("No AC is expected to get backoff soon, switch main PHY back");
SwitchMainPhyBackDelayExpired(linkId);
}
else
{
// the main PHY must stay for some time on this link to check if it gets channel
// access. The timer is stopped if a DL or UL TXOP is started. When the timer
// expires, the main PHY switches back to the preferred link if SwitchAuxPhy is
// false
m_switchMainPhyBackEvent.Cancel();
m_switchMainPhyBackEvent =
Simulator::Schedule(accessDelay + m_switchMainPhyBackDelay,
&AdvancedEmlsrManager::SwitchMainPhyBackDelayExpired,
this,
linkId);
}
});
}