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 s.cqi_value_for_lc = UeToCQIValue.find(userWithMaximumMetric)->second;
1499 s.resource_block_index = currentRB;
1500
1501 auto itMap = allocationMapPerRntiPerLCId.find(userWithMaximumMetric.m_rnti);
1502
1503 if (itMap == allocationMapPerRntiPerLCId.end())
1504 {
1505 std::multimap<uint8_t, qos_rb_and_CQI_assigned_to_lc> tempMap;
1506 tempMap.insert(
1507 std::pair<uint8_t, qos_rb_and_CQI_assigned_to_lc>(userWithMaximumMetric.m_lcId,
1508 s));
1509 allocationMapPerRntiPerLCId.insert(
1510 std::pair<uint16_t, std::multimap<uint8_t, qos_rb_and_CQI_assigned_to_lc>>(
1511 userWithMaximumMetric.m_rnti,
1512 tempMap));
1513 }
1514 else
1515 {
1516 itMap->second.insert(
1517 std::pair<uint8_t, qos_rb_and_CQI_assigned_to_lc>(userWithMaximumMetric.m_lcId,
1518 s));
1519 }
1520
1521 // erase current RBG from the list of available RBG
1522 availableRBGs.erase(currentRB);
1523
1524 if (UeToAmountOfDataToTransfer.find(userWithMaximumMetric)->second <=
1525 UeToAmountOfAssignedResources.find(userWithMaximumMetric)->second * tolerance)
1526 //||(UeHasReachedGBR.find(userWithMaximumMetric)->second == true))
1527 {
1528 itCurrentGroup->second.erase(userWithMaximumMetric);
1529 }
1530
1531 } // while there are more users in current group
1532 } // while there are more groups of users
1533
1534 // reset TTI stats of users
1535 for (auto itStats = m_flowStatsDl.begin(); itStats != m_flowStatsDl.end(); itStats++)
1536 {
1537 (*itStats).second.lastTtiBytesTransmitted = 0;
1538 }
1539
1540 // 3) Creating the correspondent DCIs (Generate the transmission opportunities by grouping the
1541 // RBGs of the same RNTI)
1542 // FfMacSchedSapUser::SchedDlConfigIndParameters ret;
1543 auto itMap = allocationMapPerRntiPerLCId.begin();
1544 std::map<uint16_t, double> m_rnti_per_ratio;
1545
1546 while (itMap != allocationMapPerRntiPerLCId.end())
1547 {
1548 // create new BuildDataListElement_s for this LC
1550 newEl.m_rnti = (*itMap).first;
1551 NS_LOG_INFO("Scheduled RNTI:" << newEl.m_rnti);
1552 // create the DlDciListElement_s
1553 DlDciListElement_s newDci;
1554 std::vector<RlcPduListElement_s> newRlcPduLe;
1555 newDci.m_rnti = (*itMap).first;
1556 newDci.m_harqProcess = UpdateHarqProcessId((*itMap).first);
1557 uint16_t lcActives = LcActivePerFlow(itMap->first);
1558 if (lcActives == 0)
1559 { // if there is still no buffer report information on any flow
1560 lcActives = 1;
1561 }
1562 // NS_LOG_DEBUG (this << "Allocate user " << newEl.m_rnti << " rbg " << lcActives);
1563 uint16_t RbgPerRnti = (*itMap).second.size();
1564 double doubleRBgPerRnti = RbgPerRnti;
1565 double doubleRbgNum = numberOfRBGs;
1566 double rrRatio = doubleRBgPerRnti / doubleRbgNum;
1567 m_rnti_per_ratio.insert(std::pair<uint16_t, double>((*itMap).first, rrRatio));
1568 uint8_t worstCqi = 15;
1569
1570 // assign the worst value of CQI that user experienced on any of its subbands
1571 for (auto it = (*itMap).second.begin(); it != (*itMap).second.end(); it++)
1572 {
1573 if (it->second.cqi_value_for_lc < worstCqi)
1574 {
1575 worstCqi = it->second.cqi_value_for_lc;
1576 }
1577 }
1578
1579 newDci.m_mcs.push_back(m_amc->GetMcsFromCqi(worstCqi));
1580 int tbSize = (m_amc->GetDlTbSizeFromMcs(newDci.m_mcs.at(0), RbgPerRnti * rbgSize) /
1581 8); // (size of TB in bytes according to table 7.1.7.2.1-1 of 36.213)
1582 newDci.m_tbsSize.push_back(tbSize);
1583 newDci.m_resAlloc = 0; // only allocation type 0 at this stage
1584 newDci.m_rbBitmap = 0; // TBD (32 bit bitmap see 7.1.6 of 36.213)
1585 uint32_t rbgMask = 0;
1586 for (auto itRBGsPerRNTI = (*itMap).second.begin(); itRBGsPerRNTI != (*itMap).second.end();
1587 itRBGsPerRNTI++)
1588 {
1589 rbgMask = rbgMask + (0x1 << itRBGsPerRNTI->second.resource_block_index);
1590 }
1591 newDci.m_rbBitmap = rbgMask; // (32 bit bitmap see 7.1.6 of 36.213)
1592 // NOTE: In this first version of CqaFfMacScheduler, it is assumed one flow per user.
1593 // create the rlc PDUs -> equally divide resources among active LCs
1594 for (auto itBufReq = m_rlcBufferReq.begin(); itBufReq != m_rlcBufferReq.end(); itBufReq++)
1595 {
1596 if (((*itBufReq).first.m_rnti == (*itMap).first) &&
1597 (((*itBufReq).second.m_rlcTransmissionQueueSize > 0) ||
1598 ((*itBufReq).second.m_rlcRetransmissionQueueSize > 0) ||
1599 ((*itBufReq).second.m_rlcStatusPduSize > 0)))
1600 {
1601 std::vector<RlcPduListElement_s> newRlcPduLe;
1602 // for (uint8_t j = 0; j < nLayer; j++)
1603 //{
1604 RlcPduListElement_s newRlcEl;
1605 newRlcEl.m_logicalChannelIdentity = (*itBufReq).first.m_lcId;
1606 // newRlcEl.m_size = newDci.m_tbsSize.at (j) / lcActives;
1607 newRlcEl.m_size = tbSize / lcActives;
1608 // NS_LOG_INFO (this << " LCID " << (uint32_t) newRlcEl.m_logicalChannelIdentity <<
1609 // " size " << newRlcEl.m_size << " layer " << (uint16_t)j);
1610 newRlcPduLe.push_back(newRlcEl);
1612 newRlcEl.m_logicalChannelIdentity,
1613 newRlcEl.m_size);
1614 if (m_harqOn)
1615 {
1616 // store RLC PDU list for HARQ
1617 auto itRlcPdu = m_dlHarqProcessesRlcPduListBuffer.find((*itMap).first);
1618 if (itRlcPdu == m_dlHarqProcessesRlcPduListBuffer.end())
1619 {
1620 NS_FATAL_ERROR("Unable to find RlcPdcList in HARQ buffer for RNTI "
1621 << (*itMap).first);
1622 }
1623 int j = 0;
1624 (*itRlcPdu).second.at(j).at(newDci.m_harqProcess).push_back(newRlcEl);
1625 }
1626 // }
1627 newEl.m_rlcPduList.push_back(newRlcPduLe);
1628 }
1629 if ((*itBufReq).first.m_rnti > (*itMap).first)
1630 {
1631 break;
1632 }
1633 }
1634 // for (uint8_t j = 0; j < nLayer; j++)
1635 // {
1636 newDci.m_ndi.push_back(1);
1637 newDci.m_rv.push_back(0);
1638 //}
1639
1640 newDci.m_tpc = m_ffrSapProvider->GetTpc((*itMap).first);
1641
1642 newEl.m_dci = newDci;
1643
1644 if (m_harqOn)
1645 {
1646 // store DCI for HARQ
1647 auto itDci = m_dlHarqProcessesDciBuffer.find(newEl.m_rnti);
1648 if (itDci == m_dlHarqProcessesDciBuffer.end())
1649 {
1650 NS_FATAL_ERROR("Unable to find RNTI entry in DCI HARQ buffer for RNTI "
1651 << newEl.m_rnti);
1652 }
1653 (*itDci).second.at(newDci.m_harqProcess) = newDci;
1654 // refresh timer
1655 auto itHarqTimer = m_dlHarqProcessesTimer.find(newEl.m_rnti);
1656 if (itHarqTimer == m_dlHarqProcessesTimer.end())
1657 {
1658 NS_FATAL_ERROR("Unable to find HARQ timer for RNTI " << (uint16_t)newEl.m_rnti);
1659 }
1660 (*itHarqTimer).second.at(newDci.m_harqProcess) = 0;
1661 }
1662
1663 // ...more parameters -> ignored in this version
1664
1665 ret.m_buildDataList.push_back(newEl);
1666 // update UE stats
1667 auto it = m_flowStatsDl.find((*itMap).first);
1668 if (it != m_flowStatsDl.end())
1669 {
1670 (*it).second.lastTtiBytesTransmitted = tbSize;
1671 }
1672 else
1673 {
1674 NS_FATAL_ERROR(this << " No Stats for this allocated UE");
1675 }
1676
1677 itMap++;
1678 } // end while allocation
1679 ret.m_nrOfPdcchOfdmSymbols = 1; // TODO: check correct value according the DCIs txed
1680
1681 // update UEs stats
1682 NS_LOG_INFO(this << " Update UEs statistics");
1683 for (auto itStats = m_flowStatsDl.begin(); itStats != m_flowStatsDl.end(); itStats++)
1684 {
1685 if (allocationMapPerRntiPerLCId.find(itStats->first) != allocationMapPerRntiPerLCId.end())
1686 {
1687 (*itStats).second.secondLastAveragedThroughput =
1688 ((1.0 - (1 / m_timeWindow)) * (*itStats).second.secondLastAveragedThroughput) +
1689 ((1 / m_timeWindow) * (double)((*itStats).second.lastTtiBytesTransmitted / 0.001));
1690 }
1691
1692 (*itStats).second.totalBytesTransmitted += (*itStats).second.lastTtiBytesTransmitted;
1693 // update average throughput (see eq. 12.3 of Sec 12.3.1.2 of LTE – The UMTS Long Term
1694 // Evolution, Ed Wiley)
1695 (*itStats).second.lastAveragedThroughput =
1696 ((1.0 - (1.0 / m_timeWindow)) * (*itStats).second.lastAveragedThroughput) +
1697 ((1.0 / m_timeWindow) * (double)((*itStats).second.lastTtiBytesTransmitted / 0.001));
1698 NS_LOG_INFO(this << " UE total bytes " << (*itStats).second.totalBytesTransmitted);
1699 NS_LOG_INFO(this << " UE average throughput " << (*itStats).second.lastAveragedThroughput);
1700 (*itStats).second.lastTtiBytesTransmitted = 0;
1701 }
1702
1704
1705 int count_allocated_resource_blocks = 0;
1706 for (auto itMap = allocationMapPerRntiPerLCId.begin();
1707 itMap != allocationMapPerRntiPerLCId.end();
1708 itMap++)
1709 {
1710 count_allocated_resource_blocks += itMap->second.size();
1711 }
1712 NS_LOG_INFO(this << " Allocated RBs:" << count_allocated_resource_blocks);
1713}
1714
1715void
1718{
1719 NS_LOG_FUNCTION(this);
1720
1721 m_rachList = params.m_rachList;
1722}
1723
1724void
1727{
1728 NS_LOG_FUNCTION(this);
1730
1731 for (unsigned int i = 0; i < params.m_cqiList.size(); i++)
1732 {
1733 if (params.m_cqiList.at(i).m_cqiType == CqiListElement_s::P10)
1734 {
1735 NS_LOG_LOGIC("wideband CQI " << (uint32_t)params.m_cqiList.at(i).m_wbCqi.at(0)
1736 << " reported");
1737 uint16_t rnti = params.m_cqiList.at(i).m_rnti;
1738 auto it = m_p10CqiRxed.find(rnti);
1739 if (it == m_p10CqiRxed.end())
1740 {
1741 // create the new entry
1742 m_p10CqiRxed[rnti] =
1743 params.m_cqiList.at(i).m_wbCqi.at(0); // only codeword 0 at this stage (SISO)
1744 // generate correspondent timer
1745 m_p10CqiTimers.insert(std::pair<uint16_t, uint32_t>(rnti, m_cqiTimersThreshold));
1746 }
1747 else
1748 {
1749 // update the CQI value and refresh correspondent timer
1750 (*it).second = params.m_cqiList.at(i).m_wbCqi.at(0);
1751 // update correspondent timer
1752 auto itTimers = m_p10CqiTimers.find(rnti);
1753 (*itTimers).second = m_cqiTimersThreshold;
1754 }
1755 }
1756 else if (params.m_cqiList.at(i).m_cqiType == CqiListElement_s::A30)
1757 {
1758 // subband CQI reporting high layer configured
1759 uint16_t rnti = params.m_cqiList.at(i).m_rnti;
1760 auto it = m_a30CqiRxed.find(rnti);
1761 if (it == m_a30CqiRxed.end())
1762 {
1763 // create the new entry
1764 m_a30CqiRxed[rnti] = params.m_cqiList.at(i).m_sbMeasResult;
1765 m_a30CqiTimers.insert(std::pair<uint16_t, uint32_t>(rnti, m_cqiTimersThreshold));
1766 }
1767 else
1768 {
1769 // update the CQI value and refresh correspondent timer
1770 (*it).second = params.m_cqiList.at(i).m_sbMeasResult;
1771 auto itTimers = m_a30CqiTimers.find(rnti);
1772 (*itTimers).second = m_cqiTimersThreshold;
1773 }
1774 }
1775 else
1776 {
1777 NS_LOG_ERROR(this << " CQI type unknown");
1778 }
1779 }
1780}
1781
1782double
1783CqaFfMacScheduler::EstimateUlSinr(uint16_t rnti, uint16_t rb)
1784{
1785 auto itCqi = m_ueCqi.find(rnti);
1786 if (itCqi == m_ueCqi.end())
1787 {
1788 // no cqi info about this UE
1789 return NO_SINR;
1790 }
1791 else
1792 {
1793 // take the average SINR value among the available
1794 double sinrSum = 0;
1795 unsigned int sinrNum = 0;
1796 for (uint32_t i = 0; i < m_cschedCellConfig.m_ulBandwidth; i++)
1797 {
1798 double sinr = (*itCqi).second.at(i);
1799 if (sinr != NO_SINR)
1800 {
1801 sinrSum += sinr;
1802 sinrNum++;
1803 }
1804 }
1805 double estimatedSinr = (sinrNum > 0) ? (sinrSum / sinrNum) : DBL_MAX;
1806 // store the value
1807 (*itCqi).second.at(rb) = estimatedSinr;
1808 return estimatedSinr;
1809 }
1810}
1811
1812void
1815{
1816 NS_LOG_FUNCTION(this << " UL - Frame no. " << (params.m_sfnSf >> 4) << " subframe no. "
1817 << (0xF & params.m_sfnSf) << " size " << params.m_ulInfoList.size());
1818
1821
1822 // Generate RBs map
1824 std::vector<bool> rbMap;
1825 uint16_t rbAllocatedNum = 0;
1826 std::set<uint16_t> rntiAllocated;
1827 std::vector<uint16_t> rbgAllocationMap;
1828 // update with RACH allocation map
1829 rbgAllocationMap = m_rachAllocationMap;
1830 // rbgAllocationMap.resize (m_cschedCellConfig.m_ulBandwidth, 0);
1831 m_rachAllocationMap.clear();
1833
1834 rbMap.resize(m_cschedCellConfig.m_ulBandwidth, false);
1835
1837
1838 for (auto it = rbMap.begin(); it != rbMap.end(); it++)
1839 {
1840 if (*it)
1841 {
1842 rbAllocatedNum++;
1843 }
1844 }
1845
1846 uint8_t minContinuousUlBandwidth = m_ffrSapProvider->GetMinContinuousUlBandwidth();
1847 uint8_t ffrUlBandwidth = m_cschedCellConfig.m_ulBandwidth - rbAllocatedNum;
1848
1849 // remove RACH allocation
1850 for (uint16_t i = 0; i < m_cschedCellConfig.m_ulBandwidth; i++)
1851 {
1852 if (rbgAllocationMap.at(i) != 0)
1853 {
1854 rbMap.at(i) = true;
1855 NS_LOG_DEBUG(this << " Allocated for RACH " << i);
1856 }
1857 }
1858
1859 if (m_harqOn)
1860 {
1861 // Process UL HARQ feedback
1862 for (std::size_t i = 0; i < params.m_ulInfoList.size(); i++)
1863 {
1864 if (params.m_ulInfoList.at(i).m_receptionStatus == UlInfoListElement_s::NotOk)
1865 {
1866 // retx correspondent block: retrieve the UL-DCI
1867 uint16_t rnti = params.m_ulInfoList.at(i).m_rnti;
1868 auto itProcId = m_ulHarqCurrentProcessId.find(rnti);
1869 if (itProcId == m_ulHarqCurrentProcessId.end())
1870 {
1871 NS_LOG_ERROR("No info find in HARQ buffer for UE (might change eNB) " << rnti);
1872 }
1873 uint8_t harqId = (uint8_t)((*itProcId).second - HARQ_PERIOD) % HARQ_PROC_NUM;
1874 NS_LOG_INFO(this << " UL-HARQ retx RNTI " << rnti << " harqId " << (uint16_t)harqId
1875 << " i " << i << " size " << params.m_ulInfoList.size());
1876 auto itHarq = m_ulHarqProcessesDciBuffer.find(rnti);
1877 if (itHarq == m_ulHarqProcessesDciBuffer.end())
1878 {
1879 NS_LOG_ERROR("No info find in HARQ buffer for UE (might change eNB) " << rnti);
1880 continue;
1881 }
1882 UlDciListElement_s dci = (*itHarq).second.at(harqId);
1883 auto itStat = m_ulHarqProcessesStatus.find(rnti);
1884 if (itStat == m_ulHarqProcessesStatus.end())
1885 {
1886 NS_LOG_ERROR("No info find in HARQ buffer for UE (might change eNB) " << rnti);
1887 }
1888 if ((*itStat).second.at(harqId) >= 3)
1889 {
1890 NS_LOG_INFO("Max number of retransmissions reached (UL)-> drop process");
1891 continue;
1892 }
1893 bool free = true;
1894
1895 for (int j = dci.m_rbStart; j < dci.m_rbStart + dci.m_rbLen; j++)
1896 {
1897 if (rbMap.at(j))
1898 {
1899 free = false;
1900 NS_LOG_INFO(this << " BUSY " << j);
1901 }
1902 }
1903 if (free)
1904 {
1905 // retx on the same RBs
1906 for (int j = dci.m_rbStart; j < dci.m_rbStart + dci.m_rbLen; j++)
1907 {
1908 rbMap.at(j) = true;
1909 rbgAllocationMap.at(j) = dci.m_rnti;
1910 NS_LOG_INFO("\tRB " << j);
1911 rbAllocatedNum++;
1912 }
1913 NS_LOG_INFO(this << " Send retx in the same RBs " << (uint16_t)dci.m_rbStart
1914 << " to " << dci.m_rbStart + dci.m_rbLen << " RV "
1915 << (*itStat).second.at(harqId) + 1);
1916 }
1917 else
1918 {
1919 NS_LOG_INFO("Cannot allocate retx due to RACH allocations for UE " << rnti);
1920 continue;
1921 }
1922 dci.m_ndi = 0;
1923 // Update HARQ buffers with new HarqId
1924 (*itStat).second.at((*itProcId).second) = (*itStat).second.at(harqId) + 1;
1925 (*itStat).second.at(harqId) = 0;
1926 (*itHarq).second.at((*itProcId).second) = dci;
1927 ret.m_dciList.push_back(dci);
1928 rntiAllocated.insert(dci.m_rnti);
1929 }
1930 else
1931 {
1932 NS_LOG_INFO(this << " HARQ-ACK feedback from RNTI "
1933 << params.m_ulInfoList.at(i).m_rnti);
1934 }
1935 }
1936 }
1937
1938 std::map<uint16_t, uint32_t>::iterator it;
1939 int nflows = 0;
1940
1941 for (it = m_ceBsrRxed.begin(); it != m_ceBsrRxed.end(); it++)
1942 {
1943 auto itRnti = rntiAllocated.find((*it).first);
1944 // select UEs with queues not empty and not yet allocated for HARQ
1945 if (((*it).second > 0) && (itRnti == rntiAllocated.end()))
1946 {
1947 nflows++;
1948 }
1949 }
1950
1951 if (nflows == 0)
1952 {
1953 if (!ret.m_dciList.empty())
1954 {
1955 m_allocationMaps[params.m_sfnSf] = rbgAllocationMap;
1957 }
1958
1959 return; // no flows to be scheduled
1960 }
1961
1962 // Divide the remaining resources equally among the active users starting from the subsequent
1963 // one served last scheduling trigger
1964 uint16_t tempRbPerFlow = (ffrUlBandwidth) / (nflows + rntiAllocated.size());
1965 uint16_t rbPerFlow =
1966 (minContinuousUlBandwidth < tempRbPerFlow) ? minContinuousUlBandwidth : tempRbPerFlow;
1967
1968 if (rbPerFlow < 3)
1969 {
1970 rbPerFlow = 3; // at least 3 rbg per flow (till available resource) to ensure TxOpportunity
1971 // >= 7 bytes
1972 }
1973 int rbAllocated = 0;
1974
1975 if (m_nextRntiUl != 0)
1976 {
1977 for (it = m_ceBsrRxed.begin(); it != m_ceBsrRxed.end(); it++)
1978 {
1979 if ((*it).first == m_nextRntiUl)
1980 {
1981 break;
1982 }
1983 }
1984 if (it == m_ceBsrRxed.end())
1985 {
1986 NS_LOG_ERROR(this << " no user found");
1987 }
1988 }
1989 else
1990 {
1991 it = m_ceBsrRxed.begin();
1992 m_nextRntiUl = (*it).first;
1993 }
1994 do
1995 {
1996 auto itRnti = rntiAllocated.find((*it).first);
1997 if ((itRnti != rntiAllocated.end()) || ((*it).second == 0))
1998 {
1999 // UE already allocated for UL-HARQ -> skip it
2000 NS_LOG_DEBUG(this << " UE already allocated in HARQ -> discarded, RNTI "
2001 << (*it).first);
2002 it++;
2003 if (it == m_ceBsrRxed.end())
2004 {
2005 // restart from the first
2006 it = m_ceBsrRxed.begin();
2007 }
2008 continue;
2009 }
2010 if (rbAllocated + rbPerFlow - 1 > m_cschedCellConfig.m_ulBandwidth)
2011 {
2012 // limit to physical resources last resource assignment
2013 rbPerFlow = m_cschedCellConfig.m_ulBandwidth - rbAllocated;
2014 // at least 3 rbg per flow to ensure TxOpportunity >= 7 bytes
2015 if (rbPerFlow < 3)
2016 {
2017 // terminate allocation
2018 rbPerFlow = 0;
2019 }
2020 }
2021
2022 rbAllocated = 0;
2023 UlDciListElement_s uldci;
2024 uldci.m_rnti = (*it).first;
2025 uldci.m_rbLen = rbPerFlow;
2026 bool allocated = false;
2027 NS_LOG_INFO(this << " RB Allocated " << rbAllocated << " rbPerFlow " << rbPerFlow
2028 << " flows " << nflows);
2029 while ((!allocated) && ((rbAllocated + rbPerFlow - m_cschedCellConfig.m_ulBandwidth) < 1) &&
2030 (rbPerFlow != 0))
2031 {
2032 // check availability
2033 bool free = true;
2034 for (int j = rbAllocated; j < rbAllocated + rbPerFlow; j++)
2035 {
2036 if (rbMap.at(j))
2037 {
2038 free = false;
2039 break;
2040 }
2041 if (!m_ffrSapProvider->IsUlRbgAvailableForUe(j, (*it).first))
2042 {
2043 free = false;
2044 break;
2045 }
2046 }
2047 if (free)
2048 {
2049 NS_LOG_INFO(this << "RNTI: " << (*it).first << " RB Allocated " << rbAllocated
2050 << " rbPerFlow " << rbPerFlow << " flows " << nflows);
2051 uldci.m_rbStart = rbAllocated;
2052
2053 for (int j = rbAllocated; j < rbAllocated + rbPerFlow; j++)
2054 {
2055 rbMap.at(j) = true;
2056 // store info on allocation for managing ul-cqi interpretation
2057 rbgAllocationMap.at(j) = (*it).first;
2058 }
2059 rbAllocated += rbPerFlow;
2060 allocated = true;
2061 break;
2062 }
2063 rbAllocated++;
2064 if (rbAllocated + rbPerFlow - 1 > m_cschedCellConfig.m_ulBandwidth)
2065 {
2066 // limit to physical resources last resource assignment
2067 rbPerFlow = m_cschedCellConfig.m_ulBandwidth - rbAllocated;
2068 // at least 3 rbg per flow to ensure TxOpportunity >= 7 bytes
2069 if (rbPerFlow < 3)
2070 {
2071 // terminate allocation
2072 rbPerFlow = 0;
2073 }
2074 }
2075 }
2076 if (!allocated)
2077 {
2078 // unable to allocate new resource: finish scheduling
2079 // m_nextRntiUl = (*it).first;
2080 // if (ret.m_dciList.size () > 0)
2081 // {
2082 // m_schedSapUser->SchedUlConfigInd (ret);
2083 // }
2084 // m_allocationMaps[params.m_sfnSf] = rbgAllocationMap; return;
2085 break;
2086 }
2087
2088 auto itCqi = m_ueCqi.find((*it).first);
2089 int cqi = 0;
2090 if (itCqi == m_ueCqi.end())
2091 {
2092 // no cqi info about this UE
2093 uldci.m_mcs = 0; // MCS 0 -> UL-AMC TBD
2094 }
2095 else
2096 {
2097 // take the lowest CQI value (worst RB)
2098 NS_ABORT_MSG_IF((*itCqi).second.empty(),
2099 "CQI of RNTI = " << (*it).first << " has expired");
2100 double minSinr = (*itCqi).second.at(uldci.m_rbStart);
2101 if (minSinr == NO_SINR)
2102 {
2103 minSinr = EstimateUlSinr((*it).first, uldci.m_rbStart);
2104 }
2105 for (uint16_t i = uldci.m_rbStart; i < uldci.m_rbStart + uldci.m_rbLen; i++)
2106 {
2107 double sinr = (*itCqi).second.at(i);
2108 if (sinr == NO_SINR)
2109 {
2110 sinr = EstimateUlSinr((*it).first, i);
2111 }
2112 if (sinr < minSinr)
2113 {
2114 minSinr = sinr;
2115 }
2116 }
2117
2118 // translate SINR -> cqi: WILD ACK: same as DL
2119 double s = log2(1 + (std::pow(10, minSinr / 10) / ((-std::log(5.0 * 0.00005)) / 1.5)));
2120 cqi = m_amc->GetCqiFromSpectralEfficiency(s);
2121 if (cqi == 0)
2122 {
2123 it++;
2124 if (it == m_ceBsrRxed.end())
2125 {
2126 // restart from the first
2127 it = m_ceBsrRxed.begin();
2128 }
2129 NS_LOG_DEBUG(this << " UE discarded for CQI = 0, RNTI " << uldci.m_rnti);
2130 // remove UE from allocation map
2131 for (uint16_t i = uldci.m_rbStart; i < uldci.m_rbStart + uldci.m_rbLen; i++)
2132 {
2133 rbgAllocationMap.at(i) = 0;
2134 }
2135 continue; // CQI == 0 means "out of range" (see table 7.2.3-1 of 36.213)
2136 }
2137 uldci.m_mcs = m_amc->GetMcsFromCqi(cqi);
2138 }
2139
2140 uldci.m_tbSize = (m_amc->GetUlTbSizeFromMcs(uldci.m_mcs, rbPerFlow) / 8);
2142 uldci.m_ndi = 1;
2143 uldci.m_cceIndex = 0;
2144 uldci.m_aggrLevel = 1;
2145 uldci.m_ueTxAntennaSelection = 3; // antenna selection OFF
2146 uldci.m_hopping = false;
2147 uldci.m_n2Dmrs = 0;
2148 uldci.m_tpc = 0; // no power control
2149 uldci.m_cqiRequest = false; // only period CQI at this stage
2150 uldci.m_ulIndex = 0; // TDD parameter
2151 uldci.m_dai = 1; // TDD parameter
2152 uldci.m_freqHopping = 0;
2153 uldci.m_pdcchPowerOffset = 0; // not used
2154 ret.m_dciList.push_back(uldci);
2155 // store DCI for HARQ_PERIOD
2156 uint8_t harqId = 0;
2157 if (m_harqOn)
2158 {
2159 auto itProcId = m_ulHarqCurrentProcessId.find(uldci.m_rnti);
2160 if (itProcId == m_ulHarqCurrentProcessId.end())
2161 {
2162 NS_FATAL_ERROR("No info find in HARQ buffer for UE " << uldci.m_rnti);
2163 }
2164 harqId = (*itProcId).second;
2165 auto itDci = m_ulHarqProcessesDciBuffer.find(uldci.m_rnti);
2166 if (itDci == m_ulHarqProcessesDciBuffer.end())
2167 {
2168 NS_FATAL_ERROR("Unable to find RNTI entry in UL DCI HARQ buffer for RNTI "
2169 << uldci.m_rnti);
2170 }
2171 (*itDci).second.at(harqId) = uldci;
2172 // Update HARQ process status (RV 0)
2173 auto itStat = m_ulHarqProcessesStatus.find(uldci.m_rnti);
2174 if (itStat == m_ulHarqProcessesStatus.end())
2175 {
2176 NS_LOG_ERROR("No info find in HARQ buffer for UE (might change eNB) "
2177 << uldci.m_rnti);
2178 }
2179 (*itStat).second.at(harqId) = 0;
2180 }
2181
2182 NS_LOG_INFO(this << " UE Allocation RNTI " << (*it).first << " startPRB "
2183 << (uint32_t)uldci.m_rbStart << " nPRB " << (uint32_t)uldci.m_rbLen
2184 << " CQI " << cqi << " MCS " << (uint32_t)uldci.m_mcs << " TBsize "
2185 << uldci.m_tbSize << " RbAlloc " << rbAllocated << " harqId "
2186 << (uint16_t)harqId);
2187
2188 // update TTI UE stats
2189 auto itStats = m_flowStatsUl.find((*it).first);
2190 if (itStats != m_flowStatsUl.end())
2191 {
2192 (*itStats).second.lastTtiBytesTransmitted = uldci.m_tbSize;
2193 }
2194 else
2195 {
2196 NS_LOG_DEBUG(this << " No Stats for this allocated UE");
2197 }
2198
2199 it++;
2200 if (it == m_ceBsrRxed.end())
2201 {
2202 // restart from the first
2203 it = m_ceBsrRxed.begin();
2204 }
2205 if ((rbAllocated == m_cschedCellConfig.m_ulBandwidth) || (rbPerFlow == 0))
2206 {
2207 // Stop allocation: no more PRBs
2208 m_nextRntiUl = (*it).first;
2209 break;
2210 }
2211 } while (((*it).first != m_nextRntiUl) && (rbPerFlow != 0));
2212
2213 // Update global UE stats
2214 // update UEs stats
2215 for (auto itStats = m_flowStatsUl.begin(); itStats != m_flowStatsUl.end(); itStats++)
2216 {
2217 (*itStats).second.totalBytesTransmitted += (*itStats).second.lastTtiBytesTransmitted;
2218 // update average throughput (see eq. 12.3 of Sec 12.3.1.2 of LTE – The UMTS Long Term
2219 // Evolution, Ed Wiley)
2220 (*itStats).second.lastAveragedThroughput =
2221 ((1.0 - (1.0 / m_timeWindow)) * (*itStats).second.lastAveragedThroughput) +
2222 ((1.0 / m_timeWindow) * (double)((*itStats).second.lastTtiBytesTransmitted / 0.001));
2223 NS_LOG_INFO(this << " UE total bytes " << (*itStats).second.totalBytesTransmitted);
2224 NS_LOG_INFO(this << " UE average throughput " << (*itStats).second.lastAveragedThroughput);
2225 (*itStats).second.lastTtiBytesTransmitted = 0;
2226 }
2227 m_allocationMaps[params.m_sfnSf] = rbgAllocationMap;
2229}
2230
2231void
2237
2238void
2244
2245void
2248{
2249 NS_LOG_FUNCTION(this);
2250
2251 for (unsigned int i = 0; i < params.m_macCeList.size(); i++)
2252 {
2253 if (params.m_macCeList.at(i).m_macCeType == MacCeListElement_s::BSR)
2254 {
2255 // buffer status report
2256 // note that this scheduler does not differentiate the
2257 // allocation according to which LCGs have more/less bytes
2258 // to send.
2259 // Hence the BSR of different LCGs are just summed up to get
2260 // a total queue size that is used for allocation purposes.
2261
2262 uint32_t buffer = 0;
2263 for (uint8_t lcg = 0; lcg < 4; ++lcg)
2264 {
2265 uint8_t bsrId = params.m_macCeList.at(i).m_macCeValue.m_bufferStatus.at(lcg);
2266 buffer += BufferSizeLevelBsr::BsrId2BufferSize(bsrId);
2267 }
2268
2269 uint16_t rnti = params.m_macCeList.at(i).m_rnti;
2270 NS_LOG_LOGIC(this << "RNTI=" << rnti << " buffer=" << buffer);
2271 auto it = m_ceBsrRxed.find(rnti);
2272 if (it == m_ceBsrRxed.end())
2273 {
2274 // create the new entry
2275 m_ceBsrRxed.insert(std::pair<uint16_t, uint32_t>(rnti, buffer));
2276 }
2277 else
2278 {
2279 // update the buffer size value
2280 (*it).second = buffer;
2281 }
2282 }
2283 }
2284}
2285
2286void
2289{
2290 NS_LOG_FUNCTION(this);
2291 // retrieve the allocation for this subframe
2292 switch (m_ulCqiFilter)
2293 {
2295 // filter all the CQIs that are not SRS based
2296 if (params.m_ulCqi.m_type != UlCqi_s::SRS)
2297 {
2298 return;
2299 }
2300 }
2301 break;
2303 // filter all the CQIs that are not SRS based
2304 if (params.m_ulCqi.m_type != UlCqi_s::PUSCH)
2305 {
2306 return;
2307 }
2308 }
2309 break;
2310 default:
2311 NS_FATAL_ERROR("Unknown UL CQI type");
2312 }
2313
2314 switch (params.m_ulCqi.m_type)
2315 {
2316 case UlCqi_s::PUSCH: {
2317 NS_LOG_DEBUG(this << " Collect PUSCH CQIs of Frame no. " << (params.m_sfnSf >> 4)
2318 << " subframe no. " << (0xF & params.m_sfnSf));
2319 auto itMap = m_allocationMaps.find(params.m_sfnSf);
2320 if (itMap == m_allocationMaps.end())
2321 {
2322 return;
2323 }
2324 for (uint32_t i = 0; i < (*itMap).second.size(); i++)
2325 {
2326 // convert from fixed point notation Sxxxxxxxxxxx.xxx to double
2327 double sinr = LteFfConverter::fpS11dot3toDouble(params.m_ulCqi.m_sinr.at(i));
2328 auto itCqi = m_ueCqi.find((*itMap).second.at(i));
2329 if (itCqi == m_ueCqi.end())
2330 {
2331 // create a new entry
2332 std::vector<double> newCqi;
2333 for (uint32_t j = 0; j < m_cschedCellConfig.m_ulBandwidth; j++)
2334 {
2335 if (i == j)
2336 {
2337 newCqi.push_back(sinr);
2338 }
2339 else
2340 {
2341 // initialize with NO_SINR value.
2342 newCqi.push_back(NO_SINR);
2343 }
2344 }
2345 m_ueCqi[(*itMap).second.at(i)] = newCqi;
2346 // generate correspondent timer
2347 m_ueCqiTimers[(*itMap).second.at(i)] = m_cqiTimersThreshold;
2348 }
2349 else
2350 {
2351 // update the value
2352 (*itCqi).second.at(i) = sinr;
2353 NS_LOG_DEBUG(this << " RNTI " << (*itMap).second.at(i) << " RB " << i << " SINR "
2354 << sinr);
2355 // update correspondent timer
2356 auto itTimers = m_ueCqiTimers.find((*itMap).second.at(i));
2357 (*itTimers).second = m_cqiTimersThreshold;
2358 }
2359 }
2360 // remove obsolete info on allocation
2361 m_allocationMaps.erase(itMap);
2362 }
2363 break;
2364 case UlCqi_s::SRS: {
2365 NS_LOG_DEBUG(this << " Collect SRS CQIs of Frame no. " << (params.m_sfnSf >> 4)
2366 << " subframe no. " << (0xF & params.m_sfnSf));
2367 // get the RNTI from vendor specific parameters
2368 uint16_t rnti = 0;
2369 NS_ASSERT(!params.m_vendorSpecificList.empty());
2370 for (std::size_t i = 0; i < params.m_vendorSpecificList.size(); i++)
2371 {
2372 if (params.m_vendorSpecificList.at(i).m_type == SRS_CQI_RNTI_VSP)
2373 {
2374 Ptr<SrsCqiRntiVsp> vsp =
2375 DynamicCast<SrsCqiRntiVsp>(params.m_vendorSpecificList.at(i).m_value);
2376 rnti = vsp->GetRnti();
2377 }
2378 }
2379 auto itCqi = m_ueCqi.find(rnti);
2380 if (itCqi == m_ueCqi.end())
2381 {
2382 // create a new entry
2383 std::vector<double> newCqi;
2384 for (uint32_t j = 0; j < m_cschedCellConfig.m_ulBandwidth; j++)
2385 {
2386 double sinr = LteFfConverter::fpS11dot3toDouble(params.m_ulCqi.m_sinr.at(j));
2387 newCqi.push_back(sinr);
2388 NS_LOG_INFO(this << " RNTI " << rnti << " new SRS-CQI for RB " << j << " value "
2389 << sinr);
2390 }
2391 m_ueCqi.insert(std::pair<uint16_t, std::vector<double>>(rnti, newCqi));
2392 // generate correspondent timer
2393 m_ueCqiTimers.insert(std::pair<uint16_t, uint32_t>(rnti, m_cqiTimersThreshold));
2394 }
2395 else
2396 {
2397 // update the values
2398 for (uint32_t j = 0; j < m_cschedCellConfig.m_ulBandwidth; j++)
2399 {
2400 double sinr = LteFfConverter::fpS11dot3toDouble(params.m_ulCqi.m_sinr.at(j));
2401 (*itCqi).second.at(j) = sinr;
2402 NS_LOG_INFO(this << " RNTI " << rnti << " update SRS-CQI for RB " << j << " value "
2403 << sinr);
2404 }
2405 // update correspondent timer
2406 auto itTimers = m_ueCqiTimers.find(rnti);
2407 (*itTimers).second = m_cqiTimersThreshold;
2408 }
2409 }
2410 break;
2411 case UlCqi_s::PUCCH_1:
2412 case UlCqi_s::PUCCH_2:
2413 case UlCqi_s::PRACH: {
2414 NS_FATAL_ERROR("PfFfMacScheduler supports only PUSCH and SRS UL-CQIs");
2415 }
2416 break;
2417 default:
2418 NS_FATAL_ERROR("Unknown type of UL-CQI");
2419 }
2420}
2421
2422void
2424{
2425 // refresh DL CQI P01 Map
2426 auto itP10 = m_p10CqiTimers.begin();
2427 while (itP10 != m_p10CqiTimers.end())
2428 {
2429 NS_LOG_INFO(this << " P10-CQI for user " << (*itP10).first << " is "
2430 << (uint32_t)(*itP10).second << " thr " << (uint32_t)m_cqiTimersThreshold);
2431 if ((*itP10).second == 0)
2432 {
2433 // delete correspondent entries
2434 auto itMap = m_p10CqiRxed.find((*itP10).first);
2435 NS_ASSERT_MSG(itMap != m_p10CqiRxed.end(),
2436 " Does not find CQI report for user " << (*itP10).first);
2437 NS_LOG_INFO(this << " P10-CQI expired for user " << (*itP10).first);
2438 m_p10CqiRxed.erase(itMap);
2439 auto temp = itP10;
2440 itP10++;
2441 m_p10CqiTimers.erase(temp);
2442 }
2443 else
2444 {
2445 (*itP10).second--;
2446 itP10++;
2447 }
2448 }
2449
2450 // refresh DL CQI A30 Map
2451 auto itA30 = m_a30CqiTimers.begin();
2452 while (itA30 != m_a30CqiTimers.end())
2453 {
2454 NS_LOG_INFO(this << " A30-CQI for user " << (*itA30).first << " is "
2455 << (uint32_t)(*itA30).second << " thr " << (uint32_t)m_cqiTimersThreshold);
2456 if ((*itA30).second == 0)
2457 {
2458 // delete correspondent entries
2459 auto itMap = m_a30CqiRxed.find((*itA30).first);
2460 NS_ASSERT_MSG(itMap != m_a30CqiRxed.end(),
2461 " Does not find CQI report for user " << (*itA30).first);
2462 NS_LOG_INFO(this << " A30-CQI expired for user " << (*itA30).first);
2463 m_a30CqiRxed.erase(itMap);
2464 auto temp = itA30;
2465 itA30++;
2466 m_a30CqiTimers.erase(temp);
2467 }
2468 else
2469 {
2470 (*itA30).second--;
2471 itA30++;
2472 }
2473 }
2474}
2475
2476void
2478{
2479 // refresh UL CQI Map
2480 auto itUl = m_ueCqiTimers.begin();
2481 while (itUl != m_ueCqiTimers.end())
2482 {
2483 NS_LOG_INFO(this << " UL-CQI for user " << (*itUl).first << " is "
2484 << (uint32_t)(*itUl).second << " thr " << (uint32_t)m_cqiTimersThreshold);
2485 if ((*itUl).second == 0)
2486 {
2487 // delete correspondent entries
2488 auto itMap = m_ueCqi.find((*itUl).first);
2489 NS_ASSERT_MSG(itMap != m_ueCqi.end(),
2490 " Does not find CQI report for user " << (*itUl).first);
2491 NS_LOG_INFO(this << " UL-CQI exired for user " << (*itUl).first);
2492 (*itMap).second.clear();
2493 m_ueCqi.erase(itMap);
2494 auto temp = itUl;
2495 itUl++;
2496 m_ueCqiTimers.erase(temp);
2497 }
2498 else
2499 {
2500 (*itUl).second--;
2501 itUl++;
2502 }
2503 }
2504}
2505
2506void
2507CqaFfMacScheduler::UpdateDlRlcBufferInfo(uint16_t rnti, uint8_t lcid, uint16_t size)
2508{
2509 LteFlowId_t flow(rnti, lcid);
2510 auto it = m_rlcBufferReq.find(flow);
2511 if (it != m_rlcBufferReq.end())
2512 {
2513 NS_LOG_INFO(this << " UE " << rnti << " LC " << (uint16_t)lcid << " txqueue "
2514 << (*it).second.m_rlcTransmissionQueueSize << " retxqueue "
2515 << (*it).second.m_rlcRetransmissionQueueSize << " status "
2516 << (*it).second.m_rlcStatusPduSize << " decrease " << size);
2517 // Update queues: RLC tx order Status, ReTx, Tx
2518 // Update status queue
2519 if (((*it).second.m_rlcStatusPduSize > 0) && (size >= (*it).second.m_rlcStatusPduSize))
2520 {
2521 (*it).second.m_rlcStatusPduSize = 0;
2522 }
2523 else if (((*it).second.m_rlcRetransmissionQueueSize > 0) &&
2524 (size >= (*it).second.m_rlcRetransmissionQueueSize))
2525 {
2526 (*it).second.m_rlcRetransmissionQueueSize = 0;
2527 }
2528 else if ((*it).second.m_rlcTransmissionQueueSize > 0)
2529 {
2530 uint32_t rlcOverhead;
2531 if (lcid == 1)
2532 {
2533 // for SRB1 (using RLC AM) it's better to
2534 // overestimate RLC overhead rather than
2535 // underestimate it and risk unneeded
2536 // segmentation which increases delay
2537 rlcOverhead = 4;
2538 }
2539 else
2540 {
2541 // minimum RLC overhead due to header
2542 rlcOverhead = 2;
2543 }
2544 // update transmission queue
2545 if ((*it).second.m_rlcTransmissionQueueSize <= size - rlcOverhead)
2546 {
2547 (*it).second.m_rlcTransmissionQueueSize = 0;
2548 }
2549 else
2550 {
2551 (*it).second.m_rlcTransmissionQueueSize -= size - rlcOverhead;
2552 }
2553 }
2554 }
2555 else
2556 {
2557 NS_LOG_ERROR(this << " Does not find DL RLC Buffer Report of UE " << rnti);
2558 }
2559}
2560
2561void
2562CqaFfMacScheduler::UpdateUlRlcBufferInfo(uint16_t rnti, uint16_t size)
2563{
2564 size = size - 2; // remove the minimum RLC overhead
2565 auto it = m_ceBsrRxed.find(rnti);
2566 if (it != m_ceBsrRxed.end())
2567 {
2568 NS_LOG_INFO(this << " UE " << rnti << " size " << size << " BSR " << (*it).second);
2569 if ((*it).second >= size)
2570 {
2571 (*it).second -= size;
2572 }
2573 else
2574 {
2575 (*it).second = 0;
2576 }
2577 }
2578 else
2579 {
2580 NS_LOG_ERROR(this << " Does not find BSR report info of UE " << rnti);
2581 }
2582}
2583
2584void
2586{
2587 NS_LOG_FUNCTION(this << " RNTI " << rnti << " txMode " << (uint16_t)txMode);
2589 params.m_rnti = rnti;
2590 params.m_transmissionMode = txMode;
2592}
2593
2594} // 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:48
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.