A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
advanced-emlsr-manager.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2024 Universita' 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/log.h"
15#include "ns3/wifi-net-device.h"
16#include "ns3/wifi-phy.h"
17
18#include <algorithm>
19
20namespace ns3
21{
22
23NS_LOG_COMPONENT_DEFINE("AdvancedEmlsrManager");
24
25NS_OBJECT_ENSURE_REGISTERED(AdvancedEmlsrManager);
26
27TypeId
29{
30 static TypeId tid =
31 TypeId("ns3::AdvancedEmlsrManager")
33 .SetGroupName("Wifi")
34 .AddConstructor<AdvancedEmlsrManager>()
35 .AddAttribute("UseNotifiedMacHdr",
36 "Whether to use the information about the MAC header of the MPDU "
37 "being received, if notified by the PHY.",
38 BooleanValue(true),
41 .AddAttribute("AllowUlTxopInRx",
42 "Whether a (main or aux) PHY is allowed to start an UL TXOP if "
43 "another PHY is receiving a PPDU (possibly starting a DL TXOP). "
44 "If this attribute is true, the PPDU may be dropped.",
45 BooleanValue(false),
48 .AddAttribute("InterruptSwitch",
49 "Whether the main PHY can be interrupted while switching to start "
50 "switching to another link.",
51 BooleanValue(false),
54 .AddAttribute("UseAuxPhyCca",
55 "Whether the CCA performed in the last PIFS interval by a non-TX "
56 "capable aux PHY should be used when the main PHY ends switching to "
57 "the aux PHY's link to determine whether TX can start or not (and what "
58 "bandwidth can be used for transmission) independently of whether the "
59 "aux PHY bandwidth is smaller than the main PHY bandwidth or not.",
60 BooleanValue(false),
63 .AddAttribute("SwitchMainPhyBackDelay",
64 "Duration of the timer started in case of non-TX capable aux PHY (that "
65 "does not switch link) when medium is sensed busy during the PIFS "
66 "interval preceding/following the main PHY switch end. When the timer "
67 "expires, the main PHY is switched back to the primary link.",
71 return tid;
72}
73
78
83
84void
86{
87 NS_LOG_FUNCTION(this);
88 for (auto phy : GetStaMac()->GetDevice()->GetPhys())
89 {
90 phy->TraceDisconnectWithoutContext(
91 "PhyRxMacHeaderEnd",
93 }
95}
96
97void
99{
100 NS_LOG_FUNCTION(this << mac);
101
102 for (auto phy : GetStaMac()->GetDevice()->GetPhys())
103 {
104 phy->TraceConnectWithoutContext(
105 "PhyRxMacHeaderEnd",
107 }
108}
109
110std::pair<bool, Time>
112{
113 NS_LOG_FUNCTION(this << linkId);
114
115 // prevent or allow an UL TXOP depending on whether another PHY is receiving a PPDU
116 for (const auto id : GetStaMac()->GetLinkIds())
117 {
118 if (id != linkId && GetStaMac()->IsEmlsrLink(id))
119 {
120 auto phy = GetStaMac()->GetWifiPhy(id);
121
122 if (auto macHdr = GetEhtFem(id)->GetReceivedMacHdr(); macHdr && m_useNotifiedMacHdr)
123 {
124 NS_ASSERT(phy &&
125 phy->GetState()->GetLastTime({WifiPhyState::RX}) == Simulator::Now());
126 // we are receiving the MAC payload of a PSDU; if the PSDU being received on
127 // another link is an ICF, give up the TXOP and restart channel access at the
128 // end of PSDU reception. Note that we cannot be sure that the PSDU being received
129 // is an ICF addressed to us until we receive the entire PSDU
130 if (const auto& hdr = macHdr->get();
131 hdr.IsTrigger() &&
132 (hdr.GetAddr1().IsBroadcast() || hdr.GetAddr1() == GetEhtFem(id)->GetAddress()))
133 {
134 return {false, phy->GetDelayUntilIdle()};
135 }
136 continue;
137 }
138
139 if (phy && phy->IsReceivingPhyHeader())
140 {
141 // we don't know yet the type of the frame being received; prevent or allow
142 // the UL TXOP based on user configuration
144 {
145 // retry channel access after the end of the current PHY header field
146 return {false, phy->GetDelayUntilIdle()};
147 }
148 continue;
149 }
150
151 if (phy && phy->IsStateRx())
152 {
153 // we don't know yet the type of the frame being received; prevent or allow
154 // the UL TXOP based on user configuration
156 {
158 {
159 // restart channel access at the end of PSDU reception
160 return {false, phy->GetDelayUntilIdle()};
161 }
162
163 // retry channel access after the expected end of the MAC header reception
165 4 /* A-MPDU subframe header length */;
166 auto ongoingRxInfo = GetEhtFem(id)->GetOngoingRxInfo();
167 // if a PHY is in RX state, it should have info about received MAC header.
168 // The exception is represented by this situation:
169 // - an aux PHY is disconnected from the MAC stack because the main PHY is
170 // operating on its link
171 // - the main PHY notifies the MAC header info to the FEM and then leaves the
172 // link (e.g., because it recognizes that the MPDU is not addressed to the
173 // EMLSR client). Disconnecting the main PHY from the MAC stack causes the
174 // MAC header info to be discarded by the FEM
175 // - the aux PHY is re-connected to the MAC stack and is still in RX state
176 // when the main PHY gets channel access on another link (and we get here)
177 if (!ongoingRxInfo.has_value())
178 {
179 NS_ASSERT_MSG(phy != GetStaMac()->GetDevice()->GetPhy(GetMainPhyId()),
180 "Main PHY should have MAC header info when in RX state");
181 // we are in the situation described above; if the MPDU being received
182 // by the aux PHY is not addressed to the EMLSR client, we can ignore it
183 continue;
184 }
185 const auto& txVector = ongoingRxInfo->get().txVector;
186 if (txVector.IsMu())
187 {
188 // this is not an ICF, ignore it
189 continue;
190 }
191 auto macHdrDuration = DataRate(txVector.GetMode().GetDataRate(txVector))
192 .CalculateBytesTxTime(macHdrSize);
193 const auto timeSinceRxStart =
194 Simulator::Now() - phy->GetState()->GetLastTime({WifiPhyState::CCA_BUSY});
195 return {false, Max(macHdrDuration - timeSinceRxStart, Time{0})};
196 }
197 continue;
198 }
199 }
200 }
201
202 return {true, Time{0}};
203}
204
205void
207 const WifiMacHeader& macHdr,
208 const WifiTxVector& txVector,
209 Time psduDuration)
210{
211 auto linkId = GetStaMac()->GetLinkForPhy(phy);
212 if (!linkId.has_value())
213 {
214 return;
215 }
216 NS_LOG_FUNCTION(this << *linkId << macHdr << txVector << psduDuration.As(Time::MS));
217
218 auto& ongoingTxopEnd = GetEhtFem(*linkId)->GetOngoingTxopEndEvent();
219
220 if (m_useNotifiedMacHdr && ongoingTxopEnd.IsPending() &&
221 macHdr.GetAddr1() != GetEhtFem(*linkId)->GetAddress() && !macHdr.GetAddr1().IsBroadcast() &&
222 !(macHdr.IsCts() && macHdr.GetAddr1() == GetEhtFem(*linkId)->GetBssid() /* CTS-to-self */))
223 {
224 // the EMLSR client is no longer involved in the TXOP and switching to listening mode
225 ongoingTxopEnd.Cancel();
226 // this method is a callback connected to the PhyRxMacHeaderEnd trace source of WifiPhy
227 // and is called within a for loop that executes all the callbacks. The call to NotifyTxop
228 // below leads the main PHY to be connected back to the primary link, thus
229 // the ResetPhy() method of the FEM on the non-primary link is called, which disconnects
230 // another callback (FEM::ReceivedMacHdr) from the PhyRxMacHeaderEnd trace source of
231 // the main PHY, thus invalidating the list of callbacks on which the for loop iterates.
232 // Hence, schedule the call to NotifyTxopEnd to execute it outside such for loop.
233 Simulator::ScheduleNow(&AdvancedEmlsrManager::NotifyTxopEnd, this, *linkId, false, false);
234 }
235}
236
237void
239{
240 NS_LOG_FUNCTION(this << linkId);
241
242 auto mainPhy = GetStaMac()->GetDevice()->GetPhy(m_mainPhyId);
243
244 if (m_switchAuxPhy && (!mainPhy->IsStateSwitching() || !m_interruptSwitching))
245 {
246 NS_LOG_DEBUG("SwitchAuxPhy true, nothing to do");
247 return;
248 }
249
251 {
252 NS_LOG_DEBUG("SwitchAuxPhy false, nothing to do");
253 return;
254 }
255
256 // we get here if:
257 // - SwitchAuxPhy is true, the main PHY is switching and switching can be interrupted
258 // or
259 // - SwitchAuxPhy is false and there is an aux PHY to reconnect
260
261 // Note that the main PHY may be switching at the end of a TXOP when, e.g., the main PHY
262 // starts switching to a link on which an aux PHY gained a TXOP and sent an RTS, but the CTS
263 // is not received and the UL TXOP ends before the main PHY channel switch is completed.
264 // In such cases, wait until the main PHY channel switch is completed (unless the channel
265 // switching can be interrupted) before requesting a new channel switch. Given that the
266 // TXOP ended, the event to put the aux PHY to sleep can be cancelled.
267 // Backoff shall not be reset on the link left by the main PHY because a TXOP ended and
268 // a new backoff value must be generated.
270
271 if (m_switchAuxPhy || !mainPhy->IsStateSwitching() || m_interruptSwitching)
272 {
275 "Aux PHY next link ID should have a value when interrupting a main PHY switch");
276 uint8_t nextLinkId = m_switchAuxPhy ? m_mainPhySwitchInfo.from : GetMainPhyId();
278 }
279 else
280 {
281 // delay link switch until current channel switching is completed
282 Simulator::Schedule(mainPhy->GetDelayUntilIdle(), [=, this]() {
283 // request the main PHY to switch back to the primary link only if in the meantime
284 // no TXOP started on another link (which will require the main PHY to switch link)
285 if (!GetEhtFem(linkId)->UsingOtherEmlsrLink())
286 {
287 SwitchMainPhy(GetMainPhyId(), false, DONT_RESET_BACKOFF, REQUEST_ACCESS);
288 }
289 });
290 }
291}
292
293std::pair<bool, Time>
294AdvancedEmlsrManager::GetDelayUnlessMainPhyTakesOverUlTxop(uint8_t linkId)
295{
296 NS_LOG_FUNCTION(this << linkId);
297
298 if (!m_interruptSwitching)
299 {
300 return DefaultEmlsrManager::GetDelayUnlessMainPhyTakesOverUlTxop(linkId);
301 }
302
303 auto mainPhy = GetStaMac()->GetDevice()->GetPhy(m_mainPhyId);
304 auto state = mainPhy->GetState()->GetState();
305
306 NS_ABORT_MSG_UNLESS(state == WifiPhyState::SWITCHING || state == WifiPhyState::RX ||
307 state == WifiPhyState::IDLE || state == WifiPhyState::CCA_BUSY,
308 "Main PHY cannot be in state " << state);
309
310 auto timeToCtsEnd = GetTimeToCtsEnd(linkId);
311 auto switchingTime = mainPhy->GetChannelSwitchDelay();
312
313 if (switchingTime > timeToCtsEnd)
314 {
315 // switching takes longer than RTS/CTS exchange, release channel
316 NS_LOG_DEBUG("Not enough time for main PHY to switch link (main PHY state: "
317 << mainPhy->GetState()->GetState() << ")");
318 // retry channel access when the CTS was expected to be received
319 return {false, timeToCtsEnd};
320 }
321
322 // TXOP can be started, schedule main PHY switch. Main PHY shall terminate the channel switch
323 // at the end of CTS reception
324 const auto delay = timeToCtsEnd - switchingTime;
325
326 NS_ASSERT(delay.IsPositive());
327 NS_LOG_DEBUG("Schedule main Phy switch in " << delay.As(Time::US));
328 m_ulMainPhySwitch[linkId] = Simulator::Schedule(delay,
329 &AdvancedEmlsrManager::SwitchMainPhy,
330 this,
331 linkId,
332 false,
333 RESET_BACKOFF,
334 DONT_REQUEST_ACCESS);
335
336 return {true, Time{0}};
337}
338
339void
340AdvancedEmlsrManager::CheckNavAndCcaLastPifs(Ptr<WifiPhy> phy, uint8_t linkId, Ptr<QosTxop> edca)
341{
342 NS_LOG_FUNCTION(this << phy->GetPhyId() << linkId << edca->GetAccessCategory());
343
344 const auto caManager = GetStaMac()->GetChannelAccessManager(linkId);
345 const auto pifs = phy->GetSifs() + phy->GetSlot();
346
347 const auto isBusy = caManager->IsBusy(); // check NAV and CCA on primary20
348 // check CCA on the entire channel
349 auto width = caManager->GetLargestIdlePrimaryChannel(pifs, Simulator::Now());
350
351 if (!isBusy && width > 0)
352 {
353 // medium idle, start TXOP
354 width = std::min(width, GetChannelForMainPhy(linkId).GetTotalWidth());
355
356 // if this function is called at the end of the main PHY switch, it is executed before the
357 // main PHY is connected to this link in order to use the CCA information of the aux PHY.
358 // Schedule now the TXOP start so that we first connect the main PHY to this link.
359 m_ccaLastPifs = Simulator::ScheduleNow([=, this]() {
360 if (GetEhtFem(linkId)->HeFrameExchangeManager::StartTransmission(edca, width))
361 {
362 NotifyUlTxopStart(linkId);
363 }
364 else if (!m_switchAuxPhy)
365 {
366 // switch main PHY back to primary link if SwitchAuxPhy is false
367 SwitchMainPhyBackToPrimaryLink(linkId);
368 }
369 });
370 }
371 else
372 {
373 // medium busy, restart channel access
374 NS_LOG_DEBUG("Medium busy in the last PIFS interval");
375 edca->NotifyChannelReleased(linkId); // to set access to NOT_REQUESTED
376 edca->StartAccessAfterEvent(linkId,
377 Txop::DIDNT_HAVE_FRAMES_TO_TRANSMIT,
378 Txop::CHECK_MEDIUM_BUSY);
379
380 // the main PHY must stay for some time on this link to check if it gets channel access.
381 // The timer is stopped if a DL or UL TXOP is started. When the timer expires, the main PHY
382 // switches back to the preferred link if SwitchAuxPhy is false
383 m_switchMainPhyBackEvent = Simulator::Schedule(m_switchMainPhyBackDelay, [this, linkId]() {
384 if (!m_switchAuxPhy)
385 {
386 SwitchMainPhyBackToPrimaryLink(linkId);
387 }
388 });
389 }
390}
391
392void
393AdvancedEmlsrManager::DoNotifyIcfReceived(uint8_t linkId)
394{
395 NS_LOG_FUNCTION(this << linkId);
396 m_switchMainPhyBackEvent.Cancel();
397 m_ccaLastPifs.Cancel();
398}
399
400void
401AdvancedEmlsrManager::DoNotifyUlTxopStart(uint8_t linkId)
402{
403 NS_LOG_FUNCTION(this << linkId);
404 m_switchMainPhyBackEvent.Cancel();
405 m_ccaLastPifs.Cancel();
406}
407
408bool
409AdvancedEmlsrManager::RequestMainPhyToSwitch(uint8_t linkId, AcIndex aci)
410{
411 NS_LOG_FUNCTION(this << linkId << aci);
412
413 // the aux PHY is not TX capable; check if main PHY has to switch to the aux PHY's link
414 auto mainPhy = GetStaMac()->GetDevice()->GetPhy(m_mainPhyId);
415 const auto mainPhyLinkId = GetStaMac()->GetLinkForPhy(mainPhy);
416
417 // if main PHY is not operating on a link, it is switching, hence do not request another switch
418 if (!mainPhyLinkId.has_value())
419 {
420 NS_LOG_DEBUG("Main PHY is not operating on any link");
421 return false;
422 }
423
424 // if the main PHY is already trying to get access on a link, do not request another switch
425 if (m_ccaLastPifs.IsPending() || m_switchMainPhyBackEvent.IsPending())
426 {
427 NS_LOG_DEBUG("Main PHY is trying to get access on another link");
428 return false;
429 }
430
431 switch (mainPhy->GetState()->GetState())
432 {
433 case WifiPhyState::IDLE:
434 // proceed to try requesting main PHY to switch
435 break;
436 case WifiPhyState::CCA_BUSY:
437 // if the main PHY is receiving the PHY header of a PPDU, we decide to proceed or give up
438 // based on the AllowUlTxopInRx attribute
439 if (mainPhy->IsReceivingPhyHeader() && !m_allowUlTxopInRx)
440 {
441 NS_LOG_DEBUG("Main PHY receiving PHY header and AllowUlTxopInRx is false");
442 return false;
443 }
444 break;
445 case WifiPhyState::RX:
446 if (auto macHdr = GetEhtFem(*mainPhyLinkId)->GetReceivedMacHdr())
447 {
448 // information on the MAC header of the PSDU being received is available; if we cannot
449 // use it or the main PHY is receiving an ICF, give up requesting main PHY to switch
450 if (const auto& hdr = macHdr->get();
451 !m_useNotifiedMacHdr ||
452 (hdr.IsTrigger() && (hdr.GetAddr1().IsBroadcast() ||
453 hdr.GetAddr1() == GetEhtFem(*mainPhyLinkId)->GetAddress())))
454 {
455 NS_LOG_DEBUG("Receiving an ICF or cannot use MAC header information");
456 return false;
457 }
458 }
459 // information on the MAC header of the PSDU being received is not available, we decide to
460 // proceed or give up based on the AllowUlTxopInRx attribute
461 else if (!m_allowUlTxopInRx)
462 {
463 NS_LOG_DEBUG("Receiving PSDU, no MAC header information, AllowUlTxopInRx is false");
464 return false;
465 }
466 break;
467 default:
468 NS_LOG_DEBUG("Cannot request main PHY to switch when in state "
469 << mainPhy->GetState()->GetState());
470 return false;
471 }
472
473 // request to switch main PHY if we expect the main PHY to get channel access on this link
474 // more quickly, i.e., if ALL the ACs with queued frames (that can be transmitted on the link
475 // on which the main PHY is currently operating) and with priority higher than or equal to
476 // that of the AC for which Aux PHY gained TXOP have their backoff counter greater than the
477 // channel switch delay plus PIFS
478
479 auto requestSwitch = false;
480 const auto now = Simulator::Now();
481
482 for (const auto& [acIndex, ac] : wifiAcList)
483 {
484 if (auto edca = GetStaMac()->GetQosTxop(acIndex);
485 acIndex >= aci && edca->HasFramesToTransmit(linkId))
486 {
487 requestSwitch = true;
488
489 const auto backoffEnd =
490 GetStaMac()->GetChannelAccessManager(*mainPhyLinkId)->GetBackoffEndFor(edca);
491 NS_LOG_DEBUG("Backoff end for " << acIndex
492 << " on primary link: " << backoffEnd.As(Time::US));
493
494 if (backoffEnd <= now + mainPhy->GetChannelSwitchDelay() +
495 GetStaMac()->GetWifiPhy(linkId)->GetPifs() &&
496 edca->HasFramesToTransmit(*mainPhyLinkId))
497 {
498 requestSwitch = false;
499 break;
500 }
501 }
502 }
503
504 return requestSwitch;
505}
506
507void
508AdvancedEmlsrManager::SwitchMainPhyIfTxopGainedByAuxPhy(uint8_t linkId, AcIndex aci)
509{
510 NS_LOG_FUNCTION(this << linkId << aci);
511
512 NS_ASSERT_MSG(!m_auxPhyTxCapable,
513 "This function should only be called if aux PHY is not TX capable");
514 auto mainPhy = GetStaMac()->GetDevice()->GetPhy(m_mainPhyId);
515
516 if (RequestMainPhyToSwitch(linkId, aci))
517 {
518 const auto auxPhy = GetStaMac()->GetWifiPhy(linkId);
519 const auto pifs = auxPhy->GetSifs() + auxPhy->GetSlot();
520
521 // schedule actions to take based on CCA sensing for a PIFS
522 if (m_useAuxPhyCca || GetChannelForAuxPhy(linkId).GetTotalWidth() >=
523 GetChannelForMainPhy(linkId).GetTotalWidth())
524 {
525 // use aux PHY CCA in the last PIFS interval before main PHY switch end
526 NS_LOG_DEBUG("Schedule CCA check at the end of main PHY switch");
527 m_ccaLastPifs = Simulator::Schedule(mainPhy->GetChannelSwitchDelay(),
528 &AdvancedEmlsrManager::CheckNavAndCcaLastPifs,
529 this,
530 auxPhy,
531 linkId,
532 GetStaMac()->GetQosTxop(aci));
533 }
534 else
535 {
536 // use main PHY CCA in the last PIFS interval after main PHY switch end
537 NS_LOG_DEBUG("Schedule CCA check a PIFS after the end of main PHY switch");
538 m_ccaLastPifs = Simulator::Schedule(mainPhy->GetChannelSwitchDelay() + pifs,
539 &AdvancedEmlsrManager::CheckNavAndCcaLastPifs,
540 this,
541 mainPhy,
542 linkId,
543 GetStaMac()->GetQosTxop(aci));
544 }
545
546 // switch main PHY
547 SwitchMainPhy(linkId, false, RESET_BACKOFF, DONT_REQUEST_ACCESS);
548 return;
549 }
550
551 // Determine if and when we need to request channel access again for the aux PHY based on
552 // the main PHY state.
553 // Note that, if we have requested the main PHY to switch (above), the function has returned
554 // and the EHT FEM will start a TXOP if medium is idle for a PIFS interval preceding/following
555 // the end of the main PHY channel switch.
556 // If the main PHY has been requested to switch by another aux PHY, this aux PHY will request
557 // channel access again when we have completed the CCA assessment on the other link.
558 // If the state is switching, CCA_BUSY or RX, then we request channel access again for the
559 // aux PHY when the main PHY state is back to IDLE.
560 // If the state is TX, it means that the main PHY is involved in a TXOP. Do nothing because
561 // the channel access will be requested when unblocking links at the end of the TXOP.
562 // If the state is IDLE, then either no AC has traffic to send or the backoff on the link
563 // of the main PHY is shorter than the channel switch delay. In the former case, do
564 // nothing because channel access will be triggered when new packets arrive; in the latter
565 // case, do nothing because the main PHY will start a TXOP and at the end of such TXOP
566 // links will be unblocked and the channel access requested on all links
567
568 Time delay{};
569
570 if (m_ccaLastPifs.IsPending() || m_switchMainPhyBackEvent.IsPending())
571 {
572 delay = std::max(Simulator::GetDelayLeft(m_ccaLastPifs),
573 Simulator::GetDelayLeft(m_switchMainPhyBackEvent));
574 }
575 else if (mainPhy->IsStateSwitching() || mainPhy->IsStateCcaBusy() || mainPhy->IsStateRx())
576 {
577 delay = mainPhy->GetDelayUntilIdle();
578 NS_ASSERT(delay.IsStrictlyPositive());
579 }
580
581 NS_LOG_DEBUG("Main PHY state is " << mainPhy->GetState()->GetState());
582
583 if (delay.IsZero())
584 {
585 NS_LOG_DEBUG("Do nothing");
586 return;
587 }
588
589 auto edca = GetStaMac()->GetQosTxop(aci);
590 edca->NotifyChannelReleased(linkId); // to set access to NOT_REQUESTED
591
592 NS_LOG_DEBUG("Schedule channel access request on link "
593 << +linkId << " at time " << (Simulator::Now() + delay).As(Time::NS));
594 Simulator::Schedule(delay, [=]() {
595 edca->StartAccessAfterEvent(linkId,
596 Txop::DIDNT_HAVE_FRAMES_TO_TRANSMIT,
597 Txop::CHECK_MEDIUM_BUSY);
598 });
599}
600
601} // namespace ns3
#define Max(a, b)
AdvancedEmlsrManager is an advanced EMLSR manager.
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...
bool m_useAuxPhyCca
whether the CCA performed in the last PIFS interval by a non-TX capable aux PHY should be used when t...
bool m_allowUlTxopInRx
whether a (main or aux) PHY is allowed to start an UL TXOP if another PHY is receiving a PPDU
void DoNotifyTxopEnd(uint8_t linkId) override
Notify the subclass of the end of a TXOP on the given link.
static TypeId GetTypeId()
Get the type ID.
bool m_useNotifiedMacHdr
whether to use the information about the MAC header of the MPDU being received (if notified by the PH...
Time m_switchMainPhyBackDelay
duration of the timer started in case of non-TX capable aux PHY when medium is sensed busy during the...
void DoDispose() override
Destructor implementation.
void DoSetWifiMac(Ptr< StaWifiMac > mac) override
Allow subclasses to take actions when the MAC is set.
void ReceivedMacHdr(Ptr< WifiPhy > phy, const WifiMacHeader &macHdr, const WifiTxVector &txVector, Time psduDuration)
Possibly take actions when notified of the MAC header of the MPDU being received by the given PHY.
bool m_interruptSwitching
whether a main PHY switching can be interrupted to start switching to another link
Class for representing data rates.
Definition data-rate.h:78
Time CalculateBytesTxTime(uint32_t bytes) const
Calculate transmission time.
Definition data-rate.cc:220
DefaultEmlsrManager is the default EMLSR manager.
Ptr< WifiPhy > m_auxPhyToReconnect
Aux PHY the ChannelAccessManager of the link on which the main PHY is operating has to connect a list...
bool m_switchAuxPhy
whether Aux PHY should switch channel to operate on the link on which the Main PHY was operating befo...
EventId m_auxPhyToSleepEvent
the event scheduled to put an Aux PHY into sleep mode
MainPhySwitchInfo m_mainPhySwitchInfo
main PHY switch info
Ptr< EhtFrameExchangeManager > GetEhtFem(uint8_t linkId) const
void NotifyTxopEnd(uint8_t linkId, bool ulTxopNotStarted=false, bool ongoingDlTxop=false)
Notify the end of a TXOP on the given link.
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)
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
bool IsBroadcast() const
virtual void DoDispose()
Destructor implementation.
Definition object.cc:433
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
static EventId ScheduleNow(FUNC f, Ts &&... args)
Schedule an event to expire Now.
Definition simulator.h:594
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
@ MS
millisecond
Definition nstime.h:106
a unique identifier for an interface.
Definition type-id.h:48
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition type-id.cc:1001
Implements the IEEE 802.11 MAC header.
bool IsCts() const
Return true if the header is a CTS header.
uint32_t GetSerializedSize() const override
Mac48Address GetAddr1() const
Return the address in the Address 1 field.
This class mimics the TXVECTOR which is to be passed to the PHY in order to define the parameters whi...
#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_UNLESS(cond, msg)
Abnormal program termination if a condition is false, with a message.
Definition abort.h:133
#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 MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1320
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
@ CCA_BUSY
The PHY layer has sense the medium busy through the CCA mechanism.
Ptr< const AttributeAccessor > MakeTimeAccessor(T1 a1)
Definition nstime.h:1396
Callback< R, Args... > MakeCallback(R(T::*memPtr)(Args...), OBJ objPtr)
Build Callbacks for class method members which take varying numbers of arguments and potentially retu...
Definition callback.h:684
const std::map< AcIndex, WifiAc > wifiAcList
Map containing the four ACs in increasing order of priority (according to Table 10-1 "UP-to-AC Mappin...
Definition qos-utils.cc:115
@ WIFI_MAC_QOSDATA
Ptr< const AttributeAccessor > MakeBooleanAccessor(T1 a1)
Definition boolean.h:70
Ptr< const AttributeChecker > MakeTimeChecker()
Helper to make an unbounded Time checker.
Definition nstime.h:1416
uint8_t from
ID of the link which the main PHY is/has been leaving.