wifi: Allow ChannelAccessManager to hold multiple PHY listeners
At any time, only one PHY listener is active
This commit is contained in:
committed by
Stefano Avallone
parent
de6586ecc0
commit
0f04ea7caf
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user