wifi: EMLSR Manager handles MediumSyncDelay timers

This commit is contained in:
Stefano Avallone
2023-06-16 12:48:08 +02:00
committed by Stefano Avallone
parent 2a2287737c
commit cf3c8182f2
3 changed files with 193 additions and 0 deletions

View File

@@ -23,6 +23,7 @@
#include "ns3/channel-access-manager.h"
#include "ns3/log.h"
#include "ns3/wifi-mpdu.h"
#include "ns3/wifi-net-device.h"
#include "ns3/wifi-phy.h"
namespace ns3
@@ -133,6 +134,7 @@ DefaultEmlsrManager::DoNotifyTxopEnd(uint8_t linkId)
SwitchMainPhy(*m_linkIdForMainPhyAfterTxop, false);
// Reconnect the aux PHY to its original link
Simulator::ScheduleNow(&StaWifiMac::NotifySwitchingEmlsrLink, GetStaMac(), phy, linkId);
SetCcaEdThresholdOnLinkSwitch(phy, linkId);
}
m_linkIdForMainPhyAfterTxop.reset();
}

View File

@@ -137,6 +137,10 @@ EmlsrManager::DoDispose()
MakeCallback(&EmlsrManager::TxDropped, this));
m_staMac = nullptr;
m_transitionTimeoutEvent.Cancel();
for (auto& [id, status] : m_mediumSyncDelayStatus)
{
status.timer.Cancel();
}
Object::DoDispose();
}
@@ -201,6 +205,17 @@ EmlsrManager::GetEhtFem(uint8_t linkId) const
return StaticCast<EhtFrameExchangeManager>(m_staMac->GetFrameExchangeManager(linkId));
}
std::optional<Time>
EmlsrManager::GetElapsedMediumSyncDelayTimer(uint8_t linkId) const
{
if (const auto statusIt = m_mediumSyncDelayStatus.find(linkId);
statusIt != m_mediumSyncDelayStatus.cend() && statusIt->second.timer.IsRunning())
{
return m_mediumSyncDuration - Simulator::GetDelayLeft(statusIt->second.timer);
}
return std::nullopt;
}
void
EmlsrManager::SetTransitionTimeout(Time timeout)
{
@@ -408,9 +423,40 @@ EmlsrManager::NotifyTxopEnd(uint8_t linkId)
}
}
StartMediumSyncDelayTimer(linkId);
DoNotifyTxopEnd(linkId);
}
void
EmlsrManager::SetCcaEdThresholdOnLinkSwitch(Ptr<WifiPhy> phy, uint8_t linkId)
{
NS_LOG_FUNCTION(this << phy << linkId);
// if a MediumSyncDelay timer is running for the link on which the main PHY is going to
// operate, set the CCA ED threshold to the MediumSyncDelay OFDM ED threshold
if (auto statusIt = m_mediumSyncDelayStatus.find(linkId);
statusIt != m_mediumSyncDelayStatus.cend() && statusIt->second.timer.IsRunning())
{
NS_LOG_DEBUG("Setting CCA ED threshold of PHY " << phy << " to " << +m_msdOfdmEdThreshold
<< " on link " << +linkId);
// store the current CCA ED threshold in the m_prevCcaEdThreshold map, if not present
m_prevCcaEdThreshold.try_emplace(phy, phy->GetCcaEdThreshold());
phy->SetCcaEdThreshold(m_msdOfdmEdThreshold);
}
// otherwise, restore the previous value for the CCA ED threshold (if any)
else if (auto threshIt = m_prevCcaEdThreshold.find(phy);
threshIt != m_prevCcaEdThreshold.cend())
{
NS_LOG_DEBUG("Resetting CCA ED threshold of PHY " << phy << " to " << threshIt->second
<< " on link " << +linkId);
phy->SetCcaEdThreshold(threshIt->second);
m_prevCcaEdThreshold.erase(threshIt);
}
}
void
EmlsrManager::SwitchMainPhy(uint8_t linkId, bool noSwitchDelay)
{
@@ -462,6 +508,7 @@ EmlsrManager::SwitchMainPhy(uint8_t linkId, bool noSwitchDelay)
}
});
SetCcaEdThresholdOnLinkSwitch(mainPhy, linkId);
NotifyMainPhySwitch(*currMainPhyLinkId, linkId);
}
@@ -489,6 +536,89 @@ EmlsrManager::SwitchAuxPhy(uint8_t currLinkId, uint8_t nextLinkId)
auxPhy->SetSlot(MicroSeconds(9));
}
});
SetCcaEdThresholdOnLinkSwitch(auxPhy, nextLinkId);
}
void
EmlsrManager::StartMediumSyncDelayTimer(uint8_t linkId)
{
NS_LOG_FUNCTION(this << linkId);
// iterate over all the other EMLSR links
for (auto id : m_staMac->GetLinkIds())
{
if (id != linkId && m_staMac->IsEmlsrLink(id))
{
const auto [it, inserted] = m_mediumSyncDelayStatus.try_emplace(id);
// reset the max number of TXOP attempts
it->second.msdNTxopsLeft = m_msdMaxNTxops;
if (!it->second.timer.IsRunning())
{
// set the MSD OFDM ED threshold
auto phy = m_staMac->GetWifiPhy(id);
NS_ASSERT_MSG(phy,
"Expected a PHY to be operating on link "
<< +id << " after terminating a TXOP");
NS_LOG_DEBUG("Setting CCA ED threshold on link "
<< +id << " to " << +m_msdOfdmEdThreshold << " PHY " << phy);
m_prevCcaEdThreshold[phy] = phy->GetCcaEdThreshold();
phy->SetCcaEdThreshold(m_msdOfdmEdThreshold);
}
// (re)start the timer
it->second.timer.Cancel();
it->second.timer = Simulator::Schedule(m_mediumSyncDuration,
&EmlsrManager::MediumSyncDelayTimerExpired,
this,
id);
}
}
}
void
EmlsrManager::CancelMediumSyncDelayTimer(uint8_t linkId)
{
NS_LOG_FUNCTION(this << linkId);
auto timerIt = m_mediumSyncDelayStatus.find(linkId);
NS_ASSERT(timerIt != m_mediumSyncDelayStatus.cend() && timerIt->second.timer.IsRunning());
timerIt->second.timer.Cancel();
MediumSyncDelayTimerExpired(linkId);
}
void
EmlsrManager::MediumSyncDelayTimerExpired(uint8_t linkId)
{
NS_LOG_FUNCTION(this << linkId);
auto timerIt = m_mediumSyncDelayStatus.find(linkId);
NS_ASSERT(timerIt != m_mediumSyncDelayStatus.cend() && !timerIt->second.timer.IsRunning());
// reset the MSD OFDM ED threshold
auto phy = m_staMac->GetWifiPhy(linkId);
if (!phy)
{
// no PHY is operating on this link. This may happen when a MediumSyncDelay timer expires
// on the link left "uncovered" by the main PHY that is operating on another link (and the
// aux PHY of that link did not switch). In this case, do nothing, since the CCA ED
// threshold on the main PHY will be restored once the main PHY switches back to its link
return;
}
auto threshIt = m_prevCcaEdThreshold.find(phy);
NS_ASSERT_MSG(threshIt != m_prevCcaEdThreshold.cend(),
"No value to restore for CCA ED threshold on PHY " << phy);
NS_LOG_DEBUG("Resetting CCA ED threshold of PHY " << phy << " to " << threshIt->second
<< " on link " << +linkId);
phy->SetCcaEdThreshold(threshIt->second);
m_prevCcaEdThreshold.erase(threshIt);
}
MgtEmlOmn

