wifi: Add main PHY switch trace source to EMLSR manager
Based on suggestions from Sharan Naribole
This commit is contained in:
committed by
Stefano Avallone
parent
93ff99d46c
commit
9d53b09450
@@ -43,6 +43,7 @@ The required Doxygen version for documentation generation is version 1.11.
|
||||
- (wifi) Added a new `BaEstablished` trace source to `QosTxop` to notify that a block ack agreement has been established with a given recipient for a given TID.
|
||||
- (zigbee) Added Zigbee module support.
|
||||
- (energy) Added new information and reformatted energy module documentation.
|
||||
- (wifi) Added a new `MainPhySwitch` trace source to EmlsrManager, which is fired when the main PHY switches channel to operate on another link and provides information about the reason for starting the switch.
|
||||
|
||||
### Bugs fixed
|
||||
|
||||
|
||||
@@ -722,6 +722,12 @@ ChannelAccessManager::GetBackoffEndFor(Ptr<Txop> txop, Time accessGrantStart) co
|
||||
return backoffEnd;
|
||||
}
|
||||
|
||||
Time
|
||||
ChannelAccessManager::GetNavEnd() const
|
||||
{
|
||||
return m_lastNavEnd;
|
||||
}
|
||||
|
||||
void
|
||||
ChannelAccessManager::UpdateBackoff()
|
||||
{
|
||||
|
||||
@@ -170,6 +170,11 @@ class ChannelAccessManager : public Object
|
||||
*/
|
||||
Time GetBackoffEndFor(Ptr<Txop> txop) const;
|
||||
|
||||
/**
|
||||
* @return the time until the NAV has been set
|
||||
*/
|
||||
Time GetNavEnd() const;
|
||||
|
||||
/**
|
||||
* @param qosTxop a QosTxop that needs to be disabled
|
||||
* @param duration the amount of time during which the QosTxop is disabled
|
||||
|
||||
@@ -305,17 +305,27 @@ AdvancedEmlsrManager::DoNotifyTxopEnd(uint8_t linkId)
|
||||
!m_switchAuxPhy || m_mainPhySwitchInfo.end >= Simulator::Now(),
|
||||
"Aux PHY next link ID should have a value when interrupting a main PHY switch");
|
||||
uint8_t nextLinkId = m_switchAuxPhy ? m_mainPhySwitchInfo.from : GetMainPhyId();
|
||||
SwitchMainPhy(nextLinkId, false, DONT_RESET_BACKOFF, REQUEST_ACCESS);
|
||||
const auto delay = mainPhy->IsStateSwitching() ? mainPhy->GetDelayUntilIdle() : Time{0};
|
||||
SwitchMainPhy(nextLinkId,
|
||||
false,
|
||||
DONT_RESET_BACKOFF,
|
||||
REQUEST_ACCESS,
|
||||
EmlsrTxopEndedTrace(delay));
|
||||
}
|
||||
else
|
||||
{
|
||||
// delay link switch until current channel switching is completed
|
||||
Simulator::Schedule(mainPhy->GetDelayUntilIdle(), [=, this]() {
|
||||
const auto delay = mainPhy->GetDelayUntilIdle();
|
||||
Simulator::Schedule(delay, [=, this]() {
|
||||
// request the main PHY to switch back to the preferred link only if in the meantime
|
||||
// no TXOP started on another link (which will require the main PHY to switch link)
|
||||
if (!GetEhtFem(linkId)->UsingOtherEmlsrLink())
|
||||
{
|
||||
SwitchMainPhy(GetMainPhyId(), false, DONT_RESET_BACKOFF, REQUEST_ACCESS);
|
||||
SwitchMainPhy(GetMainPhyId(),
|
||||
false,
|
||||
DONT_RESET_BACKOFF,
|
||||
REQUEST_ACCESS,
|
||||
EmlsrTxopEndedTrace(delay));
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -385,7 +395,7 @@ AdvancedEmlsrManager::CheckNavAndCcaLastPifs(Ptr<WifiPhy> phy, uint8_t linkId, P
|
||||
else if (!m_switchAuxPhy)
|
||||
{
|
||||
// switch main PHY back to preferred link if SwitchAuxPhy is false
|
||||
SwitchMainPhyBackToPreferredLink(linkId);
|
||||
SwitchMainPhyBackToPreferredLink(linkId, EmlsrSwitchMainPhyBackTrace(true));
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -405,7 +415,7 @@ AdvancedEmlsrManager::CheckNavAndCcaLastPifs(Ptr<WifiPhy> phy, uint8_t linkId, P
|
||||
m_switchMainPhyBackEvent = Simulator::Schedule(m_switchMainPhyBackDelay, [this, linkId]() {
|
||||
if (!m_switchAuxPhy)
|
||||
{
|
||||
SwitchMainPhyBackToPreferredLink(linkId);
|
||||
SwitchMainPhyBackToPreferredLink(linkId, EmlsrSwitchMainPhyBackTrace(false));
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -578,7 +588,18 @@ AdvancedEmlsrManager::SwitchMainPhyIfTxopGainedByAuxPhy(uint8_t linkId, AcIndex
|
||||
}
|
||||
|
||||
// switch main PHY
|
||||
SwitchMainPhy(linkId, false, RESET_BACKOFF, DONT_REQUEST_ACCESS);
|
||||
Time remNav{0};
|
||||
if (const auto mainPhyLinkId = GetStaMac()->GetLinkForPhy(mainPhy))
|
||||
{
|
||||
auto mainPhyNavEnd = GetStaMac()->GetChannelAccessManager(*mainPhyLinkId)->GetNavEnd();
|
||||
remNav = Max(remNav, mainPhyNavEnd - Simulator::Now());
|
||||
}
|
||||
|
||||
SwitchMainPhy(linkId,
|
||||
false,
|
||||
RESET_BACKOFF,
|
||||
DONT_REQUEST_ACCESS,
|
||||
EmlsrUlTxopAuxPhyNotTxCapableTrace(aci, Time{0}, remNav));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -678,7 +699,18 @@ AdvancedEmlsrManager::SwitchMainPhyIfTxopToBeGainedByAuxPhy(uint8_t linkId,
|
||||
}
|
||||
|
||||
// switch main PHY
|
||||
SwitchMainPhy(linkId, false, RESET_BACKOFF, DONT_REQUEST_ACCESS);
|
||||
Time remNav{0};
|
||||
if (const auto mainPhyLinkId = GetStaMac()->GetLinkForPhy(mainPhy))
|
||||
{
|
||||
auto mainPhyNavEnd = GetStaMac()->GetChannelAccessManager(*mainPhyLinkId)->GetNavEnd();
|
||||
remNav = Max(remNav, mainPhyNavEnd - Simulator::Now());
|
||||
}
|
||||
|
||||
SwitchMainPhy(linkId,
|
||||
false,
|
||||
RESET_BACKOFF,
|
||||
DONT_REQUEST_ACCESS,
|
||||
EmlsrUlTxopAuxPhyNotTxCapableTrace(aci, delay, remNav));
|
||||
|
||||
// if the remaining backoff time is shorter than PIFS when the main PHY completes the switch,
|
||||
// we need to schedule a CCA check a PIFS after the end of the main PHY switch
|
||||
@@ -710,7 +742,7 @@ AdvancedEmlsrManager::SwitchMainPhyIfTxopToBeGainedByAuxPhy(uint8_t linkId,
|
||||
Simulator::Schedule(minDelay + m_switchMainPhyBackDelay, [this, linkId]() {
|
||||
if (!m_switchAuxPhy)
|
||||
{
|
||||
SwitchMainPhyBackToPreferredLink(linkId);
|
||||
SwitchMainPhyBackToPreferredLink(linkId, EmlsrSwitchMainPhyBackTrace(false));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -116,6 +116,28 @@ class AdvancedEmlsrManager : public DefaultEmlsrManager
|
||||
//!< preceding/following the main PHY switch end
|
||||
};
|
||||
|
||||
/**
|
||||
* Struct to trace that main PHY switched to leave a link on which an aux PHY was expected to gain
|
||||
* a TXOP but the main PHY did not manage to gain a TXOP in the pre-configured amount of time.
|
||||
*/
|
||||
struct EmlsrSwitchMainPhyBackTrace : public EmlsrMainPhySwitchTraceImpl<EmlsrSwitchMainPhyBackTrace>
|
||||
{
|
||||
static constexpr std::string_view m_name = "TxopNotGainedOnAuxPhyLink"; //!< trace name
|
||||
|
||||
bool nothingToTx; //!< if true, the main PHY managed to gain a TXOP but had nothing to transmit
|
||||
|
||||
/**
|
||||
* Constructor provided because this struct is not an aggregate (it has a base struct), hence
|
||||
* we cannot use designated initializers.
|
||||
*
|
||||
* @param nothing the value for the nothingToTx field
|
||||
*/
|
||||
EmlsrSwitchMainPhyBackTrace(bool nothing)
|
||||
: nothingToTx(nothing)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
#endif /* ADVANCED_EMLSR_MANAGER_H */
|
||||
|
||||
@@ -189,14 +189,17 @@ DefaultEmlsrManager::DoNotifyTxopEnd(uint8_t linkId)
|
||||
// switch main PHY to the previous link, if needed
|
||||
if (!m_switchAuxPhy)
|
||||
{
|
||||
SwitchMainPhyBackToPreferredLink(linkId);
|
||||
const auto mainPhy = GetStaMac()->GetDevice()->GetPhy(m_mainPhyId);
|
||||
const auto delay = mainPhy->IsStateSwitching() ? mainPhy->GetDelayUntilIdle() : Time{0};
|
||||
SwitchMainPhyBackToPreferredLink(linkId, EmlsrTxopEndedTrace(delay));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
DefaultEmlsrManager::SwitchMainPhyBackToPreferredLink(uint8_t linkId)
|
||||
DefaultEmlsrManager::SwitchMainPhyBackToPreferredLink(uint8_t linkId,
|
||||
EmlsrMainPhySwitchTrace&& traceInfo)
|
||||
{
|
||||
NS_LOG_FUNCTION(this << linkId);
|
||||
NS_LOG_FUNCTION(this << linkId << traceInfo.GetName());
|
||||
|
||||
NS_ABORT_MSG_IF(m_switchAuxPhy, "This method can only be called when SwitchAuxPhy is false");
|
||||
|
||||
@@ -216,16 +219,25 @@ DefaultEmlsrManager::SwitchMainPhyBackToPreferredLink(uint8_t linkId)
|
||||
// a new backoff value must be generated.
|
||||
if (!mainPhy->IsStateSwitching())
|
||||
{
|
||||
SwitchMainPhy(GetMainPhyId(), false, DONT_RESET_BACKOFF, REQUEST_ACCESS);
|
||||
SwitchMainPhy(GetMainPhyId(),
|
||||
false,
|
||||
DONT_RESET_BACKOFF,
|
||||
REQUEST_ACCESS,
|
||||
std::forward<EmlsrMainPhySwitchTrace>(traceInfo));
|
||||
}
|
||||
else
|
||||
{
|
||||
Simulator::Schedule(mainPhy->GetDelayUntilIdle(), [=, this]() {
|
||||
// request the main PHY to switch back to the preferred link only if in the meantime
|
||||
// no TXOP started on another link (which will require the main PHY to switch link)
|
||||
Simulator::Schedule(mainPhy->GetDelayUntilIdle(), [=, info = traceInfo.Clone(), this]() {
|
||||
// request the main PHY to switch back to the preferred link only if
|
||||
// in the meantime no TXOP started on another link (which will
|
||||
// require the main PHY to switch link)
|
||||
if (!GetEhtFem(linkId)->UsingOtherEmlsrLink())
|
||||
{
|
||||
SwitchMainPhy(GetMainPhyId(), false, DONT_RESET_BACKOFF, REQUEST_ACCESS);
|
||||
SwitchMainPhy(GetMainPhyId(),
|
||||
false,
|
||||
DONT_RESET_BACKOFF,
|
||||
REQUEST_ACCESS,
|
||||
std::move(*info));
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -331,13 +343,13 @@ DefaultEmlsrManager::NotifyRtsSent(uint8_t linkId,
|
||||
"RTS is being sent, but not enough time for main PHY to switch");
|
||||
|
||||
NS_LOG_DEBUG("Schedule main Phy switch in " << delay.As(Time::US));
|
||||
m_ulMainPhySwitch[linkId] = Simulator::Schedule(delay,
|
||||
&DefaultEmlsrManager::SwitchMainPhy,
|
||||
this,
|
||||
linkId,
|
||||
false,
|
||||
RESET_BACKOFF,
|
||||
DONT_REQUEST_ACCESS);
|
||||
m_ulMainPhySwitch[linkId] = Simulator::Schedule(delay, [=, this]() {
|
||||
SwitchMainPhy(linkId,
|
||||
false,
|
||||
RESET_BACKOFF,
|
||||
DONT_REQUEST_ACCESS,
|
||||
EmlsrUlTxopRtsSentByAuxPhyTrace{});
|
||||
});
|
||||
|
||||
m_switchMainPhyOnRtsTx.erase(it);
|
||||
}
|
||||
|
||||
@@ -70,8 +70,10 @@ class DefaultEmlsrManager : public EmlsrManager
|
||||
* main PHY.
|
||||
*
|
||||
* @param linkId the ID of the link that the main PHY is leaving
|
||||
* @param traceInfo information to pass to the main PHY switch traced callback (the fromLinkId
|
||||
* and toLinkId fields are set by SwitchMainPhy)
|
||||
*/
|
||||
void SwitchMainPhyBackToPreferredLink(uint8_t linkId);
|
||||
void SwitchMainPhyBackToPreferredLink(uint8_t linkId, EmlsrMainPhySwitchTrace&& traceInfo);
|
||||
|
||||
/// Store information about a main PHY switch.
|
||||
struct MainPhySwitchInfo
|
||||
|
||||
@@ -124,7 +124,15 @@ EmlsrManager::GetTypeId()
|
||||
BooleanValue(false),
|
||||
MakeBooleanAccessor(&EmlsrManager::SetCamStateReset,
|
||||
&EmlsrManager::GetCamStateReset),
|
||||
MakeBooleanChecker());
|
||||
MakeBooleanChecker())
|
||||
.AddTraceSource("MainPhySwitch",
|
||||
"This trace source is fired when the main PHY switches channel to "
|
||||
"operate on another link. Information associated with the main PHY "
|
||||
"switch is provided through a struct that is inherited from struct "
|
||||
"EmlsrMainPhySwitchTrace (use the GetName() method to get the type "
|
||||
"of the provided object).",
|
||||
MakeTraceSourceAccessor(&EmlsrManager::m_mainPhySwitchTrace),
|
||||
"ns3::EmlsrManager::MainPhySwitchCallback");
|
||||
return tid;
|
||||
}
|
||||
|
||||
@@ -443,7 +451,8 @@ EmlsrManager::NotifyIcfReceived(uint8_t linkId)
|
||||
SwitchMainPhy(linkId,
|
||||
true, // channel switch should occur instantaneously
|
||||
RESET_BACKOFF,
|
||||
DONT_REQUEST_ACCESS);
|
||||
DONT_REQUEST_ACCESS,
|
||||
EmlsrDlTxopIcfReceivedByAuxPhyTrace{});
|
||||
|
||||
// aux PHY received the ICF but main PHY will send the response
|
||||
auto uid = auxPhy->GetPreviouslyRxPpduUid();
|
||||
@@ -668,9 +677,11 @@ void
|
||||
EmlsrManager::SwitchMainPhy(uint8_t linkId,
|
||||
bool noSwitchDelay,
|
||||
bool resetBackoff,
|
||||
bool requestAccess)
|
||||
bool requestAccess,
|
||||
EmlsrMainPhySwitchTrace&& traceInfo)
|
||||
{
|
||||
NS_LOG_FUNCTION(this << linkId << noSwitchDelay << resetBackoff << requestAccess);
|
||||
NS_LOG_FUNCTION(this << linkId << noSwitchDelay << resetBackoff << requestAccess
|
||||
<< traceInfo.GetName());
|
||||
|
||||
auto mainPhy = m_staMac->GetDevice()->GetPhy(m_mainPhyId);
|
||||
|
||||
@@ -679,6 +690,9 @@ EmlsrManager::SwitchMainPhy(uint8_t linkId,
|
||||
|
||||
// find the link on which the main PHY is operating
|
||||
auto currMainPhyLinkId = m_staMac->GetLinkForPhy(mainPhy);
|
||||
traceInfo.fromLinkId = currMainPhyLinkId;
|
||||
traceInfo.toLinkId = linkId;
|
||||
m_mainPhySwitchTrace(traceInfo);
|
||||
|
||||
NS_ASSERT_MSG(currMainPhyLinkId.has_value() || mainPhy->IsStateSwitching(),
|
||||
"If the main PHY is not operating on a link, it must be switching");
|
||||
|
||||
@@ -16,8 +16,10 @@
|
||||
#include "ns3/wifi-phy-operating-channel.h"
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <set>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
|
||||
class EmlsrCcaBusyTest;
|
||||
@@ -29,6 +31,45 @@ class EhtFrameExchangeManager;
|
||||
class MgtEmlOmn;
|
||||
class WifiMpdu;
|
||||
|
||||
/**
|
||||
* @ingroup wifi
|
||||
* Base struct for EMLSR Main PHY switch traces.
|
||||
*/
|
||||
struct EmlsrMainPhySwitchTrace
|
||||
{
|
||||
virtual ~EmlsrMainPhySwitchTrace() = default;
|
||||
|
||||
/// @return the name of this instance
|
||||
virtual std::string_view GetName() const = 0;
|
||||
|
||||
/// @return a pointer to the clone of this object
|
||||
virtual std::shared_ptr<EmlsrMainPhySwitchTrace> Clone() const = 0;
|
||||
|
||||
std::optional<uint8_t> fromLinkId; //!< ID of the link the main PHY is moving from (if any)
|
||||
uint8_t toLinkId{WIFI_LINKID_UNDEFINED}; //!< ID of the link the main PHY is moving to
|
||||
};
|
||||
|
||||
/**
|
||||
* Implementation for the EMLSR Main PHY switch trace base struct. Child structs are inherited
|
||||
* from this implementation according to the CRTP idiom and must define a static string_view
|
||||
* member containing the name of the child.
|
||||
*/
|
||||
template <class T>
|
||||
struct EmlsrMainPhySwitchTraceImpl : public EmlsrMainPhySwitchTrace
|
||||
{
|
||||
/// @copydoc ns3::EmlsrMainPhySwitchTrace::GetName
|
||||
std::string_view GetName() const override
|
||||
{
|
||||
return T::m_name;
|
||||
}
|
||||
|
||||
/// @copydoc ns3::EmlsrMainPhySwitchTrace::Clone
|
||||
std::shared_ptr<EmlsrMainPhySwitchTrace> Clone() const override
|
||||
{
|
||||
return std::shared_ptr<EmlsrMainPhySwitchTrace>(new T(static_cast<const T&>(*this)));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @ingroup wifi
|
||||
*
|
||||
@@ -351,8 +392,14 @@ class EmlsrManager : public Object
|
||||
* is operating
|
||||
* @param requestAccess whether channel access should be requested on the link on which the
|
||||
* main PHY is moving onto
|
||||
* @param traceInfo information to pass to the main PHY switch traced callback (the fromLinkId
|
||||
* and toLinkId fields are set by this function)
|
||||
*/
|
||||
void SwitchMainPhy(uint8_t linkId, bool noSwitchDelay, bool resetBackoff, bool requestAccess);
|
||||
void SwitchMainPhy(uint8_t linkId,
|
||||
bool noSwitchDelay,
|
||||
bool resetBackoff,
|
||||
bool requestAccess,
|
||||
EmlsrMainPhySwitchTrace&& traceInfo);
|
||||
|
||||
static constexpr bool RESET_BACKOFF = true; //!< reset backoff on main PHY switch
|
||||
static constexpr bool DONT_RESET_BACKOFF = false; //!< do not reset backoff on main PHY switch
|
||||
@@ -574,6 +621,18 @@ class EmlsrManager : public Object
|
||||
//!< MediumSyncDelay timer is running
|
||||
};
|
||||
|
||||
/**
|
||||
* TracedCallback signature for main PHY switch events.
|
||||
*
|
||||
* @param info the information associated with the main PHY switch event
|
||||
*/
|
||||
typedef void (*MainPhySwitchCallback)(const EmlsrMainPhySwitchTrace& info);
|
||||
|
||||
/// TracedCallback for main PHY switch events typedef
|
||||
using MainPhySwitchTracedCallback = TracedCallback<const EmlsrMainPhySwitchTrace&>;
|
||||
|
||||
MainPhySwitchTracedCallback m_mainPhySwitchTrace; //!< main PHY switch trace source
|
||||
|
||||
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 */
|
||||
@@ -608,6 +667,116 @@ class EmlsrManager : public Object
|
||||
m_noPhySince; //!< link ID-indexed map of the time since no PHY is operating on the link
|
||||
};
|
||||
|
||||
/**
|
||||
* Struct to trace that main PHY switched to start a DL TXOP after that an aux PHY received an ICF.
|
||||
*/
|
||||
struct EmlsrDlTxopIcfReceivedByAuxPhyTrace
|
||||
: public EmlsrMainPhySwitchTraceImpl<EmlsrDlTxopIcfReceivedByAuxPhyTrace>
|
||||
{
|
||||
static constexpr std::string_view m_name = "DlTxopIcfReceivedByAuxPhy"; //!< trace name
|
||||
};
|
||||
|
||||
/**
|
||||
* Struct to trace that main PHY switched to start an UL TXOP after that an aux PHY transmitted an
|
||||
* RTS.
|
||||
*/
|
||||
struct EmlsrUlTxopRtsSentByAuxPhyTrace
|
||||
: public EmlsrMainPhySwitchTraceImpl<EmlsrUlTxopRtsSentByAuxPhyTrace>
|
||||
{
|
||||
static constexpr std::string_view m_name = "UlTxopRtsSentByAuxPhy"; //!< trace name
|
||||
};
|
||||
|
||||
/**
|
||||
* Struct to trace that main PHY switched when a (DL or UL) TXOP ended.
|
||||
*
|
||||
* This trace is normally called when aux PHYs do not switch link and the main PHY switches back to
|
||||
* the preferred link when a TXOP carried out on another link ends. In such a case, the remTime
|
||||
* field is set to zero.
|
||||
*
|
||||
* Note that the main PHY may be already switching when the TXOP ends; this happens, e.g., when the
|
||||
* main PHY starts switching to a link on which an aux PHY gained a TXOP and sent an RTS, but the
|
||||
* CTS is not received and the UL TXOP ends before the main PHY channel switch is completed. In this
|
||||
* case, the main PHY switch is postponed until the previous switch is completed and the remTime
|
||||
* field is set to the remaining channel switch delay at the time the TXOP ends:
|
||||
*
|
||||
* |-- main PHY switch --|
|
||||
* |----- to link 1 -----|
|
||||
* ┌───────────┐
|
||||
* │ CTS │
|
||||
* ────────────────────────┬───────────┬───┴X──────────┴─────────────────────────────
|
||||
* [link 1] │ RTS │ │-remTime-│
|
||||
* └───────────┘ │ |-- main PHY switch --|
|
||||
* │ |- to preferred link -|
|
||||
* CTS timeout
|
||||
*
|
||||
* Note also that the Advanced EMLSR manager may allow a main PHY switch to be interrupted. If this
|
||||
* option is enabled and the main PHY is switching when the TXOP ends, the previous switch is
|
||||
* interrupted and the main PHY starts switching to the preferred link (in this case, the remTime
|
||||
* field indicates the time that was left to complete the previous switch). Also note that, with
|
||||
* the Advanced EMLSR manager, this trace may also be called when aux PHYs switch link. This happens
|
||||
* when the TXOP ends while the main PHY is switching; in this case, the previous switch is
|
||||
* interrupted and the main PHY returns to the link on which it was operating before the previous
|
||||
* switch.
|
||||
*
|
||||
* |-- main PHY switch --|
|
||||
* |----- to link 1 -----|(interrupted)
|
||||
* ┌───────────┐
|
||||
* │ CTS │
|
||||
* ────────────────────────┬───────────┬───┴X──────────┴─────────────────────────────
|
||||
* [link 1] │ RTS │ │-remTime-│
|
||||
* └───────────┘ │-- main PHY switch --|
|
||||
* │- to preferred link -|
|
||||
* CTS timeout
|
||||
*/
|
||||
struct EmlsrTxopEndedTrace : public EmlsrMainPhySwitchTraceImpl<EmlsrTxopEndedTrace>
|
||||
{
|
||||
static constexpr std::string_view m_name = "TxopEnded"; //!< trace name
|
||||
|
||||
Time remTime; //!< the remaining time (at TXOP end) until the main PHY completes the
|
||||
//!< channel switch, in case the main PHY is completing a previous switch
|
||||
//!< when the TXOP ends
|
||||
|
||||
/**
|
||||
* Constructor provided because this struct is not an aggregate (it has a base struct), hence
|
||||
* we cannot use designated initializers.
|
||||
*
|
||||
* @param t the value for the sinceTxopEnd field
|
||||
*/
|
||||
EmlsrTxopEndedTrace(const Time& t)
|
||||
: remTime(t)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Struct to trace that main PHY switched to operate on a link on which an aux PHY that is not
|
||||
* TX capable has gained or is expected to shortly gain a TXOP.
|
||||
*/
|
||||
struct EmlsrUlTxopAuxPhyNotTxCapableTrace
|
||||
: public EmlsrMainPhySwitchTraceImpl<EmlsrUlTxopAuxPhyNotTxCapableTrace>
|
||||
{
|
||||
static constexpr std::string_view m_name = "UlTxopAuxPhyNotTxCapable"; //!< trace name
|
||||
|
||||
AcIndex acIndex; //!< Access category of TXOP on aux PHY
|
||||
Time remTime; //!< Remaining time to complete backoff countdown on the aux PHY link
|
||||
Time remNav; //!< the remaining NAV on main PHY link when main PHY is requested to switch
|
||||
|
||||
/**
|
||||
* Constructor provided because this struct is not an aggregate (it has a base struct), hence
|
||||
* we cannot use designated initializers.
|
||||
*
|
||||
* @param aci the value for the acIndex field
|
||||
* @param delay the value for the remTime field
|
||||
* @param navLeft the value for the remNav field
|
||||
*/
|
||||
EmlsrUlTxopAuxPhyNotTxCapableTrace(AcIndex aci, const Time& delay, const Time& navLeft)
|
||||
: acIndex(aci),
|
||||
remTime(delay),
|
||||
remNav(navLeft)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
#endif /* EMLSR_MANAGER_H */
|
||||
|
||||
@@ -4655,10 +4655,12 @@ EmlsrCcaBusyTest::StartTraffic()
|
||||
m_nextMainPhyLinkId = (m_currMainPhyLinkId + 1) % 2;
|
||||
|
||||
// request the main PHY to switch to another link
|
||||
m_staMacs[0]->GetEmlsrManager()->SwitchMainPhy(m_nextMainPhyLinkId,
|
||||
false,
|
||||
EmlsrManager::DONT_RESET_BACKOFF,
|
||||
EmlsrManager::DONT_REQUEST_ACCESS);
|
||||
m_staMacs[0]->GetEmlsrManager()->SwitchMainPhy(
|
||||
m_nextMainPhyLinkId,
|
||||
false,
|
||||
EmlsrManager::DONT_RESET_BACKOFF,
|
||||
EmlsrManager::DONT_REQUEST_ACCESS,
|
||||
EmlsrDlTxopIcfReceivedByAuxPhyTrace{}); // trace info not used
|
||||
|
||||
// the other MLD transmits a packet to the AP
|
||||
TransmitPacketToAp(m_nextMainPhyLinkId);
|
||||
|
||||
Reference in New Issue
Block a user