A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
cqa-ff-mac-scheduler.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2012 Centre Tecnologic de Telecomunicacions de Catalunya (CTTC)
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 * Authors: Biljana Bojovic <bbojovic@cttc.es>, Nicola Baldo<nbaldo@cttc.es>.
7 *
8 * Note:
9 * Implementation is using many common scheduler functionalities in its
10 * original version implemented by Marco Miozzo<mmiozzo@cttc.es> in
11 * Proportional Fair and Round Robin schedulers implementations.
12 */
13
15
16#include "ff-mac-common.h"
17#include "lte-amc.h"
19
20#include "ns3/boolean.h"
21#include "ns3/integer.h"
22#include "ns3/log.h"
23#include "ns3/math.h"
24#include "ns3/pointer.h"
25#include "ns3/simulator.h"
26#include "ns3/string.h"
27
28#include <cfloat>
29#include <set>
30#include <stdexcept>
31
32namespace ns3
33{
34
35NS_LOG_COMPONENT_DEFINE("CqaFfMacScheduler");
36
37/// CGA Type 0 Allocation
38static const int CqaType0AllocationRbg[4] = {
39 10, // RBG size 1
40 26, // RBG size 2
41 63, // RBG size 3
42 110, // RBG size 4
43}; // see table 7.1.6.1-1 of 36.213
44
45NS_OBJECT_ENSURE_REGISTERED(CqaFfMacScheduler);
46
47/// qos_rb_and_CQI_assigned_to_lc
49{
50 uint16_t resource_block_index; ///< Resource block indexHOL_GROUP_index
51 uint8_t cqi_value_for_lc; ///< CQI indicator value
52};
53
54/**
55 * CQI value comparator function
56 * @param key1 the first item
57 * @param key2 the second item
58 * @returns true if the first item is > the second item
59 */
60bool
61CQIValueDescComparator(uint8_t key1, uint8_t key2)
62{
63 return key1 > key2;
64}
65
66/**
67 * CGA group comparator function
68 * @param key1 the first item
69 * @param key2 the second item
70 * @returns true if the first item is > the second item
71 */
72bool
73CqaGroupDescComparator(int key1, int key2)
74{
75 return key1 > key2;
76}
77
78/// CQI value typedef
79typedef uint8_t CQI_value;
80/// RBG index typedef
81typedef int RBG_index;
82/// HOL group typedef
83typedef int HOL_group;
84
85/// CQI value map typedef
86typedef std::map<CQI_value, LteFlowId_t, bool (*)(uint8_t, uint8_t)> t_map_CQIToUE; // sorted
87/// RBG index map typedef
88typedef std::map<RBG_index, t_map_CQIToUE> t_map_RBGToCQIsSorted;
89/// HOL group map typedef
90typedef std::map<HOL_group, t_map_RBGToCQIsSorted> t_map_HOLGroupToRBGs;
91
92/// CQI value map iterator typedef
93typedef std::map<CQI_value, LteFlowId_t, bool (*)(uint8_t, uint8_t)>::iterator
94 t_it_CQIToUE; // sorted
95/// RBG index map iterator typedef
96typedef std::map<RBG_index, t_map_CQIToUE>::iterator t_it_RBGToCQIsSorted;
97/// HOL group map iterator typedef
98typedef std::map<HOL_group, t_map_RBGToCQIsSorted>::iterator t_it_HOLGroupToRBGs;
99
100/// HOL group map typedef
101typedef std::multimap<HOL_group, std::set<LteFlowId_t>, bool (*)(int, int)> t_map_HOLgroupToUEs;
102/// HOL group multi map iterator typedef
103typedef std::map<HOL_group, std::set<LteFlowId_t>>::iterator t_it_HOLgroupToUEs;
104
105// typedef std::map<RBG_index,CQI_value> map_RBG_to_CQI;
106// typedef std::map<LteFlowId_t,map_RBG_to_CQI> map_flowId_to_CQI_map;
107
108/**
109 * CQA key comparator
110 * @param key1 the first item
111 * @param key2 the second item
112 * @returns true if the first item > the second item
113 */
114bool
115CqaKeyDescComparator(uint16_t key1, uint16_t key2)
116{
117 return key1 > key2;
118}
119
121 : m_cschedSapUser(nullptr),
122 m_schedSapUser(nullptr),
123 m_timeWindow(99.0),
124 m_nextRntiUl(0)
125{
129 m_ffrSapProvider = nullptr;
131}
132
137
138void
153
154TypeId
156{
157 static TypeId tid =
158 TypeId("ns3::CqaFfMacScheduler")
160 .SetGroupName("Lte")
161 .AddConstructor<CqaFfMacScheduler>()
162 .AddAttribute("CqiTimerThreshold",
163 "The number of TTIs a CQI is valid (default 1000 - 1 sec.)",
164 UintegerValue(1000),
167 .AddAttribute("CqaMetric",
168 "CqaFfMacScheduler metric type that can be: CqaFf, CqaPf",
169 StringValue("CqaFf"),
172 .AddAttribute("HarqEnabled",
173 "Activate/Deactivate the HARQ [by default is active].",
174 BooleanValue(true),
177 .AddAttribute("UlGrantMcs",
178 "The MCS of the UL grant, must be [0..15] (default 0)",
179 UintegerValue(0),
182 return tid;
183}
184
185void
190
191void
196
202
208
209void
214
220
221void
233
234void
237{
238 NS_LOG_FUNCTION(this << " RNTI " << params.m_rnti << " txMode "
239 << (uint16_t)params.m_transmissionMode);
240 auto it = m_uesTxMode.find(params.m_rnti);
241 if (it == m_uesTxMode.end())
242 {
243 m_uesTxMode.insert(std::pair<uint16_t, uint8_t>(params.m_rnti, params.m_transmissionMode));
244 // generate HARQ buffers
245 m_dlHarqCurrentProcessId.insert(std::pair<uint16_t, uint8_t>(params.m_rnti, 0));
246 DlHarqProcessesStatus_t dlHarqPrcStatus;
247 dlHarqPrcStatus.resize(8, 0);
248 m_dlHarqProcessesStatus[params.m_rnti] = dlHarqPrcStatus;
249 DlHarqProcessesTimer_t dlHarqProcessesTimer;
250 dlHarqProcessesTimer.resize(8, 0);
251 m_dlHarqProcessesTimer[params.m_rnti] = dlHarqProcessesTimer;
253 dlHarqdci.resize(8);
254 m_dlHarqProcessesDciBuffer[params.m_rnti] = dlHarqdci;
255 DlHarqRlcPduListBuffer_t dlHarqRlcPdu;
256 dlHarqRlcPdu.resize(2);
257 dlHarqRlcPdu.at(0).resize(8);
258 dlHarqRlcPdu.at(1).resize(8);
259 m_dlHarqProcessesRlcPduListBuffer[params.m_rnti] = dlHarqRlcPdu;
260 m_ulHarqCurrentProcessId.insert(std::pair<uint16_t, uint8_t>(params.m_rnti, 0));
261 UlHarqProcessesStatus_t ulHarqPrcStatus;
262 ulHarqPrcStatus.resize(8, 0);
263 m_ulHarqProcessesStatus[params.m_rnti] = ulHarqPrcStatus;
265 ulHarqdci.resize(8);
266 m_ulHarqProcessesDciBuffer[params.m_rnti] = ulHarqdci;
267 }
268 else
269 {
270 (*it).second = params.m_transmissionMode;
271 }
272}
273
274void
277{
278 NS_LOG_FUNCTION(this << " New LC, rnti: " << params.m_rnti);
279
280 NS_LOG_FUNCTION("LC configuration. Number of LCs:" << params.m_logicalChannelConfigList.size());
281
282 // m_reconfigureFlat indicates if this is a reconfiguration or new UE is added, table 4.1.5 in
283 // LTE MAC scheduler specification
284 if (params.m_reconfigureFlag)
285 {
286 for (auto lcit = params.m_logicalChannelConfigList.begin();
287 lcit != params.m_logicalChannelConfigList.end();
288 lcit++)
289 {
290 LteFlowId_t flowid = LteFlowId_t(params.m_rnti, lcit->m_logicalChannelIdentity);
291
293 {
294 NS_LOG_ERROR("UE logical channels can not be reconfigured because it was not "
295 "configured before.");
296 }
297 else
298 {
299 m_ueLogicalChannelsConfigList.find(flowid)->second = *lcit;
300 }
301 }
302
303 } // else new UE is added
304 else
305 {
306 for (auto lcit = params.m_logicalChannelConfigList.begin();
307 lcit != params.m_logicalChannelConfigList.end();
308 lcit++)
309 {
310 LteFlowId_t flowId = LteFlowId_t(params.m_rnti, lcit->m_logicalChannelIdentity);
312 std::pair<LteFlowId_t, LogicalChannelConfigListElement_s>(flowId, *lcit));
313 }
314 }
315
316 for (std::size_t i = 0; i < params.m_logicalChannelConfigList.size(); i++)
317 {
318 auto it = m_flowStatsDl.find(params.m_rnti);
319
320 if (it == m_flowStatsDl.end())
321 {
322 double tbrDlInBytes =
323 params.m_logicalChannelConfigList.at(i).m_eRabGuaranteedBitrateDl / 8; // byte/s
324 double tbrUlInBytes =
325 params.m_logicalChannelConfigList.at(i).m_eRabGuaranteedBitrateUl / 8; // byte/s
326
327 CqasFlowPerf_t flowStatsDl;
328 flowStatsDl.flowStart = Simulator::Now();
329 flowStatsDl.totalBytesTransmitted = 0;
330 flowStatsDl.lastTtiBytesTransmitted = 0;
331 flowStatsDl.lastAveragedThroughput = 1;
332 flowStatsDl.secondLastAveragedThroughput = 1;
333 flowStatsDl.targetThroughput = tbrDlInBytes;
334 m_flowStatsDl.insert(std::pair<uint16_t, CqasFlowPerf_t>(params.m_rnti, flowStatsDl));
335 CqasFlowPerf_t flowStatsUl;
336 flowStatsUl.flowStart = Simulator::Now();
337 flowStatsUl.totalBytesTransmitted = 0;
338 flowStatsUl.lastTtiBytesTransmitted = 0;
339 flowStatsUl.lastAveragedThroughput = 1;
340 flowStatsUl.secondLastAveragedThroughput = 1;
341 flowStatsUl.targetThroughput = tbrUlInBytes;
342 m_flowStatsUl.insert(std::pair<uint16_t, CqasFlowPerf_t>(params.m_rnti, flowStatsUl));
343 }
344 else
345 {
346 // update GBR from UeManager::SetupDataRadioBearer ()
347 double tbrDlInBytes =
348 params.m_logicalChannelConfigList.at(i).m_eRabGuaranteedBitrateDl / 8; // byte/s
349 double tbrUlInBytes =
350 params.m_logicalChannelConfigList.at(i).m_eRabGuaranteedBitrateUl / 8; // byte/s
351 m_flowStatsDl[(*it).first].targetThroughput = tbrDlInBytes;
352 m_flowStatsUl[(*it).first].targetThroughput = tbrUlInBytes;
353 }
354 }
355}
356
357void
360{
361 NS_LOG_FUNCTION(this);
362
363 for (auto it = params.m_logicalChannelIdentity.begin();
364 it != params.m_logicalChannelIdentity.end();
365 it++)
366 {
367 LteFlowId_t flowId = LteFlowId_t(params.m_rnti, *it);
368
369 // find the logical channel with the same Logical Channel Identity in the current list,
370 // release it
372 {
373 m_ueLogicalChannelsConfigList.erase(flowId);
374 }
375 else
376 {
377 NS_FATAL_ERROR("Logical channels cannot be released because it can not be found in the "
378 "list of active LCs");
379 }
380 }
381
382 for (std::size_t i = 0; i < params.m_logicalChannelIdentity.size(); i++)
383 {
384 auto it = m_rlcBufferReq.begin();
385 while (it != m_rlcBufferReq.end())
386 {
387 if (((*it).first.m_rnti == params.m_rnti) &&
388 ((*it).first.m_lcId == params.m_logicalChannelIdentity.at(i)))
389 {
390 auto temp = it;
391 it++;
392 m_rlcBufferReq.erase(temp);
393 }
394 else
395 {
396 it++;
397 }
398 }
399 }
400}
401
402void
405{
406 NS_LOG_FUNCTION(this);
407
408 for (int i = 0; i < MAX_LC_LIST; i++)
409 {
410 LteFlowId_t flowId = LteFlowId_t(params.m_rnti, i);
411 // find the logical channel with the same Logical Channel Identity in the current list,
412 // release it
414 {
415 m_ueLogicalChannelsConfigList.erase(flowId);
416 }
417 }
418
419 m_uesTxMode.erase(params.m_rnti);
420 m_dlHarqCurrentProcessId.erase(params.m_rnti);
421 m_dlHarqProcessesStatus.erase(params.m_rnti);
422 m_dlHarqProcessesTimer.erase(params.m_rnti);
423 m_dlHarqProcessesDciBuffer.erase(params.m_rnti);
424 m_dlHarqProcessesRlcPduListBuffer.erase(params.m_rnti);
425 m_ulHarqCurrentProcessId.erase(params.m_rnti);
426 m_ulHarqProcessesStatus.erase(params.m_rnti);
427 m_ulHarqProcessesDciBuffer.erase(params.m_rnti);
428 m_flowStatsDl.erase(params.m_rnti);
429 m_flowStatsUl.erase(params.m_rnti);
430 m_ceBsrRxed.erase(params.m_rnti);
431 auto it = m_rlcBufferReq.begin();
432 while (it != m_rlcBufferReq.end())
433 {
434 if ((*it).first.m_rnti == params.m_rnti)
435 {
436 auto temp = it;
437 it++;
438 m_rlcBufferReq.erase(temp);
439 }
440 else
441 {
442 it++;
443 }
444 }
445 if (m_nextRntiUl == params.m_rnti)
446 {
447 m_nextRntiUl = 0;
448 }
449}
450
451void
454{
455 NS_LOG_FUNCTION(this << params.m_rnti << (uint32_t)params.m_logicalChannelIdentity);
456 // API generated by RLC for updating RLC parameters on a LC (tx and retx queues)
457
458 LteFlowId_t flow(params.m_rnti, params.m_logicalChannelIdentity);
459
460 auto it = m_rlcBufferReq.find(flow);
461
462 if (it == m_rlcBufferReq.end())
463 {
464 m_rlcBufferReq[flow] = params;
465 }
466 else
467 {
468 (*it).second = params;
469 }
470}
471
472void
479
480void
487
488int
490{
491 for (int i = 0; i < 4; i++)
492 {
493 if (dlbandwidth < CqaType0AllocationRbg[i])
494 {
495 return i + 1;
496 }
497 }
498
499 return -1;
500}
501
502unsigned int
504{
505 unsigned int lcActive = 0;
506 for (auto it = m_rlcBufferReq.begin(); it != m_rlcBufferReq.end(); it++)
507 {
508 if (((*it).first.m_rnti == rnti) && (((*it).second.m_rlcTransmissionQueueSize > 0) ||
509 ((*it).second.m_rlcRetransmissionQueueSize > 0) ||
510 ((*it).second.m_rlcStatusPduSize > 0)))
511 {
512 lcActive++;
513 }
514 if ((*it).first.m_rnti > rnti)
515 {
516 break;
517 }
518 }
519 return lcActive;
520}
521
522bool
524{
525 NS_LOG_FUNCTION(this << rnti);
526
527 auto it = m_dlHarqCurrentProcessId.find(rnti);
528 if (it == m_dlHarqCurrentProcessId.end())
529 {
530 NS_FATAL_ERROR("No Process Id found for this RNTI " << rnti);
531 }
532 auto itStat = m_dlHarqProcessesStatus.find(rnti);
533 if (itStat == m_dlHarqProcessesStatus.end())
534 {
535 NS_FATAL_ERROR("No Process Id Statusfound for this RNTI " << rnti);
536 }
537 uint8_t i = (*it).second;
538 do
539 {
540 i = (i + 1) % HARQ_PROC_NUM;
541 } while (((*itStat).second.at(i) != 0) && (i != (*it).second));
542
543 return (*itStat).second.at(i) == 0;
544}
545
546uint8_t
548{
549 NS_LOG_FUNCTION(this << rnti);
550
551 if (!m_harqOn)
552 {
553 return 0;
554 }
555
556 auto it = m_dlHarqCurrentProcessId.find(rnti);
557 if (it == m_dlHarqCurrentProcessId.end())
558 {
559 NS_FATAL_ERROR("No Process Id found for this RNTI " << rnti);
560 }
561 auto itStat = m_dlHarqProcessesStatus.find(rnti);
562 if (itStat == m_dlHarqProcessesStatus.end())
563 {
564 NS_FATAL_ERROR("No Process Id Statusfound for this RNTI " << rnti);
565 }
566 uint8_t i = (*it).second;
567 do
568 {
569 i = (i + 1) % HARQ_PROC_NUM;
570 } while (((*itStat).second.at(i) != 0) && (i != (*it).second));
571 if ((*itStat).second.at(i) == 0)
572 {
573 (*it).second = i;
574 (*itStat).second.at(i) = 1;
575 }
576 else
577 {
578 NS_FATAL_ERROR("No HARQ process available for RNTI "
579 << rnti << " check before update with HarqProcessAvailability");
580 }
581
582 return (*it).second;
583}
584
585void
587{
588 NS_LOG_FUNCTION(this);
589
590 for (auto itTimers = m_dlHarqProcessesTimer.begin(); itTimers != m_dlHarqProcessesTimer.end();
591 itTimers++)
592 {
593 for (uint16_t i = 0; i < HARQ_PROC_NUM; i++)
594 {
595 if ((*itTimers).second.at(i) == HARQ_DL_TIMEOUT)
596 {
597 // reset HARQ process
598
599 NS_LOG_DEBUG(this << " Reset HARQ proc " << i << " for RNTI " << (*itTimers).first);
600 auto itStat = m_dlHarqProcessesStatus.find((*itTimers).first);
601 if (itStat == m_dlHarqProcessesStatus.end())
602 {
603 NS_FATAL_ERROR("No Process Id Status found for this RNTI "
604 << (*itTimers).first);
605 }
606 (*itStat).second.at(i) = 0;
607 (*itTimers).second.at(i) = 0;
608 }
609 else
610 {
611 (*itTimers).second.at(i)++;
612 }
613 }
614 }
615}
616
617void
620{
621 NS_LOG_FUNCTION(this << " Frame no. " << (params.m_sfnSf >> 4) << " subframe no. "
622 << (0xF & params.m_sfnSf));
623 // API generated by RLC for triggering the scheduling of a DL subframe
624 // evaluate the relative channel quality indicator for each UE per each RBG
625 // (since we are using allocation type 0 the small unit of allocation is RBG)
626 // Resource allocation type 0 (see sec 7.1.6.1 of 36.213)
627
629
631 int numberOfRBGs = m_cschedCellConfig.m_dlBandwidth / rbgSize;
632 std::map<uint16_t, std::multimap<uint8_t, qos_rb_and_CQI_assigned_to_lc>>
633 allocationMapPerRntiPerLCId;
634 allocationMapPerRntiPerLCId.clear();
635 bool (*key_function_pointer_groups)(int, int) = CqaGroupDescComparator;
636 t_map_HOLgroupToUEs map_GBRHOLgroupToUE(key_function_pointer_groups);
637 t_map_HOLgroupToUEs map_nonGBRHOLgroupToUE(key_function_pointer_groups);
638 int grouping_parameter = 1000;
639 double tolerance = 1.1;
640 std::map<LteFlowId_t, int> UEtoHOL;
641 std::vector<bool> rbgMap; // global RBGs map
642 uint16_t rbgAllocatedNum = 0;
643 std::set<uint16_t> rntiAllocated;
644 rbgMap.resize(m_cschedCellConfig.m_dlBandwidth / rbgSize, false);
645
647 for (auto it = rbgMap.begin(); it != rbgMap.end(); it++)
648 {
649 if (*it)
650 {
651 rbgAllocatedNum++;
652 }
653 }
654
656
657 // update UL HARQ proc id
658 for (auto itProcId = m_ulHarqCurrentProcessId.begin();
659 itProcId != m_ulHarqCurrentProcessId.end();
660 itProcId++)
661 {
662 (*itProcId).second = ((*itProcId).second + 1) % HARQ_PROC_NUM;
663 }
664
665 // RACH Allocation
666 std::vector<bool> ulRbMap;
667 ulRbMap.resize(m_cschedCellConfig.m_ulBandwidth, false);
669 uint8_t maxContinuousUlBandwidth = 0;
670 uint8_t tmpMinBandwidth = 0;
671 uint16_t ffrRbStartOffset = 0;
672 uint16_t tmpFfrRbStartOffset = 0;
673 uint16_t index = 0;
674
675 for (auto it = ulRbMap.begin(); it != ulRbMap.end(); it++)
676 {
677 if (*it)
678 {
679 if (tmpMinBandwidth > maxContinuousUlBandwidth)
680 {
681 maxContinuousUlBandwidth = tmpMinBandwidth;
682 ffrRbStartOffset = tmpFfrRbStartOffset;
683 }
684 tmpMinBandwidth = 0;
685 }
686 else
687 {
688 if (tmpMinBandwidth == 0)
689 {
690 tmpFfrRbStartOffset = index;
691 }
692 tmpMinBandwidth++;
693 }
694 index++;
695 }
696
697 if (tmpMinBandwidth > maxContinuousUlBandwidth)
698 {
699 maxContinuousUlBandwidth = tmpMinBandwidth;
700 ffrRbStartOffset = tmpFfrRbStartOffset;
701 }
702
704 uint16_t rbStart = 0;
705 rbStart = ffrRbStartOffset;
706 for (auto itRach = m_rachList.begin(); itRach != m_rachList.end(); itRach++)
707 {
709 (*itRach).m_estimatedSize,
710 " Default UL Grant MCS does not allow to send RACH messages");
712 newRar.m_rnti = (*itRach).m_rnti;
713 // DL-RACH Allocation
714 // Ideal: no needs of configuring m_dci
715 // UL-RACH Allocation
716 newRar.m_grant.m_rnti = newRar.m_rnti;
717 newRar.m_grant.m_mcs = m_ulGrantMcs;
718 uint16_t rbLen = 1;
719 uint16_t tbSizeBits = 0;
720 // find lowest TB size that fits UL grant estimated size
721 while ((tbSizeBits < (*itRach).m_estimatedSize) &&
722 (rbStart + rbLen < (ffrRbStartOffset + maxContinuousUlBandwidth)))
723 {
724 rbLen++;
725 tbSizeBits = m_amc->GetUlTbSizeFromMcs(m_ulGrantMcs, rbLen);
726 }
727 if (tbSizeBits < (*itRach).m_estimatedSize)
728 {
729 // no more allocation space: finish allocation
730 break;
731 }
732 newRar.m_grant.m_rbStart = rbStart;
733 newRar.m_grant.m_rbLen = rbLen;
734 newRar.m_grant.m_tbSize = tbSizeBits / 8;
735 newRar.m_grant.m_hopping = false;
736 newRar.m_grant.m_tpc = 0;
737 newRar.m_grant.m_cqiRequest = false;
738 newRar.m_grant.m_ulDelay = false;
739 NS_LOG_INFO(this << " UL grant allocated to RNTI " << (*itRach).m_rnti << " rbStart "
740 << rbStart << " rbLen " << rbLen << " MCS " << m_ulGrantMcs << " tbSize "
741 << newRar.m_grant.m_tbSize);
742 for (uint16_t i = rbStart; i < rbStart + rbLen; i++)
743 {
744 m_rachAllocationMap.at(i) = (*itRach).m_rnti;
745 }
746
747 if (m_harqOn)
748 {
749 // generate UL-DCI for HARQ retransmissions
750 UlDciListElement_s uldci;
751 uldci.m_rnti = newRar.m_rnti;
752 uldci.m_rbLen = rbLen;
753 uldci.m_rbStart = rbStart;
754 uldci.m_mcs = m_ulGrantMcs;
755 uldci.m_tbSize = tbSizeBits / 8;
756 uldci.m_ndi = 1;
757 uldci.m_cceIndex = 0;
758 uldci.m_aggrLevel = 1;
759 uldci.m_ueTxAntennaSelection = 3; // antenna selection OFF
760 uldci.m_hopping = false;
761 uldci.m_n2Dmrs = 0;
762 uldci.m_tpc = 0; // no power control
763 uldci.m_cqiRequest = false; // only period CQI at this stage
764 uldci.m_ulIndex = 0; // TDD parameter
765 uldci.m_dai = 1; // TDD parameter
766 uldci.m_freqHopping = 0;
767 uldci.m_pdcchPowerOffset = 0; // not used
768
769 uint8_t harqId = 0;
770 auto itProcId = m_ulHarqCurrentProcessId.find(uldci.m_rnti);
771 if (itProcId == m_ulHarqCurrentProcessId.end())
772 {
773 NS_FATAL_ERROR("No info find in HARQ buffer for UE " << uldci.m_rnti);
774 }
775 harqId = (*itProcId).second;
776 auto itDci = m_ulHarqProcessesDciBuffer.find(uldci.m_rnti);
777 if (itDci == m_ulHarqProcessesDciBuffer.end())
778 {
779 NS_FATAL_ERROR("Unable to find RNTI entry in UL DCI HARQ buffer for RNTI "
780 << uldci.m_rnti);
781 }
782 (*itDci).second.at(harqId) = uldci;
783 }
784
785 rbStart = rbStart + rbLen;
786 ret.m_buildRarList.push_back(newRar);
787 }
788 m_rachList.clear();
789
790 // Process DL HARQ feedback
792 // retrieve past HARQ retx buffered
793 if (!m_dlInfoListBuffered.empty())
794 {
795 if (!params.m_dlInfoList.empty())
796 {
797 NS_LOG_INFO(this << " Received DL-HARQ feedback");
799 params.m_dlInfoList.begin(),
800 params.m_dlInfoList.end());
801 }
802 }
803 else
804 {
805 if (!params.m_dlInfoList.empty())
806 {
807 m_dlInfoListBuffered = params.m_dlInfoList;
808 }
809 }
810 if (!m_harqOn)
811 {
812 // Ignore HARQ feedback
813 m_dlInfoListBuffered.clear();
814 }
815 std::vector<DlInfoListElement_s> dlInfoListUntxed;
816 for (std::size_t i = 0; i < m_dlInfoListBuffered.size(); i++)
817 {
818 auto itRnti = rntiAllocated.find(m_dlInfoListBuffered.at(i).m_rnti);
819 if (itRnti != rntiAllocated.end())
820 {
821 // RNTI already allocated for retx
822 continue;
823 }
824 auto nLayers = m_dlInfoListBuffered.at(i).m_harqStatus.size();
825 std::vector<bool> retx;
826 NS_LOG_INFO(this << " Processing DLHARQ feedback");
827 if (nLayers == 1)
828 {
829 retx.push_back(m_dlInfoListBuffered.at(i).m_harqStatus.at(0) ==
831 retx.push_back(false);
832 }
833 else
834 {
835 retx.push_back(m_dlInfoListBuffered.at(i).m_harqStatus.at(0) ==
837 retx.push_back(m_dlInfoListBuffered.at(i).m_harqStatus.at(1) ==
839 }
840 if (retx.at(0) || retx.at(1))
841 {
842 // retrieve HARQ process information
843 uint16_t rnti = m_dlInfoListBuffered.at(i).m_rnti;
844 uint8_t harqId = m_dlInfoListBuffered.at(i).m_harqProcessId;
845 NS_LOG_INFO(this << " HARQ retx RNTI " << rnti << " harqId " << (uint16_t)harqId);
846 auto itHarq = m_dlHarqProcessesDciBuffer.find(rnti);
847 if (itHarq == m_dlHarqProcessesDciBuffer.end())
848 {
849 NS_FATAL_ERROR("No info find in HARQ buffer for UE " << rnti);
850 }
851
852 DlDciListElement_s dci = (*itHarq).second.at(harqId);
853 int rv = 0;
854 if (dci.m_rv.size() == 1)
855 {
856 rv = dci.m_rv.at(0);
857 }
858 else
859 {
860 rv = (dci.m_rv.at(0) > dci.m_rv.at(1) ? dci.m_rv.at(0) : dci.m_rv.at(1));
861 }
862
863 if (rv == 3)
864 {
865 // maximum number of retx reached -> drop process
866 NS_LOG_INFO("Maximum number of retransmissions reached -> drop process");
867 auto it = m_dlHarqProcessesStatus.find(rnti);
868 if (it == m_dlHarqProcessesStatus.end())
869 {
870 NS_LOG_ERROR("No info find in HARQ buffer for UE (might change eNB) "
871 << m_dlInfoListBuffered.at(i).m_rnti);
872 }
873 (*it).second.at(harqId) = 0;
874 auto itRlcPdu = m_dlHarqProcessesRlcPduListBuffer.find(rnti);
875 if (itRlcPdu == m_dlHarqProcessesRlcPduListBuffer.end())
876 {
877 NS_FATAL_ERROR("Unable to find RlcPdcList in HARQ buffer for RNTI "
878 << m_dlInfoListBuffered.at(i).m_rnti);
879 }
880 for (std::size_t k = 0; k < (*itRlcPdu).second.size(); k++)
881 {
882 (*itRlcPdu).second.at(k).at(harqId).clear();
883 }
884 continue;
885 }
886 // check the feasibility of retransmitting on the same RBGs
887 // translate the DCI to Spectrum framework
888 std::vector<int> dciRbg;
889 uint32_t mask = 0x1;
890 NS_LOG_INFO("Original RBGs " << dci.m_rbBitmap << " rnti " << dci.m_rnti);
891 for (int j = 0; j < 32; j++)
892 {
893 if (((dci.m_rbBitmap & mask) >> j) == 1)
894 {
895 dciRbg.push_back(j);
896 NS_LOG_INFO("\t" << j);
897 }
898 mask = (mask << 1);
899 }
900 bool free = true;
901 for (std::size_t j = 0; j < dciRbg.size(); j++)
902 {
903 if (rbgMap.at(dciRbg.at(j)))
904 {
905 free = false;
906 break;
907 }
908 }
909 if (free)
910 {
911 // use the same RBGs for the retx
912 // reserve RBGs
913 for (std::size_t j = 0; j < dciRbg.size(); j++)
914 {
915 rbgMap.at(dciRbg.at(j)) = true;
916 NS_LOG_INFO("RBG " << dciRbg.at(j) << " assigned");
917 rbgAllocatedNum++;
918 }
919
920 NS_LOG_INFO(this << " Send retx in the same RBGs");
921 }
922 else
923 {
924 // find RBGs for sending HARQ retx
925 uint8_t j = 0;
926 uint8_t rbgId = (dciRbg.at(dciRbg.size() - 1) + 1) % numberOfRBGs;
927 uint8_t startRbg = dciRbg.at(dciRbg.size() - 1);
928 std::vector<bool> rbgMapCopy = rbgMap;
929 while ((j < dciRbg.size()) && (startRbg != rbgId))
930 {
931 if (!rbgMapCopy.at(rbgId))
932 {
933 rbgMapCopy.at(rbgId) = true;
934 dciRbg.at(j) = rbgId;
935 j++;
936 }
937 rbgId = (rbgId + 1) % numberOfRBGs;
938 }
939 if (j == dciRbg.size())
940 {
941 // find new RBGs -> update DCI map
942 uint32_t rbgMask = 0;
943 for (std::size_t k = 0; k < dciRbg.size(); k++)
944 {
945 rbgMask = rbgMask + (0x1 << dciRbg.at(k));
946 rbgAllocatedNum++;
947 }
948 dci.m_rbBitmap = rbgMask;
949 rbgMap = rbgMapCopy;
950 NS_LOG_INFO(this << " Move retx in RBGs " << dciRbg.size());
951 }
952 else
953 {
954 // HARQ retx cannot be performed on this TTI -> store it
955 dlInfoListUntxed.push_back(m_dlInfoListBuffered.at(i));
956 NS_LOG_INFO(this << " No resource for this retx -> buffer it");
957 }
958 }
959 // retrieve RLC PDU list for retx TBsize and update DCI
961 auto itRlcPdu = m_dlHarqProcessesRlcPduListBuffer.find(rnti);
962 if (itRlcPdu == m_dlHarqProcessesRlcPduListBuffer.end())
963 {
964 NS_FATAL_ERROR("Unable to find RlcPdcList in HARQ buffer for RNTI " << rnti);
965 }
966 for (std::size_t j = 0; j < nLayers; j++)
967 {
968 if (retx.at(j))
969 {
970 if (j >= dci.m_ndi.size())
971 {
972 // for avoiding errors in MIMO transient phases
973 dci.m_ndi.push_back(0);
974 dci.m_rv.push_back(0);
975 dci.m_mcs.push_back(0);
976 dci.m_tbsSize.push_back(0);
977 NS_LOG_INFO(this << " layer " << (uint16_t)j
978 << " no txed (MIMO transition)");
979 }
980 else
981 {
982 dci.m_ndi.at(j) = 0;
983 dci.m_rv.at(j)++;
984 (*itHarq).second.at(harqId).m_rv.at(j)++;
985 NS_LOG_INFO(this << " layer " << (uint16_t)j << " RV "
986 << (uint16_t)dci.m_rv.at(j));
987 }
988 }
989 else
990 {
991 // empty TB of layer j
992 dci.m_ndi.at(j) = 0;
993 dci.m_rv.at(j) = 0;
994 dci.m_mcs.at(j) = 0;
995 dci.m_tbsSize.at(j) = 0;
996 NS_LOG_INFO(this << " layer " << (uint16_t)j << " no retx");
997 }
998 }
999 for (std::size_t k = 0; k < (*itRlcPdu).second.at(0).at(dci.m_harqProcess).size(); k++)
1000 {
1001 std::vector<RlcPduListElement_s> rlcPduListPerLc;
1002 for (std::size_t j = 0; j < nLayers; j++)
1003 {
1004 if (retx.at(j))
1005 {
1006 if (j < dci.m_ndi.size())
1007 {
1008 NS_LOG_INFO(" layer " << (uint16_t)j << " tb size "
1009 << dci.m_tbsSize.at(j));
1010 rlcPduListPerLc.push_back(
1011 (*itRlcPdu).second.at(j).at(dci.m_harqProcess).at(k));
1012 }
1013 }
1014 else
1015 { // if no retx needed on layer j, push an RlcPduListElement_s object with
1016 // m_size=0 to keep the size of rlcPduListPerLc vector = 2 in case of MIMO
1017 NS_LOG_INFO(" layer " << (uint16_t)j << " tb size " << dci.m_tbsSize.at(j));
1018 RlcPduListElement_s emptyElement;
1019 emptyElement.m_logicalChannelIdentity = (*itRlcPdu)
1020 .second.at(j)
1021 .at(dci.m_harqProcess)
1022 .at(k)
1023 .m_logicalChannelIdentity;
1024 emptyElement.m_size = 0;
1025 rlcPduListPerLc.push_back(emptyElement);
1026 }
1027 }
1028
1029 if (!rlcPduListPerLc.empty())
1030 {
1031 newEl.m_rlcPduList.push_back(rlcPduListPerLc);
1032 }
1033 }
1034 newEl.m_rnti = rnti;
1035 newEl.m_dci = dci;
1036 (*itHarq).second.at(harqId).m_rv = dci.m_rv;
1037 // refresh timer
1038 auto itHarqTimer = m_dlHarqProcessesTimer.find(rnti);
1039 if (itHarqTimer == m_dlHarqProcessesTimer.end())
1040 {
1041 NS_FATAL_ERROR("Unable to find HARQ timer for RNTI " << (uint16_t)rnti);
1042 }
1043 (*itHarqTimer).second.at(harqId) = 0;
1044 ret.m_buildDataList.push_back(newEl);
1045 rntiAllocated.insert(rnti);
1046 }
1047 else
1048 {
1049 // update HARQ process status
1050 NS_LOG_INFO(this << " HARQ received ACK for UE " << m_dlInfoListBuffered.at(i).m_rnti);
1051 auto it = m_dlHarqProcessesStatus.find(m_dlInfoListBuffered.at(i).m_rnti);
1052 if (it == m_dlHarqProcessesStatus.end())
1053 {
1054 NS_FATAL_ERROR("No info find in HARQ buffer for UE "
1055 << m_dlInfoListBuffered.at(i).m_rnti);
1056 }
1057 (*it).second.at(m_dlInfoListBuffered.at(i).m_harqProcessId) = 0;
1058 auto itRlcPdu =
1060 if (itRlcPdu == m_dlHarqProcessesRlcPduListBuffer.end())
1061 {
1062 NS_FATAL_ERROR("Unable to find RlcPdcList in HARQ buffer for RNTI "
1063 << m_dlInfoListBuffered.at(i).m_rnti);
1064 }
1065 for (std::size_t k = 0; k < (*itRlcPdu).second.size(); k++)
1066 {
1067 (*itRlcPdu).second.at(k).at(m_dlInfoListBuffered.at(i).m_harqProcessId).clear();
1068 }
1069 }
1070 }
1071 m_dlInfoListBuffered.clear();
1072 m_dlInfoListBuffered = dlInfoListUntxed;
1073
1074 if (rbgAllocatedNum == numberOfRBGs)
1075 {
1076 // all the RBGs are already allocated -> exit
1077 if (!ret.m_buildDataList.empty() || !ret.m_buildRarList.empty())
1078 {
1080 }
1081 return;
1082 }
1083
1084 for (auto itLogicalChannels = m_ueLogicalChannelsConfigList.begin();
1085 itLogicalChannels != m_ueLogicalChannelsConfigList.end();
1086 itLogicalChannels++)
1087 {
1088 auto itRnti = rntiAllocated.find(itLogicalChannels->first.m_rnti);
1089 if ((itRnti != rntiAllocated.end()) ||
1090 (!HarqProcessAvailability(itLogicalChannels->first.m_rnti)))
1091 {
1092 // UE already allocated for HARQ or without HARQ process available -> drop it
1093 if (itRnti != rntiAllocated.end())
1094 {
1095 NS_LOG_DEBUG(this << " RNTI discarded for HARQ tx"
1096 << (uint16_t)(itLogicalChannels->first.m_rnti));
1097 }
1098 if (!HarqProcessAvailability(itLogicalChannels->first.m_rnti))
1099 {
1100 NS_LOG_DEBUG(this << " RNTI discarded for HARQ id"
1101 << (uint16_t)(itLogicalChannels->first.m_rnti));
1102 }
1103 continue;
1104 }
1105
1106 auto itRlcBufferReq = m_rlcBufferReq.find(itLogicalChannels->first);
1107 if (itRlcBufferReq == m_rlcBufferReq.end())
1108 {
1109 continue;
1110 }
1111
1112 int group = -1;
1113 int delay = 0;
1114
1115 if (itRlcBufferReq->second.m_rlcRetransmissionQueueSize > 0)
1116 {
1117 delay = itRlcBufferReq->second.m_rlcRetransmissionHolDelay;
1118 group = delay / grouping_parameter;
1119 }
1120 else if (itRlcBufferReq->second.m_rlcTransmissionQueueSize > 0)
1121 {
1122 delay = itRlcBufferReq->second.m_rlcTransmissionQueueHolDelay;
1123 group = delay / grouping_parameter;
1124 }
1125 else
1126 {
1127 continue;
1128 }
1129
1130 UEtoHOL.insert(std::pair<LteFlowId_t, int>(itLogicalChannels->first, delay));
1131
1132 if (itLogicalChannels->second.m_qosBearerType ==
1134 {
1135 if (map_nonGBRHOLgroupToUE.count(group) == 0)
1136 {
1137 std::set<LteFlowId_t> v;
1138 v.insert(itRlcBufferReq->first);
1139 map_nonGBRHOLgroupToUE.insert(std::pair<int, std::set<LteFlowId_t>>(group, v));
1140 }
1141 else
1142 {
1143 map_nonGBRHOLgroupToUE.find(group)->second.insert(itRlcBufferReq->first);
1144 }
1145 }
1146 else if (itLogicalChannels->second.m_qosBearerType ==
1148 itLogicalChannels->second.m_qosBearerType ==
1150 {
1151 if (map_GBRHOLgroupToUE.count(group) == 0)
1152 {
1153 std::set<LteFlowId_t> v;
1154 v.insert(itRlcBufferReq->first);
1155 map_GBRHOLgroupToUE.insert(std::pair<int, std::set<LteFlowId_t>>(group, v));
1156 }
1157 else
1158 {
1159 map_GBRHOLgroupToUE.find(group)->second.insert(itRlcBufferReq->first);
1160 }
1161 }
1162 };
1163
1164 // Prepare data for the scheduling mechanism
1165 // map: UE, to the amount of traffic they have to transfer
1166 std::map<LteFlowId_t, int> UeToAmountOfDataToTransfer;
1167 // Initialize the map per UE, how much resources is already assigned to the user
1168 std::map<LteFlowId_t, int> UeToAmountOfAssignedResources;
1169 // prepare values to calculate FF metric, this metric will be the same for all flows(logical
1170 // channels) that belong to the same RNTI
1171 std::map<uint16_t, uint8_t> sbCqiSum;
1172
1173 for (auto itrbr = m_rlcBufferReq.begin(); itrbr != m_rlcBufferReq.end(); itrbr++)
1174 {
1175 LteFlowId_t flowId = itrbr->first; // Prepare data for the scheduling mechanism
1176 // check first the channel conditions for this UE, if CQI!=0
1177 auto itCqi = m_a30CqiRxed.find((*itrbr).first.m_rnti);
1178 auto itTxMode = m_uesTxMode.find((*itrbr).first.m_rnti);
1179 if (itTxMode == m_uesTxMode.end())
1180 {
1181 NS_FATAL_ERROR("No Transmission Mode info on user " << (*itrbr).first.m_rnti);
1182 }
1183 auto nLayer = TransmissionModesLayers::TxMode2LayerNum((*itTxMode).second);
1184
1185 uint8_t cqiSum = 0;
1186 for (int k = 0; k < numberOfRBGs; k++)
1187 {
1188 for (uint8_t j = 0; j < nLayer; j++)
1189 {
1190 if (itCqi == m_a30CqiRxed.end())
1191 {
1192 cqiSum += 1; // no info on this user -> lowest MCS
1193 }
1194 else
1195 {
1196 cqiSum += (*itCqi).second.m_higherLayerSelected.at(k).m_sbCqi.at(j);
1197 }
1198 }
1199 }
1200
1201 if (cqiSum == 0)
1202 {
1203 NS_LOG_INFO("Skip this flow, CQI==0, rnti:" << (*itrbr).first.m_rnti);
1204 continue;
1205 }
1206
1207 // map: UE, to the amount of traffic they have to transfer
1208 int amountOfDataToTransfer =
1209 8 * ((int)m_rlcBufferReq.find(flowId)->second.m_rlcRetransmissionQueueSize +
1210 (int)m_rlcBufferReq.find(flowId)->second.m_rlcTransmissionQueueSize);
1211
1212 UeToAmountOfDataToTransfer.insert(
1213 std::pair<LteFlowId_t, int>(flowId, amountOfDataToTransfer));
1214 UeToAmountOfAssignedResources.insert(std::pair<LteFlowId_t, int>(flowId, 0));
1215
1216 uint8_t sum = 0;
1217 for (int i = 0; i < numberOfRBGs; i++)
1218 {
1219 auto itCqi = m_a30CqiRxed.find((*itrbr).first.m_rnti);
1220 auto itTxMode = m_uesTxMode.find((*itrbr).first.m_rnti);
1221 if (itTxMode == m_uesTxMode.end())
1222 {
1223 NS_FATAL_ERROR("No Transmission Mode info on user " << (*itrbr).first.m_rnti);
1224 }
1225 auto nLayer = TransmissionModesLayers::TxMode2LayerNum((*itTxMode).second);
1226 std::vector<uint8_t> sbCqis;
1227 if (itCqi == m_a30CqiRxed.end())
1228 {
1229 sbCqis = std::vector<uint8_t>(nLayer, 1); // start with lowest value
1230 }
1231 else
1232 {
1233 sbCqis = (*itCqi).second.m_higherLayerSelected.at(i).m_sbCqi;
1234 }
1235
1236 uint8_t cqi1 = sbCqis.at(0);
1237 uint8_t cqi2 = 0;
1238 if (sbCqis.size() > 1)
1239 {
1240 cqi2 = sbCqis.at(1);
1241 }
1242
1243 uint8_t sbCqi = 0;
1244 if ((cqi1 > 0) ||
1245 (cqi2 > 0)) // CQI == 0 means "out of range" (see table 7.2.3-1 of 36.213)
1246 {
1247 for (uint8_t k = 0; k < nLayer; k++)
1248 {
1249 if (sbCqis.size() > k)
1250 {
1251 sbCqi = sbCqis.at(k);
1252 }
1253 else
1254 {
1255 // no info on this subband
1256 sbCqi = 0;
1257 }
1258 sum += sbCqi;
1259 }
1260 } // end if cqi
1261 } // end of rbgNum
1262
1263 sbCqiSum.insert(std::pair<uint16_t, uint8_t>((*itrbr).first.m_rnti, sum));
1264 }
1265
1266 // availableRBGs - set that contains indexes of available resource block groups
1267 std::set<int> availableRBGs;
1268 for (int i = 0; i < numberOfRBGs; i++)
1269 {
1270 if (!rbgMap.at(i))
1271 {
1272 availableRBGs.insert(i);
1273 }
1274 }
1275
1276 auto itGBRgroups = map_GBRHOLgroupToUE.begin();
1277 auto itnonGBRgroups = map_nonGBRHOLgroupToUE.begin();
1278
1279 // while there are more resources available, loop through the users that are grouped by HOL
1280 // value
1281 while (!availableRBGs.empty())
1282 {
1283 if (UeToAmountOfDataToTransfer.empty())
1284 {
1285 NS_LOG_INFO("No UEs to be scheduled (no data or CQI==0),");
1286 break;
1287 }
1288 std::set<LteFlowId_t> vUEs;
1289 t_it_HOLgroupToUEs itCurrentGroup;
1290
1291 if (itGBRgroups != map_GBRHOLgroupToUE.end())
1292 {
1293 itCurrentGroup = itGBRgroups;
1294 itGBRgroups++;
1295 }
1296 else if (itnonGBRgroups !=
1297 map_nonGBRHOLgroupToUE
1298 .end()) // if there are no more flows with retransmission queue start to
1299 // scheduler flows with transmission queue
1300 {
1301 itCurrentGroup = itnonGBRgroups;
1302 itnonGBRgroups++;
1303 }
1304 else
1305 {
1306 NS_LOG_INFO("Available RBGs:" << availableRBGs.size() << "but no users");
1307 break;
1308 }
1309
1310 while (!availableRBGs.empty() && !itCurrentGroup->second.empty())
1311 {
1312 bool currentRBchecked = false;
1313 int currentRB = *(availableRBGs.begin());
1314 std::map<LteFlowId_t, CQI_value> UeToCQIValue;
1315 std::map<LteFlowId_t, double> UeToCoitaMetric;
1316 std::map<LteFlowId_t, bool> UeHasReachedGBR;
1317 double maximumValueMetric = 0;
1318 LteFlowId_t userWithMaximumMetric;
1319 UeToCQIValue.clear();
1320 UeToCoitaMetric.clear();
1321
1322 // Iterate through the users and calculate which user will use the best of the current
1323 // resource block.end() and assign to that user.
1324 for (auto it = itCurrentGroup->second.begin(); it != itCurrentGroup->second.end(); it++)
1325 {
1326 LteFlowId_t flowId = *it;
1327 uint8_t cqi_value = 1; // higher better, maximum is 15
1328 double coita_metric = 1;
1329 double coita_sum = 0;
1330 double metric = 0;
1331 uint8_t worstCQIAmongRBGsAllocatedForThisUser = 15;
1332 int numberOfRBGAllocatedForThisUser = 0;
1334 m_ueLogicalChannelsConfigList.find(flowId)->second;
1335 auto itRntiCQIsMap = m_a30CqiRxed.find(flowId.m_rnti);
1336
1337 if (!m_ffrSapProvider->IsDlRbgAvailableForUe(currentRB, flowId.m_rnti))
1338 {
1339 continue;
1340 }
1341
1342 if (m_flowStatsDl.find(flowId.m_rnti) == m_flowStatsDl.end())
1343 {
1344 continue; // TO DO: check if this should be logged and how.
1345 }
1346 currentRBchecked = true;
1347
1348 auto itStats = m_flowStatsDl.find(flowId.m_rnti);
1349 double tbr_weight =
1350 (*itStats).second.targetThroughput / (*itStats).second.lastAveragedThroughput;
1351 if (tbr_weight < 1.0)
1352 {
1353 tbr_weight = 1.0;
1354 }
1355
1356 if (itRntiCQIsMap != m_a30CqiRxed.end())
1357 {
1358 for (auto it = availableRBGs.begin(); it != availableRBGs.end(); it++)
1359 {
1360 try
1361 {
1362 int val =
1363 (itRntiCQIsMap->second.m_higherLayerSelected.at(*it).m_sbCqi.at(0));
1364 if (val == 0)
1365 {
1366 val = 1; // if no info, use minimum
1367 }
1368 if (*it == currentRB)
1369 {
1370 cqi_value = val;
1371 }
1372 coita_sum += val;
1373 }
1374 catch (std::out_of_range&)
1375 {
1376 coita_sum += 1; // if no info on channel use the worst cqi
1377 NS_LOG_INFO("No CQI for lcId:" << flowId.m_lcId
1378 << " rnti:" << flowId.m_rnti
1379 << " at subband:" << currentRB);
1380 // std::cout<<"\n No CQI for
1381 // lcId:.....................................";
1382 }
1383 }
1384 coita_metric = cqi_value / coita_sum;
1385 UeToCQIValue.insert(std::pair<LteFlowId_t, CQI_value>(flowId, cqi_value));
1386 UeToCoitaMetric.insert(std::pair<LteFlowId_t, double>(flowId, coita_metric));
1387 }
1388
1389 if (allocationMapPerRntiPerLCId.find(flowId.m_rnti) ==
1390 allocationMapPerRntiPerLCId.end())
1391 {
1392 worstCQIAmongRBGsAllocatedForThisUser = cqi_value;
1393 }
1394 else
1395 {
1396 numberOfRBGAllocatedForThisUser =
1397 (allocationMapPerRntiPerLCId.find(flowId.m_rnti)->second.size());
1398
1399 for (auto itRBG =
1400 allocationMapPerRntiPerLCId.find(flowId.m_rnti)->second.begin();
1401 itRBG != allocationMapPerRntiPerLCId.find(flowId.m_rnti)->second.end();
1402 itRBG++)
1403 {
1404 qos_rb_and_CQI_assigned_to_lc e = itRBG->second;
1405 if (e.cqi_value_for_lc < worstCQIAmongRBGsAllocatedForThisUser)
1406 {
1407 worstCQIAmongRBGsAllocatedForThisUser = e.cqi_value_for_lc;
1408 }
1409 }
1410
1411 if (cqi_value < worstCQIAmongRBGsAllocatedForThisUser)
1412 {
1413 worstCQIAmongRBGsAllocatedForThisUser = cqi_value;
1414 }
1415 }
1416
1417 int mcsForThisUser = m_amc->GetMcsFromCqi(worstCQIAmongRBGsAllocatedForThisUser);
1418 int tbSize =
1419 m_amc->GetDlTbSizeFromMcs(mcsForThisUser,
1420 (numberOfRBGAllocatedForThisUser + 1) * rbgSize) /
1421 8; // similar to calculation of TB size (size of TB in bytes according to
1422 // table 7.1.7.2.1-1 of 36.213)
1423
1424 double achievableRate =
1425 ((m_amc->GetDlTbSizeFromMcs(mcsForThisUser, rbgSize) / 8) / 0.001);
1426 double pf_weight = achievableRate / (*itStats).second.secondLastAveragedThroughput;
1427
1428 UeToAmountOfAssignedResources.find(flowId)->second = 8 * tbSize;
1430 m_rlcBufferReq.find(flowId)->second;
1431
1432 if (UeToAmountOfDataToTransfer.find(flowId)->second -
1433 UeToAmountOfAssignedResources.find(flowId)->second <
1434 0)
1435 {
1436 UeHasReachedGBR.insert(std::pair<LteFlowId_t, bool>(flowId, false));
1437 }
1438
1439 double bitRateWithNewRBG = 0;
1440
1441 if (m_flowStatsDl.find(flowId.m_rnti) !=
1442 m_flowStatsDl.end()) // there are some statistics{
1443 {
1444 bitRateWithNewRBG =
1445 (1.0 - (1.0 / m_timeWindow)) *
1446 (m_flowStatsDl.find(flowId.m_rnti)->second.lastAveragedThroughput) +
1447 ((1.0 / m_timeWindow) * (double)(tbSize * 1000));
1448 }
1449 else
1450 {
1451 bitRateWithNewRBG = (1.0 / m_timeWindow) * (double)(tbSize * 1000);
1452 }
1453
1454 if (bitRateWithNewRBG > lc.m_eRabGuaranteedBitrateDl)
1455 {
1456 UeHasReachedGBR.insert(std::pair<LteFlowId_t, bool>(flowId, true));
1457 }
1458 else
1459 {
1460 UeHasReachedGBR.insert(std::pair<LteFlowId_t, bool>(flowId, false));
1461 }
1462
1463 int hol = UEtoHOL.find(flowId)->second;
1464
1465 if (hol == 0)
1466 {
1467 hol = 1;
1468 }
1469
1470 if (m_CqaMetric == "CqaFf")
1471 {
1472 metric = coita_metric * tbr_weight * hol;
1473 }
1474 else if (m_CqaMetric == "CqaPf")
1475 {
1476 metric = tbr_weight * pf_weight * hol;
1477 }
1478 else
1479 {
1480 metric = 1;
1481 }
1482
1483 if (metric >= maximumValueMetric)
1484 {
1485 maximumValueMetric = metric;
1486 userWithMaximumMetric = flowId;
1487 }
1488 }
1489
1490 if (!currentRBchecked)
1491 {
1492 // erase current RBG from the list of available RBG
1493 availableRBGs.erase(currentRB);
1494 continue;
1495 }
1496
1498 const auto ueToCqiIt = UeToCQIValue.find(userWithMaximumMetric);
1499 s.cqi_value_for_lc = ueToCqiIt != UeToCQIValue.end() ? ueToCqiIt->second : 1;
1500 s.resource_block_index = currentRB;
1501
1502 auto itMap = allocationMapPerRntiPerLCId.find(userWithMaximumMetric.m_rnti);
1503
1504 if (itMap == allocationMapPerRntiPerLCId.end())
1505 {
1506 std::multimap<uint8_t, qos_rb_and_CQI_assigned_to_lc> tempMap;
1507 tempMap.insert(
1508 std::pair<uint8_t, qos_rb_and_CQI_assigned_to_lc>(userWithMaximumMetric.m_lcId,
1509 s));
1510 allocationMapPerRntiPerLCId.insert(
1511 std::pair<uint16_t, std::multimap<uint8_t, qos_rb_and_CQI_assigned_to_lc>>(
1512 userWithMaximumMetric.m_rnti,
1513 tempMap));
1514 }
1515 else
1516 {
1517 itMap->second.insert(
1518 std::pair<uint8_t, qos_rb_and_CQI_assigned_to_lc>(userWithMaximumMetric.m_lcId,
1519 s));
1520 }
1521
1522 // erase current RBG from the list of available RBG
1523 availableRBGs.erase(currentRB);
1524
1525 if (UeToAmountOfDataToTransfer.find(userWithMaximumMetric)->second <=
1526 UeToAmountOfAssignedResources.find(userWithMaximumMetric)->second * tolerance)
1527 //||(UeHasReachedGBR.find(userWithMaximumMetric)->second == true))
1528 {
1529 itCurrentGroup->second.erase(userWithMaximumMetric);
1530 }
1531
1532 } // while there are more users in current group
1533 } // while there are more groups of users
1534
1535 // reset TTI stats of users
1536 for (auto itStats = m_flowStatsDl.begin(); itStats != m_flowStatsDl.end(); itStats++)
1537 {
1538 (*itStats).second.lastTtiBytesTransmitted = 0;
1539 }
1540
1541 // 3) Creating the correspondent DCIs (Generate the transmission opportunities by grouping the
1542 // RBGs of the same RNTI)
1543 // FfMacSchedSapUser::SchedDlConfigIndParameters ret;
1544 auto itMap = allocationMapPerRntiPerLCId.begin();
1545 std::map<uint16_t, double> m_rnti_per_ratio;
1546
1547 while (itMap != allocationMapPerRntiPerLCId.end())
1548 {
1549 // create new BuildDataListElement_s for this LC
1551 newEl.m_rnti = (*itMap).first;
1552 NS_LOG_INFO("Scheduled RNTI:" << newEl.m_rnti);
1553 // create the DlDciListElement_s
1554 DlDciListElement_s newDci;
1555 std::vector<RlcPduListElement_s> newRlcPduLe;
1556 newDci.m_rnti = (*itMap).first;
1557 newDci.m_harqProcess = UpdateHarqProcessId((*itMap).first);
1558 uint16_t lcActives = LcActivePerFlow(itMap->first);
1559 if (lcActives == 0)
1560 { // if there is still no buffer report information on any flow
1561 lcActives = 1;
1562 }
1563 // NS_LOG_DEBUG (this << "Allocate user " << newEl.m_rnti << " rbg " << lcActives);
1564 uint16_t RbgPerRnti = (*itMap).second.size();
1565 double doubleRBgPerRnti = RbgPerRnti;
1566 double doubleRbgNum = numberOfRBGs;
1567 double rrRatio = doubleRBgPerRnti / doubleRbgNum;
1568 m_rnti_per_ratio.insert(std::pair<uint16_t, double>((*itMap).first, rrRatio));
1569 uint8_t worstCqi = 15;
1570
1571 // assign the worst value of CQI that user experienced on any of its subbands
1572 for (auto it = (*itMap).second.begin(); it != (*itMap).second.end(); it++)
1573 {
1574 if (it->second.cqi_value_for_lc < worstCqi)
1575 {
1576 worstCqi = it->second.cqi_value_for_lc;
1577 }
1578 }
1579
1580 newDci.m_mcs.push_back(m_amc->GetMcsFromCqi(worstCqi));
1581 int tbSize = (m_amc->GetDlTbSizeFromMcs(newDci.m_mcs.at(0), RbgPerRnti * rbgSize) /
1582 8); // (size of TB in bytes according to table 7.1.7.2.1-1 of 36.213)
1583 newDci.m_tbsSize.push_back(tbSize);
1584 newDci.m_resAlloc = 0; // only allocation type 0 at this stage
1585 newDci.m_rbBitmap = 0; // TBD (32 bit bitmap see 7.1.6 of 36.213)
1586 uint32_t rbgMask = 0;
1587 for (auto itRBGsPerRNTI = (*itMap).second.begin(); itRBGsPerRNTI != (*itMap).second.end();
1588 itRBGsPerRNTI++)
1589 {
1590 rbgMask = rbgMask + (0x1 << itRBGsPerRNTI->second.resource_block_index);
1591 }
1592 newDci.m_rbBitmap = rbgMask; // (32 bit bitmap see 7.1.6 of 36.213)
1593 // NOTE: In this first version of CqaFfMacScheduler, it is assumed one flow per user.
1594 // create the rlc PDUs -> equally divide resources among active LCs
1595 for (auto itBufReq = m_rlcBufferReq.begin(); itBufReq != m_rlcBufferReq.end(); itBufReq++)
1596 {
1597 if (((*itBufReq).first.m_rnti == (*itMap).first) &&
1598 (((*itBufReq).second.m_rlcTransmissionQueueSize > 0) ||
1599 ((*itBufReq).second.m_rlcRetransmissionQueueSize > 0) ||
1600 ((*itBufReq).second.m_rlcStatusPduSize > 0)))
1601 {
1602 std::vector<RlcPduListElement_s> newRlcPduLe;
1603 // for (uint8_t j = 0; j < nLayer; j++)
1604 //{
1605 RlcPduListElement_s newRlcEl;
1606 newRlcEl.m_logicalChannelIdentity = (*itBufReq).first.m_lcId;
1607 // newRlcEl.m_size = newDci.m_tbsSize.at (j) / lcActives;
1608 newRlcEl.m_size = tbSize / lcActives;
1609 // NS_LOG_INFO (this << " LCID " << (uint32_t) newRlcEl.m_logicalChannelIdentity <<
1610 // " size " << newRlcEl.m_size << " layer " << (uint16_t)j);
1611 newRlcPduLe.push_back(newRlcEl);
1613 newRlcEl.m_logicalChannelIdentity,
1614 newRlcEl.m_size);
1615 if (m_harqOn)
1616 {
1617 // store RLC PDU list for HARQ
1618 auto itRlcPdu = m_dlHarqProcessesRlcPduListBuffer.find((*itMap).first);
1619 if (itRlcPdu == m_dlHarqProcessesRlcPduListBuffer.end())
1620 {
1621 NS_FATAL_ERROR("Unable to find RlcPdcList in HARQ buffer for RNTI "
1622 << (*itMap).first);
1623 }
1624 int j = 0;
1625 (*itRlcPdu).second.at(j).at(newDci.m_harqProcess).push_back(newRlcEl);
1626 }
1627 // }
1628 newEl.m_rlcPduList.push_back(newRlcPduLe);
1629 }
1630 if ((*itBufReq).first.m_rnti > (*itMap).first)
1631 {
1632 break;
1633 }
1634 }
1635 // for (uint8_t j = 0; j < nLayer; j++)
1636 // {
1637 newDci.m_ndi.push_back(1);
1638 newDci.m_rv.push_back(0);
1639 //}
1640
1641 newDci.m_tpc = m_ffrSapProvider->GetTpc((*itMap).first);
1642
1643 newEl.m_dci = newDci;
1644
1645 if (m_harqOn)
1646 {
1647 // store DCI for HARQ
1648 auto itDci = m_dlHarqProcessesDciBuffer.find(newEl.m_rnti);
1649 if (itDci == m_dlHarqProcessesDciBuffer.end())
1650 {
1651 NS_FATAL_ERROR("Unable to find RNTI entry in DCI HARQ buffer for RNTI "
1652 << newEl.m_rnti);
1653 }
1654 (*itDci).second.at(newDci.m_harqProcess) = newDci;
1655 // refresh timer
1656 auto itHarqTimer = m_dlHarqProcessesTimer.find(newEl.m_rnti);
1657 if (itHarqTimer == m_dlHarqProcessesTimer.end())
1658 {
1659 NS_FATAL_ERROR("Unable to find HARQ timer for RNTI " << (uint16_t)newEl.m_rnti);
1660 }
1661 (*itHarqTimer).second.at(newDci.m_harqProcess) = 0;
1662 }
1663
1664 // ...more parameters -> ignored in this version
1665
1666 ret.m_buildDataList.push_back(newEl);
1667 // update UE stats
1668 auto it = m_flowStatsDl.find((*itMap).first);
1669 if (it != m_flowStatsDl.end())
1670 {
1671 (*it).second.lastTtiBytesTransmitted = tbSize;
1672 }
1673 else
1674 {
1675 NS_FATAL_ERROR(this << " No Stats for this allocated UE");
1676 }
1677
1678 itMap++;
1679 } // end while allocation
1680 ret.m_nrOfPdcchOfdmSymbols = 1; // TODO: check correct value according the DCIs txed
1681
1682 // update UEs stats
1683 NS_LOG_INFO(this << " Update UEs statistics");
1684 for (auto itStats = m_flowStatsDl.begin(); itStats != m_flowStatsDl.end(); itStats++)
1685 {
1686 if (allocationMapPerRntiPerLCId.find(itStats->first) != allocationMapPerRntiPerLCId.end())
1687 {
1688 (*itStats).second.secondLastAveragedThroughput =
1689 ((1.0 - (1 / m_timeWindow)) * (*itStats).second.secondLastAveragedThroughput) +
1690 ((1 / m_timeWindow) * (double)((*itStats).second.lastTtiBytesTransmitted / 0.001));
1691 }
1692
1693 (*itStats).second.totalBytesTransmitted += (*itStats).second.lastTtiBytesTransmitted;
1694 // update average throughput (see eq. 12.3 of Sec 12.3.1.2 of LTE – The UMTS Long Term
1695 // Evolution, Ed Wiley)
1696 (*itStats).second.lastAveragedThroughput =
1697 ((1.0 - (1.0 / m_timeWindow)) * (*itStats).second.lastAveragedThroughput) +
1698 ((1.0 / m_timeWindow) * (double)((*itStats).second.lastTtiBytesTransmitted / 0.001));
1699 NS_LOG_INFO(this << " UE total bytes " << (*itStats).second.totalBytesTransmitted);
1700 NS_LOG_INFO(this << " UE average throughput " << (*itStats).second.lastAveragedThroughput);
1701 (*itStats).second.lastTtiBytesTransmitted = 0;
1702 }
1703
1705
1706 int count_allocated_resource_blocks = 0;
1707 for (auto itMap = allocationMapPerRntiPerLCId.begin();
1708 itMap != allocationMapPerRntiPerLCId.end();
1709 itMap++)
1710 {
1711 count_allocated_resource_blocks += itMap->second.size();
1712 }
1713 NS_LOG_INFO(this << " Allocated RBs:" << count_allocated_resource_blocks);
1714}
1715
1716void
1719{
1720 NS_LOG_FUNCTION(this);
1721
1722 m_rachList = params.m_rachList;
1723}
1724
1725void
1728{
1729 NS_LOG_FUNCTION(this);
1731
1732 for (unsigned int i = 0; i < params.m_cqiList.size(); i++)
1733 {
1734 if (params.m_cqiList.at(i).m_cqiType == CqiListElement_s::P10)
1735 {
1736 NS_LOG_LOGIC("wideband CQI " << (uint32_t)params.m_cqiList.at(i).m_wbCqi.at(0)
1737 << " reported");
1738 uint16_t rnti = params.m_cqiList.at(i).m_rnti;
1739 auto it = m_p10CqiRxed.find(rnti);
1740 if (it == m_p10CqiRxed.end())
1741 {
1742 // create the new entry
1743 m_p10CqiRxed[rnti] =
1744 params.m_cqiList.at(i).m_wbCqi.at(0); // only codeword 0 at this stage (SISO)
1745 // generate correspondent timer
1746 m_p10CqiTimers.insert(std::pair<uint16_t, uint32_t>(rnti, m_cqiTimersThreshold));
1747 }
1748 else
1749 {
1750 // update the CQI value and refresh correspondent timer
1751 (*it).second = params.m_cqiList.at(i).m_wbCqi.at(0);
1752 // update correspondent timer
1753 auto itTimers = m_p10CqiTimers.find(rnti);
1754 (*itTimers).second = m_cqiTimersThreshold;
1755 }
1756 }
1757 else if (params.m_cqiList.at(i).m_cqiType == CqiListElement_s::A30)
1758 {
1759 // subband CQI reporting high layer configured
1760 uint16_t rnti = params.m_cqiList.at(i).m_rnti;
1761 auto it = m_a30CqiRxed.find(rnti);
1762 if (it == m_a30CqiRxed.end())
1763 {
1764 // create the new entry
1765 m_a30CqiRxed[rnti] = params.m_cqiList.at(i).m_sbMeasResult;
1766 m_a30CqiTimers.insert(std::pair<uint16_t, uint32_t>(rnti, m_cqiTimersThreshold));
1767 }
1768 else
1769 {
1770 // update the CQI value and refresh correspondent timer
1771 (*it).second = params.m_cqiList.at(i).m_sbMeasResult;
1772 auto itTimers = m_a30CqiTimers.find(rnti);
1773 (*itTimers).second = m_cqiTimersThreshold;
1774 }
1775 }
1776 else
1777 {
1778 NS_LOG_ERROR(this << " CQI type unknown");
1779 }
1780 }
1781}
1782
1783double
1784CqaFfMacScheduler::EstimateUlSinr(uint16_t rnti, uint16_t rb)
1785{
1786 auto itCqi = m_ueCqi.find(rnti);
1787 if (itCqi == m_ueCqi.end())
1788 {
1789 // no cqi info about this UE
1790 return NO_SINR;
1791 }
1792 else
1793 {
1794 // take the average SINR value among the available
1795 double sinrSum = 0;
1796 unsigned int sinrNum = 0;
1797 for (uint32_t i = 0; i < m_cschedCellConfig.m_ulBandwidth; i++)
1798 {
1799 double sinr = (*itCqi).second.at(i);
1800 if (sinr != NO_SINR)
1801 {
1802 sinrSum += sinr;
1803 sinrNum++;
1804 }
1805 }
1806 double estimatedSinr = (sinrNum > 0) ? (sinrSum / sinrNum) : DBL_MAX;
1807 // store the value
1808 (*itCqi).second.at(rb) = estimatedSinr;
1809 return estimatedSinr;
1810 }
1811}
1812
1813void
1816{
1817 NS_LOG_FUNCTION(this << " UL - Frame no. " << (params.m_sfnSf >> 4) << " subframe no. "
1818 << (0xF & params.m_sfnSf) << " size " << params.m_ulInfoList.size());
1819
1822
1823 // Generate RBs map
1825 std::vector<bool> rbMap;
1826 uint16_t rbAllocatedNum = 0;
1827 std::set<uint16_t> rntiAllocated;
1828 std::vector<uint16_t> rbgAllocationMap;
1829 // update with RACH allocation map
1830 rbgAllocationMap = m_rachAllocationMap;
1831 // rbgAllocationMap.resize (m_cschedCellConfig.m_ulBandwidth, 0);
1832 m_rachAllocationMap.clear();
1834
1835 rbMap.resize(m_cschedCellConfig.m_ulBandwidth, false);
1836
1838
1839 for (auto it = rbMap.begin(); it != rbMap.end(); it++)
1840 {
1841 if (*it)
1842 {
1843 rbAllocatedNum++;
1844 }
1845 }
1846
1847 uint8_t minContinuousUlBandwidth = m_ffrSapProvider->GetMinContinuousUlBandwidth();
1848 uint8_t ffrUlBandwidth = m_cschedCellConfig.m_ulBandwidth - rbAllocatedNum;
1849
1850 // remove RACH allocation
1851 for (uint16_t i = 0; i < m_cschedCellConfig.m_ulBandwidth; i++)
1852 {
1853 if (rbgAllocationMap.at(i) != 0)
1854 {
1855 rbMap.at(i) = true;
1856 NS_LOG_DEBUG(this << " Allocated for RACH " << i);
1857 }
1858 }
1859
1860 if (m_harqOn)
1861 {
1862 // Process UL HARQ feedback
1863 for (std::size_t i = 0; i < params.m_ulInfoList.size(); i++)
1864 {
1865 if (params.m_ulInfoList.at(i).m_receptionStatus == UlInfoListElement_s::NotOk)
1866 {
1867 // retx correspondent block: retrieve the UL-DCI
1868 uint16_t rnti = params.m_ulInfoList.at(i).m_rnti;
1869 auto itProcId = m_ulHarqCurrentProcessId.find(rnti);
1870 if (itProcId == m_ulHarqCurrentProcessId.end())
1871 {
1872 NS_LOG_ERROR("No info find in HARQ buffer for UE (might change eNB) " << rnti);
1873 }
1874 uint8_t harqId = (uint8_t)((*itProcId).second - HARQ_PERIOD) % HARQ_PROC_NUM;
1875 NS_LOG_INFO(this << " UL-HARQ retx RNTI " << rnti << " harqId " << (uint16_t)harqId
1876 << " i " << i << " size " << params.m_ulInfoList.size());
1877 auto itHarq = m_ulHarqProcessesDciBuffer.find(rnti);
1878 if (itHarq == m_ulHarqProcessesDciBuffer.end())
1879 {
1880 NS_LOG_ERROR("No info find in HARQ buffer for UE (might change eNB) " << rnti);
1881 continue;
1882 }
1883 UlDciListElement_s dci = (*itHarq).second.at(harqId);
1884 auto itStat = m_ulHarqProcessesStatus.find(rnti);
1885 if (itStat == m_ulHarqProcessesStatus.end())
1886 {
1887 NS_LOG_ERROR("No info find in HARQ buffer for UE (might change eNB) " << rnti);
1888 }
1889 if ((*itStat).second.at(harqId) >= 3)
1890 {
1891 NS_LOG_INFO("Max number of retransmissions reached (UL)-> drop process");
1892 continue;
1893 }
1894 bool free = true;
1895
1896 for (int j = dci.m_rbStart; j < dci.m_rbStart + dci.m_rbLen; j++)
1897 {
1898 if (rbMap.at(j))
1899 {
1900 free = false;
1901 NS_LOG_INFO(this << " BUSY " << j);
1902 }
1903 }
1904 if (free)
1905 {
1906 // retx on the same RBs
1907 for (int j = dci.m_rbStart; j < dci.m_rbStart + dci.m_rbLen; j++)
1908 {
1909 rbMap.at(j) = true;
1910 rbgAllocationMap.at(j) = dci.m_rnti;
1911 NS_LOG_INFO("\tRB " << j);
1912 rbAllocatedNum++;
1913 }
1914 NS_LOG_INFO(this << " Send retx in the same RBs " << (uint16_t)dci.m_rbStart
1915 << " to " << dci.m_rbStart + dci.m_rbLen << " RV "
1916 << (*itStat).second.at(harqId) + 1);
1917 }
1918 else
1919 {
1920 NS_LOG_INFO("Cannot allocate retx due to RACH allocations for UE " << rnti);
1921 continue;
1922 }
1923 dci.m_ndi = 0;
1924 // Update HARQ buffers with new HarqId
1925 (*itStat).second.at((*itProcId).second) = (*itStat).second.at(harqId) + 1;
1926 (*itStat).second.at(harqId) = 0;
1927 (*itHarq).second.at((*itProcId).second) = dci;
1928 ret.m_dciList.push_back(dci);
1929 rntiAllocated.insert(dci.m_rnti);
1930 }
1931 else
1932 {
1933 NS_LOG_INFO(this << " HARQ-ACK feedback from RNTI "
1934 << params.m_ulInfoList.at(i).m_rnti);
1935 }
1936 }
1937 }
1938
1939 std::map<uint16_t, uint32_t>::iterator it;
1940 int nflows = 0;
1941
1942 for (it = m_ceBsrRxed.begin(); it != m_ceBsrRxed.end(); it++)
1943 {
1944 auto itRnti = rntiAllocated.find((*it).first);
1945 // select UEs with queues not empty and not yet allocated for HARQ
1946 if (((*it).second > 0) && (itRnti == rntiAllocated.end()))
1947 {
1948 nflows++;
1949 }
1950 }
1951
1952 if (nflows == 0)
1953 {
1954 if (!ret.m_dciList.empty())
1955 {
1956 m_allocationMaps[params.m_sfnSf] = rbgAllocationMap;
1958 }
1959
1960 return; // no flows to be scheduled
1961 }
1962
1963 // Divide the remaining resources equally among the active users starting from the subsequent
1964 // one served last scheduling trigger
1965 uint16_t tempRbPerFlow = (ffrUlBandwidth) / (nflows + rntiAllocated.size());
1966 uint16_t rbPerFlow =
1967 (minContinuousUlBandwidth < tempRbPerFlow) ? minContinuousUlBandwidth : tempRbPerFlow;
1968
1969 if (rbPerFlow < 3)
1970 {
1971 rbPerFlow = 3; // at least 3 rbg per flow (till available resource) to ensure TxOpportunity
1972 // >= 7 bytes
1973 }
1974 int rbAllocated = 0;
1975
1976 if (m_nextRntiUl != 0)
1977 {
1978 for (it = m_ceBsrRxed.begin(); it != m_ceBsrRxed.end(); it++)
1979 {
1980 if ((*it).first == m_nextRntiUl)
1981 {
1982 break;
1983 }
1984 }
1985 if (it == m_ceBsrRxed.end())
1986 {
1987 NS_LOG_ERROR(this << " no user found");
1988 }
1989 }
1990 else
1991 {
1992 it = m_ceBsrRxed.begin();
1993 m_nextRntiUl = (*it).first;
1994 }
1995 do
1996 {
1997 auto itRnti = rntiAllocated.find((*it).first);
1998 if ((itRnti != rntiAllocated.end()) || ((*it).second == 0))
1999 {
2000 // UE already allocated for UL-HARQ -> skip it
2001 NS_LOG_DEBUG(this << " UE already allocated in HARQ -> discarded, RNTI "
2002 << (*it).first);
2003 it++;
2004 if (it == m_ceBsrRxed.end())
2005 {
2006 // restart from the first
2007 it = m_ceBsrRxed.begin();
2008 }
2009 continue;
2010 }
2011 if (rbAllocated + rbPerFlow - 1 > m_cschedCellConfig.m_ulBandwidth)
2012 {
2013 // limit to physical resources last resource assignment
2014 rbPerFlow = m_cschedCellConfig.m_ulBandwidth - rbAllocated;
2015 // at least 3 rbg per flow to ensure TxOpportunity >= 7 bytes
2016 if (rbPerFlow < 3)
2017 {
2018 // terminate allocation
2019 rbPerFlow = 0;
2020 }
2021 }
2022
2023 rbAllocated = 0;
2024 UlDciListElement_s uldci;
2025 uldci.m_rnti = (*it).first;
2026 uldci.m_rbLen = rbPerFlow;
2027 bool allocated = false;
2028 NS_LOG_INFO(this << " RB Allocated " << rbAllocated << " rbPerFlow " << rbPerFlow
2029 << " flows " << nflows);
2030 while ((!allocated) && ((rbAllocated + rbPerFlow - m_cschedCellConfig.m_ulBandwidth) < 1) &&
2031 (rbPerFlow != 0))
2032 {
2033 // check availability
2034 bool free = true;
2035 for (int j = rbAllocated; j < rbAllocated + rbPerFlow; j++)
2036 {
2037 if (rbMap.at(j))
2038 {
2039 free = false;
2040 break;
2041 }
2042 if (!m_ffrSapProvider->IsUlRbgAvailableForUe(j, (*it).first))
2043 {
2044 free = false;
2045 break;
2046 }
2047 }
2048 if (free)
2049 {
2050 NS_LOG_INFO(this << "RNTI: " << (*it).first << " RB Allocated " << rbAllocated
2051 << " rbPerFlow " << rbPerFlow << " flows " << nflows);
2052 uldci.m_rbStart = rbAllocated;
2053
2054 for (int j = rbAllocated; j < rbAllocated + rbPerFlow; j++)
2055 {
2056 rbMap.at(j) = true;
2057 // store info on allocation for managing ul-cqi interpretation
2058 rbgAllocationMap.at(j) = (*it).first;
2059 }
2060 rbAllocated += rbPerFlow;
2061 allocated = true;
2062 break;
2063 }
2064 rbAllocated++;
2065 if (rbAllocated + rbPerFlow - 1 > m_cschedCellConfig.m_ulBandwidth)
2066 {
2067 // limit to physical resources last resource assignment
2068 rbPerFlow = m_cschedCellConfig.m_ulBandwidth - rbAllocated;
2069 // at least 3 rbg per flow to ensure TxOpportunity >= 7 bytes
2070 if (rbPerFlow < 3)
2071 {
2072 // terminate allocation
2073 rbPerFlow = 0;
2074 }
2075 }
2076 }
2077 if (!allocated)
2078 {
2079 // unable to allocate new resource: finish scheduling
2080 // m_nextRntiUl = (*it).first;
2081 // if (ret.m_dciList.size () > 0)
2082 // {
2083 // m_schedSapUser->SchedUlConfigInd (ret);
2084 // }
2085 // m_allocationMaps[params.m_sfnSf] = rbgAllocationMap; return;
2086 break;
2087 }
2088
2089 auto itCqi = m_ueCqi.find((*it).first);
2090 int cqi = 0;
2091 if (itCqi == m_ueCqi.end())
2092 {
2093 // no cqi info about this UE
2094 uldci.m_mcs = 0; // MCS 0 -> UL-AMC TBD
2095 }
2096 else
2097 {
2098 // take the lowest CQI value (worst RB)
2099 NS_ABORT_MSG_IF((*itCqi).second.empty(),
2100 "CQI of RNTI = " << (*it).first << " has expired");
2101 double minSinr = (*itCqi).second.at(uldci.m_rbStart);
2102 if (minSinr == NO_SINR)
2103 {
2104 minSinr = EstimateUlSinr((*it).first, uldci.m_rbStart);
2105 }
2106 for (uint16_t i = uldci.m_rbStart; i < uldci.m_rbStart + uldci.m_rbLen; i++)
2107 {
2108 double sinr = (*itCqi).second.at(i);
2109 if (sinr == NO_SINR)
2110 {
2111 sinr = EstimateUlSinr((*it).first, i);
2112 }
2113 if (sinr < minSinr)
2114 {
2115 minSinr = sinr;
2116 }
2117 }
2118
2119 // translate SINR -> cqi: WILD ACK: same as DL
2120 double s = log2(1 + (std::pow(10, minSinr / 10) / ((-std::log(5.0 * 0.00005)) / 1.5)));
2121 cqi = m_amc->GetCqiFromSpectralEfficiency(s);
2122 if (cqi == 0)
2123 {
2124 it++;
2125 if (it == m_ceBsrRxed.end())
2126 {
2127 // restart from the first
2128 it = m_ceBsrRxed.begin();
2129 }
2130 NS_LOG_DEBUG(this << " UE discarded for CQI = 0, RNTI " << uldci.m_rnti);
2131 // remove UE from allocation map
2132 for (uint16_t i = uldci.m_rbStart; i < uldci.m_rbStart + uldci.m_rbLen; i++)
2133 {
2134 rbgAllocationMap.at(i) = 0;
2135 }
2136 continue; // CQI == 0 means "out of range" (see table 7.2.3-1 of 36.213)
2137 }
2138 uldci.m_mcs = m_amc->GetMcsFromCqi(cqi);
2139 }
2140
2141 uldci.m_tbSize = (m_amc->GetUlTbSizeFromMcs(uldci.m_mcs, rbPerFlow) / 8);
2143 uldci.m_ndi = 1;
2144 uldci.m_cceIndex = 0;
2145 uldci.m_aggrLevel = 1;
2146 uldci.m_ueTxAntennaSelection = 3; // antenna selection OFF
2147 uldci.m_hopping = false;
2148 uldci.m_n2Dmrs = 0;
2149 uldci.m_tpc = 0; // no power control
2150 uldci.m_cqiRequest = false; // only period CQI at this stage
2151 uldci.m_ulIndex = 0; // TDD parameter
2152 uldci.m_dai = 1; // TDD parameter
2153 uldci.m_freqHopping = 0;
2154 uldci.m_pdcchPowerOffset = 0; // not used
2155 ret.m_dciList.push_back(uldci);
2156 // store DCI for HARQ_PERIOD
2157 uint8_t harqId = 0;
2158 if (m_harqOn)
2159 {
2160 auto itProcId = m_ulHarqCurrentProcessId.find(uldci.m_rnti);
2161 if (itProcId == m_ulHarqCurrentProcessId.end())
2162 {
2163 NS_FATAL_ERROR("No info find in HARQ buffer for UE " << uldci.m_rnti);
2164 }
2165 harqId = (*itProcId).second;
2166 auto itDci = m_ulHarqProcessesDciBuffer.find(uldci.m_rnti);
2167 if (itDci == m_ulHarqProcessesDciBuffer.end())
2168 {
2169 NS_FATAL_ERROR("Unable to find RNTI entry in UL DCI HARQ buffer for RNTI "
2170 << uldci.m_rnti);
2171 }
2172 (*itDci).second.at(harqId) = uldci;
2173 // Update HARQ process status (RV 0)
2174 auto itStat = m_ulHarqProcessesStatus.find(uldci.m_rnti);
2175 if (itStat == m_ulHarqProcessesStatus.end())
2176 {
2177 NS_LOG_ERROR("No info find in HARQ buffer for UE (might change eNB) "
2178 << uldci.m_rnti);
2179 }
2180 (*itStat).second.at(harqId) = 0;
2181 }
2182
2183 NS_LOG_INFO(this << " UE Allocation RNTI " << (*it).first << " startPRB "
2184 << (uint32_t)uldci.m_rbStart << " nPRB " << (uint32_t)uldci.m_rbLen
2185 << " CQI " << cqi << " MCS " << (uint32_t)uldci.m_mcs << " TBsize "
2186 << uldci.m_tbSize << " RbAlloc " << rbAllocated << " harqId "
2187 << (uint16_t)harqId);
2188
2189 // update TTI UE stats
2190 auto itStats = m_flowStatsUl.find((*it).first);
2191 if (itStats != m_flowStatsUl.end())
2192 {
2193 (*itStats).second.lastTtiBytesTransmitted = uldci.m_tbSize;
2194 }
2195 else
2196 {
2197 NS_LOG_DEBUG(this << " No Stats for this allocated UE");
2198 }
2199
2200 it++;
2201 if (it == m_ceBsrRxed.end())
2202 {
2203 // restart from the first
2204 it = m_ceBsrRxed.begin();
2205 }
2206 if ((rbAllocated == m_cschedCellConfig.m_ulBandwidth) || (rbPerFlow == 0))
2207 {
2208 // Stop allocation: no more PRBs
2209 m_nextRntiUl = (*it).first;
2210 break;
2211 }
2212 } while (((*it).first != m_nextRntiUl) && (rbPerFlow != 0));
2213
2214 // Update global UE stats
2215 // update UEs stats
2216 for (auto itStats = m_flowStatsUl.begin(); itStats != m_flowStatsUl.end(); itStats++)
2217 {
2218 (*itStats).second.totalBytesTransmitted += (*itStats).second.lastTtiBytesTransmitted;
2219 // update average throughput (see eq. 12.3 of Sec 12.3.1.2 of LTE – The UMTS Long Term
2220 // Evolution, Ed Wiley)
2221 (*itStats).second.lastAveragedThroughput =
2222 ((1.0 - (1.0 / m_timeWindow)) * (*itStats).second.lastAveragedThroughput) +
2223 ((1.0 / m_timeWindow) * (double)((*itStats).second.lastTtiBytesTransmitted / 0.001));
2224 NS_LOG_INFO(this << " UE total bytes " << (*itStats).second.totalBytesTransmitted);
2225 NS_LOG_INFO(this << " UE average throughput " << (*itStats).second.lastAveragedThroughput);
2226 (*itStats).second.lastTtiBytesTransmitted = 0;
2227 }
2228 m_allocationMaps[params.m_sfnSf] = rbgAllocationMap;
2230}
2231
2232void
2238
2239void
2245
2246void
2249{
2250 NS_LOG_FUNCTION(this);
2251
2252 for (unsigned int i = 0; i < params.m_macCeList.size(); i++)
2253 {
2254 if (params.m_macCeList.at(i).m_macCeType == MacCeListElement_s::BSR)
2255 {
2256 // buffer status report
2257 // note that this scheduler does not differentiate the
2258 // allocation according to which LCGs have more/less bytes
2259 // to send.
2260 // Hence the BSR of different LCGs are just summed up to get
2261 // a total queue size that is used for allocation purposes.
2262
2263 uint32_t buffer = 0;
2264 for (uint8_t lcg = 0; lcg < 4; ++lcg)
2265 {
2266 uint8_t bsrId = params.m_macCeList.at(i).m_macCeValue.m_bufferStatus.at(lcg);
2267 buffer += BufferSizeLevelBsr::BsrId2BufferSize(bsrId);
2268 }
2269
2270 uint16_t rnti = params.m_macCeList.at(i).m_rnti;
2271 NS_LOG_LOGIC(this << "RNTI=" << rnti << " buffer=" << buffer);
2272 auto it = m_ceBsrRxed.find(rnti);
2273 if (it == m_ceBsrRxed.end())
2274 {
2275 // create the new entry
2276 m_ceBsrRxed.insert(std::pair<uint16_t, uint32_t>(rnti, buffer));
2277 }
2278 else
2279 {
2280 // update the buffer size value
2281 (*it).second = buffer;
2282 }
2283 }
2284 }
2285}
2286
2287void
2290{
2291 NS_LOG_FUNCTION(this);
2292 // retrieve the allocation for this subframe
2293 switch (m_ulCqiFilter)
2294 {
2296 // filter all the CQIs that are not SRS based
2297 if (params.m_ulCqi.m_type != UlCqi_s::SRS)
2298 {
2299 return;
2300 }
2301 }
2302 break;
2304 // filter all the CQIs that are not SRS based
2305 if (params.m_ulCqi.m_type != UlCqi_s::PUSCH)
2306 {
2307 return;
2308 }
2309 }
2310 break;
2311 default:
2312 NS_FATAL_ERROR("Unknown UL CQI type");
2313 }
2314
2315 switch (params.m_ulCqi.m_type)
2316 {
2317 case UlCqi_s::PUSCH: {
2318 NS_LOG_DEBUG(this << " Collect PUSCH CQIs of Frame no. " << (params.m_sfnSf >> 4)
2319 << " subframe no. " << (0xF & params.m_sfnSf));
2320 auto itMap = m_allocationMaps.find(params.m_sfnSf);
2321 if (itMap == m_allocationMaps.end())
2322 {
2323 return;
2324 }
2325 for (uint32_t i = 0; i < (*itMap).second.size(); i++)
2326 {
2327 // convert from fixed point notation Sxxxxxxxxxxx.xxx to double
2328 double sinr = LteFfConverter::fpS11dot3toDouble(params.m_ulCqi.m_sinr.at(i));
2329 auto itCqi = m_ueCqi.find((*itMap).second.at(i));
2330 if (itCqi == m_ueCqi.end())
2331 {
2332 // create a new entry
2333 std::vector<double> newCqi;
2334 for (uint32_t j = 0; j < m_cschedCellConfig.m_ulBandwidth; j++)
2335 {
2336 if (i == j)
2337 {
2338 newCqi.push_back(sinr);
2339 }
2340 else
2341 {
2342 // initialize with NO_SINR value.
2343 newCqi.push_back(NO_SINR);
2344 }
2345 }
2346 m_ueCqi[(*itMap).second.at(i)] = newCqi;
2347 // generate correspondent timer
2348 m_ueCqiTimers[(*itMap).second.at(i)] = m_cqiTimersThreshold;
2349 }
2350 else
2351 {
2352 // update the value
2353 (*itCqi).second.at(i) = sinr;
2354 NS_LOG_DEBUG(this << " RNTI " << (*itMap).second.at(i) << " RB " << i << " SINR "
2355 << sinr);
2356 // update correspondent timer
2357 auto itTimers = m_ueCqiTimers.find((*itMap).second.at(i));
2358 (*itTimers).second = m_cqiTimersThreshold;
2359 }
2360 }
2361 // remove obsolete info on allocation
2362 m_allocationMaps.erase(itMap);
2363 }
2364 break;
2365 case UlCqi_s::SRS: {
2366 NS_LOG_DEBUG(this << " Collect SRS CQIs of Frame no. " << (params.m_sfnSf >> 4)
2367 << " subframe no. " << (0xF & params.m_sfnSf));
2368 // get the RNTI from vendor specific parameters
2369 uint16_t rnti = 0;
2370 NS_ASSERT(!params.m_vendorSpecificList.empty());
2371 for (std::size_t i = 0; i < params.m_vendorSpecificList.size(); i++)
2372 {
2373 if (params.m_vendorSpecificList.at(i).m_type == SRS_CQI_RNTI_VSP)
2374 {
2375 Ptr<SrsCqiRntiVsp> vsp =
2376 DynamicCast<SrsCqiRntiVsp>(params.m_vendorSpecificList.at(i).m_value);
2377 rnti = vsp->GetRnti();
2378 }
2379 }
2380 auto itCqi = m_ueCqi.find(rnti);
2381 if (itCqi == m_ueCqi.end())
2382 {
2383 // create a new entry
2384 std::vector<double> newCqi;
2385 for (uint32_t j = 0; j < m_cschedCellConfig.m_ulBandwidth; j++)
2386 {
2387 double sinr = LteFfConverter::fpS11dot3toDouble(params.m_ulCqi.m_sinr.at(j));
2388 newCqi.push_back(sinr);
2389 NS_LOG_INFO(this << " RNTI " << rnti << " new SRS-CQI for RB " << j << " value "
2390 << sinr);
2391 }
2392 m_ueCqi.insert(std::pair<uint16_t, std::vector<double>>(rnti, newCqi));
2393 // generate correspondent timer
2394 m_ueCqiTimers.insert(std::pair<uint16_t, uint32_t>(rnti, m_cqiTimersThreshold));
2395 }
2396 else
2397 {
2398 // update the values
2399 for (uint32_t j = 0; j < m_cschedCellConfig.m_ulBandwidth; j++)
2400 {
2401 double sinr = LteFfConverter::fpS11dot3toDouble(params.m_ulCqi.m_sinr.at(j));
2402 (*itCqi).second.at(j) = sinr;
2403 NS_LOG_INFO(this << " RNTI " << rnti << " update SRS-CQI for RB " << j << " value "
2404 << sinr);
2405 }
2406 // update correspondent timer
2407 auto itTimers = m_ueCqiTimers.find(rnti);
2408 (*itTimers).second = m_cqiTimersThreshold;
2409 }
2410 }
2411 break;
2412 case UlCqi_s::PUCCH_1:
2413 case UlCqi_s::PUCCH_2:
2414 case UlCqi_s::PRACH: {
2415 NS_FATAL_ERROR("PfFfMacScheduler supports only PUSCH and SRS UL-CQIs");
2416 }
2417 break;
2418 default:
2419 NS_FATAL_ERROR("Unknown type of UL-CQI");
2420 }
2421}
2422
2423void
2425{
2426 // refresh DL CQI P01 Map
2427 auto itP10 = m_p10CqiTimers.begin();
2428 while (itP10 != m_p10CqiTimers.end())
2429 {
2430 NS_LOG_INFO(this << " P10-CQI for user " << (*itP10).first << " is "
2431 << (uint32_t)(*itP10).second << " thr " << (uint32_t)m_cqiTimersThreshold);
2432 if ((*itP10).second == 0)
2433 {
2434 // delete correspondent entries
2435 auto itMap = m_p10CqiRxed.find((*itP10).first);
2436 NS_ASSERT_MSG(itMap != m_p10CqiRxed.end(),
2437 " Does not find CQI report for user " << (*itP10).first);
2438 NS_LOG_INFO(this << " P10-CQI expired for user " << (*itP10).first);
2439 m_p10CqiRxed.erase(itMap);
2440 auto temp = itP10;
2441 itP10++;
2442 m_p10CqiTimers.erase(temp);
2443 }
2444 else
2445 {
2446 (*itP10).second--;
2447 itP10++;
2448 }
2449 }
2450
2451 // refresh DL CQI A30 Map
2452 auto itA30 = m_a30CqiTimers.begin();
2453 while (itA30 != m_a30CqiTimers.end())
2454 {
2455 NS_LOG_INFO(this << " A30-CQI for user " << (*itA30).first << " is "
2456 << (uint32_t)(*itA30).second << " thr " << (uint32_t)m_cqiTimersThreshold);
2457 if ((*itA30).second == 0)
2458 {
2459 // delete correspondent entries
2460 auto itMap = m_a30CqiRxed.find((*itA30).first);
2461 NS_ASSERT_MSG(itMap != m_a30CqiRxed.end(),
2462 " Does not find CQI report for user " << (*itA30).first);
2463 NS_LOG_INFO(this << " A30-CQI expired for user " << (*itA30).first);
2464 m_a30CqiRxed.erase(itMap);
2465 auto temp = itA30;
2466 itA30++;
2467 m_a30CqiTimers.erase(temp);
2468 }
2469 else
2470 {
2471 (*itA30).second--;
2472 itA30++;
2473 }
2474 }
2475}
2476
2477void
2479{
2480 // refresh UL CQI Map
2481 auto itUl = m_ueCqiTimers.begin();
2482 while (itUl != m_ueCqiTimers.end())
2483 {
2484 NS_LOG_INFO(this << " UL-CQI for user " << (*itUl).first << " is "
2485 << (uint32_t)(*itUl).second << " thr " << (uint32_t)m_cqiTimersThreshold);
2486 if ((*itUl).second == 0)
2487 {
2488 // delete correspondent entries
2489 auto itMap = m_ueCqi.find((*itUl).first);
2490 NS_ASSERT_MSG(itMap != m_ueCqi.end(),
2491 " Does not find CQI report for user " << (*itUl).first);
2492 NS_LOG_INFO(this << " UL-CQI exired for user " << (*itUl).first);
2493 (*itMap).second.clear();
2494 m_ueCqi.erase(itMap);
2495 auto temp = itUl;
2496 itUl++;
2497 m_ueCqiTimers.erase(temp);
2498 }
2499 else
2500 {
2501 (*itUl).second--;
2502 itUl++;
2503 }
2504 }
2505}
2506
2507void
2508CqaFfMacScheduler::UpdateDlRlcBufferInfo(uint16_t rnti, uint8_t lcid, uint16_t size)
2509{
2510 LteFlowId_t flow(rnti, lcid);
2511 auto it = m_rlcBufferReq.find(flow);
2512 if (it != m_rlcBufferReq.end())
2513 {
2514 NS_LOG_INFO(this << " UE " << rnti << " LC " << (uint16_t)lcid << " txqueue "
2515 << (*it).second.m_rlcTransmissionQueueSize << " retxqueue "
2516 << (*it).second.m_rlcRetransmissionQueueSize << " status "
2517 << (*it).second.m_rlcStatusPduSize << " decrease " << size);
2518 // Update queues: RLC tx order Status, ReTx, Tx
2519 // Update status queue
2520 if (((*it).second.m_rlcStatusPduSize > 0) && (size >= (*it).second.m_rlcStatusPduSize))
2521 {
2522 (*it).second.m_rlcStatusPduSize = 0;
2523 }
2524 else if (((*it).second.m_rlcRetransmissionQueueSize > 0) &&
2525 (size >= (*it).second.m_rlcRetransmissionQueueSize))
2526 {
2527 (*it).second.m_rlcRetransmissionQueueSize = 0;
2528 }
2529 else if ((*it).second.m_rlcTransmissionQueueSize > 0)
2530 {
2531 uint32_t rlcOverhead;
2532 if (lcid == 1)
2533 {
2534 // for SRB1 (using RLC AM) it's better to
2535 // overestimate RLC overhead rather than
2536 // underestimate it and risk unneeded
2537 // segmentation which increases delay
2538 rlcOverhead = 4;
2539 }
2540 else
2541 {
2542 // minimum RLC overhead due to header
2543 rlcOverhead = 2;
2544 }
2545 // update transmission queue
2546 if ((*it).second.m_rlcTransmissionQueueSize <= size - rlcOverhead)
2547 {
2548 (*it).second.m_rlcTransmissionQueueSize = 0;
2549 }
2550 else
2551 {
2552 (*it).second.m_rlcTransmissionQueueSize -= size - rlcOverhead;
2553 }
2554 }
2555 }
2556 else
2557 {
2558 NS_LOG_ERROR(this << " Does not find DL RLC Buffer Report of UE " << rnti);
2559 }
2560}
2561
2562void
2563CqaFfMacScheduler::UpdateUlRlcBufferInfo(uint16_t rnti, uint16_t size)
2564{
2565 size = size - 2; // remove the minimum RLC overhead
2566 auto it = m_ceBsrRxed.find(rnti);
2567 if (it != m_ceBsrRxed.end())
2568 {
2569 NS_LOG_INFO(this << " UE " << rnti << " size " << size << " BSR " << (*it).second);
2570 if ((*it).second >= size)
2571 {
2572 (*it).second -= size;
2573 }
2574 else
2575 {
2576 (*it).second = 0;
2577 }
2578 }
2579 else
2580 {
2581 NS_LOG_ERROR(this << " Does not find BSR report info of UE " << rnti);
2582 }
2583}
2584
2585void
2587{
2588 NS_LOG_FUNCTION(this << " RNTI " << rnti << " txMode " << (uint16_t)txMode);
2590 params.m_rnti = rnti;
2591 params.m_transmissionMode = txMode;
2593}
2594
2595} // namespace ns3
static uint32_t BsrId2BufferSize(uint8_t val)
Convert BSR ID to buffer size.
Implements the SCHED SAP and CSCHED SAP for the Channel and QoS Aware Scheduler.
std::map< uint16_t, DlHarqRlcPduListBuffer_t > m_dlHarqProcessesRlcPduListBuffer
DL HARQ process RLC PDU list buffer.
FfMacCschedSapProvider * m_cschedSapProvider
Csched SAP provider.
void RefreshHarqProcesses()
Refresh HARQ processes according to the timers.
int GetRbgSize(int dlbandwidth)
Get RBG Size.
void DoSchedUlTriggerReq(const FfMacSchedSapProvider::SchedUlTriggerReqParameters &params)
Sched UL Trigger Request.
std::map< uint16_t, CqasFlowPerf_t > m_flowStatsDl
Map of UE statistics (per RNTI basis) in downlink.
std::map< uint16_t, uint32_t > m_p10CqiTimers
Map of UE's timers on DL CQI P01 received.
std::map< uint16_t, uint8_t > m_dlHarqCurrentProcessId
DL HARQ process ID.
static TypeId GetTypeId()
Get the type ID.
std::map< uint16_t, DlHarqProcessesTimer_t > m_dlHarqProcessesTimer
DL HARQ process timers.
std::map< uint16_t, uint32_t > m_a30CqiTimers
Map of UE's timers on DL CQI A30 received.
std::map< uint16_t, std::vector< double > > m_ueCqi
Map of UEs' UL-CQI per RBG.
std::map< uint16_t, uint32_t > m_ueCqiTimers
Map of UEs' timers on UL-CQI per RBG.
void DoSchedDlPagingBufferReq(const FfMacSchedSapProvider::SchedDlPagingBufferReqParameters &params)
Sched DL Paging Buffer Request.
~CqaFfMacScheduler() override
Destructor.
unsigned int LcActivePerFlow(uint16_t rnti)
LC Active per flow.
void SetLteFfrSapProvider(LteFfrSapProvider *s) override
Set the Provider part of the LteFfrSap that this Scheduler will interact with.
FfMacSchedSapUser * m_schedSapUser
MAC Sched SAP user.
void DoSchedDlTriggerReq(const FfMacSchedSapProvider::SchedDlTriggerReqParameters &params)
Sched DL RLC Buffer Request.
void UpdateDlRlcBufferInfo(uint16_t rnti, uint8_t lcid, uint16_t size)
Update DL RLC buffer info.
LteFfrSapProvider * m_ffrSapProvider
FFR SAP provider.
uint8_t UpdateHarqProcessId(uint16_t rnti)
Update and return a new process Id for the RNTI specified.
std::map< uint16_t, DlHarqProcessesDciBuffer_t > m_dlHarqProcessesDciBuffer
DL HARQ process DCI buffer.
void DoSchedDlRlcBufferReq(const FfMacSchedSapProvider::SchedDlRlcBufferReqParameters &params)
Sched DL RLC Buffer Request.
std::map< uint16_t, uint8_t > m_ulHarqCurrentProcessId
UL HARQ current process ID.
friend class MemberSchedSapProvider< CqaFfMacScheduler >
allow MemberSchedSapProvider<CqaFfMacScheduler> class friend access
std::map< uint16_t, SbMeasResult_s > m_a30CqiRxed
Map of UE's DL CQI A30 received.
std::vector< RachListElement_s > m_rachList
RACH list.
void DoSchedDlMacBufferReq(const FfMacSchedSapProvider::SchedDlMacBufferReqParameters &params)
Sched DL MAC Buffer Request.
void DoCschedLcReleaseReq(const FfMacCschedSapProvider::CschedLcReleaseReqParameters &params)
Csched LC Release Request.
void DoSchedUlMacCtrlInfoReq(const FfMacSchedSapProvider::SchedUlMacCtrlInfoReqParameters &params)
Sched UL MAC Control Info Request.
void DoCschedLcConfigReq(const FfMacCschedSapProvider::CschedLcConfigReqParameters &params)
Csched LC Config Request.
FfMacCschedSapUser * m_cschedSapUser
MAC Csched SAP user.
bool HarqProcessAvailability(uint16_t rnti)
Return the availability of free process for the RNTI specified.
LteFfrSapUser * m_ffrSapUser
FFR SAP user.
void UpdateUlRlcBufferInfo(uint16_t rnti, uint16_t size)
Update UL RLC buffer info.
std::map< uint16_t, UlHarqProcessesStatus_t > m_ulHarqProcessesStatus
UL HARQ process status.
uint8_t m_ulGrantMcs
MCS for UL grant (default 0)
void DoSchedUlNoiseInterferenceReq(const FfMacSchedSapProvider::SchedUlNoiseInterferenceReqParameters &params)
Sched UL Noise InterferenceRequest.
void DoSchedUlCqiInfoReq(const FfMacSchedSapProvider::SchedUlCqiInfoReqParameters &params)
Sched UL CGI Info Request.
std::map< LteFlowId_t, LogicalChannelConfigListElement_s > m_ueLogicalChannelsConfigList
Map of UE logical channel config list.
std::map< uint16_t, uint8_t > m_uesTxMode
txMode of the UEs
std::vector< uint16_t > m_rachAllocationMap
RACH allocation map.
void SetFfMacSchedSapUser(FfMacSchedSapUser *s) override
set the user part of the FfMacSchedSap that this Scheduler will interact with.
std::map< uint16_t, uint8_t > m_p10CqiRxed
Map of UE's DL CQI P01 received.
void DoDispose() override
Destructor implementation.
std::map< uint16_t, std::vector< uint16_t > > m_allocationMaps
Map of previous allocated UE per RBG (used to retrieve info from UL-CQI)
void DoSchedDlRachInfoReq(const FfMacSchedSapProvider::SchedDlRachInfoReqParameters &params)
Sched DL RACH Info Request.
std::map< uint16_t, UlHarqProcessesDciBuffer_t > m_ulHarqProcessesDciBuffer
UL HARQ process DCI buffer.
void RefreshUlCqiMaps()
Refresh UL CGI maps.
Ptr< LteAmc > m_amc
LTE AMC object.
void DoSchedDlCqiInfoReq(const FfMacSchedSapProvider::SchedDlCqiInfoReqParameters &params)
Sched DL CGI Info Request.
std::vector< DlInfoListElement_s > m_dlInfoListBuffered
DL HARQ retx buffered.
void DoCschedUeReleaseReq(const FfMacCschedSapProvider::CschedUeReleaseReqParameters &params)
Csched UE Release Request.
FfMacSchedSapProvider * GetFfMacSchedSapProvider() override
void SetFfMacCschedSapUser(FfMacCschedSapUser *s) override
set the user part of the FfMacCschedSap that this Scheduler will interact with.
std::map< uint16_t, CqasFlowPerf_t > m_flowStatsUl
Map of UE statistics (per RNTI basis)
FfMacSchedSapProvider * m_schedSapProvider
Sched SAP provider.
FfMacCschedSapProvider * GetFfMacCschedSapProvider() override
void DoCschedCellConfigReq(const FfMacCschedSapProvider::CschedCellConfigReqParameters &params)
Csched Cell Config Request.
friend class MemberCschedSapProvider< CqaFfMacScheduler >
allow MemberCschedSapProvider<CqaFfMacScheduler> class friend access
double EstimateUlSinr(uint16_t rnti, uint16_t rb)
Estimate UL Sinr.
void RefreshDlCqiMaps()
Refresh DL CGI maps.
void DoCschedUeConfigReq(const FfMacCschedSapProvider::CschedUeConfigReqParameters &params)
Csched UE Config Request.
FfMacCschedSapProvider::CschedCellConfigReqParameters m_cschedCellConfig
Internal parameters.
std::map< uint16_t, DlHarqProcessesStatus_t > m_dlHarqProcessesStatus
DL HARQ process statuses.
LteFfrSapUser * GetLteFfrSapUser() override
uint16_t m_nextRntiUl
RNTI of the next user to be served next scheduling in UL.
std::map< LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters > m_rlcBufferReq
Vectors of UE's LC info.
std::string m_CqaMetric
CQA metric name.
std::map< uint16_t, uint32_t > m_ceBsrRxed
Map of UE's buffer status reports received.
bool m_harqOn
m_harqOn when false inhibit the HARQ mechanisms (by default active)
void DoSchedUlSrInfoReq(const FfMacSchedSapProvider::SchedUlSrInfoReqParameters &params)
Sched UL Sr Info Request.
void TransmissionModeConfigurationUpdate(uint16_t rnti, uint8_t txMode)
Trans mode config update.
Provides the CSCHED SAP.
FfMacCschedSapUser class.
virtual void CschedUeConfigCnf(const CschedUeConfigCnfParameters &params)=0
CSCHED_UE_CONFIG_CNF.
virtual void CschedUeConfigUpdateInd(const CschedUeConfigUpdateIndParameters &params)=0
CSCHED_UE_UPDATE_IND.
Provides the SCHED SAP.
FfMacSchedSapUser class.
virtual void SchedUlConfigInd(const SchedUlConfigIndParameters &params)=0
SCHED_UL_CONFIG_IND.
virtual void SchedDlConfigInd(const SchedDlConfigIndParameters &params)=0
SCHED_DL_CONFIG_IND.
This abstract base class identifies the interface by means of which the helper object can plug on the...
UlCqiFilter_t m_ulCqiFilter
UL CQI filter.
static double fpS11dot3toDouble(uint16_t val)
Convert from fixed point S11.3 notation to double.
Service Access Point (SAP) offered by the Frequency Reuse algorithm instance to the MAC Scheduler ins...
Definition lte-ffr-sap.h:29
virtual uint8_t GetTpc(uint16_t rnti)=0
GetTpc.
virtual std::vector< bool > GetAvailableUlRbg()=0
Get vector of available RB in UL for this Cell.
virtual void ReportUlCqiInfo(const FfMacSchedSapProvider::SchedUlCqiInfoReqParameters &params)=0
ReportUlCqiInfo.
virtual bool IsUlRbgAvailableForUe(int i, uint16_t rnti)=0
Check if UE can be served on i-th RB in UL.
virtual void ReportDlCqiInfo(const FfMacSchedSapProvider::SchedDlCqiInfoReqParameters &params)=0
ReportDlCqiInfo.
virtual std::vector< bool > GetAvailableDlRbg()=0
Get vector of available RBG in DL for this Cell.
virtual uint16_t GetMinContinuousUlBandwidth()=0
Get the minimum continuous Ul bandwidth.
virtual bool IsDlRbgAvailableForUe(int i, uint16_t rnti)=0
Check if UE can be served on i-th RB in DL.
Service Access Point (SAP) offered by the eNodeB RRC instance to the Frequency Reuse algorithm instan...
Template for the implementation of the LteFfrSapUser as a member of an owner class of type C to which...
Smart pointer class similar to boost::intrusive_ptr.
static Time Now()
Return the current simulation virtual time.
Definition simulator.cc:197
Hold variables of type string.
Definition string.h:45
static uint8_t TxMode2LayerNum(uint8_t txMode)
Transmit mode 2 layer number.
a unique identifier for an interface.
Definition type-id.h:49
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition type-id.cc:1001
Hold an unsigned integer type.
Definition uinteger.h:34
#define MAX_LC_LIST
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition assert.h:55
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
Definition assert.h:75
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
Definition abort.h:97
#define NS_LOG_ERROR(msg)
Use NS_LOG to output a message of level LOG_ERROR.
Definition log.h:243
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition log.h:191
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition log.h:257
#define NS_LOG_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
Definition log.h:271
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
Definition log.h:264
Ptr< T > CreateObject(Args &&... args)
Create an object by type, with varying number of constructor parameters.
Definition object.h:619
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition object-base.h:35
#define HARQ_PERIOD
Definition lte-common.h:19
#define SRS_CQI_RNTI_VSP
Every class exported by the ns3 library is enclosed in the ns3 namespace.
int RBG_index
RBG index typedef.
Ptr< const AttributeChecker > MakeBooleanChecker()
Definition boolean.cc:113
std::vector< uint8_t > DlHarqProcessesTimer_t
DL HARQ process timer vector.
bool CqaKeyDescComparator(uint16_t key1, uint16_t key2)
CQA key comparator.
Ptr< const AttributeChecker > MakeUintegerChecker()
Definition uinteger.h:85
constexpr double NO_SINR
Value for SINR outside the range defined by FF-API, used to indicate that there is no CQI for this el...
std::map< CQI_value, LteFlowId_t, bool(*)(uint8_t, uint8_t)>::iterator t_it_CQIToUE
CQI value map iterator typedef.
Ptr< const AttributeAccessor > MakeUintegerAccessor(T1 a1)
Definition uinteger.h:35
std::multimap< HOL_group, std::set< LteFlowId_t >, bool(*)(int, int)> t_map_HOLgroupToUEs
HOL group map typedef.
int HOL_group
HOL group typedef.
std::vector< uint8_t > UlHarqProcessesStatus_t
UL HARQ process status vector.
std::vector< uint8_t > DlHarqProcessesStatus_t
DL HARQ process status vector.
std::map< CQI_value, LteFlowId_t, bool(*)(uint8_t, uint8_t)> t_map_CQIToUE
CQI value map typedef.
bool CQIValueDescComparator(uint8_t key1, uint8_t key2)
CQI value comparator function.
Ptr< T1 > DynamicCast(const Ptr< T2 > &p)
Cast a Ptr.
Definition ptr.h:580
std::vector< DlDciListElement_s > DlHarqProcessesDciBuffer_t
DL HARQ process DCI buffer vector.
@ SUCCESS
std::map< HOL_group, t_map_RBGToCQIsSorted >::iterator t_it_HOLGroupToRBGs
HOL group map iterator typedef.
constexpr uint32_t HARQ_DL_TIMEOUT
HARQ DL timeout.
std::map< RBG_index, t_map_CQIToUE >::iterator t_it_RBGToCQIsSorted
RBG index map iterator typedef.
std::map< HOL_group, t_map_RBGToCQIsSorted > t_map_HOLGroupToRBGs
HOL group map typedef.
constexpr uint32_t HARQ_PROC_NUM
Number of HARQ processes.
Ptr< const AttributeChecker > MakeStringChecker()
Definition string.cc:19
Ptr< const AttributeAccessor > MakeStringAccessor(T1 a1)
Definition string.h:46
Ptr< const AttributeAccessor > MakeBooleanAccessor(T1 a1)
Definition boolean.h:70
std::vector< RlcPduList_t > DlHarqRlcPduListBuffer_t
Vector of the 8 HARQ processes per UE.
std::map< HOL_group, std::set< LteFlowId_t > >::iterator t_it_HOLgroupToUEs
HOL group multi map iterator typedef.
static const int CqaType0AllocationRbg[4]
CGA Type 0 Allocation.
std::vector< UlDciListElement_s > UlHarqProcessesDciBuffer_t
UL HARQ process DCI buffer vector.
std::map< RBG_index, t_map_CQIToUE > t_map_RBGToCQIsSorted
RBG index map typedef.
uint8_t CQI_value
CQI value typedef.
bool CqaGroupDescComparator(int key1, int key2)
CGA group comparator function.
See section 4.3.8 buildDataListElement.
std::vector< std::vector< struct RlcPduListElement_s > > m_rlcPduList
RLC PDU list.
struct DlDciListElement_s m_dci
DCI.
See section 4.3.10 buildRARListElement.
CGA Flow Performance structure.
double lastAveragedThroughput
Past average throughput.
double secondLastAveragedThroughput
Second last average throughput.
double targetThroughput
Target throughput.
Time flowStart
flow start time
unsigned int lastTtiBytesTransmitted
Total bytes send by eNB in last tti for this UE.
unsigned long totalBytesTransmitted
Total bytes send by eNb for this UE.
See section 4.3.1 dlDciListElement.
std::vector< uint8_t > m_ndi
New data indicator.
uint8_t m_harqProcess
HARQ process.
uint32_t m_rbBitmap
RB bitmap.
std::vector< uint8_t > m_mcs
MCS.
uint8_t m_resAlloc
The type of resource allocation.
std::vector< uint16_t > m_tbsSize
The TBs size.
std::vector< uint8_t > m_rv
Redundancy version.
uint8_t m_tpc
Tx power control command.
Parameters of the CSCHED_LC_CONFIG_REQ primitive.
Parameters of the CSCHED_LC_RELEASE_REQ primitive.
Parameters of the CSCHED_UE_CONFIG_REQ primitive.
Parameters of the CSCHED_UE_RELEASE_REQ primitive.
Parameters of the CSCHED_UE_CONFIG_CNF primitive.
Parameters of the CSCHED_UE_CONFIG_UPDATE_IND primitive.
Parameters of the SCHED_DL_CQI_INFO_REQ primitive.
Parameters of the SCHED_DL_MAC_BUFFER_REQ primitive.
Parameters of the SCHED_DL_PAGING_BUFFER_REQ primitive.
Parameters of the SCHED_DL_RACH_INFO_REQ primitive.
Parameters of the SCHED_DL_TRIGGER_REQ primitive.
Parameters of the SCHED_UL_CQI_INFO_REQ primitive.
Parameters of the SCHED_UL_MAC_CTRL_INFO_REQ primitive.
Parameters of the SCHED_UL_NOISE_INTERFERENCE_REQ primitive.
Parameters of the SCHED_UL_SR_INFO_REQ primitive.
Parameters of the SCHED_UL_TRIGGER_REQ primitive.
std::vector< BuildDataListElement_s > m_buildDataList
build data list
std::vector< BuildRarListElement_s > m_buildRarList
build rar list
uint8_t m_nrOfPdcchOfdmSymbols
number of PDCCH OFDM symbols
Parameters of the SCHED_UL_CONFIG_IND primitive.
std::vector< UlDciListElement_s > m_dciList
DCI list.
See section 4.3.4 logicalChannelConfigListElement.
uint64_t m_eRabGuaranteedBitrateDl
ERAB guaranteed bit rate DL.
LteFlowId structure.
Definition lte-common.h:32
uint8_t m_lcId
LCID.
Definition lte-common.h:34
uint16_t m_rnti
RNTI.
Definition lte-common.h:33
See section 4.3.9 rlcPDU_ListElement.
uint8_t m_logicalChannelIdentity
logical channel identity
See section 4.3.2 ulDciListElement.
int8_t m_pdcchPowerOffset
CCH power offset.
int8_t m_tpc
Tx power control command.
uint8_t m_dai
DL assignment index.
uint8_t m_cceIndex
Control Channel Element index.
uint8_t m_ulIndex
UL index.
uint8_t m_ueTxAntennaSelection
UE antenna selection.
bool m_cqiRequest
CQI request.
uint8_t m_freqHopping
freq hopping
uint8_t m_aggrLevel
The aggregation level.
bool m_ulDelay
UL delay?
int8_t m_tpc
Tx power control command.
bool m_cqiRequest
CQI request?
bool m_hopping
hopping?
uint16_t m_tbSize
size
uint8_t m_rbLen
length
uint8_t m_mcs
MCS.
uint8_t m_rbStart
start
uint16_t m_rnti
RNTI.
qos_rb_and_CQI_assigned_to_lc
uint8_t cqi_value_for_lc
CQI indicator value.
uint16_t resource_block_index
Resource block indexHOL_GROUP_index.