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