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
25#include <ns3/boolean.h>
26#include <ns3/cqa-ff-mac-scheduler.h>
27#include <ns3/ff-mac-common.h>
28#include <ns3/integer.h>
29#include <ns3/log.h>
30#include <ns3/lte-amc.h>
31#include <ns3/lte-vendor-specific-parameters.h>
32#include <ns3/math.h>
33#include <ns3/pointer.h>
34#include <ns3/simulator.h>
35#include <ns3/string.h>
36
37#include <cfloat>
38#include <set>
39#include <stdexcept>
40
41namespace ns3
42{
43
44NS_LOG_COMPONENT_DEFINE("CqaFfMacScheduler");
45
47static const int CqaType0AllocationRbg[4] = {
48 10, // RGB size 1
49 26, // RGB size 2
50 63, // RGB size 3
51 110, // RGB size 4
52}; // see table 7.1.6.1-1 of 36.213
53
54NS_OBJECT_ENSURE_REGISTERED(CqaFfMacScheduler);
55
58{
61};
62
69bool
70CQIValueDescComparator(uint8_t key1, uint8_t key2)
71{
72 return key1 > key2;
73}
74
81bool
82CqaGroupDescComparator(int key1, int key2)
83{
84 return key1 > key2;
85}
86
88typedef uint8_t CQI_value;
90typedef int RBG_index;
92typedef int HOL_group;
93
95typedef std::map<CQI_value, LteFlowId_t, bool (*)(uint8_t, uint8_t)> t_map_CQIToUE; // sorted
97typedef std::map<RBG_index, t_map_CQIToUE> t_map_RBGToCQIsSorted;
99typedef std::map<HOL_group, t_map_RBGToCQIsSorted> t_map_HOLGroupToRBGs;
100
102typedef std::map<CQI_value, LteFlowId_t, bool (*)(uint8_t, uint8_t)>::iterator
103 t_it_CQIToUE; // sorted
105typedef std::map<RBG_index, t_map_CQIToUE>::iterator t_it_RBGToCQIsSorted;
107typedef std::map<HOL_group, t_map_RBGToCQIsSorted>::iterator t_it_HOLGroupToRBGs;
108
110typedef std::multimap<HOL_group, std::set<LteFlowId_t>, bool (*)(int, int)> t_map_HOLgroupToUEs;
112typedef std::map<HOL_group, std::set<LteFlowId_t>>::iterator t_it_HOLgroupToUEs;
113
114// typedef std::map<RBG_index,CQI_value> map_RBG_to_CQI;
115// typedef std::map<LteFlowId_t,map_RBG_to_CQI> map_flowId_to_CQI_map;
116
123bool
124CqaKeyDescComparator(uint16_t key1, uint16_t key2)
125{
126 return key1 > key2;
127}
128
130 : m_cschedSapUser(nullptr),
131 m_schedSapUser(nullptr),
132 m_timeWindow(99.0),
133 m_nextRntiUl(0)
134{
135 m_amc = CreateObject<LteAmc>();
138 m_ffrSapProvider = nullptr;
140}
141
143{
144 NS_LOG_FUNCTION(this);
145}
146
147void
149{
150 NS_LOG_FUNCTION(this);
154 m_dlInfoListBuffered.clear();
158 delete m_cschedSapProvider;
159 delete m_schedSapProvider;
160 delete m_ffrSapUser;
161}
162
163TypeId
165{
166 static TypeId tid =
167 TypeId("ns3::CqaFfMacScheduler")
169 .SetGroupName("Lte")
170 .AddConstructor<CqaFfMacScheduler>()
171 .AddAttribute("CqiTimerThreshold",
172 "The number of TTIs a CQI is valid (default 1000 - 1 sec.)",
173 UintegerValue(1000),
175 MakeUintegerChecker<uint32_t>())
176 .AddAttribute("CqaMetric",
177 "CqaFfMacScheduler metric type that can be: CqaFf, CqaPf",
178 StringValue("CqaFf"),
181 .AddAttribute("HarqEnabled",
182 "Activate/Deactivate the HARQ [by default is active].",
183 BooleanValue(true),
186 .AddAttribute("UlGrantMcs",
187 "The MCS of the UL grant, must be [0..15] (default 0)",
188 UintegerValue(0),
190 MakeUintegerChecker<uint8_t>());
191 return tid;
192}
193
194void
196{
197 m_cschedSapUser = s;
198}
199
200void
202{
203 m_schedSapUser = s;
204}
205
208{
209 return m_cschedSapProvider;
210}
211
214{
215 return m_schedSapProvider;
216}
217
218void
220{
222}
223
226{
227 return m_ffrSapUser;
228}
229
230void
233{
234 NS_LOG_FUNCTION(this);
235 // Read the subset of parameters used
236 m_cschedCellConfig = params;
239 cnf.m_result = SUCCESS;
241}
242
243void
246{
247 NS_LOG_FUNCTION(this << " RNTI " << params.m_rnti << " txMode "
248 << (uint16_t)params.m_transmissionMode);
249 std::map<uint16_t, uint8_t>::iterator it = m_uesTxMode.find(params.m_rnti);
250 if (it == m_uesTxMode.end())
251 {
252 m_uesTxMode.insert(std::pair<uint16_t, uint8_t>(params.m_rnti, params.m_transmissionMode));
253 // generate HARQ buffers
254 m_dlHarqCurrentProcessId.insert(std::pair<uint16_t, uint8_t>(params.m_rnti, 0));
255 DlHarqProcessesStatus_t dlHarqPrcStatus;
256 dlHarqPrcStatus.resize(8, 0);
258 std::pair<uint16_t, DlHarqProcessesStatus_t>(params.m_rnti, dlHarqPrcStatus));
259 DlHarqProcessesTimer_t dlHarqProcessesTimer;
260 dlHarqProcessesTimer.resize(8, 0);
262 std::pair<uint16_t, DlHarqProcessesTimer_t>(params.m_rnti, dlHarqProcessesTimer));
264 dlHarqdci.resize(8);
266 std::pair<uint16_t, DlHarqProcessesDciBuffer_t>(params.m_rnti, dlHarqdci));
267 DlHarqRlcPduListBuffer_t dlHarqRlcPdu;
268 dlHarqRlcPdu.resize(2);
269 dlHarqRlcPdu.at(0).resize(8);
270 dlHarqRlcPdu.at(1).resize(8);
272 std::pair<uint16_t, DlHarqRlcPduListBuffer_t>(params.m_rnti, dlHarqRlcPdu));
273 m_ulHarqCurrentProcessId.insert(std::pair<uint16_t, uint8_t>(params.m_rnti, 0));
274 UlHarqProcessesStatus_t ulHarqPrcStatus;
275 ulHarqPrcStatus.resize(8, 0);
277 std::pair<uint16_t, UlHarqProcessesStatus_t>(params.m_rnti, ulHarqPrcStatus));
279 ulHarqdci.resize(8);
281 std::pair<uint16_t, UlHarqProcessesDciBuffer_t>(params.m_rnti, ulHarqdci));
282 }
283 else
284 {
285 (*it).second = params.m_transmissionMode;
286 }
287}
288
289void
292{
293 NS_LOG_FUNCTION(this << " New LC, rnti: " << params.m_rnti);
294
295 NS_LOG_FUNCTION("LC configuration. Number of LCs:" << params.m_logicalChannelConfigList.size());
296
297 // m_reconfigureFlat indicates if this is a reconfiguration or new UE is added, table 4.1.5 in
298 // LTE MAC scheduler specification
299 if (params.m_reconfigureFlag)
300 {
301 std::vector<struct LogicalChannelConfigListElement_s>::const_iterator lcit;
302
303 for (lcit = params.m_logicalChannelConfigList.begin();
304 lcit != params.m_logicalChannelConfigList.end();
305 lcit++)
306 {
307 LteFlowId_t flowid = LteFlowId_t(params.m_rnti, lcit->m_logicalChannelIdentity);
308
310 {
311 NS_LOG_ERROR("UE logical channels can not be reconfigured because it was not "
312 "configured before.");
313 }
314 else
315 {
316 m_ueLogicalChannelsConfigList.find(flowid)->second = *lcit;
317 }
318 }
319
320 } // else new UE is added
321 else
322 {
323 std::vector<struct LogicalChannelConfigListElement_s>::const_iterator lcit;
324
325 for (lcit = params.m_logicalChannelConfigList.begin();
326 lcit != params.m_logicalChannelConfigList.end();
327 lcit++)
328 {
329 LteFlowId_t flowId = LteFlowId_t(params.m_rnti, lcit->m_logicalChannelIdentity);
331 std::pair<LteFlowId_t, LogicalChannelConfigListElement_s>(flowId, *lcit));
332 }
333 }
334
335 std::map<uint16_t, CqasFlowPerf_t>::iterator it;
336
337 for (std::size_t i = 0; i < params.m_logicalChannelConfigList.size(); i++)
338 {
339 it = m_flowStatsDl.find(params.m_rnti);
340
341 if (it == m_flowStatsDl.end())
342 {
343 double tbrDlInBytes =
344 params.m_logicalChannelConfigList.at(i).m_eRabGuaranteedBitrateDl / 8; // byte/s
345 double tbrUlInBytes =
346 params.m_logicalChannelConfigList.at(i).m_eRabGuaranteedBitrateUl / 8; // byte/s
347
348 CqasFlowPerf_t flowStatsDl;
349 flowStatsDl.flowStart = Simulator::Now();
350 flowStatsDl.totalBytesTransmitted = 0;
351 flowStatsDl.lastTtiBytesTransmitted = 0;
352 flowStatsDl.lastAveragedThroughput = 1;
353 flowStatsDl.secondLastAveragedThroughput = 1;
354 flowStatsDl.targetThroughput = tbrDlInBytes;
355 m_flowStatsDl.insert(std::pair<uint16_t, CqasFlowPerf_t>(params.m_rnti, flowStatsDl));
356 CqasFlowPerf_t flowStatsUl;
357 flowStatsUl.flowStart = Simulator::Now();
358 flowStatsUl.totalBytesTransmitted = 0;
359 flowStatsUl.lastTtiBytesTransmitted = 0;
360 flowStatsUl.lastAveragedThroughput = 1;
361 flowStatsUl.secondLastAveragedThroughput = 1;
362 flowStatsUl.targetThroughput = tbrUlInBytes;
363 m_flowStatsUl.insert(std::pair<uint16_t, CqasFlowPerf_t>(params.m_rnti, flowStatsUl));
364 }
365 else
366 {
367 // update GBR from UeManager::SetupDataRadioBearer ()
368 double tbrDlInBytes =
369 params.m_logicalChannelConfigList.at(i).m_eRabGuaranteedBitrateDl / 8; // byte/s
370 double tbrUlInBytes =
371 params.m_logicalChannelConfigList.at(i).m_eRabGuaranteedBitrateUl / 8; // byte/s
372 m_flowStatsDl[(*it).first].targetThroughput = tbrDlInBytes;
373 m_flowStatsUl[(*it).first].targetThroughput = tbrUlInBytes;
374 }
375 }
376}
377
378void
381{
382 NS_LOG_FUNCTION(this);
383 std::vector<uint8_t>::const_iterator it;
384
385 for (it = params.m_logicalChannelIdentity.begin(); it != params.m_logicalChannelIdentity.end();
386 it++)
387 {
388 LteFlowId_t flowId = LteFlowId_t(params.m_rnti, *it);
389
390 // find the logical channel with the same Logical Channel Identity in the current list,
391 // release it
393 {
394 m_ueLogicalChannelsConfigList.erase(flowId);
395 }
396 else
397 {
398 NS_FATAL_ERROR("Logical channels cannot be released because it can not be found in the "
399 "list of active LCs");
400 }
401 }
402
403 for (std::size_t i = 0; i < params.m_logicalChannelIdentity.size(); i++)
404 {
405 std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it =
406 m_rlcBufferReq.begin();
407 std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator temp;
408 while (it != m_rlcBufferReq.end())
409 {
410 if (((*it).first.m_rnti == params.m_rnti) &&
411 ((*it).first.m_lcId == params.m_logicalChannelIdentity.at(i)))
412 {
413 temp = it;
414 it++;
415 m_rlcBufferReq.erase(temp);
416 }
417 else
418 {
419 it++;
420 }
421 }
422 }
423}
424
425void
428{
429 NS_LOG_FUNCTION(this);
430
431 for (int i = 0; i < MAX_LC_LIST; i++)
432 {
433 LteFlowId_t flowId = LteFlowId_t(params.m_rnti, i);
434 // find the logical channel with the same Logical Channel Identity in the current list,
435 // release it
437 {
438 m_ueLogicalChannelsConfigList.erase(flowId);
439 }
440 }
441
442 m_uesTxMode.erase(params.m_rnti);
443 m_dlHarqCurrentProcessId.erase(params.m_rnti);
444 m_dlHarqProcessesStatus.erase(params.m_rnti);
445 m_dlHarqProcessesTimer.erase(params.m_rnti);
446 m_dlHarqProcessesDciBuffer.erase(params.m_rnti);
447 m_dlHarqProcessesRlcPduListBuffer.erase(params.m_rnti);
448 m_ulHarqCurrentProcessId.erase(params.m_rnti);
449 m_ulHarqProcessesStatus.erase(params.m_rnti);
450 m_ulHarqProcessesDciBuffer.erase(params.m_rnti);
451 m_flowStatsDl.erase(params.m_rnti);
452 m_flowStatsUl.erase(params.m_rnti);
453 m_ceBsrRxed.erase(params.m_rnti);
454 std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it =
455 m_rlcBufferReq.begin();
456 std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator temp;
457 while (it != m_rlcBufferReq.end())
458 {
459 if ((*it).first.m_rnti == params.m_rnti)
460 {
461 temp = it;
462 it++;
463 m_rlcBufferReq.erase(temp);
464 }
465 else
466 {
467 it++;
468 }
469 }
470 if (m_nextRntiUl == params.m_rnti)
471 {
472 m_nextRntiUl = 0;
473 }
474}
475
476void
479{
480 NS_LOG_FUNCTION(this << params.m_rnti << (uint32_t)params.m_logicalChannelIdentity);
481 // API generated by RLC for updating RLC parameters on a LC (tx and retx queues)
482
483 std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it;
484
485 LteFlowId_t flow(params.m_rnti, params.m_logicalChannelIdentity);
486
487 it = m_rlcBufferReq.find(flow);
488
489 if (it == m_rlcBufferReq.end())
490 {
491 m_rlcBufferReq.insert(
492 std::pair<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>(flow,
493 params));
494 }
495 else
496 {
497 (*it).second = params;
498 }
499}
500
501void
504{
505 NS_LOG_FUNCTION(this);
506 NS_FATAL_ERROR("method not implemented");
507}
508
509void
512{
513 NS_LOG_FUNCTION(this);
514 NS_FATAL_ERROR("method not implemented");
515}
516
517int
519{
520 for (int i = 0; i < 4; i++)
521 {
522 if (dlbandwidth < CqaType0AllocationRbg[i])
523 {
524 return (i + 1);
525 }
526 }
527
528 return (-1);
529}
530
531unsigned int
533{
534 std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it;
535 unsigned int lcActive = 0;
536 for (it = m_rlcBufferReq.begin(); it != m_rlcBufferReq.end(); it++)
537 {
538 if (((*it).first.m_rnti == rnti) && (((*it).second.m_rlcTransmissionQueueSize > 0) ||
539 ((*it).second.m_rlcRetransmissionQueueSize > 0) ||
540 ((*it).second.m_rlcStatusPduSize > 0)))
541 {
542 lcActive++;
543 }
544 if ((*it).first.m_rnti > rnti)
545 {
546 break;
547 }
548 }
549 return (lcActive);
550}
551
552bool
554{
555 NS_LOG_FUNCTION(this << rnti);
556
557 std::map<uint16_t, uint8_t>::iterator it = m_dlHarqCurrentProcessId.find(rnti);
558 if (it == m_dlHarqCurrentProcessId.end())
559 {
560 NS_FATAL_ERROR("No Process Id found for this RNTI " << rnti);
561 }
562 std::map<uint16_t, DlHarqProcessesStatus_t>::iterator itStat =
563 m_dlHarqProcessesStatus.find(rnti);
564 if (itStat == m_dlHarqProcessesStatus.end())
565 {
566 NS_FATAL_ERROR("No Process Id Statusfound for this RNTI " << rnti);
567 }
568 uint8_t i = (*it).second;
569 do
570 {
571 i = (i + 1) % HARQ_PROC_NUM;
572 } while (((*itStat).second.at(i) != 0) && (i != (*it).second));
573 if ((*itStat).second.at(i) == 0)
574 {
575 return (true);
576 }
577 else
578 {
579 return (false); // return a not valid harq proc id
580 }
581}
582
583uint8_t
585{
586 NS_LOG_FUNCTION(this << rnti);
587
588 if (m_harqOn == false)
589 {
590 return (0);
591 }
592
593 std::map<uint16_t, uint8_t>::iterator it = m_dlHarqCurrentProcessId.find(rnti);
594 if (it == m_dlHarqCurrentProcessId.end())
595 {
596 NS_FATAL_ERROR("No Process Id found for this RNTI " << rnti);
597 }
598 std::map<uint16_t, DlHarqProcessesStatus_t>::iterator itStat =
599 m_dlHarqProcessesStatus.find(rnti);
600 if (itStat == m_dlHarqProcessesStatus.end())
601 {
602 NS_FATAL_ERROR("No Process Id Statusfound for this RNTI " << rnti);
603 }
604 uint8_t i = (*it).second;
605 do
606 {
607 i = (i + 1) % HARQ_PROC_NUM;
608 } while (((*itStat).second.at(i) != 0) && (i != (*it).second));
609 if ((*itStat).second.at(i) == 0)
610 {
611 (*it).second = i;
612 (*itStat).second.at(i) = 1;
613 }
614 else
615 {
616 NS_FATAL_ERROR("No HARQ process available for RNTI "
617 << rnti << " check before update with HarqProcessAvailability");
618 }
619
620 return ((*it).second);
621}
622
623void
625{
626 NS_LOG_FUNCTION(this);
627
628 std::map<uint16_t, DlHarqProcessesTimer_t>::iterator itTimers;
629 for (itTimers = m_dlHarqProcessesTimer.begin(); itTimers != m_dlHarqProcessesTimer.end();
630 itTimers++)
631 {
632 for (uint16_t i = 0; i < HARQ_PROC_NUM; i++)
633 {
634 if ((*itTimers).second.at(i) == HARQ_DL_TIMEOUT)
635 {
636 // reset HARQ process
637
638 NS_LOG_DEBUG(this << " Reset HARQ proc " << i << " for RNTI " << (*itTimers).first);
639 std::map<uint16_t, DlHarqProcessesStatus_t>::iterator itStat =
640 m_dlHarqProcessesStatus.find((*itTimers).first);
641 if (itStat == m_dlHarqProcessesStatus.end())
642 {
643 NS_FATAL_ERROR("No Process Id Status found for this RNTI "
644 << (*itTimers).first);
645 }
646 (*itStat).second.at(i) = 0;
647 (*itTimers).second.at(i) = 0;
648 }
649 else
650 {
651 (*itTimers).second.at(i)++;
652 }
653 }
654 }
655}
656
657void
660{
661 NS_LOG_FUNCTION(this << " Frame no. " << (params.m_sfnSf >> 4) << " subframe no. "
662 << (0xF & params.m_sfnSf));
663 // API generated by RLC for triggering the scheduling of a DL subframe
664 // evaluate the relative channel quality indicator for each UE per each RBG
665 // (since we are using allocation type 0 the small unit of allocation is RBG)
666 // Resource allocation type 0 (see sec 7.1.6.1 of 36.213)
667
669
671 int numberOfRBGs = m_cschedCellConfig.m_dlBandwidth / rbgSize;
672 std::map<uint16_t, std::multimap<uint8_t, qos_rb_and_CQI_assigned_to_lc>>
673 allocationMapPerRntiPerLCId;
674 std::map<uint16_t, std::multimap<uint8_t, qos_rb_and_CQI_assigned_to_lc>>::iterator itMap;
675 allocationMapPerRntiPerLCId.clear();
676 bool (*key_function_pointer_groups)(int, int) = CqaGroupDescComparator;
677 t_map_HOLgroupToUEs map_GBRHOLgroupToUE(key_function_pointer_groups);
678 t_map_HOLgroupToUEs map_nonGBRHOLgroupToUE(key_function_pointer_groups);
679 int grouping_parameter = 1000;
680 double tolerance = 1.1;
681 std::map<LteFlowId_t, int> UEtoHOL;
682 std::vector<bool> rbgMap; // global RBGs map
683 uint16_t rbgAllocatedNum = 0;
684 std::set<uint16_t> rntiAllocated;
685 rbgMap.resize(m_cschedCellConfig.m_dlBandwidth / rbgSize, false);
686
688 for (std::vector<bool>::iterator it = rbgMap.begin(); it != rbgMap.end(); it++)
689 {
690 if ((*it) == true)
691 {
692 rbgAllocatedNum++;
693 }
694 }
695
697
698 // update UL HARQ proc id
699 std::map<uint16_t, uint8_t>::iterator itProcId;
700 for (itProcId = m_ulHarqCurrentProcessId.begin(); itProcId != m_ulHarqCurrentProcessId.end();
701 itProcId++)
702 {
703 (*itProcId).second = ((*itProcId).second + 1) % HARQ_PROC_NUM;
704 }
705
706 // RACH Allocation
707 std::vector<bool> ulRbMap;
708 ulRbMap.resize(m_cschedCellConfig.m_ulBandwidth, false);
710 uint8_t maxContinuousUlBandwidth = 0;
711 uint8_t tmpMinBandwidth = 0;
712 uint16_t ffrRbStartOffset = 0;
713 uint16_t tmpFfrRbStartOffset = 0;
714 uint16_t index = 0;
715
716 for (std::vector<bool>::iterator it = ulRbMap.begin(); it != ulRbMap.end(); it++)
717 {
718 if ((*it) == true)
719 {
720 if (tmpMinBandwidth > maxContinuousUlBandwidth)
721 {
722 maxContinuousUlBandwidth = tmpMinBandwidth;
723 ffrRbStartOffset = tmpFfrRbStartOffset;
724 }
725 tmpMinBandwidth = 0;
726 }
727 else
728 {
729 if (tmpMinBandwidth == 0)
730 {
731 tmpFfrRbStartOffset = index;
732 }
733 tmpMinBandwidth++;
734 }
735 index++;
736 }
737
738 if (tmpMinBandwidth > maxContinuousUlBandwidth)
739 {
740 maxContinuousUlBandwidth = tmpMinBandwidth;
741 ffrRbStartOffset = tmpFfrRbStartOffset;
742 }
743
745 uint16_t rbStart = 0;
746 rbStart = ffrRbStartOffset;
747 std::vector<struct RachListElement_s>::iterator itRach;
748 for (itRach = m_rachList.begin(); itRach != m_rachList.end(); itRach++)
749 {
751 (*itRach).m_estimatedSize,
752 " Default UL Grant MCS does not allow to send RACH messages");
754 newRar.m_rnti = (*itRach).m_rnti;
755 // DL-RACH Allocation
756 // Ideal: no needs of configuring m_dci
757 // UL-RACH Allocation
758 newRar.m_grant.m_rnti = newRar.m_rnti;
759 newRar.m_grant.m_mcs = m_ulGrantMcs;
760 uint16_t rbLen = 1;
761 uint16_t tbSizeBits = 0;
762 // find lowest TB size that fits UL grant estimated size
763 while ((tbSizeBits < (*itRach).m_estimatedSize) &&
764 (rbStart + rbLen < (ffrRbStartOffset + maxContinuousUlBandwidth)))
765 {
766 rbLen++;
767 tbSizeBits = m_amc->GetUlTbSizeFromMcs(m_ulGrantMcs, rbLen);
768 }
769 if (tbSizeBits < (*itRach).m_estimatedSize)
770 {
771 // no more allocation space: finish allocation
772 break;
773 }
774 newRar.m_grant.m_rbStart = rbStart;
775 newRar.m_grant.m_rbLen = rbLen;
776 newRar.m_grant.m_tbSize = tbSizeBits / 8;
777 newRar.m_grant.m_hopping = false;
778 newRar.m_grant.m_tpc = 0;
779 newRar.m_grant.m_cqiRequest = false;
780 newRar.m_grant.m_ulDelay = false;
781 NS_LOG_INFO(this << " UL grant allocated to RNTI " << (*itRach).m_rnti << " rbStart "
782 << rbStart << " rbLen " << rbLen << " MCS " << m_ulGrantMcs << " tbSize "
783 << newRar.m_grant.m_tbSize);
784 for (uint16_t i = rbStart; i < rbStart + rbLen; i++)
785 {
786 m_rachAllocationMap.at(i) = (*itRach).m_rnti;
787 }
788
789 if (m_harqOn == true)
790 {
791 // generate UL-DCI for HARQ retransmissions
792 UlDciListElement_s uldci;
793 uldci.m_rnti = newRar.m_rnti;
794 uldci.m_rbLen = rbLen;
795 uldci.m_rbStart = rbStart;
796 uldci.m_mcs = m_ulGrantMcs;
797 uldci.m_tbSize = tbSizeBits / 8;
798 uldci.m_ndi = 1;
799 uldci.m_cceIndex = 0;
800 uldci.m_aggrLevel = 1;
801 uldci.m_ueTxAntennaSelection = 3; // antenna selection OFF
802 uldci.m_hopping = false;
803 uldci.m_n2Dmrs = 0;
804 uldci.m_tpc = 0; // no power control
805 uldci.m_cqiRequest = false; // only period CQI at this stage
806 uldci.m_ulIndex = 0; // TDD parameter
807 uldci.m_dai = 1; // TDD parameter
808 uldci.m_freqHopping = 0;
809 uldci.m_pdcchPowerOffset = 0; // not used
810
811 uint8_t harqId = 0;
812 std::map<uint16_t, uint8_t>::iterator itProcId;
813 itProcId = m_ulHarqCurrentProcessId.find(uldci.m_rnti);
814 if (itProcId == m_ulHarqCurrentProcessId.end())
815 {
816 NS_FATAL_ERROR("No info find in HARQ buffer for UE " << uldci.m_rnti);
817 }
818 harqId = (*itProcId).second;
819 std::map<uint16_t, UlHarqProcessesDciBuffer_t>::iterator itDci =
821 if (itDci == m_ulHarqProcessesDciBuffer.end())
822 {
823 NS_FATAL_ERROR("Unable to find RNTI entry in UL DCI HARQ buffer for RNTI "
824 << uldci.m_rnti);
825 }
826 (*itDci).second.at(harqId) = uldci;
827 }
828
829 rbStart = rbStart + rbLen;
830 ret.m_buildRarList.push_back(newRar);
831 }
832 m_rachList.clear();
833
834 // Process DL HARQ feedback
836 // retrieve past HARQ retx buffered
837 if (!m_dlInfoListBuffered.empty())
838 {
839 if (!params.m_dlInfoList.empty())
840 {
841 NS_LOG_INFO(this << " Received DL-HARQ feedback");
843 params.m_dlInfoList.begin(),
844 params.m_dlInfoList.end());
845 }
846 }
847 else
848 {
849 if (!params.m_dlInfoList.empty())
850 {
851 m_dlInfoListBuffered = params.m_dlInfoList;
852 }
853 }
854 if (m_harqOn == false)
855 {
856 // Ignore HARQ feedback
857 m_dlInfoListBuffered.clear();
858 }
859 std::vector<struct DlInfoListElement_s> dlInfoListUntxed;
860 for (std::size_t i = 0; i < m_dlInfoListBuffered.size(); i++)
861 {
862 std::set<uint16_t>::iterator itRnti = rntiAllocated.find(m_dlInfoListBuffered.at(i).m_rnti);
863 if (itRnti != rntiAllocated.end())
864 {
865 // RNTI already allocated for retx
866 continue;
867 }
868 auto nLayers = m_dlInfoListBuffered.at(i).m_harqStatus.size();
869 std::vector<bool> retx;
870 NS_LOG_INFO(this << " Processing DLHARQ feedback");
871 if (nLayers == 1)
872 {
873 retx.push_back(m_dlInfoListBuffered.at(i).m_harqStatus.at(0) ==
875 retx.push_back(false);
876 }
877 else
878 {
879 retx.push_back(m_dlInfoListBuffered.at(i).m_harqStatus.at(0) ==
881 retx.push_back(m_dlInfoListBuffered.at(i).m_harqStatus.at(1) ==
883 }
884 if (retx.at(0) || retx.at(1))
885 {
886 // retrieve HARQ process information
887 uint16_t rnti = m_dlInfoListBuffered.at(i).m_rnti;
888 uint8_t harqId = m_dlInfoListBuffered.at(i).m_harqProcessId;
889 NS_LOG_INFO(this << " HARQ retx RNTI " << rnti << " harqId " << (uint16_t)harqId);
890 std::map<uint16_t, DlHarqProcessesDciBuffer_t>::iterator itHarq =
892 if (itHarq == m_dlHarqProcessesDciBuffer.end())
893 {
894 NS_FATAL_ERROR("No info find in HARQ buffer for UE " << rnti);
895 }
896
897 DlDciListElement_s dci = (*itHarq).second.at(harqId);
898 int rv = 0;
899 if (dci.m_rv.size() == 1)
900 {
901 rv = dci.m_rv.at(0);
902 }
903 else
904 {
905 rv = (dci.m_rv.at(0) > dci.m_rv.at(1) ? dci.m_rv.at(0) : dci.m_rv.at(1));
906 }
907
908 if (rv == 3)
909 {
910 // maximum number of retx reached -> drop process
911 NS_LOG_INFO("Maximum number of retransmissions reached -> drop process");
912 std::map<uint16_t, DlHarqProcessesStatus_t>::iterator it =
913 m_dlHarqProcessesStatus.find(rnti);
914 if (it == m_dlHarqProcessesStatus.end())
915 {
916 NS_LOG_ERROR("No info find in HARQ buffer for UE (might change eNB) "
917 << m_dlInfoListBuffered.at(i).m_rnti);
918 }
919 (*it).second.at(harqId) = 0;
920 std::map<uint16_t, DlHarqRlcPduListBuffer_t>::iterator itRlcPdu =
922 if (itRlcPdu == m_dlHarqProcessesRlcPduListBuffer.end())
923 {
924 NS_FATAL_ERROR("Unable to find RlcPdcList in HARQ buffer for RNTI "
925 << m_dlInfoListBuffered.at(i).m_rnti);
926 }
927 for (std::size_t k = 0; k < (*itRlcPdu).second.size(); k++)
928 {
929 (*itRlcPdu).second.at(k).at(harqId).clear();
930 }
931 continue;
932 }
933 // check the feasibility of retransmitting on the same RBGs
934 // translate the DCI to Spectrum framework
935 std::vector<int> dciRbg;
936 uint32_t mask = 0x1;
937 NS_LOG_INFO("Original RBGs " << dci.m_rbBitmap << " rnti " << dci.m_rnti);
938 for (int j = 0; j < 32; j++)
939 {
940 if (((dci.m_rbBitmap & mask) >> j) == 1)
941 {
942 dciRbg.push_back(j);
943 NS_LOG_INFO("\t" << j);
944 }
945 mask = (mask << 1);
946 }
947 bool free = true;
948 for (std::size_t j = 0; j < dciRbg.size(); j++)
949 {
950 if (rbgMap.at(dciRbg.at(j)) == true)
951 {
952 free = false;
953 break;
954 }
955 }
956 if (free)
957 {
958 // use the same RBGs for the retx
959 // reserve RBGs
960 for (std::size_t j = 0; j < dciRbg.size(); j++)
961 {
962 rbgMap.at(dciRbg.at(j)) = true;
963 NS_LOG_INFO("RBG " << dciRbg.at(j) << " assigned");
964 rbgAllocatedNum++;
965 }
966
967 NS_LOG_INFO(this << " Send retx in the same RBGs");
968 }
969 else
970 {
971 // find RBGs for sending HARQ retx
972 uint8_t j = 0;
973 uint8_t rbgId = (dciRbg.at(dciRbg.size() - 1) + 1) % numberOfRBGs;
974 uint8_t startRbg = dciRbg.at(dciRbg.size() - 1);
975 std::vector<bool> rbgMapCopy = rbgMap;
976 while ((j < dciRbg.size()) && (startRbg != rbgId))
977 {
978 if (rbgMapCopy.at(rbgId) == false)
979 {
980 rbgMapCopy.at(rbgId) = true;
981 dciRbg.at(j) = rbgId;
982 j++;
983 }
984 rbgId = (rbgId + 1) % numberOfRBGs;
985 }
986 if (j == dciRbg.size())
987 {
988 // find new RBGs -> update DCI map
989 uint32_t rbgMask = 0;
990 for (std::size_t k = 0; k < dciRbg.size(); k++)
991 {
992 rbgMask = rbgMask + (0x1 << dciRbg.at(k));
993 rbgAllocatedNum++;
994 }
995 dci.m_rbBitmap = rbgMask;
996 rbgMap = rbgMapCopy;
997 NS_LOG_INFO(this << " Move retx in RBGs " << dciRbg.size());
998 }
999 else
1000 {
1001 // HARQ retx cannot be performed on this TTI -> store it
1002 dlInfoListUntxed.push_back(m_dlInfoListBuffered.at(i));
1003 NS_LOG_INFO(this << " No resource for this retx -> buffer it");
1004 }
1005 }
1006 // retrieve RLC PDU list for retx TBsize and update DCI
1008 std::map<uint16_t, DlHarqRlcPduListBuffer_t>::iterator itRlcPdu =
1010 if (itRlcPdu == m_dlHarqProcessesRlcPduListBuffer.end())
1011 {
1012 NS_FATAL_ERROR("Unable to find RlcPdcList in HARQ buffer for RNTI " << rnti);
1013 }
1014 for (std::size_t j = 0; j < nLayers; j++)
1015 {
1016 if (retx.at(j))
1017 {
1018 if (j >= dci.m_ndi.size())
1019 {
1020 // for avoiding errors in MIMO transient phases
1021 dci.m_ndi.push_back(0);
1022 dci.m_rv.push_back(0);
1023 dci.m_mcs.push_back(0);
1024 dci.m_tbsSize.push_back(0);
1025 NS_LOG_INFO(this << " layer " << (uint16_t)j
1026 << " no txed (MIMO transition)");
1027 }
1028 else
1029 {
1030 dci.m_ndi.at(j) = 0;
1031 dci.m_rv.at(j)++;
1032 (*itHarq).second.at(harqId).m_rv.at(j)++;
1033 NS_LOG_INFO(this << " layer " << (uint16_t)j << " RV "
1034 << (uint16_t)dci.m_rv.at(j));
1035 }
1036 }
1037 else
1038 {
1039 // empty TB of layer j
1040 dci.m_ndi.at(j) = 0;
1041 dci.m_rv.at(j) = 0;
1042 dci.m_mcs.at(j) = 0;
1043 dci.m_tbsSize.at(j) = 0;
1044 NS_LOG_INFO(this << " layer " << (uint16_t)j << " no retx");
1045 }
1046 }
1047 for (std::size_t k = 0; k < (*itRlcPdu).second.at(0).at(dci.m_harqProcess).size(); k++)
1048 {
1049 std::vector<struct RlcPduListElement_s> rlcPduListPerLc;
1050 for (std::size_t j = 0; j < nLayers; j++)
1051 {
1052 if (retx.at(j))
1053 {
1054 if (j < dci.m_ndi.size())
1055 {
1056 NS_LOG_INFO(" layer " << (uint16_t)j << " tb size "
1057 << dci.m_tbsSize.at(j));
1058 rlcPduListPerLc.push_back(
1059 (*itRlcPdu).second.at(j).at(dci.m_harqProcess).at(k));
1060 }
1061 }
1062 else
1063 { // if no retx needed on layer j, push an RlcPduListElement_s object with
1064 // m_size=0 to keep the size of rlcPduListPerLc vector = 2 in case of MIMO
1065 NS_LOG_INFO(" layer " << (uint16_t)j << " tb size " << dci.m_tbsSize.at(j));
1066 RlcPduListElement_s emptyElement;
1067 emptyElement.m_logicalChannelIdentity = (*itRlcPdu)
1068 .second.at(j)
1069 .at(dci.m_harqProcess)
1070 .at(k)
1071 .m_logicalChannelIdentity;
1072 emptyElement.m_size = 0;
1073 rlcPduListPerLc.push_back(emptyElement);
1074 }
1075 }
1076
1077 if (!rlcPduListPerLc.empty())
1078 {
1079 newEl.m_rlcPduList.push_back(rlcPduListPerLc);
1080 }
1081 }
1082 newEl.m_rnti = rnti;
1083 newEl.m_dci = dci;
1084 (*itHarq).second.at(harqId).m_rv = dci.m_rv;
1085 // refresh timer
1086 std::map<uint16_t, DlHarqProcessesTimer_t>::iterator itHarqTimer =
1087 m_dlHarqProcessesTimer.find(rnti);
1088 if (itHarqTimer == m_dlHarqProcessesTimer.end())
1089 {
1090 NS_FATAL_ERROR("Unable to find HARQ timer for RNTI " << (uint16_t)rnti);
1091 }
1092 (*itHarqTimer).second.at(harqId) = 0;
1093 ret.m_buildDataList.push_back(newEl);
1094 rntiAllocated.insert(rnti);
1095 }
1096 else
1097 {
1098 // update HARQ process status
1099 NS_LOG_INFO(this << " HARQ received ACK for UE " << m_dlInfoListBuffered.at(i).m_rnti);
1100 std::map<uint16_t, DlHarqProcessesStatus_t>::iterator it =
1102 if (it == m_dlHarqProcessesStatus.end())
1103 {
1104 NS_FATAL_ERROR("No info find in HARQ buffer for UE "
1105 << m_dlInfoListBuffered.at(i).m_rnti);
1106 }
1107 (*it).second.at(m_dlInfoListBuffered.at(i).m_harqProcessId) = 0;
1108 std::map<uint16_t, DlHarqRlcPduListBuffer_t>::iterator itRlcPdu =
1110 if (itRlcPdu == m_dlHarqProcessesRlcPduListBuffer.end())
1111 {
1112 NS_FATAL_ERROR("Unable to find RlcPdcList in HARQ buffer for RNTI "
1113 << m_dlInfoListBuffered.at(i).m_rnti);
1114 }
1115 for (std::size_t k = 0; k < (*itRlcPdu).second.size(); k++)
1116 {
1117 (*itRlcPdu).second.at(k).at(m_dlInfoListBuffered.at(i).m_harqProcessId).clear();
1118 }
1119 }
1120 }
1121 m_dlInfoListBuffered.clear();
1122 m_dlInfoListBuffered = dlInfoListUntxed;
1123
1124 if (rbgAllocatedNum == numberOfRBGs)
1125 {
1126 // all the RBGs are already allocated -> exit
1127 if (!ret.m_buildDataList.empty() || !ret.m_buildRarList.empty())
1128 {
1130 }
1131 return;
1132 }
1133
1134 std::map<LteFlowId_t, struct LogicalChannelConfigListElement_s>::iterator itLogicalChannels;
1135
1136 for (itLogicalChannels = m_ueLogicalChannelsConfigList.begin();
1137 itLogicalChannels != m_ueLogicalChannelsConfigList.end();
1138 itLogicalChannels++)
1139 {
1140 std::set<uint16_t>::iterator itRnti = rntiAllocated.find(itLogicalChannels->first.m_rnti);
1141 if ((itRnti != rntiAllocated.end()) ||
1142 (!HarqProcessAvailability(itLogicalChannels->first.m_rnti)))
1143 {
1144 // UE already allocated for HARQ or without HARQ process available -> drop it
1145 if (itRnti != rntiAllocated.end())
1146 {
1147 NS_LOG_DEBUG(this << " RNTI discarded for HARQ tx"
1148 << (uint16_t)(itLogicalChannels->first.m_rnti));
1149 }
1150 if (!HarqProcessAvailability(itLogicalChannels->first.m_rnti))
1151 {
1152 NS_LOG_DEBUG(this << " RNTI discarded for HARQ id"
1153 << (uint16_t)(itLogicalChannels->first.m_rnti));
1154 }
1155 continue;
1156 }
1157
1158 std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator
1159 itRlcBufferReq = m_rlcBufferReq.find(itLogicalChannels->first);
1160 if (itRlcBufferReq == m_rlcBufferReq.end())
1161 {
1162 continue;
1163 }
1164
1165 int group = -1;
1166 int delay = 0;
1167
1168 if (itRlcBufferReq->second.m_rlcRetransmissionQueueSize > 0)
1169 {
1170 delay = itRlcBufferReq->second.m_rlcRetransmissionHolDelay;
1171 group = delay / grouping_parameter;
1172 }
1173 else if (itRlcBufferReq->second.m_rlcTransmissionQueueSize > 0)
1174 {
1175 delay = itRlcBufferReq->second.m_rlcTransmissionQueueHolDelay;
1176 group = delay / grouping_parameter;
1177 }
1178 else
1179 {
1180 continue;
1181 }
1182
1183 UEtoHOL.insert(std::pair<LteFlowId_t, int>(itLogicalChannels->first, delay));
1184
1185 if (itLogicalChannels->second.m_qosBearerType == itLogicalChannels->second.QBT_NON_GBR)
1186 {
1187 if (map_nonGBRHOLgroupToUE.count(group) == 0)
1188 {
1189 std::set<LteFlowId_t> v;
1190 v.insert(itRlcBufferReq->first);
1191 map_nonGBRHOLgroupToUE.insert(std::pair<int, std::set<LteFlowId_t>>(group, v));
1192 }
1193 else
1194 {
1195 map_nonGBRHOLgroupToUE.find(group)->second.insert(itRlcBufferReq->first);
1196 }
1197 }
1198 else if (itLogicalChannels->second.m_qosBearerType == itLogicalChannels->second.QBT_GBR)
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) == false)
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)) == false)
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<struct 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<struct 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 == true)
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 == true)
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) == true)
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 == true)
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) == true)
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) == true)
2129 {
2130 free = false;
2131 break;
2132 }
2133 if ((m_ffrSapProvider->IsUlRbgAvailableForUe(j, (*it).first)) == false)
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 == true)
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.
void DoSchedUlSrInfoReq(const struct FfMacSchedSapProvider::SchedUlSrInfoReqParameters &params)
Sched UL Sr Info Request.
int GetRbgSize(int dlbandwidth)
Get RGB Size.
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.
void DoCschedCellConfigReq(const struct FfMacCschedSapProvider::CschedCellConfigReqParameters &params)
Csched Cell Config Request.
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.
~CqaFfMacScheduler() override
Destructor.
void DoSchedDlTriggerReq(const struct FfMacSchedSapProvider::SchedDlTriggerReqParameters &params)
Sched DL RLC Buffer Request.
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 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.
void DoSchedUlNoiseInterferenceReq(const struct FfMacSchedSapProvider::SchedUlNoiseInterferenceReqParameters &params)
Sched UL Noise InterferenceRequest.
std::map< uint16_t, DlHarqProcessesDciBuffer_t > m_dlHarqProcessesDciBuffer
DL HARQ process DCI buffer.
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.
void DoSchedDlCqiInfoReq(const struct FfMacSchedSapProvider::SchedDlCqiInfoReqParameters &params)
Sched DL CGI Info 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 DoCschedLcConfigReq(const struct FfMacCschedSapProvider::CschedLcConfigReqParameters &params)
Csched LC Config Request.
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 DoSchedDlRachInfoReq(const struct FfMacSchedSapProvider::SchedDlRachInfoReqParameters &params)
Sched DL RACH Info Request.
std::map< uint16_t, uint8_t > m_uesTxMode
txMode of the UEs
std::map< LteFlowId_t, struct LogicalChannelConfigListElement_s > m_ueLogicalChannelsConfigList
Map of UE logical channel config list.
std::vector< uint16_t > m_rachAllocationMap
RACH allocation map.
void DoCschedUeConfigReq(const struct FfMacCschedSapProvider::CschedUeConfigReqParameters &params)
Csched UE Config Request.
std::vector< struct RachListElement_s > m_rachList
RACH list.
void SetFfMacSchedSapUser(FfMacSchedSapUser *s) override
set the user part of the FfMacSchedSap that this Scheduler will interact with.
void DoSchedUlTriggerReq(const struct FfMacSchedSapProvider::SchedUlTriggerReqParameters &params)
Sched UL Trigger Request.
std::map< uint16_t, uint8_t > m_p10CqiRxed
Map of UE's DL CQI P01 received.
void DoDispose() override
Destructor implementation.
void DoSchedDlPagingBufferReq(const struct FfMacSchedSapProvider::SchedDlPagingBufferReqParameters &params)
Sched DL Paging Buffer Request.
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 DoSchedUlCqiInfoReq(const struct FfMacSchedSapProvider::SchedUlCqiInfoReqParameters &params)
Sched UL CGI 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 DoSchedDlMacBufferReq(const struct FfMacSchedSapProvider::SchedDlMacBufferReqParameters &params)
Sched DL MAC Buffer Request.
std::vector< DlInfoListElement_s > m_dlInfoListBuffered
DL HARQ retx buffered.
void DoCschedUeReleaseReq(const struct 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 DoSchedUlMacCtrlInfoReq(const struct FfMacSchedSapProvider::SchedUlMacCtrlInfoReqParameters &params)
Sched UL MAC Control Info 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.
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.
void DoSchedDlRlcBufferReq(const struct FfMacSchedSapProvider::SchedDlRlcBufferReqParameters &params)
Sched DL RLC Buffer Request.
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.
void DoCschedLcReleaseReq(const struct FfMacCschedSapProvider::CschedLcReleaseReqParameters &params)
Csched LC Release Request.
bool m_harqOn
m_harqOn when false inhibit the HARQ mechanisms (by default active)
void TransmissionModeConfigurationUpdate(uint16_t rnti, uint8_t txMode)
Trans mode config update.
Provides the CSCHED SAP.
FfMacCschedSapUser class.
virtual void CschedUeConfigUpdateInd(const struct CschedUeConfigUpdateIndParameters &params)=0
CSCHED_UE_UPDATE_IND.
virtual void CschedUeConfigCnf(const struct CschedUeConfigCnfParameters &params)=0
CSCHED_UE_CONFIG_CNF.
Provides the SCHED SAP.
FfMacSchedSapUser class.
virtual void SchedUlConfigInd(const struct SchedUlConfigIndParameters &params)=0
SCHED_UL_CONFIG_IND.
virtual void SchedDlConfigInd(const struct 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:41
virtual uint8_t GetTpc(uint16_t rnti)=0
GetTpc.
virtual void ReportUlCqiInfo(const struct FfMacSchedSapProvider::SchedUlCqiInfoReqParameters &params)=0
ReportUlCqiInfo.
virtual std::vector< bool > GetAvailableUlRbg()=0
Get vector of available RB in UL for this Cell.
virtual bool IsUlRbgAvailableForUe(int i, uint16_t rnti)=0
Check if UE can be served on i-th RB in UL.
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.
virtual void ReportDlCqiInfo(const struct FfMacSchedSapProvider::SchedDlCqiInfoReqParameters &params)=0
ReportDlCqiInfo.
Service Access Point (SAP) offered by the eNodeB RRC instance to the Frequency Reuse algorithm instan...
Definition: lte-ffr-sap.h:141
Template for the implementation of the LteFfrSapUser as a member of an owner class of type C to which...
Definition: lte-ffr-sap.h:262
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:60
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:935
Hold an unsigned integer type.
Definition: uinteger.h:45
#define NO_SINR
#define HARQ_PROC_NUM
#define HARQ_DL_TIMEOUT
#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.
std::vector< UlDciListElement_s > UlHarqProcessesDciBuffer_t
UL HARQ process DCI buffer vector.
bool CqaKeyDescComparator(uint16_t key1, uint16_t key2)
CQA key comparator.
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.
std::vector< uint8_t > DlHarqProcessesTimer_t
DL HARQ process timer vector typedef.
int HOL_group
HOL group typedef.
std::vector< uint8_t > DlHarqProcessesStatus_t
DL HARQ process status vector typedef.
std::vector< RlcPduList_t > DlHarqRlcPduListBuffer_t
vector of the 8 HARQ processes per UE
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.
@ SUCCESS
Definition: ff-mac-common.h:62
std::map< HOL_group, t_map_RBGToCQIsSorted >::iterator t_it_HOLGroupToRBGs
HOL group map iterator typedef.
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.
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::map< RBG_index, t_map_CQIToUE > t_map_RBGToCQIsSorted
RBG index map typedef.
uint8_t CQI_value
CQI value typedef.
std::vector< DlDciListElement_s > DlHarqProcessesDciBuffer_t
DL HARQ process DCI buffer vector typedef.
std::vector< uint8_t > UlHarqProcessesStatus_t
UL HARQ process status vector.
bool CqaGroupDescComparator(int key1, int key2)
CGA group comparator function.
See section 4.3.8 builDataListElement.
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.
uint8_t m_nrOfPdcchOfdmSymbols
number of PDCCH OFDM symbols
std::vector< struct BuildDataListElement_s > m_buildDataList
build data list
std::vector< struct BuildRarListElement_s > m_buildRarList
build rar list
Parameters of the SCHED_UL_CONFIG_IND primitive.
std::vector< struct 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:37
uint8_t m_lcId
LCID.
Definition: lte-common.h:39
uint16_t m_rnti
RNTI.
Definition: lte-common.h:38
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.