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 auto heConfiguration = m_apMac->GetHeConfiguration();
178 NS_ASSERT(heConfiguration);
179
180 WifiTxVector txVector;
182 txVector.SetGuardInterval(heConfiguration->GetGuardInterval());
183 txVector.SetBssColor(heConfiguration->m_bssColor);
185
186 const auto firstCandidate =
187 std::find_if(m_staListUl.begin(), m_staListUl.end(), canBeSolicited);
188 if (firstCandidate == m_staListUl.cend())
189 {
190 NS_LOG_DEBUG("No candidate");
191 return txVector;
192 }
193
194 // determine RUs to allocate to stations
195 const auto isEht =
196 (m_apMac->GetEhtSupported() && m_apMac->GetEhtSupported(firstCandidate->address));
197 auto count = std::min<std::size_t>(m_nStations, m_staListUl.size());
198 std::size_t nCentral26TonesRus;
200 count,
201 nCentral26TonesRus,
203 NS_ASSERT(count >= 1);
204
206 {
207 nCentral26TonesRus = 0;
208 }
209
210 if (isEht)
211 {
213 txVector.SetEhtPpduType(0);
214 }
215 // TODO otherwise make sure the TX width does not exceed 160 MHz
216
217 // iterate over the associated stations until an enough number of stations is identified
218 auto staIt = firstCandidate;
219 m_candidates.clear();
220
221 while (staIt != m_staListUl.end() &&
222 txVector.GetHeMuUserInfoMap().size() <
223 std::min<std::size_t>(m_nStations, count + nCentral26TonesRus))
224 {
225 NS_LOG_DEBUG("Next candidate STA (MAC=" << staIt->address << ", AID=" << staIt->aid << ")");
226
227 if (txVector.GetPreambleType() == WIFI_PREAMBLE_EHT_TB &&
228 !m_apMac->GetEhtSupported(staIt->address))
229 {
231 "Skipping non-EHT STA because this Trigger Frame is only soliciting EHT STAs");
232 staIt = std::find_if(++staIt, m_staListUl.end(), canBeSolicited);
233 continue;
234 }
235
236 // prepare the MAC header of a frame that would be sent to the candidate station,
237 // just for the purpose of retrieving the TXVECTOR used to transmit to that station
240 ->GetAffiliatedStaAddress(staIt->address)
241 .value_or(staIt->address));
242 hdr.SetAddr2(m_apMac->GetFrameExchangeManager(m_linkId)->GetAddress());
243 WifiTxVector suTxVector =
245 txVector.SetHeMuUserInfo(staIt->aid,
246 {HeRu::RuSpec(), // assigned later by FinalizeTxVector
247 suTxVector.GetMode().GetMcsValue(),
248 suTxVector.GetNss()});
249 m_candidates.emplace_back(staIt, nullptr);
250
251 // move to the next candidate station in the list
252 staIt = std::find_if(++staIt, m_staListUl.end(), canBeSolicited);
253 }
254
255 if (txVector.GetHeMuUserInfoMap().empty())
256 {
257 NS_LOG_DEBUG("No suitable station");
258 return txVector;
259 }
260
261 FinalizeTxVector(txVector);
262 return txVector;
263}
264
265bool
267{
268 // check if station has setup the current link
269 if (!m_apMac->GetStaList(m_linkId).contains(info.aid))
270 {
271 NS_LOG_INFO("STA with AID " << info.aid << " has not setup link " << +m_linkId
272 << ": skipping station");
273 return false;
274 }
275
276 uint8_t tid = 0;
277 while (tid < 8)
278 {
279 // check that a BA agreement is established with the receiver for the
280 // considered TID, since ack sequences for UL MU require block ack
281 if (m_apMac->GetBaAgreementEstablishedAsRecipient(info.address, tid))
282 {
283 break;
284 }
285 ++tid;
286 }
287 if (tid == 8)
288 {
289 NS_LOG_DEBUG("No Block Ack agreement established with " << info.address
290 << ": skipping station");
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 << ": skipping station");
317 return false;
318 }
319
320 // check if the station is an EMLSR client that is using another link
321 if (GetWifiRemoteStationManager(m_linkId)->GetEmlsrEnabled(info.address) &&
322 (m_apMac->GetTxBlockedOnLink(AC_BE,
323 {WIFI_QOSDATA_QUEUE, WIFI_UNICAST, *mldAddr, 0},
324 m_linkId,
326 m_apMac->GetTxBlockedOnLink(AC_BE,
327 {WIFI_QOSDATA_QUEUE, WIFI_UNICAST, *mldAddr, 0},
328 m_linkId,
330 {
331 NS_LOG_INFO("EMLSR client " << *mldAddr << " is using another link: skipping station");
332 return false;
333 }
334
335 return true;
336}
337
340{
341 NS_LOG_FUNCTION(this);
342
343 if (m_staListUl.empty())
344 {
345 NS_LOG_DEBUG("No HE stations associated: return SU_TX");
346 return TxFormat::SU_TX;
347 }
348
349 auto txVector = GetTxVectorForUlMu(
350 std::bind(&RrMultiUserScheduler::CanSolicitStaInBsrpTf, this, std::placeholders::_1));
351
352 if (txVector.GetHeMuUserInfoMap().empty())
353 {
354 NS_LOG_DEBUG("No suitable station found");
355 return TxFormat::DL_MU_TX;
356 }
357
359 txVector.SetGuardInterval(m_trigger.GetGuardInterval());
360
361 auto item = GetTriggerFrame(m_trigger, m_linkId);
362 m_triggerMacHdr = item->GetHeader();
363
365 // set the TXVECTOR used to send the Trigger Frame
367 m_apMac->GetWifiRemoteStationManager(m_linkId)->GetRtsTxVector(m_triggerMacHdr.GetAddr1(),
369
370 // If this BSRP TF is an ICF, we need to add padding and adjust the TXVECTOR
371 if (auto ehtFem =
372 DynamicCast<EhtFrameExchangeManager>(m_apMac->GetFrameExchangeManager(m_linkId)))
373 {
374 auto prevPaddingSize = m_trigger.GetPaddingSize();
375 ehtFem->SetIcfPaddingAndTxVector(m_trigger, m_txParams.m_txVector);
376 // serialize again if padding has been added
377 if (m_trigger.GetPaddingSize() != prevPaddingSize)
378 {
379 auto packet = Create<Packet>();
380 packet->AddHeader(m_trigger);
381 item = Create<WifiMpdu>(packet, item->GetHeader());
382 }
383 }
384
385 if (!GetHeFem(m_linkId)->TryAddMpdu(item, m_txParams, m_availableTime))
386 {
387 // sending the BSRP Trigger Frame is not possible, hence return NO_TX. In
388 // this way, no transmission will occur now and the next time we will
389 // try again sending a BSRP Trigger Frame.
390 NS_LOG_DEBUG("Remaining TXOP duration is not enough for BSRP TF exchange");
391 return NO_TX;
392 }
393
394 // Compute the time taken by each station to transmit 8 QoS Null frames
395 Time qosNullTxDuration;
396 for (const auto& userInfo : m_trigger)
397 {
399 txVector,
400 m_apMac->GetWifiPhy(m_linkId)->GetPhyBand(),
401 userInfo.GetAid12());
402 qosNullTxDuration = Max(qosNullTxDuration, duration);
403 }
404
405 NS_ASSERT(m_txParams.m_txDuration.has_value());
407
408 if (m_availableTime != Time::Min())
409 {
410 // TryAddMpdu only considers the time to transmit the Trigger Frame
411 NS_ASSERT(m_txParams.m_protection && m_txParams.m_protection->protectionTime.has_value());
413 m_txParams.m_acknowledgment->acknowledgmentTime.has_value() &&
414 m_txParams.m_acknowledgment->acknowledgmentTime->IsZero());
415
416 if (*m_txParams.m_protection->protectionTime + *m_txParams.m_txDuration // BSRP TF tx time
417 + m_apMac->GetWifiPhy(m_linkId)->GetSifs() + qosNullTxDuration >
419 {
420 NS_LOG_DEBUG("Remaining TXOP duration is not enough for BSRP TF exchange");
421 return NO_TX;
422 }
423 }
424
425 uint16_t ulLength;
426 std::tie(ulLength, qosNullTxDuration) = HePhy::ConvertHeTbPpduDurationToLSigLength(
427 qosNullTxDuration,
429 m_apMac->GetWifiPhy(m_linkId)->GetPhyBand());
430 NS_LOG_DEBUG("Duration of QoS Null frames: " << qosNullTxDuration.As(Time::MS));
431 m_trigger.SetUlLength(ulLength);
432
433 return UL_MU_TX;
434}
435
436bool
438{
439 // in addition to the checks performed when sending a BSRP TF, also check if the station
440 // has reported a null queue size
441 if (!CanSolicitStaInBsrpTf(info))
442 {
443 return false;
444 }
445
446 return m_apMac->GetMaxBufferStatus(info.address) > 0;
447}
448
451{
452 NS_LOG_FUNCTION(this);
453
454 if (m_staListUl.empty())
455 {
456 NS_LOG_DEBUG("No HE stations associated: return SU_TX");
457 return TxFormat::SU_TX;
458 }
459
460 // check if an UL OFDMA transmission is possible after a DL OFDMA transmission
461 NS_ABORT_MSG_IF(m_ulPsduSize == 0, "The UlPsduSize attribute must be set to a non-null value");
462
463 auto txVector = GetTxVectorForUlMu(
464 std::bind(&RrMultiUserScheduler::CanSolicitStaInBasicTf, this, std::placeholders::_1));
465
466 if (txVector.GetHeMuUserInfoMap().empty())
467 {
468 NS_LOG_DEBUG("No suitable station found");
469 return TxFormat::DL_MU_TX;
470 }
471
472 uint32_t maxBufferSize = 0;
473
474 for (const auto& candidate : txVector.GetHeMuUserInfoMap())
475 {
476 auto address = m_apMac->GetMldOrLinkAddressByAid(candidate.first);
477 NS_ASSERT_MSG(address, "AID " << candidate.first << " not found");
478
479 uint8_t queueSize = m_apMac->GetMaxBufferStatus(*address);
480 if (queueSize == 255)
481 {
482 NS_LOG_DEBUG("Buffer status of station " << *address << " is unknown");
483 maxBufferSize = std::max(maxBufferSize, m_ulPsduSize);
484 }
485 else if (queueSize == 254)
486 {
487 NS_LOG_DEBUG("Buffer status of station " << *address << " is not limited");
488 maxBufferSize = 0xffffffff;
489 }
490 else
491 {
492 NS_LOG_DEBUG("Buffer status of station " << *address << " is " << +queueSize);
493 maxBufferSize = std::max(maxBufferSize, static_cast<uint32_t>(queueSize * 256));
494 }
495 }
496
497 if (maxBufferSize == 0)
498 {
499 return DL_MU_TX;
500 }
501
503 txVector.SetGuardInterval(m_trigger.GetGuardInterval());
504
505 auto item = GetTriggerFrame(m_trigger, m_linkId);
506 m_triggerMacHdr = item->GetHeader();
507
508 // compute the maximum amount of time that can be granted to stations.
509 // This value is limited by the max PPDU duration
510 Time maxDuration = GetPpduMaxTime(txVector.GetPreambleType());
511
513 // set the TXVECTOR used to send the Trigger Frame
515 m_apMac->GetWifiRemoteStationManager(m_linkId)->GetRtsTxVector(m_triggerMacHdr.GetAddr1(),
517
518 if (!GetHeFem(m_linkId)->TryAddMpdu(item, m_txParams, m_availableTime))
519 {
520 // an UL OFDMA transmission is not possible, hence return NO_TX. In
521 // this way, no transmission will occur now and the next time we will
522 // try again performing an UL OFDMA transmission.
523 NS_LOG_DEBUG("Remaining TXOP duration is not enough for UL MU exchange");
524 return NO_TX;
525 }
526
527 NS_ASSERT(m_txParams.m_txDuration.has_value());
529
530 if (m_availableTime != Time::Min())
531 {
532 // TryAddMpdu only considers the time to transmit the Trigger Frame
533 NS_ASSERT(m_txParams.m_protection && m_txParams.m_protection->protectionTime.has_value());
535 m_txParams.m_acknowledgment->acknowledgmentTime.has_value());
536
537 maxDuration = Min(maxDuration,
538 m_availableTime - *m_txParams.m_protection->protectionTime -
539 *m_txParams.m_txDuration - m_apMac->GetWifiPhy(m_linkId)->GetSifs() -
540 *m_txParams.m_acknowledgment->acknowledgmentTime);
541 if (maxDuration.IsNegative())
542 {
543 NS_LOG_DEBUG("Remaining TXOP duration is not enough for UL MU exchange");
544 return NO_TX;
545 }
546 }
547
548 // Compute the time taken by each station to transmit a frame of maxBufferSize size
549 Time bufferTxTime;
550 for (const auto& userInfo : m_trigger)
551 {
552 Time duration = WifiPhy::CalculateTxDuration(maxBufferSize,
553 txVector,
554 m_apMac->GetWifiPhy(m_linkId)->GetPhyBand(),
555 userInfo.GetAid12());
556 bufferTxTime = Max(bufferTxTime, duration);
557 }
558
559 if (bufferTxTime < maxDuration)
560 {
561 // the maximum buffer size can be transmitted within the allowed time
562 maxDuration = bufferTxTime;
563 }
564 else
565 {
566 // maxDuration may be a too short time. If it does not allow any station to
567 // transmit at least m_ulPsduSize bytes, give up the UL MU transmission for now
568 Time minDuration;
569 for (const auto& userInfo : m_trigger)
570 {
571 Time duration =
573 txVector,
574 m_apMac->GetWifiPhy(m_linkId)->GetPhyBand(),
575 userInfo.GetAid12());
576 minDuration = (minDuration.IsZero() ? duration : Min(minDuration, duration));
577 }
578
579 if (maxDuration < minDuration)
580 {
581 // maxDuration is a too short time, hence return NO_TX. In this way,
582 // no transmission will occur now and the next time we will try again
583 // performing an UL OFDMA transmission.
584 NS_LOG_DEBUG("Available time " << maxDuration.As(Time::MS) << " is too short");
585 return NO_TX;
586 }
587 }
588
589 // maxDuration is the time to grant to the stations. Finalize the Trigger Frame
590 uint16_t ulLength;
591 std::tie(ulLength, maxDuration) =
593 txVector,
594 m_apMac->GetWifiPhy(m_linkId)->GetPhyBand());
595 NS_LOG_DEBUG("TB PPDU duration: " << maxDuration.As(Time::MS));
596 m_trigger.SetUlLength(ulLength);
597 // set Preferred AC to the AC that gained channel access
598 for (auto& userInfo : m_trigger)
599 {
600 userInfo.SetBasicTriggerDepUserInfo(0, 0, m_edca->GetAccessCategory());
601 }
602
603 UpdateCredits(m_staListUl, maxDuration, txVector);
604
605 return UL_MU_TX;
606}
607
608void
610 CtrlTriggerHeader& trigger,
611 WifiTxParameters& txParams) const
612{
613 NS_LOG_FUNCTION(this << linkId << &txParams);
614
615 // remove unprotected EMLSR clients, unless this is a BSRP TF (which acts as ICF)
616 if (trigger.IsBsrp())
617 {
618 NS_LOG_INFO("BSRP TF is an ICF for unprotected EMLSR clients");
619 return;
620 }
621
622 NS_LOG_INFO("Checking unprotected EMLSR clients");
623 RemoveRecipientsFromTf(linkId, trigger, txParams, m_isUnprotectedEmlsrClient);
624}
625
626void
628 WifiPsduMap& psduMap,
629 WifiTxParameters& txParams) const
630{
631 NS_LOG_FUNCTION(this << linkId << &txParams);
632
633 NS_LOG_INFO("Checking unprotected EMLSR clients");
634 RemoveRecipientsFromDlMu(linkId, psduMap, txParams, m_isUnprotectedEmlsrClient);
635}
636
637Time
639{
640 auto phy = m_apMac->GetWifiPhy(linkId);
642 uint16_t aid{0};
643 Mac48Address staAddress;
644
645 // we assume that a Basic Trigger Frame is sent after a BSRP Trigger Frame. In order to
646 // compute the TX duration of the Multi-STA BlockAck, we need to find the bitmap length
647 // for each STA solicited by the Trigger Frame
648 for (const auto& userInfo : m_trigger)
649 {
650 aid = userInfo.GetAid12();
651 auto it = m_apMac->GetStaList(linkId).find(aid);
652 NS_ASSERT(it != m_apMac->GetStaList(linkId).cend());
653 staAddress = it->second;
654
655 // find a TID for which a BA agreement exists with the given originator
656 uint8_t tid = 0;
657 while (tid < 8 && !m_apMac->GetBaAgreementEstablishedAsRecipient(staAddress, tid))
658 {
659 ++tid;
660 }
661 NS_ASSERT_MSG(tid < 8, "No Block Ack agreement established with originator " << staAddress);
662
663 baType.m_bitmapLen.push_back(
664 m_apMac->GetBaTypeAsRecipient(staAddress, tid).m_bitmapLen.at(0));
665 }
666
667 NS_ASSERT_MSG(aid != 0, "No User Info field in the Trigger Frame");
668
669 auto multiStaBaTxVector =
670 GetWifiRemoteStationManager(linkId)->GetBlockAckTxVector(staAddress,
672
673 auto multiStaBaDuration = WifiPhy::CalculateTxDuration(GetBlockAckSize(baType),
674 multiStaBaTxVector,
675 phy->GetPhyBand());
676
677 return m_triggerTxDuration + m_defaultTbPpduDuration + multiStaBaDuration + 3 * phy->GetSifs();
678}
679
680void
682{
683 NS_LOG_FUNCTION(this << aid << address);
684
685 if (!m_apMac->GetHeSupported(address))
686 {
687 return;
688 }
689
690 auto mldOrLinkAddress = m_apMac->GetMldOrLinkAddressByAid(aid);
691 NS_ASSERT_MSG(mldOrLinkAddress, "AID " << aid << " not found");
692
693 for (auto& staList : m_staListDl)
694 {
695 // if this is not the first STA of a non-AP MLD to be notified, an entry
696 // for this non-AP MLD already exists
697 const auto staIt = std::find_if(staList.second.cbegin(),
698 staList.second.cend(),
699 [aid](auto&& info) { return info.aid == aid; });
700 if (staIt == staList.second.cend())
701 {
702 staList.second.push_back(MasterInfo{aid, *mldOrLinkAddress, 0.0});
703 }
704 }
705
706 const auto staIt = std::find_if(m_staListUl.cbegin(), m_staListUl.cend(), [aid](auto&& info) {
707 return info.aid == aid;
708 });
709 if (staIt == m_staListUl.cend())
710 {
711 m_staListUl.push_back(MasterInfo{aid, *mldOrLinkAddress, 0.0});
712 }
713}
714
715void
717{
718 NS_LOG_FUNCTION(this << aid << address);
719
720 if (!m_apMac->GetHeSupported(address))
721 {
722 return;
723 }
724
725 auto mldOrLinkAddress = m_apMac->GetMldOrLinkAddressByAid(aid);
726 NS_ASSERT_MSG(mldOrLinkAddress, "AID " << aid << " not found");
727
728 if (m_apMac->IsAssociated(*mldOrLinkAddress))
729 {
730 // Another STA of the non-AP MLD is still associated
731 return;
732 }
733
734 for (auto& staList : m_staListDl)
735 {
736 staList.second.remove_if([&aid](const MasterInfo& info) { return info.aid == aid; });
737 }
738 m_staListUl.remove_if([&aid](const MasterInfo& info) { return info.aid == aid; });
739}
740
743{
744 NS_LOG_FUNCTION(this);
745
746 AcIndex primaryAc = m_edca->GetAccessCategory();
747
748 if (m_staListDl[primaryAc].empty())
749 {
750 NS_LOG_DEBUG("No HE stations associated: return SU_TX");
751 return TxFormat::SU_TX;
752 }
753
754 std::size_t count =
755 std::min(static_cast<std::size_t>(m_nStations), m_staListDl[primaryAc].size());
756 std::size_t nCentral26TonesRus{0};
757
758 uint8_t currTid = wifiAcList.at(primaryAc).GetHighTid();
759
761
762 if (mpdu && mpdu->GetHeader().IsQosData())
763 {
764 currTid = mpdu->GetHeader().GetQosTid();
765 }
766
767 // determine the list of TIDs to check
768 std::vector<uint8_t> tids;
769
771 {
772 for (auto acIt = wifiAcList.find(primaryAc); acIt != wifiAcList.end(); acIt++)
773 {
774 uint8_t firstTid = (acIt->first == primaryAc ? currTid : acIt->second.GetHighTid());
775 tids.push_back(firstTid);
776 tids.push_back(acIt->second.GetOtherTid(firstTid));
777 }
778 }
779 else
780 {
781 tids.push_back(currTid);
782 }
783
784 Ptr<HeConfiguration> heConfiguration = m_apMac->GetHeConfiguration();
785 NS_ASSERT(heConfiguration);
786
790 m_txParams.m_txVector.SetGuardInterval(heConfiguration->GetGuardInterval());
791 m_txParams.m_txVector.SetBssColor(heConfiguration->m_bssColor);
792
793 // The TXOP limit can be exceeded by the TXOP holder if it does not transmit more
794 // than one Data or Management frame in the TXOP and the frame is not in an A-MPDU
795 // consisting of more than one MPDU (Sec. 10.22.2.8 of 802.11-2016).
796 // For the moment, we are considering just one MPDU per receiver.
797 Time actualAvailableTime = (m_initialFrame ? Time::Min() : m_availableTime);
798
799 // iterate over the associated stations until an enough number of stations is identified
800 auto staIt = m_staListDl[primaryAc].begin();
801 m_candidates.clear();
802
803 std::vector<uint8_t> ruAllocations;
805 ruAllocations.resize(numRuAllocs);
806 NS_ASSERT((m_candidates.size() % numRuAllocs) == 0);
807
809 while (staIt != m_staListDl[primaryAc].end() &&
810 m_candidates.size() <
811 std::min(static_cast<std::size_t>(m_nStations), count + nCentral26TonesRus))
812 {
813 NS_LOG_DEBUG("Next candidate STA (MAC=" << staIt->address << ", AID=" << staIt->aid << ")");
814
816 !m_apMac->GetEhtSupported(staIt->address))
817 {
818 NS_LOG_DEBUG("Skipping non-EHT STA because this DL MU PPDU is sent to EHT STAs only");
819 staIt++;
820 continue;
821 }
822
823 // check if the AP has at least one frame to be sent to the current station
824 for (uint8_t tid : tids)
825 {
826 AcIndex ac = QosUtilsMapTidToAc(tid);
827 NS_ASSERT(ac >= primaryAc);
828 // check that a BA agreement is established with the receiver for the
829 // considered TID, since ack sequences for DL MU PPDUs require block ack
830 if (m_apMac->GetBaAgreementEstablishedAsOriginator(staIt->address, tid))
831 {
832 mpdu = m_apMac->GetQosTxop(ac)->PeekNextMpdu(m_linkId, tid, staIt->address);
833
834 // we only check if the first frame of the current TID meets the size
835 // and duration constraints. We do not explore the queues further.
836 if (mpdu)
837 {
838 mpdu = GetHeFem(m_linkId)->CreateAliasIfNeeded(mpdu);
839 // Use a temporary TX vector including only the STA-ID of the
840 // candidate station to check if the MPDU meets the size and time limits.
841 // An RU of the computed size is tentatively assigned to the candidate
842 // station, so that the TX duration can be correctly computed.
843 WifiTxVector suTxVector =
844 GetWifiRemoteStationManager(m_linkId)->GetDataTxVector(mpdu->GetHeader(),
846
847 WifiTxVector txVectorCopy = m_txParams.m_txVector;
848
849 // the first candidate STA determines the preamble type for the DL MU PPDU
850 if (m_candidates.empty())
851 {
853 if (suTxVector.GetPreambleType() == WIFI_PREAMBLE_EHT_MU)
854 {
857 0); // indicates DL OFDMA transmission
859 }
861 count,
862 nCentral26TonesRus,
863 mc);
864 NS_ASSERT(count >= 1);
866 {
867 nCentral26TonesRus = 0;
868 }
869 }
870
872 const auto currRuType =
873 (m_candidates.size() < count ? ruType : RuType::RU_26_TONE);
874 const auto ru =
876 ? WifiRu::RuSpec(EhtRu::RuSpec{currRuType, 1, true, true})
877 : WifiRu::RuSpec(HeRu::RuSpec{currRuType, 1, true});
879 staIt->aid,
880 {ru, suTxVector.GetMode().GetMcsValue(), suTxVector.GetNss()});
881
882 if (!GetHeFem(m_linkId)->TryAddMpdu(mpdu, m_txParams, actualAvailableTime))
883 {
884 NS_LOG_DEBUG("Adding the peeked frame violates the time constraints");
885 m_txParams.m_txVector = txVectorCopy;
886 }
887 else
888 {
889 // the frame meets the constraints
890 NS_LOG_DEBUG("Adding candidate STA (MAC=" << staIt->address
891 << ", AID=" << staIt->aid
892 << ") TID=" << +tid);
893 m_candidates.emplace_back(staIt, mpdu);
894 break; // terminate the for loop
895 }
896 }
897 else
898 {
899 NS_LOG_DEBUG("No frames to send to " << staIt->address << " with TID=" << +tid);
900 }
901 }
902 }
903
904 // move to the next station in the list
905 staIt++;
906 }
907
908 if (m_candidates.empty())
909 {
910 if (m_forceDlOfdma)
911 {
912 NS_LOG_DEBUG("The AP does not have suitable frames to transmit: return NO_TX");
913 return NO_TX;
914 }
915 NS_LOG_DEBUG("The AP does not have suitable frames to transmit: return SU_TX");
916 return SU_TX;
917 }
918
919 return TxFormat::DL_MU_TX;
920}
921
922void
924{
925 // Do not log txVector because GetTxVectorForUlMu() left RUs undefined and
926 // printing them will crash the simulation
927 NS_LOG_FUNCTION(this);
928 NS_ASSERT(txVector.GetHeMuUserInfoMap().size() == m_candidates.size());
929
930 // compute how many stations can be granted an RU and the RU size
931 std::size_t nRusAssigned = m_candidates.size();
932 std::size_t nCentral26TonesRus;
934 nRusAssigned,
935 nCentral26TonesRus,
936 txVector.GetModulationClass());
937
938 NS_LOG_DEBUG(nRusAssigned << " stations are being assigned a " << ruType << " RU");
939
940 if (!m_useCentral26TonesRus || m_candidates.size() == nRusAssigned)
941 {
942 nCentral26TonesRus = 0;
943 }
944 else
945 {
946 nCentral26TonesRus = std::min(m_candidates.size() - nRusAssigned, nCentral26TonesRus);
947 NS_LOG_DEBUG(nCentral26TonesRus << " stations are being assigned a 26-tones RU");
948 }
949
950 // re-allocate RUs based on the actual number of candidate stations
951 WifiTxVector::HeMuUserInfoMap heMuUserInfoMap;
952 std::swap(heMuUserInfoMap, txVector.GetHeMuUserInfoMap());
953
954 const auto mc = IsEht(txVector.GetPreambleType()) ? WIFI_MOD_CLASS_EHT : WIFI_MOD_CLASS_HE;
955 auto candidateIt = m_candidates.begin(); // iterator over the list of candidate receivers
956 auto ruSet = WifiRu::GetRusOfType(m_allowedWidth, ruType, mc);
957 auto ruSetIt = ruSet.begin();
958 auto central26TonesRus = WifiRu::GetCentral26TonesRus(m_allowedWidth, ruType, mc);
959 auto central26TonesRusIt = central26TonesRus.begin();
960
961 for (std::size_t i = 0; i < nRusAssigned + nCentral26TonesRus; i++)
962 {
963 NS_ASSERT(candidateIt != m_candidates.end());
964 auto mapIt = heMuUserInfoMap.find(candidateIt->first->aid);
965 NS_ASSERT(mapIt != heMuUserInfoMap.end());
966
967 txVector.SetHeMuUserInfo(mapIt->first,
968 {(i < nRusAssigned ? *ruSetIt++ : *central26TonesRusIt++),
969 mapIt->second.mcs,
970 mapIt->second.nss});
971 candidateIt++;
972 }
973
974 // remove candidates that will not be served
975 m_candidates.erase(candidateIt, m_candidates.end());
976}
977
978void
979RrMultiUserScheduler::UpdateCredits(std::list<MasterInfo>& staList,
980 Time txDuration,
981 const WifiTxVector& txVector)
982{
983 NS_LOG_FUNCTION(this << txDuration.As(Time::US) << txVector);
984
985 // find how many RUs have been allocated for each RU type
986 std::map<RuType, std::size_t> ruMap;
987 for (const auto& userInfo : txVector.GetHeMuUserInfoMap())
988 {
989 ruMap.insert({WifiRu::GetRuType(userInfo.second.ru), 0}).first->second++;
990 }
991
992 // The amount of credits received by each station equals the TX duration (in
993 // microseconds) divided by the number of stations.
994 double creditsPerSta = txDuration.ToDouble(Time::US) / staList.size();
995 // Transmitting stations have to pay a number of credits equal to the TX duration
996 // (in microseconds) times the allocated bandwidth share.
997 double debitsPerMhz =
998 txDuration.ToDouble(Time::US) /
999 std::accumulate(ruMap.begin(), ruMap.end(), 0, [](uint16_t sum, auto pair) {
1000 return sum + pair.second * WifiRu::GetBandwidth(pair.first);
1001 });
1002
1003 // assign credits to all stations
1004 for (auto& sta : staList)
1005 {
1006 sta.credits += creditsPerSta;
1007 sta.credits = std::min(sta.credits, m_maxCredits.ToDouble(Time::US));
1008 }
1009
1010 // subtract debits to the selected stations
1011 for (auto& candidate : m_candidates)
1012 {
1013 auto mapIt = txVector.GetHeMuUserInfoMap().find(candidate.first->aid);
1014 NS_ASSERT(mapIt != txVector.GetHeMuUserInfoMap().end());
1015
1016 candidate.first->credits -=
1017 debitsPerMhz * WifiRu::GetBandwidth(WifiRu::GetRuType(mapIt->second.ru));
1018 }
1019
1020 // sort the list in decreasing order of credits
1021 staList.sort([](const MasterInfo& a, const MasterInfo& b) { return a.credits > b.credits; });
1022}
1023
1026{
1027 NS_LOG_FUNCTION(this);
1028
1029 if (m_candidates.empty())
1030 {
1031 return DlMuInfo();
1032 }
1033
1034 DlMuInfo dlMuInfo;
1035 std::swap(dlMuInfo.txParams.m_txVector, m_txParams.m_txVector);
1037
1038 m_txParams.Clear();
1039 Ptr<WifiMpdu> mpdu;
1040
1041 // Compute the TX params (again) by using the stored MPDUs and the final TXVECTOR
1042 Time actualAvailableTime = (m_initialFrame ? Time::Min() : m_availableTime);
1043
1044 for (const auto& candidate : m_candidates)
1045 {
1046 mpdu = candidate.second;
1047 NS_ASSERT(mpdu);
1048
1049 bool ret [[maybe_unused]] =
1050 GetHeFem(m_linkId)->TryAddMpdu(mpdu, dlMuInfo.txParams, actualAvailableTime);
1051 NS_ASSERT_MSG(ret,
1052 "Weird that an MPDU does not meet constraints when "
1053 "transmitted over a larger RU");
1054 }
1055
1056 // We have to complete the PSDUs to send
1057 Ptr<WifiMacQueue> queue;
1058
1059 for (const auto& candidate : m_candidates)
1060 {
1061 // Let us try first A-MSDU aggregation if possible
1062 mpdu = candidate.second;
1063 NS_ASSERT(mpdu);
1064 uint8_t tid = mpdu->GetHeader().GetQosTid();
1065 NS_ASSERT_MSG(mpdu->GetOriginal()->GetHeader().GetAddr1() == candidate.first->address,
1066 "RA of the stored MPDU must match the stored address");
1067
1068 NS_ASSERT(mpdu->IsQueued());
1069 Ptr<WifiMpdu> item = mpdu;
1070
1071 if (!mpdu->GetHeader().IsRetry())
1072 {
1073 // this MPDU must have been dequeued from the AC queue and we can try
1074 // A-MSDU aggregation
1075 item = GetHeFem(m_linkId)->GetMsduAggregator()->GetNextAmsdu(mpdu,
1076 dlMuInfo.txParams,
1078
1079 if (!item)
1080 {
1081 // A-MSDU aggregation failed or disabled
1082 item = mpdu;
1083 }
1084 m_apMac->GetQosTxop(QosUtilsMapTidToAc(tid))->AssignSequenceNumber(item);
1085 }
1086
1087 // Now, let's try A-MPDU aggregation if possible
1088 std::vector<Ptr<WifiMpdu>> mpduList =
1089 GetHeFem(m_linkId)->GetMpduAggregator()->GetNextAmpdu(item,
1090 dlMuInfo.txParams,
1092
1093 if (mpduList.size() > 1)
1094 {
1095 // A-MPDU aggregation succeeded, update psduMap
1096 dlMuInfo.psduMap[candidate.first->aid] = Create<WifiPsdu>(std::move(mpduList));
1097 }
1098 else
1099 {
1100 dlMuInfo.psduMap[candidate.first->aid] = Create<WifiPsdu>(item, true);
1101 }
1102 }
1103
1104 NS_ASSERT(dlMuInfo.txParams.m_txDuration.has_value());
1105 AcIndex primaryAc = m_edca->GetAccessCategory();
1106 UpdateCredits(m_staListDl[primaryAc],
1107 *dlMuInfo.txParams.m_txDuration,
1108 dlMuInfo.txParams.m_txVector);
1109
1110 NS_LOG_DEBUG("Next station to serve has AID=" << m_staListDl[primaryAc].front().aid);
1111
1112 return dlMuInfo;
1113}
1114
1120
1121} // 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/EHT TB PPDU.
void SetUlLength(uint16_t len)
Set the UL Length subfield of the Common Info field.
RU Specification.
Definition eht-ru.h:34
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:263
RU Specification.
Definition he-ru.h:37
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.
UlMuInfo ComputeUlMuInfo() override
Prepare the information required to solicit an UL MU transmission.
DlMuInfo ComputeDlMuInfo() override
Compute the information required to perform a DL MU transmission.
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
@ US
microsecond
Definition nstime.h:107
@ 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.
static Time CalculateTxDuration(uint32_t size, const WifiTxVector &txVector, WifiPhyBand band, uint16_t staId=SU_STA_ID)
Definition wifi-phy.cc:1563
std::variant< HeRu::RuSpec, EhtRu::RuSpec > RuSpec
variant of the RU specification
Definition wifi-ru.h:27
static std::vector< RuSpec > GetRusOfType(MHz_u bw, RuType ruType, WifiModulationClass mc)
Get the set of distinct RUs of the given type (number of tones) available in an MU PPDU of the given ...
Definition wifi-ru.cc:173
static MHz_u GetBandwidth(RuType ruType)
Get the approximate bandwidth occupied by a RU.
Definition wifi-ru.cc:78
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
static RuType GetRuType(RuSpec ru)
Get the type of a given RU.
Definition wifi-ru.cc:45
static std::vector< RuSpec > GetCentral26TonesRus(MHz_u bw, RuType ruType, WifiModulationClass mc)
Get the set of 26-tone RUs that can be additionally allocated if the given bandwidth is split in RUs ...
Definition wifi-ru.cc:190
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
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.
WifiModulationClass GetModulationClass() const
Get the modulation class specified by this TXVECTOR.
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
WifiModulationClass
This enumeration defines the modulation classes per (Table 10-6 "Modulation classes"; IEEE 802....
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_EHT
EHT (Clause 36)
@ 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
bool IsEht(WifiPreamble preamble)
Return true if a preamble corresponds to an EHT transmission.
RuType
The different Resource Unit (RU) types.
Definition wifi-types.h:99
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:138
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:59
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