wifi: Allow ChannelAccessManager to hold multiple PHY listeners

At any time, only one PHY listener is active
This commit is contained in:
Stefano Avallone
2023-04-03 12:29:35 +02:00
committed by Stefano Avallone
parent de6586ecc0
commit 0f04ea7caf
2 changed files with 148 additions and 32 deletions

View File

@@ -36,7 +36,11 @@ namespace ns3
NS_LOG_COMPONENT_DEFINE("ChannelAccessManager");
/**
* Listener for PHY events. Forwards to ChannelAccessManager
* Listener for PHY events. Forwards to ChannelAccessManager.
* The ChannelAccessManager may handle multiple PHY listeners connected to distinct PHYs,
* but only one listener at a time can be active. Notifications from inactive listeners are
* ignored by the ChannelAccessManager, except for the channel switch notification.
* Inactive PHY listeners are typically configured by 11be EMLSR clients.
*/
class PhyListener : public ns3::WifiPhyListener
{
@@ -47,7 +51,8 @@ class PhyListener : public ns3::WifiPhyListener
* \param cam the ChannelAccessManager
*/
PhyListener(ns3::ChannelAccessManager* cam)
: m_cam(cam)
: m_cam(cam),
m_active(true)
{
}
@@ -55,31 +60,64 @@ class PhyListener : public ns3::WifiPhyListener
{
}
/**
* Set this listener to be active or not.
*
* \param active whether this listener is active or not
*/
void SetActive(bool active)
{
m_active = active;
}
/**
* \return whether this listener is active or not
*/
bool IsActive() const
{
return m_active;
}
void NotifyRxStart(Time duration) override
{
m_cam->NotifyRxStartNow(duration);
if (m_active)
{
m_cam->NotifyRxStartNow(duration);
}
}
void NotifyRxEndOk() override
{
m_cam->NotifyRxEndOkNow();
if (m_active)
{
m_cam->NotifyRxEndOkNow();
}
}
void NotifyRxEndError() override
{
m_cam->NotifyRxEndErrorNow();
if (m_active)
{
m_cam->NotifyRxEndErrorNow();
}
}
void NotifyTxStart(Time duration, double txPowerDbm) override
{
m_cam->NotifyTxStartNow(duration);
if (m_active)
{
m_cam->NotifyTxStartNow(duration);
}
}
void NotifyCcaBusyStart(Time duration,
WifiChannelListType channelType,
const std::vector<Time>& per20MhzDurations) override
{
m_cam->NotifyCcaBusyStartNow(duration, channelType, per20MhzDurations);
if (m_active)
{
m_cam->NotifyCcaBusyStartNow(duration, channelType, per20MhzDurations);
}
}
void NotifySwitchingStart(Time duration) override
@@ -89,26 +127,39 @@ class PhyListener : public ns3::WifiPhyListener
void NotifySleep() override
{
m_cam->NotifySleepNow();
if (m_active)
{
m_cam->NotifySleepNow();
}
}
void NotifyOff() override
{
m_cam->NotifyOffNow();
if (m_active)
{
m_cam->NotifyOffNow();
}
}
void NotifyWakeup() override
{
m_cam->NotifyWakeupNow();
if (m_active)
{
m_cam->NotifyWakeupNow();
}
}
void NotifyOn() override
{
m_cam->NotifyOnNow();
if (m_active)
{
m_cam->NotifyOnNow();
}
}
private:
ns3::ChannelAccessManager* m_cam; //!< ChannelAccessManager to forward events to
bool m_active; //!< whether this PHY listener is active
};
/****************************************************************
@@ -125,7 +176,6 @@ ChannelAccessManager::ChannelAccessManager()
m_lastSwitchingEnd(MicroSeconds(0)),
m_sleeping(false),
m_off(false),
m_phyListener(nullptr),
m_linkId(0)
{
NS_LOG_FUNCTION(this);
@@ -135,8 +185,6 @@ ChannelAccessManager::ChannelAccessManager()
ChannelAccessManager::~ChannelAccessManager()
{
NS_LOG_FUNCTION(this);
delete m_phyListener;
m_phyListener = nullptr;
}
void
@@ -157,16 +205,45 @@ ChannelAccessManager::DoDispose()
}
m_phy = nullptr;
m_feManager = nullptr;
m_phyListeners.clear();
}
PhyListener*
ChannelAccessManager::GetPhyListener(Ptr<WifiPhy> phy) const
{
if (auto listenerIt = m_phyListeners.find(phy); listenerIt != m_phyListeners.end())
{
return listenerIt->second.get();
}
return nullptr;
}
void
ChannelAccessManager::SetupPhyListener(Ptr<WifiPhy> phy)
{
NS_LOG_FUNCTION(this << phy);
NS_ASSERT(m_phyListener == nullptr);
m_phyListener = new PhyListener(this);
phy->RegisterListener(m_phyListener);
m_phy = phy;
auto phyListener = GetPhyListener(phy);
if (phyListener)
{
// a PHY listener for the given PHY already exists, it must be inactive
NS_ASSERT_MSG(!phyListener->IsActive(),
"There is already an active listener registered for given PHY");
NS_ASSERT_MSG(!m_phy, "Cannot reactivate a listener if another PHY is active");
phyListener->SetActive(true);
}
else
{
phyListener = new PhyListener(this);
m_phyListeners.emplace(phy, phyListener);
phy->RegisterListener(phyListener);
}
if (m_phy)
{
DeactivatePhyListener(m_phy);
}
m_phy = phy; // this is the new active PHY
InitLastBusyStructs();
}
@@ -174,11 +251,28 @@ void
ChannelAccessManager::RemovePhyListener(Ptr<WifiPhy> phy)
{
NS_LOG_FUNCTION(this << phy);
if (m_phyListener != nullptr)
if (auto phyListener = GetPhyListener(phy))
{
phy->UnregisterListener(phyListener);
m_phyListeners.erase(phy);
// reset m_phy if we are removing listener registered for the active PHY
if (m_phy == phy)
{
m_phy = nullptr;
}
}
}
void
ChannelAccessManager::DeactivatePhyListener(Ptr<WifiPhy> phy)
{
NS_LOG_FUNCTION(this << phy);
if (auto listener = GetPhyListener(phy))
{
listener->SetActive(false);
}
if (m_phy == phy)
{
phy->UnregisterListener(m_phyListener);
delete m_phyListener;
m_phyListener = nullptr;
m_phy = nullptr;
}
}

View File

@@ -28,6 +28,8 @@
#include <algorithm>
#include <map>
#include <memory>
#include <unordered_map>
#include <vector>
namespace ns3
@@ -60,17 +62,26 @@ class ChannelAccessManager : public Object
~ChannelAccessManager() override;
/**
* Set up listener for PHY events.
* Set up (or reactivate) listener for PHY events on the given PHY. The new (or reactivated)
* listener becomes the active listener and the previous active listener attached to another
* PHY, if any, is deactivated.
*
* \param phy the WifiPhy to listen to
*/
void SetupPhyListener(Ptr<WifiPhy> phy);
/**
* Remove current registered listener for PHY events.
* Remove current registered listener for PHY events on the given PHY.
*
* \param phy the WifiPhy to listen to
*/
void RemovePhyListener(Ptr<WifiPhy> phy);
/**
* Deactivate current registered listener for PHY events on the given PHY. All notifications
* but channel switch notifications coming from an inactive listener are ignored.
*
* \param phy the WifiPhy to listen to
*/
void DeactivatePhyListener(Ptr<WifiPhy> phy);
/**
* Set the ID of the link this Channel Access Manager is associated with.
*
@@ -265,6 +276,13 @@ class ChannelAccessManager : public Object
void DoDispose() override;
private:
/**
* Get current registered listener for PHY events on the given PHY.
*
* \param phy the given PHY
* \return the current registered listener for PHY events on the given PHY
*/
PhyListener* GetPhyListener(Ptr<WifiPhy> phy) const;
/**
* Initialize the structures holding busy end times per channel type (primary,
* secondary, etc.) and per 20 MHz channel.
@@ -360,14 +378,18 @@ class ChannelAccessManager : public Object
std::vector<Time> m_lastPer20MHzBusyEnd; /**< the last busy end time per 20 MHz channel
(HE stations and channel width > 20 MHz only) */
std::map<WifiChannelListType, Timespan>
m_lastIdle; //!< the last idle start and end time for each channel type
Time m_lastSwitchingEnd; //!< the last switching end time
bool m_sleeping; //!< flag whether it is in sleeping state
bool m_off; //!< flag whether it is in off state
Time m_eifsNoDifs; //!< EIFS no DIFS time
EventId m_accessTimeout; //!< the access timeout ID
PhyListener* m_phyListener; //!< the PHY listener
Ptr<WifiPhy> m_phy; //!< pointer to the PHY
m_lastIdle; //!< the last idle start and end time for each channel type
Time m_lastSwitchingEnd; //!< the last switching end time
bool m_sleeping; //!< flag whether it is in sleeping state
bool m_off; //!< flag whether it is in off state
Time m_eifsNoDifs; //!< EIFS no DIFS time
EventId m_accessTimeout; //!< the access timeout ID
/// Maps each PHY listener to the associated PHY
using PhyListenerMap = std::unordered_map<Ptr<WifiPhy>, std::unique_ptr<PhyListener>>;
PhyListenerMap m_phyListeners; //!< the PHY listeners
Ptr<WifiPhy> m_phy; //!< pointer to the unique active PHY
Ptr<FrameExchangeManager> m_feManager; //!< pointer to the Frame Exchange Manager
uint8_t m_linkId; //!< the ID of the link this object is associated with
};