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 (see table 7.1.6.1-1 of 36.213)
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};
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
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
224{
225 NS_LOG_FUNCTION(this);
226 // Read the subset of parameters used
227 m_cschedCellConfig = params;
228 m_rachAllocationMap.resize(m_cschedCellConfig.m_ulBandwidth, 0);
230 cnf.m_result = SUCCESS;
231 m_cschedSapUser->CschedUeConfigCnf(cnf);
232}
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
304 {
305 // Add new UE
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
630 int rbgSize = GetRbgSize(m_cschedCellConfig.m_dlBandwidth);
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
646 rbgMap = m_ffrSapProvider->GetAvailableDlRbg();
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);
668 ulRbMap = m_ffrSapProvider->GetAvailableUlRbg();
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
703 m_rachAllocationMap.resize(m_cschedCellConfig.m_ulBandwidth, 0);
704 uint16_t rbStart = 0;
705 rbStart = ffrRbStartOffset;
706 for (auto itRach = m_rachList.begin(); itRach != m_rachList.end(); itRach++)
707 {
708 NS_ASSERT_MSG(m_amc->GetUlTbSizeFromMcs(m_ulGrantMcs, m_cschedCellConfig.m_ulBandwidth) >
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 retx.reserve(2);
827 NS_LOG_INFO(this << " Processing DLHARQ feedback");
828 if (nLayers == 1)
829 {
830 retx.push_back(m_dlInfoListBuffered.at(i).m_harqStatus.at(0) ==
832 retx.push_back(false);
833 }
834 else
835 {
836 retx.push_back(m_dlInfoListBuffered.at(i).m_harqStatus.at(0) ==
838 retx.push_back(m_dlInfoListBuffered.at(i).m_harqStatus.at(1) ==
840 }
841 if (retx.at(0) || retx.at(1))
842 {
843 // retrieve HARQ process information
844 uint16_t rnti = m_dlInfoListBuffered.at(i).m_rnti;
845 uint8_t harqId = m_dlInfoListBuffered.at(i).m_harqProcessId;
846 NS_LOG_INFO(this << " HARQ retx RNTI " << rnti << " harqId " << (uint16_t)harqId);
847 auto itHarq = m_dlHarqProcessesDciBuffer.find(rnti);
848 if (itHarq == m_dlHarqProcessesDciBuffer.end())
849 {
850 NS_FATAL_ERROR("No info find in HARQ buffer for UE " << rnti);
851 }
852
853 DlDciListElement_s dci = (*itHarq).second.at(harqId);
854 int rv = 0;
855 if (dci.m_rv.size() == 1)
856 {
857 rv = dci.m_rv.at(0);
858 }
859 else
860 {
861 rv = (dci.m_rv.at(0) > dci.m_rv.at(1) ? dci.m_rv.at(0) : dci.m_rv.at(1));
862 }
863
864 if (rv == 3)
865 {
866 // maximum number of retx reached -> drop process
867 NS_LOG_INFO("Maximum number of retransmissions reached -> drop process");
868 auto it = m_dlHarqProcessesStatus.find(rnti);
869 if (it == m_dlHarqProcessesStatus.end())
870 {
871 NS_LOG_ERROR("No info find in HARQ buffer for UE (might change eNB) "
872 << m_dlInfoListBuffered.at(i).m_rnti);
873 }
874 (*it).second.at(harqId) = 0;
875 auto itRlcPdu = m_dlHarqProcessesRlcPduListBuffer.find(rnti);
876 if (itRlcPdu == m_dlHarqProcessesRlcPduListBuffer.end())
877 {
878 NS_FATAL_ERROR("Unable to find RlcPdcList in HARQ buffer for RNTI "
879 << m_dlInfoListBuffered.at(i).m_rnti);
880 }
881 for (std::size_t k = 0; k < (*itRlcPdu).second.size(); k++)
882 {
883 (*itRlcPdu).second.at(k).at(harqId).clear();
884 }
885 continue;
886 }
887 // check the feasibility of retransmitting on the same RBGs
888 // translate the DCI to Spectrum framework
889 std::vector<int> dciRbg;
890 uint32_t mask = 0x1;
891 NS_LOG_INFO("Original RBGs " << dci.m_rbBitmap << " rnti " << dci.m_rnti);
892 for (int j = 0; j < 32; j++)
893 {
894 if (((dci.m_rbBitmap & mask) >> j) == 1)
895 {
896 dciRbg.push_back(j);
897 NS_LOG_INFO("\t" << j);
898 }
899 mask = (mask << 1);
900 }
901 bool free = true;
902 for (std::size_t j = 0; j < dciRbg.size(); j++)
903 {
904 if (rbgMap.at(dciRbg.at(j)))
905 {
906 free = false;
907 break;
908 }
909 }
910 if (free)
911 {
912 // use the same RBGs for the retx
913 // reserve RBGs
914 for (std::size_t j = 0; j < dciRbg.size(); j++)
915 {
916 rbgMap.at(dciRbg.at(j)) = true;
917 NS_LOG_INFO("RBG " << dciRbg.at(j) << " assigned");
918 rbgAllocatedNum++;
919 }
920
921 NS_LOG_INFO(this << " Send retx in the same RBGs");
922 }
923 else
924 {
925 // find RBGs for sending HARQ retx
926 uint8_t j = 0;
927 uint8_t rbgId = (dciRbg.at(dciRbg.size() - 1) + 1) % numberOfRBGs;
928 uint8_t startRbg = dciRbg.at(dciRbg.size() - 1);
929 std::vector<bool> rbgMapCopy = rbgMap;
930 while ((j < dciRbg.size()) && (startRbg != rbgId))
931 {
932 if (!rbgMapCopy.at(rbgId))
933 {
934 rbgMapCopy.at(rbgId) = true;
935 dciRbg.at(j) = rbgId;
936 j++;
937 }
938 rbgId = (rbgId + 1) % numberOfRBGs;
939 }
940 if (j == dciRbg.size())
941 {
942 // find new RBGs -> update DCI map
943 uint32_t rbgMask = 0;
944 for (std::size_t k = 0; k < dciRbg.size(); k++)
945 {
946 rbgMask = rbgMask + (0x1 << dciRbg.at(k));
947 rbgAllocatedNum++;
948 }
949 dci.m_rbBitmap = rbgMask;
950 rbgMap = rbgMapCopy;
951 NS_LOG_INFO(this << " Move retx in RBGs " << dciRbg.size());
952 }
953 else
954 {
955 // HARQ retx cannot be performed on this TTI -> store it
956 dlInfoListUntxed.push_back(m_dlInfoListBuffered.at(i));
957 NS_LOG_INFO(this << " No resource for this retx -> buffer it");
958 }
959 }
960 // retrieve RLC PDU list for retx TBsize and update DCI
962 auto itRlcPdu = m_dlHarqProcessesRlcPduListBuffer.find(rnti);
963 if (itRlcPdu == m_dlHarqProcessesRlcPduListBuffer.end())
964 {
965 NS_FATAL_ERROR("Unable to find RlcPdcList in HARQ buffer for RNTI " << rnti);
966 }
967 for (std::size_t j = 0; j < nLayers; j++)
968 {
969 if (retx.at(j))
970 {
971 if (j >= dci.m_ndi.size())
972 {
973 // for avoiding errors in MIMO transient phases
974 dci.m_ndi.push_back(0);
975 dci.m_rv.push_back(0);
976 dci.m_mcs.push_back(0);
977 dci.m_tbsSize.push_back(0);
978 NS_LOG_INFO(this << " layer " << (uint16_t)j
979 << " no txed (MIMO transition)");
980 }
981 else
982 {
983 dci.m_ndi.at(j) = 0;
984 dci.m_rv.at(j)++;
985 (*itHarq).second.at(harqId).m_rv.at(j)++;
986 NS_LOG_INFO(this << " layer " << (uint16_t)j << " RV "
987 << (uint16_t)dci.m_rv.at(j));
988 }
989 }
990 else
991 {
992 // empty TB of layer j
993 dci.m_ndi.at(j) = 0;
994 dci.m_rv.at(j) = 0;
995 dci.m_mcs.at(j) = 0;
996 dci.m_tbsSize.at(j) = 0;
997 NS_LOG_INFO(this << " layer " << (uint16_t)j << " no retx");
998 }
999 }
1000 for (std::size_t k = 0; k < (*itRlcPdu).second.at(0).at(dci.m_harqProcess).size(); k++)
1001 {
1002 std::vector<RlcPduListElement_s> rlcPduListPerLc;
1003 for (std::size_t j = 0; j < nLayers; j++)
1004 {
1005 if (retx.at(j))
1006 {
1007 if (j < dci.m_ndi.size())
1008 {
1009 NS_LOG_INFO(" layer " << (uint16_t)j << " tb size "
1010 << dci.m_tbsSize.at(j));
1011 rlcPduListPerLc.push_back(
1012 (*itRlcPdu).second.at(j).at(dci.m_harqProcess).at(k));
1013 }
1014 }
1015 else
1016 { // if no retx needed on layer j, push an RlcPduListElement_s object with
1017 // m_size=0 to keep the size of rlcPduListPerLc vector = 2 in case of MIMO
1018 NS_LOG_INFO(" layer " << (uint16_t)j << " tb size " << dci.m_tbsSize.at(j));
1019 RlcPduListElement_s emptyElement;
1020 emptyElement.m_logicalChannelIdentity = (*itRlcPdu)
1021 .second.at(j)
1022 .at(dci.m_harqProcess)
1023 .at(k)
1024 .m_logicalChannelIdentity;
1025 emptyElement.m_size = 0;
1026 rlcPduListPerLc.push_back(emptyElement);
1027 }
1028 }
1029
1030 if (!rlcPduListPerLc.empty())
1031 {
1032 newEl.m_rlcPduList.push_back(rlcPduListPerLc);
1033 }
1034 }
1035 newEl.m_rnti = rnti;
1036 newEl.m_dci = dci;
1037 (*itHarq).second.at(harqId).m_rv = dci.m_rv;
1038 // refresh timer
1039 auto itHarqTimer = m_dlHarqProcessesTimer.find(rnti);
1040 if (itHarqTimer == m_dlHarqProcessesTimer.end())
1041 {
1042 NS_FATAL_ERROR("Unable to find HARQ timer for RNTI " << (uint16_t)rnti);
1043 }
1044 (*itHarqTimer).second.at(harqId) = 0;
1045 ret.m_buildDataList.push_back(newEl);
1046 rntiAllocated.insert(rnti);
1047 }
1048 else
1049 {
1050 // update HARQ process status
1051 NS_LOG_INFO(this << " HARQ received ACK for UE " << m_dlInfoListBuffered.at(i).m_rnti);
1052 auto it = m_dlHarqProcessesStatus.find(m_dlInfoListBuffered.at(i).m_rnti);
1053 if (it == m_dlHarqProcessesStatus.end())
1054 {
1055 NS_FATAL_ERROR("No info find in HARQ buffer for UE "
1056 << m_dlInfoListBuffered.at(i).m_rnti);
1057 }
1058 (*it).second.at(m_dlInfoListBuffered.at(i).m_harqProcessId) = 0;
1059 auto itRlcPdu =
1061 if (itRlcPdu == m_dlHarqProcessesRlcPduListBuffer.end())
1062 {
1063 NS_FATAL_ERROR("Unable to find RlcPdcList in HARQ buffer for RNTI "
1064 << m_dlInfoListBuffered.at(i).m_rnti);
1065 }
1066 for (std::size_t k = 0; k < (*itRlcPdu).second.size(); k++)
1067 {
1068 (*itRlcPdu).second.at(k).at(m_dlInfoListBuffered.at(i).m_harqProcessId).clear();
1069 }
1070 }
1071 }
1072 m_dlInfoListBuffered.clear();
1073 m_dlInfoListBuffered = dlInfoListUntxed;
1074
1075 if (rbgAllocatedNum == numberOfRBGs)
1076 {
1077 // all the RBGs are already allocated -> exit
1078 if (!ret.m_buildDataList.empty() || !ret.m_buildRarList.empty())
1079 {
1080 m_schedSapUser->SchedDlConfigInd(ret);
1081 }
1082 return;
1083 }
1084
1085 for (auto itLogicalChannels = m_ueLogicalChannelsConfigList.begin();
1086 itLogicalChannels != m_ueLogicalChannelsConfigList.end();
1087 itLogicalChannels++)
1088 {
1089 auto itRnti = rntiAllocated.find(itLogicalChannels->first.m_rnti);
1090 if ((itRnti != rntiAllocated.end()) ||
1091 (!HarqProcessAvailability(itLogicalChannels->first.m_rnti)))
1092 {
1093 // UE already allocated for HARQ or without HARQ process available -> drop it
1094 if (itRnti != rntiAllocated.end())
1095 {
1096 NS_LOG_DEBUG(this << " RNTI discarded for HARQ tx"
1097 << (uint16_t)(itLogicalChannels->first.m_rnti));
1098 }
1099 if (!HarqProcessAvailability(itLogicalChannels->first.m_rnti))
1100 {
1101 NS_LOG_DEBUG(this << " RNTI discarded for HARQ id"
1102 << (uint16_t)(itLogicalChannels->first.m_rnti));
1103 }
1104 continue;
1105 }
1106
1107 auto itRlcBufferReq = m_rlcBufferReq.find(itLogicalChannels->first);
1108 if (itRlcBufferReq == m_rlcBufferReq.end())
1109 {
1110 continue;
1111 }
1112
1113 int group = -1;
1114 int delay = 0;
1115
1116 if (itRlcBufferReq->second.m_rlcRetransmissionQueueSize > 0)
1117 {
1118 delay = itRlcBufferReq->second.m_rlcRetransmissionHolDelay;
1119 group = delay / grouping_parameter;
1120 }
1121 else if (itRlcBufferReq->second.m_rlcTransmissionQueueSize > 0)
1122 {
1123 delay = itRlcBufferReq->second.m_rlcTransmissionQueueHolDelay;
1124 group = delay / grouping_parameter;
1125 }
1126 else
1127 {
1128 continue;
1129 }
1130
1131 UEtoHOL.insert(std::pair<LteFlowId_t, int>(itLogicalChannels->first, delay));
1132
1133 if (itLogicalChannels->second.m_qosBearerType ==
1135 {
1136 if (map_nonGBRHOLgroupToUE.count(group) == 0)
1137 {
1138 std::set<LteFlowId_t> v;
1139 v.insert(itRlcBufferReq->first);
1140 map_nonGBRHOLgroupToUE.insert(std::pair<int, std::set<LteFlowId_t>>(group, v));
1141 }
1142 else
1143 {
1144 map_nonGBRHOLgroupToUE.find(group)->second.insert(itRlcBufferReq->first);
1145 }
1146 }
1147 else if (itLogicalChannels->second.m_qosBearerType ==
1149 itLogicalChannels->second.m_qosBearerType ==
1151 {
1152 if (map_GBRHOLgroupToUE.count(group) == 0)
1153 {
1154 std::set<LteFlowId_t> v;
1155 v.insert(itRlcBufferReq->first);
1156 map_GBRHOLgroupToUE.insert(std::pair<int, std::set<LteFlowId_t>>(group, v));
1157 }
1158 else
1159 {
1160 map_GBRHOLgroupToUE.find(group)->second.insert(itRlcBufferReq->first);
1161 }
1162 }
1163 };
1164
1165 // Prepare data for the scheduling mechanism
1166 // map: UE, to the amount of traffic they have to transfer
1167 std::map<LteFlowId_t, int> UeToAmountOfDataToTransfer;
1168 // Initialize the map per UE, how much resources is already assigned to the user
1169 std::map<LteFlowId_t, int> UeToAmountOfAssignedResources;
1170 // prepare values to calculate FF metric, this metric will be the same for all flows(logical
1171 // channels) that belong to the same RNTI
1172 std::map<uint16_t, uint8_t> sbCqiSum;
1173
1174 for (auto itrbr = m_rlcBufferReq.begin(); itrbr != m_rlcBufferReq.end(); itrbr++)
1175 {
1176 LteFlowId_t flowId = itrbr->first; // Prepare data for the scheduling mechanism
1177 // check first the channel conditions for this UE, if CQI!=0
1178 auto itCqi = m_a30CqiRxed.find((*itrbr).first.m_rnti);
1179 auto itTxMode = m_uesTxMode.find((*itrbr).first.m_rnti);
1180 if (itTxMode == m_uesTxMode.end())
1181 {
1182 NS_FATAL_ERROR("No Transmission Mode info on user " << (*itrbr).first.m_rnti);
1183 }
1184 auto nLayer = TransmissionModesLayers::TxMode2LayerNum((*itTxMode).second);
1185
1186 uint8_t cqiSum = 0;
1187 for (int k = 0; k < numberOfRBGs; k++)
1188 {
1189 for (uint8_t j = 0; j < nLayer; j++)
1190 {
1191 if (itCqi == m_a30CqiRxed.end())
1192 {
1193 cqiSum += 1; // no info on this user -> lowest MCS
1194 }
1195 else
1196 {
1197 cqiSum += (*itCqi).second.m_higherLayerSelected.at(k).m_sbCqi.at(j);
1198 }
1199 }
1200 }
1201
1202 if (cqiSum == 0)
1203 {
1204 NS_LOG_INFO("Skip this flow, CQI==0, rnti:" << (*itrbr).first.m_rnti);
1205 continue;
1206 }
1207
1208 // map: UE, to the amount of traffic they have to transfer
1209 int amountOfDataToTransfer =
1210 8 * ((int)m_rlcBufferReq.find(flowId)->second.m_rlcRetransmissionQueueSize +
1211 (int)m_rlcBufferReq.find(flowId)->second.m_rlcTransmissionQueueSize);
1212
1213 UeToAmountOfDataToTransfer.insert(
1214 std::pair<LteFlowId_t, int>(flowId, amountOfDataToTransfer));
1215 UeToAmountOfAssignedResources.insert(std::pair<LteFlowId_t, int>(flowId, 0));
1216
1217 uint8_t sum = 0;
1218 for (int i = 0; i < numberOfRBGs; i++)
1219 {
1220 auto itCqi = m_a30CqiRxed.find((*itrbr).first.m_rnti);
1221 auto itTxMode = m_uesTxMode.find((*itrbr).first.m_rnti);
1222 if (itTxMode == m_uesTxMode.end())
1223 {
1224 NS_FATAL_ERROR("No Transmission Mode info on user " << (*itrbr).first.m_rnti);
1225 }
1226 auto nLayer = TransmissionModesLayers::TxMode2LayerNum((*itTxMode).second);
1227 std::vector<uint8_t> sbCqis;
1228 if (itCqi == m_a30CqiRxed.end())
1229 {
1230 sbCqis = std::vector<uint8_t>(nLayer, 1); // start with lowest value
1231 }
1232 else
1233 {
1234 sbCqis = (*itCqi).second.m_higherLayerSelected.at(i).m_sbCqi;
1235 }
1236
1237 uint8_t cqi1 = sbCqis.at(0);
1238 uint8_t cqi2 = 0;
1239 if (sbCqis.size() > 1)
1240 {
1241 cqi2 = sbCqis.at(1);
1242 }
1243
1244 uint8_t sbCqi = 0;
1245 if ((cqi1 > 0) ||
1246 (cqi2 > 0)) // CQI == 0 means "out of range" (see table 7.2.3-1 of 36.213)
1247 {
1248 for (uint8_t k = 0; k < nLayer; k++)
1249 {
1250 if (sbCqis.size() > k)
1251 {
1252 sbCqi = sbCqis.at(k);
1253 }
1254 else
1255 {
1256 // no info on this subband
1257 sbCqi = 0;
1258 }
1259 sum += sbCqi;
1260 }
1261 }
1262 }
1263
1264 sbCqiSum.insert(std::pair<uint16_t, uint8_t>((*itrbr).first.m_rnti, sum));
1265 }
1266
1267 // availableRBGs - set that contains indexes of available resource block groups
1268 std::set<int> availableRBGs;
1269 for (int i = 0; i < numberOfRBGs; i++)
1270 {
1271 if (!rbgMap.at(i))
1272 {
1273 availableRBGs.insert(i);
1274 }
1275 }
1276
1277 auto itGBRgroups = map_GBRHOLgroupToUE.begin();
1278 auto itnonGBRgroups = map_nonGBRHOLgroupToUE.begin();
1279
1280 // while there are more resources available, loop through the users that are grouped by HOL
1281 // value
1282 while (!availableRBGs.empty())
1283 {
1284 if (UeToAmountOfDataToTransfer.empty())
1285 {
1286 NS_LOG_INFO("No UEs to be scheduled (no data or CQI==0),");
1287 break;
1288 }
1289 std::set<LteFlowId_t> vUEs;
1290 t_it_HOLgroupToUEs itCurrentGroup;
1291
1292 if (itGBRgroups != map_GBRHOLgroupToUE.end())
1293 {
1294 itCurrentGroup = itGBRgroups;
1295 itGBRgroups++;
1296 }
1297 else if (itnonGBRgroups !=
1298 map_nonGBRHOLgroupToUE
1299 .end()) // if there are no more flows with retransmission queue start to
1300 // scheduler flows with transmission queue
1301 {
1302 itCurrentGroup = itnonGBRgroups;
1303 itnonGBRgroups++;
1304 }
1305 else
1306 {
1307 NS_LOG_INFO("Available RBGs:" << availableRBGs.size() << "but no users");
1308 break;
1309 }
1310
1311 // While there are more users in current group
1312 while (!availableRBGs.empty() && !itCurrentGroup->second.empty())
1313 {
1314 bool currentRBchecked = false;
1315 int currentRB = *(availableRBGs.begin());
1316 std::map<LteFlowId_t, CQI_value> UeToCQIValue;
1317 std::map<LteFlowId_t, double> UeToCoitaMetric;
1318 std::map<LteFlowId_t, bool> UeHasReachedGBR;
1319 double maximumValueMetric = 0;
1320 LteFlowId_t userWithMaximumMetric;
1321 UeToCQIValue.clear();
1322 UeToCoitaMetric.clear();
1323
1324 // Iterate through the users and calculate which user will use the best of the current
1325 // resource block.end() and assign to that user.
1326 for (auto it = itCurrentGroup->second.begin(); it != itCurrentGroup->second.end(); it++)
1327 {
1328 LteFlowId_t flowId = *it;
1329 uint8_t cqi_value = 1; // higher better, maximum is 15
1330 double coita_metric = 1;
1331 double coita_sum = 0;
1332 double metric = 0;
1333 uint8_t worstCQIAmongRBGsAllocatedForThisUser = 15;
1334 int numberOfRBGAllocatedForThisUser = 0;
1336 m_ueLogicalChannelsConfigList.find(flowId)->second;
1337 auto itRntiCQIsMap = m_a30CqiRxed.find(flowId.m_rnti);
1338
1339 if (!m_ffrSapProvider->IsDlRbgAvailableForUe(currentRB, flowId.m_rnti))
1340 {
1341 continue;
1342 }
1343
1344 if (m_flowStatsDl.find(flowId.m_rnti) == m_flowStatsDl.end())
1345 {
1346 continue; // TO DO: check if this should be logged and how.
1347 }
1348 currentRBchecked = true;
1349
1350 auto itStats = m_flowStatsDl.find(flowId.m_rnti);
1351 double tbr_weight =
1352 (*itStats).second.targetThroughput / (*itStats).second.lastAveragedThroughput;
1353 if (tbr_weight < 1.0)
1354 {
1355 tbr_weight = 1.0;
1356 }
1357
1358 if (itRntiCQIsMap != m_a30CqiRxed.end())
1359 {
1360 for (auto it = availableRBGs.begin(); it != availableRBGs.end(); it++)
1361 {
1362 try
1363 {
1364 int val =
1365 (itRntiCQIsMap->second.m_higherLayerSelected.at(*it).m_sbCqi.at(0));
1366 if (val == 0)
1367 {
1368 val = 1; // if no info, use minimum
1369 }
1370 if (*it == currentRB)
1371 {
1372 cqi_value = val;
1373 }
1374 coita_sum += val;
1375 }
1376 catch (std::out_of_range&)
1377 {
1378 coita_sum += 1; // if no info on channel use the worst cqi
1379 NS_LOG_INFO("No CQI for lcId:" << flowId.m_lcId
1380 << " rnti:" << flowId.m_rnti
1381 << " at subband:" << currentRB);
1382 // std::cout<<"\n No CQI for
1383 // lcId:.....................................";
1384 }
1385 }
1386 coita_metric = cqi_value / coita_sum;
1387 UeToCQIValue.insert(std::pair<LteFlowId_t, CQI_value>(flowId, cqi_value));
1388 UeToCoitaMetric.insert(std::pair<LteFlowId_t, double>(flowId, coita_metric));
1389 }
1390
1391 if (allocationMapPerRntiPerLCId.find(flowId.m_rnti) ==
1392 allocationMapPerRntiPerLCId.end())
1393 {
1394 worstCQIAmongRBGsAllocatedForThisUser = cqi_value;
1395 }
1396 else
1397 {
1398 numberOfRBGAllocatedForThisUser =
1399 (allocationMapPerRntiPerLCId.find(flowId.m_rnti)->second.size());
1400
1401 for (auto itRBG =
1402 allocationMapPerRntiPerLCId.find(flowId.m_rnti)->second.begin();
1403 itRBG != allocationMapPerRntiPerLCId.find(flowId.m_rnti)->second.end();
1404 itRBG++)
1405 {
1406 qos_rb_and_CQI_assigned_to_lc e = itRBG->second;
1407 if (e.cqi_value_for_lc < worstCQIAmongRBGsAllocatedForThisUser)
1408 {
1409 worstCQIAmongRBGsAllocatedForThisUser = e.cqi_value_for_lc;
1410 }
1411 }
1412
1413 if (cqi_value < worstCQIAmongRBGsAllocatedForThisUser)
1414 {
1415 worstCQIAmongRBGsAllocatedForThisUser = cqi_value;
1416 }
1417 }
1418
1419 int mcsForThisUser = m_amc->GetMcsFromCqi(worstCQIAmongRBGsAllocatedForThisUser);
1420 int tbSize =
1421 m_amc->GetDlTbSizeFromMcs(mcsForThisUser,
1422 (numberOfRBGAllocatedForThisUser + 1) * rbgSize) /
1423 8; // similar to calculation of TB size (size of TB in bytes according to
1424 // table 7.1.7.2.1-1 of 36.213)
1425
1426 double achievableRate =
1427 ((m_amc->GetDlTbSizeFromMcs(mcsForThisUser, rbgSize) / 8) / 0.001);
1428 double pf_weight = achievableRate / (*itStats).second.secondLastAveragedThroughput;
1429
1430 UeToAmountOfAssignedResources.find(flowId)->second = 8 * tbSize;
1432 m_rlcBufferReq.find(flowId)->second;
1433
1434 if (UeToAmountOfDataToTransfer.find(flowId)->second -
1435 UeToAmountOfAssignedResources.find(flowId)->second <
1436 0)
1437 {
1438 UeHasReachedGBR.insert(std::pair<LteFlowId_t, bool>(flowId, false));
1439 }
1440
1441 double bitRateWithNewRBG = 0;
1442
1443 if (m_flowStatsDl.find(flowId.m_rnti) !=
1444 m_flowStatsDl.end()) // there are some statistics{
1445 {
1446 bitRateWithNewRBG =
1447 (1.0 - (1.0 / m_timeWindow)) *
1448 (m_flowStatsDl.find(flowId.m_rnti)->second.lastAveragedThroughput) +
1449 ((1.0 / m_timeWindow) * (double)(tbSize * 1000));
1450 }
1451 else
1452 {
1453 bitRateWithNewRBG = (1.0 / m_timeWindow) * (double)(tbSize * 1000);
1454 }
1455
1456 if (bitRateWithNewRBG > lc.m_eRabGuaranteedBitrateDl)
1457 {
1458 UeHasReachedGBR.insert(std::pair<LteFlowId_t, bool>(flowId, true));
1459 }
1460 else
1461 {
1462 UeHasReachedGBR.insert(std::pair<LteFlowId_t, bool>(flowId, false));
1463 }
1464
1465 int hol = UEtoHOL.find(flowId)->second;
1466
1467 if (hol == 0)
1468 {
1469 hol = 1;
1470 }
1471
1472 if (m_CqaMetric == "CqaFf")
1473 {
1474 metric = coita_metric * tbr_weight * hol;
1475 }
1476 else if (m_CqaMetric == "CqaPf")
1477 {
1478 metric = tbr_weight * pf_weight * hol;
1479 }
1480 else
1481 {
1482 metric = 1;
1483 }
1484
1485 if (metric >= maximumValueMetric)
1486 {
1487 maximumValueMetric = metric;
1488 userWithMaximumMetric = flowId;
1489 }
1490 }
1491
1492 if (!currentRBchecked)
1493 {
1494 // erase current RBG from the list of available RBG
1495 availableRBGs.erase(currentRB);
1496 continue;
1497 }
1498
1500 const auto ueToCqiIt = UeToCQIValue.find(userWithMaximumMetric);
1501 s.cqi_value_for_lc = ueToCqiIt != UeToCQIValue.end() ? ueToCqiIt->second : 1;
1502 s.resource_block_index = currentRB;
1503
1504 auto itMap = allocationMapPerRntiPerLCId.find(userWithMaximumMetric.m_rnti);
1505
1506 if (itMap == allocationMapPerRntiPerLCId.end())
1507 {
1508 std::multimap<uint8_t, qos_rb_and_CQI_assigned_to_lc> tempMap;
1509 tempMap.insert(
1510 std::pair<uint8_t, qos_rb_and_CQI_assigned_to_lc>(userWithMaximumMetric.m_lcId,
1511 s));
1512 allocationMapPerRntiPerLCId.insert(
1513 std::pair<uint16_t, std::multimap<uint8_t, qos_rb_and_CQI_assigned_to_lc>>(
1514 userWithMaximumMetric.m_rnti,
1515 tempMap));
1516 }
1517 else
1518 {
1519 itMap->second.insert(
1520 std::pair<uint8_t, qos_rb_and_CQI_assigned_to_lc>(userWithMaximumMetric.m_lcId,
1521 s));
1522 }
1523
1524 // erase current RBG from the list of available RBG
1525 availableRBGs.erase(currentRB);
1526
1527 if (UeToAmountOfDataToTransfer.find(userWithMaximumMetric)->second <=
1528 UeToAmountOfAssignedResources.find(userWithMaximumMetric)->second * tolerance)
1529 //||(UeHasReachedGBR.find(userWithMaximumMetric)->second == true))
1530 {
1531 itCurrentGroup->second.erase(userWithMaximumMetric);
1532 }
1533 }
1534 }
1535
1536 // reset TTI stats of users
1537 for (auto itStats = m_flowStatsDl.begin(); itStats != m_flowStatsDl.end(); itStats++)
1538 {
1539 (*itStats).second.lastTtiBytesTransmitted = 0;
1540 }
1541
1542 // 3) Creating the correspondent DCIs (Generate the transmission opportunities by grouping the
1543 // RBGs of the same RNTI)
1544 // FfMacSchedSapUser::SchedDlConfigIndParameters ret;
1545 auto itMap = allocationMapPerRntiPerLCId.begin();
1546 std::map<uint16_t, double> m_rnti_per_ratio;
1547
1548 while (itMap != allocationMapPerRntiPerLCId.end())
1549 {
1550 // create new BuildDataListElement_s for this LC
1552 newEl.m_rnti = (*itMap).first;
1553 NS_LOG_INFO("Scheduled RNTI:" << newEl.m_rnti);
1554 // create the DlDciListElement_s
1555 DlDciListElement_s newDci;
1556 std::vector<RlcPduListElement_s> newRlcPduLe;
1557 newDci.m_rnti = (*itMap).first;
1558 newDci.m_harqProcess = UpdateHarqProcessId((*itMap).first);
1559 uint16_t lcActives = LcActivePerFlow(itMap->first);
1560 if (lcActives == 0)
1561 { // if there is still no buffer report information on any flow
1562 lcActives = 1;
1563 }
1564 // NS_LOG_DEBUG (this << "Allocate user " << newEl.m_rnti << " rbg " << lcActives);
1565 uint16_t RbgPerRnti = (*itMap).second.size();
1566 double doubleRBgPerRnti = RbgPerRnti;
1567 double doubleRbgNum = numberOfRBGs;
1568 double rrRatio = doubleRBgPerRnti / doubleRbgNum;
1569 m_rnti_per_ratio.insert(std::pair<uint16_t, double>((*itMap).first, rrRatio));
1570 uint8_t worstCqi = 15;
1571
1572 // assign the worst value of CQI that user experienced on any of its subbands
1573 for (auto it = (*itMap).second.begin(); it != (*itMap).second.end(); it++)
1574 {
1575 if (it->second.cqi_value_for_lc < worstCqi)
1576 {
1577 worstCqi = it->second.cqi_value_for_lc;
1578 }
1579 }
1580
1581 newDci.m_mcs.push_back(m_amc->GetMcsFromCqi(worstCqi));
1582 int tbSize = (m_amc->GetDlTbSizeFromMcs(newDci.m_mcs.at(0), RbgPerRnti * rbgSize) /
1583 8); // (size of TB in bytes according to table 7.1.7.2.1-1 of 36.213)
1584 newDci.m_tbsSize.push_back(tbSize);
1585 newDci.m_resAlloc = 0; // only allocation type 0 at this stage
1586 newDci.m_rbBitmap = 0; // TBD (32 bit bitmap see 7.1.6 of 36.213)
1587 uint32_t rbgMask = 0;
1588 for (auto itRBGsPerRNTI = (*itMap).second.begin(); itRBGsPerRNTI != (*itMap).second.end();
1589 itRBGsPerRNTI++)
1590 {
1591 rbgMask = rbgMask + (0x1 << itRBGsPerRNTI->second.resource_block_index);
1592 }
1593 newDci.m_rbBitmap = rbgMask; // (32 bit bitmap see 7.1.6 of 36.213)
1594 // NOTE: In this first version of CqaFfMacScheduler, it is assumed one flow per user.
1595 // create the rlc PDUs -> equally divide resources among active LCs
1596 for (auto itBufReq = m_rlcBufferReq.begin(); itBufReq != m_rlcBufferReq.end(); itBufReq++)
1597 {
1598 if (((*itBufReq).first.m_rnti == (*itMap).first) &&
1599 (((*itBufReq).second.m_rlcTransmissionQueueSize > 0) ||
1600 ((*itBufReq).second.m_rlcRetransmissionQueueSize > 0) ||
1601 ((*itBufReq).second.m_rlcStatusPduSize > 0)))
1602 {
1603 std::vector<RlcPduListElement_s> newRlcPduLe;
1604 // for (uint8_t j = 0; j < nLayer; j++)
1605 //{
1606 RlcPduListElement_s newRlcEl;
1607 newRlcEl.m_logicalChannelIdentity = (*itBufReq).first.m_lcId;
1608 // newRlcEl.m_size = newDci.m_tbsSize.at (j) / lcActives;
1609 newRlcEl.m_size = tbSize / lcActives;
1610 // NS_LOG_INFO (this << " LCID " << (uint32_t) newRlcEl.m_logicalChannelIdentity <<
1611 // " size " << newRlcEl.m_size << " layer " << (uint16_t)j);
1612 newRlcPduLe.push_back(newRlcEl);
1614 newRlcEl.m_logicalChannelIdentity,
1615 newRlcEl.m_size);
1616 if (m_harqOn)
1617 {
1618 // store RLC PDU list for HARQ
1619 auto itRlcPdu = m_dlHarqProcessesRlcPduListBuffer.find((*itMap).first);
1620 if (itRlcPdu == m_dlHarqProcessesRlcPduListBuffer.end())
1621 {
1622 NS_FATAL_ERROR("Unable to find RlcPdcList in HARQ buffer for RNTI "
1623 << (*itMap).first);
1624 }
1625 int j = 0;
1626 (*itRlcPdu).second.at(j).at(newDci.m_harqProcess).push_back(newRlcEl);
1627 }
1628 // }
1629 newEl.m_rlcPduList.push_back(newRlcPduLe);
1630 }
1631 if ((*itBufReq).first.m_rnti > (*itMap).first)
1632 {
1633 break;
1634 }
1635 }
1636 // for (uint8_t j = 0; j < nLayer; j++)
1637 // {
1638 newDci.m_ndi.push_back(1);
1639 newDci.m_rv.push_back(0);
1640 //}
1641
1642 newDci.m_tpc = m_ffrSapProvider->GetTpc((*itMap).first);
1643
1644 newEl.m_dci = newDci;
1645
1646 if (m_harqOn)
1647 {
1648 // store DCI for HARQ
1649 auto itDci = m_dlHarqProcessesDciBuffer.find(newEl.m_rnti);
1650 if (itDci == m_dlHarqProcessesDciBuffer.end())
1651 {
1652 NS_FATAL_ERROR("Unable to find RNTI entry in DCI HARQ buffer for RNTI "
1653 << newEl.m_rnti);
1654 }
1655 (*itDci).second.at(newDci.m_harqProcess) = newDci;
1656 // refresh timer
1657 auto itHarqTimer = m_dlHarqProcessesTimer.find(newEl.m_rnti);
1658 if (itHarqTimer == m_dlHarqProcessesTimer.end())
1659 {
1660 NS_FATAL_ERROR("Unable to find HARQ timer for RNTI " << (uint16_t)newEl.m_rnti);
1661 }
1662 (*itHarqTimer).second.at(newDci.m_harqProcess) = 0;
1663 }
1664
1665 // ...more parameters -> ignored in this version
1666
1667 ret.m_buildDataList.push_back(newEl);
1668 // update UE stats
1669 auto it = m_flowStatsDl.find((*itMap).first);
1670 if (it != m_flowStatsDl.end())
1671 {
1672 (*it).second.lastTtiBytesTransmitted = tbSize;
1673 }
1674 else
1675 {
1676 NS_FATAL_ERROR(this << " No Stats for this allocated UE");
1677 }
1678
1679 itMap++;
1680 }
1681 ret.m_nrOfPdcchOfdmSymbols = 1; // TODO: check correct value according the DCIs txed
1682
1683 // update UEs stats
1684 NS_LOG_INFO(this << " Update UEs statistics");
1685 for (auto itStats = m_flowStatsDl.begin(); itStats != m_flowStatsDl.end(); itStats++)
1686 {
1687 if (allocationMapPerRntiPerLCId.find(itStats->first) != allocationMapPerRntiPerLCId.end())
1688 {
1689 (*itStats).second.secondLastAveragedThroughput =
1690 ((1.0 - (1 / m_timeWindow)) * (*itStats).second.secondLastAveragedThroughput) +
1691 ((1 / m_timeWindow) * (double)((*itStats).second.lastTtiBytesTransmitted / 0.001));
1692 }
1693
1694 (*itStats).second.totalBytesTransmitted += (*itStats).second.lastTtiBytesTransmitted;
1695 // update average throughput (see eq. 12.3 of Sec 12.3.1.2 of LTE – The UMTS Long Term
1696 // Evolution, Ed Wiley)
1697 (*itStats).second.lastAveragedThroughput =
1698 ((1.0 - (1.0 / m_timeWindow)) * (*itStats).second.lastAveragedThroughput) +
1699 ((1.0 / m_timeWindow) * (double)((*itStats).second.lastTtiBytesTransmitted / 0.001));
1700 NS_LOG_INFO(this << " UE total bytes " << (*itStats).second.totalBytesTransmitted);
1701 NS_LOG_INFO(this << " UE average throughput " << (*itStats).second.lastAveragedThroughput);
1702 (*itStats).second.lastTtiBytesTransmitted = 0;
1703 }
1704
1705 m_schedSapUser->SchedDlConfigInd(ret);
1706
1707 int count_allocated_resource_blocks = 0;
1708 for (auto itMap = allocationMapPerRntiPerLCId.begin();
1709 itMap != allocationMapPerRntiPerLCId.end();
1710 itMap++)
1711 {
1712 count_allocated_resource_blocks += itMap->second.size();
1713 }
1714 NS_LOG_INFO(this << " Allocated RBs:" << count_allocated_resource_blocks);
1715}
1716
1717void
1720{
1721 NS_LOG_FUNCTION(this);
1722
1723 m_rachList = params.m_rachList;
1724}
1725
1726void
1729{
1730 NS_LOG_FUNCTION(this);
1731 m_ffrSapProvider->ReportDlCqiInfo(params);
1732
1733 for (unsigned int i = 0; i < params.m_cqiList.size(); i++)
1734 {
1735 if (params.m_cqiList.at(i).m_cqiType == CqiListElement_s::P10)
1736 {
1737 NS_LOG_LOGIC("wideband CQI " << (uint32_t)params.m_cqiList.at(i).m_wbCqi.at(0)
1738 << " reported");
1739 uint16_t rnti = params.m_cqiList.at(i).m_rnti;
1740 auto it = m_p10CqiRxed.find(rnti);
1741 if (it == m_p10CqiRxed.end())
1742 {
1743 // create the new entry
1744 m_p10CqiRxed[rnti] =
1745 params.m_cqiList.at(i).m_wbCqi.at(0); // only codeword 0 at this stage (SISO)
1746 // generate correspondent timer
1747 m_p10CqiTimers.insert(std::pair<uint16_t, uint32_t>(rnti, m_cqiTimersThreshold));
1748 }
1749 else
1750 {
1751 // update the CQI value and refresh correspondent timer
1752 (*it).second = params.m_cqiList.at(i).m_wbCqi.at(0);
1753 // update correspondent timer
1754 auto itTimers = m_p10CqiTimers.find(rnti);
1755 (*itTimers).second = m_cqiTimersThreshold;
1756 }
1757 }
1758 else if (params.m_cqiList.at(i).m_cqiType == CqiListElement_s::A30)
1759 {
1760 // subband CQI reporting high layer configured
1761 uint16_t rnti = params.m_cqiList.at(i).m_rnti;
1762 auto it = m_a30CqiRxed.find(rnti);
1763 if (it == m_a30CqiRxed.end())
1764 {
1765 // create the new entry
1766 m_a30CqiRxed[rnti] = params.m_cqiList.at(i).m_sbMeasResult;
1767 m_a30CqiTimers.insert(std::pair<uint16_t, uint32_t>(rnti, m_cqiTimersThreshold));
1768 }
1769 else
1770 {
1771 // update the CQI value and refresh correspondent timer
1772 (*it).second = params.m_cqiList.at(i).m_sbMeasResult;
1773 auto itTimers = m_a30CqiTimers.find(rnti);
1774 (*itTimers).second = m_cqiTimersThreshold;
1775 }
1776 }
1777 else
1778 {
1779 NS_LOG_ERROR(this << " CQI type unknown");
1780 }
1781 }
1782}
1783
1784double
1785CqaFfMacScheduler::EstimateUlSinr(uint16_t rnti, uint16_t rb)
1786{
1787 auto itCqi = m_ueCqi.find(rnti);
1788 if (itCqi == m_ueCqi.end())
1789 {
1790 // no cqi info about this UE
1791 return NO_SINR;
1792 }
1793 else
1794 {
1795 // take the average SINR value among the available
1796 double sinrSum = 0;
1797 unsigned int sinrNum = 0;
1798 for (uint32_t i = 0; i < m_cschedCellConfig.m_ulBandwidth; i++)
1799 {
1800 double sinr = (*itCqi).second.at(i);
1801 if (sinr != NO_SINR)
1802 {
1803 sinrSum += sinr;
1804 sinrNum++;
1805 }
1806 }
1807 double estimatedSinr = (sinrNum > 0) ? (sinrSum / sinrNum) : DBL_MAX;
1808 // store the value
1809 (*itCqi).second.at(rb) = estimatedSinr;
1810 return estimatedSinr;
1811 }
1812}
1813
1814void
1817{
1818 NS_LOG_FUNCTION(this << " UL - Frame no. " << (params.m_sfnSf >> 4) << " subframe no. "
1819 << (0xF & params.m_sfnSf) << " size " << params.m_ulInfoList.size());
1820
1822 m_ffrSapProvider->ReportUlCqiInfo(m_ueCqi);
1823
1824 // Generate RBs map
1826 std::vector<bool> rbMap;
1827 uint16_t rbAllocatedNum = 0;
1828 std::set<uint16_t> rntiAllocated;
1829 std::vector<uint16_t> rbgAllocationMap;
1830 // update with RACH allocation map
1831 rbgAllocationMap = m_rachAllocationMap;
1832 // rbgAllocationMap.resize (m_cschedCellConfig.m_ulBandwidth, 0);
1833 m_rachAllocationMap.clear();
1834 m_rachAllocationMap.resize(m_cschedCellConfig.m_ulBandwidth, 0);
1835
1836 rbMap.resize(m_cschedCellConfig.m_ulBandwidth, false);
1837
1838 rbMap = m_ffrSapProvider->GetAvailableUlRbg();
1839
1840 for (auto it = rbMap.begin(); it != rbMap.end(); it++)
1841 {
1842 if (*it)
1843 {
1844 rbAllocatedNum++;
1845 }
1846 }
1847
1848 uint8_t minContinuousUlBandwidth = m_ffrSapProvider->GetMinContinuousUlBandwidth();
1849 uint8_t ffrUlBandwidth = m_cschedCellConfig.m_ulBandwidth - rbAllocatedNum;
1850
1851 // remove RACH allocation
1852 for (uint16_t i = 0; i < m_cschedCellConfig.m_ulBandwidth; i++)
1853 {
1854 if (rbgAllocationMap.at(i) != 0)
1855 {
1856 rbMap.at(i) = true;
1857 NS_LOG_DEBUG(this << " Allocated for RACH " << i);
1858 }
1859 }
1860
1861 if (m_harqOn)
1862 {
1863 // Process UL HARQ feedback
1864 for (std::size_t i = 0; i < params.m_ulInfoList.size(); i++)
1865 {
1866 if (params.m_ulInfoList.at(i).m_receptionStatus == UlInfoListElement_s::NotOk)
1867 {
1868 // retx correspondent block: retrieve the UL-DCI
1869 uint16_t rnti = params.m_ulInfoList.at(i).m_rnti;
1870 auto itProcId = m_ulHarqCurrentProcessId.find(rnti);
1871 if (itProcId == m_ulHarqCurrentProcessId.end())
1872 {
1873 NS_LOG_ERROR("No info find in HARQ buffer for UE (might change eNB) " << rnti);
1874 }
1875 uint8_t harqId = (uint8_t)((*itProcId).second - HARQ_PERIOD) % HARQ_PROC_NUM;
1876 NS_LOG_INFO(this << " UL-HARQ retx RNTI " << rnti << " harqId " << (uint16_t)harqId
1877 << " i " << i << " size " << params.m_ulInfoList.size());
1878 auto itHarq = m_ulHarqProcessesDciBuffer.find(rnti);
1879 if (itHarq == m_ulHarqProcessesDciBuffer.end())
1880 {
1881 NS_LOG_ERROR("No info find in HARQ buffer for UE (might change eNB) " << rnti);
1882 continue;
1883 }
1884 UlDciListElement_s dci = (*itHarq).second.at(harqId);
1885 auto itStat = m_ulHarqProcessesStatus.find(rnti);
1886 if (itStat == m_ulHarqProcessesStatus.end())
1887 {
1888 NS_LOG_ERROR("No info find in HARQ buffer for UE (might change eNB) " << rnti);
1889 }
1890 if ((*itStat).second.at(harqId) >= 3)
1891 {
1892 NS_LOG_INFO("Max number of retransmissions reached (UL)-> drop process");
1893 continue;
1894 }
1895 bool free = true;
1896
1897 for (int j = dci.m_rbStart; j < dci.m_rbStart + dci.m_rbLen; j++)
1898 {
1899 if (rbMap.at(j))
1900 {
1901 free = false;
1902 NS_LOG_INFO(this << " BUSY " << j);
1903 }
1904 }
1905 if (free)
1906 {
1907 // retx on the same RBs
1908 for (int j = dci.m_rbStart; j < dci.m_rbStart + dci.m_rbLen; j++)
1909 {
1910 rbMap.at(j) = true;
1911 rbgAllocationMap.at(j) = dci.m_rnti;
1912 NS_LOG_INFO("\tRB " << j);
1913 rbAllocatedNum++;
1914 }
1915 NS_LOG_INFO(this << " Send retx in the same RBs " << (uint16_t)dci.m_rbStart
1916 << " to " << dci.m_rbStart + dci.m_rbLen << " RV "
1917 << (*itStat).second.at(harqId) + 1);
1918 }
1919 else
1920 {
1921 NS_LOG_INFO("Cannot allocate retx due to RACH allocations for UE " << rnti);
1922 continue;
1923 }
1924 dci.m_ndi = 0;
1925 // Update HARQ buffers with new HarqId
1926 (*itStat).second.at((*itProcId).second) = (*itStat).second.at(harqId) + 1;
1927 (*itStat).second.at(harqId) = 0;
1928 (*itHarq).second.at((*itProcId).second) = dci;
1929 ret.m_dciList.push_back(dci);
1930 rntiAllocated.insert(dci.m_rnti);
1931 }
1932 else
1933 {
1934 NS_LOG_INFO(this << " HARQ-ACK feedback from RNTI "
1935 << params.m_ulInfoList.at(i).m_rnti);
1936 }
1937 }
1938 }
1939
1940 std::map<uint16_t, uint32_t>::iterator it;
1941 int nflows = 0;
1942
1943 for (it = m_ceBsrRxed.begin(); it != m_ceBsrRxed.end(); it++)
1944 {
1945 auto itRnti = rntiAllocated.find((*it).first);
1946 // select UEs with queues not empty and not yet allocated for HARQ
1947 if (((*it).second > 0) && (itRnti == rntiAllocated.end()))
1948 {
1949 nflows++;
1950 }
1951 }
1952
1953 if (nflows == 0)
1954 {
1955 if (!ret.m_dciList.empty())
1956 {
1957 m_allocationMaps[params.m_sfnSf] = rbgAllocationMap;
1958 m_schedSapUser->SchedUlConfigInd(ret);
1959 }
1960
1961 return; // no flows to be scheduled
1962 }
1963
1964 // Divide the remaining resources equally among the active users starting from the subsequent
1965 // one served last scheduling trigger
1966 uint16_t tempRbPerFlow = (ffrUlBandwidth) / (nflows + rntiAllocated.size());
1967 uint16_t rbPerFlow =
1968 (minContinuousUlBandwidth < tempRbPerFlow) ? minContinuousUlBandwidth : tempRbPerFlow;
1969
1970 if (rbPerFlow < 3)
1971 {
1972 rbPerFlow = 3; // at least 3 rbg per flow (till available resource) to ensure TxOpportunity
1973 // >= 7 bytes
1974 }
1975 int rbAllocated = 0;
1976
1977 if (m_nextRntiUl != 0)
1978 {
1979 for (it = m_ceBsrRxed.begin(); it != m_ceBsrRxed.end(); it++)
1980 {
1981 if ((*it).first == m_nextRntiUl)
1982 {
1983 break;
1984 }
1985 }
1986 if (it == m_ceBsrRxed.end())
1987 {
1988 NS_LOG_ERROR(this << " no user found");
1989 }
1990 }
1991 else
1992 {
1993 it = m_ceBsrRxed.begin();
1994 m_nextRntiUl = (*it).first;
1995 }
1996 do
1997 {
1998 auto itRnti = rntiAllocated.find((*it).first);
1999 if ((itRnti != rntiAllocated.end()) || ((*it).second == 0))
2000 {
2001 // UE already allocated for UL-HARQ -> skip it
2002 NS_LOG_DEBUG(this << " UE already allocated in HARQ -> discarded, RNTI "
2003 << (*it).first);
2004 it++;
2005 if (it == m_ceBsrRxed.end())
2006 {
2007 // restart from the first
2008 it = m_ceBsrRxed.begin();
2009 }
2010 continue;
2011 }
2012 if (rbAllocated + rbPerFlow - 1 > m_cschedCellConfig.m_ulBandwidth)
2013 {
2014 // limit to physical resources last resource assignment
2015 rbPerFlow = m_cschedCellConfig.m_ulBandwidth - rbAllocated;
2016 // at least 3 rbg per flow to ensure TxOpportunity >= 7 bytes
2017 if (rbPerFlow < 3)
2018 {
2019 // terminate allocation
2020 rbPerFlow = 0;
2021 }
2022 }
2023
2024 rbAllocated = 0;
2025 UlDciListElement_s uldci;
2026 uldci.m_rnti = (*it).first;
2027 uldci.m_rbLen = rbPerFlow;
2028 bool allocated = false;
2029 NS_LOG_INFO(this << " RB Allocated " << rbAllocated << " rbPerFlow " << rbPerFlow
2030 << " flows " << nflows);
2031 while ((!allocated) && ((rbAllocated + rbPerFlow - m_cschedCellConfig.m_ulBandwidth) < 1) &&
2032 (rbPerFlow != 0))
2033 {
2034 // check availability
2035 bool free = true;
2036 for (int j = rbAllocated; j < rbAllocated + rbPerFlow; j++)
2037 {
2038 if (rbMap.at(j))
2039 {
2040 free = false;
2041 break;
2042 }
2043 if (!m_ffrSapProvider->IsUlRbgAvailableForUe(j, (*it).first))
2044 {
2045 free = false;
2046 break;
2047 }
2048 }
2049 if (free)
2050 {
2051 NS_LOG_INFO(this << "RNTI: " << (*it).first << " RB Allocated " << rbAllocated
2052 << " rbPerFlow " << rbPerFlow << " flows " << nflows);
2053 uldci.m_rbStart = rbAllocated;
2054
2055 for (int j = rbAllocated; j < rbAllocated + rbPerFlow; j++)
2056 {
2057 rbMap.at(j) = true;
2058 // store info on allocation for managing ul-cqi interpretation
2059 rbgAllocationMap.at(j) = (*it).first;
2060 }
2061 rbAllocated += rbPerFlow;
2062 allocated = true;
2063 break;
2064 }
2065 rbAllocated++;
2066 if (rbAllocated + rbPerFlow - 1 > m_cschedCellConfig.m_ulBandwidth)
2067 {
2068 // limit to physical resources last resource assignment
2069 rbPerFlow = m_cschedCellConfig.m_ulBandwidth - rbAllocated;
2070 // at least 3 rbg per flow to ensure TxOpportunity >= 7 bytes
2071 if (rbPerFlow < 3)
2072 {
2073 // terminate allocation
2074 rbPerFlow = 0;
2075 }
2076 }
2077 }
2078 if (!allocated)
2079 {
2080 // unable to allocate new resource: finish scheduling
2081 // m_nextRntiUl = (*it).first;
2082 // if (ret.m_dciList.size () > 0)
2083 // {
2084 // m_schedSapUser->SchedUlConfigInd (ret);
2085 // }
2086 // m_allocationMaps[params.m_sfnSf] = rbgAllocationMap; return;
2087 break;
2088 }
2089
2090 auto itCqi = m_ueCqi.find((*it).first);
2091 int cqi = 0;
2092 if (itCqi == m_ueCqi.end())
2093 {
2094 // no cqi info about this UE
2095 uldci.m_mcs = 0; // MCS 0 -> UL-AMC TBD
2096 }
2097 else
2098 {
2099 // take the lowest CQI value (worst RB)
2100 NS_ABORT_MSG_IF((*itCqi).second.empty(),
2101 "CQI of RNTI = " << (*it).first << " has expired");
2102 double minSinr = (*itCqi).second.at(uldci.m_rbStart);
2103 if (minSinr == NO_SINR)
2104 {
2105 minSinr = EstimateUlSinr((*it).first, uldci.m_rbStart);
2106 }
2107 for (uint16_t i = uldci.m_rbStart; i < uldci.m_rbStart + uldci.m_rbLen; i++)
2108 {
2109 double sinr = (*itCqi).second.at(i);
2110 if (sinr == NO_SINR)
2111 {
2112 sinr = EstimateUlSinr((*it).first, i);
2113 }
2114 if (sinr < minSinr)
2115 {
2116 minSinr = sinr;
2117 }
2118 }
2119
2120 // translate SINR -> cqi: WILD ACK: same as DL
2121 double s = log2(1 + (std::pow(10, minSinr / 10) / ((-std::log(5.0 * 0.00005)) / 1.5)));
2122 cqi = m_amc->GetCqiFromSpectralEfficiency(s);
2123 if (cqi == 0)
2124 {
2125 it++;
2126 if (it == m_ceBsrRxed.end())
2127 {
2128 // restart from the first
2129 it = m_ceBsrRxed.begin();
2130 }
2131 NS_LOG_DEBUG(this << " UE discarded for CQI = 0, RNTI " << uldci.m_rnti);
2132 // remove UE from allocation map
2133 for (uint16_t i = uldci.m_rbStart; i < uldci.m_rbStart + uldci.m_rbLen; i++)
2134 {
2135 rbgAllocationMap.at(i) = 0;
2136 }
2137 continue; // CQI == 0 means "out of range" (see table 7.2.3-1 of 36.213)
2138 }
2139 uldci.m_mcs = m_amc->GetMcsFromCqi(cqi);
2140 }
2141
2142 uldci.m_tbSize = (m_amc->GetUlTbSizeFromMcs(uldci.m_mcs, rbPerFlow) / 8);
2144 uldci.m_ndi = 1;
2145 uldci.m_cceIndex = 0;
2146 uldci.m_aggrLevel = 1;
2147 uldci.m_ueTxAntennaSelection = 3; // antenna selection OFF
2148 uldci.m_hopping = false;
2149 uldci.m_n2Dmrs = 0;
2150 uldci.m_tpc = 0; // no power control
2151 uldci.m_cqiRequest = false; // only period CQI at this stage
2152 uldci.m_ulIndex = 0; // TDD parameter
2153 uldci.m_dai = 1; // TDD parameter
2154 uldci.m_freqHopping = 0;
2155 uldci.m_pdcchPowerOffset = 0; // not used
2156 ret.m_dciList.push_back(uldci);
2157 // store DCI for HARQ_PERIOD
2158 uint8_t harqId = 0;
2159 if (m_harqOn)
2160 {
2161 auto itProcId = m_ulHarqCurrentProcessId.find(uldci.m_rnti);
2162 if (itProcId == m_ulHarqCurrentProcessId.end())
2163 {
2164 NS_FATAL_ERROR("No info find in HARQ buffer for UE " << uldci.m_rnti);
2165 }
2166 harqId = (*itProcId).second;
2167 auto itDci = m_ulHarqProcessesDciBuffer.find(uldci.m_rnti);
2168 if (itDci == m_ulHarqProcessesDciBuffer.end())
2169 {
2170 NS_FATAL_ERROR("Unable to find RNTI entry in UL DCI HARQ buffer for RNTI "
2171 << uldci.m_rnti);
2172 }
2173 (*itDci).second.at(harqId) = uldci;
2174 // Update HARQ process status (RV 0)
2175 auto itStat = m_ulHarqProcessesStatus.find(uldci.m_rnti);
2176 if (itStat == m_ulHarqProcessesStatus.end())
2177 {
2178 NS_LOG_ERROR("No info find in HARQ buffer for UE (might change eNB) "
2179 << uldci.m_rnti);
2180 }
2181 (*itStat).second.at(harqId) = 0;
2182 }
2183
2184 NS_LOG_INFO(this << " UE Allocation RNTI " << (*it).first << " startPRB "
2185 << (uint32_t)uldci.m_rbStart << " nPRB " << (uint32_t)uldci.m_rbLen
2186 << " CQI " << cqi << " MCS " << (uint32_t)uldci.m_mcs << " TBsize "
2187 << uldci.m_tbSize << " RbAlloc " << rbAllocated << " harqId "
2188 << (uint16_t)harqId);
2189
2190 // update TTI UE stats
2191 auto itStats = m_flowStatsUl.find((*it).first);
2192 if (itStats != m_flowStatsUl.end())
2193 {
2194 (*itStats).second.lastTtiBytesTransmitted = uldci.m_tbSize;
2195 }
2196 else
2197 {
2198 NS_LOG_DEBUG(this << " No Stats for this allocated UE");
2199 }
2200
2201 it++;
2202 if (it == m_ceBsrRxed.end())
2203 {
2204 // restart from the first
2205 it = m_ceBsrRxed.begin();
2206 }
2207 if ((rbAllocated == m_cschedCellConfig.m_ulBandwidth) || (rbPerFlow == 0))
2208 {
2209 // Stop allocation: no more PRBs
2210 m_nextRntiUl = (*it).first;
2211 break;
2212 }
2213 } while (((*it).first != m_nextRntiUl) && (rbPerFlow != 0));
2214
2215 // Update global UE stats
2216 // update UEs stats
2217 for (auto itStats = m_flowStatsUl.begin(); itStats != m_flowStatsUl.end(); itStats++)
2218 {
2219 (*itStats).second.totalBytesTransmitted += (*itStats).second.lastTtiBytesTransmitted;
2220 // update average throughput (see eq. 12.3 of Sec 12.3.1.2 of LTE – The UMTS Long Term
2221 // Evolution, Ed Wiley)
2222 (*itStats).second.lastAveragedThroughput =
2223 ((1.0 - (1.0 / m_timeWindow)) * (*itStats).second.lastAveragedThroughput) +
2224 ((1.0 / m_timeWindow) * (double)((*itStats).second.lastTtiBytesTransmitted / 0.001));
2225 NS_LOG_INFO(this << " UE total bytes " << (*itStats).second.totalBytesTransmitted);
2226 NS_LOG_INFO(this << " UE average throughput " << (*itStats).second.lastAveragedThroughput);
2227 (*itStats).second.lastTtiBytesTransmitted = 0;
2228 }
2229 m_allocationMaps[params.m_sfnSf] = rbgAllocationMap;
2230 m_schedSapUser->SchedUlConfigInd(ret);
2231}
2232
2233void
2239
2240void
2246
2247void
2250{
2251 NS_LOG_FUNCTION(this);
2252
2253 for (unsigned int i = 0; i < params.m_macCeList.size(); i++)
2254 {
2255 if (params.m_macCeList.at(i).m_macCeType == MacCeListElement_s::BSR)
2256 {
2257 // buffer status report
2258 // note that this scheduler does not differentiate the
2259 // allocation according to which LCGs have more/less bytes
2260 // to send.
2261 // Hence the BSR of different LCGs are just summed up to get
2262 // a total queue size that is used for allocation purposes.
2263
2264 uint32_t buffer = 0;
2265 for (uint8_t lcg = 0; lcg < 4; ++lcg)
2266 {
2267 uint8_t bsrId = params.m_macCeList.at(i).m_macCeValue.m_bufferStatus.at(lcg);
2268 buffer += BufferSizeLevelBsr::BsrId2BufferSize(bsrId);
2269 }
2270
2271 uint16_t rnti = params.m_macCeList.at(i).m_rnti;
2272 NS_LOG_LOGIC(this << "RNTI=" << rnti << " buffer=" << buffer);
2273 auto it = m_ceBsrRxed.find(rnti);
2274 if (it == m_ceBsrRxed.end())
2275 {
2276 // create the new entry
2277 m_ceBsrRxed.insert(std::pair<uint16_t, uint32_t>(rnti, buffer));
2278 }
2279 else
2280 {
2281 // update the buffer size value
2282 (*it).second = buffer;
2283 }
2284 }
2285 }
2286}
2287
2288void
2291{
2292 NS_LOG_FUNCTION(this);
2293 // retrieve the allocation for this subframe
2294 switch (m_ulCqiFilter)
2295 {
2297 // filter all the CQIs that are not SRS based
2298 if (params.m_ulCqi.m_type != UlCqi_s::SRS)
2299 {
2300 return;
2301 }
2302 }
2303 break;
2305 // filter all the CQIs that are not SRS based
2306 if (params.m_ulCqi.m_type != UlCqi_s::PUSCH)
2307 {
2308 return;
2309 }
2310 }
2311 break;
2312 default:
2313 NS_FATAL_ERROR("Unknown UL CQI type");
2314 }
2315
2316 switch (params.m_ulCqi.m_type)
2317 {
2318 case UlCqi_s::PUSCH: {
2319 NS_LOG_DEBUG(this << " Collect PUSCH CQIs of Frame no. " << (params.m_sfnSf >> 4)
2320 << " subframe no. " << (0xF & params.m_sfnSf));
2321 auto itMap = m_allocationMaps.find(params.m_sfnSf);
2322 if (itMap == m_allocationMaps.end())
2323 {
2324 return;
2325 }
2326 for (uint32_t i = 0; i < (*itMap).second.size(); i++)
2327 {
2328 // convert from fixed point notation Sxxxxxxxxxxx.xxx to double
2329 double sinr = LteFfConverter::fpS11dot3toDouble(params.m_ulCqi.m_sinr.at(i));
2330 auto itCqi = m_ueCqi.find((*itMap).second.at(i));
2331 if (itCqi == m_ueCqi.end())
2332 {
2333 // create a new entry
2334 std::vector<double> newCqi;
2335 for (uint32_t j = 0; j < m_cschedCellConfig.m_ulBandwidth; j++)
2336 {
2337 if (i == j)
2338 {
2339 newCqi.push_back(sinr);
2340 }
2341 else
2342 {
2343 // initialize with NO_SINR value.
2344 newCqi.push_back(NO_SINR);
2345 }
2346 }
2347 m_ueCqi[(*itMap).second.at(i)] = newCqi;
2348 // generate correspondent timer
2349 m_ueCqiTimers[(*itMap).second.at(i)] = m_cqiTimersThreshold;
2350 }
2351 else
2352 {
2353 // update the value
2354 (*itCqi).second.at(i) = sinr;
2355 NS_LOG_DEBUG(this << " RNTI " << (*itMap).second.at(i) << " RB " << i << " SINR "
2356 << sinr);
2357 // update correspondent timer
2358 auto itTimers = m_ueCqiTimers.find((*itMap).second.at(i));
2359 (*itTimers).second = m_cqiTimersThreshold;
2360 }
2361 }
2362 // remove obsolete info on allocation
2363 m_allocationMaps.erase(itMap);
2364 }
2365 break;
2366 case UlCqi_s::SRS: {
2367 NS_LOG_DEBUG(this << " Collect SRS CQIs of Frame no. " << (params.m_sfnSf >> 4)
2368 << " subframe no. " << (0xF & params.m_sfnSf));
2369 // get the RNTI from vendor specific parameters
2370 uint16_t rnti = 0;
2371 NS_ASSERT(!params.m_vendorSpecificList.empty());
2372 for (std::size_t i = 0; i < params.m_vendorSpecificList.size(); i++)
2373 {
2374 if (params.m_vendorSpecificList.at(i).m_type == SRS_CQI_RNTI_VSP)
2375 {
2376 Ptr<SrsCqiRntiVsp> vsp =
2377 DynamicCast<SrsCqiRntiVsp>(params.m_vendorSpecificList.at(i).m_value);
2378 rnti = vsp->GetRnti();
2379 }
2380 }
2381 auto itCqi = m_ueCqi.find(rnti);
2382 if (itCqi == m_ueCqi.end())
2383 {
2384 // create a new entry
2385 std::vector<double> newCqi;
2386 for (uint32_t j = 0; j < m_cschedCellConfig.m_ulBandwidth; j++)
2387 {
2388 double sinr = LteFfConverter::fpS11dot3toDouble(params.m_ulCqi.m_sinr.at(j));
2389 newCqi.push_back(sinr);
2390 NS_LOG_INFO(this << " RNTI " << rnti << " new SRS-CQI for RB " << j << " value "
2391 << sinr);
2392 }
2393 m_ueCqi.insert(std::pair<uint16_t, std::vector<double>>(rnti, newCqi));
2394 // generate correspondent timer
2395 m_ueCqiTimers.insert(std::pair<uint16_t, uint32_t>(rnti, m_cqiTimersThreshold));
2396 }
2397 else
2398 {
2399 // update the values
2400 for (uint32_t j = 0; j < m_cschedCellConfig.m_ulBandwidth; j++)
2401 {
2402 double sinr = LteFfConverter::fpS11dot3toDouble(params.m_ulCqi.m_sinr.at(j));
2403 (*itCqi).second.at(j) = sinr;
2404 NS_LOG_INFO(this << " RNTI " << rnti << " update SRS-CQI for RB " << j << " value "
2405 << sinr);
2406 }
2407 // update correspondent timer
2408 auto itTimers = m_ueCqiTimers.find(rnti);
2409 (*itTimers).second = m_cqiTimersThreshold;
2410 }
2411 }
2412 break;
2413 case UlCqi_s::PUCCH_1:
2414 case UlCqi_s::PUCCH_2:
2415 case UlCqi_s::PRACH: {
2416 NS_FATAL_ERROR("PfFfMacScheduler supports only PUSCH and SRS UL-CQIs");
2417 }
2418 break;
2419 default:
2420 NS_FATAL_ERROR("Unknown type of UL-CQI");
2421 }
2422}
2423
2424void
2426{
2427 // refresh DL CQI P01 Map
2428 auto itP10 = m_p10CqiTimers.begin();
2429 while (itP10 != m_p10CqiTimers.end())
2430 {
2431 NS_LOG_INFO(this << " P10-CQI for user " << (*itP10).first << " is "
2432 << (uint32_t)(*itP10).second << " thr " << (uint32_t)m_cqiTimersThreshold);
2433 if ((*itP10).second == 0)
2434 {
2435 // delete correspondent entries
2436 auto itMap = m_p10CqiRxed.find((*itP10).first);
2437 NS_ASSERT_MSG(itMap != m_p10CqiRxed.end(),
2438 " Does not find CQI report for user " << (*itP10).first);
2439 NS_LOG_INFO(this << " P10-CQI expired for user " << (*itP10).first);
2440 m_p10CqiRxed.erase(itMap);
2441 auto temp = itP10;
2442 itP10++;
2443 m_p10CqiTimers.erase(temp);
2444 }
2445 else
2446 {
2447 (*itP10).second--;
2448 itP10++;
2449 }
2450 }
2451
2452 // refresh DL CQI A30 Map
2453 auto itA30 = m_a30CqiTimers.begin();
2454 while (itA30 != m_a30CqiTimers.end())
2455 {
2456 NS_LOG_INFO(this << " A30-CQI for user " << (*itA30).first << " is "
2457 << (uint32_t)(*itA30).second << " thr " << (uint32_t)m_cqiTimersThreshold);
2458 if ((*itA30).second == 0)
2459 {
2460 // delete correspondent entries
2461 auto itMap = m_a30CqiRxed.find((*itA30).first);
2462 NS_ASSERT_MSG(itMap != m_a30CqiRxed.end(),
2463 " Does not find CQI report for user " << (*itA30).first);
2464 NS_LOG_INFO(this << " A30-CQI expired for user " << (*itA30).first);
2465 m_a30CqiRxed.erase(itMap);
2466 auto temp = itA30;
2467 itA30++;
2468 m_a30CqiTimers.erase(temp);
2469 }
2470 else
2471 {
2472 (*itA30).second--;
2473 itA30++;
2474 }
2475 }
2476}
2477
2478void
2480{
2481 // refresh UL CQI Map
2482 auto itUl = m_ueCqiTimers.begin();
2483 while (itUl != m_ueCqiTimers.end())
2484 {
2485 NS_LOG_INFO(this << " UL-CQI for user " << (*itUl).first << " is "
2486 << (uint32_t)(*itUl).second << " thr " << (uint32_t)m_cqiTimersThreshold);
2487 if ((*itUl).second == 0)
2488 {
2489 // delete correspondent entries
2490 auto itMap = m_ueCqi.find((*itUl).first);
2491 NS_ASSERT_MSG(itMap != m_ueCqi.end(),
2492 " Does not find CQI report for user " << (*itUl).first);
2493 NS_LOG_INFO(this << " UL-CQI exired for user " << (*itUl).first);
2494 (*itMap).second.clear();
2495 m_ueCqi.erase(itMap);
2496 auto temp = itUl;
2497 itUl++;
2498 m_ueCqiTimers.erase(temp);
2499 }
2500 else
2501 {
2502 (*itUl).second--;
2503 itUl++;
2504 }
2505 }
2506}
2507
2508void
2509CqaFfMacScheduler::UpdateDlRlcBufferInfo(uint16_t rnti, uint8_t lcid, uint16_t size)
2510{
2511 LteFlowId_t flow(rnti, lcid);
2512 auto it = m_rlcBufferReq.find(flow);
2513 if (it != m_rlcBufferReq.end())
2514 {
2515 NS_LOG_INFO(this << " UE " << rnti << " LC " << (uint16_t)lcid << " txqueue "
2516 << (*it).second.m_rlcTransmissionQueueSize << " retxqueue "
2517 << (*it).second.m_rlcRetransmissionQueueSize << " status "
2518 << (*it).second.m_rlcStatusPduSize << " decrease " << size);
2519 // Update queues: RLC tx order Status, ReTx, Tx
2520 // Update status queue
2521 if (((*it).second.m_rlcStatusPduSize > 0) && (size >= (*it).second.m_rlcStatusPduSize))
2522 {
2523 (*it).second.m_rlcStatusPduSize = 0;
2524 }
2525 else if (((*it).second.m_rlcRetransmissionQueueSize > 0) &&
2526 (size >= (*it).second.m_rlcRetransmissionQueueSize))
2527 {
2528 (*it).second.m_rlcRetransmissionQueueSize = 0;
2529 }
2530 else if ((*it).second.m_rlcTransmissionQueueSize > 0)
2531 {
2532 uint32_t rlcOverhead;
2533 if (lcid == 1)
2534 {
2535 // for SRB1 (using RLC AM) it's better to
2536 // overestimate RLC overhead rather than
2537 // underestimate it and risk unneeded
2538 // segmentation which increases delay
2539 rlcOverhead = 4;
2540 }
2541 else
2542 {
2543 // minimum RLC overhead due to header
2544 rlcOverhead = 2;
2545 }
2546 // update transmission queue
2547 if ((*it).second.m_rlcTransmissionQueueSize <= size - rlcOverhead)
2548 {
2549 (*it).second.m_rlcTransmissionQueueSize = 0;
2550 }
2551 else
2552 {
2553 (*it).second.m_rlcTransmissionQueueSize -= size - rlcOverhead;
2554 }
2555 }
2556 }
2557 else
2558 {
2559 NS_LOG_ERROR(this << " Does not find DL RLC Buffer Report of UE " << rnti);
2560 }
2561}
2562
2563void
2564CqaFfMacScheduler::UpdateUlRlcBufferInfo(uint16_t rnti, uint16_t size)
2565{
2566 size = size - 2; // remove the minimum RLC overhead
2567 auto it = m_ceBsrRxed.find(rnti);
2568 if (it != m_ceBsrRxed.end())
2569 {
2570 NS_LOG_INFO(this << " UE " << rnti << " size " << size << " BSR " << (*it).second);
2571 if ((*it).second >= size)
2572 {
2573 (*it).second -= size;
2574 }
2575 else
2576 {
2577 (*it).second = 0;
2578 }
2579 }
2580 else
2581 {
2582 NS_LOG_ERROR(this << " Does not find BSR report info of UE " << rnti);
2583 }
2584}
2585
2586void
2588{
2589 NS_LOG_FUNCTION(this << " RNTI " << rnti << " txMode " << (uint16_t)txMode);
2591 params.m_rnti = rnti;
2592 params.m_transmissionMode = txMode;
2593 m_cschedSapUser->CschedUeConfigUpdateInd(params);
2594}
2595
2596} // namespace ns3
uint32_t v
static uint32_t BsrId2BufferSize(uint8_t val)
Convert BSR ID to buffer size.
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.
Provides the SCHED SAP.
FfMacSchedSapUser class.
FfMacScheduler()
constructor
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
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.
Definition ptr.h:70
static Time Now()
Return the current simulation virtual time.
Definition simulator.cc:191
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:50
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition type-id.cc:999
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:246
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition log.h:194
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition log.h:260
#define NS_LOG_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
Definition log.h:274
#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:267
Ptr< T > CreateObject(Args &&... args)
Create an object by type, with varying number of constructor parameters.
Definition object.h:627
#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:643
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 (see table 7.1.6.1-1 of 36.213).
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.