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