A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
default-emlsr-manager.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2023 Universita' degli Studi di Napoli Federico II
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 * Author: Stefano Avallone <stavallo@unina.it>
7 */
8
10
12
13#include "ns3/boolean.h"
14#include "ns3/channel-access-manager.h"
15#include "ns3/log.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"
20
21namespace ns3
22{
23
24NS_LOG_COMPONENT_DEFINE("DefaultEmlsrManager");
25
26NS_OBJECT_ENSURE_REGISTERED(DefaultEmlsrManager);
27
28TypeId
30{
31 static TypeId tid =
32 TypeId("ns3::DefaultEmlsrManager")
34 .SetGroupName("Wifi")
35 .AddConstructor<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).",
42 BooleanValue(true),
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).",
49 BooleanValue(true),
52 return tid;
53}
54
56 : m_mainPhySwitchInfo{}
57{
58 NS_LOG_FUNCTION(this);
59}
60
65
66void
68{
69 NS_LOG_FUNCTION(this << *mpdu << linkId);
70}
71
72uint8_t
74{
75 NS_LOG_FUNCTION(this);
76 auto linkId = GetStaMac()->GetLinkForPhy(m_mainPhyId);
77 NS_ASSERT_MSG(linkId, "Link on which the main PHY is operating not found");
78 return *linkId;
79}
80
81std::optional<uint8_t>
83{
84 NS_LOG_FUNCTION(this);
85 auto linkId = GetStaMac()->GetLinkForPhy(m_mainPhyId);
86 NS_ASSERT_MSG(linkId, "Link on which the main PHY is operating not found");
87 return *linkId;
88}
89
90void
95
96void
97DefaultEmlsrManager::NotifyMainPhySwitch(std::optional<uint8_t> currLinkId,
98 uint8_t nextLinkId,
99 Time duration)
100{
101 NS_LOG_FUNCTION(this << (currLinkId ? std::to_string(*currLinkId) : "") << nextLinkId
102 << duration.As(Time::US));
103
104 // if currLinkId has no value (i.e., the main PHY is not operating on any link), it means that
105 // the main PHY is switching
106 const auto now = Simulator::Now();
107 NS_ASSERT_MSG(currLinkId || m_mainPhySwitchInfo.end >= now,
108 "No current link ID provided nor valid main PHY switch information stored");
109 m_mainPhySwitchInfo.from = currLinkId.value_or(m_mainPhySwitchInfo.from);
110 m_mainPhySwitchInfo.end = now + duration;
111
112 if (m_switchAuxPhy)
113 {
114 // cancel any previously requested aux PHY switch
116
117 if (nextLinkId == m_mainPhySwitchInfo.from)
118 {
119 // the main PHY is now switching to the link where it is coming from; nothing else
120 // needs to be done
121 return;
122 }
123
124 // schedule Aux PHY switch so that it operates on the link on which the main PHY was
125 // operating
126 auto auxPhy = GetStaMac()->GetWifiPhy(nextLinkId);
127
128 NS_LOG_DEBUG("Aux PHY (" << auxPhy << ") operating on link " << +nextLinkId
129 << " will switch to link " << +currLinkId.value() << " in "
130 << duration.As(Time::US));
131
133 Simulator::Schedule(duration, [=, this, prevLinkId = m_mainPhySwitchInfo.from]() {
134 SwitchAuxPhy(auxPhy, nextLinkId, prevLinkId);
135 });
136 return;
137 }
138
139 if (currLinkId.has_value() && currLinkId != GetMainPhyId())
140 {
141 // the main PHY is leaving a non-primary link, hence an aux PHY needs to be reconnected
144 "There should be an aux PHY to reconnect when the main PHY leaves a non-primary link");
145
146 // the Aux PHY is not actually switching (hence no switching delay)
147 GetStaMac()->NotifySwitchingEmlsrLink(m_auxPhyToReconnect, *currLinkId, Seconds(0));
148 // resume aux PHY from sleep (once reconnected to its original link)
151 }
152
153 // if currLinkId has no value, it means that the main PHY switch is interrupted, hence reset
154 // the aux PHY to reconnect and cancel the event to put the aux PHY to sleep. Doing so when
155 // the main PHY is leaving the primary link makes no harm (the aux PHY to reconnect and the
156 // event to put the aux PHY to sleep are set below), thus no need to add an 'if' condition
157 m_auxPhyToReconnect = nullptr;
159
160 if (nextLinkId != GetMainPhyId())
161 {
162 // the main PHY is moving to a non-primary link and the aux PHY does not switch link
163 m_auxPhyToReconnect = GetStaMac()->GetWifiPhy(nextLinkId);
164
165 if (m_auxPhyToSleep)
166 {
167 // aux PHY can be put into sleep mode when the main PHY completes the channel switch
170 }
171 }
172}
173
174std::pair<bool, Time>
176{
177 NS_LOG_FUNCTION(this << linkId);
178 return {true, Time{0}}; // start the TXOP
179}
180
181void
183{
184 NS_LOG_FUNCTION(this << linkId);
185}
186
187void
189{
190 NS_LOG_FUNCTION(this << linkId);
191}
192
193void
195{
196 NS_LOG_FUNCTION(this << linkId);
197
198 // switch main PHY to the previous link, if needed
199 if (!m_switchAuxPhy)
200 {
202 }
203}
204
205void
207{
208 NS_LOG_FUNCTION(this << linkId);
209
210 NS_ABORT_MSG_IF(m_switchAuxPhy, "This method can only be called when SwitchAuxPhy is false");
211
213 {
214 return;
215 }
216
217 auto mainPhy = GetStaMac()->GetDevice()->GetPhy(m_mainPhyId);
218
219 // the main PHY may be switching at the end of a TXOP when, e.g., the main PHY starts
220 // switching to a link on which an aux PHY gained a TXOP and sent an RTS, but the CTS
221 // is not received and the UL TXOP ends before the main PHY channel switch is completed.
222 // In such cases, wait until the main PHY channel switch is completed before requesting
223 // a new channel switch and cancel the event to put the aux PHY to sleep.
224 // Backoff shall not be reset on the link left by the main PHY because a TXOP ended and
225 // a new backoff value must be generated.
226 if (!mainPhy->IsStateSwitching())
227 {
229 }
230 else
231 {
233 Simulator::Schedule(mainPhy->GetDelayUntilIdle(), [=, this]() {
234 // request the main PHY to switch back to the primary link only if in the meantime
235 // no TXOP started on another link (which will require the main PHY to switch link)
236 if (!GetEhtFem(linkId)->UsingOtherEmlsrLink())
237 {
238 SwitchMainPhy(GetMainPhyId(), false, DONT_RESET_BACKOFF, REQUEST_ACCESS);
239 }
240 });
241 }
242}
243
244void
245DefaultEmlsrManager::SwitchMainPhyIfTxopGainedByAuxPhy(uint8_t linkId, AcIndex aci)
246{
247 NS_LOG_FUNCTION(this << linkId << aci);
248 NS_LOG_DEBUG("Do nothing, aux PHY is not TX capable");
249}
250
251Time
252DefaultEmlsrManager::GetTimeToCtsEnd(uint8_t linkId) const
253{
254 NS_LOG_FUNCTION(this << linkId);
255
256 auto phy = GetStaMac()->GetWifiPhy(linkId);
257 NS_ASSERT_MSG(phy, "No PHY operating on link " << +linkId);
258
259 // we have to check whether the main PHY can switch to take over the UL TXOP
260 const auto stationManager = GetStaMac()->GetWifiRemoteStationManager(linkId);
261 const auto bssid = GetEhtFem(linkId)->GetBssid();
262 const auto allowedWidth = GetEhtFem(linkId)->GetAllowedWidth();
263
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());
268
269 // the main PHY shall terminate the channel switch at the end of CTS reception;
270 // the time remaining to the end of CTS reception includes two propagation delays
271 return rtsTxTime + phy->GetSifs() + ctsTxTime + MicroSeconds(2 * MAX_PROPAGATION_DELAY_USEC);
272}
273
274std::pair<bool, Time>
275DefaultEmlsrManager::GetDelayUnlessMainPhyTakesOverUlTxop(uint8_t linkId)
276{
277 NS_LOG_FUNCTION(this << linkId);
278
279 auto mainPhy = GetStaMac()->GetDevice()->GetPhy(m_mainPhyId);
280 auto timeToCtsEnd = GetTimeToCtsEnd(linkId);
281 auto switchingTime = mainPhy->GetChannelSwitchDelay();
282
283 switch (mainPhy->GetState()->GetState())
284 {
285 case WifiPhyState::SWITCHING:
286 // the main PHY is switching (to another link), hence the remaining time to
287 // the end of the current channel switch needs to be added up
288 switchingTime += mainPhy->GetDelayUntilIdle();
289 [[fallthrough]];
290 case WifiPhyState::RX:
291 case WifiPhyState::IDLE:
292 case WifiPhyState::CCA_BUSY:
293 if (switchingTime > timeToCtsEnd)
294 {
295 // switching takes longer than RTS/CTS exchange, release channel
296 NS_LOG_DEBUG("Not enough time for main PHY to switch link (main PHY state: "
297 << mainPhy->GetState()->GetState() << ")");
298 // retry channel access when the CTS was expected to be received
299 return {false, timeToCtsEnd};
300 }
301 break;
302 default:
303 NS_ABORT_MSG("Main PHY cannot be in state " << mainPhy->GetState()->GetState());
304 }
305
306 // TXOP can be started, schedule main PHY switch. Main PHY shall terminate the channel switch
307 // at the end of CTS reception
308 const auto delay = timeToCtsEnd - mainPhy->GetChannelSwitchDelay();
309
310 NS_ASSERT(delay.IsPositive());
311 NS_LOG_DEBUG("Schedule main Phy switch in " << delay.As(Time::US));
312 m_ulMainPhySwitch[linkId] = Simulator::Schedule(delay,
313 &DefaultEmlsrManager::SwitchMainPhy,
314 this,
315 linkId,
316 false,
317 RESET_BACKOFF,
318 DONT_REQUEST_ACCESS);
319
320 return {true, Time{0}};
321}
322
323} // namespace ns3
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.
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.
Definition event-id.cc:44
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.
Definition simulator.h:560
static Time Now()
Return the current simulation virtual time.
Definition simulator.cc:197
Simulation virtual time values and global simulation resolution.
Definition nstime.h:94
TimeWithUnit As(const Unit unit=Time::AUTO) const
Attach a unit to a Time, to facilitate output in a specific unit.
Definition time.cc:404
@ US
microsecond
Definition nstime.h:107
a unique identifier for an interface.
Definition type-id.h:48
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition type-id.cc:1001
void ResumeFromSleep()
Resume from sleep mode.
Definition wifi-phy.cc:1458
void SetSleepMode()
Put in sleep mode.
Definition wifi-phy.cc:1411
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition assert.h:55
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
Definition assert.h:75
#define NS_ABORT_MSG(msg)
Unconditional abnormal program termination with a message.
Definition abort.h:38
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
Definition abort.h:97
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition log.h:191
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition log.h:257
#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.
Definition object-base.h:35
Time MicroSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1332
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition nstime.h:1308
AcIndex
This enumeration defines the Access Categories as an enumeration with values corresponding to the AC ...
Definition qos-utils.h:62
Every class exported by the ns3 library is enclosed in the ns3 namespace.
Ptr< const AttributeChecker > MakeBooleanChecker()
Definition boolean.cc:113
uint32_t GetRtsSize()
Return the total RTS size (including FCS trailer).
Definition wifi-utils.cc:95
Ptr< const AttributeAccessor > MakeBooleanAccessor(T1 a1)
Definition boolean.h:70
uint32_t GetCtsSize()
Return the total CTS size (including FCS trailer).
uint8_t from
ID of the link which the main PHY is/has been leaving.