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