13#include "ns3/boolean.h"
14#include "ns3/channel-access-manager.h"
16#include "ns3/qos-txop.h"
17#include "ns3/wifi-mpdu.h"
18#include "ns3/wifi-net-device.h"
19#include "ns3/wifi-phy.h"
32 TypeId(
"ns3::DefaultEmlsrManager")
36 .AddAttribute(
"SwitchAuxPhy",
37 "Whether Aux PHY should switch channel to operate on the link on which "
38 "the Main PHY was operating before moving to the link of the Aux PHY. "
39 "Note that, if the Aux PHY does not switch channel, the main PHY will "
40 "switch back to its previous link once the TXOP terminates (otherwise, "
41 "no PHY will be listening on that EMLSR link).",
45 .AddAttribute(
"PutAuxPhyToSleep",
46 "Whether Aux PHY should be put into sleep mode while the Main PHY "
47 "is operating on the same link as the Aux PHY (this only matters "
48 "when the Aux PHY does not switch channel).",
56 : m_mainPhySwitchInfo{}
77 NS_ASSERT_MSG(linkId,
"Link on which the main PHY is operating not found");
86 NS_ASSERT_MSG(linkId,
"Link on which the main PHY is operating not found");
101 NS_LOG_FUNCTION(
this << (currLinkId ? std::to_string(*currLinkId) :
"") << nextLinkId
108 "No current link ID provided nor valid main PHY switch information stored");
126 auto auxPhy =
GetStaMac()->GetWifiPhy(nextLinkId);
128 NS_LOG_DEBUG(
"Aux PHY (" << auxPhy <<
") operating on link " << +nextLinkId
129 <<
" will switch to link " << +currLinkId.value() <<
" in "
134 SwitchAuxPhy(auxPhy, nextLinkId, prevLinkId);
139 if (currLinkId.has_value() && currLinkId !=
GetMainPhyId())
144 "There should be an aux PHY to reconnect when the main PHY leaves a non-primary link");
178 return {
true,
Time{0}};
226 if (!mainPhy->IsStateSwitching())
236 if (!GetEhtFem(linkId)->UsingOtherEmlsrLink())
238 SwitchMainPhy(GetMainPhyId(), false, DONT_RESET_BACKOFF, REQUEST_ACCESS);
245DefaultEmlsrManager::SwitchMainPhyIfTxopGainedByAuxPhy(uint8_t linkId,
AcIndex aci)
252DefaultEmlsrManager::GetTimeToCtsEnd(uint8_t linkId)
const
256 auto phy = GetStaMac()->GetWifiPhy(linkId);
260 const auto stationManager = GetStaMac()->GetWifiRemoteStationManager(linkId);
261 const auto bssid = GetEhtFem(linkId)->GetBssid();
262 const auto allowedWidth = GetEhtFem(linkId)->GetAllowedWidth();
264 const auto rtsTxVector = stationManager->GetRtsTxVector(bssid, allowedWidth);
265 const auto rtsTxTime = phy->CalculateTxDuration(
GetRtsSize(), rtsTxVector, phy->GetPhyBand());
266 const auto ctsTxVector = stationManager->GetCtsTxVector(bssid, rtsTxVector.GetMode());
267 const auto ctsTxTime = phy->CalculateTxDuration(
GetCtsSize(), ctsTxVector, phy->GetPhyBand());
271 return rtsTxTime + phy->GetSifs() + ctsTxTime +
MicroSeconds(2 * MAX_PROPAGATION_DELAY_USEC);
275DefaultEmlsrManager::GetDelayUnlessMainPhyTakesOverUlTxop(uint8_t linkId)
279 auto mainPhy = GetStaMac()->GetDevice()->GetPhy(m_mainPhyId);
280 auto timeToCtsEnd = GetTimeToCtsEnd(linkId);
281 auto switchingTime = mainPhy->GetChannelSwitchDelay();
283 switch (mainPhy->GetState()->GetState())
285 case WifiPhyState::SWITCHING:
288 switchingTime += mainPhy->GetDelayUntilIdle();
290 case WifiPhyState::RX:
291 case WifiPhyState::IDLE:
292 case WifiPhyState::CCA_BUSY:
293 if (switchingTime > timeToCtsEnd)
296 NS_LOG_DEBUG(
"Not enough time for main PHY to switch link (main PHY state: "
297 << mainPhy->GetState()->GetState() <<
")");
299 return {
false, timeToCtsEnd};
303 NS_ABORT_MSG(
"Main PHY cannot be in state " << mainPhy->GetState()->GetState());
308 const auto delay = timeToCtsEnd - mainPhy->GetChannelSwitchDelay();
311 NS_LOG_DEBUG(
"Schedule main Phy switch in " << delay.As(Time::US));
312 m_ulMainPhySwitch[linkId] = Simulator::Schedule(delay,
313 &DefaultEmlsrManager::SwitchMainPhy,
318 DONT_REQUEST_ACCESS);
320 return {
true,
Time{0}};
DefaultEmlsrManager is the default EMLSR manager.
void DoNotifyMgtFrameReceived(Ptr< const WifiMpdu > mpdu, uint8_t linkId) override
Notify the subclass of the reception of a management frame addressed to us.
bool m_auxPhyToSleep
whether Aux PHY should be put into sleep mode while the Main PHY is operating on the same link as the...
void NotifyEmlsrModeChanged() override
Notify subclass that EMLSR mode changed.
EventId m_auxPhySwitchEvent
event scheduled for an aux PHY to switch link
Ptr< WifiPhy > m_auxPhyToReconnect
Aux PHY the ChannelAccessManager of the link on which the main PHY is operating has to connect a list...
void DoNotifyUlTxopStart(uint8_t linkId) override
Notify the subclass of the start of an UL TXOP on the given link.
bool m_switchAuxPhy
whether Aux PHY should switch channel to operate on the link on which the Main PHY was operating befo...
std::pair< bool, Time > DoGetDelayUntilAccessRequest(uint8_t linkId) override
Subclasses have to provide an implementation for this method, that is called by the base class when t...
static TypeId GetTypeId()
Get the type ID.
void DoNotifyIcfReceived(uint8_t linkId) override
Notify the subclass of the reception of an initial Control frame on the given link.
std::optional< uint8_t > ResendNotification(Ptr< const WifiMpdu > mpdu) override
A previous EML Operating Mode Notification frame was dropped.
void SwitchMainPhyBackToPrimaryLink(uint8_t linkId)
This method can only be called when aux PHYs do not switch link.
EventId m_auxPhyToSleepEvent
the event scheduled to put an Aux PHY into sleep mode
void DoNotifyTxopEnd(uint8_t linkId) override
Notify the subclass of the end of a TXOP on the given link.
void NotifyMainPhySwitch(std::optional< uint8_t > currLinkId, uint8_t nextLinkId, Time duration) override
Notify subclass that the main PHY is switching channel to operate on another link.
~DefaultEmlsrManager() override
MainPhySwitchInfo m_mainPhySwitchInfo
main PHY switch info
uint8_t GetLinkToSendEmlOmn() override
EmlsrManager is an abstract base class defining the API that EHT non-AP MLDs with EMLSR activated can...
void SwitchMainPhy(uint8_t linkId, bool noSwitchDelay, bool resetBackoff, bool requestAccess)
Switch channel on the Main PHY so that it operates on the given link.
uint8_t m_mainPhyId
ID of main PHY (position in the vector of PHYs held by WifiNetDevice)
void SetCcaEdThresholdOnLinkSwitch(Ptr< WifiPhy > phy, uint8_t linkId)
Set the CCA ED threshold (if needed) on the given PHY that is switching channel to operate on the giv...
static constexpr bool REQUEST_ACCESS
request channel access when PHY switch ends
Ptr< StaWifiMac > GetStaMac() const
uint8_t GetMainPhyId() const
static constexpr bool DONT_RESET_BACKOFF
do not reset backoff on main PHY switch
void Cancel()
This method is syntactic sugar for the ns3::Simulator::Cancel method.
Smart pointer class similar to boost::intrusive_ptr.
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
static Time Now()
Return the current simulation virtual time.
Simulation virtual time values and global simulation resolution.
TimeWithUnit As(const Unit unit=Time::AUTO) const
Attach a unit to a Time, to facilitate output in a specific unit.
a unique identifier for an interface.
TypeId SetParent(TypeId tid)
Set the parent TypeId.
void ResumeFromSleep()
Resume from sleep mode.
void SetSleepMode()
Put in sleep mode.
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
#define NS_ABORT_MSG(msg)
Unconditional abnormal program termination with a message.
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
#define NS_LOG_FUNCTION_NOARGS()
Output the name of the function.
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Time MicroSeconds(uint64_t value)
Construct a Time in the indicated unit.
Time Seconds(double value)
Construct a Time in the indicated unit.
AcIndex
This enumeration defines the Access Categories as an enumeration with values corresponding to the AC ...
Every class exported by the ns3 library is enclosed in the ns3 namespace.
Ptr< const AttributeChecker > MakeBooleanChecker()
uint32_t GetRtsSize()
Return the total RTS size (including FCS trailer).
Ptr< const AttributeAccessor > MakeBooleanAccessor(T1 a1)
uint32_t GetCtsSize()
Return the total CTS size (including FCS trailer).
Time end
end of channel switching
uint8_t from
ID of the link which the main PHY is/has been leaving.