5G-LENA nr-v3.0-32-g83aee33
The 5G/NR module for the ns-3 simulator
Loading...
Searching...
No Matches
nr-mac-scheduler-ns3.cc
1/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
2
3// Copyright (c) 2019 Centre Tecnologic de Telecomunicacions de Catalunya (CTTC)
4//
5// SPDX-License-Identifier: GPL-2.0-only
6
7#define NS_LOG_APPEND_CONTEXT \
8 do \
9 { \
10 std::clog << " [ CellId " << GetCellId() << ", bwpId " << GetBwpId() << "] "; \
11 } while (false);
12
13#include "nr-mac-scheduler-ns3.h"
14
15#include "nr-mac-scheduler-harq-rr.h"
16#include "nr-mac-scheduler-lc-rr.h"
17#include "nr-mac-scheduler-srs-default.h"
18#include "nr-mac-short-bsr-ce.h"
19
20#include <ns3/boolean.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
47 m_cqiManagement.InstallGetBwpIdFn(std::bind(&NrMacSchedulerNs3::GetBwpId, this));
48 m_cqiManagement.InstallGetCellIdFn(std::bind(&NrMacSchedulerNs3::GetCellId, this));
49 m_cqiManagement.InstallGetNrAmcDlFn(std::bind([this]() { return m_dlAmc; }));
50 m_cqiManagement.InstallGetNrAmcUlFn(std::bind([this]() { return m_ulAmc; }));
51 m_cqiManagement.InstallGetStartMcsDlFn(std::bind([this]() { return m_startMcsDl; }));
52 m_cqiManagement.InstallGetStartMcsUlFn(std::bind([this]() { return m_startMcsUl; }));
53
54 // If more Srs allocators will be created, then we will add an attribute
55 m_schedulerSrs = CreateObject<NrMacSchedulerSrsDefault>();
56}
57
59{
60 m_ueMap.clear();
61}
62
63void
64NrMacSchedulerNs3::InstallDlAmc(const Ptr<NrAmc>& dlAmc)
65{
66 m_dlAmc = dlAmc;
67 m_dlAmc->SetDlMode();
68}
69
70void
71NrMacSchedulerNs3::InstallUlAmc(const Ptr<NrAmc>& ulAmc)
72{
73 m_ulAmc = ulAmc;
74 m_ulAmc->SetUlMode();
75}
76
77Ptr<const NrAmc>
79{
80 NS_LOG_FUNCTION(this);
81 return m_ulAmc;
82}
83
84Ptr<const NrAmc>
86{
87 NS_LOG_FUNCTION(this);
88 return m_dlAmc;
89}
90
91int64_t
93{
94 NS_LOG_FUNCTION(this << stream);
95 return m_schedulerSrs->AssignStreams(stream);
96 ;
97}
98
99TypeId
101{
102 static TypeId tid =
103 TypeId("ns3::NrMacSchedulerNs3")
104 .SetParent<NrMacScheduler>()
105 .AddAttribute("CqiTimerThreshold",
106 "The time while a CQI is valid",
107 TimeValue(Seconds(1)),
110 MakeTimeChecker())
111 .AddAttribute("FixedMcsDl",
112 "Fix MCS to value set in StartingMcsDl",
113 BooleanValue(false),
114 MakeBooleanAccessor(&NrMacSchedulerNs3::SetFixedDlMcs,
116 MakeBooleanChecker())
117 .AddAttribute("FixedMcsUl",
118 "Fix MCS to value set in StartingMcsUl",
119 BooleanValue(false),
120 MakeBooleanAccessor(&NrMacSchedulerNs3::SetFixedUlMcs,
122 MakeBooleanChecker())
123 .AddAttribute("StartingMcsDl",
124 "Starting MCS for DL",
125 UintegerValue(0),
126 MakeUintegerAccessor(&NrMacSchedulerNs3::SetStartMcsDl,
128 MakeUintegerChecker<uint8_t>())
129 .AddAttribute("StartingMcsUl",
130 "Starting MCS for UL",
131 UintegerValue(0),
132 MakeUintegerAccessor(&NrMacSchedulerNs3::SetStartMcsUl,
134 MakeUintegerChecker<uint8_t>())
135 .AddAttribute("DlCtrlSymbols",
136 "Number of symbols allocated for DL CTRL",
137 UintegerValue(1),
138 MakeUintegerAccessor(&NrMacSchedulerNs3::SetDlCtrlSyms,
140 MakeUintegerChecker<uint8_t>())
141 .AddAttribute("UlCtrlSymbols",
142 "Number of symbols allocated for UL CTRL",
143 UintegerValue(1),
144 MakeUintegerAccessor(&NrMacSchedulerNs3::SetUlCtrlSyms,
146 MakeUintegerChecker<uint8_t>())
147 .AddAttribute("SrsSymbols",
148 "Number of symbols allocated for UL SRS",
149 UintegerValue(1),
150 MakeUintegerAccessor(&NrMacSchedulerNs3::SetSrsCtrlSyms,
152 MakeUintegerChecker<uint8_t>())
153 .AddAttribute("EnableSrsInUlSlots",
154 "Denotes whether the SRSs will be transmitted only in F slots"
155 "or both in F and UL slots. If False, SRS is transmitted only"
156 "in F slots, if True in both (F/UL)",
157 BooleanValue(true),
158 MakeBooleanAccessor(&NrMacSchedulerNs3::SetSrsInUlSlots,
160 MakeBooleanChecker())
161 .AddAttribute("EnableSrsInFSlots",
162 "Denotes whether the SRSs will be transmitted in F slots"
163 "If true, it can be transmitted in F slots, otherwise "
164 "it cannot.",
165 BooleanValue(true),
166 MakeBooleanAccessor(&NrMacSchedulerNs3::SetSrsInFSlots,
168 MakeBooleanChecker())
169 .AddAttribute("DlAmc",
170 "The DL AMC of this scheduler",
171 PointerValue(),
172 MakePointerAccessor(&NrMacSchedulerNs3::m_dlAmc),
173 MakePointerChecker<NrAmc>())
174 .AddAttribute("UlAmc",
175 "The UL AMC of this scheduler",
176 PointerValue(),
177 MakePointerAccessor(&NrMacSchedulerNs3::m_ulAmc),
178 MakePointerChecker<NrAmc>())
179 .AddAttribute("MaxDlMcs",
180 "Maximum MCS index for DL",
181 IntegerValue(-1),
182 MakeIntegerAccessor(&NrMacSchedulerNs3::SetMaxDlMcs,
184 MakeIntegerChecker<int8_t>(-1, 30))
185 .AddAttribute("EnableHarqReTx",
186 "If true, it would set the max HARQ ReTx to 3; otherwise it set it to 0",
187 BooleanValue(true),
188 MakeBooleanAccessor(&NrMacSchedulerNs3::EnableHarqReTx,
190 MakeBooleanChecker())
191 .AddAttribute(
192 "SchedLcAlgorithmType",
193 "Type of the scheduling algorithm that assigns bytes to the different LCs.",
194 TypeIdValue(NrMacSchedulerLcRR::GetTypeId()),
195 MakeTypeIdAccessor(&NrMacSchedulerNs3::SetLcSched),
196 //&NrMacSchedulerNs3::GetLcSched),
197 MakeTypeIdChecker());
198
199 return tid;
200}
201
209void
211{
212 NS_LOG_FUNCTION(this);
213 m_fixedMcsDl = true;
214 m_fixedMcsUl = true;
215 m_startMcsDl = static_cast<uint8_t>(mcs);
216 m_startMcsUl = static_cast<uint8_t>(mcs);
217}
218
219void
222{
223 NS_LOG_FUNCTION(this);
224
225 m_rachList = params.m_rachList;
226}
227
228void
230{
231 NS_LOG_FUNCTION(this);
232 m_cqiTimersThreshold = v;
233}
234
235Time
237{
238 NS_LOG_FUNCTION(this);
239 return m_cqiTimersThreshold;
240}
241
242void
244{
245 NS_LOG_FUNCTION(this);
246 m_fixedMcsDl = v;
247}
248
249bool
251{
252 NS_LOG_FUNCTION(this);
253 return m_fixedMcsDl;
254}
255
256void
258{
259 NS_LOG_FUNCTION(this);
260 m_fixedMcsUl = v;
261}
262
263bool
265{
266 NS_LOG_FUNCTION(this);
267 return m_fixedMcsUl;
268}
269
270void
272{
273 NS_LOG_FUNCTION(this);
274 m_startMcsDl = v;
275}
276
277uint8_t
279{
280 NS_LOG_FUNCTION(this);
281 return m_startMcsDl;
282}
283
284void
286{
287 NS_LOG_FUNCTION(this);
288 m_maxDlMcs = v;
289}
290
291int8_t
293{
294 NS_LOG_FUNCTION(this);
295 return m_maxDlMcs;
296}
297
298void
300{
301 NS_LOG_FUNCTION(this);
302 ObjectFactory factory;
303 m_schedLcType = type;
304
305 factory.SetTypeId(m_schedLcType);
306 m_schedLc = DynamicCast<NrMacSchedulerLcAlgorithm>(factory.Create());
307 NS_ASSERT(m_schedLc != nullptr);
308}
309
310void
312{
313 NS_LOG_FUNCTION(this);
314 m_startMcsUl = v;
315}
316
317uint8_t
319{
320 NS_LOG_FUNCTION(this);
321 return m_startMcsUl;
322}
323
324void
326{
327 m_dlCtrlSymbols = v;
328}
329
330uint8_t
332{
333 return m_dlCtrlSymbols;
334}
335
336void
338{
339 m_ulCtrlSymbols = v;
340}
341
342void
343NrMacSchedulerNs3::SetDlNotchedRbgMask(const std::vector<uint8_t>& dlNotchedRbgsMask)
344{
345 NS_LOG_FUNCTION(this);
346 m_dlNotchedRbgsMask = dlNotchedRbgsMask;
347 std::stringstream ss;
348
349 // print the DL mask set (prefix + is added just for printing purposes)
350 for (const auto& x : m_dlNotchedRbgsMask)
351 {
352 ss << +x << " ";
353 }
354 NS_LOG_INFO("Set DL notched mask: " << ss.str());
355}
356
357std::vector<uint8_t>
359{
360 return m_dlNotchedRbgsMask;
361}
362
363void
364NrMacSchedulerNs3::SetUlNotchedRbgMask(const std::vector<uint8_t>& ulNotchedRbgsMask)
365{
366 NS_LOG_FUNCTION(this);
367 m_ulNotchedRbgsMask = ulNotchedRbgsMask;
368 std::stringstream ss;
369
370 // print the UL mask set (prefix + is added just for printing purposes)
371 for (const auto& x : m_ulNotchedRbgsMask)
372 {
373 ss << +x << " ";
374 }
375 NS_LOG_INFO("Set UL notched mask: " << ss.str());
376}
377
378std::vector<uint8_t>
380{
381 return m_ulNotchedRbgsMask;
382}
383
384void
386{
387 m_srsCtrlSymbols = v;
388}
389
390uint8_t
392{
393 return m_srsCtrlSymbols;
394}
395
396void
398{
399 m_enableSrsInUlSlots = v;
400}
401
402bool
404{
405 return m_enableSrsInUlSlots;
406}
407
408void
410{
411 m_enableSrsInFSlots = v;
412}
413
414bool
416{
417 return m_enableSrsInFSlots;
418}
419
420void
422{
423 m_enableHarqReTx = enableFlag;
424}
425
426bool
428{
429 return m_enableHarqReTx;
430}
431
432uint8_t
434 uint8_t symAvail,
435 const NrMacSchedulerNs3::ActiveHarqMap& activeDlHarq,
436 const std::unordered_map<uint16_t, UePtr>& ueMap,
437 std::vector<DlHarqInfo>* dlHarqToRetransmit,
438 const std::vector<DlHarqInfo>& dlHarqFeedback,
439 SlotAllocInfo* slotAlloc) const
440{
441 NS_LOG_FUNCTION(this);
442 return m_schedHarq->ScheduleDlHarq(startingPoint,
443 symAvail,
444 activeDlHarq,
445 ueMap,
446 dlHarqToRetransmit,
447 dlHarqFeedback,
448 slotAlloc);
449}
450
451uint8_t
453 uint8_t symAvail,
454 const std::unordered_map<uint16_t, UePtr>& ueMap,
455 std::vector<UlHarqInfo>* ulHarqToRetransmit,
456 const std::vector<UlHarqInfo>& ulHarqFeedback,
457 SlotAllocInfo* slotAlloc) const
458{
459 NS_LOG_FUNCTION(this);
460 return m_schedHarq->ScheduleUlHarq(startingPoint,
461 symAvail,
462 ueMap,
463 ulHarqToRetransmit,
464 ulHarqFeedback,
465 slotAlloc);
466}
467
468void
470{
471 NS_LOG_FUNCTION(this);
472 m_schedHarq->SortDlHarq(activeDlHarq);
473}
474
475void
477{
478 NS_LOG_FUNCTION(this);
479 m_schedHarq->SortDlHarq(activeUlHarq);
480}
481
482uint8_t
484{
485 return m_ulCtrlSymbols;
486}
487
494void
497{
498 NS_LOG_FUNCTION(this);
499
500 NS_ASSERT(params.m_ulBandwidth == params.m_dlBandwidth);
501 m_bandwidth = params.m_dlBandwidth;
502
504 cnf.m_result = SUCCESS;
505 m_macCschedSapUser->CschedUeConfigCnf(cnf);
506}
507
517void
520{
521 NS_LOG_FUNCTION(this << " RNTI " << params.m_rnti << " txMode "
522 << static_cast<uint32_t>(params.m_transmissionMode));
523
524 auto itUe = m_ueMap.find(params.m_rnti);
525 GetSecond UeInfoOf;
526 if (itUe == m_ueMap.end())
527 {
528 itUe = m_ueMap.insert(std::make_pair(params.m_rnti, CreateUeRepresentation(params))).first;
529
530 UeInfoOf(*itUe)->m_dlHarq.SetMaxSize(
531 static_cast<uint8_t>(m_macSchedSapUser->GetNumHarqProcess()));
532 UeInfoOf(*itUe)->m_ulHarq.SetMaxSize(
533 static_cast<uint8_t>(m_macSchedSapUser->GetNumHarqProcess()));
534 UeInfoOf(*itUe)->m_dlMcs = m_startMcsDl;
535 UeInfoOf(*itUe)->m_startMcsDlUe = m_startMcsDl;
536 UeInfoOf(*itUe)->m_ulMcs = m_startMcsUl;
537
538 NrMacSchedulerSrs::SrsPeriodicityAndOffset srs = m_schedulerSrs->AddUe();
539
540 if (!srs.m_isValid)
541 {
542 bool ret = m_schedulerSrs->IncreasePeriodicity(
543 &m_ueMap); // The new UE will get the SRS offset/periodicity here
544 NS_ASSERT(ret);
545 }
546 else
547 {
548 UeInfoOf(*itUe)->m_srsPeriodicity =
549 srs.m_periodicity; // set the periodicity/offset based on the return value
550 UeInfoOf(*itUe)->m_srsOffset = srs.m_offset;
551 }
552
553 NS_LOG_INFO("Creating user, beam " << params.m_beamId << " and ue " << params.m_rnti
554 << " assigned SRS periodicity " << srs.m_periodicity
555 << " and offset " << srs.m_offset);
556 }
557 else
558 {
559 NS_LOG_LOGIC("Updating Beam for UE " << params.m_rnti << " beam " << params.m_beamId);
560 UeInfoOf(*itUe)->m_beamId = params.m_beamId;
561 }
562}
563
571void
574{
575 NS_LOG_FUNCTION(this << " Release RNTI " << params.m_rnti);
576
577 auto itUe = m_ueMap.find(params.m_rnti);
578 NS_ABORT_IF(itUe == m_ueMap.end());
579
580 m_schedulerSrs->RemoveUe(itUe->second->m_srsOffset);
581 m_ueMap.erase(itUe);
582
583 // When it will be the case of reducing the periodicity? Question for the
584 // future...
585
586 NS_LOG_INFO("Release RNTI " << params.m_rnti);
587}
588
589uint64_t
594
605LCPtr
606NrMacSchedulerNs3::CreateLC(const LogicalChannelConfigListElement_s& config) const
607{
608 NS_LOG_FUNCTION(this);
609 return std::make_unique<NrMacSchedulerLC>(config);
610}
611
622LCGPtr
623NrMacSchedulerNs3::CreateLCG(const LogicalChannelConfigListElement_s& config) const
624{
625 NS_LOG_FUNCTION(this);
626 return std::make_unique<NrMacSchedulerLCG>(config.m_logicalChannelGroup);
627}
628
642void
645{
646 NS_LOG_FUNCTION(this << static_cast<uint32_t>(params.m_rnti));
647 auto itUe = m_ueMap.find(params.m_rnti);
648 GetSecond UeInfoOf;
649 NS_ABORT_IF(itUe == m_ueMap.end());
650
651 for (const auto& lcConfig : params.m_logicalChannelConfigList)
652 {
653 if (lcConfig.m_direction == LogicalChannelConfigListElement_s::DIR_DL ||
654 lcConfig.m_direction == LogicalChannelConfigListElement_s::DIR_BOTH)
655 {
656 auto itDl = UeInfoOf(*itUe)->m_dlLCG.find(lcConfig.m_logicalChannelGroup);
657 auto itDlEnd = UeInfoOf(*itUe)->m_dlLCG.end();
658 if (itDl == itDlEnd)
659 {
660 NS_LOG_DEBUG("Created DL LCG for UE "
661 << UeInfoOf(*itUe)->m_rnti
662 << " ID=" << static_cast<uint32_t>(lcConfig.m_logicalChannelGroup));
663 std::unique_ptr<NrMacSchedulerLCG> lcg = CreateLCG(lcConfig);
664 itDl = UeInfoOf(*itUe)
665 ->m_dlLCG.emplace(lcConfig.m_logicalChannelGroup, std::move(lcg))
666 .first;
667 }
668
669 itDl->second->Insert(CreateLC(lcConfig));
670 NS_LOG_DEBUG("Created DL LC for UE "
671 << UeInfoOf(*itUe)->m_rnti
672 << " ID=" << static_cast<uint32_t>(lcConfig.m_logicalChannelIdentity)
673 << " in LCG " << static_cast<uint32_t>(lcConfig.m_logicalChannelGroup));
674 }
675 if (lcConfig.m_direction == LogicalChannelConfigListElement_s::DIR_UL ||
676 lcConfig.m_direction == LogicalChannelConfigListElement_s::DIR_BOTH)
677 {
678 auto itUl = UeInfoOf(*itUe)->m_ulLCG.find(lcConfig.m_logicalChannelGroup);
679 auto itUlEnd = UeInfoOf(*itUe)->m_ulLCG.end();
680 if (itUl == itUlEnd)
681 {
682 NS_LOG_DEBUG("Created UL LCG for UE "
683 << UeInfoOf(*itUe)->m_rnti
684 << " ID=" << static_cast<uint32_t>(lcConfig.m_logicalChannelGroup));
685 std::unique_ptr<NrMacSchedulerLCG> lcg = CreateLCG(lcConfig);
686 itUl = UeInfoOf(*itUe)
687 ->m_ulLCG.emplace(lcConfig.m_logicalChannelGroup, std::move(lcg))
688 .first;
689 }
690
691 // Create a LC ID only if it is the first. For detail, see documentation
692 // of NrMacSchedulerLCG.
693 if (itUl->second->NumOfLC() == 0)
694 {
695 itUl->second->Insert(CreateLC(lcConfig));
696 NS_LOG_DEBUG("Created UL LC for UE "
697 << UeInfoOf(*itUe)->m_rnti
698 << " ID=" << static_cast<uint32_t>(lcConfig.m_logicalChannelIdentity)
699 << " in LCG "
700 << static_cast<uint32_t>(lcConfig.m_logicalChannelGroup));
701 }
702 }
703 }
704}
705
712void
715{
716 NS_LOG_FUNCTION(this);
717
718 for ([[maybe_unused]] const auto& lcId : params.m_logicalChannelIdentity)
719 {
720 auto itUe = m_ueMap.find(params.m_rnti);
721 NS_ABORT_IF(itUe == m_ueMap.end());
722
723 // TODO !!!!
724 // UeInfoOf(itUe)->ReleaseLC (lcId);
725 }
726}
727
736void
739{
740 NS_LOG_FUNCTION(this << params.m_rnti
741 << static_cast<uint32_t>(params.m_logicalChannelIdentity));
742
743 GetSecond UeInfoOf;
744 auto itUe = m_ueMap.find(params.m_rnti);
745 NS_ABORT_IF(itUe == m_ueMap.end());
746
747 for (const auto& lcg : UeInfoOf(*itUe)->m_dlLCG)
748 {
749 if (lcg.second->Contains(params.m_logicalChannelIdentity))
750 {
751 NS_LOG_INFO("Updating DL LC Info: " << params
752 << " in LCG: " << static_cast<uint32_t>(lcg.first));
753 lcg.second->UpdateInfo(params);
754 return;
755 }
756 }
757 // Fail miserabily because we didn't found any LC
758 NS_FATAL_ERROR("The LC does not exist. Can't update");
759}
760
770void
771NrMacSchedulerNs3::BSRReceivedFromUe(const MacCeElement& bsr)
772{
773 NS_LOG_FUNCTION(this);
774 NS_ASSERT(bsr.m_macCeType == MacCeElement::BSR);
775 GetSecond UeInfoOf;
776 auto itUe = m_ueMap.find(bsr.m_rnti);
777 NS_ABORT_IF(itUe == m_ueMap.end());
778
779 // The UE only notifies the buf size as sum of all components.
780 // see nr-ue-mac.cc:395
781 for (uint8_t lcg = 0; lcg < 4; ++lcg)
782 {
783 uint8_t bsrId = bsr.m_macCeValue.m_bufferStatus.at(lcg);
784 uint32_t bufSize = NrMacShortBsrCe::FromLevelToBytes(bsrId);
785
786 auto itLcg = UeInfoOf(*itUe)->m_ulLCG.find(lcg);
787 if (itLcg == UeInfoOf(*itUe)->m_ulLCG.end())
788 {
789 NS_ABORT_MSG_IF(bufSize > 0,
790 "LCG " << static_cast<uint32_t>(lcg) << " not found for UE "
791 << itUe->second->m_rnti);
792 continue;
793 }
794
795 if (itLcg->second->GetTotalSize() > 0 || bufSize > 0)
796 {
797 NS_LOG_INFO("Updating UL LCG " << static_cast<uint32_t>(lcg) << " for UE " << bsr.m_rnti
798 << " size " << bufSize);
799 }
800
801 itLcg->second->UpdateInfo(bufSize);
802 }
803}
804
812void
815{
816 NS_LOG_FUNCTION(this);
817
818 for (const auto& element : params.m_macCeList)
819 {
820 if (element.m_macCeType == MacCeElement::BSR)
821 {
822 BSRReceivedFromUe(element);
823 }
824 else
825 {
826 NS_LOG_INFO("Ignoring received CTRL message because it's not a BSR");
827 }
828 }
829}
830
841void
844{
845 NS_LOG_FUNCTION(this);
846
847 if (m_fixedMcsDl)
848 {
849 return;
850 }
851
852 NS_ASSERT(m_cqiTimersThreshold >= m_macSchedSapUser->GetSlotPeriod());
853
854 uint32_t expirationTime =
855 static_cast<uint32_t>(m_cqiTimersThreshold.GetNanoSeconds() /
856 m_macSchedSapUser->GetSlotPeriod().GetNanoSeconds());
857
858 for (const auto& cqi : params.m_cqiList)
859 {
860 NS_ASSERT(m_ueMap.find(cqi.m_rnti) != m_ueMap.end());
861 const std::shared_ptr<NrMacSchedulerUeInfo>& ue = m_ueMap.find(cqi.m_rnti)->second;
862
863 if (cqi.m_cqiType == DlCqiInfo::WB)
864 {
865 m_cqiManagement.DlWBCQIReported(cqi, ue, expirationTime, m_maxDlMcs);
866 }
867 else
868 {
869 m_cqiManagement.DlSBCQIReported(cqi, ue);
870 }
871 }
872}
873
887void
890{
891 NS_LOG_FUNCTION(this);
892
893 if (m_fixedMcsUl)
894 {
895 return;
896 }
897
898 GetSecond UeInfoOf;
899
900 uint32_t expirationTime =
901 static_cast<uint32_t>(m_cqiTimersThreshold.GetNanoSeconds() /
902 m_macSchedSapUser->GetSlotPeriod().GetNanoSeconds());
903
904 switch (params.m_ulCqi.m_type)
905 {
906 case UlCqiInfo::PUSCH: {
907 [[maybe_unused]] bool found = false;
908 uint8_t symStart = params.m_symStart;
909 SfnSf ulSfnSf = params.m_sfnSf;
910
911 NS_LOG_INFO("CQI for allocation: " << params.m_sfnSf << " started at sym: " << +symStart
912 << " modified allocation " << ulSfnSf << " sym Start "
913 << static_cast<uint32_t>(symStart));
914
915 auto itAlloc = m_ulAllocationMap.find(ulSfnSf.GetEncoding());
916 NS_ASSERT_MSG(itAlloc != m_ulAllocationMap.end(), "Can't find allocation for " << ulSfnSf);
917 std::vector<AllocElem>& ulAllocations = itAlloc->second.m_ulAllocations;
918
919 for (auto it = ulAllocations.cbegin(); it != ulAllocations.cend(); /* NO INC */)
920 {
921 const AllocElem& allocation = *(it);
922 if (allocation.m_symStart == symStart)
923 {
924 auto itUe = m_ueMap.find(allocation.m_rnti);
925 NS_ASSERT(itUe != m_ueMap.end());
926 NS_ASSERT(allocation.m_numSym > 0);
927 NS_ASSERT(allocation.m_tbs > 0);
928
929 m_cqiManagement.UlSBCQIReported(expirationTime,
930 allocation.m_tbs,
931 params,
932 UeInfoOf(*itUe),
933 allocation.m_rbgMask,
936 found = true;
937 it = ulAllocations.erase(it);
938 }
939 else
940 {
941 ++it;
942 }
943 }
944 NS_ASSERT(found);
945
946 if (ulAllocations.empty())
947 {
948 // remove obsolete info on allocation; we already processed all the CQI
949 NS_LOG_INFO("Removing allocation for " << ulSfnSf);
950 m_ulAllocationMap.erase(itAlloc);
951 }
952 }
953 break;
954 default:
955 NS_FATAL_ERROR("Unknown type of UL-CQI");
956 }
957}
958
972template <typename T>
973std::vector<T>
974NrMacSchedulerNs3::MergeHARQ(std::vector<T>* existingFeedbacks,
975 const std::vector<T>& inFeedbacks,
976 const std::string& mode) const
977{
978 NS_LOG_FUNCTION(this);
979 NS_LOG_INFO("To retransmit : " << existingFeedbacks->size() << " " << mode << " HARQ, received "
980 << inFeedbacks.size() << " " << mode << " HARQ Feedback");
981 uint64_t existingSize = existingFeedbacks->size();
982 uint64_t inSize = inFeedbacks.size();
983 existingFeedbacks->insert(existingFeedbacks->end(), inFeedbacks.begin(), inFeedbacks.end());
984 NS_ASSERT(existingFeedbacks->size() == existingSize + inSize);
985
986 auto ret = std::vector<T>(std::make_move_iterator(existingFeedbacks->begin()),
987 std::make_move_iterator(existingFeedbacks->end()));
988 existingFeedbacks->clear();
989
990 return ret;
991}
992
1010template <typename T>
1011void
1012NrMacSchedulerNs3::ProcessHARQFeedbacks(
1013 std::vector<T>* harqInfo,
1014 const NrMacSchedulerUeInfo::GetHarqVectorFn& GetHarqVectorFn,
1015 const std::string& direction) const
1016{
1017 NS_LOG_FUNCTION(this);
1018 uint32_t nackReceived = 0;
1019
1020 // Check the HARQ feedback, erase ACKed, updated NACKed
1021 for (auto harqFeedbackIt = harqInfo->begin(); harqFeedbackIt != harqInfo->end();
1022 /* nothing as increment */)
1023 {
1024 uint8_t harqId = harqFeedbackIt->m_harqProcessId;
1025 uint16_t rnti = harqFeedbackIt->m_rnti;
1026 NrMacHarqVector& ueHarqVector = GetHarqVectorFn(m_ueMap.find(rnti)->second);
1027 HarqProcess& ueProcess = ueHarqVector.Get(harqId);
1028
1029 NS_LOG_INFO("Evaluating feedback: " << *harqFeedbackIt);
1030 if (!ueProcess.m_active)
1031 {
1032 NS_LOG_INFO("UE " << rnti << " HARQ vector: " << ueHarqVector);
1033 NS_FATAL_ERROR("Received feedback for a process which is not active");
1034 }
1035 NS_ABORT_IF(ueProcess.m_dciElement == nullptr);
1036
1037 // RV number should not be greater than 3
1038 NS_ASSERT(ueProcess.m_dciElement->m_rv < 4);
1039 uint8_t maxHarqReTx = m_enableHarqReTx ? 3 : 0;
1040
1041 if (harqFeedbackIt->IsReceivedOk() || ueProcess.m_dciElement->m_rv == maxHarqReTx)
1042 {
1043 ueHarqVector.Erase(harqId);
1044 harqFeedbackIt = harqInfo->erase(harqFeedbackIt);
1045 NS_LOG_INFO("Erased processID " << static_cast<uint32_t>(harqId) << " of UE " << rnti
1046 << " direction " << direction);
1047 }
1048 else if (!harqFeedbackIt->IsReceivedOk())
1049 {
1050 ueProcess.m_status = HarqProcess::RECEIVED_FEEDBACK;
1051 nackReceived++;
1052 ++harqFeedbackIt;
1053 NS_LOG_INFO("NACK received for UE " << static_cast<uint32_t>(rnti) << " process "
1054 << static_cast<uint32_t>(harqId) << " direction "
1055 << direction);
1056 }
1057 }
1058
1059 NS_ASSERT(harqInfo->size() == nackReceived);
1060}
1061
1073void
1074NrMacSchedulerNs3::ResetExpiredHARQ(uint16_t rnti, NrMacHarqVector* harq)
1075{
1076 NS_LOG_FUNCTION(this << harq);
1077
1078 for (auto harqIt = harq->Begin(); harqIt != harq->End(); ++harqIt)
1079 {
1080 HarqProcess& process = harqIt->second;
1081 uint8_t processId = harqIt->first;
1082
1083 if (process.m_status == HarqProcess::INACTIVE)
1084 {
1085 continue;
1086 }
1087
1088 if (process.m_timer < m_macSchedSapUser->GetNumHarqProcess())
1089 {
1090 ++process.m_timer;
1091 NS_LOG_INFO("Updated process for UE " << rnti << " number "
1092 << static_cast<uint32_t>(processId)
1093 << ", resulting process: " << process);
1094 }
1095 else
1096 {
1097 harq->Erase(processId);
1098 NS_LOG_INFO("Erased process for UE " << rnti << " number "
1099 << static_cast<uint32_t>(processId)
1100 << " for time limits");
1101 }
1102 }
1103}
1104
1113uint8_t
1114NrMacSchedulerNs3::PrependCtrlSym(uint8_t symStart,
1115 uint8_t numSymToAllocate,
1117 std::deque<VarTtiAllocInfo>* allocations) const
1118{
1119 std::vector<uint8_t> rbgBitmask(GetBandwidthInRbg(), 1);
1120
1121 NS_ASSERT_MSG(rbgBitmask.size() == GetBandwidthInRbg(),
1122 "bitmask size " << rbgBitmask.size() << " conf " << GetBandwidthInRbg());
1123 if (mode == DciInfoElementTdma::DL)
1124 {
1125 NS_ASSERT(allocations->empty()); // no previous allocations
1126 NS_ASSERT(symStart == 0); // start from the symbol 0
1127 }
1128
1129 for (uint8_t sym = symStart; sym < symStart + numSymToAllocate; ++sym)
1130 {
1131 allocations->emplace_front(std::make_shared<DciInfoElementTdma>(sym,
1132 1,
1133 mode,
1135 rbgBitmask));
1136 NS_LOG_INFO("Allocating CTRL symbol, type"
1137 << mode << " in TDMA. numSym=1, symStart=" << static_cast<uint32_t>(sym)
1138 << " Remaining CTRL sym to allocate: " << sym - symStart);
1139 }
1140 return symStart + numSymToAllocate;
1141}
1142
1151uint8_t
1152NrMacSchedulerNs3::AppendCtrlSym(uint8_t symStart,
1153 uint8_t numSymToAllocate,
1155 std::deque<VarTtiAllocInfo>* allocations) const
1156{
1157 std::vector<uint8_t> rbgBitmask(GetBandwidthInRbg(), 1);
1158
1159 NS_ASSERT(rbgBitmask.size() == GetBandwidthInRbg());
1160 if (mode == DciInfoElementTdma::DL)
1161 {
1162 NS_ASSERT(allocations->empty()); // no previous allocations
1163 NS_ASSERT(symStart == 0); // start from the symbol 0
1164 }
1165
1166 for (uint8_t sym = symStart; sym < symStart + numSymToAllocate; ++sym)
1167 {
1168 allocations->emplace_back(std::make_shared<DciInfoElementTdma>(sym,
1169 1,
1170 mode,
1172 rbgBitmask));
1173 NS_LOG_INFO("Allocating CTRL symbol, type"
1174 << mode << " in TDMA. numSym=1, symStart=" << static_cast<uint32_t>(sym)
1175 << " Remaining CTRL sym to allocate: " << sym - symStart);
1176 }
1177 return symStart + numSymToAllocate;
1178}
1179
1190void
1191NrMacSchedulerNs3::ComputeActiveHarq(ActiveHarqMap* activeDlHarq,
1192 const std::vector<DlHarqInfo>& dlHarqFeedback) const
1193{
1194 NS_LOG_FUNCTION(this);
1195 NS_ASSERT(activeDlHarq->empty());
1196
1197 for (const auto& feedback : dlHarqFeedback)
1198 {
1199 uint16_t rnti = feedback.m_rnti;
1200 auto& schedInfo = m_ueMap.find(rnti)->second;
1201 auto beamIterator = activeDlHarq->find(schedInfo->m_beamId);
1202
1203 if (beamIterator == activeDlHarq->end())
1204 {
1205 std::vector<NrMacHarqVector::iterator> harqVector;
1206 NS_ASSERT(schedInfo->m_dlHarq.Find(feedback.m_harqProcessId)->second.m_active);
1207
1208 harqVector.emplace_back(schedInfo->m_dlHarq.Find(feedback.m_harqProcessId));
1209 activeDlHarq->emplace(std::make_pair(schedInfo->m_beamId, harqVector));
1210 }
1211 else
1212 {
1213 NS_ASSERT(schedInfo->m_dlHarq.Find(feedback.m_harqProcessId)->second.m_active);
1214 beamIterator->second.emplace_back(schedInfo->m_dlHarq.Find(feedback.m_harqProcessId));
1215 }
1216 NS_LOG_INFO("Received feedback for UE " << rnti << " ID "
1217 << static_cast<uint32_t>(feedback.m_harqProcessId)
1218 << " marked as active");
1219 NS_ASSERT(schedInfo->m_dlHarq.Find(feedback.m_harqProcessId)->second.m_status ==
1221 }
1222
1223 SortDlHarq(activeDlHarq);
1224}
1225
1236void
1237NrMacSchedulerNs3::ComputeActiveHarq(ActiveHarqMap* activeUlHarq,
1238 const std::vector<UlHarqInfo>& ulHarqFeedback) const
1239{
1240 NS_LOG_FUNCTION(this);
1241
1242 for (const auto& feedback : ulHarqFeedback)
1243 {
1244 uint16_t rnti = feedback.m_rnti;
1245 auto& schedInfo = m_ueMap.find(rnti)->second;
1246 auto beamIterator = activeUlHarq->find(schedInfo->m_beamId);
1247
1248 if (beamIterator == activeUlHarq->end())
1249 {
1250 std::vector<NrMacHarqVector::iterator> harqVector;
1251 NS_ASSERT(schedInfo->m_ulHarq.Find(feedback.m_harqProcessId)->second.m_active);
1252 harqVector.emplace_back(schedInfo->m_ulHarq.Find(feedback.m_harqProcessId));
1253 activeUlHarq->emplace(std::make_pair(schedInfo->m_beamId, harqVector));
1254 }
1255 else
1256 {
1257 NS_ASSERT(schedInfo->m_ulHarq.Find(feedback.m_harqProcessId)->second.m_active);
1258 beamIterator->second.emplace_back(schedInfo->m_ulHarq.Find(feedback.m_harqProcessId));
1259 }
1260 }
1261 SortUlHarq(activeUlHarq);
1262}
1263
1276void
1277NrMacSchedulerNs3::ComputeActiveUe(ActiveUeMap* activeUe,
1278 const NrMacSchedulerUeInfo::GetLCGFn& GetLCGFn,
1279 const NrMacSchedulerUeInfo::GetHarqVectorFn& GetHarqVector,
1280 const std::string& mode) const
1281{
1282 NS_LOG_FUNCTION(this);
1283 for (const auto& ueInfo : m_ueMap)
1284 {
1285 uint32_t totBuffer = 0;
1286 const auto& ue = ueInfo.second;
1287
1288 // compute total DL and UL bytes buffered
1289 for (const auto& lcgInfo : GetLCGFn(ue))
1290 {
1291 const auto& lcg = lcgInfo.second;
1292 if (lcg->GetTotalSize() > 0)
1293 {
1294 NS_LOG_INFO("UE " << ue->m_rnti << " " << mode << " LCG "
1295 << static_cast<uint32_t>(lcgInfo.first) << " bytes "
1296 << lcg->GetTotalSize());
1297 }
1298 totBuffer += lcg->GetTotalSize();
1299 }
1300
1301 auto harqV = GetHarqVector(ue);
1302
1303 if (totBuffer > 0 && harqV.CanInsert())
1304 {
1305 auto it = activeUe->find(ue->m_beamId);
1306 if (it == activeUe->end())
1307 {
1308 std::vector<std::pair<std::shared_ptr<NrMacSchedulerUeInfo>, uint32_t>> tmp;
1309 tmp.emplace_back(ue, totBuffer);
1310 activeUe->insert(std::make_pair(ue->m_beamId, tmp));
1311 }
1312 else
1313 {
1314 it->second.emplace_back(ue, totBuffer);
1315 }
1316 }
1317 }
1318}
1319
1351uint8_t
1352NrMacSchedulerNs3::DoScheduleDlData(PointInFTPlane* spoint,
1353 uint32_t symAvail,
1354 const ActiveUeMap& activeDl,
1355 SlotAllocInfo* slotAlloc) const
1356{
1357 NS_LOG_FUNCTION(this << symAvail);
1358 NS_ASSERT(spoint->m_rbg == 0);
1359 BeamSymbolMap symPerBeam = AssignDLRBG(symAvail, activeDl);
1360 GetFirst GetBeam;
1361 uint8_t usedSym = 0;
1362
1363 for (const auto& beam : activeDl)
1364 {
1365 uint32_t availableRBG =
1366 (GetBandwidthInRbg() - spoint->m_rbg) * symPerBeam.at(GetBeam(beam));
1367 bool assigned = false;
1368 std::unordered_set<uint8_t> symbStartDci;
1369 // allocSym is used to count the number of allocated symbols to the UEs of the beam
1370 // we are iterating over
1371 uint32_t allocSym = 0;
1372
1373 NS_LOG_DEBUG(activeDl.size()
1374 << " active DL beam, this beam has " << symPerBeam.at(GetBeam(beam))
1375 << " SYM, starts from RB " << spoint->m_rbg << " and symbol "
1376 << static_cast<uint32_t>(spoint->m_sym) << " for a total of " << availableRBG
1377 << " RBG. In one symbol we have " << GetBandwidthInRbg() << " RBG.");
1378
1379 if (symPerBeam.at(GetBeam(beam)) == 0)
1380 {
1381 NS_LOG_INFO("No available symbols for this beam, continue");
1382 continue;
1383 }
1384
1385 for (const auto& ue : beam.second)
1386 {
1387 if (ue.first->m_dlRBG == 0)
1388 {
1389 NS_LOG_INFO("UE " << ue.first->m_rnti << " does not have RBG assigned");
1390 continue;
1391 }
1392
1393 std::shared_ptr<DciInfoElementTdma> dci =
1394 CreateDlDci(spoint, ue.first, symPerBeam.at(GetBeam(beam)));
1395 if (dci == nullptr)
1396 {
1397 // By continuing to the next UE means that we are
1398 // wasting a resource assign to this UE. For a TDMA
1399 // scheduler this resource would be one or more
1400 // symbols, and for OFDMA scheduler it would be a
1401 // chunk of time + freq, i.e., one or more
1402 // symbols in time and one or more RBG in freq.
1403 // TODO To avoid this, a more accurate solution
1404 // is needed to assign resources. That is, a solution
1405 // that would not assign resources to a UE if the assigned resources
1406 // result a TB size of less than 7 bytes (3 mac header, 2 rlc header, 2 data).
1407 // Because if this happens CreateDlDci will not create DCI.
1408 NS_LOG_DEBUG("No DCI has been created, ignoring");
1409 ue.first->ResetDlMetric();
1410 continue;
1411 }
1412
1413 assigned = true;
1414
1415 if (symbStartDci.insert(dci->m_symStart).second)
1416 {
1417 allocSym += dci->m_numSym;
1418 }
1419
1420 NS_LOG_INFO("UE " << ue.first->m_rnti << " has " << ue.first->m_dlRBG
1421 << " RBG assigned");
1422 NS_ASSERT_MSG(dci->m_symStart + dci->m_numSym <= m_macSchedSapUser->GetSymbolsPerSlot(),
1423 "symStart: "
1424 << static_cast<uint32_t>(dci->m_symStart)
1425 << " symEnd: " << static_cast<uint32_t>(dci->m_numSym) << " symbols: "
1426 << static_cast<uint32_t>(m_macSchedSapUser->GetSymbolsPerSlot()));
1427
1428 HarqProcess harqProcess(true, HarqProcess::WAITING_FEEDBACK, 0, dci);
1429 uint8_t id;
1430
1431 if (!ue.first->m_dlHarq.CanInsert())
1432 {
1433 NS_LOG_INFO("Harq Vector condition for UE " << ue.first->m_rnti << std::endl
1434 << ue.first->m_dlHarq);
1435 NS_FATAL_ERROR("UE " << ue.first->m_rnti << " does not have DL HARQ space");
1436 }
1437
1438 ue.first->m_dlHarq.Insert(&id, harqProcess);
1439 ue.first->m_dlHarq.Get(id).m_dciElement->m_harqProcess = id;
1440
1441 // distribute tbsize among the LCs of the UE
1442 // distributedBytes size is equal to the number of LCs
1443 auto distributedBytes =
1444 m_schedLc->AssignBytesToDlLC(ue.first->m_dlLCG,
1445 dci->m_tbSize,
1447
1448 std::vector<std::vector<NrMacSchedulerLcAlgorithm::Assignation>> bytesPerLc(
1449 distributedBytes.size());
1450
1451 for (std::size_t numLc = 0; numLc < distributedBytes.size(); numLc++)
1452 {
1453 bytesPerLc.at(numLc).emplace_back(distributedBytes.at(numLc).m_lcg,
1454 distributedBytes.at(numLc).m_lcId,
1455 distributedBytes.at(numLc).m_bytes);
1456 }
1457
1458 VarTtiAllocInfo slotInfo(dci);
1459
1460 NS_LOG_INFO("Assigned process ID " << static_cast<uint32_t>(dci->m_harqProcess)
1461 << " to UE " << ue.first->m_rnti);
1462 NS_LOG_DEBUG(" UE" << dci->m_rnti << " gets DL symbols "
1463 << static_cast<uint32_t>(dci->m_symStart) << "-"
1464 << static_cast<uint32_t>(dci->m_symStart + dci->m_numSym) << " tbs "
1465 << dci->m_tbSize << " mcs " << static_cast<uint32_t>(dci->m_mcs)
1466 << " harqId " << static_cast<uint32_t>(id) << " rv "
1467 << static_cast<uint32_t>(dci->m_rv));
1468
1469 for (const auto& byteDistribution : distributedBytes)
1470 {
1471 NS_ASSERT(byteDistribution.m_bytes >= 3);
1472 uint8_t lcId = byteDistribution.m_lcId;
1473 uint8_t lcgId = byteDistribution.m_lcg;
1474 uint32_t bytes = byteDistribution.m_bytes - 3; // Consider the subPdu overhead
1475
1476 RlcPduInfo newRlcPdu(lcId, bytes);
1477 HarqProcess& process = ue.first->m_dlHarq.Get(dci->m_harqProcess);
1478
1479 slotInfo.m_rlcPduInfo.push_back(newRlcPdu);
1480 process.m_rlcPduInfo.push_back(newRlcPdu);
1481
1482 ue.first->m_dlLCG.at(lcgId)->AssignedData(lcId, bytes, "DL");
1483
1484 NS_LOG_DEBUG("DL LCG " << static_cast<uint32_t>(lcgId) << " LCID "
1485 << static_cast<uint32_t>(lcId) << " got bytes "
1486 << newRlcPdu.m_size);
1487 }
1488
1489 NS_ABORT_IF(slotInfo.m_rlcPduInfo.empty());
1490
1491 slotAlloc->m_varTtiAllocInfo.emplace_back(slotInfo);
1492 }
1493 if (assigned)
1494 {
1495 ChangeDlBeam(spoint, symPerBeam.at(GetBeam(beam)));
1496 usedSym += allocSym;
1497 slotAlloc->m_numSymAlloc += allocSym;
1498 }
1499 }
1500
1501 for (auto& beam : activeDl)
1502 {
1503 for (auto& ue : beam.second)
1504 {
1505 ue.first->ResetDlSchedInfo();
1506 }
1507 }
1508
1509 NS_ASSERT(spoint->m_rbg == 0);
1510
1511 return usedSym;
1512}
1513
1549uint8_t
1550NrMacSchedulerNs3::DoScheduleUlData(PointInFTPlane* spoint,
1551 uint32_t symAvail,
1552 const ActiveUeMap& activeUl,
1553 SlotAllocInfo* slotAlloc) const
1554{
1555 NS_LOG_FUNCTION(this);
1556 NS_ASSERT(symAvail > 0 && !activeUl.empty());
1557 NS_ASSERT(spoint->m_rbg == 0);
1558
1559 BeamSymbolMap symPerBeam = AssignULRBG(symAvail, activeUl);
1560 uint8_t usedSym = 0;
1561 GetFirst GetBeam;
1562
1563 for (const auto& beam : activeUl)
1564 {
1565 uint32_t availableRBG =
1566 (GetBandwidthInRbg() - spoint->m_rbg) * symPerBeam.at(GetBeam(beam));
1567 bool assigned = false;
1568 std::unordered_set<uint8_t> symbStartDci;
1569 // allocSym is used to count the number of allocated symbols to the UEs of the beam
1570 // we are iterating over
1571 uint32_t allocSym = 0;
1572
1573 NS_LOG_DEBUG(activeUl.size()
1574 << " active UL beam, this beam has " << symPerBeam.at(GetBeam(beam))
1575 << " SYM, starts from RBG " << spoint->m_rbg << " and symbol "
1576 << static_cast<uint32_t>(spoint->m_sym) << " (going backward) for a total of "
1577 << availableRBG << " RBG. In one symbol we have " << GetBandwidthInRbg()
1578 << " RBG.");
1579
1580 if (symPerBeam.at(GetBeam(beam)) == 0)
1581 {
1582 NS_LOG_INFO("No available symbols for this beam, continue");
1583 continue;
1584 }
1585
1586 for (const auto& ue : beam.second)
1587 {
1588 if (ue.first->m_ulRBG == 0)
1589 {
1590 NS_LOG_INFO("UE " << ue.first->m_rnti << " does not have RBG assigned");
1591 continue;
1592 }
1593
1594 std::shared_ptr<DciInfoElementTdma> dci =
1595 CreateUlDci(spoint, ue.first, symPerBeam.at(GetBeam(beam)));
1596
1597 if (dci == nullptr)
1598 {
1599 // By continuing to the next UE means that we are
1600 // wasting a resource assign to this UE. For a TDMA
1601 // scheduler this resource would be one or more
1602 // symbols, and for OFDMA scheduler it would be a
1603 // chunk of time + freq, i.e., one or more
1604 // symbols in time and one or more RBG in freq.
1605 // TODO To avoid this, a more accurate solution
1606 // is needed to assign resources. That is, a solution
1607 // that would not assign resources to a UE if the assigned resources
1608 // result a TB size of less than 7 bytes (3 mac header, 2 rlc header, 2
1609 // data). Because if this happens CreateUlDci will not create DCI.
1610 NS_LOG_DEBUG("No DCI has been created, ignoring");
1611 ue.first->ResetUlMetric();
1612 continue;
1613 }
1614
1615 assigned = true;
1616
1617 if (symbStartDci.insert(dci->m_symStart).second)
1618 {
1619 allocSym += dci->m_numSym;
1620 }
1621
1622 if (!ue.first->m_ulHarq.CanInsert())
1623 {
1624 NS_LOG_INFO("Harq Vector condition for UE " << ue.first->m_rnti << std::endl
1625 << ue.first->m_ulHarq);
1626 NS_FATAL_ERROR("UE " << ue.first->m_rnti << " does not have UL HARQ space");
1627 }
1628
1629 HarqProcess harqProcess(true, HarqProcess::WAITING_FEEDBACK, 0, dci);
1630 uint8_t id;
1631 ue.first->m_ulHarq.Insert(&id, harqProcess);
1632
1633 ue.first->m_ulHarq.Get(id).m_dciElement->m_harqProcess = id;
1634
1635 VarTtiAllocInfo slotInfo(dci);
1636
1637 NS_LOG_INFO("Assigned process ID " << static_cast<uint32_t>(dci->m_harqProcess)
1638 << " to UE " << ue.first->m_rnti);
1639 NS_LOG_DEBUG(" UE" << dci->m_rnti << " gets UL symbols "
1640 << static_cast<uint32_t>(dci->m_symStart) << "-"
1641 << static_cast<uint32_t>(dci->m_symStart + dci->m_numSym) << " tbs "
1642 << dci->m_tbSize << " mcs " << static_cast<uint32_t>(dci->m_mcs)
1643 << " harqId " << static_cast<uint32_t>(id) << " rv "
1644 << static_cast<uint32_t>(dci->m_rv));
1645
1646 auto distributedBytes = m_schedLc->AssignBytesToUlLC(ue.first->m_ulLCG, dci->m_tbSize);
1647 bool assignedToLC = false;
1648 for (const auto& byteDistribution : distributedBytes)
1649 {
1650 assignedToLC = true;
1651 ue.first->m_ulLCG.at(byteDistribution.m_lcg)
1652 ->AssignedData(byteDistribution.m_lcId, byteDistribution.m_bytes, "UL");
1653 NS_LOG_DEBUG("UL LCG " << static_cast<uint32_t>(byteDistribution.m_lcg)
1654 << " assigned bytes " << byteDistribution.m_bytes
1655 << " to LCID "
1656 << static_cast<uint32_t>(byteDistribution.m_lcId));
1657 }
1658 NS_ASSERT(assignedToLC);
1659 slotAlloc->m_varTtiAllocInfo.emplace_front(slotInfo);
1660 }
1661 if (assigned)
1662 {
1663 ChangeUlBeam(spoint, symPerBeam.at(GetBeam(beam)));
1664 usedSym += allocSym;
1665 slotAlloc->m_numSymAlloc += allocSym;
1666 }
1667 }
1668
1669 for (auto& beam : activeUl)
1670 {
1671 for (auto& ue : beam.second)
1672 {
1673 ue.first->ResetUlSchedInfo();
1674 }
1675 }
1676
1677 NS_ASSERT(spoint->m_rbg == 0);
1678
1679 return usedSym;
1680}
1681
1693void
1694NrMacSchedulerNs3::DoScheduleUlSr(PointInFTPlane* spoint, const std::list<uint16_t>& rntiList) const
1695{
1696 NS_LOG_FUNCTION(this);
1697 NS_ASSERT(spoint->m_rbg == 0);
1698
1699 for (const auto& v : rntiList)
1700 {
1701 for (auto& ulLcg : NrMacSchedulerUeInfo::GetUlLCG(m_ueMap.at(v)))
1702 {
1703 NS_LOG_DEBUG("Assigning 12 bytes to UE " << v << " because of a SR");
1704 ulLcg.second->UpdateInfo(12);
1705 }
1706 }
1707}
1708
1747void
1748NrMacSchedulerNs3::ScheduleDl(const NrMacSchedSapProvider::SchedDlTriggerReqParameters& params,
1749 const std::vector<DlHarqInfo>& dlHarqFeedback)
1750{
1751 NS_LOG_FUNCTION(this);
1752 NS_LOG_INFO("Scheduling invoked for slot " << params.m_snfSf << " of type "
1753 << params.m_slotType);
1754
1755 NrMacSchedSapUser::SchedConfigIndParameters dlSlot(params.m_snfSf);
1756 dlSlot.m_slotAllocInfo.m_sfnSf = params.m_snfSf;
1757 dlSlot.m_slotAllocInfo.m_type = SlotAllocInfo::DL;
1758 auto ulAllocationIt =
1759 m_ulAllocationMap.find(params.m_snfSf.GetEncoding()); // UL allocations for this slot
1760 if (ulAllocationIt == m_ulAllocationMap.end())
1761 {
1762 ulAllocationIt =
1763 m_ulAllocationMap.insert(std::make_pair(params.m_snfSf.GetEncoding(), SlotElem(0)))
1764 .first;
1765 }
1766 auto& ulAllocations = ulAllocationIt->second;
1767
1768 // add slot for DL control, at symbol 0
1769 PrependCtrlSym(0,
1770 m_dlCtrlSymbols,
1772 &dlSlot.m_slotAllocInfo.m_varTtiAllocInfo);
1773 dlSlot.m_slotAllocInfo.m_numSymAlloc += m_dlCtrlSymbols;
1774
1775 // In case of S slot, add UL CTRL and update the symbol used count
1776 if (params.m_slotType == LteNrTddSlotType::S)
1777 {
1778 NS_LOG_INFO("S slot, adding UL CTRL");
1779 AppendCtrlSym(static_cast<uint8_t>(m_macSchedSapUser->GetSymbolsPerSlot() - 1),
1780 m_ulCtrlSymbols,
1782 &dlSlot.m_slotAllocInfo.m_varTtiAllocInfo);
1783 ulAllocations.m_totUlSym += m_ulCtrlSymbols;
1784 dlSlot.m_slotAllocInfo.m_numSymAlloc += m_ulCtrlSymbols;
1785 }
1786
1787 // RACH
1788 for (const auto& rachReq : m_rachList)
1789 {
1790 BuildRarListElement_s newRar;
1791 newRar.m_rnti = rachReq.m_rnti;
1792 // newRar.m_ulGrant is not used
1793 dlSlot.m_buildRarList.push_back(newRar);
1794 }
1795 m_rachList.clear();
1796
1797 // compute active ue in the current subframe, group them by BeamId
1798 ActiveHarqMap activeDlHarq;
1799 ComputeActiveHarq(&activeDlHarq, dlHarqFeedback);
1800
1801 ActiveUeMap activeDlUe;
1802 ComputeActiveUe(&activeDlUe,
1805 "DL");
1806
1807 DoScheduleDl(dlHarqFeedback,
1808 activeDlHarq,
1809 &activeDlUe,
1810 params.m_snfSf,
1811 ulAllocations,
1812 &dlSlot.m_slotAllocInfo);
1813
1814 // if the number of allocated symbols is greater than GetUlCtrlSymbols (), then don't
1815 // delete the allocation, as it will be removed when the CQI will be processed.
1816 // Otherwise, delete the allocation history for the slot.
1817 if (ulAllocations.m_totUlSym <= GetUlCtrlSyms())
1818 {
1819 NS_LOG_INFO("Removing UL allocation for slot " << params.m_snfSf << " size "
1820 << m_ulAllocationMap.size());
1821 m_ulAllocationMap.erase(ulAllocationIt);
1822 }
1823
1824 NS_LOG_INFO("Total DCI for DL : " << dlSlot.m_slotAllocInfo.m_varTtiAllocInfo.size()
1825 << " including DL CTRL");
1827}
1828
1865void
1866NrMacSchedulerNs3::ScheduleUl(const NrMacSchedSapProvider::SchedUlTriggerReqParameters& params,
1867 const std::vector<UlHarqInfo>& ulHarqFeedback)
1868{
1869 NS_LOG_FUNCTION(this);
1870 NS_LOG_INFO("Scheduling invoked for slot " << params.m_snfSf);
1871
1872 NrMacSchedSapUser::SchedConfigIndParameters ulSlot(params.m_snfSf);
1873 ulSlot.m_slotAllocInfo.m_sfnSf = params.m_snfSf;
1874 ulSlot.m_slotAllocInfo.m_type = SlotAllocInfo::UL;
1875
1876 // add slot for UL control, at last symbol, for slot type F and UL.
1877 AppendCtrlSym(static_cast<uint8_t>(m_macSchedSapUser->GetSymbolsPerSlot() - 1),
1878 m_ulCtrlSymbols,
1880 &ulSlot.m_slotAllocInfo.m_varTtiAllocInfo);
1881 ulSlot.m_slotAllocInfo.m_numSymAlloc += m_ulCtrlSymbols;
1882
1883 // Doing UL for slot ulSlot
1884 DoScheduleUl(ulHarqFeedback, params.m_snfSf, &ulSlot.m_slotAllocInfo, params.m_slotType);
1885
1886 NS_LOG_INFO("Total DCI for UL : " << ulSlot.m_slotAllocInfo.m_varTtiAllocInfo.size()
1887 << " including UL CTRL");
1889}
1890
1928uint8_t
1929NrMacSchedulerNs3::DoScheduleUl(const std::vector<UlHarqInfo>& ulHarqFeedback,
1930 const SfnSf& ulSfn,
1931 SlotAllocInfo* allocInfo,
1932 LteNrTddSlotType type)
1933{
1934 NS_LOG_FUNCTION(this);
1935
1936 NS_ASSERT(allocInfo->m_varTtiAllocInfo.size() == 1); // Just the UL CTRL
1937
1938 uint8_t dataSymPerSlot = m_macSchedSapUser->GetSymbolsPerSlot() - m_ulCtrlSymbols;
1939 if (type == LteNrTddSlotType::F)
1940 { // if it's a type F, we have to consider DL CTRL symbols, otherwise, don't
1941 dataSymPerSlot -= m_dlCtrlSymbols;
1942 }
1943
1944 ActiveHarqMap activeUlHarq;
1945 ComputeActiveHarq(&activeUlHarq, ulHarqFeedback);
1946
1947 // Start the assignation from the last available data symbol, and like a shrimp
1948 // go backward.
1949 uint8_t lastSym = m_macSchedSapUser->GetSymbolsPerSlot() - m_ulCtrlSymbols;
1950 PointInFTPlane ulAssignationStartPoint(0, lastSym);
1951 uint8_t ulSymAvail = dataSymPerSlot;
1952
1953 // Create the UL allocation map entry
1954 m_ulAllocationMap.emplace(ulSfn.GetEncoding(), SlotElem(0));
1955
1956 if ((m_enableSrsInFSlots && type == LteNrTddSlotType::F) ||
1957 (m_enableSrsInUlSlots && type == LteNrTddSlotType::UL))
1958 { // SRS are included in F slots, and in UL slots if m_enableSrsInUlSlots=true
1959 m_srsSlotCounter++; // It's an uint, don't worry about wrap around
1960 NS_ASSERT(m_srsCtrlSymbols <= ulSymAvail);
1961 uint8_t srsSym = DoScheduleSrs(&ulAssignationStartPoint, allocInfo);
1962 ulSymAvail -= srsSym;
1963 }
1964
1965 NS_LOG_DEBUG("Scheduling UL " << ulSfn << " UL HARQ to retransmit: " << ulHarqFeedback.size()
1966 << " Active Beams UL HARQ: " << activeUlHarq.size()
1967 << " starting from (" << +ulAssignationStartPoint.m_rbg << ", "
1968 << +ulAssignationStartPoint.m_sym << ")");
1969
1970 if (!activeUlHarq.empty())
1971 {
1972 uint8_t usedHarq = ScheduleUlHarq(&ulAssignationStartPoint,
1973 ulSymAvail,
1974 m_ueMap,
1975 &m_ulHarqToRetransmit,
1976 ulHarqFeedback,
1977 allocInfo);
1978 NS_ASSERT_MSG(ulSymAvail >= usedHarq,
1979 "Available: " << +ulSymAvail << " used by HARQ: " << +usedHarq);
1980 NS_LOG_INFO("For the slot " << ulSfn << " reserved " << static_cast<uint32_t>(usedHarq)
1981 << " symbols for UL HARQ retx");
1982 ulSymAvail -= usedHarq;
1983 }
1984
1985 NS_ASSERT(ulAssignationStartPoint.m_rbg == 0);
1986
1987 if (ulSymAvail > 0 && !m_srList.empty())
1988 {
1989 DoScheduleUlSr(&ulAssignationStartPoint, m_srList);
1990 m_srList.clear();
1991 }
1992
1993 ActiveUeMap activeUlUe;
1994 ComputeActiveUe(&activeUlUe,
1997 "UL");
1998
1999 GetSecond GetUeInfoList;
2000 for (const auto& alloc : allocInfo->m_varTtiAllocInfo)
2001 {
2002 for (auto it = activeUlUe.begin(); it != activeUlUe.end(); /* no incr */)
2003 {
2004 auto& ueInfos = GetUeInfoList(*it);
2005 for (auto ueIt = ueInfos.begin(); ueIt != ueInfos.end(); /* no incr */)
2006 {
2007 GetFirst GetUeInfoPtr;
2008 if (GetUeInfoPtr(*ueIt)->m_rnti == alloc.m_dci->m_rnti)
2009 {
2010 NS_LOG_INFO("Removed RNTI " << alloc.m_dci->m_rnti
2011 << " from active ue list "
2012 "because it has already an HARQ scheduled");
2013 ueInfos.erase(ueIt);
2014 break;
2015 }
2016 else
2017 {
2018 ++ueIt;
2019 }
2020 }
2021 if (!ueInfos.empty())
2022 {
2023 ++it;
2024 }
2025 else
2026 {
2027 activeUlUe.erase(it);
2028 break;
2029 }
2030 }
2031 }
2032
2033 if (ulSymAvail > 0 && !activeUlUe.empty())
2034 {
2035 uint8_t usedUl =
2036 DoScheduleUlData(&ulAssignationStartPoint, ulSymAvail, activeUlUe, allocInfo);
2037 NS_LOG_INFO("For the slot " << ulSfn << " reserved " << static_cast<uint32_t>(usedUl)
2038 << " symbols for UL data tx");
2039 ulSymAvail -= usedUl;
2040 }
2041
2042 std::vector<uint32_t> symToAl;
2043 symToAl.resize(15, 0);
2044
2045 auto& totUlSym = m_ulAllocationMap.at(ulSfn.GetEncoding()).m_totUlSym;
2046 auto& allocations = m_ulAllocationMap.at(ulSfn.GetEncoding()).m_ulAllocations;
2047 for (const auto& alloc : allocInfo->m_varTtiAllocInfo)
2048 {
2049 if (alloc.m_dci->m_format == DciInfoElementTdma::UL)
2050 {
2051 // Here we are assuming (with the assignment) that all the
2052 // allocations starting at a particular symbol will have the same
2053 // length.
2054 symToAl[alloc.m_dci->m_symStart] = alloc.m_dci->m_numSym;
2055 NS_LOG_INFO("UL Allocation. RNTI " << alloc.m_dci->m_rnti << ", symStart "
2056 << static_cast<uint32_t>(alloc.m_dci->m_symStart)
2057 << " numSym " << +alloc.m_dci->m_numSym);
2058
2059 if (alloc.m_dci->m_type == DciInfoElementTdma::DATA)
2060 {
2061 NS_LOG_INFO("Placed the above allocation in the CQI map");
2062 allocations.emplace_back(alloc.m_dci->m_rnti,
2063 alloc.m_dci->m_tbSize,
2064 alloc.m_dci->m_symStart,
2065 alloc.m_dci->m_numSym,
2066 alloc.m_dci->m_mcs,
2067 alloc.m_dci->m_rank,
2068 alloc.m_dci->m_rbgBitmask);
2069 }
2070 }
2071 }
2072
2073 for (const auto& v : symToAl)
2074 {
2075 totUlSym += v;
2076 }
2077
2078 NS_ASSERT_MSG((dataSymPerSlot + m_ulCtrlSymbols) - ulSymAvail == totUlSym,
2079 "UL symbols available: "
2080 << static_cast<uint32_t>(dataSymPerSlot + m_ulCtrlSymbols)
2081 << " UL symbols available at end of sched: "
2082 << static_cast<uint32_t>(ulSymAvail)
2083 << " total of symbols registered in the allocation: "
2084 << static_cast<uint32_t>(totUlSym) << " slot type " << type);
2085
2086 NS_LOG_INFO("For the slot " << ulSfn << " registered a total of "
2087 << static_cast<uint32_t>(totUlSym) << " symbols and "
2088 << allocations.size() << " data allocations, with a total of "
2089 << allocInfo->m_varTtiAllocInfo.size());
2090 NS_ASSERT(m_ulAllocationMap.at(ulSfn.GetEncoding()).m_totUlSym == totUlSym);
2091
2092 return dataSymPerSlot - ulSymAvail;
2093}
2094
2095uint8_t
2096NrMacSchedulerNs3::DoScheduleSrs(PointInFTPlane* spoint, SlotAllocInfo* allocInfo)
2097{
2098 NS_LOG_FUNCTION(this);
2099
2100 uint8_t used = 0;
2101
2102 // Without UE, don't schedule any SRS
2103 if (m_ueMap.empty())
2104 {
2105 return used;
2106 }
2107
2108 // Find the UE for which this is true:
2109 // absolute_slot_number % periodicity = offset_UEx
2110 // Assuming that all UEs share the same periodicity.
2111
2112 uint32_t offset_UEx = m_srsSlotCounter % m_ueMap.begin()->second->m_srsPeriodicity;
2113 uint16_t rnti = 0;
2114
2115 for (const auto& ue : m_ueMap)
2116 {
2117 if (ue.second->m_srsOffset == offset_UEx)
2118 {
2119 rnti = ue.second->m_rnti;
2120 }
2121 }
2122
2123 if (rnti == 0)
2124 {
2125 return used; // No SRS in this slot!
2126 }
2127
2128 // Schedule 4 allocation, of 1 symbol each, in TDMA mode, for the RNTI found.
2129
2130 for (uint32_t i = 0; i < m_srsCtrlSymbols; ++i)
2131 {
2132 std::vector<uint8_t> rbgAssigned(GetBandwidthInRbg(), 1);
2133
2134 NS_LOG_INFO("UE " << rnti << " assigned symbol " << +spoint->m_sym << " for SRS tx");
2135
2136 std::vector<uint8_t> rbgBitmask(GetBandwidthInRbg(), 1);
2137
2138 spoint->m_sym--;
2139
2140 uint8_t numSym{1};
2141 uint8_t mcs{0};
2142 uint8_t rank{1};
2143 Ptr<const ComplexMatrixArray> precMats{nullptr};
2144 uint32_t tbs{0};
2145 uint8_t ndi{1};
2146 uint8_t rv{0};
2147 auto dci = std::make_shared<DciInfoElementTdma>(rnti,
2149 spoint->m_sym,
2150 numSym,
2151 mcs,
2152 rank,
2153 precMats,
2154 tbs,
2155 ndi,
2156 rv,
2158 GetBwpId(),
2159 GetTpc());
2160 dci->m_rbgBitmask = rbgBitmask;
2161
2162 allocInfo->m_numSymAlloc += 1;
2163 allocInfo->m_varTtiAllocInfo.emplace_front(dci);
2164
2165 used++;
2166 }
2167
2168 return used;
2169}
2170
2171uint16_t
2173{
2175 {
2176 return m_macSchedSapUser->GetBwpId();
2177 }
2178 else
2179 {
2180 return UINT16_MAX;
2181 }
2182}
2183
2184uint16_t
2186{
2188 {
2189 return m_macSchedSapUser->GetCellId();
2190 }
2191 else
2192 {
2193 return UINT16_MAX;
2194 }
2195}
2196
2197uint16_t
2199{
2200 return m_bandwidth;
2201}
2202
2222uint8_t
2223NrMacSchedulerNs3::DoScheduleDl(const std::vector<DlHarqInfo>& dlHarqFeedback,
2224 const ActiveHarqMap& activeDlHarq,
2225 ActiveUeMap* activeDlUe,
2226 const SfnSf& dlSfnSf,
2227 const SlotElem& ulAllocations,
2228 SlotAllocInfo* allocInfo)
2229{
2230 NS_LOG_FUNCTION(this);
2231 NS_ASSERT(activeDlUe != nullptr);
2232
2233 uint8_t dataSymPerSlot = m_macSchedSapUser->GetSymbolsPerSlot() - m_dlCtrlSymbols;
2234
2235 uint8_t dlSymAvail = dataSymPerSlot - ulAllocations.m_totUlSym;
2236 PointInFTPlane dlAssignationStartPoint(0, m_dlCtrlSymbols);
2237
2238 NS_LOG_DEBUG("Scheduling DL for slot "
2239 << dlSfnSf << " DL HARQ to retransmit: " << dlHarqFeedback.size()
2240 << " Active Beams DL HARQ: " << activeDlHarq.size()
2241 << " sym available: " << static_cast<uint32_t>(dlSymAvail) << " starting from sym "
2242 << static_cast<uint32_t>(m_dlCtrlSymbols));
2243
2244 if (!activeDlHarq.empty())
2245 {
2246 uint8_t usedHarq = ScheduleDlHarq(&dlAssignationStartPoint,
2247 dlSymAvail,
2248 activeDlHarq,
2249 m_ueMap,
2250 &m_dlHarqToRetransmit,
2251 dlHarqFeedback,
2252 allocInfo);
2253 NS_ASSERT(dlSymAvail >= usedHarq);
2254 dlSymAvail -= usedHarq;
2255 }
2256
2257 GetSecond GetUeInfoList;
2258
2259 for (const auto& alloc : allocInfo->m_varTtiAllocInfo)
2260 {
2261 for (auto it = activeDlUe->begin(); it != activeDlUe->end(); /* no incr */)
2262 {
2263 auto& ueInfos = GetUeInfoList(*it);
2264 for (auto ueIt = ueInfos.begin(); ueIt != ueInfos.end(); /* no incr */)
2265 {
2266 GetFirst GetUeInfoPtr;
2267 if (GetUeInfoPtr(*ueIt)->m_rnti == alloc.m_dci->m_rnti)
2268 {
2269 NS_LOG_INFO("Removed RNTI " << alloc.m_dci->m_rnti
2270 << " from active ue list "
2271 "because it has already an HARQ scheduled");
2272 ueInfos.erase(ueIt);
2273 break;
2274 }
2275 else
2276 {
2277 ++ueIt;
2278 }
2279 }
2280 if (!ueInfos.empty())
2281 {
2282 ++it;
2283 }
2284 else
2285 {
2286 activeDlUe->erase(it);
2287 break;
2288 }
2289 }
2290 }
2291
2292 NS_ASSERT(dlAssignationStartPoint.m_rbg == 0);
2293
2294 if (dlSymAvail > 0 && !activeDlUe->empty())
2295 {
2296 uint8_t usedDl =
2297 DoScheduleDlData(&dlAssignationStartPoint, dlSymAvail, *activeDlUe, allocInfo);
2298 NS_ASSERT(dlSymAvail >= usedDl);
2299 dlSymAvail -= usedDl;
2300 }
2301
2302 return (dataSymPerSlot - ulAllocations.m_totUlSym) - dlSymAvail;
2303}
2304
2315void
2318{
2319 NS_LOG_FUNCTION(this);
2320
2321 // process received CQIs
2322 m_cqiManagement.RefreshDlCqiMaps(m_ueMap);
2323
2324 // reset expired HARQ
2325 for (const auto& itUe : m_ueMap)
2326 {
2327 ResetExpiredHARQ(itUe.second->m_rnti, &itUe.second->m_dlHarq);
2328 }
2329
2330 // Merge not-retransmitted and received feedback
2331 std::vector<DlHarqInfo> dlHarqFeedback;
2332
2333 if (!params.m_dlHarqInfoList.empty() || !m_dlHarqToRetransmit.empty())
2334 {
2335 // m_dlHarqToRetransmit will be cleared inside MergeHARQ
2336 uint64_t existingSize = m_dlHarqToRetransmit.size();
2337 uint64_t inSize = params.m_dlHarqInfoList.size();
2338
2339 dlHarqFeedback = MergeHARQ(&m_dlHarqToRetransmit, params.m_dlHarqInfoList, "DL");
2340
2341 NS_ASSERT(m_dlHarqToRetransmit.empty());
2342 NS_ASSERT_MSG(existingSize + inSize == dlHarqFeedback.size(),
2343 " existing: " << existingSize << " received: " << inSize
2344 << " calculated: " << dlHarqFeedback.size());
2345
2346 std::unordered_map<uint16_t, std::set<uint32_t>> feedbacksDup;
2347
2348 // Let's find out:
2349 // 1) Feedback that arrived late (i.e., their process has been marked inactive
2350 // due to timings
2351 // 2) Duplicated feedbacks (same UE, same process ID). I don't know why
2352 // these are generated.. but anyway..
2353 for (auto it = dlHarqFeedback.begin(); it != dlHarqFeedback.end(); /* no inc */)
2354 {
2355 auto& ueInfo = m_ueMap.find(it->m_rnti)->second;
2356 auto& process = ueInfo->m_dlHarq.Find(it->m_harqProcessId)->second;
2357 NS_LOG_INFO("Analyzing feedback for UE " << it->m_rnti << " process "
2358 << static_cast<uint32_t>(it->m_harqProcessId));
2359 if (!process.m_active)
2360 {
2361 NS_LOG_INFO("Feedback for UE " << it->m_rnti << " process "
2362 << static_cast<uint32_t>(it->m_harqProcessId)
2363 << " ignored because process is INACTIVE");
2364 it = dlHarqFeedback.erase(it); /* INC */
2365 }
2366 else
2367 {
2368 auto itDuplicated = feedbacksDup.find(it->m_rnti);
2369 if (itDuplicated == feedbacksDup.end())
2370 {
2371 feedbacksDup.insert(std::make_pair(it->m_rnti, std::set<uint32_t>()));
2372 feedbacksDup.at(it->m_rnti).insert(it->m_harqProcessId);
2373 ++it; /* INC */
2374 }
2375 else
2376 {
2377 if (itDuplicated->second.find(it->m_harqProcessId) ==
2378 itDuplicated->second.end())
2379 {
2380 itDuplicated->second.insert(it->m_harqProcessId);
2381 ++it; /* INC */
2382 }
2383 else
2384 {
2385 NS_LOG_INFO("Feedback for UE "
2386 << it->m_rnti << " process "
2387 << static_cast<uint32_t>(it->m_harqProcessId)
2388 << " ignored because is a duplicate of another feedback");
2389 it = dlHarqFeedback.erase(it); /* INC */
2390 }
2391 }
2392 }
2393 }
2394
2395 ProcessHARQFeedbacks(&dlHarqFeedback, NrMacSchedulerUeInfo::GetDlHarqVector, "DL");
2396 }
2397
2398 ScheduleDl(params, dlHarqFeedback);
2399}
2400
2411void
2414{
2415 NS_LOG_FUNCTION(this);
2416
2417 // process received CQIs
2418 m_cqiManagement.RefreshUlCqiMaps(m_ueMap);
2419
2420 // reset expired HARQ
2421 for (const auto& itUe : m_ueMap)
2422 {
2423 ResetExpiredHARQ(itUe.second->m_rnti, &itUe.second->m_ulHarq);
2424 }
2425
2426 // Merge not-retransmitted and received feedback
2427 std::vector<UlHarqInfo> ulHarqFeedback;
2428 if (!params.m_ulHarqInfoList.empty() || !m_ulHarqToRetransmit.empty())
2429 {
2430 // m_ulHarqToRetransmit will be cleared inside MergeHARQ
2431 uint64_t existingSize = m_ulHarqToRetransmit.size();
2432 uint64_t inSize = params.m_ulHarqInfoList.size();
2433
2434 ulHarqFeedback = MergeHARQ(&m_ulHarqToRetransmit, params.m_ulHarqInfoList, "UL");
2435
2436 NS_ASSERT(m_ulHarqToRetransmit.empty());
2437 NS_ASSERT_MSG(existingSize + inSize == ulHarqFeedback.size(),
2438 " existing: " << existingSize << " received: " << inSize
2439 << " calculated: " << ulHarqFeedback.size());
2440
2441 // if there are feedbacks for expired process, remove them
2442 for (auto it = ulHarqFeedback.begin(); it != ulHarqFeedback.end(); /* no inc */)
2443 {
2444 auto& ueInfo = m_ueMap.find(it->m_rnti)->second;
2445 auto& process = ueInfo->m_ulHarq.Find(it->m_harqProcessId)->second;
2446 if (!process.m_active)
2447 {
2448 NS_LOG_INFO("Feedback for UE " << it->m_rnti << " process "
2449 << static_cast<uint32_t>(it->m_harqProcessId)
2450 << " ignored because process is INACTIVE");
2451 it = ulHarqFeedback.erase(it);
2452 }
2453 else
2454 {
2455 ++it;
2456 }
2457 }
2458
2459 ProcessHARQFeedbacks(&ulHarqFeedback, NrMacSchedulerUeInfo::GetUlHarqVector, "UL");
2460 }
2461
2462 ScheduleUl(params, ulHarqFeedback);
2463}
2464
2471void
2474{
2475 NS_LOG_FUNCTION(this);
2476
2477 // Merge RNTI in our current list
2478 for (const auto& ue : params.m_srList)
2479 {
2480 NS_LOG_INFO("UE " << ue << " asked for a SR ");
2481
2482 auto it = std::find(m_srList.begin(), m_srList.end(), ue);
2483 if (it == m_srList.end())
2484 {
2485 m_srList.push_back(ue);
2486 }
2487 }
2488 NS_ASSERT(m_srList.size() >= params.m_srList.size());
2489}
2490
2491} // namespace ns3
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 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 UlSBCQIReported(uint32_t expirationTime, uint32_t tbs, const NrMacSchedSapProvider::SchedUlCqiInfoReqParameters &params, const std::shared_ptr< NrMacSchedulerUeInfo > &ueInfo, const std::vector< uint8_t > &rbgMask, uint32_t numRbPerRbg, const Ptr< const SpectrumModel > &model) const
An UL SB CQI has been reported for the specified UE.
void InstallGetBwpIdFn(const std::function< uint16_t()> &fn)
Install a function to retrieve the bwp id.
void DlSBCQIReported(const DlCqiInfo &info, const std::shared_ptr< NrMacSchedulerUeInfo > &ueInfo) const
SB CQI reported.
void DlWBCQIReported(const DlCqiInfo &info, const std::shared_ptr< NrMacSchedulerUeInfo > &ueInfo, uint32_t expirationTime, int8_t maxDlMcs) 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.
void SetSrsInFSlots(bool v)
Set if the F slots are allowed for SRS transmission.
void SetDlNotchedRbgMask(const std::vector< uint8_t > &dlNotchedRbgsMask)
Set the notched (blank) RBGs Mask for the DL.
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...
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.
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...
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.
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.
static TypeId GetTypeId()
GetTypeId.
Time GetCqiTimerThreshold() const
Get the CqiTimerThreshold.
std::vector< uint8_t > GetDlNotchedRbgMask() const
Get the notched (blank) RBGs Mask for the DL.
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.
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 SetUlNotchedRbgMask(const std::vector< uint8_t > &ulNotchedRbgsMask)
Set the notched (blank) RBGs Mask for the UL.
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 DoSchedUlMacCtrlInfoReq(const NrMacSchedSapProvider::SchedUlMacCtrlInfoReqParameters &params) override
Evaluate different types of control messages (only BSR for the moment)
std::vector< uint8_t > GetUlNotchedRbgMask() const
Get the notched (blank) RBGs Mask for the UL.
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.
bool IsDlMcsFixed() const
Check if the MCS in DL is fixed.
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.
virtual LCPtr CreateLC(const LogicalChannelConfigListElement_s &config) const
Create a logical channel starting from a configuration.
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 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.
virtual LCGPtr CreateLCG(const LogicalChannelConfigListElement_s &config) const
Create a logical channel group starting from a configuration.
static std::unordered_map< uint8_t, LCGPtr > & GetUlLCG(const UePtr &ue)
GetUlLCG.
static NrMacHarqVector & GetUlHarqVector(const UePtr &ue)
GetUlHarqVector.
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:34
uint64_t GetEncoding() const
Get encoding for this SfnSf.
Definition sfnsf.cc:26
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.
enum ns3::DlCqiInfo::DlCqiType WB
The type of the CQI.
@ 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 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.
@ UL
UL Allocations.
@ DL
DL Allocations.