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