wifi: Default EMLSR Manager switches main PHY back to its previous link
...when a TXOP ends, if the aux PHYs do not switch link
This commit is contained in:
committed by
Stefano Avallone
parent
f38712dc3c
commit
4fc5162f97
@@ -42,7 +42,10 @@ DefaultEmlsrManager::GetTypeId()
|
||||
.AddConstructor<DefaultEmlsrManager>()
|
||||
.AddAttribute("SwitchAuxPhy",
|
||||
"Whether Aux PHY should switch channel to operate on the link on which "
|
||||
"the Main PHY was operating before moving to the link of the Aux PHY.",
|
||||
"the Main PHY was operating before moving to the link of the Aux PHY. "
|
||||
"Note that, if the Aux PHY does not switch channel, the main PHY will "
|
||||
"switch back to its previous link once the TXOP terminates (otherwise, "
|
||||
"no PHY will be listening on that EMLSR link).",
|
||||
BooleanValue(true),
|
||||
MakeBooleanAccessor(&DefaultEmlsrManager::m_switchAuxPhy),
|
||||
MakeBooleanChecker());
|
||||
@@ -96,7 +99,10 @@ DefaultEmlsrManager::NotifyMainPhySwitch(uint8_t currLinkId, uint8_t nextLinkId)
|
||||
|
||||
if (!m_switchAuxPhy)
|
||||
{
|
||||
return; // nothing to do
|
||||
// record that the main PHY will have to switch back to its current link
|
||||
m_linkIdForMainPhyAfterTxop = currLinkId;
|
||||
m_auxPhyToReconnect = GetStaMac()->GetWifiPhy(nextLinkId);
|
||||
return;
|
||||
}
|
||||
|
||||
// switch channel on Aux PHY so that it operates on the link on which the main PHY was operating
|
||||
@@ -119,6 +125,16 @@ void
|
||||
DefaultEmlsrManager::DoNotifyTxopEnd(uint8_t linkId)
|
||||
{
|
||||
NS_LOG_FUNCTION(this << linkId);
|
||||
|
||||
// switch main PHY to the previous link, if needed
|
||||
if (m_linkIdForMainPhyAfterTxop && linkId != m_linkIdForMainPhyAfterTxop)
|
||||
{
|
||||
auto phy = m_auxPhyToReconnect;
|
||||
SwitchMainPhy(*m_linkIdForMainPhyAfterTxop, false);
|
||||
// Reconnect the aux PHY to its original link
|
||||
Simulator::ScheduleNow(&StaWifiMac::NotifySwitchingEmlsrLink, GetStaMac(), phy, linkId);
|
||||
}
|
||||
m_linkIdForMainPhyAfterTxop.reset();
|
||||
}
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
@@ -58,6 +58,12 @@ class DefaultEmlsrManager : public EmlsrManager
|
||||
|
||||
bool m_switchAuxPhy; /**< whether Aux PHY should switch channel to operate on the link on which
|
||||
the Main PHY was operating before moving to the link of the Aux PHY */
|
||||
std::optional<uint8_t>
|
||||
m_linkIdForMainPhyAfterTxop; //!< ID of the link the main PHY has to switch to once
|
||||
//!< the current TXOP terminates
|
||||
Ptr<WifiPhy> m_auxPhyToReconnect; //!< Aux PHY the ChannelAccessManager of the link on which
|
||||
//!< the main PHY is operating has to connect a listener to
|
||||
//!< when the main PHY is back operating on its previous link
|
||||
};
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
@@ -177,6 +177,14 @@ class EmlsrManager : public Object
|
||||
*/
|
||||
const WifiPhyOperatingChannel& GetChannelForAuxPhy(uint8_t linkId) const;
|
||||
|
||||
/**
|
||||
* Switch channel on the Main PHY so that it operates on the given link.
|
||||
*
|
||||
* \param linkId the ID of the link on which the main PHY has to operate
|
||||
* \param noSwitchDelay whether switching delay should be zero
|
||||
*/
|
||||
void SwitchMainPhy(uint8_t linkId, bool noSwitchDelay);
|
||||
|
||||
/**
|
||||
* Switch channel on the Aux PHY operating on the given current link so that it operates
|
||||
* on the given next link.
|
||||
@@ -269,14 +277,6 @@ class EmlsrManager : public Object
|
||||
*/
|
||||
void ChangeEmlsrMode();
|
||||
|
||||
/**
|
||||
* Switch channel on the Main PHY so that it operates on the given link.
|
||||
*
|
||||
* \param linkId the ID of the link on which the main PHY has to operate
|
||||
* \param noSwitchDelay whether switching delay should be zero
|
||||
*/
|
||||
void SwitchMainPhy(uint8_t linkId, bool noSwitchDelay);
|
||||
|
||||
/**
|
||||
* Adjust the operating channel of all the aux PHYs to meet the constraint on the maximum
|
||||
* channel width supported by aux PHYs.
|
||||
|
||||
@@ -2217,6 +2217,9 @@ EmlsrLinkSwitchTest::EmlsrLinkSwitchTest(const Params& params)
|
||||
m_mainPhyId = 1;
|
||||
m_establishBaDl = true;
|
||||
m_duration = Seconds(1.0);
|
||||
// when aux PHYs do not switch link, the main PHY switches back to its previous link after
|
||||
// a TXOP, hence the transition delay must exceed the channel switch delay (default: 250us)
|
||||
m_transitionDelay = {MicroSeconds(256)};
|
||||
}
|
||||
|
||||
void
|
||||
@@ -2413,25 +2416,27 @@ EmlsrLinkSwitchTest::CheckQosFrames(const WifiConstPsduMap& psduMap,
|
||||
* └───┘ └──┘
|
||||
*
|
||||
*
|
||||
* AUX PHY switching disabled
|
||||
* AUX PHY switching disabled (X = main PHY channel switch delay)
|
||||
*
|
||||
* |--------- aux PHY A ---------|------ main PHY ------|
|
||||
* |------------------------------------------ aux PHY A ---------------------------------------
|
||||
* |-- main PHY --|X|
|
||||
* ┌───┐ ┌───┐
|
||||
* │ICF│ │QoS│
|
||||
* ──────────────────────────┴───┴┬───┬┴───┴┬──┬────────────────────────────────────────────────
|
||||
* [link 0] │CTS│ │BA│
|
||||
* └───┘ └──┘
|
||||
*
|
||||
*
|
||||
* |--------- main PHY ----------|
|
||||
* ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐
|
||||
* │ICF│ │QoS│ │ICF│ │ICF│ │ICF│
|
||||
* ───┴───┴┬───┬┴───┴┬──┬──────────────────────────────────────────────────┴───┴──┴───┴──┴───┴──
|
||||
* [link 1]│CTS│ │BA│
|
||||
* └───┘ └──┘
|
||||
* |-main|
|
||||
* |--------- main PHY ----------| |-PHY-| |------ main PHY ------
|
||||
* ┌───┐ ┌───┐ ┌───┐ ┌───┐
|
||||
* │ICF│ │QoS│ │ICF│ │QoS│
|
||||
* ───┴───┴┬───┬┴───┴┬──┬──────────────────────────────────────────────────┴───┴┬───┬┴───┴┬──┬──
|
||||
* [link 1]│CTS│ │BA│ │CTS│ │BA│
|
||||
* └───┘ └──┘ └───┘ └──┘
|
||||
*
|
||||
*
|
||||
* |--------------------- aux PHY B --------------------|--------------- main PHY --------------
|
||||
* |------------------------------------------ aux PHY B ---------------------------------------
|
||||
* |-- main PHY --|X|
|
||||
* ┌───┐ ┌───┐
|
||||
* │ICF│ │QoS│
|
||||
* ─────────────────────────────────────────────────┴───┴┬───┬┴───┴┬──┬─────────────────────────
|
||||
@@ -2451,6 +2456,8 @@ EmlsrLinkSwitchTest::CheckInitialControlFrame(const WifiConstPsduMap& psduMap,
|
||||
return;
|
||||
}
|
||||
|
||||
NS_TEST_EXPECT_MSG_LT(m_countQoSframes, 4, "Unexpected number of ICFs");
|
||||
|
||||
auto mainPhy = m_staMacs[0]->GetDevice()->GetPhy(m_mainPhyId);
|
||||
auto phyRecvIcf = m_staMacs[0]->GetWifiPhy(linkId); // PHY receiving the ICF
|
||||
|
||||
@@ -2458,66 +2465,68 @@ EmlsrLinkSwitchTest::CheckInitialControlFrame(const WifiConstPsduMap& psduMap,
|
||||
NS_TEST_ASSERT_MSG_EQ(currMainPhyLinkId.has_value(),
|
||||
true,
|
||||
"Didn't find the link on which the Main PHY is operating");
|
||||
NS_TEST_ASSERT_MSG_NE(phyRecvIcf,
|
||||
nullptr,
|
||||
"No PHY on the link where ICF " << m_countQoSframes << " was sent");
|
||||
|
||||
if (phyRecvIcf && phyRecvIcf != mainPhy)
|
||||
if (phyRecvIcf != mainPhy)
|
||||
{
|
||||
NS_TEST_EXPECT_MSG_LT_OR_EQ(
|
||||
phyRecvIcf->GetChannelWidth(),
|
||||
m_auxPhyMaxChWidth,
|
||||
"Aux PHY that received ICF is operating on a channel whose width exceeds the limit "
|
||||
<< m_countQoSframes);
|
||||
"Aux PHY that received ICF "
|
||||
<< m_countQoSframes << " is operating on a channel whose width exceeds the limit");
|
||||
}
|
||||
|
||||
// if aux PHYs switch links, only the first ICF is received by the main PHY; otherwise,
|
||||
// the first ICF and the last ICF are received by the main PHY
|
||||
NS_TEST_EXPECT_MSG_EQ((phyRecvIcf == mainPhy),
|
||||
(m_countQoSframes == 0 || (!m_switchAuxPhy && m_countQoSframes == 3)),
|
||||
"Expecting that the ICF was received by the main PHY");
|
||||
|
||||
// if aux PHYs do not switch links, the main PHY is operating on its original link when
|
||||
// the transmission of an ICF starts
|
||||
NS_TEST_EXPECT_MSG_EQ(m_switchAuxPhy || currMainPhyLinkId == m_mainPhyId,
|
||||
true,
|
||||
"Main PHY is operating on an unexpected link ("
|
||||
<< +currMainPhyLinkId.value() << ", expected " << +m_mainPhyId
|
||||
<< ")");
|
||||
|
||||
auto txDuration =
|
||||
WifiPhy::CalculateTxDuration(psduMap, txVector, m_apMac->GetWifiPhy(linkId)->GetPhyBand());
|
||||
|
||||
// check that PHYs are operating on the expected link after the reception of the ICF
|
||||
Simulator::Schedule(txDuration + NanoSeconds(1), [=]() {
|
||||
std::size_t nRxOk = m_switchAuxPhy ? 4 : 3; // successfully received ICFs
|
||||
|
||||
if (m_countQoSframes < nRxOk)
|
||||
{
|
||||
// the main PHY must be operating on the link where ICF was sent
|
||||
NS_TEST_EXPECT_MSG_EQ(m_staMacs[0]->GetWifiPhy(linkId),
|
||||
mainPhy,
|
||||
"PHY operating on link where ICF was sent is not the main PHY");
|
||||
}
|
||||
|
||||
// the first ICF is received by the main PHY and no channel switch occurs
|
||||
if (m_countQoSframes == 0)
|
||||
{
|
||||
NS_TEST_EXPECT_MSG_EQ(phyRecvIcf,
|
||||
mainPhy,
|
||||
"PHY that received the ICF is not the main PHY");
|
||||
return;
|
||||
}
|
||||
// the main PHY must be operating on the link where ICF was sent
|
||||
NS_TEST_EXPECT_MSG_EQ(m_staMacs[0]->GetWifiPhy(linkId),
|
||||
mainPhy,
|
||||
"PHY operating on link where ICF was sent is not the main PHY");
|
||||
|
||||
// the behavior of Aux PHYs depends on whether they switch channel or not
|
||||
if (m_switchAuxPhy)
|
||||
{
|
||||
NS_TEST_EXPECT_MSG_LT(m_countQoSframes, nRxOk, "Unexpected number of ICFs");
|
||||
if (mainPhy != phyRecvIcf)
|
||||
{
|
||||
NS_TEST_EXPECT_MSG_EQ(phyRecvIcf->IsStateSwitching(),
|
||||
true,
|
||||
"Aux PHY expected to switch channel");
|
||||
}
|
||||
Simulator::Schedule(phyRecvIcf->GetChannelSwitchDelay(), [=]() {
|
||||
NS_TEST_EXPECT_MSG_EQ(m_staMacs[0]->GetWifiPhy(*currMainPhyLinkId),
|
||||
phyRecvIcf,
|
||||
"PHY operating on link where Main PHY was before switching "
|
||||
"channel is not the aux PHY that received the ICF");
|
||||
"The Aux PHY that received the ICF is expected to operate "
|
||||
"on the link where Main PHY was before switching channel");
|
||||
});
|
||||
}
|
||||
else if (m_countQoSframes < nRxOk)
|
||||
{
|
||||
// the first 3 ICFs are actually received by some PHY
|
||||
NS_TEST_EXPECT_MSG_NE(phyRecvIcf, nullptr, "Expected some PHY to receive the ICF");
|
||||
NS_TEST_EXPECT_MSG_EQ(m_staMacs[0]->GetWifiPhy(*currMainPhyLinkId),
|
||||
nullptr,
|
||||
"No PHY expected to operate on link where Main PHY was "
|
||||
"before switching channel");
|
||||
}
|
||||
else
|
||||
{
|
||||
// no PHY received the ICF
|
||||
NS_TEST_EXPECT_MSG_EQ(phyRecvIcf,
|
||||
nullptr,
|
||||
"Expected no PHY to operate on link where ICF is sent");
|
||||
NS_TEST_EXPECT_MSG_EQ(phyRecvIcf->IsStateSwitching(),
|
||||
false,
|
||||
"Aux PHY is not expected to switch channel");
|
||||
NS_TEST_EXPECT_MSG_EQ(phyRecvIcf->GetPhyBand(),
|
||||
mainPhy->GetPhyBand(),
|
||||
"The Aux PHY that received the ICF is expected to operate "
|
||||
"on the same band as the Main PHY");
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -2527,7 +2536,7 @@ EmlsrLinkSwitchTest::CheckResults()
|
||||
{
|
||||
NS_TEST_ASSERT_MSG_NE(m_txPsdusPos, 0, "BA agreement establishment not completed");
|
||||
|
||||
std::size_t nRxOk = m_switchAuxPhy ? 4 : 3; // successfully received ICFs
|
||||
const std::size_t nRxOk = 4; // successfully received ICFs
|
||||
|
||||
NS_TEST_ASSERT_MSG_GT_OR_EQ(m_txPsdus.size(),
|
||||
m_txPsdusPos + 3 + nRxOk * 4,
|
||||
|
||||
Reference in New Issue
Block a user