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