wifi: Set all aux PHYs to sleep while main PHY carries out a TXOP
This commit is contained in:
@@ -296,12 +296,9 @@ AdvancedEmlsrManager::DoNotifyTxopEnd(uint8_t linkId)
|
||||
// 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 such cases, wait until the main PHY channel switch is completed (unless the channel
|
||||
// switching can be interrupted) before requesting a new channel switch. Given that the
|
||||
// TXOP ended, the event to put the aux PHY to sleep can be cancelled.
|
||||
// switching can be interrupted) before requesting a new channel switch.
|
||||
// Backoff shall not be reset on the link left by the main PHY because a TXOP ended and
|
||||
// a new backoff value must be generated.
|
||||
m_auxPhyToSleepEvent.Cancel();
|
||||
|
||||
if (m_switchAuxPhy || !mainPhy->IsStateSwitching() || m_interruptSwitching)
|
||||
{
|
||||
NS_ASSERT_MSG(
|
||||
|
||||
@@ -41,13 +41,6 @@ DefaultEmlsrManager::GetTypeId()
|
||||
"no PHY will be listening on that EMLSR link).",
|
||||
BooleanValue(true),
|
||||
MakeBooleanAccessor(&DefaultEmlsrManager::m_switchAuxPhy),
|
||||
MakeBooleanChecker())
|
||||
.AddAttribute("PutAuxPhyToSleep",
|
||||
"Whether Aux PHY should be put into sleep mode while the Main PHY "
|
||||
"is operating on the same link as the Aux PHY (this only matters "
|
||||
"when the Aux PHY does not switch channel).",
|
||||
BooleanValue(true),
|
||||
MakeBooleanAccessor(&DefaultEmlsrManager::m_auxPhyToSleep),
|
||||
MakeBooleanChecker());
|
||||
return tid;
|
||||
}
|
||||
@@ -154,29 +147,18 @@ DefaultEmlsrManager::NotifyMainPhySwitch(std::optional<uint8_t> currLinkId,
|
||||
|
||||
// the Aux PHY is not actually switching (hence no switching delay)
|
||||
GetStaMac()->NotifySwitchingEmlsrLink(m_auxPhyToReconnect, *currLinkId, Seconds(0));
|
||||
// resume aux PHY from sleep (once reconnected to its original link)
|
||||
m_auxPhyToReconnect->ResumeFromSleep();
|
||||
SetCcaEdThresholdOnLinkSwitch(m_auxPhyToReconnect, *currLinkId);
|
||||
}
|
||||
|
||||
// if currLinkId has no value, it means that the main PHY switch is interrupted, hence reset
|
||||
// the aux PHY to reconnect and cancel the event to put the aux PHY to sleep. Doing so when
|
||||
// the main PHY is leaving the preferred link makes no harm (the aux PHY to reconnect and the
|
||||
// event to put the aux PHY to sleep are set below), thus no need to add an 'if' condition
|
||||
// the aux PHY to reconnect. Doing so when the main PHY is leaving the preferred link makes
|
||||
// no harm (the aux PHY to reconnect is set below), thus no need to add an 'if' condition
|
||||
m_auxPhyToReconnect = nullptr;
|
||||
m_auxPhyToSleepEvent.Cancel();
|
||||
|
||||
if (nextLinkId != GetMainPhyId())
|
||||
{
|
||||
// the main PHY is moving to an auxiliary link and the aux PHY does not switch link
|
||||
m_auxPhyToReconnect = GetStaMac()->GetWifiPhy(nextLinkId);
|
||||
|
||||
if (m_auxPhyToSleep)
|
||||
{
|
||||
// aux PHY can be put into sleep mode when the main PHY completes the channel switch
|
||||
m_auxPhyToSleepEvent =
|
||||
Simulator::Schedule(duration, &WifiPhy::SetSleepMode, m_auxPhyToReconnect, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -229,7 +211,7 @@ DefaultEmlsrManager::SwitchMainPhyBackToPreferredLink(uint8_t linkId)
|
||||
// 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 such cases, wait until the main PHY channel switch is completed before requesting
|
||||
// a new channel switch and cancel the event to put the aux PHY to sleep.
|
||||
// a new channel switch.
|
||||
// Backoff shall not be reset on the link left by the main PHY because a TXOP ended and
|
||||
// a new backoff value must be generated.
|
||||
if (!mainPhy->IsStateSwitching())
|
||||
@@ -238,7 +220,6 @@ DefaultEmlsrManager::SwitchMainPhyBackToPreferredLink(uint8_t linkId)
|
||||
}
|
||||
else
|
||||
{
|
||||
m_auxPhyToSleepEvent.Cancel();
|
||||
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)
|
||||
|
||||
@@ -67,11 +67,8 @@ class DefaultEmlsrManager : public EmlsrManager
|
||||
uint8_t to; //!< ID of the link which the main PHY is moving to
|
||||
};
|
||||
|
||||
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 */
|
||||
bool m_auxPhyToSleep; //!< whether Aux PHY should be put into sleep mode while the Main PHY
|
||||
//!< is operating on the same link as the Aux PHY
|
||||
EventId m_auxPhyToSleepEvent; //!< the event scheduled to put an Aux PHY into sleep mode
|
||||
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 */
|
||||
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
|
||||
|
||||
@@ -318,6 +318,19 @@ EhtFrameExchangeManager::StartTransmission(Ptr<Txop> edca, MHz_u allowedWidth)
|
||||
return started;
|
||||
}
|
||||
|
||||
void
|
||||
EhtFrameExchangeManager::ProtectionCompleted()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
|
||||
if (m_staMac && m_staMac->GetEmlsrManager())
|
||||
{
|
||||
m_staMac->GetEmlsrManager()->NotifyProtectionCompleted(m_linkId);
|
||||
}
|
||||
|
||||
HeFrameExchangeManager::ProtectionCompleted();
|
||||
}
|
||||
|
||||
void
|
||||
EhtFrameExchangeManager::ForwardPsduDown(Ptr<const WifiPsdu> psdu, WifiTxVector& txVector)
|
||||
{
|
||||
|
||||
@@ -204,6 +204,7 @@ class EhtFrameExchangeManager : public HeFrameExchangeManager
|
||||
const WifiMacHeader& hdr) override;
|
||||
void TbPpduTimeout(WifiPsduMap* psduMap, std::size_t nSolicitedStations) override;
|
||||
void BlockAcksInTbPpduTimeout(WifiPsduMap* psduMap, std::size_t nSolicitedStations) override;
|
||||
void ProtectionCompleted() override;
|
||||
|
||||
/**
|
||||
* \return whether this is an EMLSR client that cannot respond to an ICF received a SIFS before
|
||||
|
||||
@@ -101,6 +101,16 @@ EmlsrManager::GetTypeId()
|
||||
MakeBooleanAccessor(&EmlsrManager::SetInDeviceInterference,
|
||||
&EmlsrManager::GetInDeviceInterference),
|
||||
MakeBooleanChecker())
|
||||
.AddAttribute("PutAuxPhyToSleep",
|
||||
"Whether Aux PHYs should be put into sleep mode while the Main PHY "
|
||||
"is carrying out a (DL or UL) TXOP. Specifically, for DL TXOPs, aux "
|
||||
"PHYs are put to sleep after receiving the ICF; for UL TXOPs, aux PHYs "
|
||||
"are put to sleep when the CTS frame is received, if RTS/CTS is used, "
|
||||
"or when the transmission of the data frame starts, otherwise. "
|
||||
"Aux PHYs are resumed from sleep when the TXOP ends.",
|
||||
BooleanValue(false),
|
||||
MakeBooleanAccessor(&EmlsrManager::m_auxPhyToSleep),
|
||||
MakeBooleanChecker())
|
||||
.AddAttribute(
|
||||
"EmlsrLinkSet",
|
||||
"IDs of the links on which EMLSR mode will be enabled. An empty set "
|
||||
@@ -440,6 +450,12 @@ EmlsrManager::NotifyIcfReceived(uint8_t linkId)
|
||||
mainPhy->SetPreviouslyRxPpduUid(uid);
|
||||
}
|
||||
|
||||
// a DL TXOP started, set all aux PHYs to sleep
|
||||
if (m_auxPhyToSleep)
|
||||
{
|
||||
SetSleepStateForAllAuxPhys(true);
|
||||
}
|
||||
|
||||
DoNotifyIcfReceived(linkId);
|
||||
}
|
||||
|
||||
@@ -502,6 +518,30 @@ EmlsrManager::NotifyUlTxopStart(uint8_t linkId)
|
||||
DoNotifyUlTxopStart(linkId);
|
||||
}
|
||||
|
||||
void
|
||||
EmlsrManager::NotifyProtectionCompleted(uint8_t linkId)
|
||||
{
|
||||
NS_LOG_FUNCTION(this << linkId);
|
||||
|
||||
if (m_auxPhyToSleep && m_staMac->IsEmlsrLink(linkId))
|
||||
{
|
||||
if (auto mainPhy = m_staMac->GetDevice()->GetPhy(m_mainPhyId); mainPhy->IsStateSwitching())
|
||||
{
|
||||
// main PHY is switching to this link to take over the UL TXOP. Postpone aux PHY
|
||||
// sleeping until after the main PHY has completed switching
|
||||
Simulator::Schedule(mainPhy->GetDelayUntilIdle() + TimeStep(1),
|
||||
&EmlsrManager::SetSleepStateForAllAuxPhys,
|
||||
this,
|
||||
true);
|
||||
}
|
||||
else
|
||||
{
|
||||
// put aux PHYs to sleep
|
||||
SetSleepStateForAllAuxPhys(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
EmlsrManager::NotifyTxopEnd(uint8_t linkId, bool ulTxopNotStarted, bool ongoingDlTxop)
|
||||
{
|
||||
@@ -544,6 +584,12 @@ EmlsrManager::NotifyTxopEnd(uint8_t linkId, bool ulTxopNotStarted, bool ongoingD
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_auxPhyToSleep)
|
||||
{
|
||||
// TXOP ended, resume all aux PHYs from sleep
|
||||
SetSleepStateForAllAuxPhys(false);
|
||||
}
|
||||
|
||||
DoNotifyTxopEnd(linkId);
|
||||
|
||||
Simulator::ScheduleNow([=, this]() {
|
||||
@@ -1140,4 +1186,64 @@ EmlsrManager::GetChannelForAuxPhy(uint8_t linkId) const
|
||||
return it->second;
|
||||
}
|
||||
|
||||
void
|
||||
EmlsrManager::CancelAllSleepEvents()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
|
||||
for (auto& [id, event] : m_auxPhyToSleepEvents)
|
||||
{
|
||||
event.Cancel();
|
||||
}
|
||||
m_auxPhyToSleepEvents.clear();
|
||||
}
|
||||
|
||||
void
|
||||
EmlsrManager::SetSleepStateForAllAuxPhys(bool sleep)
|
||||
{
|
||||
NS_LOG_FUNCTION(this << sleep);
|
||||
|
||||
CancelAllSleepEvents();
|
||||
|
||||
for (const auto& phy : m_staMac->GetDevice()->GetPhys())
|
||||
{
|
||||
if (phy->GetPhyId() == m_mainPhyId)
|
||||
{
|
||||
continue; // do not set sleep mode/resume from sleep the main PHY
|
||||
}
|
||||
|
||||
if (auto linkId = m_staMac->GetLinkForPhy(phy);
|
||||
linkId.has_value() && !m_staMac->IsEmlsrLink(*linkId))
|
||||
{
|
||||
continue; // this PHY is not operating on an EMLSR link
|
||||
}
|
||||
|
||||
if (!sleep)
|
||||
{
|
||||
NS_LOG_DEBUG("PHY " << +phy->GetPhyId() << ": Resuming from sleep");
|
||||
phy->ResumeFromSleep();
|
||||
continue;
|
||||
}
|
||||
|
||||
// we force WifiPhy::SetSleepMode() to abort RX and switch immediately to sleep mode in
|
||||
// case the state is RX. If the state is TX or SWITCHING, WifiPhy::SetSleepMode() postpones
|
||||
// setting sleep mode to end of TX or SWITCHING. This is fine, but we schedule events here
|
||||
// to be able to cancel them later if needed
|
||||
std::stringstream ss;
|
||||
auto s = std::string("PHY ") + std::to_string(phy->GetPhyId()) + ": Setting sleep mode";
|
||||
if (phy->IsStateTx() || phy->IsStateSwitching())
|
||||
{
|
||||
const auto delay = phy->GetDelayUntilIdle();
|
||||
NS_LOG_DEBUG(s << " in " << delay.As(Time::US));
|
||||
m_auxPhyToSleepEvents[phy->GetPhyId()] =
|
||||
Simulator::Schedule(delay, &WifiPhy::SetSleepMode, phy, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
NS_LOG_DEBUG(s);
|
||||
phy->SetSleepMode(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
@@ -206,6 +206,14 @@ class EmlsrManager : public Object
|
||||
*/
|
||||
void NotifyUlTxopStart(uint8_t linkId);
|
||||
|
||||
/**
|
||||
* Notify that protection (if required) is completed and data frame exchange can start
|
||||
* on the given link.
|
||||
*
|
||||
* \param linkId the ID of the given link
|
||||
*/
|
||||
void NotifyProtectionCompleted(uint8_t linkId);
|
||||
|
||||
/**
|
||||
* Notify the end of a TXOP on the given link.
|
||||
*
|
||||
@@ -410,12 +418,28 @@ class EmlsrManager : public Object
|
||||
*/
|
||||
virtual std::pair<bool, Time> GetDelayUnlessMainPhyTakesOverUlTxop(uint8_t linkId) = 0;
|
||||
|
||||
/**
|
||||
* Set sleep state or awake state for all aux PHYs.
|
||||
*
|
||||
* \param sleep set sleep state, if true, or awake state, otherwise
|
||||
*/
|
||||
void SetSleepStateForAllAuxPhys(bool sleep);
|
||||
|
||||
/**
|
||||
* Cancel all pending events to put aux PHYs into sleep/awake state.
|
||||
*/
|
||||
void CancelAllSleepEvents();
|
||||
|
||||
Time m_emlsrPaddingDelay; //!< EMLSR Padding delay
|
||||
Time m_emlsrTransitionDelay; //!< EMLSR Transition delay
|
||||
uint8_t m_mainPhyId; //!< ID of main PHY (position in the vector of PHYs held by WifiNetDevice)
|
||||
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
|
||||
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, EventId> m_ulMainPhySwitch; //!< link ID-indexed map of timers started when
|
||||
//!< an aux PHY gains an UL TXOP and schedules
|
||||
//!< a channel switch for the main PHY
|
||||
|
||||
Reference in New Issue
Block a user