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