5G-LENA nr-v3.3-120-gdac69c56
The 5G/NR module for the ns-3 simulator
Loading...
Searching...
No Matches
nr-mac-scheduler-ns3.cc
1// Copyright (c) 2019 Centre Tecnologic de Telecomunicacions de Catalunya (CTTC)
2//
3// SPDX-License-Identifier: GPL-2.0-only
4
5#define NS_LOG_APPEND_CONTEXT \
6 do \
7 { \
8 std::clog << " [ CellId " << GetCellId() << ", bwpId " << GetBwpId() << "] "; \
9 } while (false);
10
11#include "nr-mac-scheduler-ns3.h"
12
13#include "nr-fh-control.h"
14#include "nr-mac-scheduler-harq-rr.h"
15#include "nr-mac-scheduler-lc-rr.h"
16#include "nr-mac-scheduler-srs-default.h"
17#include "nr-mac-short-bsr-ce.h"
18
19#include "ns3/boolean.h"
20#include "ns3/enum.h"
21#include "ns3/integer.h"
22#include "ns3/log.h"
23#include "ns3/pointer.h"
24#include "ns3/uinteger.h"
25
26#include <algorithm>
27#include <memory>
28#include <unordered_set>
29
30namespace ns3
31{
32
33NS_LOG_COMPONENT_DEFINE("NrMacSchedulerNs3");
34NS_OBJECT_ENSURE_REGISTERED(NrMacSchedulerNs3);
35
38{
39 NS_LOG_FUNCTION_NOARGS();
40
41 // Hardcoded, but the type can be a parameter if needed
42 m_schedHarq = std::make_unique<NrMacSchedulerHarqRr>();
43 m_schedHarq->InstallGetBwInRBG(std::bind(&NrMacSchedulerNs3::GetBandwidthInRbg, this));
44 m_schedHarq->InstallGetBwpIdFn(std::bind(&NrMacSchedulerNs3::GetBwpId, this));
45 m_schedHarq->InstallGetCellIdFn(std::bind(&NrMacSchedulerNs3::GetCellId, this));
46 m_schedHarq->InstallGetFhControlMethodFn(
48 m_schedHarq->InstallDoesFhAllocationFitFn(
49 std::bind_front(&NrMacSchedulerNs3::DoesFhAllocationFit, this));
50
51 m_cqiManagement.InstallGetBwpIdFn(std::bind(&NrMacSchedulerNs3::GetBwpId, this));
52 m_cqiManagement.InstallGetCellIdFn(std::bind(&NrMacSchedulerNs3::GetCellId, this));
53 m_cqiManagement.InstallGetNrAmcDlFn([this]() { return m_dlAmc; });
54 m_cqiManagement.InstallGetNrAmcUlFn([this]() { return m_ulAmc; });
55 m_cqiManagement.InstallGetStartMcsDlFn([this]() { return m_startMcsDl; });
56 m_cqiManagement.InstallGetStartMcsUlFn([this]() { return m_startMcsUl; });
57
58 // If more Srs allocators will be created, then we will add an attribute
59 m_schedulerSrs = CreateObject<NrMacSchedulerSrsDefault>();
61}
62
64{
65 m_ueMap.clear();
66 delete m_nrFhSchedSapUser;
67 m_nrFhSchedSapUser = nullptr;
68 m_nrFhSchedSapProvider = nullptr;
69}
70
71void
72NrMacSchedulerNs3::InstallDlAmc(const Ptr<NrAmc>& dlAmc)
73{
74 m_dlAmc = dlAmc;
75 m_dlAmc->SetDlMode();
76}
77
78void
79NrMacSchedulerNs3::InstallUlAmc(const Ptr<NrAmc>& ulAmc)
80{
81 m_ulAmc = ulAmc;
82 m_ulAmc->SetUlMode();
83}
84
85Ptr<const NrAmc>
87{
88 NS_LOG_FUNCTION(this);
89 return m_ulAmc;
90}
91
92Ptr<const NrAmc>
94{
95 NS_LOG_FUNCTION(this);
96 return m_dlAmc;
97}
98
99int64_t
101{
102 NS_LOG_FUNCTION(this << stream);
103 return m_schedulerSrs->AssignStreams(stream);
104}
105
106TypeId
108{
109 static TypeId tid =
110 TypeId("ns3::NrMacSchedulerNs3")
111 .SetParent<NrMacScheduler>()
112 .AddAttribute("CqiTimerThreshold",
113 "The time while a CQI is valid",
114 TimeValue(Seconds(1)),
117 MakeTimeChecker())
118 .AddAttribute("FixedMcsDl",
119 "Fix MCS to value set in StartingMcsDl",
120 BooleanValue(false),
121 MakeBooleanAccessor(&NrMacSchedulerNs3::SetFixedDlMcs,
123 MakeBooleanChecker())
124 .AddAttribute("FixedMcsUl",
125 "Fix MCS to value set in StartingMcsUl",
126 BooleanValue(false),
127 MakeBooleanAccessor(&NrMacSchedulerNs3::SetFixedUlMcs,
129 MakeBooleanChecker())
130 .AddAttribute("StartingMcsDl",
131 "Starting MCS for DL",
132 UintegerValue(0),
133 MakeUintegerAccessor(&NrMacSchedulerNs3::SetStartMcsDl,
135 MakeUintegerChecker<uint8_t>())
136 .AddAttribute("StartingMcsUl",
137 "Starting MCS for UL",
138 UintegerValue(0),
139 MakeUintegerAccessor(&NrMacSchedulerNs3::SetStartMcsUl,
141 MakeUintegerChecker<uint8_t>())
142 .AddAttribute("DlCtrlSymbols",
143 "Number of symbols allocated for DL CTRL",
144 UintegerValue(1),
145 MakeUintegerAccessor(&NrMacSchedulerNs3::SetDlCtrlSyms,
147 MakeUintegerChecker<uint8_t>())
148 .AddAttribute("UlCtrlSymbols",
149 "Number of symbols allocated for UL CTRL",
150 UintegerValue(1),
151 MakeUintegerAccessor(&NrMacSchedulerNs3::SetUlCtrlSyms,
153 MakeUintegerChecker<uint8_t>())
154 .AddAttribute("SrsSymbols",
155 "Number of symbols allocated for UL SRS",
156 UintegerValue(1),
157 MakeUintegerAccessor(&NrMacSchedulerNs3::SetSrsCtrlSyms,
159 MakeUintegerChecker<uint8_t>())
160 .AddAttribute("EnableSrsInUlSlots",
161 "Denotes whether the SRSs will be transmitted only in F slots"
162 "or both in F and UL slots. If False, SRS is transmitted only"
163 "in F slots, if True in both (F/UL)",
164 BooleanValue(true),
165 MakeBooleanAccessor(&NrMacSchedulerNs3::SetSrsInUlSlots,
167 MakeBooleanChecker())
168 .AddAttribute("EnableSrsInFSlots",
169 "Denotes whether the SRSs will be transmitted in F slots"
170 "If true, it can be transmitted in F slots, otherwise "
171 "it cannot.",
172 BooleanValue(true),
173 MakeBooleanAccessor(&NrMacSchedulerNs3::SetSrsInFSlots,
175 MakeBooleanChecker())
176 .AddAttribute("DlAmc",
177 "The DL AMC of this scheduler",
178 PointerValue(),
179 MakePointerAccessor(&NrMacSchedulerNs3::m_dlAmc),
180 MakePointerChecker<NrAmc>())
181 .AddAttribute("UlAmc",
182 "The UL AMC of this scheduler",
183 PointerValue(),
184 MakePointerAccessor(&NrMacSchedulerNs3::m_ulAmc),
185 MakePointerChecker<NrAmc>())
186 .AddAttribute("MaxDlMcs",
187 "Maximum MCS index for DL",
188 IntegerValue(-1),
189 MakeIntegerAccessor(&NrMacSchedulerNs3::SetMaxDlMcs,
191 MakeIntegerChecker<int8_t>(-1, 30))
192 .AddAttribute("EnableHarqReTx",
193 "If true, it would set the max HARQ ReTx to 3; otherwise it set it to 0",
194 BooleanValue(true),
195 MakeBooleanAccessor(&NrMacSchedulerNs3::EnableHarqReTx,
197 MakeBooleanChecker())
198 .AddAttribute(
199 "SchedLcAlgorithmType",
200 "Type of the scheduling algorithm that assigns bytes to the different LCs.",
201 TypeIdValue(NrMacSchedulerLcRR::GetTypeId()),
202 MakeTypeIdAccessor(&NrMacSchedulerNs3::SetLcSched),
203 //&NrMacSchedulerNs3::GetLcSched),
204 MakeTypeIdChecker())
205 .AddAttribute("RachUlGrantMcs",
206 "The MCS of the RACH UL grant, must be [0..15] (default 0)",
207 UintegerValue(0),
208 MakeUintegerAccessor(&NrMacSchedulerNs3::SetRachUlGrantMcs),
209 MakeUintegerChecker<uint8_t>())
210 .AddAttribute(
211 "McsCsiSource",
212 "Choose which CSI information is used to estimate DL MCS(default AVG_MCS)",
214 MakeEnumAccessor<NrMacSchedulerUeInfo::McsCsiSource>(
216 MakeEnumChecker<NrMacSchedulerUeInfo::McsCsiSource>(
218 "AVG_MCS",
220 "AVG_SPEC_EFF",
222 "AVG_SINR",
224 "WIDEBAND_MCS"))
225 .AddTraceSource("CsiFeedbackReceived",
226 "Received CSI feedback post-processed by the scheduler CQI management",
227 MakeTraceSourceAccessor(&NrMacSchedulerNs3::m_csiFeedbackReceived),
228 "ns3::NrMacSchedulerNs3::CsiFeedbackReceived::TracedCallback");
229
230 return tid;
231}
232
240void
242{
243 NS_LOG_FUNCTION(this);
244 m_fixedMcsDl = true;
245 m_fixedMcsUl = true;
246 m_startMcsDl = static_cast<uint8_t>(mcs);
247 m_startMcsUl = static_cast<uint8_t>(mcs);
248}
249
250void
253{
254 NS_LOG_FUNCTION(this);
255
256 m_rachList = params.m_rachList;
257}
258
259void
261{
262 NS_LOG_FUNCTION(this);
263 m_cqiTimersThreshold = v;
264}
265
266Time
268{
269 NS_LOG_FUNCTION(this);
270 return m_cqiTimersThreshold;
271}
272
273void
275{
276 NS_LOG_FUNCTION(this);
277 m_fixedMcsDl = v;
278}
279
280bool
282{
283 NS_LOG_FUNCTION(this);
284 return m_fixedMcsDl;
285}
286
287void
289{
290 NS_LOG_FUNCTION(this);
291 m_fixedMcsUl = v;
292}
293
294bool
296{
297 NS_LOG_FUNCTION(this);
298 return m_fixedMcsUl;
299}
300
301void
303{
304 NS_LOG_FUNCTION(this);
305 m_startMcsDl = v;
306}
307
308uint8_t
310{
311 NS_LOG_FUNCTION(this);
312 return m_startMcsDl;
313}
314
315void
317{
318 NS_LOG_FUNCTION(this);
319 m_maxDlMcs = v;
320}
321
322int8_t
324{
325 NS_LOG_FUNCTION(this);
326 return m_maxDlMcs;
327}
328
329void
331{
332 m_rachUlGrantMcs = v;
333}
334
335void
337{
338 NS_LOG_FUNCTION(this);
339 ObjectFactory factory;
340 m_schedLcType = type;
341
342 factory.SetTypeId(m_schedLcType);
343 m_schedLc = DynamicCast<NrMacSchedulerLcAlgorithm>(factory.Create());
344 NS_ASSERT(m_schedLc != nullptr);
345}
346
347void
349{
350 NS_LOG_FUNCTION(this);
351 m_startMcsUl = v;
352}
353
354uint8_t
356{
357 NS_LOG_FUNCTION(this);
358 return m_startMcsUl;
359}
360
361void
363{
364 m_dlCtrlSymbols = v;
365}
366
367uint8_t
369{
370 return m_dlCtrlSymbols;
371}
372
373void
375{
376 m_ulCtrlSymbols = v;
377}
378
379void
380NrMacSchedulerNs3::SetDlNotchedRbgMask(const std::vector<bool>& dlNotchedRbgsMask)
381{
382 NS_LOG_FUNCTION(this);
383 m_dlNotchedRbgsMask = dlNotchedRbgsMask;
384 std::stringstream ss;
385
386 // print the DL mask set (prefix + is added just for printing purposes)
387 for (const auto& x : m_dlNotchedRbgsMask)
388 {
389 ss << +x << " ";
390 }
391 NS_LOG_INFO("Set DL notched mask: " << ss.str());
392}
393
394std::vector<bool>
396{
397 return m_dlNotchedRbgsMask;
398}
399
400void
401NrMacSchedulerNs3::SetUlNotchedRbgMask(const std::vector<bool>& ulNotchedRbgsMask)
402{
403 NS_LOG_FUNCTION(this);
404 m_ulNotchedRbgsMask = ulNotchedRbgsMask;
405 std::stringstream ss;
406
407 // print the UL mask set (prefix + is added just for printing purposes)
408 for (const auto& x : m_ulNotchedRbgsMask)
409 {
410 ss << +x << " ";
411 }
412 NS_LOG_INFO("Set UL notched mask: " << ss.str());
413}
414
415std::vector<bool>
417{
418 return m_ulNotchedRbgsMask;
419}
420
421void
423{
424 m_srsCtrlSymbols = v;
425}
426
427uint8_t
429{
430 return m_srsCtrlSymbols;
431}
432
433void
435{
436 m_enableSrsInUlSlots = v;
437}
438
439bool
441{
442 return m_enableSrsInUlSlots;
443}
444
445void
447{
448 m_enableSrsInFSlots = v;
449}
450
451bool
453{
454 return m_enableSrsInFSlots;
455}
456
457void
459{
460 m_enableHarqReTx = enableFlag;
461}
462
463bool
465{
466 return m_enableHarqReTx;
467}
468
469void
474
480
481uint8_t
483 uint8_t symAvail,
484 const NrMacSchedulerNs3::ActiveHarqMap& activeDlHarq,
485 const std::unordered_map<uint16_t, UePtr>& ueMap,
486 std::vector<DlHarqInfo>* dlHarqToRetransmit,
487 const std::vector<DlHarqInfo>& dlHarqFeedback,
488 SlotAllocInfo* slotAlloc) const
489{
490 NS_LOG_FUNCTION(this);
491 return m_schedHarq->ScheduleDlHarq(startingPoint,
492 symAvail,
493 activeDlHarq,
494 ueMap,
495 dlHarqToRetransmit,
496 dlHarqFeedback,
497 slotAlloc);
498}
499
500uint8_t
502 uint8_t symAvail,
503 const std::unordered_map<uint16_t, UePtr>& ueMap,
504 std::vector<UlHarqInfo>* ulHarqToRetransmit,
505 const std::vector<UlHarqInfo>& ulHarqFeedback,
506 SlotAllocInfo* slotAlloc) const
507{
508 NS_LOG_FUNCTION(this);
509 return m_schedHarq->ScheduleUlHarq(startingPoint,
510 symAvail,
511 ueMap,
512 ulHarqToRetransmit,
513 ulHarqFeedback,
514 slotAlloc);
515}
516
517void
519{
520 NS_LOG_FUNCTION(this);
521 m_schedHarq->SortDlHarq(activeDlHarq);
522}
523
524void
526{
527 NS_LOG_FUNCTION(this);
528 m_schedHarq->SortDlHarq(activeUlHarq);
529}
530
531uint8_t
533{
534 return m_ulCtrlSymbols;
535}
536
543void
546{
547 NS_LOG_FUNCTION(this);
548
549 NS_ASSERT(params.m_ulBandwidth == params.m_dlBandwidth);
550 m_bandwidth = params.m_dlBandwidth;
551
553 cnf.m_result = NrMacCschedSapUser::Result_e::SUCCESS;
554 m_macCschedSapUser->CschedUeConfigCnf(cnf);
555}
556
566void
569{
570 NS_LOG_FUNCTION(this << " RNTI " << params.m_rnti << " txMode "
571 << static_cast<uint32_t>(params.m_transmissionMode));
572
573 auto itUe = m_ueMap.find(params.m_rnti);
574 GetSecond UeInfoOf;
575 if (itUe == m_ueMap.end())
576 {
577 itUe = m_ueMap.insert(std::make_pair(params.m_rnti, CreateUeRepresentation(params))).first;
578
579 UeInfoOf(*itUe)->m_dlHarq.SetMaxSize(
580 static_cast<uint8_t>(m_macSchedSapUser->GetNumHarqProcess()));
581 UeInfoOf(*itUe)->m_ulHarq.SetMaxSize(
582 static_cast<uint8_t>(m_macSchedSapUser->GetNumHarqProcess()));
583 UeInfoOf(*itUe)->m_dlMcs = m_startMcsDl;
584 UeInfoOf(*itUe)->m_startMcsDlUe = m_startMcsDl;
585 UeInfoOf(*itUe)->m_ulMcs = m_startMcsUl;
586 UeInfoOf(*itUe)->m_dlAmc = m_dlAmc;
587 UeInfoOf(*itUe)->m_ulAmc = m_ulAmc;
588 UeInfoOf(*itUe)->m_mcsCsiSource = m_mcsCsiSource;
589
590 NrMacSchedulerSrs::SrsPeriodicityAndOffset srs = m_schedulerSrs->AddUe();
591
592 if (!srs.m_isValid)
593 {
594 bool ret = m_schedulerSrs->IncreasePeriodicity(
595 &m_ueMap); // The new UE will get the SRS offset/periodicity here
596 NS_ASSERT(ret);
597 }
598 else
599 {
600 UeInfoOf(*itUe)->m_srsPeriodicity =
601 srs.m_periodicity; // set the periodicity/offset based on the return value
602 UeInfoOf(*itUe)->m_srsOffset = srs.m_offset;
603 }
604
605 NS_LOG_INFO("Creating user, beam " << params.m_beamId << " and ue " << params.m_rnti
606 << " assigned SRS periodicity " << srs.m_periodicity
607 << " and offset " << srs.m_offset);
608 }
609 else
610 {
611 NS_LOG_LOGIC("Updating Beam for UE " << params.m_rnti << " beam " << params.m_beamId);
612 UeInfoOf(*itUe)->m_beamId = params.m_beamId;
613 }
614}
615
623void
626{
627 NS_LOG_FUNCTION(this << " Release RNTI " << params.m_rnti);
628
629 auto itUe = m_ueMap.find(params.m_rnti);
630 NS_ABORT_IF(itUe == m_ueMap.end());
631
632 m_schedulerSrs->RemoveUe(itUe->second->m_srsOffset);
633 m_ueMap.erase(itUe);
634
635 // When it will be the case of reducing the periodicity? Question for the
636 // future...
637
638 NS_LOG_INFO("Release RNTI " << params.m_rnti);
639}
640
641uint64_t
646
657LCPtr
659{
660 NS_LOG_FUNCTION(this);
661 return std::make_unique<NrMacSchedulerLC>(config);
662}
663
674LCGPtr
676{
677 NS_LOG_FUNCTION(this);
678 return std::make_unique<NrMacSchedulerLCG>(config.m_logicalChannelGroup);
679}
680
694void
697{
698 NS_LOG_FUNCTION(this << static_cast<uint32_t>(params.m_rnti));
699 auto itUe = m_ueMap.find(params.m_rnti);
700 GetSecond UeInfoOf;
701 NS_ABORT_IF(itUe == m_ueMap.end());
702
703 for (const auto& lcConfig : params.m_logicalChannelConfigList)
704 {
705 if (lcConfig.m_direction == nr::LogicalChannelConfigListElement_s::DIR_DL ||
706 lcConfig.m_direction == nr::LogicalChannelConfigListElement_s::DIR_BOTH)
707 {
708 auto itDl = UeInfoOf(*itUe)->m_dlLCG.find(lcConfig.m_logicalChannelGroup);
709 auto itDlEnd = UeInfoOf(*itUe)->m_dlLCG.end();
710 if (itDl == itDlEnd)
711 {
712 NS_LOG_DEBUG("Created DL LCG for UE "
713 << UeInfoOf(*itUe)->m_rnti
714 << " ID=" << static_cast<uint32_t>(lcConfig.m_logicalChannelGroup));
715 std::unique_ptr<NrMacSchedulerLCG> lcg = CreateLCG(lcConfig);
716 itDl = UeInfoOf(*itUe)
717 ->m_dlLCG.emplace(lcConfig.m_logicalChannelGroup, std::move(lcg))
718 .first;
719 }
720
721 itDl->second->Insert(CreateLC(lcConfig));
722 NS_LOG_DEBUG("Created DL LC for UE "
723 << UeInfoOf(*itUe)->m_rnti
724 << " ID=" << static_cast<uint32_t>(lcConfig.m_logicalChannelIdentity)
725 << " in LCG " << static_cast<uint32_t>(lcConfig.m_logicalChannelGroup));
726 }
727 if (lcConfig.m_direction == nr::LogicalChannelConfigListElement_s::DIR_UL ||
728 lcConfig.m_direction == nr::LogicalChannelConfigListElement_s::DIR_BOTH)
729 {
730 auto itUl = UeInfoOf(*itUe)->m_ulLCG.find(lcConfig.m_logicalChannelGroup);
731 auto itUlEnd = UeInfoOf(*itUe)->m_ulLCG.end();
732 if (itUl == itUlEnd)
733 {
734 NS_LOG_DEBUG("Created UL LCG for UE "
735 << UeInfoOf(*itUe)->m_rnti
736 << " ID=" << static_cast<uint32_t>(lcConfig.m_logicalChannelGroup));
737 std::unique_ptr<NrMacSchedulerLCG> lcg = CreateLCG(lcConfig);
738 itUl = UeInfoOf(*itUe)
739 ->m_ulLCG.emplace(lcConfig.m_logicalChannelGroup, std::move(lcg))
740 .first;
741 }
742
743 // Create a LC ID only if it is the first. For detail, see documentation
744 // of NrMacSchedulerLCG.
745 if (itUl->second->NumOfLC() == 0)
746 {
747 itUl->second->Insert(CreateLC(lcConfig));
748 NS_LOG_DEBUG("Created UL LC for UE "
749 << UeInfoOf(*itUe)->m_rnti
750 << " ID=" << static_cast<uint32_t>(lcConfig.m_logicalChannelIdentity)
751 << " in LCG "
752 << static_cast<uint32_t>(lcConfig.m_logicalChannelGroup));
753 }
754 }
755 }
756}
757
762void
765{
766 NS_LOG_FUNCTION(this);
767
768 for (const auto& lcId : params.m_logicalChannelIdentity)
769 {
770 auto itUe = m_ueMap.find(params.m_rnti);
771 NS_ABORT_IF(itUe == m_ueMap.end());
772 itUe->second->ReleaseLC(lcId);
773 }
774}
775
784void
787{
788 NS_LOG_FUNCTION(this << params.m_rnti
789 << static_cast<uint32_t>(params.m_logicalChannelIdentity));
790
791 GetSecond UeInfoOf;
792 auto itUe = m_ueMap.find(params.m_rnti);
793 NS_ABORT_IF(itUe == m_ueMap.end());
794
795 for (const auto& lcg : UeInfoOf(*itUe)->m_dlLCG)
796 {
797 if (lcg.second->Contains(params.m_logicalChannelIdentity))
798 {
799 NS_LOG_INFO("Updating DL LC Info: " << params
800 << " in LCG: " << static_cast<uint32_t>(lcg.first));
801 lcg.second->UpdateInfo(params);
802
804 {
805 m_nrFhSchedSapProvider->SetActiveUe(GetBwpId(),
806 params.m_rnti,
807 lcg.second->GetTotalSize());
808 }
809 return;
810 }
811 }
812 // Fail miserabily because we didn't found any LC
813 NS_FATAL_ERROR("The LC does not exist. Can't update");
814}
815
825void
826NrMacSchedulerNs3::BSRReceivedFromUe(const MacCeElement& bsr)
827{
828 NS_LOG_FUNCTION(this);
829 NS_ASSERT(bsr.m_macCeType == MacCeElement::BSR);
830 GetSecond UeInfoOf;
831 auto itUe = m_ueMap.find(bsr.m_rnti);
832 NS_ABORT_IF(itUe == m_ueMap.end());
833
834 // The UE only notifies the buf size as sum of all components.
835 // see nr-ue-mac.cc:395
836 for (uint8_t lcg = 0; lcg < 4; ++lcg)
837 {
838 uint8_t bsrId = bsr.m_macCeValue.m_bufferStatus.at(lcg);
839 uint32_t bufSize = NrMacShortBsrCe::FromLevelToBytes(bsrId);
840
841 auto itLcg = UeInfoOf(*itUe)->m_ulLCG.find(lcg);
842 if (itLcg == UeInfoOf(*itUe)->m_ulLCG.end())
843 {
844 // NS_ABORT_MSG_IF(bufSize > 0,
845 // "LCG " << static_cast<uint32_t>(lcg) << " not found for UE "
846 // << itUe->second->m_rnti);
847 NS_LOG_DEBUG("BSR does not match an established lcg");
848 continue;
849 }
850
851 if (itLcg->second->GetTotalSize() > 0 || bufSize > 0)
852 {
853 NS_LOG_INFO("Updating UL LCG " << static_cast<uint32_t>(lcg) << " for UE " << bsr.m_rnti
854 << " size " << bufSize);
855 }
856
857 itLcg->second->UpdateInfo(bufSize);
858 }
859}
860
868void
871{
872 NS_LOG_FUNCTION(this);
873
874 for (const auto& element : params.m_macCeList)
875 {
876 if (element.m_macCeType == MacCeElement::BSR)
877 {
878 BSRReceivedFromUe(element);
879 }
880 else
881 {
882 NS_LOG_INFO("Ignoring received CTRL message because it's not a BSR");
883 }
884 }
885}
886
897void
900{
901 NS_LOG_FUNCTION(this);
902
903 if (m_fixedMcsDl)
904 {
905 return;
906 }
907
908 NS_ASSERT(m_cqiTimersThreshold >= m_macSchedSapUser->GetSlotPeriod());
909
910 uint32_t expirationTime =
911 static_cast<uint32_t>(m_cqiTimersThreshold.GetNanoSeconds() /
912 m_macSchedSapUser->GetSlotPeriod().GetNanoSeconds());
913
914 for (const auto& cqi : params.m_cqiList)
915 {
916 NS_ASSERT(m_ueMap.find(cqi.m_rnti) != m_ueMap.end());
917 const std::shared_ptr<NrMacSchedulerUeInfo>& ue = m_ueMap.find(cqi.m_rnti)->second;
918 m_cqiManagement.DlCqiReported(cqi, ue, expirationTime, m_maxDlMcs, GetBandwidthInRbg());
919 m_csiFeedbackReceived(GetCellId(), GetBwpId(), ue);
920 }
921}
922
936void
939{
940 NS_LOG_FUNCTION(this);
941
942 if (m_fixedMcsUl)
943 {
944 return;
945 }
946
947 GetSecond UeInfoOf;
948
949 uint32_t expirationTime =
950 static_cast<uint32_t>(m_cqiTimersThreshold.GetNanoSeconds() /
951 m_macSchedSapUser->GetSlotPeriod().GetNanoSeconds());
952
953 switch (params.m_ulCqi.m_type)
954 {
955 case UlCqiInfo::PUSCH: {
956 [[maybe_unused]] bool found = false;
957 uint8_t symStart = params.m_symStart;
958 SfnSf ulSfnSf = params.m_sfnSf;
959
960 NS_LOG_INFO("CQI for allocation: " << params.m_sfnSf << " started at sym: " << +symStart
961 << " modified allocation " << ulSfnSf << " sym Start "
962 << static_cast<uint32_t>(symStart));
963
964 auto itAlloc = m_ulAllocationMap.find(ulSfnSf.GetEncoding());
965 NS_ASSERT_MSG(itAlloc != m_ulAllocationMap.end(), "Can't find allocation for " << ulSfnSf);
966 std::vector<AllocElem>& ulAllocations = itAlloc->second.m_ulAllocations;
967
968 for (auto it = ulAllocations.cbegin(); it != ulAllocations.cend(); /* NO INC */)
969 {
970 const AllocElem& allocation = *(it);
971 if (allocation.m_symStart == symStart)
972 {
973 auto itUe = m_ueMap.find(allocation.m_rnti);
974 NS_ASSERT(itUe != m_ueMap.end());
975 NS_ASSERT(allocation.m_numSym > 0);
976 NS_ASSERT(allocation.m_tbs > 0);
977
978 m_cqiManagement.UlSBCQIReported(expirationTime,
979 allocation.m_tbs,
980 params,
981 UeInfoOf(*itUe),
982 allocation.m_rbgMask,
985 found = true;
986 it = ulAllocations.erase(it);
987 }
988 else
989 {
990 ++it;
991 }
992 }
993 NS_ASSERT(found);
994
995 if (ulAllocations.empty())
996 {
997 // remove obsolete info on allocation; we already processed all the CQI
998 NS_LOG_INFO("Removing allocation for " << ulSfnSf);
999 m_ulAllocationMap.erase(itAlloc);
1000 }
1001 }
1002 break;
1003 default:
1004 NS_FATAL_ERROR("Unknown type of UL-CQI");
1005 }
1006}
1007
1021template <typename T>
1022std::vector<T>
1023NrMacSchedulerNs3::MergeHARQ(std::vector<T>* existingFeedbacks,
1024 const std::vector<T>& inFeedbacks,
1025 const std::string& mode) const
1026{
1027 NS_LOG_FUNCTION(this);
1028 NS_LOG_INFO("To retransmit : " << existingFeedbacks->size() << " " << mode << " HARQ, received "
1029 << inFeedbacks.size() << " " << mode << " HARQ Feedback");
1030 uint64_t existingSize = existingFeedbacks->size();
1031 uint64_t inSize = inFeedbacks.size();
1032 existingFeedbacks->insert(existingFeedbacks->end(), inFeedbacks.begin(), inFeedbacks.end());
1033 NS_ASSERT(existingFeedbacks->size() == existingSize + inSize);
1034
1035 auto ret = std::vector<T>(std::make_move_iterator(existingFeedbacks->begin()),
1036 std::make_move_iterator(existingFeedbacks->end()));
1037 existingFeedbacks->clear();
1038
1039 return ret;
1040}
1041
1059template <typename T>
1060void
1061NrMacSchedulerNs3::ProcessHARQFeedbacks(
1062 std::vector<T>* harqInfo,
1063 const NrMacSchedulerUeInfo::GetHarqVectorFn& GetHarqVectorFn,
1064 const std::string& direction) const
1065{
1066 NS_LOG_FUNCTION(this);
1067 uint32_t nackReceived = 0;
1068
1069 // Check the HARQ feedback, erase ACKed, updated NACKed
1070 for (auto harqFeedbackIt = harqInfo->begin(); harqFeedbackIt != harqInfo->end();
1071 /* nothing as increment */)
1072 {
1073 uint8_t harqId = harqFeedbackIt->m_harqProcessId;
1074 uint16_t rnti = harqFeedbackIt->m_rnti;
1075 NrMacHarqVector& ueHarqVector = GetHarqVectorFn(m_ueMap.find(rnti)->second);
1076 HarqProcess& ueProcess = ueHarqVector.Get(harqId);
1077
1078 NS_LOG_INFO("Evaluating feedback: " << *harqFeedbackIt);
1079 if (!ueProcess.m_active)
1080 {
1081 NS_LOG_INFO("UE " << rnti << " HARQ vector: " << ueHarqVector);
1082 NS_FATAL_ERROR("Received feedback for a process which is not active");
1083 }
1084 NS_ABORT_IF(ueProcess.m_dciElement == nullptr);
1085
1086 // RV number should not be greater than 3
1087 NS_ASSERT(ueProcess.m_dciElement->m_rv < 4);
1088 uint8_t maxHarqReTx = m_enableHarqReTx ? 3 : 0;
1089
1090 if (harqFeedbackIt->IsReceivedOk() || ueProcess.m_dciElement->m_rv == maxHarqReTx)
1091 {
1092 ueHarqVector.Erase(harqId);
1093 harqFeedbackIt = harqInfo->erase(harqFeedbackIt);
1094 NS_LOG_INFO("Erased processID " << static_cast<uint32_t>(harqId) << " of UE " << rnti
1095 << " direction " << direction);
1096 }
1097 else if (!harqFeedbackIt->IsReceivedOk())
1098 {
1099 ueProcess.m_status = HarqProcess::RECEIVED_FEEDBACK;
1100 nackReceived++;
1101 ++harqFeedbackIt;
1102 NS_LOG_INFO("NACK received for UE " << static_cast<uint32_t>(rnti) << " process "
1103 << static_cast<uint32_t>(harqId) << " direction "
1104 << direction);
1105 }
1106 }
1107
1108 NS_ASSERT(harqInfo->size() == nackReceived);
1109}
1110
1122void
1123NrMacSchedulerNs3::ResetExpiredHARQ(uint16_t rnti, NrMacHarqVector* harq)
1124{
1125 NS_LOG_FUNCTION(this << harq);
1126
1127 for (auto harqIt = harq->Begin(); harqIt != harq->End(); ++harqIt)
1128 {
1129 HarqProcess& process = harqIt->second;
1130 uint8_t processId = harqIt->first;
1131
1132 if (process.m_status == HarqProcess::INACTIVE)
1133 {
1134 continue;
1135 }
1136
1137 if (process.m_timer < m_macSchedSapUser->GetNumHarqProcess())
1138 {
1139 ++process.m_timer;
1140 NS_LOG_INFO("Updated process for UE " << rnti << " number "
1141 << static_cast<uint32_t>(processId)
1142 << ", resulting process: " << process);
1143 }
1144 else
1145 {
1146 harq->Erase(processId);
1147 NS_LOG_INFO("Erased process for UE " << rnti << " number "
1148 << static_cast<uint32_t>(processId)
1149 << " for time limits");
1150 }
1151 }
1152}
1153
1162uint8_t
1163NrMacSchedulerNs3::PrependCtrlSym(uint8_t symStart,
1164 uint8_t numSymToAllocate,
1166 std::deque<VarTtiAllocInfo>* allocations) const
1167{
1168 std::vector<bool> rbgBitmask(GetBandwidthInRbg(), true);
1169
1170 NS_ASSERT_MSG(rbgBitmask.size() == GetBandwidthInRbg(),
1171 "bitmask size " << rbgBitmask.size() << " conf " << GetBandwidthInRbg());
1172 if (mode == DciInfoElementTdma::DL)
1173 {
1174 NS_ASSERT(allocations->empty()); // no previous allocations
1175 NS_ASSERT(symStart == 0); // start from the symbol 0
1176 }
1177
1178 for (uint8_t sym = symStart; sym < symStart + numSymToAllocate; ++sym)
1179 {
1180 allocations->emplace_front(std::make_shared<DciInfoElementTdma>(sym,
1181 1,
1182 mode,
1184 rbgBitmask));
1185 NS_LOG_INFO("Allocating CTRL symbol, type"
1186 << mode << " in TDMA. numSym=1, symStart=" << static_cast<uint32_t>(sym)
1187 << " Remaining CTRL sym to allocate: " << sym - symStart);
1188 }
1189 return symStart + numSymToAllocate;
1190}
1191
1200uint8_t
1201NrMacSchedulerNs3::AppendCtrlSym(uint8_t symStart,
1202 uint8_t numSymToAllocate,
1204 std::deque<VarTtiAllocInfo>* allocations) const
1205{
1206 std::vector<bool> rbgBitmask(GetBandwidthInRbg(), true);
1207
1208 NS_ASSERT(rbgBitmask.size() == GetBandwidthInRbg());
1209 if (mode == DciInfoElementTdma::DL)
1210 {
1211 NS_ASSERT(allocations->empty()); // no previous allocations
1212 NS_ASSERT(symStart == 0); // start from the symbol 0
1213 }
1214
1215 for (uint8_t sym = symStart; sym < symStart + numSymToAllocate; ++sym)
1216 {
1217 allocations->emplace_back(std::make_shared<DciInfoElementTdma>(sym,
1218 1,
1219 mode,
1221 rbgBitmask));
1222 NS_LOG_INFO("Allocating CTRL symbol, type"
1223 << mode << " in TDMA. numSym=1, symStart=" << static_cast<uint32_t>(sym)
1224 << " Remaining CTRL sym to allocate: " << sym - symStart);
1225 }
1226 return symStart + numSymToAllocate;
1227}
1228
1239void
1240NrMacSchedulerNs3::ComputeActiveHarq(ActiveHarqMap* activeDlHarq,
1241 const std::vector<DlHarqInfo>& dlHarqFeedback) const
1242{
1243 NS_LOG_FUNCTION(this);
1244 NS_ASSERT(activeDlHarq->empty());
1245
1246 for (const auto& feedback : dlHarqFeedback)
1247 {
1248 uint16_t rnti = feedback.m_rnti;
1249 auto& schedInfo = m_ueMap.find(rnti)->second;
1250 auto beamIterator = activeDlHarq->find(schedInfo->m_beamId);
1251
1252 if (beamIterator == activeDlHarq->end())
1253 {
1254 std::vector<NrMacHarqVector::iterator> harqVector;
1255 NS_ASSERT(schedInfo->m_dlHarq.Find(feedback.m_harqProcessId)->second.m_active);
1256
1257 harqVector.emplace_back(schedInfo->m_dlHarq.Find(feedback.m_harqProcessId));
1258 activeDlHarq->emplace(std::make_pair(schedInfo->m_beamId, harqVector));
1259 }
1260 else
1261 {
1262 NS_ASSERT(schedInfo->m_dlHarq.Find(feedback.m_harqProcessId)->second.m_active);
1263 beamIterator->second.emplace_back(schedInfo->m_dlHarq.Find(feedback.m_harqProcessId));
1264 }
1265 NS_LOG_INFO("Received feedback for UE " << rnti << " ID "
1266 << static_cast<uint32_t>(feedback.m_harqProcessId)
1267 << " marked as active");
1268 NS_ASSERT(schedInfo->m_dlHarq.Find(feedback.m_harqProcessId)->second.m_status ==
1271 {
1272 m_nrFhSchedSapProvider->SetActiveHarqUes(GetBwpId(), rnti);
1273 }
1274 }
1275
1276 SortDlHarq(activeDlHarq);
1277}
1278
1289void
1290NrMacSchedulerNs3::ComputeActiveHarq(ActiveHarqMap* activeUlHarq,
1291 const std::vector<UlHarqInfo>& ulHarqFeedback) const
1292{
1293 NS_LOG_FUNCTION(this);
1294
1295 for (const auto& feedback : ulHarqFeedback)
1296 {
1297 uint16_t rnti = feedback.m_rnti;
1298 auto& schedInfo = m_ueMap.find(rnti)->second;
1299 auto beamIterator = activeUlHarq->find(schedInfo->m_beamId);
1300
1301 if (beamIterator == activeUlHarq->end())
1302 {
1303 std::vector<NrMacHarqVector::iterator> harqVector;
1304 NS_ASSERT(schedInfo->m_ulHarq.Find(feedback.m_harqProcessId)->second.m_active);
1305 harqVector.emplace_back(schedInfo->m_ulHarq.Find(feedback.m_harqProcessId));
1306 activeUlHarq->emplace(std::make_pair(schedInfo->m_beamId, harqVector));
1307 }
1308 else
1309 {
1310 NS_ASSERT(schedInfo->m_ulHarq.Find(feedback.m_harqProcessId)->second.m_active);
1311 beamIterator->second.emplace_back(schedInfo->m_ulHarq.Find(feedback.m_harqProcessId));
1312 }
1313 }
1314 SortUlHarq(activeUlHarq);
1315}
1316
1329void
1330NrMacSchedulerNs3::ComputeActiveUe(ActiveUeMap* activeUe,
1331 const NrMacSchedulerUeInfo::GetLCGFn& GetLCGFn,
1332 const NrMacSchedulerUeInfo::GetHarqVectorFn& GetHarqVector,
1333 const std::string& mode) const
1334{
1335 NS_LOG_FUNCTION(this);
1336 for (const auto& ueInfo : m_ueMap)
1337 {
1338 uint32_t totBuffer = 0;
1339 const auto& ue = ueInfo.second;
1340
1341 // compute total DL and UL bytes buffered
1342 for (const auto& lcgInfo : GetLCGFn(ue))
1343 {
1344 const auto& lcg = lcgInfo.second;
1345 if (lcg->GetTotalSize() > 0)
1346 {
1347 NS_LOG_INFO("UE " << ue->m_rnti << " " << mode << " LCG "
1348 << static_cast<uint32_t>(lcgInfo.first) << " bytes "
1349 << lcg->GetTotalSize());
1350 }
1351 totBuffer += lcg->GetTotalSize();
1352 }
1353
1354 auto harqV = GetHarqVector(ue);
1355
1356 if (totBuffer > 0 && harqV.CanInsert())
1357 {
1358 auto it = activeUe->find(ue->m_beamId);
1359 if (it == activeUe->end())
1360 {
1361 std::vector<std::pair<std::shared_ptr<NrMacSchedulerUeInfo>, uint32_t>> tmp;
1362 tmp.emplace_back(ue, totBuffer);
1363 activeUe->insert(std::make_pair(ue->m_beamId, tmp));
1364 }
1365 else
1366 {
1367 it->second.emplace_back(ue, totBuffer);
1368 }
1369 }
1370 }
1371}
1372
1404uint8_t
1405NrMacSchedulerNs3::DoScheduleDlData(PointInFTPlane* spoint,
1406 uint32_t symAvail,
1407 const ActiveUeMap& activeDl,
1408 SlotAllocInfo* slotAlloc) const
1409{
1410 NS_LOG_FUNCTION(this << symAvail);
1411 NS_ASSERT(spoint->m_rbg == 0);
1412 BeamSymbolMap symPerBeam = AssignDLRBG(symAvail, activeDl);
1413 GetFirst GetBeam;
1414 uint8_t usedSym = 0;
1415
1416 for (const auto& beam : activeDl)
1417 {
1418 uint32_t availableRBG =
1419 (GetBandwidthInRbg() - spoint->m_rbg) * symPerBeam.at(GetBeam(beam));
1420 bool assigned = false;
1421 std::unordered_set<uint8_t> symbStartDci;
1422 // allocSym is used to count the number of allocated symbols to the UEs of the beam
1423 // we are iterating over
1424 uint32_t allocSym = 0;
1425
1426 NS_LOG_DEBUG(activeDl.size()
1427 << " active DL beam, this beam has " << symPerBeam.at(GetBeam(beam))
1428 << " SYM, starts from RB " << spoint->m_rbg << " and symbol "
1429 << static_cast<uint32_t>(spoint->m_sym) << " for a total of " << availableRBG
1430 << " RBG. In one symbol we have " << GetBandwidthInRbg() << " RBG.");
1431
1432 if (symPerBeam.at(GetBeam(beam)) == 0)
1433 {
1434 NS_LOG_INFO("No available symbols for this beam, continue");
1435 continue;
1436 }
1437
1438 for (const auto& ue : beam.second)
1439 {
1440 if (ue.first->m_dlRBG.empty())
1441 {
1442 NS_LOG_INFO("UE " << ue.first->m_rnti << " does not have RBG assigned");
1443 continue;
1444 }
1445
1446 std::shared_ptr<DciInfoElementTdma> dci =
1447 CreateDlDci(spoint, ue.first, symPerBeam.at(GetBeam(beam)));
1448 if (dci == nullptr)
1449 {
1450 // By continuing to the next UE means that we are
1451 // wasting a resource assign to this UE. For a TDMA
1452 // scheduler this resource would be one or more
1453 // symbols, and for OFDMA scheduler it would be a
1454 // chunk of time + freq, i.e., one or more
1455 // symbols in time and one or more RBG in freq.
1456 // TODO To avoid this, a more accurate solution
1457 // is needed to assign resources. That is, a solution
1458 // that would not assign resources to a UE if the assigned resources
1459 // result a TB size of less than 7 bytes (3 mac header, 2 rlc header, 2 data).
1460 // Because if this happens CreateDlDci will not create DCI.
1461 NS_LOG_DEBUG("No DCI has been created, ignoring");
1462 ue.first->ResetDlMetric();
1463 continue;
1464 }
1465
1466 assigned = true;
1467
1468 if (symbStartDci.insert(dci->m_symStart).second)
1469 {
1470 allocSym += dci->m_numSym;
1471 }
1472
1473 NS_LOG_INFO("UE " << ue.first->m_rnti << " has " << ue.first->m_dlRBG.size()
1474 << " RBG assigned");
1475 NS_ASSERT_MSG(dci->m_symStart + dci->m_numSym <= m_macSchedSapUser->GetSymbolsPerSlot(),
1476 "symStart: "
1477 << static_cast<uint32_t>(dci->m_symStart)
1478 << " symEnd: " << static_cast<uint32_t>(dci->m_numSym) << " symbols: "
1479 << static_cast<uint32_t>(m_macSchedSapUser->GetSymbolsPerSlot()));
1480
1481 HarqProcess harqProcess(true, HarqProcess::WAITING_FEEDBACK, 0, dci);
1482 uint8_t id;
1483
1484 if (!ue.first->m_dlHarq.CanInsert())
1485 {
1486 NS_LOG_INFO("Harq Vector condition for UE " << ue.first->m_rnti << std::endl
1487 << ue.first->m_dlHarq);
1488 NS_FATAL_ERROR("UE " << ue.first->m_rnti << " does not have DL HARQ space");
1489 }
1490
1491 ue.first->m_dlHarq.Insert(&id, harqProcess);
1492 ue.first->m_dlHarq.Get(id).m_dciElement->m_harqProcess = id;
1493
1494 // distribute tbsize among the LCs of the UE
1495 // distributedBytes size is equal to the number of LCs
1496 auto distributedBytes =
1497 m_schedLc->AssignBytesToDlLC(ue.first->m_dlLCG,
1498 dci->m_tbSize,
1500
1501 std::vector<std::vector<NrMacSchedulerLcAlgorithm::Assignation>> bytesPerLc(
1502 distributedBytes.size());
1503
1504 for (std::size_t numLc = 0; numLc < distributedBytes.size(); numLc++)
1505 {
1506 bytesPerLc.at(numLc).emplace_back(distributedBytes.at(numLc).m_lcg,
1507 distributedBytes.at(numLc).m_lcId,
1508 distributedBytes.at(numLc).m_bytes);
1509 }
1510
1511 VarTtiAllocInfo slotInfo(dci);
1512
1513 NS_LOG_INFO("Assigned process ID " << static_cast<uint32_t>(dci->m_harqProcess)
1514 << " to UE " << ue.first->m_rnti);
1515 NS_LOG_DEBUG(" UE" << dci->m_rnti << " gets DL symbols "
1516 << static_cast<uint32_t>(dci->m_symStart) << "-"
1517 << static_cast<uint32_t>(dci->m_symStart + dci->m_numSym) << " tbs "
1518 << dci->m_tbSize << " mcs " << static_cast<uint32_t>(dci->m_mcs)
1519 << " harqId " << static_cast<uint32_t>(id) << " rv "
1520 << static_cast<uint32_t>(dci->m_rv));
1521
1522 for (const auto& byteDistribution : distributedBytes)
1523 {
1524 NS_ASSERT(byteDistribution.m_bytes >= 3);
1525 uint8_t lcId = byteDistribution.m_lcId;
1526 uint8_t lcgId = byteDistribution.m_lcg;
1527 uint32_t bytes = byteDistribution.m_bytes - 3; // Consider the subPdu overhead
1528
1529 RlcPduInfo newRlcPdu(lcId, bytes);
1530 HarqProcess& process = ue.first->m_dlHarq.Get(dci->m_harqProcess);
1531
1532 slotInfo.m_rlcPduInfo.push_back(newRlcPdu);
1533 process.m_rlcPduInfo.push_back(newRlcPdu);
1534
1535 ue.first->m_dlLCG.at(lcgId)->AssignedData(lcId, bytes, "DL");
1536
1537 NS_LOG_DEBUG("DL LCG " << static_cast<uint32_t>(lcgId) << " LCID "
1538 << static_cast<uint32_t>(lcId) << " got bytes "
1539 << newRlcPdu.m_size);
1540 }
1541
1542 NS_ABORT_IF(slotInfo.m_rlcPduInfo.empty());
1543
1544 slotAlloc->m_varTtiAllocInfo.emplace_back(slotInfo);
1545 }
1546 if (assigned)
1547 {
1548 ChangeDlBeam(spoint, symPerBeam.at(GetBeam(beam)));
1549 usedSym += allocSym;
1550 slotAlloc->m_numSymAlloc += allocSym;
1551 }
1552 }
1553
1554 for (auto& beam : activeDl)
1555 {
1556 for (auto& ue : beam.second)
1557 {
1558 ue.first->ResetDlSchedInfo();
1559 }
1560 }
1561
1562 NS_ASSERT(spoint->m_rbg == 0);
1563
1564 return usedSym;
1565}
1566
1602uint8_t
1603NrMacSchedulerNs3::DoScheduleUlData(PointInFTPlane* spoint,
1604 uint32_t symAvail,
1605 const ActiveUeMap& activeUl,
1606 SlotAllocInfo* slotAlloc) const
1607{
1608 NS_LOG_FUNCTION(this);
1609 NS_ASSERT(symAvail > 0 && !activeUl.empty());
1610 NS_ASSERT(spoint->m_rbg == 0);
1611
1612 BeamSymbolMap symPerBeam = AssignULRBG(symAvail, activeUl);
1613 uint8_t usedSym = 0;
1614 GetFirst GetBeam;
1615
1616 for (const auto& beam : activeUl)
1617 {
1618 uint32_t availableRBG =
1619 (GetBandwidthInRbg() - spoint->m_rbg) * symPerBeam.at(GetBeam(beam));
1620 bool assigned = false;
1621 std::unordered_set<uint8_t> symbStartDci;
1622 // allocSym is used to count the number of allocated symbols to the UEs of the beam
1623 // we are iterating over
1624 uint32_t allocSym = 0;
1625
1626 NS_LOG_DEBUG(activeUl.size()
1627 << " active UL beam, this beam has " << symPerBeam.at(GetBeam(beam))
1628 << " SYM, starts from RBG " << spoint->m_rbg << " and symbol "
1629 << static_cast<uint32_t>(spoint->m_sym) << " (going backward) for a total of "
1630 << availableRBG << " RBG. In one symbol we have " << GetBandwidthInRbg()
1631 << " RBG.");
1632
1633 if (symPerBeam.at(GetBeam(beam)) == 0)
1634 {
1635 NS_LOG_INFO("No available symbols for this beam, continue");
1636 continue;
1637 }
1638
1639 for (const auto& ue : beam.second)
1640 {
1641 if (ue.first->m_ulRBG.empty())
1642 {
1643 NS_LOG_INFO("UE " << ue.first->m_rnti << " does not have RBG assigned");
1644 continue;
1645 }
1646
1647 std::shared_ptr<DciInfoElementTdma> dci =
1648 CreateUlDci(spoint, ue.first, symPerBeam.at(GetBeam(beam)));
1649
1650 if (dci == nullptr)
1651 {
1652 // By continuing to the next UE means that we are
1653 // wasting a resource assign to this UE. For a TDMA
1654 // scheduler this resource would be one or more
1655 // symbols, and for OFDMA scheduler it would be a
1656 // chunk of time + freq, i.e., one or more
1657 // symbols in time and one or more RBG in freq.
1658 // TODO To avoid this, a more accurate solution
1659 // is needed to assign resources. That is, a solution
1660 // that would not assign resources to a UE if the assigned resources
1661 // result a TB size of less than 7 bytes (3 mac header, 2 rlc header, 2
1662 // data). Because if this happens CreateUlDci will not create DCI.
1663 NS_LOG_DEBUG("No DCI has been created, ignoring");
1664 ue.first->ResetUlMetric();
1665 continue;
1666 }
1667
1668 assigned = true;
1669
1670 if (symbStartDci.insert(dci->m_symStart).second)
1671 {
1672 allocSym += dci->m_numSym;
1673 }
1674
1675 if (!ue.first->m_ulHarq.CanInsert())
1676 {
1677 NS_LOG_INFO("Harq Vector condition for UE " << ue.first->m_rnti << std::endl
1678 << ue.first->m_ulHarq);
1679 NS_FATAL_ERROR("UE " << ue.first->m_rnti << " does not have UL HARQ space");
1680 }
1681
1682 HarqProcess harqProcess(true, HarqProcess::WAITING_FEEDBACK, 0, dci);
1683 uint8_t id;
1684 ue.first->m_ulHarq.Insert(&id, harqProcess);
1685
1686 ue.first->m_ulHarq.Get(id).m_dciElement->m_harqProcess = id;
1687
1688 VarTtiAllocInfo slotInfo(dci);
1689
1690 NS_LOG_INFO("Assigned process ID " << static_cast<uint32_t>(dci->m_harqProcess)
1691 << " to UE " << ue.first->m_rnti);
1692 NS_LOG_DEBUG(" UE" << dci->m_rnti << " gets UL symbols "
1693 << static_cast<uint32_t>(dci->m_symStart) << "-"
1694 << static_cast<uint32_t>(dci->m_symStart + dci->m_numSym) << " tbs "
1695 << dci->m_tbSize << " mcs " << static_cast<uint32_t>(dci->m_mcs)
1696 << " harqId " << static_cast<uint32_t>(id) << " rv "
1697 << static_cast<uint32_t>(dci->m_rv));
1698
1699 auto distributedBytes = m_schedLc->AssignBytesToUlLC(ue.first->m_ulLCG, dci->m_tbSize);
1700 bool assignedToLC = false;
1701 for (const auto& byteDistribution : distributedBytes)
1702 {
1703 assignedToLC = true;
1704 ue.first->m_ulLCG.at(byteDistribution.m_lcg)
1705 ->AssignedData(byteDistribution.m_lcId, byteDistribution.m_bytes, "UL");
1706 NS_LOG_DEBUG("UL LCG " << static_cast<uint32_t>(byteDistribution.m_lcg)
1707 << " assigned bytes " << byteDistribution.m_bytes
1708 << " to LCID "
1709 << static_cast<uint32_t>(byteDistribution.m_lcId));
1710 }
1711 NS_ASSERT(assignedToLC);
1712 slotAlloc->m_varTtiAllocInfo.emplace_front(slotInfo);
1713 }
1714 if (assigned)
1715 {
1716 ChangeUlBeam(spoint, symPerBeam.at(GetBeam(beam)));
1717 usedSym += allocSym;
1718 slotAlloc->m_numSymAlloc += allocSym;
1719 }
1720 }
1721
1722 for (auto& beam : activeUl)
1723 {
1724 for (auto& ue : beam.second)
1725 {
1726 ue.first->ResetUlSchedInfo();
1727 }
1728 }
1729
1730 NS_ASSERT(spoint->m_rbg == 0);
1731
1732 return usedSym;
1733}
1734
1746void
1747NrMacSchedulerNs3::DoScheduleUlSr(PointInFTPlane* spoint, const std::list<uint16_t>& rntiList) const
1748{
1749 NS_LOG_FUNCTION(this);
1750 NS_ASSERT(spoint->m_rbg == 0);
1751
1752 for (const auto& v : rntiList)
1753 {
1754 for (auto& ulLcg : NrMacSchedulerUeInfo::GetUlLCG(m_ueMap.at(v)))
1755 {
1756 NS_LOG_DEBUG("Assigning 12 bytes to UE " << v << " because of a SR");
1757 ulLcg.second->UpdateInfo(12);
1758 }
1759 }
1760}
1761
1800void
1801NrMacSchedulerNs3::ScheduleDl(const NrMacSchedSapProvider::SchedDlTriggerReqParameters& params,
1802 const std::vector<DlHarqInfo>& dlHarqFeedback)
1803{
1804 NS_LOG_FUNCTION(this);
1805 NS_LOG_INFO("Scheduling invoked for slot " << params.m_snfSf << " of type "
1806 << params.m_slotType);
1807
1808 NrMacSchedSapUser::SchedConfigIndParameters dlSlot(params.m_snfSf);
1809 dlSlot.m_slotAllocInfo.m_sfnSf = params.m_snfSf;
1810 dlSlot.m_slotAllocInfo.m_type = SlotAllocInfo::DL;
1811 auto ulAllocationIt =
1812 m_ulAllocationMap.find(params.m_snfSf.GetEncoding()); // UL allocations for this slot
1813 if (ulAllocationIt == m_ulAllocationMap.end())
1814 {
1815 ulAllocationIt =
1816 m_ulAllocationMap.insert(std::make_pair(params.m_snfSf.GetEncoding(), SlotElem(0)))
1817 .first;
1818 }
1819 auto& ulAllocations = ulAllocationIt->second;
1820
1821 // add slot for DL control, at symbol 0
1822 PrependCtrlSym(0,
1823 m_dlCtrlSymbols,
1825 &dlSlot.m_slotAllocInfo.m_varTtiAllocInfo);
1826 dlSlot.m_slotAllocInfo.m_numSymAlloc += m_dlCtrlSymbols;
1827
1828 // In case of S slot, add UL CTRL and update the symbol used count
1829 if (params.m_slotType == LteNrTddSlotType::S)
1830 {
1831 NS_LOG_INFO("S slot, adding UL CTRL");
1832 AppendCtrlSym(static_cast<uint8_t>(m_macSchedSapUser->GetSymbolsPerSlot() - 1),
1833 m_ulCtrlSymbols,
1835 &dlSlot.m_slotAllocInfo.m_varTtiAllocInfo);
1836 ulAllocations.m_totUlSym += m_ulCtrlSymbols;
1837 dlSlot.m_slotAllocInfo.m_numSymAlloc += m_ulCtrlSymbols;
1838 }
1839
1840 // compute active ue in the current subframe, group them by BeamId
1841 ActiveHarqMap activeDlHarq;
1842 ComputeActiveHarq(&activeDlHarq, dlHarqFeedback);
1843
1844 ActiveUeMap activeDlUe;
1845 ComputeActiveUe(&activeDlUe,
1848 "DL");
1849
1850 DoScheduleDl(dlHarqFeedback,
1851 activeDlHarq,
1852 &activeDlUe,
1853 params.m_snfSf,
1854 ulAllocations,
1855 &dlSlot.m_slotAllocInfo);
1856
1857 // if the number of allocated symbols is greater than GetUlCtrlSymbols (), then don't
1858 // delete the allocation, as it will be removed when the CQI will be processed.
1859 // Otherwise, delete the allocation history for the slot.
1860 if (ulAllocations.m_totUlSym <= GetUlCtrlSyms())
1861 {
1862 NS_LOG_INFO("Removing UL allocation for slot " << params.m_snfSf << " size "
1863 << m_ulAllocationMap.size());
1864 m_ulAllocationMap.erase(ulAllocationIt);
1865 }
1866
1867 NS_LOG_INFO("Total DCI for DL : " << dlSlot.m_slotAllocInfo.m_varTtiAllocInfo.size()
1868 << " including DL CTRL");
1869
1871 {
1872 if (m_nrFhSchedSapProvider->GetFhControlMethod() !=
1874 m_nrFhSchedSapProvider->GetFhControlMethod() != UINT8_MAX)
1875 {
1876 Simulator::Schedule(NanoSeconds(1),
1877 &NrMacSchedulerNs3::CallNrFhControlForMapUpdate,
1878 this,
1879 dlSlot.m_slotAllocInfo.m_varTtiAllocInfo,
1880 m_ueMap); // 1ns delay to give time for scheduling in all cells
1881 }
1882 }
1883
1885}
1886
1923void
1924NrMacSchedulerNs3::ScheduleUl(const NrMacSchedSapProvider::SchedUlTriggerReqParameters& params,
1925 const std::vector<UlHarqInfo>& ulHarqFeedback)
1926{
1927 NS_LOG_FUNCTION(this);
1928 NS_LOG_INFO("Scheduling invoked for slot " << params.m_snfSf);
1929
1930 NrMacSchedSapUser::SchedConfigIndParameters ulSlot(params.m_snfSf);
1931 ulSlot.m_slotAllocInfo.m_sfnSf = params.m_snfSf;
1932 ulSlot.m_slotAllocInfo.m_type = SlotAllocInfo::UL;
1933
1934 // add slot for UL control, at last symbol, for slot type F and UL.
1935 AppendCtrlSym(static_cast<uint8_t>(m_macSchedSapUser->GetSymbolsPerSlot() - 1),
1936 m_ulCtrlSymbols,
1938 &ulSlot.m_slotAllocInfo.m_varTtiAllocInfo);
1939 ulSlot.m_slotAllocInfo.m_numSymAlloc += m_ulCtrlSymbols;
1940
1941 // Doing UL for slot ulSlot
1942 DoScheduleUl(ulHarqFeedback, params.m_snfSf, &ulSlot.m_slotAllocInfo, params.m_slotType);
1943
1944 NS_LOG_INFO("Total DCI for UL : " << ulSlot.m_slotAllocInfo.m_varTtiAllocInfo.size()
1945 << " including UL CTRL");
1946 m_macSchedSapUser->BuildRarList(ulSlot.m_slotAllocInfo);
1948}
1949
1987uint8_t
1988NrMacSchedulerNs3::DoScheduleUl(const std::vector<UlHarqInfo>& ulHarqFeedback,
1989 const SfnSf& ulSfn,
1990 SlotAllocInfo* allocInfo,
1991 LteNrTddSlotType type)
1992{
1993 NS_LOG_FUNCTION(this);
1994
1995 NS_ASSERT(allocInfo->m_varTtiAllocInfo.size() == 1); // Just the UL CTRL
1996
1997 uint8_t dataSymPerSlot = m_macSchedSapUser->GetSymbolsPerSlot() - m_ulCtrlSymbols;
1998 if (type == LteNrTddSlotType::F)
1999 { // if it's a type F, we have to consider DL CTRL symbols, otherwise, don't
2000 dataSymPerSlot -= m_dlCtrlSymbols;
2001 }
2002
2003 ActiveHarqMap activeUlHarq;
2004 ComputeActiveHarq(&activeUlHarq, ulHarqFeedback);
2005
2006 // Start the assignation from the last available data symbol, and like a shrimp
2007 // go backward.
2008 uint8_t lastSym = m_macSchedSapUser->GetSymbolsPerSlot() - m_ulCtrlSymbols;
2009 PointInFTPlane ulAssignationStartPoint(0, lastSym);
2010 uint8_t ulSymAvail = dataSymPerSlot;
2011
2012 // Create the UL allocation map entry
2013 m_ulAllocationMap.emplace(ulSfn.GetEncoding(), SlotElem(0));
2014
2015 if ((m_enableSrsInFSlots && type == LteNrTddSlotType::F) ||
2016 (m_enableSrsInUlSlots && type == LteNrTddSlotType::UL))
2017 { // SRS are included in F slots, and in UL slots if m_enableSrsInUlSlots=true
2018 m_srsSlotCounter++; // It's an uint, don't worry about wrap around
2019 NS_ASSERT(m_srsCtrlSymbols <= ulSymAvail);
2020 uint8_t srsSym = DoScheduleSrs(&ulAssignationStartPoint, allocInfo);
2021 ulSymAvail -= srsSym;
2022 }
2023
2024 NS_LOG_DEBUG("Scheduling UL " << ulSfn << " UL HARQ to retransmit: " << ulHarqFeedback.size()
2025 << " Active Beams UL HARQ: " << activeUlHarq.size()
2026 << " starting from (" << +ulAssignationStartPoint.m_rbg << ", "
2027 << +ulAssignationStartPoint.m_sym << ")");
2028
2029 // RACH
2030 uint8_t usedMsg3 = 0;
2031 if (!m_rachList.empty())
2032 {
2033 usedMsg3 = DoScheduleUlMsg3(&ulAssignationStartPoint, ulSymAvail, allocInfo);
2034 NS_ASSERT_MSG(ulSymAvail >= usedMsg3,
2035 "Available: " << +ulSymAvail << " used by UL MSG3: " << +usedMsg3);
2036 NS_LOG_INFO("For the slot " << ulSfn << " reserved " << static_cast<uint32_t>(usedMsg3)
2037 << " symbols for UL MSG3");
2038 ulSymAvail -= usedMsg3;
2039 allocInfo->m_numSymAlloc += usedMsg3;
2040 }
2041
2042 if (!activeUlHarq.empty())
2043 {
2044 uint8_t usedHarq = ScheduleUlHarq(&ulAssignationStartPoint,
2045 ulSymAvail,
2046 m_ueMap,
2047 &m_ulHarqToRetransmit,
2048 ulHarqFeedback,
2049 allocInfo);
2050 NS_ASSERT_MSG(ulSymAvail >= usedHarq,
2051 "Available: " << +ulSymAvail << " used by HARQ: " << +usedHarq);
2052 NS_LOG_INFO("For the slot " << ulSfn << " reserved " << static_cast<uint32_t>(usedHarq)
2053 << " symbols for UL HARQ retx");
2054 ulSymAvail -= usedHarq;
2055 }
2056
2057 NS_ASSERT(ulAssignationStartPoint.m_rbg == 0);
2058
2059 if (ulSymAvail > 0 && !m_srList.empty())
2060 {
2061 DoScheduleUlSr(&ulAssignationStartPoint, m_srList);
2062 m_srList.clear();
2063 }
2064
2065 ActiveUeMap activeUlUe;
2066 ComputeActiveUe(&activeUlUe,
2069 "UL");
2070
2071 GetSecond GetUeInfoList;
2072 for (const auto& alloc : allocInfo->m_varTtiAllocInfo)
2073 {
2074 for (auto it = activeUlUe.begin(); it != activeUlUe.end(); /* no incr */)
2075 {
2076 auto& ueInfos = GetUeInfoList(*it);
2077 for (auto ueIt = ueInfos.begin(); ueIt != ueInfos.end(); /* no incr */)
2078 {
2079 GetFirst GetUeInfoPtr;
2080 if (GetUeInfoPtr(*ueIt)->m_rnti == alloc.m_dci->m_rnti)
2081 {
2082 NS_LOG_INFO("Removed RNTI " << alloc.m_dci->m_rnti
2083 << " from active ue list "
2084 "because it has already an HARQ scheduled");
2085 ueInfos.erase(ueIt);
2086 break;
2087 }
2088 else
2089 {
2090 ++ueIt;
2091 }
2092 }
2093 if (!ueInfos.empty())
2094 {
2095 ++it;
2096 }
2097 else
2098 {
2099 activeUlUe.erase(it);
2100 break;
2101 }
2102 }
2103 }
2104
2105 if (ulSymAvail > 0 && !activeUlUe.empty())
2106 {
2107 uint8_t usedUl =
2108 DoScheduleUlData(&ulAssignationStartPoint, ulSymAvail, activeUlUe, allocInfo);
2109 NS_LOG_INFO("For the slot " << ulSfn << " reserved " << static_cast<uint32_t>(usedUl)
2110 << " symbols for UL data tx");
2111 ulSymAvail -= usedUl;
2112 }
2113
2114 std::vector<uint32_t> symToAl;
2115 symToAl.resize(15, 0);
2116
2117 auto& totUlSym = m_ulAllocationMap.at(ulSfn.GetEncoding()).m_totUlSym;
2118 auto& allocations = m_ulAllocationMap.at(ulSfn.GetEncoding()).m_ulAllocations;
2119 for (const auto& alloc : allocInfo->m_varTtiAllocInfo)
2120 {
2121 if (alloc.m_dci->m_format == DciInfoElementTdma::UL)
2122 {
2123 // Here we are assuming (with the assignment) that all the
2124 // allocations starting at a particular symbol will have the same
2125 // length.
2126 symToAl[alloc.m_dci->m_symStart] = alloc.m_dci->m_numSym;
2127 NS_LOG_INFO("UL Allocation. RNTI " << alloc.m_dci->m_rnti << ", symStart "
2128 << static_cast<uint32_t>(alloc.m_dci->m_symStart)
2129 << " numSym " << +alloc.m_dci->m_numSym);
2130
2131 if (alloc.m_dci->m_type == DciInfoElementTdma::DATA ||
2132 alloc.m_dci->m_type == DciInfoElementTdma::MSG3)
2133 {
2134 NS_LOG_INFO("Placed the above allocation in the CQI map");
2135 allocations.emplace_back(alloc.m_dci->m_rnti,
2136 alloc.m_dci->m_tbSize,
2137 alloc.m_dci->m_symStart,
2138 alloc.m_dci->m_numSym,
2139 alloc.m_dci->m_mcs,
2140 alloc.m_dci->m_rank,
2141 alloc.m_dci->m_rbgBitmask);
2142 }
2143 }
2144 }
2145
2146 for (const auto& v : symToAl)
2147 {
2148 totUlSym += v;
2149 }
2150
2151 NS_ASSERT_MSG((dataSymPerSlot + m_ulCtrlSymbols) - ulSymAvail == totUlSym,
2152 "UL symbols available: "
2153 << static_cast<uint32_t>(dataSymPerSlot + m_ulCtrlSymbols)
2154 << " UL symbols available at end of sched: "
2155 << static_cast<uint32_t>(ulSymAvail)
2156 << " total of symbols registered in the allocation: "
2157 << static_cast<uint32_t>(totUlSym) << " slot type " << type);
2158
2159 NS_LOG_INFO("For the slot " << ulSfn << " registered a total of "
2160 << static_cast<uint32_t>(totUlSym) << " symbols and "
2161 << allocations.size() << " data allocations, with a total of "
2162 << allocInfo->m_varTtiAllocInfo.size());
2163 NS_ASSERT(m_ulAllocationMap.at(ulSfn.GetEncoding()).m_totUlSym == totUlSym);
2164
2165 return dataSymPerSlot - ulSymAvail;
2166}
2167
2168uint8_t
2169NrMacSchedulerNs3::DoScheduleSrs(PointInFTPlane* spoint, SlotAllocInfo* allocInfo)
2170{
2171 NS_LOG_FUNCTION(this);
2172
2173 uint8_t used = 0;
2174
2175 // Without UE, don't schedule any SRS
2176 if (m_ueMap.empty())
2177 {
2178 return used;
2179 }
2180
2181 // Find the UE for which this is true:
2182 // absolute_slot_number % periodicity = offset_UEx
2183 // Assuming that all UEs share the same periodicity.
2184
2185 uint32_t offset_UEx = m_srsSlotCounter % m_ueMap.begin()->second->m_srsPeriodicity;
2186 uint16_t rnti = 0;
2187
2188 for (const auto& ue : m_ueMap)
2189 {
2190 if (ue.second->m_srsOffset == offset_UEx)
2191 {
2192 rnti = ue.second->m_rnti;
2193 }
2194 }
2195
2196 if (rnti == 0)
2197 {
2198 return used; // No SRS in this slot!
2199 }
2200
2201 // Schedule 4 allocation, of 1 symbol each, in TDMA mode, for the RNTI found.
2202
2203 for (uint32_t i = 0; i < m_srsCtrlSymbols; ++i)
2204 {
2205 std::vector<bool> rbgAssigned(GetBandwidthInRbg(), true);
2206
2207 NS_LOG_INFO("UE " << rnti << " assigned symbol " << +spoint->m_sym << " for SRS tx");
2208
2209 std::vector<bool> rbgBitmask(GetBandwidthInRbg(), true);
2210
2211 spoint->m_sym--;
2212
2213 uint8_t numSym{1};
2214 uint8_t mcs{0};
2215 uint8_t rank{1};
2216 Ptr<const ComplexMatrixArray> precMats{nullptr};
2217 uint32_t tbs{0};
2218 uint8_t ndi{1};
2219 uint8_t rv{0};
2220 auto dci = std::make_shared<DciInfoElementTdma>(rnti,
2222 spoint->m_sym,
2223 numSym,
2224 mcs,
2225 rank,
2226 precMats,
2227 tbs,
2228 ndi,
2229 rv,
2231 GetBwpId(),
2232 GetTpc());
2233 dci->m_rbgBitmask = rbgBitmask;
2234
2235 allocInfo->m_numSymAlloc += 1;
2236 allocInfo->m_varTtiAllocInfo.emplace_front(dci);
2237
2238 used++;
2239 }
2240
2241 return used;
2242}
2243
2244uint16_t
2246{
2248 {
2249 return m_macSchedSapUser->GetBwpId();
2250 }
2251 else
2252 {
2253 return UINT16_MAX;
2254 }
2255}
2256
2257uint16_t
2259{
2261 {
2262 return m_macSchedSapUser->GetCellId();
2263 }
2264 else
2265 {
2266 return UINT16_MAX;
2267 }
2268}
2269
2270uint16_t
2272{
2273 return m_bandwidth;
2274}
2275
2276uint8_t
2278{
2279 NS_LOG_FUNCTION(this);
2281 {
2282 return m_nrFhSchedSapProvider->GetFhControlMethod();
2283 }
2284 else
2285 {
2286 return UINT8_MAX;
2287 }
2288}
2289
2290bool
2292 uint32_t mcs,
2293 uint32_t nRegs,
2294 uint8_t dlRank) const
2295{
2296 NS_LOG_FUNCTION(this);
2297 NS_ASSERT(m_nrFhSchedSapProvider);
2298 return m_nrFhSchedSapProvider->DoesAllocationFit(bwpId, mcs, nRegs, dlRank);
2299}
2300
2307void
2308NrMacSchedulerNs3::CallNrFhControlForMapUpdate(
2309 const std::deque<VarTtiAllocInfo>& allocation,
2310 const std::unordered_map<uint16_t, std::shared_ptr<NrMacSchedulerUeInfo>>& ueMap)
2311{
2312 m_nrFhSchedSapProvider->UpdateActiveUesMap(GetBwpId(), allocation, ueMap);
2313}
2314
2334uint8_t
2335NrMacSchedulerNs3::DoScheduleDl(const std::vector<DlHarqInfo>& dlHarqFeedback,
2336 const ActiveHarqMap& activeDlHarq,
2337 ActiveUeMap* activeDlUe,
2338 const SfnSf& dlSfnSf,
2339 const SlotElem& ulAllocations,
2340 SlotAllocInfo* allocInfo)
2341{
2342 NS_LOG_FUNCTION(this);
2343 NS_ASSERT(activeDlUe != nullptr);
2344
2345 uint8_t dataSymPerSlot = m_macSchedSapUser->GetSymbolsPerSlot() - m_dlCtrlSymbols;
2346
2347 uint8_t dlSymAvail = dataSymPerSlot - ulAllocations.m_totUlSym;
2348 PointInFTPlane dlAssignationStartPoint(0, m_dlCtrlSymbols);
2349
2350 NS_LOG_DEBUG("Scheduling DL for slot "
2351 << dlSfnSf << " DL HARQ to retransmit: " << dlHarqFeedback.size()
2352 << " Active Beams DL HARQ: " << activeDlHarq.size()
2353 << " sym available: " << static_cast<uint32_t>(dlSymAvail) << " starting from sym "
2354 << static_cast<uint32_t>(m_dlCtrlSymbols));
2355
2356 if (!activeDlHarq.empty())
2357 {
2358 uint8_t usedHarq = ScheduleDlHarq(&dlAssignationStartPoint,
2359 dlSymAvail,
2360 activeDlHarq,
2361 m_ueMap,
2362 &m_dlHarqToRetransmit,
2363 dlHarqFeedback,
2364 allocInfo);
2365 NS_ASSERT(dlSymAvail >= usedHarq);
2366 dlSymAvail -= usedHarq;
2367 }
2368
2369 GetSecond GetUeInfoList;
2370
2371 for (const auto& alloc : allocInfo->m_varTtiAllocInfo)
2372 {
2373 for (auto it = activeDlUe->begin(); it != activeDlUe->end(); /* no incr */)
2374 {
2375 auto& ueInfos = GetUeInfoList(*it);
2376 for (auto ueIt = ueInfos.begin(); ueIt != ueInfos.end(); /* no incr */)
2377 {
2378 GetFirst GetUeInfoPtr;
2379 if (GetUeInfoPtr(*ueIt)->m_rnti == alloc.m_dci->m_rnti)
2380 {
2381 NS_LOG_INFO("Removed RNTI " << alloc.m_dci->m_rnti
2382 << " from active ue list "
2383 "because it has already an HARQ scheduled");
2384 ueInfos.erase(ueIt);
2385 break;
2386 }
2387 else
2388 {
2389 ++ueIt;
2390 }
2391 }
2392 if (!ueInfos.empty())
2393 {
2394 ++it;
2395 }
2396 else
2397 {
2398 activeDlUe->erase(it);
2399 break;
2400 }
2401 }
2402 }
2403
2404 NS_ASSERT(dlAssignationStartPoint.m_rbg == 0);
2405
2406 if (dlSymAvail > 0 && !activeDlUe->empty())
2407 {
2408 uint8_t usedDl =
2409 DoScheduleDlData(&dlAssignationStartPoint, dlSymAvail, *activeDlUe, allocInfo);
2410 NS_ASSERT(dlSymAvail >= usedDl);
2411 dlSymAvail -= usedDl;
2412 }
2413
2414 return (dataSymPerSlot - ulAllocations.m_totUlSym) - dlSymAvail;
2415}
2416
2427void
2430{
2431 NS_LOG_FUNCTION(this);
2432
2433 // process received CQIs
2434 m_cqiManagement.RefreshDlCqiMaps(m_ueMap);
2435
2436 // reset expired HARQ
2437 for (const auto& itUe : m_ueMap)
2438 {
2439 ResetExpiredHARQ(itUe.second->m_rnti, &itUe.second->m_dlHarq);
2440 }
2441
2442 // Merge not-retransmitted and received feedback
2443 std::vector<DlHarqInfo> dlHarqFeedback;
2444
2445 if (!params.m_dlHarqInfoList.empty() || !m_dlHarqToRetransmit.empty())
2446 {
2447 // m_dlHarqToRetransmit will be cleared inside MergeHARQ
2448 uint64_t existingSize = m_dlHarqToRetransmit.size();
2449 uint64_t inSize = params.m_dlHarqInfoList.size();
2450
2451 dlHarqFeedback = MergeHARQ(&m_dlHarqToRetransmit, params.m_dlHarqInfoList, "DL");
2452
2453 NS_ASSERT(m_dlHarqToRetransmit.empty());
2454 NS_ASSERT_MSG(existingSize + inSize == dlHarqFeedback.size(),
2455 " existing: " << existingSize << " received: " << inSize
2456 << " calculated: " << dlHarqFeedback.size());
2457
2458 std::unordered_map<uint16_t, std::set<uint32_t>> feedbacksDup;
2459
2460 // Let's find out:
2461 // 1) Feedback that arrived late (i.e., their process has been marked inactive
2462 // due to timings
2463 // 2) Duplicated feedbacks (same UE, same process ID). I don't know why
2464 // these are generated.. but anyway..
2465 for (auto it = dlHarqFeedback.begin(); it != dlHarqFeedback.end(); /* no inc */)
2466 {
2467 auto& ueInfo = m_ueMap.find(it->m_rnti)->second;
2468 auto& process = ueInfo->m_dlHarq.Find(it->m_harqProcessId)->second;
2469 NS_LOG_INFO("Analyzing feedback for UE " << it->m_rnti << " process "
2470 << static_cast<uint32_t>(it->m_harqProcessId));
2471 if (!process.m_active)
2472 {
2473 NS_LOG_INFO("Feedback for UE " << it->m_rnti << " process "
2474 << static_cast<uint32_t>(it->m_harqProcessId)
2475 << " ignored because process is INACTIVE");
2476 it = dlHarqFeedback.erase(it); /* INC */
2477 }
2478 else
2479 {
2480 auto itDuplicated = feedbacksDup.find(it->m_rnti);
2481 if (itDuplicated == feedbacksDup.end())
2482 {
2483 feedbacksDup.insert(std::make_pair(it->m_rnti, std::set<uint32_t>()));
2484 feedbacksDup.at(it->m_rnti).insert(it->m_harqProcessId);
2485 ++it; /* INC */
2486 }
2487 else
2488 {
2489 if (itDuplicated->second.find(it->m_harqProcessId) ==
2490 itDuplicated->second.end())
2491 {
2492 itDuplicated->second.insert(it->m_harqProcessId);
2493 ++it; /* INC */
2494 }
2495 else
2496 {
2497 NS_LOG_INFO("Feedback for UE "
2498 << it->m_rnti << " process "
2499 << static_cast<uint32_t>(it->m_harqProcessId)
2500 << " ignored because is a duplicate of another feedback");
2501 it = dlHarqFeedback.erase(it); /* INC */
2502 }
2503 }
2504 }
2505 }
2506
2507 ProcessHARQFeedbacks(&dlHarqFeedback, NrMacSchedulerUeInfo::GetDlHarqVector, "DL");
2508 }
2509
2510 ScheduleDl(params, dlHarqFeedback);
2511}
2512
2523void
2526{
2527 NS_LOG_FUNCTION(this);
2528
2529 // process received CQIs
2530 m_cqiManagement.RefreshUlCqiMaps(m_ueMap);
2531
2532 // reset expired HARQ
2533 for (const auto& itUe : m_ueMap)
2534 {
2535 ResetExpiredHARQ(itUe.second->m_rnti, &itUe.second->m_ulHarq);
2536 }
2537
2538 // Merge not-retransmitted and received feedback
2539 std::vector<UlHarqInfo> ulHarqFeedback;
2540 if (!params.m_ulHarqInfoList.empty() || !m_ulHarqToRetransmit.empty())
2541 {
2542 // m_ulHarqToRetransmit will be cleared inside MergeHARQ
2543 uint64_t existingSize = m_ulHarqToRetransmit.size();
2544 uint64_t inSize = params.m_ulHarqInfoList.size();
2545
2546 ulHarqFeedback = MergeHARQ(&m_ulHarqToRetransmit, params.m_ulHarqInfoList, "UL");
2547
2548 NS_ASSERT(m_ulHarqToRetransmit.empty());
2549 NS_ASSERT_MSG(existingSize + inSize == ulHarqFeedback.size(),
2550 " existing: " << existingSize << " received: " << inSize
2551 << " calculated: " << ulHarqFeedback.size());
2552
2553 // if there are feedbacks for expired process, remove them
2554 for (auto it = ulHarqFeedback.begin(); it != ulHarqFeedback.end(); /* no inc */)
2555 {
2556 auto& ueInfo = m_ueMap.find(it->m_rnti)->second;
2557 auto& process = ueInfo->m_ulHarq.Find(it->m_harqProcessId)->second;
2558 if (!process.m_active)
2559 {
2560 NS_LOG_INFO("Feedback for UE " << it->m_rnti << " process "
2561 << static_cast<uint32_t>(it->m_harqProcessId)
2562 << " ignored because process is INACTIVE");
2563 it = ulHarqFeedback.erase(it);
2564 }
2565 else
2566 {
2567 ++it;
2568 }
2569 }
2570
2571 ProcessHARQFeedbacks(&ulHarqFeedback, NrMacSchedulerUeInfo::GetUlHarqVector, "UL");
2572 }
2573
2574 ScheduleUl(params, ulHarqFeedback);
2575}
2576
2583void
2586{
2587 NS_LOG_FUNCTION(this);
2588
2589 // Merge RNTI in our current list
2590 for (const auto& ue : params.m_srList)
2591 {
2592 NS_LOG_INFO("UE " << ue << " asked for a SR ");
2593
2594 auto it = std::find(m_srList.begin(), m_srList.end(), ue);
2595 if (it == m_srList.end())
2596 {
2597 m_srList.push_back(ue);
2598 }
2599 }
2600 NS_ASSERT(m_srList.size() >= params.m_srList.size());
2601}
2602
2618uint8_t
2619NrMacSchedulerNs3::DoScheduleUlMsg3(PointInFTPlane* sPoint,
2620 uint8_t symAvail,
2621 SlotAllocInfo* slotAlloc)
2622{
2623 NS_LOG_FUNCTION(this);
2624 NS_ASSERT(sPoint->m_rbg == 0);
2625
2626 uint8_t symAvailBeforeRach = symAvail;
2627
2628 for (const auto& rachReq : m_rachList)
2629 {
2630 uint8_t allocSymbols = 0;
2631 uint16_t tbSizeBits = 0;
2632
2633 // find the lowest TB size that fits UL grant estimated size
2634 while ((tbSizeBits < rachReq.m_estimatedSize) && (symAvail - allocSymbols > 0))
2635 {
2636 allocSymbols++;
2637 tbSizeBits =
2638 GetUlAmc()->CalculateTbSize(m_rachUlGrantMcs,
2639 1,
2640 GetBandwidthInRbg() * GetNumRbPerRbg() * allocSymbols) *
2641 8;
2642 }
2643
2644 if (tbSizeBits < rachReq.m_estimatedSize)
2645 {
2646 // no more allocation space: finish allocation
2647 break;
2648 }
2649
2650 sPoint->m_sym -= allocSymbols;
2651
2652 // DL-RACH Allocation
2653 // Ideal: no needs of configuring m_dci
2654 // UL-RACH Allocation
2655 uint8_t rank{1};
2656 Ptr<const ComplexMatrixArray> precMats{nullptr};
2657 std::shared_ptr<DciInfoElementTdma> ulMsg3Dci =
2658 std::make_shared<DciInfoElementTdma>(rachReq.m_rnti,
2660 sPoint->m_sym,
2661 allocSymbols,
2662 m_rachUlGrantMcs,
2663 rank,
2664 precMats,
2665 tbSizeBits / 8,
2666 1,
2667 0,
2669 GetBwpId(),
2670 GetTpc());
2671
2672 std::vector<bool> rbgBitmask(GetBandwidthInRbg(), true);
2673
2674 ulMsg3Dci->m_rbgBitmask = rbgBitmask;
2675 symAvail -= allocSymbols;
2676
2677 NS_LOG_INFO(" UL grant allocated to RNTI "
2678 << ulMsg3Dci->m_rnti << " in slot: " << slotAlloc->m_sfnSf << " symStart "
2679 << +ulMsg3Dci->m_symStart << " symEnd " << +ulMsg3Dci->m_numSym
2680 << " number of PRB" << GetBandwidthInRbg() * GetNumRbPerRbg() << " MCS "
2681 << (uint16_t) + ulMsg3Dci->m_mcs << " tbSize in bytes:" << +ulMsg3Dci->m_tbSize
2682 << " BWP index: " << +ulMsg3Dci->m_bwpIndex
2683 << " RBG bitmask:" << +ulMsg3Dci->m_rbgBitmask.size());
2684
2685 VarTtiAllocInfo slotInfo(ulMsg3Dci);
2686 slotAlloc->m_varTtiAllocInfo.emplace_front(slotInfo);
2687 }
2688
2689 m_rachList.clear();
2690 return (symAvailBeforeRach - symAvail);
2691}
2692
2693} // namespace ns3
Template for the implementation of the NrFhSchedSapUser as a member of an owner class of type C to wh...
@ Dropping
Drop DCI + DATA at the PHY Layer.
Service Access Point (SAP) offered by the FhControl instance to the MAC Scheduler instance.
Service Access Point (SAP) offered by the MAC Scheduler instance to the FhControl instance.
virtual uint32_t GetNumRbPerRbg() const =0
Get the number of RB per RBG.
virtual Time GetSlotPeriod() const =0
Get the slot period.
virtual uint16_t GetBwpId() const =0
Get the BWP ID.
virtual uint32_t GetSymbolsPerSlot() const =0
Get the Symbol per slot.
virtual void SchedConfigInd(const struct SchedConfigIndParameters &params)=0
Install a scheduling decision.
virtual uint16_t GetCellId() const =0
Get the Cell ID.
virtual Ptr< const SpectrumModel > GetSpectrumModel() const =0
Get the SpectrumModel.
virtual void BuildRarList(SlotAllocInfo &slotAllocInfo)=0
Build RAR list from allocations and assign preamble IDs.
virtual uint8_t GetNumHarqProcess() const =0
Get the number of HARQ process.
void RefreshUlCqiMaps(const std::unordered_map< uint16_t, std::shared_ptr< NrMacSchedulerUeInfo > > &m_ueMap) const
Refresh the UL CQI for all the UE.
void InstallGetCellIdFn(const std::function< uint16_t()> &fn)
Install a function to retrieve the cell id.
void RefreshDlCqiMaps(const std::unordered_map< uint16_t, std::shared_ptr< NrMacSchedulerUeInfo > > &m_ueMap) const
Refresh the DL CQI for all the UE.
void InstallGetBwpIdFn(const std::function< uint16_t()> &fn)
Install a function to retrieve the bwp id.
void UlSBCQIReported(uint32_t expirationTime, uint32_t tbs, const NrMacSchedSapProvider::SchedUlCqiInfoReqParameters &params, const std::shared_ptr< NrMacSchedulerUeInfo > &ueInfo, const std::vector< bool > &rbgMask, uint32_t numRbPerRbg, const Ptr< const SpectrumModel > &model) const
An UL SB CQI has been reported for the specified UE.
void DlCqiReported(const DlCqiInfo &info, const std::shared_ptr< NrMacSchedulerUeInfo > &ueInfo, uint32_t expirationTime, int8_t maxDlMcs, uint16_t bandwidthInRbgs) const
A wideband CQI has been reported for the specified UE.
Interface for all the nr schedulers.
NrMacSchedSapUser * m_macSchedSapUser
SAP user.
NrMacCschedSapUser * m_macCschedSapUser
SAP User.
static TypeId GetTypeId()
Get the type ID.
bool IsSrsInUlSlots() const
Check if the UL slots are allowed for SRS transmission.
void DoCschedUeConfigReq(const NrMacCschedSapProvider::CschedUeConfigReqParameters &params) override
Register an UE.
NrMacSchedulerNs3()
NrMacSchedulerNs3 default constructor.
uint8_t GetUlCtrlSyms() const override
Retrieve the number of UL ctrl symbols configured in the scheduler.
std::unordered_map< BeamId, HarqVectorIteratorList, BeamIdHash > ActiveHarqMap
Map between a beamID and the HARQ of that beam.
virtual std::shared_ptr< NrMacSchedulerUeInfo > CreateUeRepresentation(const NrMacCschedSapProvider::CschedUeConfigReqParameters &params) const =0
Create an UE representation for the scheduler.
Ptr< NrAmc > m_ulAmc
AMC pointer.
bool IsHarqReTxEnable() const
Is HARQ ReTx enable function.
uint8_t GetStartMcsDl() const
Get the DL MCS starting value.
int64_t AssignStreams(int64_t stream) override
Assign a fixed random variable stream number to the random variables used by this model....
void DoCschedUeReleaseReq(const NrMacCschedSapProvider::CschedUeReleaseReqParameters &params) override
Release an UE.
void DoSchedUlTriggerReq(const NrMacSchedSapProvider::SchedUlTriggerReqParameters &params) override
Decide how to fill the frequency/time of a UL slot.
NrMacSchedulerUeInfo::McsCsiSource m_mcsCsiSource
CSI information source for DL MCS estimation.
void SetSrsInFSlots(bool v)
Set if the F slots are allowed for SRS transmission.
virtual void ChangeDlBeam(PointInFTPlane *spoint, uint32_t symOfBeam) const =0
Perform a custom operation on the starting point each time all the UE of a DL beam have been schedule...
void SetRachUlGrantMcs(uint8_t v)
Sets the default RACH UL grant MCS.
virtual BeamSymbolMap AssignDLRBG(uint32_t symAvail, const ActiveUeMap &activeDl) const =0
Assign the DL RBG to the active UE, and return the distribution of symbols per beam.
virtual void SortUlHarq(ActiveHarqMap *activeUlHarq) const
Sort the UL HARQ retransmission.
NrFhSchedSapUser * GetNrFhSchedSapUser() override
void SetSrsCtrlSyms(uint8_t v)
Set the number of UL SRS symbols.
void DoCschedLcReleaseReq(const NrMacCschedSapProvider::CschedLcReleaseReqParameters &params) override
Release a LC.
void SetFixedDlMcs(bool v)
Set if the MCS in DL is fixed (in case, it will take the starting value)
virtual void ChangeUlBeam(PointInFTPlane *spoint, uint32_t symOfBeam) const =0
Perform a custom operation on the starting point each time all the UE of an UL beam have been schedul...
NrFhSchedSapProvider * m_nrFhSchedSapProvider
FH Control SAP provider.
Ptr< NrAmc > m_dlAmc
AMC pointer.
bool IsSrsInFSlots() const
Check if the F slots are allowed for SRS transmission.
void SetUlCtrlSyms(uint8_t v)
Set the number of UL ctrl symbols.
uint8_t GetSrsCtrlSyms() const
Get the configured value for the SRS symbols.
virtual uint8_t ScheduleUlHarq(NrMacSchedulerNs3::PointInFTPlane *startingPoint, uint8_t symAvail, const std::unordered_map< uint16_t, UePtr > &ueMap, std::vector< UlHarqInfo > *ulHarqToRetransmit, const std::vector< UlHarqInfo > &ulHarqFeedback, SlotAllocInfo *slotAlloc) const
Giving the input, append to slotAlloc the allocations for the DL HARQ retransmissions.
void InstallUlAmc(const Ptr< NrAmc > &ulAmc)
Install the AMC for the DL part.
Ptr< const NrAmc > GetDlAmc() const
Get the AMC for DL.
void SetSrsInUlSlots(bool v)
Set if the UL slots are allowed for SRS transmission (if True, UL and F slots may carry SRS,...
void SetStartMcsUl(uint8_t v)
Set the starting value for the UL MCS.
std::vector< bool > GetUlNotchedRbgMask() const
Get the notched (blank) RBGs Mask for the UL.
uint8_t GetStartMcsUl() const
Get the DL MCS starting value.
std::unordered_map< BeamId, uint32_t, BeamIdHash > BeamSymbolMap
Map between a BeamId and the symbol assigned to that beam.
void DoSchedSetMcs(uint32_t mcs) override
Set a fixed MCS.
void DoCschedLcConfigReq(const NrMacCschedSapProvider::CschedLcConfigReqParameters &params) override
Configure a logical channel for a UE.
void DoSchedDlCqiInfoReq(const NrMacSchedSapProvider::SchedDlCqiInfoReqParameters &params) override
Received a DL CQI message.
virtual std::shared_ptr< DciInfoElementTdma > CreateUlDci(PointInFTPlane *spoint, const std::shared_ptr< NrMacSchedulerUeInfo > &ueInfo, uint32_t maxSym) const =0
Create a DCI for the specified UE for UL data.
void DoSchedUlCqiInfoReq(const NrMacSchedSapProvider::SchedUlCqiInfoReqParameters &params) override
Received a UL CQI message.
uint16_t GetBwpId() const
Get the bwp id of this MAC.
void DoCschedCellConfigReq(const NrMacCschedSapProvider::CschedCellConfigReqParameters &params) override
Cell configuration.
void SetStartMcsDl(uint8_t v)
Set the starting value for the DL MCS.
void SetLcSched(const TypeId &type)
Set LC Scheduler Algorithm model type.
virtual BeamSymbolMap AssignULRBG(uint32_t symAvail, const ActiveUeMap &activeUl) const =0
Assign the UL RBG to the active UE, and return the distribution of symbols per beam.
NrFhSchedSapUser * m_nrFhSchedSapUser
FH Control SAP user.
static TypeId GetTypeId()
GetTypeId.
bool DoesFhAllocationFit(uint16_t bwpId, uint32_t mcs, uint32_t nRegs, uint8_t dlRank) const
Returns a boolean indicating whether the current allocation can fit in the available FH bandwidth (wh...
Time GetCqiTimerThreshold() const
Get the CqiTimerThreshold.
void SetUlNotchedRbgMask(const std::vector< bool > &ulNotchedRbgsMask)
Set the notched (blank) RBGs Mask for the UL.
std::unordered_map< BeamId, std::vector< UePtrAndBufferReq >, BeamIdHash > ActiveUeMap
Map between a BeamId and a vector of UE (the UE are in that beam)
bool IsUlMcsFixed() const
Check if the MCS in UL is fixed.
std::vector< bool > GetDlNotchedRbgMask() const
Get the notched (blank) RBGs Mask for the DL.
void InstallDlAmc(const Ptr< NrAmc > &dlAmc)
Install the AMC for the DL part.
~NrMacSchedulerNs3() override
NrMacSchedulerNs3 deconstructor.
virtual void SortDlHarq(ActiveHarqMap *activeDlHarq) const
Sort the DL HARQ retransmission.
void SetFixedUlMcs(bool v)
Set if the MCS in UL is fixed (in case, it will take the starting value)
virtual uint8_t GetTpc() const =0
Returns TPC command.
void DoSchedDlRlcBufferReq(const NrMacSchedSapProvider::SchedDlRlcBufferReqParameters &params) override
RLC informs of DL data.
void DoSchedDlRachInfoReq(const NrMacSchedSapProvider::SchedDlRachInfoReqParameters &params) override
RACH information.
void EnableHarqReTx(bool enableFlag)
Enable HARQ ReTx function.
virtual std::shared_ptr< DciInfoElementTdma > CreateDlDci(PointInFTPlane *spoint, const std::shared_ptr< NrMacSchedulerUeInfo > &ueInfo, uint32_t maxSym) const =0
Create a DCI for the specified UE for DL data.
void DoSchedDlTriggerReq(const NrMacSchedSapProvider::SchedDlTriggerReqParameters &params) override
Decide how to fill the frequency/time of a DL slot.
void SetNrFhSchedSapProvider(NrFhSchedSapProvider *s) override
void DoSchedUlMacCtrlInfoReq(const NrMacSchedSapProvider::SchedUlMacCtrlInfoReqParameters &params) override
Evaluate different types of control messages (only BSR for the moment)
virtual uint8_t ScheduleDlHarq(NrMacSchedulerNs3::PointInFTPlane *startingPoint, uint8_t symAvail, const ActiveHarqMap &activeDlHarq, const std::unordered_map< uint16_t, UePtr > &ueMap, std::vector< DlHarqInfo > *dlHarqToRetransmit, const std::vector< DlHarqInfo > &dlHarqFeedback, SlotAllocInfo *slotAlloc) const
Giving the input, append to slotAlloc the allocations for the DL HARQ retransmissions.
virtual LCPtr CreateLC(const nr::LogicalChannelConfigListElement_s &config) const
Create a logical channel starting from a configuration.
bool IsDlMcsFixed() const
Check if the MCS in DL is fixed.
virtual LCGPtr CreateLCG(const nr::LogicalChannelConfigListElement_s &config) const
Create a logical channel group starting from a configuration.
void DoSchedUlSrInfoReq(const NrMacSchedSapProvider::SchedUlSrInfoReqParameters &params) override
Save the SR list into m_srList.
uint64_t GetNumRbPerRbg() const
Private function that is used to get the number of resource blocks per resource block group and also ...
uint16_t GetCellId() const
Get the cell id of this MAC.
void SetDlCtrlSyms(uint8_t v)
Set the number of DL ctrl symbols.
void SetMaxDlMcs(int8_t v)
Set the maximum index for the DL MCS.
Ptr< const NrAmc > GetUlAmc() const
Get the AMC for UL.
uint8_t GetFhControlMethod() const
Get the FH Control Method.
uint8_t GetDlCtrlSyms() const override
Retrieve the number of DL ctrl symbols configured in the scheduler.
int8_t GetMaxDlMcs() const
Get the maximum DL MCS index.
void SetCqiTimerThreshold(const Time &v)
Set the CqiTimerThreshold.
void SetDlNotchedRbgMask(const std::vector< bool > &dlNotchedRbgsMask)
Set the notched (blank) RBGs Mask for the DL.
static std::unordered_map< uint8_t, LCGPtr > & GetUlLCG(const UePtr &ue)
GetUlLCG.
static NrMacHarqVector & GetUlHarqVector(const UePtr &ue)
GetUlHarqVector.
@ AVG_MCS
Estimate MCS based on the average MCS of allocated RBGs.
@ AVG_SPEC_EFF
Estimate MCS based on the average spectral efficiency of allocated RBGs.
@ AVG_SINR
Estimate MCS based on the average SINR of allocated RBGs.
static std::unordered_map< uint8_t, LCGPtr > & GetDlLCG(const UePtr &ue)
GetDlLCG.
static NrMacHarqVector & GetDlHarqVector(const UePtr &ue)
GetDlHarqVector.
static uint64_t FromLevelToBytes(uint8_t bufferLevel)
Convert a buffer level into a buffer size.
The SfnSf class.
Definition sfnsf.h:32
uint64_t GetEncoding() const
Get encoding for this SfnSf.
Definition sfnsf.cc:24
std::unique_ptr< NrMacSchedulerLC > LCPtr
Unique pointer to an instance of NrMacSchedulerLC.
std::unique_ptr< NrMacSchedulerLCG > LCGPtr
LCGPtr unique pointer to a LCG.
LteNrTddSlotType
Available TDD slot types. Ordering is important.
@ F
DL CTRL + DL DATA + UL DATA + UL CTRL.
@ S
DL CTRL + DL DATA + UL CTRL.
@ UL
UL DATA + UL CTRL.
@ CTRL
Used for DL/UL CTRL.
@ DATA
Used for DL/UL DATA.
@ SRS
Used for SRS (it would be like DCI format 2_3)
DciFormat
Format of the DCI.
@ RECEIVED_FEEDBACK
Received feedback (NACK)
@ WAITING_FEEDBACK
Data transmitted, waiting the feedback.
@ INACTIVE
Inactive process.
See section 4.3.14 macCEListElement.
uint16_t m_dlBandwidth
In number of RBG, created by MAC and passed to the scheduler.
uint16_t m_ulBandwidth
In number of RBG, created by MAC and passed to the scheduler.
std::vector< struct DlCqiInfo > m_cqiList
cqi list
std::vector< struct nr::RachListElement_s > m_rachList
RACH list.
uint8_t m_logicalChannelIdentity
The logical channel ID, range: 0..10.
DL HARQ information to be used when scheduling UL data.
std::vector< struct DlHarqInfo > m_dlHarqInfoList
DL HARQ info list.
uint8_t m_symStart
Sym start of the transmission to which this CQI refers to.
The SchedUlMacCtrlInfoReqParameters struct.
std::vector< struct MacCeElement > m_macCeList
MacCeElement list.
SR received from MAC, to pass to schedulers.
std::vector< uint16_t > m_srList
List of RNTI which asked for a SR.
UL HARQ information to be used when scheduling UL data.
std::vector< struct UlHarqInfo > m_ulHarqInfoList
UL HARQ info list.
Point in the Frequency/Time plane.
Struct to indicate to the scheduler the periodicity and the offset, in slots.
uint32_t m_periodicity
The periodicity requested (in slot).
uint32_t m_offset
The offset requested (in slot).
bool m_isValid
Indicates if the values are valid.
The SlotAllocInfo struct.
SfnSf m_sfnSf
SfnSf of this allocation.
@ UL
UL Allocations.
@ DL
DL Allocations.
std::deque< VarTtiAllocInfo > m_varTtiAllocInfo
queue of allocations
See section 4.3.4 logicalChannelConfigListElement.
uint8_t m_logicalChannelGroup
logical channel group