5#define NS_LOG_APPEND_CONTEXT \
8 std::clog << " [ CellId " << GetCellId() << ", bwpId " << GetBwpId() << "] "; \
11#include "nr-mac-scheduler-ns3.h"
13#include "nr-mac-scheduler-harq-rr.h"
14#include "nr-mac-scheduler-lc-rr.h"
15#include "nr-mac-scheduler-srs-default.h"
16#include "nr-mac-short-bsr-ce.h"
18#include <ns3/boolean.h>
19#include <ns3/integer.h>
21#include <ns3/pointer.h>
22#include <ns3/uinteger.h>
26#include <unordered_set>
31NS_LOG_COMPONENT_DEFINE(
"NrMacSchedulerNs3");
32NS_OBJECT_ENSURE_REGISTERED(NrMacSchedulerNs3);
37 NS_LOG_FUNCTION_NOARGS();
40 m_schedHarq = std::make_unique<NrMacSchedulerHarqRr>();
47 m_cqiManagement.InstallGetNrAmcDlFn(std::bind([
this]() {
return m_dlAmc; }));
48 m_cqiManagement.InstallGetNrAmcUlFn(std::bind([
this]() {
return m_ulAmc; }));
49 m_cqiManagement.InstallGetStartMcsDlFn(std::bind([
this]() {
return m_startMcsDl; }));
50 m_cqiManagement.InstallGetStartMcsUlFn(std::bind([
this]() {
return m_startMcsUl; }));
53 m_schedulerSrs = CreateObject<NrMacSchedulerSrsDefault>();
78 NS_LOG_FUNCTION(
this);
85 NS_LOG_FUNCTION(
this);
92 NS_LOG_FUNCTION(
this << stream);
93 return m_schedulerSrs->AssignStreams(stream);
100 TypeId(
"ns3::NrMacSchedulerNs3")
102 .AddAttribute(
"CqiTimerThreshold",
103 "The time while a CQI is valid",
104 TimeValue(Seconds(1)),
108 .AddAttribute(
"FixedMcsDl",
109 "Fix MCS to value set in StartingMcsDl",
113 MakeBooleanChecker())
114 .AddAttribute(
"FixedMcsUl",
115 "Fix MCS to value set in StartingMcsUl",
119 MakeBooleanChecker())
120 .AddAttribute(
"StartingMcsDl",
121 "Starting MCS for DL",
125 MakeUintegerChecker<uint8_t>())
126 .AddAttribute(
"StartingMcsUl",
127 "Starting MCS for UL",
131 MakeUintegerChecker<uint8_t>())
132 .AddAttribute(
"DlCtrlSymbols",
133 "Number of symbols allocated for DL CTRL",
137 MakeUintegerChecker<uint8_t>())
138 .AddAttribute(
"UlCtrlSymbols",
139 "Number of symbols allocated for UL CTRL",
143 MakeUintegerChecker<uint8_t>())
144 .AddAttribute(
"SrsSymbols",
145 "Number of symbols allocated for UL SRS",
149 MakeUintegerChecker<uint8_t>())
150 .AddAttribute(
"EnableSrsInUlSlots",
151 "Denotes whether the SRSs will be transmitted only in F slots"
152 "or both in F and UL slots. If False, SRS is transmitted only"
153 "in F slots, if True in both (F/UL)",
157 MakeBooleanChecker())
158 .AddAttribute(
"EnableSrsInFSlots",
159 "Denotes whether the SRSs will be transmitted in F slots"
160 "If true, it can be transmitted in F slots, otherwise "
165 MakeBooleanChecker())
166 .AddAttribute(
"DlAmc",
167 "The DL AMC of this scheduler",
170 MakePointerChecker<NrAmc>())
171 .AddAttribute(
"UlAmc",
172 "The UL AMC of this scheduler",
175 MakePointerChecker<NrAmc>())
176 .AddAttribute(
"MaxDlMcs",
177 "Maximum MCS index for DL",
181 MakeIntegerChecker<int8_t>(-1, 30))
182 .AddAttribute(
"EnableHarqReTx",
183 "If true, it would set the max HARQ ReTx to 3; otherwise it set it to 0",
187 MakeBooleanChecker())
189 "SchedLcAlgorithmType",
190 "Type of the scheduling algorithm that assigns bytes to the different LCs.",
195 .AddAttribute(
"RachUlGrantMcs",
196 "The MCS of the RACH UL grant, must be [0..15] (default 0)",
199 MakeUintegerChecker<uint8_t>());
214 NS_LOG_FUNCTION(
this);
217 m_startMcsDl =
static_cast<uint8_t
>(mcs);
218 m_startMcsUl =
static_cast<uint8_t
>(mcs);
225 NS_LOG_FUNCTION(
this);
233 NS_LOG_FUNCTION(
this);
234 m_cqiTimersThreshold = v;
240 NS_LOG_FUNCTION(
this);
241 return m_cqiTimersThreshold;
247 NS_LOG_FUNCTION(
this);
254 NS_LOG_FUNCTION(
this);
261 NS_LOG_FUNCTION(
this);
268 NS_LOG_FUNCTION(
this);
275 NS_LOG_FUNCTION(
this);
282 NS_LOG_FUNCTION(
this);
289 NS_LOG_FUNCTION(
this);
296 NS_LOG_FUNCTION(
this);
303 m_rachUlGrantMcs = v;
309 NS_LOG_FUNCTION(
this);
310 ObjectFactory factory;
311 m_schedLcType = type;
313 factory.SetTypeId(m_schedLcType);
314 m_schedLc = DynamicCast<NrMacSchedulerLcAlgorithm>(factory.Create());
315 NS_ASSERT(m_schedLc !=
nullptr);
321 NS_LOG_FUNCTION(
this);
328 NS_LOG_FUNCTION(
this);
341 return m_dlCtrlSymbols;
353 NS_LOG_FUNCTION(
this);
354 m_dlNotchedRbgsMask = dlNotchedRbgsMask;
355 std::stringstream ss;
358 for (
const auto& x : m_dlNotchedRbgsMask)
362 NS_LOG_INFO(
"Set DL notched mask: " << ss.str());
368 return m_dlNotchedRbgsMask;
374 NS_LOG_FUNCTION(
this);
375 m_ulNotchedRbgsMask = ulNotchedRbgsMask;
376 std::stringstream ss;
379 for (
const auto& x : m_ulNotchedRbgsMask)
383 NS_LOG_INFO(
"Set UL notched mask: " << ss.str());
389 return m_ulNotchedRbgsMask;
395 m_srsCtrlSymbols = v;
401 return m_srsCtrlSymbols;
407 m_enableSrsInUlSlots = v;
413 return m_enableSrsInUlSlots;
419 m_enableSrsInFSlots = v;
425 return m_enableSrsInFSlots;
431 m_enableHarqReTx = enableFlag;
437 return m_enableHarqReTx;
444 const std::unordered_map<uint16_t, UePtr>& ueMap,
445 std::vector<DlHarqInfo>* dlHarqToRetransmit,
446 const std::vector<DlHarqInfo>& dlHarqFeedback,
449 NS_LOG_FUNCTION(
this);
450 return m_schedHarq->ScheduleDlHarq(startingPoint,
462 const std::unordered_map<uint16_t, UePtr>& ueMap,
463 std::vector<UlHarqInfo>* ulHarqToRetransmit,
464 const std::vector<UlHarqInfo>& ulHarqFeedback,
467 NS_LOG_FUNCTION(
this);
468 return m_schedHarq->ScheduleUlHarq(startingPoint,
479 NS_LOG_FUNCTION(
this);
480 m_schedHarq->SortDlHarq(activeDlHarq);
486 NS_LOG_FUNCTION(
this);
487 m_schedHarq->SortDlHarq(activeUlHarq);
493 return m_ulCtrlSymbols;
506 NS_LOG_FUNCTION(
this);
512 cnf.m_result = NrMacCschedSapUser::Result_e::SUCCESS;
529 NS_LOG_FUNCTION(
this <<
" RNTI " << params.m_rnti <<
" txMode "
530 <<
static_cast<uint32_t
>(params.m_transmissionMode));
532 auto itUe = m_ueMap.find(params.m_rnti);
534 if (itUe == m_ueMap.end())
538 UeInfoOf(*itUe)->m_dlHarq.SetMaxSize(
540 UeInfoOf(*itUe)->m_ulHarq.SetMaxSize(
542 UeInfoOf(*itUe)->m_dlMcs = m_startMcsDl;
543 UeInfoOf(*itUe)->m_startMcsDlUe = m_startMcsDl;
544 UeInfoOf(*itUe)->m_ulMcs = m_startMcsUl;
550 bool ret = m_schedulerSrs->IncreasePeriodicity(
556 UeInfoOf(*itUe)->m_srsPeriodicity =
558 UeInfoOf(*itUe)->m_srsOffset = srs.
m_offset;
561 NS_LOG_INFO(
"Creating user, beam " << params.
m_beamId <<
" and ue " << params.m_rnti
567 NS_LOG_LOGIC(
"Updating Beam for UE " << params.m_rnti <<
" beam " << params.
m_beamId);
568 UeInfoOf(*itUe)->m_beamId = params.
m_beamId;
583 NS_LOG_FUNCTION(
this <<
" Release RNTI " << params.m_rnti);
585 auto itUe = m_ueMap.find(params.m_rnti);
586 NS_ABORT_IF(itUe == m_ueMap.end());
588 m_schedulerSrs->RemoveUe(itUe->second->m_srsOffset);
594 NS_LOG_INFO(
"Release RNTI " << params.m_rnti);
616 NS_LOG_FUNCTION(
this);
617 return std::make_unique<NrMacSchedulerLC>(config);
633 NS_LOG_FUNCTION(
this);
654 NS_LOG_FUNCTION(
this <<
static_cast<uint32_t
>(params.m_rnti));
655 auto itUe = m_ueMap.find(params.m_rnti);
657 NS_ABORT_IF(itUe == m_ueMap.end());
659 for (
const auto& lcConfig : params.m_logicalChannelConfigList)
661 if (lcConfig.m_direction == nr::LogicalChannelConfigListElement_s::DIR_DL ||
662 lcConfig.m_direction == nr::LogicalChannelConfigListElement_s::DIR_BOTH)
664 auto itDl = UeInfoOf(*itUe)->m_dlLCG.find(lcConfig.m_logicalChannelGroup);
665 auto itDlEnd = UeInfoOf(*itUe)->m_dlLCG.end();
668 NS_LOG_DEBUG(
"Created DL LCG for UE "
669 << UeInfoOf(*itUe)->m_rnti
670 <<
" ID=" <<
static_cast<uint32_t
>(lcConfig.m_logicalChannelGroup));
671 std::unique_ptr<NrMacSchedulerLCG> lcg =
CreateLCG(lcConfig);
672 itDl = UeInfoOf(*itUe)
673 ->m_dlLCG.emplace(lcConfig.m_logicalChannelGroup, std::move(lcg))
677 itDl->second->Insert(
CreateLC(lcConfig));
678 NS_LOG_DEBUG(
"Created DL LC for UE "
679 << UeInfoOf(*itUe)->m_rnti
680 <<
" ID=" <<
static_cast<uint32_t
>(lcConfig.m_logicalChannelIdentity)
681 <<
" in LCG " <<
static_cast<uint32_t
>(lcConfig.m_logicalChannelGroup));
683 if (lcConfig.m_direction == nr::LogicalChannelConfigListElement_s::DIR_UL ||
684 lcConfig.m_direction == nr::LogicalChannelConfigListElement_s::DIR_BOTH)
686 auto itUl = UeInfoOf(*itUe)->m_ulLCG.find(lcConfig.m_logicalChannelGroup);
687 auto itUlEnd = UeInfoOf(*itUe)->m_ulLCG.end();
690 NS_LOG_DEBUG(
"Created UL LCG for UE "
691 << UeInfoOf(*itUe)->m_rnti
692 <<
" ID=" <<
static_cast<uint32_t
>(lcConfig.m_logicalChannelGroup));
693 std::unique_ptr<NrMacSchedulerLCG> lcg =
CreateLCG(lcConfig);
694 itUl = UeInfoOf(*itUe)
695 ->m_ulLCG.emplace(lcConfig.m_logicalChannelGroup, std::move(lcg))
701 if (itUl->second->NumOfLC() == 0)
703 itUl->second->Insert(
CreateLC(lcConfig));
704 NS_LOG_DEBUG(
"Created UL LC for UE "
705 << UeInfoOf(*itUe)->m_rnti
706 <<
" ID=" <<
static_cast<uint32_t
>(lcConfig.m_logicalChannelIdentity)
708 <<
static_cast<uint32_t
>(lcConfig.m_logicalChannelGroup));
722 NS_LOG_FUNCTION(
this);
724 for (
const auto& lcId : params.m_logicalChannelIdentity)
726 auto itUe = m_ueMap.find(params.m_rnti);
727 NS_ABORT_IF(itUe == m_ueMap.end());
728 itUe->second->ReleaseLC(lcId);
744 NS_LOG_FUNCTION(
this << params.
m_rnti
748 auto itUe = m_ueMap.find(params.
m_rnti);
749 NS_ABORT_IF(itUe == m_ueMap.end());
751 for (
const auto& lcg : UeInfoOf(*itUe)->m_dlLCG)
755 NS_LOG_INFO(
"Updating DL LC Info: " << params
756 <<
" in LCG: " <<
static_cast<uint32_t
>(lcg.first));
757 lcg.second->UpdateInfo(params);
762 NS_FATAL_ERROR(
"The LC does not exist. Can't update");
775NrMacSchedulerNs3::BSRReceivedFromUe(
const MacCeElement& bsr)
777 NS_LOG_FUNCTION(
this);
778 NS_ASSERT(bsr.m_macCeType == MacCeElement::BSR);
780 auto itUe = m_ueMap.find(bsr.m_rnti);
781 NS_ABORT_IF(itUe == m_ueMap.end());
785 for (uint8_t lcg = 0; lcg < 4; ++lcg)
787 uint8_t bsrId = bsr.m_macCeValue.m_bufferStatus.at(lcg);
790 auto itLcg = UeInfoOf(*itUe)->m_ulLCG.find(lcg);
791 if (itLcg == UeInfoOf(*itUe)->m_ulLCG.end())
796 NS_LOG_DEBUG(
"BSR does not match an established lcg");
800 if (itLcg->second->GetTotalSize() > 0 || bufSize > 0)
802 NS_LOG_INFO(
"Updating UL LCG " <<
static_cast<uint32_t
>(lcg) <<
" for UE " << bsr.m_rnti
803 <<
" size " << bufSize);
806 itLcg->second->UpdateInfo(bufSize);
821 NS_LOG_FUNCTION(
this);
825 if (element.m_macCeType == MacCeElement::BSR)
827 BSRReceivedFromUe(element);
831 NS_LOG_INFO(
"Ignoring received CTRL message because it's not a BSR");
850 NS_LOG_FUNCTION(
this);
859 uint32_t expirationTime =
860 static_cast<uint32_t
>(m_cqiTimersThreshold.GetNanoSeconds() /
865 NS_ASSERT(m_ueMap.find(cqi.m_rnti) != m_ueMap.end());
866 const std::shared_ptr<NrMacSchedulerUeInfo>& ue = m_ueMap.find(cqi.m_rnti)->second;
896 NS_LOG_FUNCTION(
this);
905 uint32_t expirationTime =
906 static_cast<uint32_t
>(m_cqiTimersThreshold.GetNanoSeconds() /
911 case UlCqiInfo::PUSCH: {
912 [[maybe_unused]]
bool found =
false;
916 NS_LOG_INFO(
"CQI for allocation: " << params.
m_sfnSf <<
" started at sym: " << +symStart
917 <<
" modified allocation " << ulSfnSf <<
" sym Start "
918 <<
static_cast<uint32_t
>(symStart));
920 auto itAlloc = m_ulAllocationMap.find(ulSfnSf.
GetEncoding());
921 NS_ASSERT_MSG(itAlloc != m_ulAllocationMap.end(),
"Can't find allocation for " << ulSfnSf);
922 std::vector<AllocElem>& ulAllocations = itAlloc->second.m_ulAllocations;
924 for (
auto it = ulAllocations.cbegin(); it != ulAllocations.cend(); )
926 const AllocElem& allocation = *(it);
927 if (allocation.m_symStart == symStart)
929 auto itUe = m_ueMap.find(allocation.m_rnti);
930 NS_ASSERT(itUe != m_ueMap.end());
931 NS_ASSERT(allocation.m_numSym > 0);
932 NS_ASSERT(allocation.m_tbs > 0);
938 allocation.m_rbgMask,
942 it = ulAllocations.erase(it);
951 if (ulAllocations.empty())
954 NS_LOG_INFO(
"Removing allocation for " << ulSfnSf);
955 m_ulAllocationMap.erase(itAlloc);
960 NS_FATAL_ERROR(
"Unknown type of UL-CQI");
979NrMacSchedulerNs3::MergeHARQ(std::vector<T>* existingFeedbacks,
980 const std::vector<T>& inFeedbacks,
981 const std::string& mode)
const
983 NS_LOG_FUNCTION(
this);
984 NS_LOG_INFO(
"To retransmit : " << existingFeedbacks->size() <<
" " << mode <<
" HARQ, received "
985 << inFeedbacks.size() <<
" " << mode <<
" HARQ Feedback");
986 uint64_t existingSize = existingFeedbacks->size();
987 uint64_t inSize = inFeedbacks.size();
988 existingFeedbacks->insert(existingFeedbacks->end(), inFeedbacks.begin(), inFeedbacks.end());
989 NS_ASSERT(existingFeedbacks->size() == existingSize + inSize);
991 auto ret = std::vector<T>(std::make_move_iterator(existingFeedbacks->begin()),
992 std::make_move_iterator(existingFeedbacks->end()));
993 existingFeedbacks->clear();
1015template <
typename T>
1017NrMacSchedulerNs3::ProcessHARQFeedbacks(
1018 std::vector<T>* harqInfo,
1019 const NrMacSchedulerUeInfo::GetHarqVectorFn& GetHarqVectorFn,
1020 const std::string& direction)
const
1022 NS_LOG_FUNCTION(
this);
1023 uint32_t nackReceived = 0;
1026 for (
auto harqFeedbackIt = harqInfo->begin(); harqFeedbackIt != harqInfo->end();
1029 uint8_t harqId = harqFeedbackIt->m_harqProcessId;
1030 uint16_t rnti = harqFeedbackIt->m_rnti;
1031 NrMacHarqVector& ueHarqVector = GetHarqVectorFn(m_ueMap.find(rnti)->second);
1032 HarqProcess& ueProcess = ueHarqVector.Get(harqId);
1034 NS_LOG_INFO(
"Evaluating feedback: " << *harqFeedbackIt);
1035 if (!ueProcess.m_active)
1037 NS_LOG_INFO(
"UE " << rnti <<
" HARQ vector: " << ueHarqVector);
1038 NS_FATAL_ERROR(
"Received feedback for a process which is not active");
1040 NS_ABORT_IF(ueProcess.m_dciElement ==
nullptr);
1043 NS_ASSERT(ueProcess.m_dciElement->m_rv < 4);
1044 uint8_t maxHarqReTx = m_enableHarqReTx ? 3 : 0;
1046 if (harqFeedbackIt->IsReceivedOk() || ueProcess.m_dciElement->m_rv == maxHarqReTx)
1048 ueHarqVector.Erase(harqId);
1049 harqFeedbackIt = harqInfo->erase(harqFeedbackIt);
1050 NS_LOG_INFO(
"Erased processID " <<
static_cast<uint32_t
>(harqId) <<
" of UE " << rnti
1051 <<
" direction " << direction);
1053 else if (!harqFeedbackIt->IsReceivedOk())
1058 NS_LOG_INFO(
"NACK received for UE " <<
static_cast<uint32_t
>(rnti) <<
" process "
1059 <<
static_cast<uint32_t
>(harqId) <<
" direction "
1064 NS_ASSERT(harqInfo->size() == nackReceived);
1079NrMacSchedulerNs3::ResetExpiredHARQ(uint16_t rnti, NrMacHarqVector* harq)
1081 NS_LOG_FUNCTION(
this << harq);
1083 for (
auto harqIt = harq->Begin(); harqIt != harq->End(); ++harqIt)
1085 HarqProcess& process = harqIt->second;
1086 uint8_t processId = harqIt->first;
1096 NS_LOG_INFO(
"Updated process for UE " << rnti <<
" number "
1097 <<
static_cast<uint32_t
>(processId)
1098 <<
", resulting process: " << process);
1102 harq->Erase(processId);
1103 NS_LOG_INFO(
"Erased process for UE " << rnti <<
" number "
1104 <<
static_cast<uint32_t
>(processId)
1105 <<
" for time limits");
1119NrMacSchedulerNs3::PrependCtrlSym(uint8_t symStart,
1120 uint8_t numSymToAllocate,
1122 std::deque<VarTtiAllocInfo>* allocations)
const
1130 NS_ASSERT(allocations->empty());
1131 NS_ASSERT(symStart == 0);
1134 for (uint8_t sym = symStart; sym < symStart + numSymToAllocate; ++sym)
1136 allocations->emplace_front(std::make_shared<DciInfoElementTdma>(sym,
1141 NS_LOG_INFO(
"Allocating CTRL symbol, type"
1142 << mode <<
" in TDMA. numSym=1, symStart=" <<
static_cast<uint32_t
>(sym)
1143 <<
" Remaining CTRL sym to allocate: " << sym - symStart);
1145 return symStart + numSymToAllocate;
1157NrMacSchedulerNs3::AppendCtrlSym(uint8_t symStart,
1158 uint8_t numSymToAllocate,
1160 std::deque<VarTtiAllocInfo>* allocations)
const
1167 NS_ASSERT(allocations->empty());
1168 NS_ASSERT(symStart == 0);
1171 for (uint8_t sym = symStart; sym < symStart + numSymToAllocate; ++sym)
1173 allocations->emplace_back(std::make_shared<DciInfoElementTdma>(sym,
1178 NS_LOG_INFO(
"Allocating CTRL symbol, type"
1179 << mode <<
" in TDMA. numSym=1, symStart=" <<
static_cast<uint32_t
>(sym)
1180 <<
" Remaining CTRL sym to allocate: " << sym - symStart);
1182 return symStart + numSymToAllocate;
1196NrMacSchedulerNs3::ComputeActiveHarq(ActiveHarqMap* activeDlHarq,
1197 const std::vector<DlHarqInfo>& dlHarqFeedback)
const
1199 NS_LOG_FUNCTION(
this);
1200 NS_ASSERT(activeDlHarq->empty());
1202 for (
const auto& feedback : dlHarqFeedback)
1204 uint16_t rnti = feedback.m_rnti;
1205 auto& schedInfo = m_ueMap.find(rnti)->second;
1206 auto beamIterator = activeDlHarq->find(schedInfo->m_beamId);
1208 if (beamIterator == activeDlHarq->end())
1210 std::vector<NrMacHarqVector::iterator> harqVector;
1211 NS_ASSERT(schedInfo->m_dlHarq.Find(feedback.m_harqProcessId)->second.m_active);
1213 harqVector.emplace_back(schedInfo->m_dlHarq.Find(feedback.m_harqProcessId));
1214 activeDlHarq->emplace(std::make_pair(schedInfo->m_beamId, harqVector));
1218 NS_ASSERT(schedInfo->m_dlHarq.Find(feedback.m_harqProcessId)->second.m_active);
1219 beamIterator->second.emplace_back(schedInfo->m_dlHarq.Find(feedback.m_harqProcessId));
1221 NS_LOG_INFO(
"Received feedback for UE " << rnti <<
" ID "
1222 <<
static_cast<uint32_t
>(feedback.m_harqProcessId)
1223 <<
" marked as active");
1224 NS_ASSERT(schedInfo->m_dlHarq.Find(feedback.m_harqProcessId)->second.m_status ==
1242NrMacSchedulerNs3::ComputeActiveHarq(ActiveHarqMap* activeUlHarq,
1243 const std::vector<UlHarqInfo>& ulHarqFeedback)
const
1245 NS_LOG_FUNCTION(
this);
1247 for (
const auto& feedback : ulHarqFeedback)
1249 uint16_t rnti = feedback.m_rnti;
1250 auto& schedInfo = m_ueMap.find(rnti)->second;
1251 auto beamIterator = activeUlHarq->find(schedInfo->m_beamId);
1253 if (beamIterator == activeUlHarq->end())
1255 std::vector<NrMacHarqVector::iterator> harqVector;
1256 NS_ASSERT(schedInfo->m_ulHarq.Find(feedback.m_harqProcessId)->second.m_active);
1257 harqVector.emplace_back(schedInfo->m_ulHarq.Find(feedback.m_harqProcessId));
1258 activeUlHarq->emplace(std::make_pair(schedInfo->m_beamId, harqVector));
1262 NS_ASSERT(schedInfo->m_ulHarq.Find(feedback.m_harqProcessId)->second.m_active);
1263 beamIterator->second.emplace_back(schedInfo->m_ulHarq.Find(feedback.m_harqProcessId));
1282NrMacSchedulerNs3::ComputeActiveUe(ActiveUeMap* activeUe,
1283 const NrMacSchedulerUeInfo::GetLCGFn& GetLCGFn,
1284 const NrMacSchedulerUeInfo::GetHarqVectorFn& GetHarqVector,
1285 const std::string& mode)
const
1287 NS_LOG_FUNCTION(
this);
1288 for (
const auto& ueInfo : m_ueMap)
1290 uint32_t totBuffer = 0;
1291 const auto& ue = ueInfo.second;
1294 for (
const auto& lcgInfo : GetLCGFn(ue))
1296 const auto& lcg = lcgInfo.second;
1297 if (lcg->GetTotalSize() > 0)
1299 NS_LOG_INFO(
"UE " << ue->m_rnti <<
" " << mode <<
" LCG "
1300 <<
static_cast<uint32_t
>(lcgInfo.first) <<
" bytes "
1301 << lcg->GetTotalSize());
1303 totBuffer += lcg->GetTotalSize();
1306 auto harqV = GetHarqVector(ue);
1308 if (totBuffer > 0 && harqV.CanInsert())
1310 auto it = activeUe->find(ue->m_beamId);
1311 if (it == activeUe->end())
1313 std::vector<std::pair<std::shared_ptr<NrMacSchedulerUeInfo>, uint32_t>> tmp;
1314 tmp.emplace_back(ue, totBuffer);
1315 activeUe->insert(std::make_pair(ue->m_beamId, tmp));
1319 it->second.emplace_back(ue, totBuffer);
1357NrMacSchedulerNs3::DoScheduleDlData(PointInFTPlane* spoint,
1359 const ActiveUeMap& activeDl,
1360 SlotAllocInfo* slotAlloc)
const
1362 NS_LOG_FUNCTION(
this << symAvail);
1363 NS_ASSERT(spoint->m_rbg == 0);
1366 uint8_t usedSym = 0;
1368 for (
const auto& beam : activeDl)
1370 uint32_t availableRBG =
1372 bool assigned =
false;
1373 std::unordered_set<uint8_t> symbStartDci;
1376 uint32_t allocSym = 0;
1378 NS_LOG_DEBUG(activeDl.size()
1379 <<
" active DL beam, this beam has " << symPerBeam.at(GetBeam(beam))
1380 <<
" SYM, starts from RB " << spoint->m_rbg <<
" and symbol "
1381 <<
static_cast<uint32_t
>(spoint->m_sym) <<
" for a total of " << availableRBG
1384 if (symPerBeam.at(GetBeam(beam)) == 0)
1386 NS_LOG_INFO(
"No available symbols for this beam, continue");
1390 for (
const auto& ue : beam.second)
1392 if (ue.first->m_dlRBG == 0)
1394 NS_LOG_INFO(
"UE " << ue.first->m_rnti <<
" does not have RBG assigned");
1398 std::shared_ptr<DciInfoElementTdma> dci =
1399 CreateDlDci(spoint, ue.first, symPerBeam.at(GetBeam(beam)));
1413 NS_LOG_DEBUG(
"No DCI has been created, ignoring");
1414 ue.first->ResetDlMetric();
1420 if (symbStartDci.insert(dci->m_symStart).second)
1422 allocSym += dci->m_numSym;
1425 NS_LOG_INFO(
"UE " << ue.first->m_rnti <<
" has " << ue.first->m_dlRBG
1426 <<
" RBG assigned");
1429 <<
static_cast<uint32_t
>(dci->m_symStart)
1430 <<
" symEnd: " <<
static_cast<uint32_t
>(dci->m_numSym) <<
" symbols: "
1436 if (!ue.first->m_dlHarq.CanInsert())
1438 NS_LOG_INFO(
"Harq Vector condition for UE " << ue.first->m_rnti << std::endl
1439 << ue.first->m_dlHarq);
1440 NS_FATAL_ERROR(
"UE " << ue.first->m_rnti <<
" does not have DL HARQ space");
1443 ue.first->m_dlHarq.Insert(&
id, harqProcess);
1444 ue.first->m_dlHarq.Get(
id).m_dciElement->m_harqProcess = id;
1448 auto distributedBytes =
1449 m_schedLc->AssignBytesToDlLC(ue.first->m_dlLCG,
1453 std::vector<std::vector<NrMacSchedulerLcAlgorithm::Assignation>> bytesPerLc(
1454 distributedBytes.size());
1456 for (std::size_t numLc = 0; numLc < distributedBytes.size(); numLc++)
1458 bytesPerLc.at(numLc).emplace_back(distributedBytes.at(numLc).m_lcg,
1459 distributedBytes.at(numLc).m_lcId,
1460 distributedBytes.at(numLc).m_bytes);
1463 VarTtiAllocInfo slotInfo(dci);
1465 NS_LOG_INFO(
"Assigned process ID " <<
static_cast<uint32_t
>(dci->m_harqProcess)
1466 <<
" to UE " << ue.first->m_rnti);
1467 NS_LOG_DEBUG(
" UE" << dci->m_rnti <<
" gets DL symbols "
1468 <<
static_cast<uint32_t
>(dci->m_symStart) <<
"-"
1469 <<
static_cast<uint32_t
>(dci->m_symStart + dci->m_numSym) <<
" tbs "
1470 << dci->m_tbSize <<
" mcs " <<
static_cast<uint32_t
>(dci->m_mcs)
1471 <<
" harqId " <<
static_cast<uint32_t
>(
id) <<
" rv "
1472 <<
static_cast<uint32_t
>(dci->m_rv));
1474 for (
const auto& byteDistribution : distributedBytes)
1476 NS_ASSERT(byteDistribution.m_bytes >= 3);
1477 uint8_t lcId = byteDistribution.m_lcId;
1478 uint8_t lcgId = byteDistribution.m_lcg;
1479 uint32_t bytes = byteDistribution.m_bytes - 3;
1481 RlcPduInfo newRlcPdu(lcId, bytes);
1482 HarqProcess& process = ue.first->m_dlHarq.Get(dci->m_harqProcess);
1484 slotInfo.m_rlcPduInfo.push_back(newRlcPdu);
1485 process.m_rlcPduInfo.push_back(newRlcPdu);
1487 ue.first->m_dlLCG.at(lcgId)->AssignedData(lcId, bytes,
"DL");
1489 NS_LOG_DEBUG(
"DL LCG " <<
static_cast<uint32_t
>(lcgId) <<
" LCID "
1490 <<
static_cast<uint32_t
>(lcId) <<
" got bytes "
1491 << newRlcPdu.m_size);
1494 NS_ABORT_IF(slotInfo.m_rlcPduInfo.empty());
1496 slotAlloc->m_varTtiAllocInfo.emplace_back(slotInfo);
1501 usedSym += allocSym;
1502 slotAlloc->m_numSymAlloc += allocSym;
1506 for (
auto& beam : activeDl)
1508 for (
auto& ue : beam.second)
1510 ue.first->ResetDlSchedInfo();
1514 NS_ASSERT(spoint->m_rbg == 0);
1555NrMacSchedulerNs3::DoScheduleUlData(PointInFTPlane* spoint,
1557 const ActiveUeMap& activeUl,
1558 SlotAllocInfo* slotAlloc)
const
1560 NS_LOG_FUNCTION(
this);
1561 NS_ASSERT(symAvail > 0 && !activeUl.empty());
1562 NS_ASSERT(spoint->m_rbg == 0);
1565 uint8_t usedSym = 0;
1568 for (
const auto& beam : activeUl)
1570 uint32_t availableRBG =
1572 bool assigned =
false;
1573 std::unordered_set<uint8_t> symbStartDci;
1576 uint32_t allocSym = 0;
1578 NS_LOG_DEBUG(activeUl.size()
1579 <<
" active UL beam, this beam has " << symPerBeam.at(GetBeam(beam))
1580 <<
" SYM, starts from RBG " << spoint->m_rbg <<
" and symbol "
1581 <<
static_cast<uint32_t
>(spoint->m_sym) <<
" (going backward) for a total of "
1585 if (symPerBeam.at(GetBeam(beam)) == 0)
1587 NS_LOG_INFO(
"No available symbols for this beam, continue");
1591 for (
const auto& ue : beam.second)
1593 if (ue.first->m_ulRBG == 0)
1595 NS_LOG_INFO(
"UE " << ue.first->m_rnti <<
" does not have RBG assigned");
1599 std::shared_ptr<DciInfoElementTdma> dci =
1600 CreateUlDci(spoint, ue.first, symPerBeam.at(GetBeam(beam)));
1615 NS_LOG_DEBUG(
"No DCI has been created, ignoring");
1616 ue.first->ResetUlMetric();
1622 if (symbStartDci.insert(dci->m_symStart).second)
1624 allocSym += dci->m_numSym;
1627 if (!ue.first->m_ulHarq.CanInsert())
1629 NS_LOG_INFO(
"Harq Vector condition for UE " << ue.first->m_rnti << std::endl
1630 << ue.first->m_ulHarq);
1631 NS_FATAL_ERROR(
"UE " << ue.first->m_rnti <<
" does not have UL HARQ space");
1636 ue.first->m_ulHarq.Insert(&
id, harqProcess);
1638 ue.first->m_ulHarq.Get(
id).m_dciElement->m_harqProcess = id;
1640 VarTtiAllocInfo slotInfo(dci);
1642 NS_LOG_INFO(
"Assigned process ID " <<
static_cast<uint32_t
>(dci->m_harqProcess)
1643 <<
" to UE " << ue.first->m_rnti);
1644 NS_LOG_DEBUG(
" UE" << dci->m_rnti <<
" gets UL symbols "
1645 <<
static_cast<uint32_t
>(dci->m_symStart) <<
"-"
1646 <<
static_cast<uint32_t
>(dci->m_symStart + dci->m_numSym) <<
" tbs "
1647 << dci->m_tbSize <<
" mcs " <<
static_cast<uint32_t
>(dci->m_mcs)
1648 <<
" harqId " <<
static_cast<uint32_t
>(
id) <<
" rv "
1649 <<
static_cast<uint32_t
>(dci->m_rv));
1651 auto distributedBytes = m_schedLc->AssignBytesToUlLC(ue.first->m_ulLCG, dci->m_tbSize);
1652 bool assignedToLC =
false;
1653 for (
const auto& byteDistribution : distributedBytes)
1655 assignedToLC =
true;
1656 ue.first->m_ulLCG.at(byteDistribution.m_lcg)
1657 ->AssignedData(byteDistribution.m_lcId, byteDistribution.m_bytes,
"UL");
1658 NS_LOG_DEBUG(
"UL LCG " <<
static_cast<uint32_t
>(byteDistribution.m_lcg)
1659 <<
" assigned bytes " << byteDistribution.m_bytes
1661 <<
static_cast<uint32_t
>(byteDistribution.m_lcId));
1663 NS_ASSERT(assignedToLC);
1664 slotAlloc->m_varTtiAllocInfo.emplace_front(slotInfo);
1669 usedSym += allocSym;
1670 slotAlloc->m_numSymAlloc += allocSym;
1674 for (
auto& beam : activeUl)
1676 for (
auto& ue : beam.second)
1678 ue.first->ResetUlSchedInfo();
1682 NS_ASSERT(spoint->m_rbg == 0);
1699NrMacSchedulerNs3::DoScheduleUlSr(PointInFTPlane* spoint,
const std::list<uint16_t>& rntiList)
const
1701 NS_LOG_FUNCTION(
this);
1702 NS_ASSERT(spoint->m_rbg == 0);
1704 for (
const auto& v : rntiList)
1706 for (
auto& ulLcg : NrMacSchedulerUeInfo::GetUlLCG(m_ueMap.at(v)))
1708 NS_LOG_DEBUG(
"Assigning 12 bytes to UE " << v <<
" because of a SR");
1709 ulLcg.second->UpdateInfo(12);
1753NrMacSchedulerNs3::ScheduleDl(
const NrMacSchedSapProvider::SchedDlTriggerReqParameters& params,
1754 const std::vector<DlHarqInfo>& dlHarqFeedback)
1756 NS_LOG_FUNCTION(
this);
1757 NS_LOG_INFO(
"Scheduling invoked for slot " << params.m_snfSf <<
" of type "
1758 << params.m_slotType);
1760 NrMacSchedSapUser::SchedConfigIndParameters dlSlot(params.m_snfSf);
1761 dlSlot.m_slotAllocInfo.m_sfnSf = params.m_snfSf;
1763 auto ulAllocationIt =
1764 m_ulAllocationMap.find(params.m_snfSf.GetEncoding());
1765 if (ulAllocationIt == m_ulAllocationMap.end())
1768 m_ulAllocationMap.insert(std::make_pair(params.m_snfSf.GetEncoding(), SlotElem(0)))
1771 auto& ulAllocations = ulAllocationIt->second;
1777 &dlSlot.m_slotAllocInfo.m_varTtiAllocInfo);
1778 dlSlot.m_slotAllocInfo.m_numSymAlloc += m_dlCtrlSymbols;
1783 NS_LOG_INFO(
"S slot, adding UL CTRL");
1787 &dlSlot.m_slotAllocInfo.m_varTtiAllocInfo);
1788 ulAllocations.m_totUlSym += m_ulCtrlSymbols;
1789 dlSlot.m_slotAllocInfo.m_numSymAlloc += m_ulCtrlSymbols;
1794 ComputeActiveHarq(&activeDlHarq, dlHarqFeedback);
1797 ComputeActiveUe(&activeDlUe,
1802 DoScheduleDl(dlHarqFeedback,
1807 &dlSlot.m_slotAllocInfo);
1814 NS_LOG_INFO(
"Removing UL allocation for slot " << params.m_snfSf <<
" size "
1815 << m_ulAllocationMap.size());
1816 m_ulAllocationMap.erase(ulAllocationIt);
1819 NS_LOG_INFO(
"Total DCI for DL : " << dlSlot.m_slotAllocInfo.m_varTtiAllocInfo.size()
1820 <<
" including DL CTRL");
1861NrMacSchedulerNs3::ScheduleUl(
const NrMacSchedSapProvider::SchedUlTriggerReqParameters& params,
1862 const std::vector<UlHarqInfo>& ulHarqFeedback)
1864 NS_LOG_FUNCTION(
this);
1865 NS_LOG_INFO(
"Scheduling invoked for slot " << params.m_snfSf);
1867 NrMacSchedSapUser::SchedConfigIndParameters ulSlot(params.m_snfSf);
1868 ulSlot.m_slotAllocInfo.m_sfnSf = params.m_snfSf;
1875 &ulSlot.m_slotAllocInfo.m_varTtiAllocInfo);
1876 ulSlot.m_slotAllocInfo.m_numSymAlloc += m_ulCtrlSymbols;
1879 DoScheduleUl(ulHarqFeedback, params.m_snfSf, &ulSlot.m_slotAllocInfo, params.m_slotType);
1881 NS_LOG_INFO(
"Total DCI for UL : " << ulSlot.m_slotAllocInfo.m_varTtiAllocInfo.size()
1882 <<
" including UL CTRL");
1925NrMacSchedulerNs3::DoScheduleUl(
const std::vector<UlHarqInfo>& ulHarqFeedback,
1927 SlotAllocInfo* allocInfo,
1930 NS_LOG_FUNCTION(
this);
1932 NS_ASSERT(allocInfo->m_varTtiAllocInfo.size() == 1);
1937 dataSymPerSlot -= m_dlCtrlSymbols;
1941 ComputeActiveHarq(&activeUlHarq, ulHarqFeedback);
1946 PointInFTPlane ulAssignationStartPoint(0, lastSym);
1947 uint8_t ulSymAvail = dataSymPerSlot;
1950 m_ulAllocationMap.emplace(ulSfn.GetEncoding(), SlotElem(0));
1956 NS_ASSERT(m_srsCtrlSymbols <= ulSymAvail);
1957 uint8_t srsSym = DoScheduleSrs(&ulAssignationStartPoint, allocInfo);
1958 ulSymAvail -= srsSym;
1961 NS_LOG_DEBUG(
"Scheduling UL " << ulSfn <<
" UL HARQ to retransmit: " << ulHarqFeedback.size()
1962 <<
" Active Beams UL HARQ: " << activeUlHarq.size()
1963 <<
" starting from (" << +ulAssignationStartPoint.m_rbg <<
", "
1964 << +ulAssignationStartPoint.m_sym <<
")");
1967 uint8_t usedMsg3 = 0;
1968 if (!m_rachList.empty())
1970 usedMsg3 = DoScheduleUlMsg3(&ulAssignationStartPoint, ulSymAvail, allocInfo);
1971 NS_ASSERT_MSG(ulSymAvail >= usedMsg3,
1972 "Available: " << +ulSymAvail <<
" used by UL MSG3: " << +usedMsg3);
1973 NS_LOG_INFO(
"For the slot " << ulSfn <<
" reserved " <<
static_cast<uint32_t
>(usedMsg3)
1974 <<
" symbols for UL MSG3");
1975 ulSymAvail -= usedMsg3;
1976 allocInfo->m_numSymAlloc += usedMsg3;
1979 if (!activeUlHarq.empty())
1984 &m_ulHarqToRetransmit,
1987 NS_ASSERT_MSG(ulSymAvail >= usedHarq,
1988 "Available: " << +ulSymAvail <<
" used by HARQ: " << +usedHarq);
1989 NS_LOG_INFO(
"For the slot " << ulSfn <<
" reserved " <<
static_cast<uint32_t
>(usedHarq)
1990 <<
" symbols for UL HARQ retx");
1991 ulSymAvail -= usedHarq;
1994 NS_ASSERT(ulAssignationStartPoint.m_rbg == 0);
1996 if (ulSymAvail > 0 && !m_srList.empty())
1998 DoScheduleUlSr(&ulAssignationStartPoint, m_srList);
2003 ComputeActiveUe(&activeUlUe,
2008 GetSecond GetUeInfoList;
2009 for (
const auto& alloc : allocInfo->m_varTtiAllocInfo)
2011 for (
auto it = activeUlUe.begin(); it != activeUlUe.end(); )
2013 auto& ueInfos = GetUeInfoList(*it);
2014 for (
auto ueIt = ueInfos.begin(); ueIt != ueInfos.end(); )
2016 GetFirst GetUeInfoPtr;
2017 if (GetUeInfoPtr(*ueIt)->m_rnti == alloc.m_dci->m_rnti)
2019 NS_LOG_INFO(
"Removed RNTI " << alloc.m_dci->m_rnti
2020 <<
" from active ue list "
2021 "because it has already an HARQ scheduled");
2022 ueInfos.erase(ueIt);
2030 if (!ueInfos.empty())
2036 activeUlUe.erase(it);
2042 if (ulSymAvail > 0 && !activeUlUe.empty())
2045 DoScheduleUlData(&ulAssignationStartPoint, ulSymAvail, activeUlUe, allocInfo);
2046 NS_LOG_INFO(
"For the slot " << ulSfn <<
" reserved " <<
static_cast<uint32_t
>(usedUl)
2047 <<
" symbols for UL data tx");
2048 ulSymAvail -= usedUl;
2051 std::vector<uint32_t> symToAl;
2052 symToAl.resize(15, 0);
2054 auto& totUlSym = m_ulAllocationMap.at(ulSfn.GetEncoding()).m_totUlSym;
2055 auto& allocations = m_ulAllocationMap.at(ulSfn.GetEncoding()).m_ulAllocations;
2056 for (
const auto& alloc : allocInfo->m_varTtiAllocInfo)
2063 symToAl[alloc.m_dci->m_symStart] = alloc.m_dci->m_numSym;
2064 NS_LOG_INFO(
"UL Allocation. RNTI " << alloc.m_dci->m_rnti <<
", symStart "
2065 <<
static_cast<uint32_t
>(alloc.m_dci->m_symStart)
2066 <<
" numSym " << +alloc.m_dci->m_numSym);
2071 NS_LOG_INFO(
"Placed the above allocation in the CQI map");
2072 allocations.emplace_back(alloc.m_dci->m_rnti,
2073 alloc.m_dci->m_tbSize,
2074 alloc.m_dci->m_symStart,
2075 alloc.m_dci->m_numSym,
2077 alloc.m_dci->m_rank,
2078 alloc.m_dci->m_rbgBitmask);
2083 for (
const auto& v : symToAl)
2088 NS_ASSERT_MSG((dataSymPerSlot + m_ulCtrlSymbols) - ulSymAvail == totUlSym,
2089 "UL symbols available: "
2090 <<
static_cast<uint32_t
>(dataSymPerSlot + m_ulCtrlSymbols)
2091 <<
" UL symbols available at end of sched: "
2092 <<
static_cast<uint32_t
>(ulSymAvail)
2093 <<
" total of symbols registered in the allocation: "
2094 <<
static_cast<uint32_t
>(totUlSym) <<
" slot type " << type);
2096 NS_LOG_INFO(
"For the slot " << ulSfn <<
" registered a total of "
2097 <<
static_cast<uint32_t
>(totUlSym) <<
" symbols and "
2098 << allocations.size() <<
" data allocations, with a total of "
2099 << allocInfo->m_varTtiAllocInfo.size());
2100 NS_ASSERT(m_ulAllocationMap.at(ulSfn.GetEncoding()).m_totUlSym == totUlSym);
2102 return dataSymPerSlot - ulSymAvail;
2106NrMacSchedulerNs3::DoScheduleSrs(PointInFTPlane* spoint, SlotAllocInfo* allocInfo)
2108 NS_LOG_FUNCTION(
this);
2113 if (m_ueMap.empty())
2122 uint32_t offset_UEx = m_srsSlotCounter % m_ueMap.begin()->second->m_srsPeriodicity;
2125 for (
const auto& ue : m_ueMap)
2127 if (ue.second->m_srsOffset == offset_UEx)
2129 rnti = ue.second->m_rnti;
2140 for (uint32_t i = 0; i < m_srsCtrlSymbols; ++i)
2144 NS_LOG_INFO(
"UE " << rnti <<
" assigned symbol " << +spoint->m_sym <<
" for SRS tx");
2153 Ptr<const ComplexMatrixArray> precMats{
nullptr};
2157 auto dci = std::make_shared<DciInfoElementTdma>(rnti,
2170 dci->m_rbgBitmask = rbgBitmask;
2172 allocInfo->m_numSymAlloc += 1;
2173 allocInfo->m_varTtiAllocInfo.emplace_front(dci);
2233NrMacSchedulerNs3::DoScheduleDl(
const std::vector<DlHarqInfo>& dlHarqFeedback,
2234 const ActiveHarqMap& activeDlHarq,
2235 ActiveUeMap* activeDlUe,
2236 const SfnSf& dlSfnSf,
2237 const SlotElem& ulAllocations,
2240 NS_LOG_FUNCTION(
this);
2241 NS_ASSERT(activeDlUe !=
nullptr);
2245 uint8_t dlSymAvail = dataSymPerSlot - ulAllocations.m_totUlSym;
2246 PointInFTPlane dlAssignationStartPoint(0, m_dlCtrlSymbols);
2248 NS_LOG_DEBUG(
"Scheduling DL for slot "
2249 << dlSfnSf <<
" DL HARQ to retransmit: " << dlHarqFeedback.size()
2250 <<
" Active Beams DL HARQ: " << activeDlHarq.size()
2251 <<
" sym available: " <<
static_cast<uint32_t
>(dlSymAvail) <<
" starting from sym "
2252 <<
static_cast<uint32_t
>(m_dlCtrlSymbols));
2254 if (!activeDlHarq.empty())
2260 &m_dlHarqToRetransmit,
2263 NS_ASSERT(dlSymAvail >= usedHarq);
2264 dlSymAvail -= usedHarq;
2267 GetSecond GetUeInfoList;
2269 for (
const auto& alloc : allocInfo->m_varTtiAllocInfo)
2271 for (
auto it = activeDlUe->begin(); it != activeDlUe->end(); )
2273 auto& ueInfos = GetUeInfoList(*it);
2274 for (
auto ueIt = ueInfos.begin(); ueIt != ueInfos.end(); )
2276 GetFirst GetUeInfoPtr;
2277 if (GetUeInfoPtr(*ueIt)->m_rnti == alloc.m_dci->m_rnti)
2279 NS_LOG_INFO(
"Removed RNTI " << alloc.m_dci->m_rnti
2280 <<
" from active ue list "
2281 "because it has already an HARQ scheduled");
2282 ueInfos.erase(ueIt);
2290 if (!ueInfos.empty())
2296 activeDlUe->erase(it);
2302 NS_ASSERT(dlAssignationStartPoint.m_rbg == 0);
2304 if (dlSymAvail > 0 && !activeDlUe->empty())
2307 DoScheduleDlData(&dlAssignationStartPoint, dlSymAvail, *activeDlUe, allocInfo);
2308 NS_ASSERT(dlSymAvail >= usedDl);
2309 dlSymAvail -= usedDl;
2312 return (dataSymPerSlot - ulAllocations.m_totUlSym) - dlSymAvail;
2329 NS_LOG_FUNCTION(
this);
2335 for (
const auto& itUe : m_ueMap)
2337 ResetExpiredHARQ(itUe.second->m_rnti, &itUe.second->m_dlHarq);
2341 std::vector<DlHarqInfo> dlHarqFeedback;
2346 uint64_t existingSize = m_dlHarqToRetransmit.size();
2349 dlHarqFeedback = MergeHARQ(&m_dlHarqToRetransmit, params.
m_dlHarqInfoList,
"DL");
2351 NS_ASSERT(m_dlHarqToRetransmit.empty());
2352 NS_ASSERT_MSG(existingSize + inSize == dlHarqFeedback.size(),
2353 " existing: " << existingSize <<
" received: " << inSize
2354 <<
" calculated: " << dlHarqFeedback.size());
2356 std::unordered_map<uint16_t, std::set<uint32_t>> feedbacksDup;
2363 for (
auto it = dlHarqFeedback.begin(); it != dlHarqFeedback.end(); )
2365 auto& ueInfo = m_ueMap.find(it->m_rnti)->second;
2366 auto& process = ueInfo->m_dlHarq.Find(it->m_harqProcessId)->second;
2367 NS_LOG_INFO(
"Analyzing feedback for UE " << it->m_rnti <<
" process "
2368 <<
static_cast<uint32_t
>(it->m_harqProcessId));
2369 if (!process.m_active)
2371 NS_LOG_INFO(
"Feedback for UE " << it->m_rnti <<
" process "
2372 <<
static_cast<uint32_t
>(it->m_harqProcessId)
2373 <<
" ignored because process is INACTIVE");
2374 it = dlHarqFeedback.erase(it);
2378 auto itDuplicated = feedbacksDup.find(it->m_rnti);
2379 if (itDuplicated == feedbacksDup.end())
2381 feedbacksDup.insert(std::make_pair(it->m_rnti, std::set<uint32_t>()));
2382 feedbacksDup.at(it->m_rnti).insert(it->m_harqProcessId);
2387 if (itDuplicated->second.find(it->m_harqProcessId) ==
2388 itDuplicated->second.end())
2390 itDuplicated->second.insert(it->m_harqProcessId);
2395 NS_LOG_INFO(
"Feedback for UE "
2396 << it->m_rnti <<
" process "
2397 <<
static_cast<uint32_t
>(it->m_harqProcessId)
2398 <<
" ignored because is a duplicate of another feedback");
2399 it = dlHarqFeedback.erase(it);
2408 ScheduleDl(params, dlHarqFeedback);
2425 NS_LOG_FUNCTION(
this);
2431 for (
const auto& itUe : m_ueMap)
2433 ResetExpiredHARQ(itUe.second->m_rnti, &itUe.second->m_ulHarq);
2437 std::vector<UlHarqInfo> ulHarqFeedback;
2441 uint64_t existingSize = m_ulHarqToRetransmit.size();
2444 ulHarqFeedback = MergeHARQ(&m_ulHarqToRetransmit, params.
m_ulHarqInfoList,
"UL");
2446 NS_ASSERT(m_ulHarqToRetransmit.empty());
2447 NS_ASSERT_MSG(existingSize + inSize == ulHarqFeedback.size(),
2448 " existing: " << existingSize <<
" received: " << inSize
2449 <<
" calculated: " << ulHarqFeedback.size());
2452 for (
auto it = ulHarqFeedback.begin(); it != ulHarqFeedback.end(); )
2454 auto& ueInfo = m_ueMap.find(it->m_rnti)->second;
2455 auto& process = ueInfo->m_ulHarq.Find(it->m_harqProcessId)->second;
2456 if (!process.m_active)
2458 NS_LOG_INFO(
"Feedback for UE " << it->m_rnti <<
" process "
2459 <<
static_cast<uint32_t
>(it->m_harqProcessId)
2460 <<
" ignored because process is INACTIVE");
2461 it = ulHarqFeedback.erase(it);
2472 ScheduleUl(params, ulHarqFeedback);
2485 NS_LOG_FUNCTION(
this);
2488 for (
const auto& ue : params.
m_srList)
2490 NS_LOG_INFO(
"UE " << ue <<
" asked for a SR ");
2492 auto it = std::find(m_srList.begin(), m_srList.end(), ue);
2493 if (it == m_srList.end())
2495 m_srList.push_back(ue);
2498 NS_ASSERT(m_srList.size() >= params.
m_srList.size());
2517NrMacSchedulerNs3::DoScheduleUlMsg3(PointInFTPlane* sPoint,
2521 NS_LOG_FUNCTION(
this);
2522 NS_ASSERT(sPoint->m_rbg == 0);
2524 uint8_t symAvailBeforeRach = symAvail;
2526 for (
const auto& rachReq : m_rachList)
2528 uint8_t allocSymbols = 0;
2529 uint16_t tbSizeBits = 0;
2532 while ((tbSizeBits < rachReq.m_estimatedSize) && (symAvail - allocSymbols > 0))
2536 GetUlAmc()->CalculateTbSize(m_rachUlGrantMcs,
2542 if (tbSizeBits < rachReq.m_estimatedSize)
2548 sPoint->m_sym -= allocSymbols;
2554 Ptr<const ComplexMatrixArray> precMats{
nullptr};
2555 std::shared_ptr<DciInfoElementTdma> ulMsg3Dci =
2556 std::make_shared<DciInfoElementTdma>(rachReq.m_rnti,
2572 ulMsg3Dci->m_rbgBitmask = rbgBitmask;
2573 symAvail -= allocSymbols;
2575 NS_LOG_INFO(
" UL grant allocated to RNTI "
2576 << ulMsg3Dci->m_rnti <<
" in slot: " << slotAlloc->
m_sfnSf <<
" symStart "
2577 << +ulMsg3Dci->m_symStart <<
" symEnd " << +ulMsg3Dci->m_numSym
2579 << (uint16_t) + ulMsg3Dci->m_mcs <<
" tbSize in bytes:" << +ulMsg3Dci->m_tbSize
2580 <<
" BWP index: " << +ulMsg3Dci->m_bwpIndex
2581 <<
" RBG bitmask:" << +ulMsg3Dci->m_rbgBitmask.size());
2583 VarTtiAllocInfo slotInfo(ulMsg3Dci);
2588 return (symAvailBeforeRach - symAvail);
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 ¶ms)=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 UlSBCQIReported(uint32_t expirationTime, uint32_t tbs, const NrMacSchedSapProvider::SchedUlCqiInfoReqParameters ¶ms, 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 ¶ms) 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 ¶ms) 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 ¶ms) override
Release an UE.
void DoSchedUlTriggerReq(const NrMacSchedSapProvider::SchedUlTriggerReqParameters ¶ms) 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...
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.
void SetSrsCtrlSyms(uint8_t v)
Set the number of UL SRS symbols.
void DoCschedLcReleaseReq(const NrMacCschedSapProvider::CschedLcReleaseReqParameters ¶ms) 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 ¶ms) override
Configure a logical channel for a UE.
void DoSchedDlCqiInfoReq(const NrMacSchedSapProvider::SchedDlCqiInfoReqParameters ¶ms) 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 ¶ms) override
Received a UL CQI message.
uint16_t GetBwpId() const
Get the bwp id of this MAC.
void DoCschedCellConfigReq(const NrMacCschedSapProvider::CschedCellConfigReqParameters ¶ms) 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 ¶ms) override
RLC informs of DL data.
void DoSchedDlRachInfoReq(const NrMacSchedSapProvider::SchedDlRachInfoReqParameters ¶ms) 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 ¶ms) override
Decide how to fill the frequency/time of a DL slot.
void DoSchedUlMacCtrlInfoReq(const NrMacSchedSapProvider::SchedUlMacCtrlInfoReqParameters ¶ms) 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.
virtual LCPtr CreateLC(const nr::LogicalChannelConfigListElement_s &config) const
Create a logical channel starting from a configuration.
uint16_t GetBandwidthInRbg() const
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 ¶ms) 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 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.
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.
uint64_t GetEncoding() const
Get encoding for this SfnSf.
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.
@ 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.
The SchedDlCqiInfoReqParameters struct.
std::vector< struct DlCqiInfo > m_cqiList
cqi list
std::vector< struct nr::RachListElement_s > m_rachList
RACH list.
uint16_t m_rnti
The RNTI identifying the UE.
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.
The SchedUlCqiInfoReqParameters struct.
struct UlCqiInfo m_ulCqi
UL CQI.
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.
std::deque< VarTtiAllocInfo > m_varTtiAllocInfo
queue of allocations
See section 4.3.4 logicalChannelConfigListElement.
uint8_t m_logicalChannelGroup
logical channel group