wifi: Interrupt switch main PHY back timer if medium gets busy for too long

This commit is contained in:
Stefano Avallone
2024-09-28 19:12:51 +02:00
parent a07cb9a05e
commit 60b4feb74d
2 changed files with 134 additions and 0 deletions

View File

@@ -13,6 +13,7 @@
#include "ns3/boolean.h"
#include "ns3/log.h"
#include "ns3/wifi-net-device.h"
#include "ns3/wifi-phy-listener.h"
#include "ns3/wifi-phy.h"
#include <algorithm>
@@ -24,6 +25,85 @@ NS_LOG_COMPONENT_DEFINE("AdvancedEmlsrManager");
NS_OBJECT_ENSURE_REGISTERED(AdvancedEmlsrManager);
/**
* PHY listener connected to the main PHY while operating on the link of an aux PHY that is
* not TX capable.
*
* PHY notifications are forwarded to this EMLSR manager one timestep later because this EMLSR
* manager may then decide to switch the main PHY back to the preferred link. Given that notifying
* a PHY listener is only one of the actions that are performed when handling events such as RX end
* or CCA busy start, it is not a good idea to request a main PHY switch while performing other
* actions. Forwarding notifications a timestep later allows to first complete the handling of the
* given event and then (possibly) starting a main PHY switch.
*/
class EmlsrPhyListener : public WifiPhyListener
{
public:
/**
* Constructor
*
* @param emlsrManager the EMLSR manager
*/
EmlsrPhyListener(Ptr<AdvancedEmlsrManager> emlsrManager)
: m_emlsrManager(emlsrManager)
{
}
void NotifyRxStart(Time /* duration */) override
{
Simulator::Schedule(TimeStep(1),
&AdvancedEmlsrManager::InterruptSwitchMainPhyBackTimerIfNeeded,
m_emlsrManager);
}
void NotifyRxEndOk() override
{
Simulator::Schedule(TimeStep(1),
&AdvancedEmlsrManager::InterruptSwitchMainPhyBackTimerIfNeeded,
m_emlsrManager);
}
void NotifyRxEndError() override
{
}
void NotifyTxStart(Time /* duration */, dBm_u /* txPower */) override
{
}
void NotifyCcaBusyStart(Time /* duration */,
WifiChannelListType /* channelType */,
const std::vector<Time>& /* per20MhzDurations */) override
{
Simulator::Schedule(TimeStep(1),
&AdvancedEmlsrManager::InterruptSwitchMainPhyBackTimerIfNeeded,
m_emlsrManager);
}
void NotifySwitchingStart(Time /* duration */) override
{
}
void NotifySleep() override
{
}
void NotifyOff() override
{
}
void NotifyWakeup() override
{
}
void NotifyOn() override
{
}
private:
Ptr<AdvancedEmlsrManager> m_emlsrManager; //!< the EMLSR manager
};
TypeId
AdvancedEmlsrManager::GetTypeId()
{
@@ -74,6 +154,7 @@ AdvancedEmlsrManager::GetTypeId()
AdvancedEmlsrManager::AdvancedEmlsrManager()
{
NS_LOG_FUNCTION(this);
m_phyListener = std::make_shared<EmlsrPhyListener>(this);
}
AdvancedEmlsrManager::~AdvancedEmlsrManager()
@@ -91,6 +172,11 @@ AdvancedEmlsrManager::DoDispose()
"PhyRxMacHeaderEnd",
MakeCallback(&AdvancedEmlsrManager::ReceivedMacHdr, this).Bind(phy));
}
if (!GetAuxPhyTxCapable())
{
GetStaMac()->GetDevice()->GetPhy(GetMainPhyId())->UnregisterListener(m_phyListener);
}
m_phyListener.reset();
DefaultEmlsrManager::DoDispose();
}
@@ -131,6 +217,10 @@ AdvancedEmlsrManager::DoSetWifiMac(Ptr<StaWifiMac> mac)
"PhyRxMacHeaderEnd",
MakeCallback(&AdvancedEmlsrManager::ReceivedMacHdr, this).Bind(phy));
}
if (!GetAuxPhyTxCapable())
{
mac->GetDevice()->GetPhy(GetMainPhyId())->RegisterListener(m_phyListener);
}
}
std::pair<bool, Time>
@@ -526,6 +616,35 @@ AdvancedEmlsrManager::SwitchMainPhyBackDelayExpired(uint8_t linkId)
SwitchMainPhyBackToPreferredLink(linkId, EmlsrSwitchMainPhyBackTrace(false));
}
void
AdvancedEmlsrManager::InterruptSwitchMainPhyBackTimerIfNeeded()
{
NS_LOG_FUNCTION(this);
if (!m_switchMainPhyBackEvent.IsPending())
{
return; // nothing to do
}
// a busy event occurred, check if the main PHY has to switch back to the preferred link
auto mainPhy = GetStaMac()->GetDevice()->GetPhy(GetMainPhyId());
auto linkId = GetStaMac()->GetLinkForPhy(GetMainPhyId());
if (!linkId.has_value())
{
NS_LOG_DEBUG("Main PHY is not operating on any link");
return;
}
const auto delay =
Simulator::GetDelayLeft(m_switchMainPhyBackEvent) + mainPhy->GetChannelSwitchDelay();
if (!GetExpectedAccessWithinDelay(*linkId, delay))
{
m_switchMainPhyBackEvent.Cancel();
SwitchMainPhyBackDelayExpired(*linkId);
}
}
void
AdvancedEmlsrManager::DoNotifyIcfReceived(uint8_t linkId)
{

View File

@@ -11,9 +11,13 @@
#include "default-emlsr-manager.h"
#include <memory>
namespace ns3
{
class WifiPhyListener;
/**
* @ingroup wifi
*
@@ -31,6 +35,14 @@ class AdvancedEmlsrManager : public DefaultEmlsrManager
AdvancedEmlsrManager();
~AdvancedEmlsrManager() override;
/**
* This method is called by the PHY listener attached to the main PHY when a switch main PHY
* back timer is started to notify of events that may delay the channel access for the main
* PHY on the current link. If the expected channel access is beyond the end of the switch
* main PHY timer expiration plus a channel switch delay, the timer is stopped immediately.
*/
void InterruptSwitchMainPhyBackTimerIfNeeded();
protected:
void DoDispose() override;
void DoSetWifiMac(Ptr<StaWifiMac> mac) override;
@@ -124,6 +136,9 @@ class AdvancedEmlsrManager : public DefaultEmlsrManager
EventId m_switchMainPhyBackEvent; //!< event scheduled in case of non-TX capable aux PHY when
//!< medium is sensed busy during the PIFS interval
//!< preceding/following the main PHY switch end
std::shared_ptr<WifiPhyListener>
m_phyListener; //!< PHY listener connected to the main PHY while operating on the link of
//!< an aux PHY that is not TX capable
};
/**