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