View File

@@ -176,6 +176,25 @@ class EmlsrManager : public Object
*/
void NotifyTxopEnd(uint8_t linkId);
/**
* Check whether the MediumSyncDelay timer is running for the STA operating on the given link.
* If so, returns the time elapsed since the timer started.
*
* \param linkId the ID of the given link
* \return the time elapsed since the MediumSyncDelay timer started, if this timer is running
* for the STA operating on the given link
*/
std::optional<Time> GetElapsedMediumSyncDelayTimer(uint8_t linkId) const;
/**
* Cancel the MediumSyncDelay timer associated with the given link and take the appropriate
* actions. This function must not be called when the MediumSyncDelay timer is not running
* on the given link.
*
* \param linkId the ID of the link associated with the MediumSyncDelay timer to cancel
*/
void CancelMediumSyncDelayTimer(uint8_t linkId);
protected:
void DoDispose() override;
@@ -235,6 +254,15 @@ class EmlsrManager : public Object
*/
void SwitchAuxPhy(uint8_t currLinkId, uint8_t nextLinkId);
/**
* Set the CCA ED threshold (if needed) on the given PHY that is switching channel to
* operate on the given link.
*
* \param phy the given PHY
* \param linkId the ID of the given link
*/
void SetCcaEdThresholdOnLinkSwitch(Ptr<WifiPhy> phy, uint8_t linkId);
/**
* \return the EML Operating Mode Notification to send
*/
@@ -268,6 +296,22 @@ class EmlsrManager : public Object
*/
void SendEmlOmn();
/**
* Start the MediumSyncDelay timer and take the appropriate actions, if the timer is not
* already running.
*
* \param linkId the ID of the link on which a TXOP was carried out that caused the STAs
* operating on other links to lose medium synchronization
*/
void StartMediumSyncDelayTimer(uint8_t linkId);
/**
* Take the appropriate actions when the MediumSyncDelay timer expires or is cancelled.
*
* \param linkId the ID of the link associated with the MediumSyncDelay timer to cancel
*/
void MediumSyncDelayTimerExpired(uint8_t linkId);
/**
* Notify the subclass of the reception of a management frame addressed to us.
*
@@ -337,6 +381,16 @@ class EmlsrManager : public Object
*/
virtual void NotifyMainPhySwitch(uint8_t currLinkId, uint8_t nextLinkId) = 0;
/**
* Information about the status of the MediumSyncDelay timer associated with a link.
*/
struct MediumSyncDelayStatus
{
EventId timer; //!< the MediumSyncDelay timer
std::optional<uint8_t> msdNTxopsLeft; //!< number of TXOP attempts left while the
//!< MediumSyncDelay timer is running
};
Ptr<StaWifiMac> m_staMac; //!< the MAC of the managed non-AP MLD
std::optional<Time> m_emlsrTransitionTimeout; /**< Transition timeout advertised by APs with
EMLSR activated */
@@ -344,6 +398,13 @@ class EmlsrManager : public Object
int8_t m_msdOfdmEdThreshold; //!< MediumSyncDelay OFDM ED threshold
std::optional<uint8_t> m_msdMaxNTxops; //!< MediumSyncDelay max number of TXOPs
std::map<uint8_t, MediumSyncDelayStatus>
m_mediumSyncDelayStatus; //!< the status of MediumSyncDelay timers (link ID-indexed)
std::map<Ptr<WifiPhy>, double> m_prevCcaEdThreshold; //!< the CCA sensitivity threshold (dBm)
//!< to restore once the MediumSyncDelay
//!< timer expires or the PHY moves to a
//!< link on which the timer is not running
std::set<uint8_t> m_emlsrLinks; //!< ID of the EMLSR links (empty if EMLSR mode is disabled)
std::optional<std::set<uint8_t>> m_nextEmlsrLinks; /**< ID of the links that will become the
EMLSR links when the pending