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