A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
rr-multi-user-scheduler.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2020 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
11#include "he-configuration.h"
12#include "he-phy.h"
13
14#include "ns3/eht-frame-exchange-manager.h"
15#include "ns3/log.h"
16#include "ns3/wifi-acknowledgment.h"
17#include "ns3/wifi-mac-queue.h"
18#include "ns3/wifi-protection.h"
19#include "ns3/wifi-psdu.h"
20
21#include <algorithm>
22#include <numeric>
23
24namespace ns3
25{
26
27NS_LOG_COMPONENT_DEFINE("RrMultiUserScheduler");
28
29NS_OBJECT_ENSURE_REGISTERED(RrMultiUserScheduler);
30
31TypeId
33{
34 static TypeId tid =
35 TypeId("ns3::RrMultiUserScheduler")
37 .SetGroupName("Wifi")
38 .AddConstructor<RrMultiUserScheduler>()
39 .AddAttribute("NStations",
40 "The maximum number of stations that can be granted an RU in a DL MU "
41 "OFDMA transmission",
45 .AddAttribute("EnableTxopSharing",
46 "If enabled, allow A-MPDUs of different TIDs in a DL MU PPDU.",
47 BooleanValue(true),
50 .AddAttribute("ForceDlOfdma",
51 "If enabled, return DL_MU_TX even if no DL MU PPDU could be built.",
52 BooleanValue(false),
55 .AddAttribute("EnableUlOfdma",
56 "If enabled, return UL_MU_TX if DL_MU_TX was returned the previous time.",
57 BooleanValue(true),
60 .AddAttribute("EnableBsrp",
61 "If enabled, send a BSRP Trigger Frame before an UL MU transmission.",
62 BooleanValue(true),
65 .AddAttribute(
66 "UlPsduSize",
67 "The default size in bytes of the solicited PSDU (to be sent in a TB PPDU)",
68 UintegerValue(500),
71 .AddAttribute("UseCentral26TonesRus",
72 "If enabled, central 26-tone RUs are allocated, too, when the "
73 "selected RU type is at least 52 tones.",
74 BooleanValue(false),
77 .AddAttribute(
78 "MaxCredits",
79 "Maximum amount of credits a station can have. When transmitting a DL MU PPDU, "
80 "the amount of credits received by each station equals the TX duration (in "
81 "microseconds) divided by the total number of stations. Stations that are the "
82 "recipient of the DL MU PPDU have to pay a number of credits equal to the TX "
83 "duration (in microseconds) times the allocated bandwidth share",
87 return tid;
88}
89
94
99
100void
102{
103 NS_LOG_FUNCTION(this);
105 m_apMac->TraceConnectWithoutContext(
106 "AssociatedSta",
108 m_apMac->TraceConnectWithoutContext(
109 "DeAssociatedSta",
111 for (const auto& ac : wifiAcList)
112 {
113 m_staListDl.insert({ac.first, {}});
114 }
116}
117
118void
120{
121 NS_LOG_FUNCTION(this);
122 m_staListDl.clear();
123 m_staListUl.clear();
124 m_candidates.clear();
126 m_apMac->TraceDisconnectWithoutContext(
127 "AssociatedSta",
129 m_apMac->TraceDisconnectWithoutContext(
130 "DeAssociatedSta",
133}
134
137{
138 NS_LOG_FUNCTION(this);
139
141
142 if (mpdu && !m_apMac->GetHeSupported(mpdu->GetHeader().GetAddr1()))
143 {
144 return SU_TX;
145 }
146
150 {
151 TxFormat txFormat = TrySendingBsrpTf();
152
153 if (txFormat != DL_MU_TX)
154 {
155 return txFormat;
156 }
157 }
160 {
161 TxFormat txFormat = TrySendingBasicTf();
162
163 if (txFormat != DL_MU_TX)
164 {
165 return txFormat;
166 }
167 }
168
169 return TrySendingDlMuPpdu();
170}
171
173RrMultiUserScheduler::GetTxVectorForUlMu(std::function<bool(const MasterInfo&)> canBeSolicited)
174{
175 NS_LOG_FUNCTION(this);
176
177 // determine RUs to allocate to stations
178 auto count = std::min<std::size_t>(m_nStations, m_staListUl.size());
179 std::size_t nCentral26TonesRus;
181 count,
182 nCentral26TonesRus,
184 NS_ASSERT(count >= 1);
185
187 {
188 nCentral26TonesRus = 0;
189 }
190
191 Ptr<HeConfiguration> heConfiguration = m_apMac->GetHeConfiguration();
192 NS_ASSERT(heConfiguration);
193
194 WifiTxVector txVector;
197 txVector.SetGuardInterval(heConfiguration->GetGuardInterval());
198 txVector.SetBssColor(heConfiguration->m_bssColor);
199
200 // iterate over the associated stations until an enough number of stations is identified
201 auto staIt = m_staListUl.begin();
202 m_candidates.clear();
203
204 while (staIt != m_staListUl.end() &&
205 txVector.GetHeMuUserInfoMap().size() <
206 std::min<std::size_t>(m_nStations, count + nCentral26TonesRus))
207 {
208 NS_LOG_DEBUG("Next candidate STA (MAC=" << staIt->address << ", AID=" << staIt->aid << ")");
209
210 if (!canBeSolicited(*staIt))
211 {
212 NS_LOG_DEBUG("Skipping station based on provided function object");
213 staIt++;
214 continue;
215 }
216
217 if (txVector.GetPreambleType() == WIFI_PREAMBLE_EHT_TB &&
218 !m_apMac->GetEhtSupported(staIt->address))
219 {
221 "Skipping non-EHT STA because this Trigger Frame is only soliciting EHT STAs");
222 staIt++;
223 continue;
224 }
225
226 uint8_t tid = 0;
227 while (tid < 8)
228 {
229 // check that a BA agreement is established with the receiver for the
230 // considered TID, since ack sequences for UL MU require block ack
231 if (m_apMac->GetBaAgreementEstablishedAsRecipient(staIt->address, tid))
232 {
233 break;
234 }
235 ++tid;
236 }
237 if (tid == 8)
238 {
239 NS_LOG_DEBUG("No Block Ack agreement established with " << staIt->address);
240 staIt++;
241 continue;
242 }
243
244 // if the first candidate STA is an EHT STA, we switch to soliciting EHT TB PPDUs
245 if (txVector.GetHeMuUserInfoMap().empty())
246 {
247 if (m_apMac->GetEhtSupported() && m_apMac->GetEhtSupported(staIt->address))
248 {
250 txVector.SetEhtPpduType(0);
251 }
252 // TODO otherwise, make sure the TX width does not exceed 160 MHz
253 }
254
255 // prepare the MAC header of a frame that would be sent to the candidate station,
256 // just for the purpose of retrieving the TXVECTOR used to transmit to that station
259 ->GetAffiliatedStaAddress(staIt->address)
260 .value_or(staIt->address));
261 hdr.SetAddr2(m_apMac->GetFrameExchangeManager(m_linkId)->GetAddress());
262 WifiTxVector suTxVector =
264 txVector.SetHeMuUserInfo(staIt->aid,
265 {HeRu::RuSpec(), // assigned later by FinalizeTxVector
266 suTxVector.GetMode().GetMcsValue(),
267 suTxVector.GetNss()});
268 m_candidates.emplace_back(staIt, nullptr);
269
270 // move to the next station in the list
271 staIt++;
272 }
273
274 if (txVector.GetHeMuUserInfoMap().empty())
275 {
276 NS_LOG_DEBUG("No suitable station");
277 return txVector;
278 }
279
280 FinalizeTxVector(txVector);
281 return txVector;
282}
283
284bool
286{
287 // check if station has setup the current link
288 if (!m_apMac->GetStaList(m_linkId).contains(info.aid))
289 {
290 NS_LOG_INFO("STA with AID " << info.aid << " has not setup link " << +m_linkId);
291 return false;
292 }
293
294 auto mldAddr = GetWifiRemoteStationManager(m_linkId)->GetMldAddress(info.address);
295
296 // remaining checks are for MLDs only
297 if (!mldAddr)
298 {
299 return true;
300 }
301
302 // check if at least one TID is mapped on the current link in the UL direction
303 bool mapped = false;
304 for (uint8_t tid = 0; tid < 8; ++tid)
305 {
306 if (m_apMac->TidMappedOnLink(*mldAddr, WifiDirection::UPLINK, tid, m_linkId))
307 {
308 mapped = true;
309 break;
310 }
311 }
312
313 if (!mapped)
314 {
315 NS_LOG_DEBUG("MLD " << *mldAddr << " has not mapped any TID on link " << +m_linkId);
316 return false;
317 }
318
319 // check if the station is an EMLSR client that is using another link
320 if (GetWifiRemoteStationManager(m_linkId)->GetEmlsrEnabled(info.address) &&
321 (m_apMac->GetTxBlockedOnLink(AC_BE,
322 {WIFI_QOSDATA_QUEUE, WIFI_UNICAST, *mldAddr, 0},
323 m_linkId,
325 m_apMac->GetTxBlockedOnLink(AC_BE,
326 {WIFI_QOSDATA_QUEUE, WIFI_UNICAST, *mldAddr, 0},
327 m_linkId,
329 {
330 NS_LOG_INFO("EMLSR client " << *mldAddr << " is using another link");
331 return false;
332 }
333
334 return true;
335}
336
339{
340 NS_LOG_FUNCTION(this);
341
342 if (m_staListUl.empty())
343 {
344 NS_LOG_DEBUG("No HE stations associated: return SU_TX");
345 return TxFormat::SU_TX;
346 }
347
348 auto txVector = GetTxVectorForUlMu(
349 std::bind(&RrMultiUserScheduler::CanSolicitStaInBsrpTf, this, std::placeholders::_1));
350
351 if (txVector.GetHeMuUserInfoMap().empty())
352 {
353 NS_LOG_DEBUG("No suitable station found");
354 return TxFormat::DL_MU_TX;
355 }
356
358 txVector.SetGuardInterval(m_trigger.GetGuardInterval());
359
360 auto item = GetTriggerFrame(m_trigger, m_linkId);
361 m_triggerMacHdr = item->GetHeader();
362
364 // set the TXVECTOR used to send the Trigger Frame
366 m_apMac->GetWifiRemoteStationManager(m_linkId)->GetRtsTxVector(m_triggerMacHdr.GetAddr1(),
368
369 // If this BSRP TF is an ICF, we need to add padding and adjust the TXVECTOR
370 if (auto ehtFem =
371 DynamicCast<EhtFrameExchangeManager>(m_apMac->GetFrameExchangeManager(m_linkId)))
372 {
373 auto prevPaddingSize = m_trigger.GetPaddingSize();
374 ehtFem->SetIcfPaddingAndTxVector(m_trigger, m_txParams.m_txVector);
375 // serialize again if padding has been added
376 if (m_trigger.GetPaddingSize() != prevPaddingSize)
377 {
378 auto packet = Create<Packet>();
379 packet->AddHeader(m_trigger);
380 item = Create<WifiMpdu>(packet, item->GetHeader());
381 }
382 }
383
384 if (!GetHeFem(m_linkId)->TryAddMpdu(item, m_txParams, m_availableTime))
385 {
386 // sending the BSRP Trigger Frame is not possible, hence return NO_TX. In
387 // this way, no transmission will occur now and the next time we will
388 // try again sending a BSRP Trigger Frame.
389 NS_LOG_DEBUG("Remaining TXOP duration is not enough for BSRP TF exchange");
390 return NO_TX;
391 }
392
393 // Compute the time taken by each station to transmit 8 QoS Null frames
394 Time qosNullTxDuration;
395 for (const auto& userInfo : m_trigger)
396 {
398 txVector,
399 m_apMac->GetWifiPhy(m_linkId)->GetPhyBand(),
400 userInfo.GetAid12());
401 qosNullTxDuration = Max(qosNullTxDuration, duration);
402 }
403
404 NS_ASSERT(m_txParams.m_txDuration.has_value());
406
407 if (m_availableTime != Time::Min())
408 {
409 // TryAddMpdu only considers the time to transmit the Trigger Frame
410 NS_ASSERT(m_txParams.m_protection && m_txParams.m_protection->protectionTime.has_value());
412 m_txParams.m_acknowledgment->acknowledgmentTime.has_value() &&
413 m_txParams.m_acknowledgment->acknowledgmentTime->IsZero());
414
415 if (*m_txParams.m_protection->protectionTime + *m_txParams.m_txDuration // BSRP TF tx time
416 + m_apMac->GetWifiPhy(m_linkId)->GetSifs() + qosNullTxDuration >
418 {
419 NS_LOG_DEBUG("Remaining TXOP duration is not enough for BSRP TF exchange");
420 return NO_TX;
421 }
422 }
423
424 uint16_t ulLength;
425 std::tie(ulLength, qosNullTxDuration) = HePhy::ConvertHeTbPpduDurationToLSigLength(
426 qosNullTxDuration,
428 m_apMac->GetWifiPhy(m_linkId)->GetPhyBand());
429 NS_LOG_DEBUG("Duration of QoS Null frames: " << qosNullTxDuration.As(Time::MS));
430 m_trigger.SetUlLength(ulLength);
431
432 return UL_MU_TX;
433}
434
435bool
437{
438 // in addition to the checks performed when sending a BSRP TF, also check if the station
439 // has reported a null queue size
440 if (!CanSolicitStaInBsrpTf(info))
441 {
442 return false;
443 }
444
445 return m_apMac->GetMaxBufferStatus(info.address) > 0;
446}
447
450{
451 NS_LOG_FUNCTION(this);
452
453 if (m_staListUl.empty())
454 {
455 NS_LOG_DEBUG("No HE stations associated: return SU_TX");
456 return TxFormat::SU_TX;
457 }
458
459 // check if an UL OFDMA transmission is possible after a DL OFDMA transmission
460 NS_ABORT_MSG_IF(m_ulPsduSize == 0, "The UlPsduSize attribute must be set to a non-null value");
461
462 auto txVector = GetTxVectorForUlMu(
463 std::bind(&RrMultiUserScheduler::CanSolicitStaInBasicTf, this, std::placeholders::_1));
464
465 if (txVector.GetHeMuUserInfoMap().empty())
466 {
467 NS_LOG_DEBUG("No suitable station found");
468 return TxFormat::DL_MU_TX;
469 }
470
471 uint32_t maxBufferSize = 0;
472
473 for (const auto& candidate : txVector.GetHeMuUserInfoMap())
474 {
475 auto address = m_apMac->GetMldOrLinkAddressByAid(candidate.first);
476 NS_ASSERT_MSG(address, "AID " << candidate.first << " not found");
477
478 uint8_t queueSize = m_apMac->GetMaxBufferStatus(*address);
479 if (queueSize == 255)
480 {
481 NS_LOG_DEBUG("Buffer status of station " << *address << " is unknown");
482 maxBufferSize = std::max(maxBufferSize, m_ulPsduSize);
483 }
484 else if (queueSize == 254)
485 {
486 NS_LOG_DEBUG("Buffer status of station " << *address << " is not limited");
487 maxBufferSize = 0xffffffff;
488 }
489 else
490 {
491 NS_LOG_DEBUG("Buffer status of station " << *address << " is " << +queueSize);
492 maxBufferSize = std::max(maxBufferSize, static_cast<uint32_t>(queueSize * 256));
493 }
494 }
495
496 if (maxBufferSize == 0)
497 {
498 return DL_MU_TX;
499 }
500
502 txVector.SetGuardInterval(m_trigger.GetGuardInterval());
503
504 auto item = GetTriggerFrame(m_trigger, m_linkId);
505 m_triggerMacHdr = item->GetHeader();
506
507 // compute the maximum amount of time that can be granted to stations.
508 // This value is limited by the max PPDU duration
509 Time maxDuration = GetPpduMaxTime(txVector.GetPreambleType());
510
512 // set the TXVECTOR used to send the Trigger Frame
514 m_apMac->GetWifiRemoteStationManager(m_linkId)->GetRtsTxVector(m_triggerMacHdr.GetAddr1(),
516
517 if (!GetHeFem(m_linkId)->TryAddMpdu(item, m_txParams, m_availableTime))
518 {
519 // an UL OFDMA transmission is not possible, hence return NO_TX. In
520 // this way, no transmission will occur now and the next time we will
521 // try again performing an UL OFDMA transmission.
522 NS_LOG_DEBUG("Remaining TXOP duration is not enough for UL MU exchange");
523 return NO_TX;
524 }
525
526 NS_ASSERT(m_txParams.m_txDuration.has_value());
528
529 if (m_availableTime != Time::Min())
530 {
531 // TryAddMpdu only considers the time to transmit the Trigger Frame
532 NS_ASSERT(m_txParams.m_protection && m_txParams.m_protection->protectionTime.has_value());
534 m_txParams.m_acknowledgment->acknowledgmentTime.has_value());
535
536 maxDuration = Min(maxDuration,
537 m_availableTime - *m_txParams.m_protection->protectionTime -
538 *m_txParams.m_txDuration - m_apMac->GetWifiPhy(m_linkId)->GetSifs() -
539 *m_txParams.m_acknowledgment->acknowledgmentTime);
540 if (maxDuration.IsNegative())
541 {
542 NS_LOG_DEBUG("Remaining TXOP duration is not enough for UL MU exchange");
543 return NO_TX;
544 }
545 }
546
547 // Compute the time taken by each station to transmit a frame of maxBufferSize size
548 Time bufferTxTime;
549 for (const auto& userInfo : m_trigger)
550 {
551 Time duration = WifiPhy::CalculateTxDuration(maxBufferSize,
552 txVector,
553 m_apMac->GetWifiPhy(m_linkId)->GetPhyBand(),
554 userInfo.GetAid12());
555 bufferTxTime = Max(bufferTxTime, duration);
556 }
557
558 if (bufferTxTime < maxDuration)
559 {
560 // the maximum buffer size can be transmitted within the allowed time
561 maxDuration = bufferTxTime;
562 }
563 else
564 {
565 // maxDuration may be a too short time. If it does not allow any station to
566 // transmit at least m_ulPsduSize bytes, give up the UL MU transmission for now
567 Time minDuration;
568 for (const auto& userInfo : m_trigger)
569 {
570 Time duration =
572 txVector,
573 m_apMac->GetWifiPhy(m_linkId)->GetPhyBand(),
574 userInfo.GetAid12());
575 minDuration = (minDuration.IsZero() ? duration : Min(minDuration, duration));
576 }
577
578 if (maxDuration < minDuration)
579 {
580 // maxDuration is a too short time, hence return NO_TX. In this way,
581 // no transmission will occur now and the next time we will try again
582 // performing an UL OFDMA transmission.
583 NS_LOG_DEBUG("Available time " << maxDuration.As(Time::MS) << " is too short");
584 return NO_TX;
585 }
586 }
587
588 // maxDuration is the time to grant to the stations. Finalize the Trigger Frame
589 uint16_t ulLength;
590 std::tie(ulLength, maxDuration) =
592 txVector,
593 m_apMac->GetWifiPhy(m_linkId)->GetPhyBand());
594 NS_LOG_DEBUG("TB PPDU duration: " << maxDuration.As(Time::MS));
595 m_trigger.SetUlLength(ulLength);
596 // set Preferred AC to the AC that gained channel access
597 for (auto& userInfo : m_trigger)
598 {
599 userInfo.SetBasicTriggerDepUserInfo(0, 0, m_edca->GetAccessCategory());
600 }
601
602 UpdateCredits(m_staListUl, maxDuration, txVector);
603
604 return UL_MU_TX;
605}
606
607void
609 CtrlTriggerHeader& trigger,
610 WifiTxParameters& txParams) const
611{
612 NS_LOG_FUNCTION(this << linkId << &txParams);
613
614 // remove unprotected EMLSR clients, unless this is a BSRP TF (which acts as ICF)
615 if (trigger.IsBsrp())
616 {
617 NS_LOG_INFO("BSRP TF is an ICF for unprotected EMLSR clients");
618 return;
619 }
620
621 NS_LOG_INFO("Checking unprotected EMLSR clients");
622 RemoveRecipientsFromTf(linkId, trigger, txParams, m_isUnprotectedEmlsrClient);
623}
624
625void
627 WifiPsduMap& psduMap,
628 WifiTxParameters& txParams) const
629{
630 NS_LOG_FUNCTION(this << linkId << &txParams);
631
632 NS_LOG_INFO("Checking unprotected EMLSR clients");
633 RemoveRecipientsFromDlMu(linkId, psduMap, txParams, m_isUnprotectedEmlsrClient);
634}
635
636Time
638{
639 auto phy = m_apMac->GetWifiPhy(linkId);
641 uint16_t aid{0};
642 Mac48Address staAddress;
643
644 // we assume that a Basic Trigger Frame is sent after a BSRP Trigger Frame. In order to
645 // compute the TX duration of the Multi-STA BlockAck, we need to find the bitmap length
646 // for each STA solicited by the Trigger Frame
647 for (const auto& userInfo : m_trigger)
648 {
649 aid = userInfo.GetAid12();
650 auto it = m_apMac->GetStaList(linkId).find(aid);
651 NS_ASSERT(it != m_apMac->GetStaList(linkId).cend());
652 staAddress = it->second;
653
654 // find a TID for which a BA agreement exists with the given originator
655 uint8_t tid = 0;
656 while (tid < 8 && !m_apMac->GetBaAgreementEstablishedAsRecipient(staAddress, tid))
657 {
658 ++tid;
659 }
660 NS_ASSERT_MSG(tid < 8, "No Block Ack agreement established with originator " << staAddress);
661
662 baType.m_bitmapLen.push_back(
663 m_apMac->GetBaTypeAsRecipient(staAddress, tid).m_bitmapLen.at(0));
664 }
665
666 NS_ASSERT_MSG(aid != 0, "No User Info field in the Trigger Frame");
667
668 auto multiStaBaTxVector =
669 GetWifiRemoteStationManager(linkId)->GetBlockAckTxVector(staAddress,
671
672 auto multiStaBaDuration = WifiPhy::CalculateTxDuration(GetBlockAckSize(baType),
673 multiStaBaTxVector,
674 phy->GetPhyBand());
675
676 return m_triggerTxDuration + m_defaultTbPpduDuration + multiStaBaDuration + 3 * phy->GetSifs();
677}
678
679void
681{
682 NS_LOG_FUNCTION(this << aid << address);
683
684 if (!m_apMac->GetHeSupported(address))
685 {
686 return;
687 }
688
689 auto mldOrLinkAddress = m_apMac->GetMldOrLinkAddressByAid(aid);
690 NS_ASSERT_MSG(mldOrLinkAddress, "AID " << aid << " not found");
691
692 for (auto& staList : m_staListDl)
693 {
694 // if this is not the first STA of a non-AP MLD to be notified, an entry
695 // for this non-AP MLD already exists
696 const auto staIt = std::find_if(staList.second.cbegin(),
697 staList.second.cend(),
698 [aid](auto&& info) { return info.aid == aid; });
699 if (staIt == staList.second.cend())
700 {
701 staList.second.push_back(MasterInfo{aid, *mldOrLinkAddress, 0.0});
702 }
703 }
704
705 const auto staIt = std::find_if(m_staListUl.cbegin(), m_staListUl.cend(), [aid](auto&& info) {
706 return info.aid == aid;
707 });
708 if (staIt == m_staListUl.cend())
709 {
710 m_staListUl.push_back(MasterInfo{aid, *mldOrLinkAddress, 0.0});
711 }
712}
713
714void
716{
717 NS_LOG_FUNCTION(this << aid << address);
718
719 if (!m_apMac->GetHeSupported(address))
720 {
721 return;
722 }
723
724 auto mldOrLinkAddress = m_apMac->GetMldOrLinkAddressByAid(aid);
725 NS_ASSERT_MSG(mldOrLinkAddress, "AID " << aid << " not found");
726
727 if (m_apMac->IsAssociated(*mldOrLinkAddress))
728 {
729 // Another STA of the non-AP MLD is still associated
730 return;
731 }
732
733 for (auto& staList : m_staListDl)
734 {
735 staList.second.remove_if([&aid](const MasterInfo& info) { return info.aid == aid; });
736 }
737 m_staListUl.remove_if([&aid](const MasterInfo& info) { return info.aid == aid; });
738}
739
742{
743 NS_LOG_FUNCTION(this);
744
745 AcIndex primaryAc = m_edca->GetAccessCategory();
746
747 if (m_staListDl[primaryAc].empty())
748 {
749 NS_LOG_DEBUG("No HE stations associated: return SU_TX");
750 return TxFormat::SU_TX;
751 }
752
753 std::size_t count =
754 std::min(static_cast<std::size_t>(m_nStations), m_staListDl[primaryAc].size());
755 std::size_t nCentral26TonesRus;
757 count,
758 nCentral26TonesRus,
760 NS_ASSERT(count >= 1);
761
763 {
764 nCentral26TonesRus = 0;
765 }
766
767 uint8_t currTid = wifiAcList.at(primaryAc).GetHighTid();
768
770
771 if (mpdu && mpdu->GetHeader().IsQosData())
772 {
773 currTid = mpdu->GetHeader().GetQosTid();
774 }
775
776 // determine the list of TIDs to check
777 std::vector<uint8_t> tids;
778
780 {
781 for (auto acIt = wifiAcList.find(primaryAc); acIt != wifiAcList.end(); acIt++)
782 {
783 uint8_t firstTid = (acIt->first == primaryAc ? currTid : acIt->second.GetHighTid());
784 tids.push_back(firstTid);
785 tids.push_back(acIt->second.GetOtherTid(firstTid));
786 }
787 }
788 else
789 {
790 tids.push_back(currTid);
791 }
792
793 Ptr<HeConfiguration> heConfiguration = m_apMac->GetHeConfiguration();
794 NS_ASSERT(heConfiguration);
795
799 m_txParams.m_txVector.SetGuardInterval(heConfiguration->GetGuardInterval());
800 m_txParams.m_txVector.SetBssColor(heConfiguration->m_bssColor);
801
802 // The TXOP limit can be exceeded by the TXOP holder if it does not transmit more
803 // than one Data or Management frame in the TXOP and the frame is not in an A-MPDU
804 // consisting of more than one MPDU (Sec. 10.22.2.8 of 802.11-2016).
805 // For the moment, we are considering just one MPDU per receiver.
806 Time actualAvailableTime = (m_initialFrame ? Time::Min() : m_availableTime);
807
808 // iterate over the associated stations until an enough number of stations is identified
809 auto staIt = m_staListDl[primaryAc].begin();
810 m_candidates.clear();
811
812 std::vector<uint8_t> ruAllocations;
814 ruAllocations.resize(numRuAllocs);
815 NS_ASSERT((m_candidates.size() % numRuAllocs) == 0);
816
817 while (staIt != m_staListDl[primaryAc].end() &&
818 m_candidates.size() <
819 std::min(static_cast<std::size_t>(m_nStations), count + nCentral26TonesRus))
820 {
821 NS_LOG_DEBUG("Next candidate STA (MAC=" << staIt->address << ", AID=" << staIt->aid << ")");
822
824 !m_apMac->GetEhtSupported(staIt->address))
825 {
826 NS_LOG_DEBUG("Skipping non-EHT STA because this DL MU PPDU is sent to EHT STAs only");
827 staIt++;
828 continue;
829 }
830
831 RuType currRuType = (m_candidates.size() < count ? ruType : RuType::RU_26_TONE);
832
833 // check if the AP has at least one frame to be sent to the current station
834 for (uint8_t tid : tids)
835 {
836 AcIndex ac = QosUtilsMapTidToAc(tid);
837 NS_ASSERT(ac >= primaryAc);
838 // check that a BA agreement is established with the receiver for the
839 // considered TID, since ack sequences for DL MU PPDUs require block ack
840 if (m_apMac->GetBaAgreementEstablishedAsOriginator(staIt->address, tid))
841 {
842 mpdu = m_apMac->GetQosTxop(ac)->PeekNextMpdu(m_linkId, tid, staIt->address);
843
844 // we only check if the first frame of the current TID meets the size
845 // and duration constraints. We do not explore the queues further.
846 if (mpdu)
847 {
848 mpdu = GetHeFem(m_linkId)->CreateAliasIfNeeded(mpdu);
849 // Use a temporary TX vector including only the STA-ID of the
850 // candidate station to check if the MPDU meets the size and time limits.
851 // An RU of the computed size is tentatively assigned to the candidate
852 // station, so that the TX duration can be correctly computed.
853 WifiTxVector suTxVector =
854 GetWifiRemoteStationManager(m_linkId)->GetDataTxVector(mpdu->GetHeader(),
856
857 WifiTxVector txVectorCopy = m_txParams.m_txVector;
858
859 // the first candidate STA determines the preamble type for the DL MU PPDU
860 if (m_candidates.empty() &&
862 {
864 m_txParams.m_txVector.SetEhtPpduType(0); // indicates DL OFDMA transmission
865 }
866
868 {HeRu::RuSpec{currRuType, 1, true},
869 suTxVector.GetMode().GetMcsValue(),
870 suTxVector.GetNss()});
871
872 if (!GetHeFem(m_linkId)->TryAddMpdu(mpdu, m_txParams, actualAvailableTime))
873 {
874 NS_LOG_DEBUG("Adding the peeked frame violates the time constraints");
875 m_txParams.m_txVector = txVectorCopy;
876 }
877 else
878 {
879 // the frame meets the constraints
880 NS_LOG_DEBUG("Adding candidate STA (MAC=" << staIt->address
881 << ", AID=" << staIt->aid
882 << ") TID=" << +tid);
883 m_candidates.emplace_back(staIt, mpdu);
884 break; // terminate the for loop
885 }
886 }
887 else
888 {
889 NS_LOG_DEBUG("No frames to send to " << staIt->address << " with TID=" << +tid);
890 }
891 }
892 }
893
894 // move to the next station in the list
895 staIt++;
896 }
897
898 if (m_candidates.empty())
899 {
900 if (m_forceDlOfdma)
901 {
902 NS_LOG_DEBUG("The AP does not have suitable frames to transmit: return NO_TX");
903 return NO_TX;
904 }
905 NS_LOG_DEBUG("The AP does not have suitable frames to transmit: return SU_TX");
906 return SU_TX;
907 }
908
909 return TxFormat::DL_MU_TX;
910}
911
912void
913RrMultiUserScheduler::FinalizeTxVector(WifiTxVector& txVector)
914{
915 // Do not log txVector because GetTxVectorForUlMu() left RUs undefined and
916 // printing them will crash the simulation
917 NS_LOG_FUNCTION(this);
918 NS_ASSERT(txVector.GetHeMuUserInfoMap().size() == m_candidates.size());
919
920 // compute how many stations can be granted an RU and the RU size
921 std::size_t nRusAssigned = m_candidates.size();
922 std::size_t nCentral26TonesRus;
923 const auto ruType = WifiRu::GetEqualSizedRusForStations(m_allowedWidth,
924 nRusAssigned,
925 nCentral26TonesRus,
927
928 NS_LOG_DEBUG(nRusAssigned << " stations are being assigned a " << ruType << " RU");
929
930 if (!m_useCentral26TonesRus || m_candidates.size() == nRusAssigned)
931 {
932 nCentral26TonesRus = 0;
933 }
934 else
935 {
936 nCentral26TonesRus = std::min(m_candidates.size() - nRusAssigned, nCentral26TonesRus);
937 NS_LOG_DEBUG(nCentral26TonesRus << " stations are being assigned a 26-tones RU");
938 }
939
940 // re-allocate RUs based on the actual number of candidate stations
941 WifiTxVector::HeMuUserInfoMap heMuUserInfoMap;
942 std::swap(heMuUserInfoMap, txVector.GetHeMuUserInfoMap());
943
944 auto candidateIt = m_candidates.begin(); // iterator over the list of candidate receivers
945 auto ruSet = WifiRu::GetRusOfType(m_allowedWidth, ruType, WIFI_MOD_CLASS_HE);
946 auto ruSetIt = ruSet.begin();
947 auto central26TonesRus =
948 WifiRu::GetCentral26TonesRus(m_allowedWidth, ruType, WIFI_MOD_CLASS_HE);
949 auto central26TonesRusIt = central26TonesRus.begin();
950
951 for (std::size_t i = 0; i < nRusAssigned + nCentral26TonesRus; i++)
952 {
953 NS_ASSERT(candidateIt != m_candidates.end());
954 auto mapIt = heMuUserInfoMap.find(candidateIt->first->aid);
955 NS_ASSERT(mapIt != heMuUserInfoMap.end());
956
957 txVector.SetHeMuUserInfo(mapIt->first,
958 {(i < nRusAssigned ? *ruSetIt++ : *central26TonesRusIt++),
959 mapIt->second.mcs,
960 mapIt->second.nss});
961 candidateIt++;
962 }
963
964 // remove candidates that will not be served
965 m_candidates.erase(candidateIt, m_candidates.end());
966}
967
968void
969RrMultiUserScheduler::UpdateCredits(std::list<MasterInfo>& staList,
970 Time txDuration,
971 const WifiTxVector& txVector)
972{
973 NS_LOG_FUNCTION(this << txDuration.As(Time::US) << txVector);
974
975 // find how many RUs have been allocated for each RU type
976 std::map<RuType, std::size_t> ruMap;
977 for (const auto& userInfo : txVector.GetHeMuUserInfoMap())
978 {
979 ruMap.insert({WifiRu::GetRuType(userInfo.second.ru), 0}).first->second++;
980 }
981
982 // The amount of credits received by each station equals the TX duration (in
983 // microseconds) divided by the number of stations.
984 double creditsPerSta = txDuration.ToDouble(Time::US) / staList.size();
985 // Transmitting stations have to pay a number of credits equal to the TX duration
986 // (in microseconds) times the allocated bandwidth share.
987 double debitsPerMhz =
988 txDuration.ToDouble(Time::US) /
989 std::accumulate(ruMap.begin(), ruMap.end(), 0, [](uint16_t sum, auto pair) {
990 return sum + pair.second * WifiRu::GetBandwidth(pair.first);
991 });
992
993 // assign credits to all stations
994 for (auto& sta : staList)
995 {
996 sta.credits += creditsPerSta;
997 sta.credits = std::min(sta.credits, m_maxCredits.ToDouble(Time::US));
998 }
999
1000 // subtract debits to the selected stations
1001 for (auto& candidate : m_candidates)
1002 {
1003 auto mapIt = txVector.GetHeMuUserInfoMap().find(candidate.first->aid);
1004 NS_ASSERT(mapIt != txVector.GetHeMuUserInfoMap().end());
1005
1006 candidate.first->credits -=
1007 debitsPerMhz * WifiRu::GetBandwidth(WifiRu::GetRuType(mapIt->second.ru));
1008 }
1009
1010 // sort the list in decreasing order of credits
1011 staList.sort([](const MasterInfo& a, const MasterInfo& b) { return a.credits > b.credits; });
1012}
1013
1015RrMultiUserScheduler::ComputeDlMuInfo()
1016{
1017 NS_LOG_FUNCTION(this);
1018
1019 if (m_candidates.empty())
1020 {
1021 return DlMuInfo();
1022 }
1023
1024 DlMuInfo dlMuInfo;
1025 std::swap(dlMuInfo.txParams.m_txVector, m_txParams.m_txVector);
1026 FinalizeTxVector(dlMuInfo.txParams.m_txVector);
1027
1028 m_txParams.Clear();
1029 Ptr<WifiMpdu> mpdu;
1030
1031 // Compute the TX params (again) by using the stored MPDUs and the final TXVECTOR
1032 Time actualAvailableTime = (m_initialFrame ? Time::Min() : m_availableTime);
1033
1034 for (const auto& candidate : m_candidates)
1035 {
1036 mpdu = candidate.second;
1037 NS_ASSERT(mpdu);
1038
1039 bool ret [[maybe_unused]] =
1040 GetHeFem(m_linkId)->TryAddMpdu(mpdu, dlMuInfo.txParams, actualAvailableTime);
1041 NS_ASSERT_MSG(ret,
1042 "Weird that an MPDU does not meet constraints when "
1043 "transmitted over a larger RU");
1044 }
1045
1046 // We have to complete the PSDUs to send
1047 Ptr<WifiMacQueue> queue;
1048
1049 for (const auto& candidate : m_candidates)
1050 {
1051 // Let us try first A-MSDU aggregation if possible
1052 mpdu = candidate.second;
1053 NS_ASSERT(mpdu);
1054 uint8_t tid = mpdu->GetHeader().GetQosTid();
1055 NS_ASSERT_MSG(mpdu->GetOriginal()->GetHeader().GetAddr1() == candidate.first->address,
1056 "RA of the stored MPDU must match the stored address");
1057
1058 NS_ASSERT(mpdu->IsQueued());
1059 Ptr<WifiMpdu> item = mpdu;
1060
1061 if (!mpdu->GetHeader().IsRetry())
1062 {
1063 // this MPDU must have been dequeued from the AC queue and we can try
1064 // A-MSDU aggregation
1065 item = GetHeFem(m_linkId)->GetMsduAggregator()->GetNextAmsdu(mpdu,
1066 dlMuInfo.txParams,
1067 m_availableTime);
1068
1069 if (!item)
1070 {
1071 // A-MSDU aggregation failed or disabled
1072 item = mpdu;
1073 }
1074 m_apMac->GetQosTxop(QosUtilsMapTidToAc(tid))->AssignSequenceNumber(item);
1075 }
1076
1077 // Now, let's try A-MPDU aggregation if possible
1078 std::vector<Ptr<WifiMpdu>> mpduList =
1079 GetHeFem(m_linkId)->GetMpduAggregator()->GetNextAmpdu(item,
1080 dlMuInfo.txParams,
1081 m_availableTime);
1082
1083 if (mpduList.size() > 1)
1084 {
1085 // A-MPDU aggregation succeeded, update psduMap
1086 dlMuInfo.psduMap[candidate.first->aid] = Create<WifiPsdu>(std::move(mpduList));
1087 }
1088 else
1089 {
1090 dlMuInfo.psduMap[candidate.first->aid] = Create<WifiPsdu>(item, true);
1091 }
1092 }
1093
1094 NS_ASSERT(dlMuInfo.txParams.m_txDuration.has_value());
1095 AcIndex primaryAc = m_edca->GetAccessCategory();
1096 UpdateCredits(m_staListDl[primaryAc],
1097 *dlMuInfo.txParams.m_txDuration,
1098 dlMuInfo.txParams.m_txVector);
1099
1100 NS_LOG_DEBUG("Next station to serve has AID=" << m_staListDl[primaryAc].front().aid);
1101
1102 return dlMuInfo;
1103}
1104
1106RrMultiUserScheduler::ComputeUlMuInfo()
1107{
1108 return UlMuInfo{m_trigger, m_triggerMacHdr, std::move(m_txParams)};
1109}
1110
1111} // namespace ns3
#define Max(a, b)
#define Min(a, b)
AttributeValue implementation for Boolean.
Definition boolean.h:26
Headers for Trigger frames.
std::size_t GetPaddingSize() const
WifiTxVector GetHeTbTxVector(uint16_t staId) const
Get the TX vector that the station with the given STA-ID will use to send the HE TB PPDU solicited by...
bool IsBsrp() const
Check if this is a Buffer Status Report Poll Trigger frame.
TriggerFrameType GetType() const
Get the Trigger Frame type.
ConstIterator begin() const
Get a const iterator pointing to the first User Info field in the list.
Time GetGuardInterval() const
Get the guard interval duration of the solicited HE TB PPDU.
void SetUlLength(uint16_t len)
Set the UL Length subfield of the Common Info field.
static std::pair< uint16_t, Time > ConvertHeTbPpduDurationToLSigLength(Time ppduDuration, const WifiTxVector &txVector, WifiPhyBand band)
Compute the L-SIG length value corresponding to the given HE TB PPDU duration.
Definition he-phy.cc:262
an EUI-48 address
MultiUserScheduler is an abstract base class defining the API that APs supporting at least VHT can us...
bool m_initialFrame
true if a TXOP is being started
void DoInitialize() override
Initialize() implementation.
Ptr< ApWifiMac > m_apMac
the AP wifi MAC
Time m_availableTime
the time available for frame exchange
void RemoveRecipientsFromTf(uint8_t linkId, CtrlTriggerHeader &trigger, WifiTxParameters &txParams, std::function< bool(uint8_t, Mac48Address)> predicate) const
Remove the User Info fields for which the given predicate is true from the given Trigger Frame.
Ptr< WifiRemoteStationManager > GetWifiRemoteStationManager(uint8_t linkId) const
Get the station manager attached to the AP on the given link.
uint8_t m_linkId
the ID of the link over which channel access has been granted
uint32_t GetMaxSizeOfQosNullAmpdu(const CtrlTriggerHeader &trigger) const
Get the maximum size in bytes among the A-MPDUs containing QoS Null frames and solicited by the given...
const std::function< bool(uint8_t, Mac48Address)> m_isUnprotectedEmlsrClient
predicate returning true if the device with the given (link) address is an EMLSR client that is not p...
Ptr< QosTxop > m_edca
the AC that gained channel access
Time m_defaultTbPpduDuration
the default duration of TB PPDUs solicited by Basic TFs
TxFormat GetLastTxFormat(uint8_t linkId) const
Get the format of the last transmission on the given link, as determined by the last call to NotifyAc...
void DoDispose() override
Destructor implementation.
Ptr< WifiMpdu > GetTriggerFrame(const CtrlTriggerHeader &trigger, uint8_t linkId) const
Get an MPDU containing the given Trigger Frame.
MHz_u m_allowedWidth
the allowed width for the current transmission
Ptr< HeFrameExchangeManager > GetHeFem(uint8_t linkId) const
Get the HE Frame Exchange Manager attached to the AP on the given link.
TxFormat
Enumeration of the possible transmission formats.
void RemoveRecipientsFromDlMu(uint8_t linkId, WifiPsduMap &psduMap, WifiTxParameters &txParams, std::function< bool(uint8_t, Mac48Address)> predicate) const
Remove PSDUs for which the given predicate is true from the given PSDU map.
Smart pointer class similar to boost::intrusive_ptr.
Ptr< WifiMpdu > PeekNextMpdu(uint8_t linkId, uint8_t tid=8, Mac48Address recipient=Mac48Address::GetBroadcast(), Ptr< const WifiMpdu > mpdu=nullptr)
Peek the next frame to transmit on the given link to the given receiver and of the given TID from the...
Definition qos-txop.cc:385
AcIndex GetAccessCategory() const
Get the access category of this object.
Definition qos-txop.cc:863
RrMultiUserScheduler is a simple OFDMA scheduler that indicates to perform a DL OFDMA transmission if...
TxFormat SelectTxFormat() override
Select the format of the next transmission.
bool m_enableBsrp
send a BSRP before an UL MU transmission
void NotifyStationAssociated(uint16_t aid, Mac48Address address)
Notify the scheduler that a station associated with the AP.
static TypeId GetTypeId()
Get the type ID.
uint32_t m_ulPsduSize
the size in byte of the solicited PSDU
std::list< CandidateInfo > m_candidates
Candidate stations for MU TX.
bool m_useCentral26TonesRus
whether to allocate central 26-tone RUs
bool m_forceDlOfdma
return DL_OFDMA even if no DL MU PPDU was built
bool m_enableUlOfdma
enable the scheduler to also return UL_OFDMA
void DoInitialize() override
Initialize() implementation.
void DoDispose() override
Destructor implementation.
void UpdateCredits(std::list< MasterInfo > &staList, Time txDuration, const WifiTxVector &txVector)
Update credits of the stations in the given list considering that a PPDU having the given duration is...
WifiMacHeader m_triggerMacHdr
MAC header for Trigger Frame.
uint8_t m_nStations
Number of stations/slots to fill.
Time m_triggerTxDuration
Trigger Frame TX duration.
void UpdateDlMuAfterProtection(uint8_t linkId, WifiPsduMap &psduMap, WifiTxParameters &txParams) const override
Update the given PSDU map after protection is completed on the given link.
WifiTxParameters m_txParams
TX parameters.
virtual TxFormat TrySendingDlMuPpdu()
Check if it is possible to send a DL MU PPDU given the current time limits.
void NotifyStationDeassociated(uint16_t aid, Mac48Address address)
Notify the scheduler that a station deassociated with the AP.
Time m_maxCredits
Max amount of credits a station can have.
void UpdateTriggerFrameAfterProtection(uint8_t linkId, CtrlTriggerHeader &trigger, WifiTxParameters &txParams) const override
Update the given Trigger Frame after protection is completed on the given link.
virtual WifiTxVector GetTxVectorForUlMu(std::function< bool(const MasterInfo &)> canBeSolicited)
Compute a TXVECTOR that can be used to construct a Trigger Frame to solicit transmissions from suitab...
Time GetExtraTimeForBsrpTfDurationId(uint8_t linkId) const override
When the TXOP limit is zero and the TXOP continues a SIFS after receiving a response to a BSRP TF,...
bool m_enableTxopSharing
allow A-MPDUs of different TIDs in a DL MU PPDU
CtrlTriggerHeader m_trigger
Trigger Frame to send.
std::map< AcIndex, std::list< MasterInfo > > m_staListDl
Per-AC list of stations (next to serve for DL first)
virtual bool CanSolicitStaInBasicTf(const MasterInfo &info) const
Determine whether the given STA can be solicited via a Basic Trigger Frame.
virtual TxFormat TrySendingBsrpTf()
Check if it is possible to send a BSRP Trigger Frame given the current time limits.
virtual bool CanSolicitStaInBsrpTf(const MasterInfo &info) const
Determine whether the given STA can be solicited via a BSRP Trigger Frame.
virtual TxFormat TrySendingBasicTf()
Check if it is possible to send a Basic Trigger Frame given the current time limits.
void FinalizeTxVector(WifiTxVector &txVector)
Finalize the given TXVECTOR by only including the largest subset of the current set of candidate stat...
std::list< MasterInfo > m_staListUl
List of stations to serve for UL.
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:403
bool IsNegative() const
Exactly equivalent to t <= 0.
Definition nstime.h:313
static Time Min()
Minimum representable Time Not to be confused with Min(Time,Time).
Definition nstime.h:276
@ MS
millisecond
Definition nstime.h:106
double ToDouble(Unit unit) const
Get the Time value expressed in a particular unit.
Definition nstime.h:586
bool IsZero() const
Exactly equivalent to t == 0.
Definition nstime.h:304
AttributeValue implementation for Time.
Definition nstime.h:1432
a unique identifier for an interface.
Definition type-id.h:49
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition type-id.cc:1001
Hold an unsigned integer type.
Definition uinteger.h:34
Implements the IEEE 802.11 MAC header.
Mac48Address GetAddr1() const
Return the address in the Address 1 field.
void SetAddr1(Mac48Address address)
Fill the Address 1 field with the given address.
void SetAddr2(Mac48Address address)
Fill the Address 2 field with the given address.
uint8_t GetMcsValue() const
Definition wifi-mode.cc:151
static Time CalculateTxDuration(uint32_t size, const WifiTxVector &txVector, WifiPhyBand band, uint16_t staId=SU_STA_ID)
Definition wifi-phy.cc:1588
static RuType GetEqualSizedRusForStations(MHz_u bandwidth, std::size_t &nStations, std::size_t &nCentral26TonesRus, WifiModulationClass mc)
Given the channel bandwidth and the number of stations candidate for being assigned an RU,...
Definition wifi-ru.cc:237
This class stores the TX parameters (TX vector, protection mechanism, acknowledgment mechanism,...
std::optional< Time > m_txDuration
TX duration of the frame.
std::unique_ptr< WifiProtection > m_protection
protection method
std::unique_ptr< WifiAcknowledgment > m_acknowledgment
acknowledgment method
WifiTxVector m_txVector
TXVECTOR of the frame being prepared.
void Clear()
Reset the TX parameters.
This class mimics the TXVECTOR which is to be passed to the PHY in order to define the parameters whi...
void SetEhtPpduType(uint8_t type)
Set the EHT_PPDU_TYPE parameter.
void SetGuardInterval(Time guardInterval)
Sets the guard interval duration (in nanoseconds)
std::map< uint16_t, HeMuUserInfo > HeMuUserInfoMap
map of HE MU specific user info parameters indexed by STA-ID
WifiMode GetMode(uint16_t staId=SU_STA_ID) const
If this TX vector is associated with an SU PPDU, return the selected payload transmission mode.
void SetHeMuUserInfo(uint16_t staId, HeMuUserInfo userInfo)
Set the HE MU user-specific transmission information for the given STA-ID.
WifiPreamble GetPreambleType() const
void SetChannelWidth(MHz_u channelWidth)
Sets the selected channelWidth.
const HeMuUserInfoMap & GetHeMuUserInfoMap() const
Get a const reference to the map HE MU user-specific transmission information indexed by STA-ID.
uint8_t GetNss(uint16_t staId=SU_STA_ID) const
If this TX vector is associated with an SU PPDU, return the number of spatial streams.
MHz_u GetChannelWidth() const
void SetBssColor(uint8_t color)
Set the BSS color.
void SetPreambleType(WifiPreamble preamble)
Sets the preamble type.
#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
Ptr< const AttributeChecker > MakeBooleanChecker()
Definition boolean.cc:113
Ptr< const AttributeAccessor > MakeBooleanAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition boolean.h:70
Ptr< const AttributeAccessor > MakeTimeAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition nstime.h:1433
Ptr< const AttributeChecker > MakeTimeChecker()
Helper to make an unbounded Time checker.
Definition nstime.h:1453
Ptr< const AttributeChecker > MakeUintegerChecker()
Definition uinteger.h:85
Ptr< const AttributeAccessor > MakeUintegerAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition uinteger.h:35
#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_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
Definition log.h:264
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition object-base.h:35
Ptr< T > Create(Ts &&... args)
Create class instances by constructors with varying numbers of arguments and return them by Ptr.
Definition ptr.h:436
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition nstime.h:1345
AcIndex QosUtilsMapTidToAc(uint8_t tid)
Maps TID (Traffic ID) to Access classes.
Definition qos-utils.cc:123
AcIndex
This enumeration defines the Access Categories as an enumeration with values corresponding to the AC ...
Definition qos-utils.h:62
@ WIFI_PREAMBLE_EHT_TB
@ WIFI_PREAMBLE_HE_TB
@ WIFI_PREAMBLE_EHT_MU
@ WIFI_PREAMBLE_HE_MU
@ WIFI_MOD_CLASS_HE
HE (Clause 27)
@ AC_BE
Best Effort.
Definition qos-utils.h:64
Declaration of ns3::HePhy class and ns3::HeSigAParameters struct.
Definition first.py:1
Every class exported by the ns3 library is enclosed in the ns3 namespace.
Time GetPpduMaxTime(WifiPreamble preamble)
Get the maximum PPDU duration (see Section 10.14 of 802.11-2016) for the PHY layers defining the aPPD...
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
RuType
The different Resource Unit (RU) types.
Definition wifi-types.h:98
Ptr< T1 > DynamicCast(const Ptr< T2 > &p)
Cast a Ptr.
Definition ptr.h:580
std::unordered_map< uint16_t, Ptr< WifiPsdu > > WifiPsduMap
Map of PSDUs indexed by STA-ID.
Definition wifi-mac.h:78
std::size_t Count20MHzSubchannels(MHz_u channelWidth)
Return the number of 20 MHz subchannels covering the channel width.
Definition wifi-utils.h:135
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
uint32_t GetBlockAckSize(BlockAckType type)
Return the total BlockAck size (including FCS trailer).
Definition wifi-utils.cc:60
The different BlockAck variants.
std::vector< uint8_t > m_bitmapLen
Length (bytes) of included bitmaps.
Information to be provided in case of DL MU transmission.
WifiTxParameters txParams
the transmission parameters
WifiPsduMap psduMap
the DL MU PPDU to transmit
Information to be provided in case of UL MU transmission.
Information used to sort stations.
Mac48Address address
station's MAC Address
double credits
credits accumulated by the station
std::ofstream queueSize