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