wifi: Reduce duplicated code in advanced EMLSR manager
This commit is contained in:
@@ -112,12 +112,6 @@ AdvancedEmlsrManager::GetTypeId()
|
||||
.SetParent<DefaultEmlsrManager>()
|
||||
.SetGroupName("Wifi")
|
||||
.AddConstructor<AdvancedEmlsrManager>()
|
||||
.AddAttribute("UseNotifiedMacHdr",
|
||||
"Whether to use the information about the MAC header of the MPDU "
|
||||
"being received, if notified by the PHY.",
|
||||
BooleanValue(true),
|
||||
MakeBooleanAccessor(&AdvancedEmlsrManager::m_useNotifiedMacHdr),
|
||||
MakeBooleanChecker())
|
||||
.AddAttribute("AllowUlTxopInRx",
|
||||
"Whether a (main or aux) PHY is allowed to start an UL TXOP if "
|
||||
"another PHY is receiving a PPDU (possibly starting a DL TXOP). "
|
||||
@@ -231,92 +225,23 @@ AdvancedEmlsrManager::DoGetDelayUntilAccessRequest(uint8_t linkId)
|
||||
// prevent or allow an UL TXOP depending on whether another PHY is receiving a PPDU
|
||||
for (const auto id : GetStaMac()->GetLinkIds())
|
||||
{
|
||||
if (auto phy = GetStaMac()->GetWifiPhy(id);
|
||||
phy && id != linkId && GetStaMac()->IsEmlsrLink(id))
|
||||
if (id == linkId)
|
||||
{
|
||||
if (auto macHdr = GetEhtFem(id)->GetReceivedMacHdr(); macHdr && m_useNotifiedMacHdr)
|
||||
{
|
||||
NS_ASSERT(phy->GetState()->GetLastTime({WifiPhyState::RX}) == Simulator::Now());
|
||||
// we are receiving the MAC payload of a PSDU; if the PSDU being received on
|
||||
// another link is an ICF, give up the TXOP and restart channel access at the
|
||||
// end of PSDU reception. Note that we cannot be sure that the PSDU being received
|
||||
// is an ICF addressed to us until we receive the entire PSDU
|
||||
if (const auto& hdr = macHdr->get();
|
||||
hdr.IsTrigger() &&
|
||||
(hdr.GetAddr1().IsBroadcast() || hdr.GetAddr1() == GetEhtFem(id)->GetAddress()))
|
||||
{
|
||||
return {false, phy->GetDelayUntilIdle()};
|
||||
}
|
||||
continue;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (auto txVector = phy->GetInfoIfRxingPhyHeader())
|
||||
{
|
||||
if (txVector->get().GetModulationClass() >= WIFI_MOD_CLASS_HT)
|
||||
{
|
||||
// The initial Control frame of frame exchanges shall be sent in the non-HT PPDU
|
||||
// or non-HT duplicate PPDU format (Sec. 35.3.17 of 802.11be D7.0), so this is
|
||||
// not an ICF, we can ignore it
|
||||
continue;
|
||||
}
|
||||
// we don't know yet the type of the frame being received; prevent or allow
|
||||
// the UL TXOP based on user configuration
|
||||
if (!m_allowUlTxopInRx)
|
||||
{
|
||||
// retry channel access after the end of the current PHY header field
|
||||
return {false, phy->GetDelayUntilIdle()};
|
||||
}
|
||||
continue;
|
||||
}
|
||||
const auto [maybeIcf, delay] = CheckPossiblyReceivingIcf(id);
|
||||
|
||||
if (phy->IsStateRx())
|
||||
{
|
||||
// we don't know yet the type of the frame being received; prevent or allow
|
||||
// the UL TXOP based on user configuration
|
||||
if (!m_allowUlTxopInRx)
|
||||
{
|
||||
if (!m_useNotifiedMacHdr)
|
||||
{
|
||||
// restart channel access at the end of PSDU reception
|
||||
return {false, phy->GetDelayUntilIdle()};
|
||||
}
|
||||
if (!maybeIcf)
|
||||
{
|
||||
// not receiving anything or receiving something that is certainly not an ICF
|
||||
continue;
|
||||
}
|
||||
|
||||
// retry channel access after the expected end of the MAC header reception
|
||||
auto macHdrSize = WifiMacHeader(WIFI_MAC_QOSDATA).GetSerializedSize() +
|
||||
4 /* A-MPDU subframe header length */;
|
||||
auto ongoingRxInfo = GetEhtFem(id)->GetOngoingRxInfo();
|
||||
// if a PHY is in RX state, it should have info about received MAC header.
|
||||
// The exception is represented by this situation:
|
||||
// - an aux PHY is disconnected from the MAC stack because the main PHY is
|
||||
// operating on its link
|
||||
// - the main PHY notifies the MAC header info to the FEM and then leaves the
|
||||
// link (e.g., because it recognizes that the MPDU is not addressed to the
|
||||
// EMLSR client). Disconnecting the main PHY from the MAC stack causes the
|
||||
// MAC header info to be discarded by the FEM
|
||||
// - the aux PHY is re-connected to the MAC stack and is still in RX state
|
||||
// when the main PHY gets channel access on another link (and we get here)
|
||||
if (!ongoingRxInfo.has_value())
|
||||
{
|
||||
NS_ASSERT_MSG(phy != GetStaMac()->GetDevice()->GetPhy(GetMainPhyId()),
|
||||
"Main PHY should have MAC header info when in RX state");
|
||||
// we are in the situation described above; if the MPDU being received
|
||||
// by the aux PHY is not addressed to the EMLSR client, we can ignore it
|
||||
continue;
|
||||
}
|
||||
const auto& txVector = ongoingRxInfo->get().txVector;
|
||||
if (txVector.GetModulationClass() >= WIFI_MOD_CLASS_HT)
|
||||
{
|
||||
// this is not an ICF, ignore it
|
||||
continue;
|
||||
}
|
||||
auto macHdrDuration = DataRate(txVector.GetMode().GetDataRate(txVector))
|
||||
.CalculateBytesTxTime(macHdrSize);
|
||||
const auto timeSinceRxStart =
|
||||
Simulator::Now() - phy->GetState()->GetLastTime({WifiPhyState::CCA_BUSY});
|
||||
return {false, Max(macHdrDuration - timeSinceRxStart, Time{0})};
|
||||
}
|
||||
continue;
|
||||
}
|
||||
// a PPDU that may be an ICF is being received
|
||||
if (!m_allowUlTxopInRx)
|
||||
{
|
||||
return {false, delay};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -552,7 +477,7 @@ AdvancedEmlsrManager::SwitchMainPhyBackDelayExpired(uint8_t linkId)
|
||||
return; // nothing to do
|
||||
}
|
||||
|
||||
Time delay{0};
|
||||
Time extension{0};
|
||||
|
||||
// check if the timer must be restarted because a frame is being received on any link
|
||||
for (const auto id : GetStaMac()->GetLinkIds())
|
||||
@@ -571,37 +496,11 @@ AdvancedEmlsrManager::SwitchMainPhyBackDelayExpired(uint8_t linkId)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (auto macHdr = GetEhtFem(id)->GetReceivedMacHdr(); macHdr && m_useNotifiedMacHdr)
|
||||
const auto [maybeIcf, delay] = CheckPossiblyReceivingIcf(id);
|
||||
|
||||
if (maybeIcf)
|
||||
{
|
||||
// the MAC header has been received; if this is a Trigger Frame, we shall restart the
|
||||
// timer, so that we do not yet switch the main PHY back to the preferred link
|
||||
if (const auto& hdr = macHdr->get();
|
||||
hdr.IsTrigger() &&
|
||||
(hdr.GetAddr1().IsBroadcast() || hdr.GetAddr1() == GetEhtFem(id)->GetAddress()))
|
||||
{
|
||||
delay = Max(delay, phy->GetDelayUntilIdle());
|
||||
}
|
||||
}
|
||||
else if (auto txVector = phy->GetInfoIfRxingPhyHeader())
|
||||
{
|
||||
if (txVector->get().GetModulationClass() < WIFI_MOD_CLASS_HT)
|
||||
{
|
||||
// the PHY header of a non-HT PPDU, which may be an ICF, is being received; check
|
||||
// again after the TX duration of a non-HT PHY header
|
||||
delay = Max(delay, EMLSR_RX_PHY_START_DELAY);
|
||||
}
|
||||
}
|
||||
else if (phy->IsStateRx())
|
||||
{
|
||||
if (auto ongoingRxInfo = GetEhtFem(id)->GetOngoingRxInfo();
|
||||
ongoingRxInfo &&
|
||||
ongoingRxInfo->get().txVector.GetModulationClass() < WIFI_MOD_CLASS_HT)
|
||||
{
|
||||
// the MAC header of a non-HT PPDU, which may be an ICF, has not been received yet
|
||||
// (or we cannot use its info); restart the timer, we will be called back when the
|
||||
// MAC header is received
|
||||
delay = Max(delay, phy->GetDelayUntilIdle());
|
||||
}
|
||||
extension = Max(extension, delay);
|
||||
}
|
||||
else if (id == linkId && phy->IsStateIdle())
|
||||
{
|
||||
@@ -610,16 +509,16 @@ AdvancedEmlsrManager::SwitchMainPhyBackDelayExpired(uint8_t linkId)
|
||||
// the timer to have the main PHY stay a bit longer on this link
|
||||
if (GetExpectedAccessWithinDelay(linkId, phy->GetChannelSwitchDelay()))
|
||||
{
|
||||
delay = Max(delay, phy->GetChannelSwitchDelay());
|
||||
extension = Max(extension, phy->GetChannelSwitchDelay());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (delay.IsStrictlyPositive())
|
||||
if (extension.IsStrictlyPositive())
|
||||
{
|
||||
NS_LOG_DEBUG("Restarting the timer, check again in " << delay.As(Time::US));
|
||||
NS_LOG_DEBUG("Restarting the timer, check again in " << extension.As(Time::US));
|
||||
m_switchMainPhyBackEvent =
|
||||
Simulator::Schedule(delay,
|
||||
Simulator::Schedule(extension,
|
||||
&AdvancedEmlsrManager::SwitchMainPhyBackDelayExpired,
|
||||
this,
|
||||
linkId);
|
||||
|
||||
@@ -117,8 +117,6 @@ class AdvancedEmlsrManager : public DefaultEmlsrManager
|
||||
void DoNotifyIcfReceived(uint8_t linkId) override;
|
||||
void DoNotifyUlTxopStart(uint8_t linkId) override;
|
||||
|
||||
bool m_useNotifiedMacHdr; //!< whether to use the information about the MAC header of
|
||||
//!< the MPDU being received (if notified by the PHY)
|
||||
bool m_allowUlTxopInRx; //!< whether a (main or aux) PHY is allowed to start an UL
|
||||
//!< TXOP if another PHY is receiving a PPDU
|
||||
bool m_interruptSwitching; //!< whether a main PHY switching can be interrupted to start
|
||||
|
||||
@@ -111,6 +111,12 @@ EmlsrManager::GetTypeId()
|
||||
BooleanValue(false),
|
||||
MakeBooleanAccessor(&EmlsrManager::m_auxPhyToSleep),
|
||||
MakeBooleanChecker())
|
||||
.AddAttribute("UseNotifiedMacHdr",
|
||||
"Whether to use the information about the MAC header of the MPDU "
|
||||
"being received, if notified by the PHY.",
|
||||
BooleanValue(true),
|
||||
MakeBooleanAccessor(&EmlsrManager::m_useNotifiedMacHdr),
|
||||
MakeBooleanChecker())
|
||||
.AddAttribute(
|
||||
"EmlsrLinkSet",
|
||||
"IDs of the links on which EMLSR mode will be enabled. An empty set "
|
||||
@@ -504,6 +510,90 @@ EmlsrManager::GetDelayUntilAccessRequest(uint8_t linkId, AcIndex aci)
|
||||
return GetDelayUnlessMainPhyTakesOverUlTxop(linkId);
|
||||
}
|
||||
|
||||
std::pair<bool, Time>
|
||||
EmlsrManager::CheckPossiblyReceivingIcf(uint8_t linkId) const
|
||||
{
|
||||
NS_LOG_FUNCTION(this << linkId);
|
||||
|
||||
auto phy = GetStaMac()->GetWifiPhy(linkId);
|
||||
|
||||
if (!phy || !GetStaMac()->IsEmlsrLink(linkId))
|
||||
{
|
||||
NS_LOG_DEBUG("No PHY (" << phy << ") or not an EMLSR link (" << +linkId << ")");
|
||||
return {false, Time{0}};
|
||||
}
|
||||
|
||||
if (auto macHdr = GetEhtFem(linkId)->GetReceivedMacHdr(); macHdr && m_useNotifiedMacHdr)
|
||||
{
|
||||
NS_LOG_DEBUG("Receiving the MAC payload of a PSDU and MAC header info can be used");
|
||||
NS_ASSERT(phy->GetState()->GetLastTime({WifiPhyState::RX}) == Simulator::Now());
|
||||
|
||||
if (const auto& hdr = macHdr->get();
|
||||
hdr.IsTrigger() &&
|
||||
(hdr.GetAddr1().IsBroadcast() || hdr.GetAddr1() == GetEhtFem(linkId)->GetAddress()))
|
||||
{
|
||||
// the PSDU being received _may_ be an ICF. Note that we cannot be sure that the PSDU
|
||||
// being received is an ICF addressed to us until we receive the entire PSDU
|
||||
NS_LOG_DEBUG("Based on MAC header, may be an ICF, postpone by "
|
||||
<< phy->GetDelayUntilIdle().As(Time::US));
|
||||
return {true, phy->GetDelayUntilIdle()};
|
||||
}
|
||||
}
|
||||
else if (auto txVector = phy->GetInfoIfRxingPhyHeader())
|
||||
{
|
||||
NS_LOG_DEBUG("Receiving PHY header");
|
||||
if (txVector->get().GetModulationClass() < WIFI_MOD_CLASS_HT)
|
||||
{
|
||||
// the PHY header of a non-HT PPDU, which may be an ICF, is being received; check
|
||||
// again after the TX duration of a non-HT PHY header
|
||||
NS_LOG_DEBUG("PHY header of a non-HT PPDU, which may be an ICF, is being received");
|
||||
return {true, EMLSR_RX_PHY_START_DELAY};
|
||||
}
|
||||
}
|
||||
else if (phy->IsStateRx())
|
||||
{
|
||||
// we have not yet received the MAC header or we cannot use its info
|
||||
|
||||
auto ongoingRxInfo = GetEhtFem(linkId)->GetOngoingRxInfo();
|
||||
// if a PHY is in RX state, it should have info about received MAC header.
|
||||
// The exception is represented by this situation:
|
||||
// - an aux PHY is disconnected from the MAC stack because the main PHY is
|
||||
// operating on its link
|
||||
// - the main PHY notifies the MAC header info to the FEM and then leaves the
|
||||
// link (e.g., because it recognizes that the MPDU is not addressed to the
|
||||
// EMLSR client). Disconnecting the main PHY from the MAC stack causes the
|
||||
// MAC header info to be discarded by the FEM
|
||||
// - the aux PHY is re-connected to the MAC stack and is still in RX state
|
||||
// when the main PHY gets channel access on another link (and we get here)
|
||||
if (!ongoingRxInfo.has_value())
|
||||
{
|
||||
NS_ASSERT_MSG(phy != GetStaMac()->GetDevice()->GetPhy(GetMainPhyId()),
|
||||
"Main PHY should have MAC header info when in RX state");
|
||||
// we are in the situation described above; if the MPDU being received
|
||||
// by the aux PHY is not addressed to the EMLSR client, we can ignore it
|
||||
}
|
||||
else if (const auto& txVector = ongoingRxInfo->get().txVector;
|
||||
txVector.GetModulationClass() < WIFI_MOD_CLASS_HT)
|
||||
{
|
||||
if (auto remTime = phy->GetTimeToMacHdrEnd(SU_STA_ID);
|
||||
m_useNotifiedMacHdr && remTime.has_value() && remTime->IsStrictlyPositive())
|
||||
{
|
||||
NS_LOG_DEBUG("Wait until the expected end of the MAC header reception: "
|
||||
<< remTime->As(Time::US));
|
||||
return {true, *remTime};
|
||||
}
|
||||
|
||||
NS_LOG_DEBUG(
|
||||
"MAC header info will not be available. Wait until the end of PSDU reception: "
|
||||
<< phy->GetDelayUntilIdle().As(Time::US));
|
||||
return {true, phy->GetDelayUntilIdle()};
|
||||
}
|
||||
}
|
||||
|
||||
NS_LOG_DEBUG("No ICF being received, state: " << phy->GetState()->GetState());
|
||||
return {false, Time{0}};
|
||||
}
|
||||
|
||||
void
|
||||
EmlsrManager::NotifyUlTxopStart(uint8_t linkId)
|
||||
{
|
||||
|
||||
@@ -334,6 +334,16 @@ class EmlsrManager : public Object
|
||||
*/
|
||||
bool MediumSyncDelayNTxopsExceeded(uint8_t linkId);
|
||||
|
||||
/**
|
||||
* Check whether a PPDU that may be an ICF is being received on the given link. If so, return
|
||||
* true along with the time to wait to know more information about the PPDU being received.
|
||||
* Otherwise, return false.
|
||||
*
|
||||
* @param linkId the ID of the given link
|
||||
* @return a pair indicating whether a PPDU that may be an ICF is being received on the link
|
||||
*/
|
||||
std::pair<bool, Time> CheckPossiblyReceivingIcf(uint8_t linkId) const;
|
||||
|
||||
protected:
|
||||
void DoDispose() override;
|
||||
|
||||
@@ -505,8 +515,10 @@ class EmlsrManager : public Object
|
||||
MHz_u m_auxPhyMaxWidth; //!< max channel width supported by aux PHYs
|
||||
WifiModulationClass m_auxPhyMaxModClass; //!< max modulation class supported by aux PHYs
|
||||
bool m_auxPhyTxCapable; //!< whether Aux PHYs are capable of transmitting PPDUs
|
||||
bool m_auxPhyToSleep; //!< whether Aux PHYs should be put into sleep mode while the Main PHY
|
||||
//!< is carrying out a (DL or UL) TXOP
|
||||
bool m_auxPhyToSleep; //!< whether Aux PHYs should be put into sleep mode while the Main PHY
|
||||
//!< is carrying out a (DL or UL) TXOP
|
||||
bool m_useNotifiedMacHdr; //!< whether to use the information about the MAC header of
|
||||
//!< the MPDU being received (if notified by the PHY)
|
||||
std::map<uint8_t, EventId> m_auxPhyToSleepEvents; //!< PHY ID-indexed map of events scheduled to
|
||||
//!< put an Aux PHY to sleep
|
||||
std::map<uint8_t, Time> m_startSleep; //!< PHY ID-indexed map of last time sleep mode started
|
||||
|
||||
Reference in New Issue
Block a user