23 #include "ns3/wifi-protection.h"
24 #include "ns3/wifi-acknowledgment.h"
25 #include "ns3/wifi-psdu.h"
42 .SetGroupName (
"Wifi")
44 .AddAttribute (
"NStations",
45 "The maximum number of stations that can be granted an RU in a DL MU OFDMA transmission",
48 MakeUintegerChecker<uint8_t> (1, 74))
49 .AddAttribute (
"EnableTxopSharing",
50 "If enabled, allow A-MPDUs of different TIDs in a DL MU PPDU.",
54 .AddAttribute (
"ForceDlOfdma",
55 "If enabled, return DL_MU_TX even if no DL MU PPDU could be built.",
59 .AddAttribute (
"EnableUlOfdma",
60 "If enabled, return UL_MU_TX if DL_MU_TX was returned the previous time.",
64 .AddAttribute (
"EnableBsrp",
65 "If enabled, send a BSRP Trigger Frame before an UL MU transmission.",
69 .AddAttribute (
"UlPsduSize",
70 "The default size in bytes of the solicited PSDU (to be sent in a TB PPDU)",
73 MakeUintegerChecker<uint32_t> ())
74 .AddAttribute (
"UseCentral26TonesRus",
75 "If enabled, central 26-tone RUs are allocated, too, when the "
76 "selected RU type is at least 52 tones.",
80 .AddAttribute (
"MaxCredits",
81 "Maximum amount of credits a station can have. When transmitting a DL MU PPDU, "
82 "the amount of credits received by each station equals the TX duration (in "
83 "microseconds) divided by the total number of stations. Stations that are the "
84 "recipient of the DL MU PPDU have to pay a number of credits equal to the TX "
85 "duration (in microseconds) times the allocated bandwidth share",
109 m_apMac->TraceConnectWithoutContext (
"AssociatedSta",
111 m_apMac->TraceConnectWithoutContext (
"DeAssociatedSta",
128 m_apMac->TraceDisconnectWithoutContext (
"AssociatedSta",
130 m_apMac->TraceDisconnectWithoutContext (
"DeAssociatedSta",
183 receiver =
m_apMac->GetStaList ().at (trigger.
begin ()->GetAid12 ());
203 NS_LOG_DEBUG (
"Remaining TXOP duration is not enough for BSRP TF exchange");
209 for (
const auto& userInfo : trigger)
212 m_apMac->GetWifiPhy ()->GetPhyBand (),
213 userInfo.GetAid12 ());
214 qosNullTxDuration =
Max (qosNullTxDuration, duration);
226 +
m_apMac->GetWifiPhy ()->GetSifs ()
230 NS_LOG_DEBUG (
"Remaining TXOP duration is not enough for BSRP TF exchange");
237 m_apMac->GetWifiPhy ()->GetPhyBand ()));
238 trigger.SetCsRequired (
true);
239 m_heFem->SetTargetRssi (trigger);
241 packet = Create<Packet> ();
243 m_trigger = Create<WifiMacQueueItem> (packet, hdr);
260 uint32_t maxBufferSize = 0;
262 std::multimap<uint8_t, CandidateInfo, std::greater<uint8_t>> ulCandidates;
266 uint8_t queueSize =
m_apMac->GetMaxBufferStatus (candidate.first->address);
267 if (queueSize == 255)
269 NS_LOG_DEBUG (
"Buffer status of station " << candidate.first->address <<
" is unknown");
272 else if (queueSize == 254)
274 NS_LOG_DEBUG (
"Buffer status of station " << candidate.first->address <<
" is not limited");
275 maxBufferSize = 0xffffffff;
279 NS_LOG_DEBUG (
"Buffer status of station " << candidate.first->address <<
" is " << +queueSize);
280 maxBufferSize =
std::max (maxBufferSize,
static_cast<uint32_t
> (queueSize * 256));
285 ulCandidates.emplace (queueSize, candidate);
290 if (maxBufferSize > 0)
293 std::size_t count = ulCandidates.size ();
294 std::size_t nCentral26TonesRus;
296 count, nCentral26TonesRus);
299 nCentral26TonesRus = 0;
303 nCentral26TonesRus =
std::min (ulCandidates.size () - count, nCentral26TonesRus);
308 auto candidateIt = ulCandidates.begin ();
315 for (std::size_t i = 0; i < count + nCentral26TonesRus; i++)
317 NS_ASSERT (candidateIt != ulCandidates.end ());
318 uint16_t staId = candidateIt->second.first->aid;
336 for (std::size_t i = 0; i < count + nCentral26TonesRus; i++)
338 NS_ASSERT (candidateIt != ulCandidates.end ());
339 uint16_t staId = candidateIt->second.first->aid;
346 userInfoIt->GetNss ()});
353 ulCandidates.erase (candidateIt, ulCandidates.end ());
361 if (ulCandidates.size () == 1)
363 receiver = ulCandidates.begin ()->second.first->address;
387 NS_LOG_DEBUG (
"Remaining TXOP duration is not enough for UL MU exchange");
401 -
m_apMac->GetWifiPhy ()->GetSifs ()
405 NS_LOG_DEBUG (
"Remaining TXOP duration is not enough for UL MU exchange");
412 for (
const auto& userInfo : trigger)
415 m_apMac->GetWifiPhy ()->GetPhyBand (),
416 userInfo.GetAid12 ());
417 bufferTxTime =
Max (bufferTxTime, duration);
420 if (bufferTxTime < maxDuration)
423 maxDuration = bufferTxTime;
430 for (
const auto& userInfo : trigger)
433 m_apMac->GetWifiPhy ()->GetPhyBand (),
434 userInfo.GetAid12 ());
435 minDuration = (minDuration.
IsZero () ? duration :
Min (minDuration, duration));
438 if (maxDuration < minDuration)
451 m_apMac->GetWifiPhy ()->GetPhyBand ()));
452 trigger.SetCsRequired (
true);
453 m_heFem->SetTargetRssi (trigger);
455 for (
auto& userInfo : trigger)
460 packet = Create<Packet> ();
462 m_trigger = Create<WifiMacQueueItem> (packet, hdr);
510 NS_LOG_DEBUG (
"No HE stations associated: return SU_TX");
511 return TxFormat::SU_TX;
515 std::size_t nCentral26TonesRus;
522 nCentral26TonesRus = 0;
525 uint8_t currTid =
wifiAcList.at (primaryAc).GetHighTid ();
529 if (mpdu !=
nullptr && mpdu->GetHeader ().IsQosData ())
531 currTid = mpdu->GetHeader ().GetQosTid ();
535 std::vector<uint8_t> tids;
541 uint8_t firstTid = (acIt->first == primaryAc ? currTid : acIt->second.GetHighTid ());
542 tids.push_back (firstTid);
543 tids.push_back (acIt->second.GetOtherTid (firstTid));
548 tids.push_back (currTid);
567 auto staIt =
m_staList[primaryAc].begin ();
570 while (staIt !=
m_staList[primaryAc].end ()
573 NS_LOG_DEBUG (
"Next candidate STA (MAC=" << staIt->address <<
", AID=" << staIt->aid <<
")");
578 for (uint8_t tid : tids)
584 if (
m_apMac->GetQosTxop (ac)->GetBaAgreementEstablished (staIt->address, tid))
586 mpdu =
m_apMac->GetQosTxop (ac)->PeekNextMpdu (tid, staIt->address);
600 {{currRuType, 1, false},
606 NS_LOG_DEBUG (
"Adding the peeked frame violates the time constraints");
612 NS_LOG_DEBUG (
"Adding candidate STA (MAC=" << staIt->address <<
", AID="
613 << staIt->aid <<
") TID=" << +tid);
620 NS_LOG_DEBUG (
"No frames to send to " << staIt->address <<
" with TID=" << +tid);
629 if (m_candidates.empty ())
633 NS_LOG_DEBUG (
"The AP does not have suitable frames to transmit: return NO_TX");
636 NS_LOG_DEBUG (
"The AP does not have suitable frames to transmit: return SU_TX");
640 return TxFormat::DL_MU_TX;
643 MultiUserScheduler::DlMuInfo
644 RrMultiUserScheduler::ComputeDlMuInfo (
void)
648 if (m_candidates.empty ())
653 uint16_t bw = m_apMac->GetWifiPhy ()->GetChannelWidth ();
656 std::size_t nRusAssigned = m_txParams.GetPsduInfoMap ().size ();
657 std::size_t nCentral26TonesRus;
658 HeRu::RuType ruType = HeRu::GetEqualSizedRusForStations (bw, nRusAssigned, nCentral26TonesRus);
660 NS_LOG_DEBUG (nRusAssigned <<
" stations are being assigned a " << ruType <<
" RU");
662 if (!m_useCentral26TonesRus || m_candidates.size () == nRusAssigned)
664 nCentral26TonesRus = 0;
668 nCentral26TonesRus =
std::min (m_candidates.size () - nRusAssigned, nCentral26TonesRus);
669 NS_LOG_DEBUG (nCentral26TonesRus <<
" stations are being assigned a 26-tones RU");
680 auto candidateIt = m_candidates.begin ();
682 for (std::size_t i = 0; i < nRusAssigned + nCentral26TonesRus; i++)
684 NS_ASSERT (candidateIt != m_candidates.end ());
686 uint16_t staId = candidateIt->first->aid;
689 {{(i < nRusAssigned ? ruType : HeRu::RU_26_TONE), 1,
false},
690 m_txParams.m_txVector.GetMode (staId),
691 m_txParams.m_txVector.GetNss (staId)});
696 m_candidates.erase (candidateIt, m_candidates.end ());
704 Time actualAvailableTime = (m_initialFrame ?
Time::Min () : m_availableTime);
706 for (
const auto& candidate : m_candidates)
708 mpdu = candidate.second;
711 bool ret = m_heFem->TryAddMpdu (mpdu, dlMuInfo.
txParams, actualAvailableTime);
713 NS_ASSERT_MSG (ret,
"Weird that an MPDU does not meet constraints when "
714 "transmitted over a larger RU");
721 for (
const auto& candidate : m_candidates)
724 mpdu = candidate.second;
726 uint8_t tid = mpdu->GetHeader ().GetQosTid ();
727 receiver = mpdu->GetHeader ().GetAddr1 ();
728 NS_ASSERT (receiver == candidate.first->address);
735 if (!mpdu->GetHeader ().IsRetry ())
739 item = m_heFem->GetMsduAggregator ()->GetNextAmsdu (mpdu, dlMuInfo.
txParams, m_availableTime, queueIt);
744 item = *mpdu->GetQueueIterator ();
750 std::vector<Ptr<WifiMacQueueItem>> mpduList = m_heFem->GetMpduAggregator ()->GetNextAmpdu (item, dlMuInfo.
txParams, m_availableTime, queueIt);
752 if (mpduList.size () > 1)
755 dlMuInfo.
psduMap[candidate.first->aid] = Create<WifiPsdu> (std::move (mpduList));
759 dlMuInfo.
psduMap[candidate.first->aid] = Create<WifiPsdu> (item,
true);
763 AcIndex primaryAc = m_edca->GetAccessCategory ();
768 / m_staList[primaryAc].size ();
772 / (nRusAssigned * HeRu::GetBandwidth (ruType)
773 + nCentral26TonesRus * HeRu::GetBandwidth (HeRu::RU_26_TONE));
776 for (
auto& sta : m_staList[primaryAc])
778 sta.credits += creditsPerSta;
779 sta.credits =
std::min (sta.credits, m_maxCredits.ToDouble (Time::US));
783 candidateIt = m_candidates.begin ();
785 for (std::size_t i = 0; i < nRusAssigned + nCentral26TonesRus; i++)
787 NS_ASSERT (candidateIt != m_candidates.end ());
789 candidateIt->first->credits -= debitsPerMhz * HeRu::GetBandwidth (i < nRusAssigned ? ruType : HeRu::RU_26_TONE);
798 NS_LOG_DEBUG (
"Next station to serve has AID=" << m_staList[primaryAc].front ().aid);
811 std::set<HeRu::RuType> ruTypeSet;
814 ruTypeSet.insert (userInfo.second.ru.GetRuType ());
817 std::vector<HeRu::RuSpec> ruSet, central26TonesRus;
820 if (ruTypeSet.size () == 2)
823 NS_ASSERT (ruTypeSet.find (HeRu::RU_26_TONE) != ruTypeSet.end ());
824 ruTypeSet.erase (HeRu::RU_26_TONE);
826 central26TonesRus = HeRu::GetCentral26TonesRus (bw, *ruTypeSet.begin ());
830 ruSet = HeRu::GetRusOfType (bw, *ruTypeSet.begin ());
832 auto ruSetIt = ruSet.begin ();
833 auto central26TonesRusIt = central26TonesRus.begin ();
837 if (userInfo.second.ru.GetRuType () == *ruTypeSet.begin ())
840 txVector.
SetRu (*ruSetIt, userInfo.first);
845 NS_ASSERT (central26TonesRusIt != central26TonesRus.end ());
846 txVector.
SetRu (*central26TonesRusIt, userInfo.first);
847 central26TonesRusIt++;
853 RrMultiUserScheduler::ComputeUlMuInfo (
void)
855 return UlMuInfo {m_trigger, m_tbPpduDuration, std::move (m_txParams)};