A Discrete-Event Network Simulator
API
tdtbfq-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("TdTbfqFfMacScheduler");
40 
42 static const int TdTbfqType0AllocationRbg[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(TdTbfqFfMacScheduler);
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::TdTbfqFfMacScheduler")
91  .SetGroupName("Lte")
92  .AddConstructor<TdTbfqFfMacScheduler>()
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[params.m_rnti] = params.m_transmissionMode;
191  // generate HARQ buffers
192  m_dlHarqCurrentProcessId[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[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 
238  tdtbfqsFlowPerf_t flowStatsDl;
239  flowStatsDl.flowStart = Simulator::Now();
240  flowStatsDl.packetArrivalRate = 0;
241  flowStatsDl.tokenGenerationRate = mbrDlInBytes;
242  flowStatsDl.tokenPoolSize = 0;
243  flowStatsDl.maxTokenPoolSize = m_tokenPoolSize;
244  flowStatsDl.counter = 0;
245  flowStatsDl.burstCredit = m_creditLimit; // bytes
246  flowStatsDl.debtLimit = m_debtLimit; // bytes
248  m_flowStatsDl[params.m_rnti] = flowStatsDl;
249  tdtbfqsFlowPerf_t flowStatsUl;
250  flowStatsUl.flowStart = Simulator::Now();
251  flowStatsUl.packetArrivalRate = 0;
252  flowStatsUl.tokenGenerationRate = mbrUlInBytes;
253  flowStatsUl.tokenPoolSize = 0;
254  flowStatsUl.maxTokenPoolSize = m_tokenPoolSize;
255  flowStatsUl.counter = 0;
256  flowStatsUl.burstCredit = m_creditLimit; // bytes
257  flowStatsUl.debtLimit = m_debtLimit; // bytes
259  m_flowStatsUl[params.m_rnti] = flowStatsUl;
260  }
261  else
262  {
263  // update MBR and GBR from UeManager::SetupDataRadioBearer ()
264  uint64_t mbrDlInBytes =
265  params.m_logicalChannelConfigList.at(i).m_eRabMaximulBitrateDl / 8; // byte/s
266  uint64_t mbrUlInBytes =
267  params.m_logicalChannelConfigList.at(i).m_eRabMaximulBitrateUl / 8; // byte/s
268  m_flowStatsDl[(*it).first].tokenGenerationRate = mbrDlInBytes;
269  m_flowStatsUl[(*it).first].tokenGenerationRate = mbrUlInBytes;
270  }
271  }
272 }
273 
274 void
277 {
278  NS_LOG_FUNCTION(this);
279  for (std::size_t i = 0; i < params.m_logicalChannelIdentity.size(); i++)
280  {
281  auto it = m_rlcBufferReq.begin();
282  while (it != m_rlcBufferReq.end())
283  {
284  if (((*it).first.m_rnti == params.m_rnti) &&
285  ((*it).first.m_lcId == params.m_logicalChannelIdentity.at(i)))
286  {
287  auto temp = it;
288  it++;
289  m_rlcBufferReq.erase(temp);
290  }
291  else
292  {
293  it++;
294  }
295  }
296  }
297 }
298 
299 void
302 {
303  NS_LOG_FUNCTION(this);
304 
305  m_uesTxMode.erase(params.m_rnti);
306  m_dlHarqCurrentProcessId.erase(params.m_rnti);
307  m_dlHarqProcessesStatus.erase(params.m_rnti);
308  m_dlHarqProcessesTimer.erase(params.m_rnti);
309  m_dlHarqProcessesDciBuffer.erase(params.m_rnti);
311  m_ulHarqCurrentProcessId.erase(params.m_rnti);
312  m_ulHarqProcessesStatus.erase(params.m_rnti);
313  m_ulHarqProcessesDciBuffer.erase(params.m_rnti);
314  m_flowStatsDl.erase(params.m_rnti);
315  m_flowStatsUl.erase(params.m_rnti);
316  m_ceBsrRxed.erase(params.m_rnti);
317  auto it = m_rlcBufferReq.begin();
318  while (it != m_rlcBufferReq.end())
319  {
320  if ((*it).first.m_rnti == params.m_rnti)
321  {
322  auto temp = it;
323  it++;
324  m_rlcBufferReq.erase(temp);
325  }
326  else
327  {
328  it++;
329  }
330  }
331  if (m_nextRntiUl == params.m_rnti)
332  {
333  m_nextRntiUl = 0;
334  }
335 }
336 
337 void
340 {
341  NS_LOG_FUNCTION(this << params.m_rnti << (uint32_t)params.m_logicalChannelIdentity);
342  // API generated by RLC for updating RLC parameters on a LC (tx and retx queues)
343 
344  LteFlowId_t flow(params.m_rnti, params.m_logicalChannelIdentity);
345 
346  auto it = m_rlcBufferReq.find(flow);
347 
348  if (it == m_rlcBufferReq.end())
349  {
350  m_rlcBufferReq[flow] = params;
351  }
352  else
353  {
354  (*it).second = params;
355  }
356 }
357 
358 void
361 {
362  NS_LOG_FUNCTION(this);
363  NS_FATAL_ERROR("method not implemented");
364 }
365 
366 void
369 {
370  NS_LOG_FUNCTION(this);
371  NS_FATAL_ERROR("method not implemented");
372 }
373 
374 int
376 {
377  for (int i = 0; i < 4; i++)
378  {
379  if (dlbandwidth < TdTbfqType0AllocationRbg[i])
380  {
381  return i + 1;
382  }
383  }
384 
385  return -1;
386 }
387 
388 unsigned int
390 {
391  unsigned int lcActive = 0;
392  for (auto it = m_rlcBufferReq.begin(); it != m_rlcBufferReq.end(); it++)
393  {
394  if (((*it).first.m_rnti == rnti) && (((*it).second.m_rlcTransmissionQueueSize > 0) ||
395  ((*it).second.m_rlcRetransmissionQueueSize > 0) ||
396  ((*it).second.m_rlcStatusPduSize > 0)))
397  {
398  lcActive++;
399  }
400  if ((*it).first.m_rnti > rnti)
401  {
402  break;
403  }
404  }
405  return lcActive;
406 }
407 
408 bool
410 {
411  NS_LOG_FUNCTION(this << rnti);
412 
413  auto it = m_dlHarqCurrentProcessId.find(rnti);
414  if (it == m_dlHarqCurrentProcessId.end())
415  {
416  NS_FATAL_ERROR("No Process Id found for this RNTI " << rnti);
417  }
418  auto itStat = m_dlHarqProcessesStatus.find(rnti);
419  if (itStat == m_dlHarqProcessesStatus.end())
420  {
421  NS_FATAL_ERROR("No Process Id Statusfound for this RNTI " << rnti);
422  }
423  uint8_t i = (*it).second;
424  do
425  {
426  i = (i + 1) % HARQ_PROC_NUM;
427  } while (((*itStat).second.at(i) != 0) && (i != (*it).second));
428 
429  return (*itStat).second.at(i) == 0;
430 }
431 
432 uint8_t
434 {
435  NS_LOG_FUNCTION(this << rnti);
436 
437  if (!m_harqOn)
438  {
439  return 0;
440  }
441 
442  auto it = m_dlHarqCurrentProcessId.find(rnti);
443  if (it == m_dlHarqCurrentProcessId.end())
444  {
445  NS_FATAL_ERROR("No Process Id found for this RNTI " << rnti);
446  }
447  auto itStat = m_dlHarqProcessesStatus.find(rnti);
448  if (itStat == m_dlHarqProcessesStatus.end())
449  {
450  NS_FATAL_ERROR("No Process Id Statusfound for this RNTI " << rnti);
451  }
452  uint8_t i = (*it).second;
453  do
454  {
455  i = (i + 1) % HARQ_PROC_NUM;
456  } while (((*itStat).second.at(i) != 0) && (i != (*it).second));
457  if ((*itStat).second.at(i) == 0)
458  {
459  (*it).second = i;
460  (*itStat).second.at(i) = 1;
461  }
462  else
463  {
464  NS_FATAL_ERROR("No HARQ process available for RNTI "
465  << rnti << " check before update with HarqProcessAvailability");
466  }
467 
468  return (*it).second;
469 }
470 
471 void
473 {
474  NS_LOG_FUNCTION(this);
475 
476  for (auto itTimers = m_dlHarqProcessesTimer.begin(); itTimers != m_dlHarqProcessesTimer.end();
477  itTimers++)
478  {
479  for (uint16_t i = 0; i < HARQ_PROC_NUM; i++)
480  {
481  if ((*itTimers).second.at(i) == HARQ_DL_TIMEOUT)
482  {
483  // reset HARQ process
484 
485  NS_LOG_DEBUG(this << " Reset HARQ proc " << i << " for RNTI " << (*itTimers).first);
486  auto itStat = m_dlHarqProcessesStatus.find((*itTimers).first);
487  if (itStat == m_dlHarqProcessesStatus.end())
488  {
489  NS_FATAL_ERROR("No Process Id Status found for this RNTI "
490  << (*itTimers).first);
491  }
492  (*itStat).second.at(i) = 0;
493  (*itTimers).second.at(i) = 0;
494  }
495  else
496  {
497  (*itTimers).second.at(i)++;
498  }
499  }
500  }
501 }
502 
503 void
506 {
507  NS_LOG_FUNCTION(this << " Frame no. " << (params.m_sfnSf >> 4) << " subframe no. "
508  << (0xF & params.m_sfnSf));
509  // API generated by RLC for triggering the scheduling of a DL subframe
510 
511  // evaluate the relative channel quality indicator for each UE per each RBG
512  // (since we are using allocation type 0 the small unit of allocation is RBG)
513  // Resource allocation type 0 (see sec 7.1.6.1 of 36.213)
514 
516 
518  int rbgNum = m_cschedCellConfig.m_dlBandwidth / rbgSize;
519  std::map<uint16_t, std::vector<uint16_t>> allocationMap; // RBs map per RNTI
520  std::vector<bool> rbgMap; // global RBGs map
521  uint16_t rbgAllocatedNum = 0;
522  std::set<uint16_t> rntiAllocated;
523  rbgMap.resize(m_cschedCellConfig.m_dlBandwidth / rbgSize, false);
524 
526  for (auto it = rbgMap.begin(); it != rbgMap.end(); it++)
527  {
528  if (*it)
529  {
530  rbgAllocatedNum++;
531  }
532  }
533 
535 
536  // update UL HARQ proc id
537  for (auto itProcId = m_ulHarqCurrentProcessId.begin();
538  itProcId != m_ulHarqCurrentProcessId.end();
539  itProcId++)
540  {
541  (*itProcId).second = ((*itProcId).second + 1) % HARQ_PROC_NUM;
542  }
543 
544  // RACH Allocation
545  std::vector<bool> ulRbMap;
546  ulRbMap.resize(m_cschedCellConfig.m_ulBandwidth, false);
547  ulRbMap = m_ffrSapProvider->GetAvailableUlRbg();
548  uint8_t maxContinuousUlBandwidth = 0;
549  uint8_t tmpMinBandwidth = 0;
550  uint16_t ffrRbStartOffset = 0;
551  uint16_t tmpFfrRbStartOffset = 0;
552  uint16_t index = 0;
553 
554  for (auto it = ulRbMap.begin(); it != ulRbMap.end(); it++)
555  {
556  if (*it)
557  {
558  if (tmpMinBandwidth > maxContinuousUlBandwidth)
559  {
560  maxContinuousUlBandwidth = tmpMinBandwidth;
561  ffrRbStartOffset = tmpFfrRbStartOffset;
562  }
563  tmpMinBandwidth = 0;
564  }
565  else
566  {
567  if (tmpMinBandwidth == 0)
568  {
569  tmpFfrRbStartOffset = index;
570  }
571  tmpMinBandwidth++;
572  }
573  index++;
574  }
575 
576  if (tmpMinBandwidth > maxContinuousUlBandwidth)
577  {
578  maxContinuousUlBandwidth = tmpMinBandwidth;
579  ffrRbStartOffset = tmpFfrRbStartOffset;
580  }
581 
583  uint16_t rbStart = 0;
584  rbStart = ffrRbStartOffset;
585  for (auto itRach = m_rachList.begin(); itRach != m_rachList.end(); itRach++)
586  {
588  (*itRach).m_estimatedSize,
589  " Default UL Grant MCS does not allow to send RACH messages");
590  BuildRarListElement_s newRar;
591  newRar.m_rnti = (*itRach).m_rnti;
592  // DL-RACH Allocation
593  // Ideal: no needs of configuring m_dci
594  // UL-RACH Allocation
595  newRar.m_grant.m_rnti = newRar.m_rnti;
596  newRar.m_grant.m_mcs = m_ulGrantMcs;
597  uint16_t rbLen = 1;
598  uint16_t tbSizeBits = 0;
599  // find lowest TB size that fits UL grant estimated size
600  while ((tbSizeBits < (*itRach).m_estimatedSize) &&
601  (rbStart + rbLen < (ffrRbStartOffset + maxContinuousUlBandwidth)))
602  {
603  rbLen++;
604  tbSizeBits = m_amc->GetUlTbSizeFromMcs(m_ulGrantMcs, rbLen);
605  }
606  if (tbSizeBits < (*itRach).m_estimatedSize)
607  {
608  // no more allocation space: finish allocation
609  break;
610  }
611  newRar.m_grant.m_rbStart = rbStart;
612  newRar.m_grant.m_rbLen = rbLen;
613  newRar.m_grant.m_tbSize = tbSizeBits / 8;
614  newRar.m_grant.m_hopping = false;
615  newRar.m_grant.m_tpc = 0;
616  newRar.m_grant.m_cqiRequest = false;
617  newRar.m_grant.m_ulDelay = false;
618  NS_LOG_INFO(this << " UL grant allocated to RNTI " << (*itRach).m_rnti << " rbStart "
619  << rbStart << " rbLen " << rbLen << " MCS " << m_ulGrantMcs << " tbSize "
620  << newRar.m_grant.m_tbSize);
621  for (uint16_t i = rbStart; i < rbStart + rbLen; i++)
622  {
623  m_rachAllocationMap.at(i) = (*itRach).m_rnti;
624  }
625 
626  if (m_harqOn)
627  {
628  // generate UL-DCI for HARQ retransmissions
629  UlDciListElement_s uldci;
630  uldci.m_rnti = newRar.m_rnti;
631  uldci.m_rbLen = rbLen;
632  uldci.m_rbStart = rbStart;
633  uldci.m_mcs = m_ulGrantMcs;
634  uldci.m_tbSize = tbSizeBits / 8;
635  uldci.m_ndi = 1;
636  uldci.m_cceIndex = 0;
637  uldci.m_aggrLevel = 1;
638  uldci.m_ueTxAntennaSelection = 3; // antenna selection OFF
639  uldci.m_hopping = false;
640  uldci.m_n2Dmrs = 0;
641  uldci.m_tpc = 0; // no power control
642  uldci.m_cqiRequest = false; // only period CQI at this stage
643  uldci.m_ulIndex = 0; // TDD parameter
644  uldci.m_dai = 1; // TDD parameter
645  uldci.m_freqHopping = 0;
646  uldci.m_pdcchPowerOffset = 0; // not used
647 
648  uint8_t harqId = 0;
649  auto itProcId = m_ulHarqCurrentProcessId.find(uldci.m_rnti);
650  if (itProcId == m_ulHarqCurrentProcessId.end())
651  {
652  NS_FATAL_ERROR("No info find in HARQ buffer for UE " << uldci.m_rnti);
653  }
654  harqId = (*itProcId).second;
655  auto itDci = m_ulHarqProcessesDciBuffer.find(uldci.m_rnti);
656  if (itDci == m_ulHarqProcessesDciBuffer.end())
657  {
658  NS_FATAL_ERROR("Unable to find RNTI entry in UL DCI HARQ buffer for RNTI "
659  << uldci.m_rnti);
660  }
661  (*itDci).second.at(harqId) = uldci;
662  }
663 
664  rbStart = rbStart + rbLen;
665  ret.m_buildRarList.push_back(newRar);
666  }
667  m_rachList.clear();
668 
669  // Process DL HARQ feedback
671  // retrieve past HARQ retx buffered
672  if (!m_dlInfoListBuffered.empty())
673  {
674  if (!params.m_dlInfoList.empty())
675  {
676  NS_LOG_INFO(this << " Received DL-HARQ feedback");
678  params.m_dlInfoList.begin(),
679  params.m_dlInfoList.end());
680  }
681  }
682  else
683  {
684  if (!params.m_dlInfoList.empty())
685  {
686  m_dlInfoListBuffered = params.m_dlInfoList;
687  }
688  }
689  if (!m_harqOn)
690  {
691  // Ignore HARQ feedback
692  m_dlInfoListBuffered.clear();
693  }
694  std::vector<DlInfoListElement_s> dlInfoListUntxed;
695  for (std::size_t i = 0; i < m_dlInfoListBuffered.size(); i++)
696  {
697  auto itRnti = rntiAllocated.find(m_dlInfoListBuffered.at(i).m_rnti);
698  if (itRnti != rntiAllocated.end())
699  {
700  // RNTI already allocated for retx
701  continue;
702  }
703  auto nLayers = m_dlInfoListBuffered.at(i).m_harqStatus.size();
704  std::vector<bool> retx;
705  NS_LOG_INFO(this << " Processing DLHARQ feedback");
706  if (nLayers == 1)
707  {
708  retx.push_back(m_dlInfoListBuffered.at(i).m_harqStatus.at(0) ==
710  retx.push_back(false);
711  }
712  else
713  {
714  retx.push_back(m_dlInfoListBuffered.at(i).m_harqStatus.at(0) ==
716  retx.push_back(m_dlInfoListBuffered.at(i).m_harqStatus.at(1) ==
718  }
719  if (retx.at(0) || retx.at(1))
720  {
721  // retrieve HARQ process information
722  uint16_t rnti = m_dlInfoListBuffered.at(i).m_rnti;
723  uint8_t harqId = m_dlInfoListBuffered.at(i).m_harqProcessId;
724  NS_LOG_INFO(this << " HARQ retx RNTI " << rnti << " harqId " << (uint16_t)harqId);
725  auto itHarq = m_dlHarqProcessesDciBuffer.find(rnti);
726  if (itHarq == m_dlHarqProcessesDciBuffer.end())
727  {
728  NS_FATAL_ERROR("No info find in HARQ buffer for UE " << rnti);
729  }
730 
731  DlDciListElement_s dci = (*itHarq).second.at(harqId);
732  int rv = 0;
733  if (dci.m_rv.size() == 1)
734  {
735  rv = dci.m_rv.at(0);
736  }
737  else
738  {
739  rv = (dci.m_rv.at(0) > dci.m_rv.at(1) ? dci.m_rv.at(0) : dci.m_rv.at(1));
740  }
741 
742  if (rv == 3)
743  {
744  // maximum number of retx reached -> drop process
745  NS_LOG_INFO("Maximum number of retransmissions reached -> drop process");
746  auto it = m_dlHarqProcessesStatus.find(rnti);
747  if (it == m_dlHarqProcessesStatus.end())
748  {
749  NS_LOG_ERROR("No info find in HARQ buffer for UE (might change eNB) "
750  << m_dlInfoListBuffered.at(i).m_rnti);
751  }
752  (*it).second.at(harqId) = 0;
753  auto itRlcPdu = m_dlHarqProcessesRlcPduListBuffer.find(rnti);
754  if (itRlcPdu == m_dlHarqProcessesRlcPduListBuffer.end())
755  {
756  NS_FATAL_ERROR("Unable to find RlcPdcList in HARQ buffer for RNTI "
757  << m_dlInfoListBuffered.at(i).m_rnti);
758  }
759  for (std::size_t k = 0; k < (*itRlcPdu).second.size(); k++)
760  {
761  (*itRlcPdu).second.at(k).at(harqId).clear();
762  }
763  continue;
764  }
765  // check the feasibility of retransmitting on the same RBGs
766  // translate the DCI to Spectrum framework
767  std::vector<int> dciRbg;
768  uint32_t mask = 0x1;
769  NS_LOG_INFO("Original RBGs " << dci.m_rbBitmap << " rnti " << dci.m_rnti);
770  for (int j = 0; j < 32; j++)
771  {
772  if (((dci.m_rbBitmap & mask) >> j) == 1)
773  {
774  dciRbg.push_back(j);
775  NS_LOG_INFO("\t" << j);
776  }
777  mask = (mask << 1);
778  }
779  bool free = true;
780  for (std::size_t j = 0; j < dciRbg.size(); j++)
781  {
782  if (rbgMap.at(dciRbg.at(j)))
783  {
784  free = false;
785  break;
786  }
787  }
788  if (free)
789  {
790  // use the same RBGs for the retx
791  // reserve RBGs
792  for (std::size_t j = 0; j < dciRbg.size(); j++)
793  {
794  rbgMap.at(dciRbg.at(j)) = true;
795  NS_LOG_INFO("RBG " << dciRbg.at(j) << " assigned");
796  rbgAllocatedNum++;
797  }
798 
799  NS_LOG_INFO(this << " Send retx in the same RBGs");
800  }
801  else
802  {
803  // find RBGs for sending HARQ retx
804  uint8_t j = 0;
805  uint8_t rbgId = (dciRbg.at(dciRbg.size() - 1) + 1) % rbgNum;
806  uint8_t startRbg = dciRbg.at(dciRbg.size() - 1);
807  std::vector<bool> rbgMapCopy = rbgMap;
808  while ((j < dciRbg.size()) && (startRbg != rbgId))
809  {
810  if (!rbgMapCopy.at(rbgId))
811  {
812  rbgMapCopy.at(rbgId) = true;
813  dciRbg.at(j) = rbgId;
814  j++;
815  }
816  rbgId = (rbgId + 1) % rbgNum;
817  }
818  if (j == dciRbg.size())
819  {
820  // find new RBGs -> update DCI map
821  uint32_t rbgMask = 0;
822  for (std::size_t k = 0; k < dciRbg.size(); k++)
823  {
824  rbgMask = rbgMask + (0x1 << dciRbg.at(k));
825  rbgAllocatedNum++;
826  }
827  dci.m_rbBitmap = rbgMask;
828  rbgMap = rbgMapCopy;
829  NS_LOG_INFO(this << " Move retx in RBGs " << dciRbg.size());
830  }
831  else
832  {
833  // HARQ retx cannot be performed on this TTI -> store it
834  dlInfoListUntxed.push_back(m_dlInfoListBuffered.at(i));
835  NS_LOG_INFO(this << " No resource for this retx -> buffer it");
836  }
837  }
838  // retrieve RLC PDU list for retx TBsize and update DCI
840  auto itRlcPdu = m_dlHarqProcessesRlcPduListBuffer.find(rnti);
841  if (itRlcPdu == m_dlHarqProcessesRlcPduListBuffer.end())
842  {
843  NS_FATAL_ERROR("Unable to find RlcPdcList in HARQ buffer for RNTI " << rnti);
844  }
845  for (std::size_t j = 0; j < nLayers; j++)
846  {
847  if (retx.at(j))
848  {
849  if (j >= dci.m_ndi.size())
850  {
851  // for avoiding errors in MIMO transient phases
852  dci.m_ndi.push_back(0);
853  dci.m_rv.push_back(0);
854  dci.m_mcs.push_back(0);
855  dci.m_tbsSize.push_back(0);
856  NS_LOG_INFO(this << " layer " << (uint16_t)j
857  << " no txed (MIMO transition)");
858  }
859  else
860  {
861  dci.m_ndi.at(j) = 0;
862  dci.m_rv.at(j)++;
863  (*itHarq).second.at(harqId).m_rv.at(j)++;
864  NS_LOG_INFO(this << " layer " << (uint16_t)j << " RV "
865  << (uint16_t)dci.m_rv.at(j));
866  }
867  }
868  else
869  {
870  // empty TB of layer j
871  dci.m_ndi.at(j) = 0;
872  dci.m_rv.at(j) = 0;
873  dci.m_mcs.at(j) = 0;
874  dci.m_tbsSize.at(j) = 0;
875  NS_LOG_INFO(this << " layer " << (uint16_t)j << " no retx");
876  }
877  }
878  for (std::size_t k = 0; k < (*itRlcPdu).second.at(0).at(dci.m_harqProcess).size(); k++)
879  {
880  std::vector<RlcPduListElement_s> rlcPduListPerLc;
881  for (std::size_t j = 0; j < nLayers; j++)
882  {
883  if (retx.at(j))
884  {
885  if (j < dci.m_ndi.size())
886  {
887  NS_LOG_INFO(" layer " << (uint16_t)j << " tb size "
888  << dci.m_tbsSize.at(j));
889  rlcPduListPerLc.push_back(
890  (*itRlcPdu).second.at(j).at(dci.m_harqProcess).at(k));
891  }
892  }
893  else
894  { // if no retx needed on layer j, push an RlcPduListElement_s object with
895  // m_size=0 to keep the size of rlcPduListPerLc vector = 2 in case of MIMO
896  NS_LOG_INFO(" layer " << (uint16_t)j << " tb size " << dci.m_tbsSize.at(j));
897  RlcPduListElement_s emptyElement;
898  emptyElement.m_logicalChannelIdentity = (*itRlcPdu)
899  .second.at(j)
900  .at(dci.m_harqProcess)
901  .at(k)
902  .m_logicalChannelIdentity;
903  emptyElement.m_size = 0;
904  rlcPduListPerLc.push_back(emptyElement);
905  }
906  }
907 
908  if (!rlcPduListPerLc.empty())
909  {
910  newEl.m_rlcPduList.push_back(rlcPduListPerLc);
911  }
912  }
913  newEl.m_rnti = rnti;
914  newEl.m_dci = dci;
915  (*itHarq).second.at(harqId).m_rv = dci.m_rv;
916  // refresh timer
917  auto itHarqTimer = m_dlHarqProcessesTimer.find(rnti);
918  if (itHarqTimer == m_dlHarqProcessesTimer.end())
919  {
920  NS_FATAL_ERROR("Unable to find HARQ timer for RNTI " << (uint16_t)rnti);
921  }
922  (*itHarqTimer).second.at(harqId) = 0;
923  ret.m_buildDataList.push_back(newEl);
924  rntiAllocated.insert(rnti);
925  }
926  else
927  {
928  // update HARQ process status
929  NS_LOG_INFO(this << " HARQ received ACK for UE " << m_dlInfoListBuffered.at(i).m_rnti);
930  auto it = m_dlHarqProcessesStatus.find(m_dlInfoListBuffered.at(i).m_rnti);
931  if (it == m_dlHarqProcessesStatus.end())
932  {
933  NS_FATAL_ERROR("No info find in HARQ buffer for UE "
934  << m_dlInfoListBuffered.at(i).m_rnti);
935  }
936  (*it).second.at(m_dlInfoListBuffered.at(i).m_harqProcessId) = 0;
937  auto itRlcPdu =
939  if (itRlcPdu == m_dlHarqProcessesRlcPduListBuffer.end())
940  {
941  NS_FATAL_ERROR("Unable to find RlcPdcList in HARQ buffer for RNTI "
942  << m_dlInfoListBuffered.at(i).m_rnti);
943  }
944  for (std::size_t k = 0; k < (*itRlcPdu).second.size(); k++)
945  {
946  (*itRlcPdu).second.at(k).at(m_dlInfoListBuffered.at(i).m_harqProcessId).clear();
947  }
948  }
949  }
950  m_dlInfoListBuffered.clear();
951  m_dlInfoListBuffered = dlInfoListUntxed;
952 
953  if (rbgAllocatedNum == rbgNum)
954  {
955  // all the RBGs are already allocated -> exit
956  if (!ret.m_buildDataList.empty() || !ret.m_buildRarList.empty())
957  {
959  }
960  return;
961  }
962 
963  // update token pool, counter and bank size
964  for (auto itStats = m_flowStatsDl.begin(); itStats != m_flowStatsDl.end(); itStats++)
965  {
966  if ((*itStats).second.tokenGenerationRate / 1000 + (*itStats).second.tokenPoolSize >
967  (*itStats).second.maxTokenPoolSize)
968  {
969  (*itStats).second.counter +=
970  (*itStats).second.tokenGenerationRate / 1000 -
971  ((*itStats).second.maxTokenPoolSize - (*itStats).second.tokenPoolSize);
972  (*itStats).second.tokenPoolSize = (*itStats).second.maxTokenPoolSize;
973  bankSize += (*itStats).second.tokenGenerationRate / 1000 -
974  ((*itStats).second.maxTokenPoolSize - (*itStats).second.tokenPoolSize);
975  }
976  else
977  {
978  (*itStats).second.tokenPoolSize += (*itStats).second.tokenGenerationRate / 1000;
979  }
980  }
981 
982  // select UE with largest metric
983  auto itMax = m_flowStatsDl.end();
984  double metricMax = 0.0;
985  bool firstRnti = true;
986  for (auto it = m_flowStatsDl.begin(); it != m_flowStatsDl.end(); it++)
987  {
988  auto itRnti = rntiAllocated.find((*it).first);
989  if ((itRnti != rntiAllocated.end()) || (!HarqProcessAvailability((*it).first)))
990  {
991  // UE already allocated for HARQ or without HARQ process available -> drop it
992  if (itRnti != rntiAllocated.end())
993  {
994  NS_LOG_DEBUG(this << " RNTI discarded for HARQ tx" << (uint16_t)(*it).first);
995  }
996  if (!HarqProcessAvailability((*it).first))
997  {
998  NS_LOG_DEBUG(this << " RNTI discarded for HARQ id" << (uint16_t)(*it).first);
999  }
1000  continue;
1001  }
1002 
1003  // check first the channel conditions for this UE, if CQI!=0
1004  auto itCqi = m_a30CqiRxed.find((*it).first);
1005  auto itTxMode = m_uesTxMode.find((*it).first);
1006  if (itTxMode == m_uesTxMode.end())
1007  {
1008  NS_FATAL_ERROR("No Transmission Mode info on user " << (*it).first);
1009  }
1010  auto nLayer = TransmissionModesLayers::TxMode2LayerNum((*itTxMode).second);
1011 
1012  uint8_t cqiSum = 0;
1013  for (int k = 0; k < rbgNum; k++)
1014  {
1015  for (uint8_t j = 0; j < nLayer; j++)
1016  {
1017  if (itCqi == m_a30CqiRxed.end())
1018  {
1019  cqiSum += 1; // no info on this user -> lowest MCS
1020  }
1021  else
1022  {
1023  cqiSum += (*itCqi).second.m_higherLayerSelected.at(k).m_sbCqi.at(j);
1024  }
1025  }
1026  }
1027 
1028  if (cqiSum == 0)
1029  {
1030  NS_LOG_INFO("Skip this flow, CQI==0, rnti:" << (*it).first);
1031  continue;
1032  }
1033 
1034  /*
1035  if (LcActivePerFlow ((*it).first) == 0)
1036  {
1037  continue;
1038  }
1039  */
1040 
1041  double metric =
1042  (((double)(*it).second.counter) / ((double)(*it).second.tokenGenerationRate));
1043 
1044  if (firstRnti)
1045  {
1046  metricMax = metric;
1047  itMax = it;
1048  firstRnti = false;
1049  continue;
1050  }
1051  if (metric > metricMax)
1052  {
1053  metricMax = metric;
1054  itMax = it;
1055  }
1056  } // end for m_flowStatsDl
1057 
1058  if (itMax == m_flowStatsDl.end())
1059  {
1060  // all UEs are allocated RBG or all UEs already allocated for HARQ or without HARQ process
1061  // available
1062  return;
1063  }
1064  else
1065  {
1066  // assign all RBGs to this UE
1067  std::vector<uint16_t> tempMap;
1068  for (int i = 0; i < rbgNum; i++)
1069  {
1070  if (rbgMap.at(i))
1071  { // this RBG is allocated in RACH procedure
1072  continue;
1073  }
1074 
1075  if (!m_ffrSapProvider->IsDlRbgAvailableForUe(i, (*itMax).first))
1076  {
1077  continue;
1078  }
1079 
1080  tempMap.push_back(i);
1081  rbgMap.at(i) = true;
1082  }
1083  if (!tempMap.empty())
1084  {
1085  allocationMap[(*itMax).first] = tempMap;
1086  }
1087  }
1088 
1089  // generate the transmission opportunities by grouping the RBGs of the same RNTI and
1090  // creating the correspondent DCIs
1091  auto itMap = allocationMap.begin();
1092  while (itMap != allocationMap.end())
1093  {
1094  // create new BuildDataListElement_s for this LC
1095  BuildDataListElement_s newEl;
1096  newEl.m_rnti = (*itMap).first;
1097  // create the DlDciListElement_s
1098  DlDciListElement_s newDci;
1099  newDci.m_rnti = (*itMap).first;
1100  newDci.m_harqProcess = UpdateHarqProcessId((*itMap).first);
1101 
1102  uint16_t lcActives = LcActivePerFlow((*itMap).first);
1103  NS_LOG_INFO(this << "Allocate user " << newEl.m_rnti << " rbg " << lcActives);
1104  if (lcActives == 0)
1105  {
1106  // Set to max value, to avoid divide by 0 below
1107  lcActives = (uint16_t)65535; // UINT16_MAX;
1108  }
1109  uint16_t RgbPerRnti = (*itMap).second.size();
1110  auto itCqi = m_a30CqiRxed.find((*itMap).first);
1111  auto itTxMode = m_uesTxMode.find((*itMap).first);
1112  if (itTxMode == m_uesTxMode.end())
1113  {
1114  NS_FATAL_ERROR("No Transmission Mode info on user " << (*itMap).first);
1115  }
1116  auto nLayer = TransmissionModesLayers::TxMode2LayerNum((*itTxMode).second);
1117  std::vector<uint8_t> worstCqi(2, 15);
1118  if (itCqi != m_a30CqiRxed.end())
1119  {
1120  for (std::size_t k = 0; k < (*itMap).second.size(); k++)
1121  {
1122  if ((*itCqi).second.m_higherLayerSelected.size() > (*itMap).second.at(k))
1123  {
1124  for (uint8_t j = 0; j < nLayer; j++)
1125  {
1126  if ((*itCqi)
1127  .second.m_higherLayerSelected.at((*itMap).second.at(k))
1128  .m_sbCqi.size() > j)
1129  {
1130  if (((*itCqi)
1131  .second.m_higherLayerSelected.at((*itMap).second.at(k))
1132  .m_sbCqi.at(j)) < worstCqi.at(j))
1133  {
1134  worstCqi.at(j) =
1135  ((*itCqi)
1136  .second.m_higherLayerSelected.at((*itMap).second.at(k))
1137  .m_sbCqi.at(j));
1138  }
1139  }
1140  else
1141  {
1142  // no CQI for this layer of this suband -> worst one
1143  worstCqi.at(j) = 1;
1144  }
1145  }
1146  }
1147  else
1148  {
1149  for (uint8_t j = 0; j < nLayer; j++)
1150  {
1151  worstCqi.at(j) = 1; // try with lowest MCS in RBG with no info on channel
1152  }
1153  }
1154  }
1155  }
1156  else
1157  {
1158  for (uint8_t j = 0; j < nLayer; j++)
1159  {
1160  worstCqi.at(j) = 1; // try with lowest MCS in RBG with no info on channel
1161  }
1162  }
1163  uint32_t bytesTxed = 0;
1164  for (uint8_t j = 0; j < nLayer; j++)
1165  {
1166  newDci.m_mcs.push_back(m_amc->GetMcsFromCqi(worstCqi.at(j)));
1167  int tbSize = (m_amc->GetDlTbSizeFromMcs(newDci.m_mcs.at(j), RgbPerRnti * rbgSize) /
1168  8); // (size of TB in bytes according to table 7.1.7.2.1-1 of 36.213)
1169  newDci.m_tbsSize.push_back(tbSize);
1170  bytesTxed += tbSize;
1171  }
1172 
1173  newDci.m_resAlloc = 0; // only allocation type 0 at this stage
1174  newDci.m_rbBitmap = 0; // TBD (32 bit bitmap see 7.1.6 of 36.213)
1175  uint32_t rbgMask = 0;
1176  for (std::size_t k = 0; k < (*itMap).second.size(); k++)
1177  {
1178  rbgMask = rbgMask + (0x1 << (*itMap).second.at(k));
1179  NS_LOG_INFO(this << " Allocated RBG " << (*itMap).second.at(k));
1180  }
1181  newDci.m_rbBitmap = rbgMask; // (32 bit bitmap see 7.1.6 of 36.213)
1182 
1183  // create the rlc PDUs -> equally divide resources among actives LCs
1184  for (auto itBufReq = m_rlcBufferReq.begin(); itBufReq != m_rlcBufferReq.end(); itBufReq++)
1185  {
1186  if (((*itBufReq).first.m_rnti == (*itMap).first) &&
1187  (((*itBufReq).second.m_rlcTransmissionQueueSize > 0) ||
1188  ((*itBufReq).second.m_rlcRetransmissionQueueSize > 0) ||
1189  ((*itBufReq).second.m_rlcStatusPduSize > 0)))
1190  {
1191  std::vector<RlcPduListElement_s> newRlcPduLe;
1192  for (uint8_t j = 0; j < nLayer; j++)
1193  {
1194  RlcPduListElement_s newRlcEl;
1195  newRlcEl.m_logicalChannelIdentity = (*itBufReq).first.m_lcId;
1196  newRlcEl.m_size = newDci.m_tbsSize.at(j) / lcActives;
1197  NS_LOG_INFO(this << " LCID " << (uint32_t)newRlcEl.m_logicalChannelIdentity
1198  << " size " << newRlcEl.m_size << " layer " << (uint16_t)j);
1199  newRlcPduLe.push_back(newRlcEl);
1201  newRlcEl.m_logicalChannelIdentity,
1202  newRlcEl.m_size);
1203  if (m_harqOn)
1204  {
1205  // store RLC PDU list for HARQ
1206  auto itRlcPdu = m_dlHarqProcessesRlcPduListBuffer.find((*itMap).first);
1207  if (itRlcPdu == m_dlHarqProcessesRlcPduListBuffer.end())
1208  {
1209  NS_FATAL_ERROR("Unable to find RlcPdcList in HARQ buffer for RNTI "
1210  << (*itMap).first);
1211  }
1212  (*itRlcPdu).second.at(j).at(newDci.m_harqProcess).push_back(newRlcEl);
1213  }
1214  }
1215  newEl.m_rlcPduList.push_back(newRlcPduLe);
1216  }
1217  if ((*itBufReq).first.m_rnti > (*itMap).first)
1218  {
1219  break;
1220  }
1221  }
1222  for (uint8_t j = 0; j < nLayer; j++)
1223  {
1224  newDci.m_ndi.push_back(1);
1225  newDci.m_rv.push_back(0);
1226  }
1227 
1228  newDci.m_tpc = m_ffrSapProvider->GetTpc((*itMap).first);
1229 
1230  newEl.m_dci = newDci;
1231 
1232  if (m_harqOn)
1233  {
1234  // store DCI for HARQ
1235  auto itDci = m_dlHarqProcessesDciBuffer.find(newEl.m_rnti);
1236  if (itDci == m_dlHarqProcessesDciBuffer.end())
1237  {
1238  NS_FATAL_ERROR("Unable to find RNTI entry in DCI HARQ buffer for RNTI "
1239  << newEl.m_rnti);
1240  }
1241  (*itDci).second.at(newDci.m_harqProcess) = newDci;
1242  // refresh timer
1243  auto itHarqTimer = m_dlHarqProcessesTimer.find(newEl.m_rnti);
1244  if (itHarqTimer == m_dlHarqProcessesTimer.end())
1245  {
1246  NS_FATAL_ERROR("Unable to find HARQ timer for RNTI " << (uint16_t)newEl.m_rnti);
1247  }
1248  (*itHarqTimer).second.at(newDci.m_harqProcess) = 0;
1249  }
1250 
1251  // update UE stats
1252  if (bytesTxed <= (*itMax).second.tokenPoolSize)
1253  {
1254  (*itMax).second.tokenPoolSize -= bytesTxed;
1255  }
1256  else
1257  {
1258  (*itMax).second.counter =
1259  (*itMax).second.counter - (bytesTxed - (*itMax).second.tokenPoolSize);
1260  (*itMax).second.tokenPoolSize = 0;
1261  if (bankSize <= (bytesTxed - (*itMax).second.tokenPoolSize))
1262  {
1263  bankSize = 0;
1264  }
1265  else
1266  {
1267  bankSize = bankSize - (bytesTxed - (*itMax).second.tokenPoolSize);
1268  }
1269  }
1270 
1271  // ...more parameters -> ignored in this version
1272 
1273  ret.m_buildDataList.push_back(newEl);
1274 
1275  itMap++;
1276  } // end while allocation
1277  ret.m_nrOfPdcchOfdmSymbols = 1;
1278 
1280 }
1281 
1282 void
1285 {
1286  NS_LOG_FUNCTION(this);
1287 
1288  m_rachList = params.m_rachList;
1289 }
1290 
1291 void
1294 {
1295  NS_LOG_FUNCTION(this);
1297 
1298  for (unsigned int i = 0; i < params.m_cqiList.size(); i++)
1299  {
1300  if (params.m_cqiList.at(i).m_cqiType == CqiListElement_s::P10)
1301  {
1302  NS_LOG_LOGIC("wideband CQI " << (uint32_t)params.m_cqiList.at(i).m_wbCqi.at(0)
1303  << " reported");
1304  uint16_t rnti = params.m_cqiList.at(i).m_rnti;
1305  auto it = m_p10CqiRxed.find(rnti);
1306  if (it == m_p10CqiRxed.end())
1307  {
1308  // create the new entry
1309  m_p10CqiRxed[rnti] =
1310  params.m_cqiList.at(i).m_wbCqi.at(0); // only codeword 0 at this stage (SISO)
1311  // generate correspondent timer
1313  }
1314  else
1315  {
1316  // update the CQI value and refresh correspondent timer
1317  (*it).second = params.m_cqiList.at(i).m_wbCqi.at(0);
1318  // update correspondent timer
1319  auto itTimers = m_p10CqiTimers.find(rnti);
1320  (*itTimers).second = m_cqiTimersThreshold;
1321  }
1322  }
1323  else if (params.m_cqiList.at(i).m_cqiType == CqiListElement_s::A30)
1324  {
1325  // subband CQI reporting high layer configured
1326  uint16_t rnti = params.m_cqiList.at(i).m_rnti;
1327  auto it = m_a30CqiRxed.find(rnti);
1328  if (it == m_a30CqiRxed.end())
1329  {
1330  // create the new entry
1331  m_a30CqiRxed[rnti] = params.m_cqiList.at(i).m_sbMeasResult;
1333  }
1334  else
1335  {
1336  // update the CQI value and refresh correspondent timer
1337  (*it).second = params.m_cqiList.at(i).m_sbMeasResult;
1338  auto itTimers = m_a30CqiTimers.find(rnti);
1339  (*itTimers).second = m_cqiTimersThreshold;
1340  }
1341  }
1342  else
1343  {
1344  NS_LOG_ERROR(this << " CQI type unknown");
1345  }
1346  }
1347 }
1348 
1349 double
1350 TdTbfqFfMacScheduler::EstimateUlSinr(uint16_t rnti, uint16_t rb)
1351 {
1352  auto itCqi = m_ueCqi.find(rnti);
1353  if (itCqi == m_ueCqi.end())
1354  {
1355  // no cqi info about this UE
1356  return NO_SINR;
1357  }
1358  else
1359  {
1360  // take the average SINR value among the available
1361  double sinrSum = 0;
1362  unsigned int sinrNum = 0;
1363  for (uint32_t i = 0; i < m_cschedCellConfig.m_ulBandwidth; i++)
1364  {
1365  double sinr = (*itCqi).second.at(i);
1366  if (sinr != NO_SINR)
1367  {
1368  sinrSum += sinr;
1369  sinrNum++;
1370  }
1371  }
1372  double estimatedSinr = (sinrNum > 0) ? (sinrSum / sinrNum) : DBL_MAX;
1373  // store the value
1374  (*itCqi).second.at(rb) = estimatedSinr;
1375  return estimatedSinr;
1376  }
1377 }
1378 
1379 void
1382 {
1383  NS_LOG_FUNCTION(this << " UL - Frame no. " << (params.m_sfnSf >> 4) << " subframe no. "
1384  << (0xF & params.m_sfnSf) << " size " << params.m_ulInfoList.size());
1385 
1386  RefreshUlCqiMaps();
1388 
1389  // Generate RBs map
1391  std::vector<bool> rbMap;
1392  uint16_t rbAllocatedNum = 0;
1393  std::set<uint16_t> rntiAllocated;
1394  std::vector<uint16_t> rbgAllocationMap;
1395  // update with RACH allocation map
1396  rbgAllocationMap = m_rachAllocationMap;
1397  // rbgAllocationMap.resize (m_cschedCellConfig.m_ulBandwidth, 0);
1398  m_rachAllocationMap.clear();
1400 
1401  rbMap.resize(m_cschedCellConfig.m_ulBandwidth, false);
1402 
1404 
1405  for (auto it = rbMap.begin(); it != rbMap.end(); it++)
1406  {
1407  if (*it)
1408  {
1409  rbAllocatedNum++;
1410  }
1411  }
1412 
1413  uint8_t minContinuousUlBandwidth = m_ffrSapProvider->GetMinContinuousUlBandwidth();
1414  uint8_t ffrUlBandwidth = m_cschedCellConfig.m_ulBandwidth - rbAllocatedNum;
1415 
1416  // remove RACH allocation
1417  for (uint16_t i = 0; i < m_cschedCellConfig.m_ulBandwidth; i++)
1418  {
1419  if (rbgAllocationMap.at(i) != 0)
1420  {
1421  rbMap.at(i) = true;
1422  NS_LOG_DEBUG(this << " Allocated for RACH " << i);
1423  }
1424  }
1425 
1426  if (m_harqOn)
1427  {
1428  // Process UL HARQ feedback
1429  for (std::size_t i = 0; i < params.m_ulInfoList.size(); i++)
1430  {
1431  if (params.m_ulInfoList.at(i).m_receptionStatus == UlInfoListElement_s::NotOk)
1432  {
1433  // retx correspondent block: retrieve the UL-DCI
1434  uint16_t rnti = params.m_ulInfoList.at(i).m_rnti;
1435  auto itProcId = m_ulHarqCurrentProcessId.find(rnti);
1436  if (itProcId == m_ulHarqCurrentProcessId.end())
1437  {
1438  NS_LOG_ERROR("No info find in HARQ buffer for UE (might change eNB) " << rnti);
1439  }
1440  uint8_t harqId = (uint8_t)((*itProcId).second - HARQ_PERIOD) % HARQ_PROC_NUM;
1441  NS_LOG_INFO(this << " UL-HARQ retx RNTI " << rnti << " harqId " << (uint16_t)harqId
1442  << " i " << i << " size " << params.m_ulInfoList.size());
1443  auto itHarq = m_ulHarqProcessesDciBuffer.find(rnti);
1444  if (itHarq == m_ulHarqProcessesDciBuffer.end())
1445  {
1446  NS_LOG_ERROR("No info find in HARQ buffer for UE (might change eNB) " << rnti);
1447  continue;
1448  }
1449  UlDciListElement_s dci = (*itHarq).second.at(harqId);
1450  auto itStat = m_ulHarqProcessesStatus.find(rnti);
1451  if (itStat == m_ulHarqProcessesStatus.end())
1452  {
1453  NS_LOG_ERROR("No info find in HARQ buffer for UE (might change eNB) " << rnti);
1454  }
1455  if ((*itStat).second.at(harqId) >= 3)
1456  {
1457  NS_LOG_INFO("Max number of retransmissions reached (UL)-> drop process");
1458  continue;
1459  }
1460  bool free = true;
1461  for (int j = dci.m_rbStart; j < dci.m_rbStart + dci.m_rbLen; j++)
1462  {
1463  if (rbMap.at(j))
1464  {
1465  free = false;
1466  NS_LOG_INFO(this << " BUSY " << j);
1467  }
1468  }
1469  if (free)
1470  {
1471  // retx on the same RBs
1472  for (int j = dci.m_rbStart; j < dci.m_rbStart + dci.m_rbLen; j++)
1473  {
1474  rbMap.at(j) = true;
1475  rbgAllocationMap.at(j) = dci.m_rnti;
1476  NS_LOG_INFO("\tRB " << j);
1477  rbAllocatedNum++;
1478  }
1479  NS_LOG_INFO(this << " Send retx in the same RBs " << (uint16_t)dci.m_rbStart
1480  << " to " << dci.m_rbStart + dci.m_rbLen << " RV "
1481  << (*itStat).second.at(harqId) + 1);
1482  }
1483  else
1484  {
1485  NS_LOG_INFO("Cannot allocate retx due to RACH allocations for UE " << rnti);
1486  continue;
1487  }
1488  dci.m_ndi = 0;
1489  // Update HARQ buffers with new HarqId
1490  (*itStat).second.at((*itProcId).second) = (*itStat).second.at(harqId) + 1;
1491  (*itStat).second.at(harqId) = 0;
1492  (*itHarq).second.at((*itProcId).second) = dci;
1493  ret.m_dciList.push_back(dci);
1494  rntiAllocated.insert(dci.m_rnti);
1495  }
1496  else
1497  {
1498  NS_LOG_INFO(this << " HARQ-ACK feedback from RNTI "
1499  << params.m_ulInfoList.at(i).m_rnti);
1500  }
1501  }
1502  }
1503 
1504  std::map<uint16_t, uint32_t>::iterator it;
1505  int nflows = 0;
1506 
1507  for (it = m_ceBsrRxed.begin(); it != m_ceBsrRxed.end(); it++)
1508  {
1509  auto itRnti = rntiAllocated.find((*it).first);
1510  // select UEs with queues not empty and not yet allocated for HARQ
1511  if (((*it).second > 0) && (itRnti == rntiAllocated.end()))
1512  {
1513  nflows++;
1514  }
1515  }
1516 
1517  if (nflows == 0)
1518  {
1519  if (!ret.m_dciList.empty())
1520  {
1521  m_allocationMaps[params.m_sfnSf] = rbgAllocationMap;
1523  }
1524 
1525  return; // no flows to be scheduled
1526  }
1527 
1528  // Divide the remaining resources equally among the active users starting from the subsequent
1529  // one served last scheduling trigger
1530  uint16_t tempRbPerFlow = (ffrUlBandwidth) / (nflows + rntiAllocated.size());
1531  uint16_t rbPerFlow =
1532  (minContinuousUlBandwidth < tempRbPerFlow) ? minContinuousUlBandwidth : tempRbPerFlow;
1533 
1534  if (rbPerFlow < 3)
1535  {
1536  rbPerFlow = 3; // at least 3 rbg per flow (till available resource) to ensure TxOpportunity
1537  // >= 7 bytes
1538  }
1539  int rbAllocated = 0;
1540 
1541  if (m_nextRntiUl != 0)
1542  {
1543  for (it = m_ceBsrRxed.begin(); it != m_ceBsrRxed.end(); it++)
1544  {
1545  if ((*it).first == m_nextRntiUl)
1546  {
1547  break;
1548  }
1549  }
1550  if (it == m_ceBsrRxed.end())
1551  {
1552  NS_LOG_ERROR(this << " no user found");
1553  }
1554  }
1555  else
1556  {
1557  it = m_ceBsrRxed.begin();
1558  m_nextRntiUl = (*it).first;
1559  }
1560  do
1561  {
1562  auto itRnti = rntiAllocated.find((*it).first);
1563  if ((itRnti != rntiAllocated.end()) || ((*it).second == 0))
1564  {
1565  // UE already allocated for UL-HARQ -> skip it
1566  NS_LOG_DEBUG(this << " UE already allocated in HARQ -> discarded, RNTI "
1567  << (*it).first);
1568  it++;
1569  if (it == m_ceBsrRxed.end())
1570  {
1571  // restart from the first
1572  it = m_ceBsrRxed.begin();
1573  }
1574  continue;
1575  }
1576  if (rbAllocated + rbPerFlow - 1 > m_cschedCellConfig.m_ulBandwidth)
1577  {
1578  // limit to physical resources last resource assignment
1579  rbPerFlow = m_cschedCellConfig.m_ulBandwidth - rbAllocated;
1580  // at least 3 rbg per flow to ensure TxOpportunity >= 7 bytes
1581  if (rbPerFlow < 3)
1582  {
1583  // terminate allocation
1584  rbPerFlow = 0;
1585  }
1586  }
1587 
1588  rbAllocated = 0;
1589  UlDciListElement_s uldci;
1590  uldci.m_rnti = (*it).first;
1591  uldci.m_rbLen = rbPerFlow;
1592  bool allocated = false;
1593  NS_LOG_INFO(this << " RB Allocated " << rbAllocated << " rbPerFlow " << rbPerFlow
1594  << " flows " << nflows);
1595  while ((!allocated) && ((rbAllocated + rbPerFlow - m_cschedCellConfig.m_ulBandwidth) < 1) &&
1596  (rbPerFlow != 0))
1597  {
1598  // check availability
1599  bool free = true;
1600  for (int j = rbAllocated; j < rbAllocated + rbPerFlow; j++)
1601  {
1602  if (rbMap.at(j))
1603  {
1604  free = false;
1605  break;
1606  }
1607  if (!m_ffrSapProvider->IsUlRbgAvailableForUe(j, (*it).first))
1608  {
1609  free = false;
1610  break;
1611  }
1612  }
1613  if (free)
1614  {
1615  NS_LOG_INFO(this << "RNTI: " << (*it).first << " RB Allocated " << rbAllocated
1616  << " rbPerFlow " << rbPerFlow << " flows " << nflows);
1617  uldci.m_rbStart = rbAllocated;
1618 
1619  for (int j = rbAllocated; j < rbAllocated + rbPerFlow; j++)
1620  {
1621  rbMap.at(j) = true;
1622  // store info on allocation for managing ul-cqi interpretation
1623  rbgAllocationMap.at(j) = (*it).first;
1624  }
1625  rbAllocated += rbPerFlow;
1626  allocated = true;
1627  break;
1628  }
1629  rbAllocated++;
1630  if (rbAllocated + rbPerFlow - 1 > m_cschedCellConfig.m_ulBandwidth)
1631  {
1632  // limit to physical resources last resource assignment
1633  rbPerFlow = m_cschedCellConfig.m_ulBandwidth - rbAllocated;
1634  // at least 3 rbg per flow to ensure TxOpportunity >= 7 bytes
1635  if (rbPerFlow < 3)
1636  {
1637  // terminate allocation
1638  rbPerFlow = 0;
1639  }
1640  }
1641  }
1642  if (!allocated)
1643  {
1644  // unable to allocate new resource: finish scheduling
1645  // m_nextRntiUl = (*it).first;
1646  // if (ret.m_dciList.size () > 0)
1647  // {
1648  // m_schedSapUser->SchedUlConfigInd (ret);
1649  // }
1650  // m_allocationMaps[params.m_sfnSf] = rbgAllocationMap; return;
1651  break;
1652  }
1653 
1654  auto itCqi = m_ueCqi.find((*it).first);
1655  int cqi = 0;
1656  if (itCqi == m_ueCqi.end())
1657  {
1658  // no cqi info about this UE
1659  uldci.m_mcs = 0; // MCS 0 -> UL-AMC TBD
1660  }
1661  else
1662  {
1663  // take the lowest CQI value (worst RB)
1664  NS_ABORT_MSG_IF((*itCqi).second.empty(),
1665  "CQI of RNTI = " << (*it).first << " has expired");
1666  double minSinr = (*itCqi).second.at(uldci.m_rbStart);
1667  if (minSinr == NO_SINR)
1668  {
1669  minSinr = EstimateUlSinr((*it).first, uldci.m_rbStart);
1670  }
1671  for (uint16_t i = uldci.m_rbStart; i < uldci.m_rbStart + uldci.m_rbLen; i++)
1672  {
1673  double sinr = (*itCqi).second.at(i);
1674  if (sinr == NO_SINR)
1675  {
1676  sinr = EstimateUlSinr((*it).first, i);
1677  }
1678  if (sinr < minSinr)
1679  {
1680  minSinr = sinr;
1681  }
1682  }
1683 
1684  // translate SINR -> cqi: WILD ACK: same as DL
1685  double s = log2(1 + (std::pow(10, minSinr / 10) / ((-std::log(5.0 * 0.00005)) / 1.5)));
1686  cqi = m_amc->GetCqiFromSpectralEfficiency(s);
1687  if (cqi == 0)
1688  {
1689  it++;
1690  if (it == m_ceBsrRxed.end())
1691  {
1692  // restart from the first
1693  it = m_ceBsrRxed.begin();
1694  }
1695  NS_LOG_DEBUG(this << " UE discarded for CQI = 0, RNTI " << uldci.m_rnti);
1696  // remove UE from allocation map
1697  for (uint16_t i = uldci.m_rbStart; i < uldci.m_rbStart + uldci.m_rbLen; i++)
1698  {
1699  rbgAllocationMap.at(i) = 0;
1700  }
1701  continue; // CQI == 0 means "out of range" (see table 7.2.3-1 of 36.213)
1702  }
1703  uldci.m_mcs = m_amc->GetMcsFromCqi(cqi);
1704  }
1705 
1706  uldci.m_tbSize = (m_amc->GetUlTbSizeFromMcs(uldci.m_mcs, rbPerFlow) / 8);
1707  UpdateUlRlcBufferInfo(uldci.m_rnti, uldci.m_tbSize);
1708  uldci.m_ndi = 1;
1709  uldci.m_cceIndex = 0;
1710  uldci.m_aggrLevel = 1;
1711  uldci.m_ueTxAntennaSelection = 3; // antenna selection OFF
1712  uldci.m_hopping = false;
1713  uldci.m_n2Dmrs = 0;
1714  uldci.m_tpc = 0; // no power control
1715  uldci.m_cqiRequest = false; // only period CQI at this stage
1716  uldci.m_ulIndex = 0; // TDD parameter
1717  uldci.m_dai = 1; // TDD parameter
1718  uldci.m_freqHopping = 0;
1719  uldci.m_pdcchPowerOffset = 0; // not used
1720  ret.m_dciList.push_back(uldci);
1721  // store DCI for HARQ_PERIOD
1722  uint8_t harqId = 0;
1723  if (m_harqOn)
1724  {
1725  auto itProcId = m_ulHarqCurrentProcessId.find(uldci.m_rnti);
1726  if (itProcId == m_ulHarqCurrentProcessId.end())
1727  {
1728  NS_FATAL_ERROR("No info find in HARQ buffer for UE " << uldci.m_rnti);
1729  }
1730  harqId = (*itProcId).second;
1731  auto itDci = m_ulHarqProcessesDciBuffer.find(uldci.m_rnti);
1732  if (itDci == m_ulHarqProcessesDciBuffer.end())
1733  {
1734  NS_FATAL_ERROR("Unable to find RNTI entry in UL DCI HARQ buffer for RNTI "
1735  << uldci.m_rnti);
1736  }
1737  (*itDci).second.at(harqId) = uldci;
1738  // Update HARQ process status (RV 0)
1739  auto itStat = m_ulHarqProcessesStatus.find(uldci.m_rnti);
1740  if (itStat == m_ulHarqProcessesStatus.end())
1741  {
1742  NS_LOG_ERROR("No info find in HARQ buffer for UE (might change eNB) "
1743  << uldci.m_rnti);
1744  }
1745  (*itStat).second.at(harqId) = 0;
1746  }
1747 
1748  NS_LOG_INFO(this << " UE Allocation RNTI " << (*it).first << " startPRB "
1749  << (uint32_t)uldci.m_rbStart << " nPRB " << (uint32_t)uldci.m_rbLen
1750  << " CQI " << cqi << " MCS " << (uint32_t)uldci.m_mcs << " TBsize "
1751  << uldci.m_tbSize << " RbAlloc " << rbAllocated << " harqId "
1752  << (uint16_t)harqId);
1753 
1754  it++;
1755  if (it == m_ceBsrRxed.end())
1756  {
1757  // restart from the first
1758  it = m_ceBsrRxed.begin();
1759  }
1760  if ((rbAllocated == m_cschedCellConfig.m_ulBandwidth) || (rbPerFlow == 0))
1761  {
1762  // Stop allocation: no more PRBs
1763  m_nextRntiUl = (*it).first;
1764  break;
1765  }
1766  } while (((*it).first != m_nextRntiUl) && (rbPerFlow != 0));
1767 
1768  m_allocationMaps[params.m_sfnSf] = rbgAllocationMap;
1770 }
1771 
1772 void
1775 {
1776  NS_LOG_FUNCTION(this);
1777 }
1778 
1779 void
1782 {
1783  NS_LOG_FUNCTION(this);
1784 }
1785 
1786 void
1789 {
1790  NS_LOG_FUNCTION(this);
1791 
1792  for (unsigned int i = 0; i < params.m_macCeList.size(); i++)
1793  {
1794  if (params.m_macCeList.at(i).m_macCeType == MacCeListElement_s::BSR)
1795  {
1796  // buffer status report
1797  // note that this scheduler does not differentiate the
1798  // allocation according to which LCGs have more/less bytes
1799  // to send.
1800  // Hence the BSR of different LCGs are just summed up to get
1801  // a total queue size that is used for allocation purposes.
1802 
1803  uint32_t buffer = 0;
1804  for (uint8_t lcg = 0; lcg < 4; ++lcg)
1805  {
1806  uint8_t bsrId = params.m_macCeList.at(i).m_macCeValue.m_bufferStatus.at(lcg);
1807  buffer += BufferSizeLevelBsr::BsrId2BufferSize(bsrId);
1808  }
1809 
1810  uint16_t rnti = params.m_macCeList.at(i).m_rnti;
1811  NS_LOG_LOGIC(this << "RNTI=" << rnti << " buffer=" << buffer);
1812  auto it = m_ceBsrRxed.find(rnti);
1813  if (it == m_ceBsrRxed.end())
1814  {
1815  // create the new entry
1816  m_ceBsrRxed[rnti] = buffer;
1817  }
1818  else
1819  {
1820  // update the buffer size value
1821  (*it).second = buffer;
1822  }
1823  }
1824  }
1825 }
1826 
1827 void
1830 {
1831  NS_LOG_FUNCTION(this);
1832  // retrieve the allocation for this subframe
1833  switch (m_ulCqiFilter)
1834  {
1836  // filter all the CQIs that are not SRS based
1837  if (params.m_ulCqi.m_type != UlCqi_s::SRS)
1838  {
1839  return;
1840  }
1841  }
1842  break;
1844  // filter all the CQIs that are not SRS based
1845  if (params.m_ulCqi.m_type != UlCqi_s::PUSCH)
1846  {
1847  return;
1848  }
1849  }
1850  break;
1851  default:
1852  NS_FATAL_ERROR("Unknown UL CQI type");
1853  }
1854 
1855  switch (params.m_ulCqi.m_type)
1856  {
1857  case UlCqi_s::PUSCH: {
1858  NS_LOG_DEBUG(this << " Collect PUSCH CQIs of Frame no. " << (params.m_sfnSf >> 4)
1859  << " subframe no. " << (0xF & params.m_sfnSf));
1860  auto itMap = m_allocationMaps.find(params.m_sfnSf);
1861  if (itMap == m_allocationMaps.end())
1862  {
1863  return;
1864  }
1865  for (uint32_t i = 0; i < (*itMap).second.size(); i++)
1866  {
1867  // convert from fixed point notation Sxxxxxxxxxxx.xxx to double
1868  double sinr = LteFfConverter::fpS11dot3toDouble(params.m_ulCqi.m_sinr.at(i));
1869  auto itCqi = m_ueCqi.find((*itMap).second.at(i));
1870  if (itCqi == m_ueCqi.end())
1871  {
1872  // create a new entry
1873  std::vector<double> newCqi;
1874  for (uint32_t j = 0; j < m_cschedCellConfig.m_ulBandwidth; j++)
1875  {
1876  if (i == j)
1877  {
1878  newCqi.push_back(sinr);
1879  }
1880  else
1881  {
1882  // initialize with NO_SINR value.
1883  newCqi.push_back(NO_SINR);
1884  }
1885  }
1886  m_ueCqi[(*itMap).second.at(i)] = newCqi;
1887  // generate correspondent timer
1888  m_ueCqiTimers[(*itMap).second.at(i)] = m_cqiTimersThreshold;
1889  }
1890  else
1891  {
1892  // update the value
1893  (*itCqi).second.at(i) = sinr;
1894  NS_LOG_DEBUG(this << " RNTI " << (*itMap).second.at(i) << " RB " << i << " SINR "
1895  << sinr);
1896  // update correspondent timer
1897  auto itTimers = m_ueCqiTimers.find((*itMap).second.at(i));
1898  (*itTimers).second = m_cqiTimersThreshold;
1899  }
1900  }
1901  // remove obsolete info on allocation
1902  m_allocationMaps.erase(itMap);
1903  }
1904  break;
1905  case UlCqi_s::SRS: {
1906  // get the RNTI from vendor specific parameters
1907  uint16_t rnti = 0;
1908  NS_ASSERT(!params.m_vendorSpecificList.empty());
1909  for (std::size_t i = 0; i < params.m_vendorSpecificList.size(); i++)
1910  {
1911  if (params.m_vendorSpecificList.at(i).m_type == SRS_CQI_RNTI_VSP)
1912  {
1913  Ptr<SrsCqiRntiVsp> vsp =
1914  DynamicCast<SrsCqiRntiVsp>(params.m_vendorSpecificList.at(i).m_value);
1915  rnti = vsp->GetRnti();
1916  }
1917  }
1918  auto itCqi = m_ueCqi.find(rnti);
1919  if (itCqi == m_ueCqi.end())
1920  {
1921  // create a new entry
1922  std::vector<double> newCqi;
1923  for (uint32_t j = 0; j < m_cschedCellConfig.m_ulBandwidth; j++)
1924  {
1925  double sinr = LteFfConverter::fpS11dot3toDouble(params.m_ulCqi.m_sinr.at(j));
1926  newCqi.push_back(sinr);
1927  NS_LOG_INFO(this << " RNTI " << rnti << " new SRS-CQI for RB " << j << " value "
1928  << sinr);
1929  }
1930  m_ueCqi[rnti] = newCqi;
1931  // generate correspondent timer
1933  }
1934  else
1935  {
1936  // update the values
1937  for (uint32_t j = 0; j < m_cschedCellConfig.m_ulBandwidth; j++)
1938  {
1939  double sinr = LteFfConverter::fpS11dot3toDouble(params.m_ulCqi.m_sinr.at(j));
1940  (*itCqi).second.at(j) = sinr;
1941  NS_LOG_INFO(this << " RNTI " << rnti << " update SRS-CQI for RB " << j << " value "
1942  << sinr);
1943  }
1944  // update correspondent timer
1945  auto itTimers = m_ueCqiTimers.find(rnti);
1946  (*itTimers).second = m_cqiTimersThreshold;
1947  }
1948  }
1949  break;
1950  case UlCqi_s::PUCCH_1:
1951  case UlCqi_s::PUCCH_2:
1952  case UlCqi_s::PRACH: {
1953  NS_FATAL_ERROR("TdTbfqFfMacScheduler supports only PUSCH and SRS UL-CQIs");
1954  }
1955  break;
1956  default:
1957  NS_FATAL_ERROR("Unknown type of UL-CQI");
1958  }
1959 }
1960 
1961 void
1963 {
1964  // refresh DL CQI P01 Map
1965  auto itP10 = m_p10CqiTimers.begin();
1966  while (itP10 != m_p10CqiTimers.end())
1967  {
1968  NS_LOG_INFO(this << " P10-CQI for user " << (*itP10).first << " is "
1969  << (uint32_t)(*itP10).second << " thr " << (uint32_t)m_cqiTimersThreshold);
1970  if ((*itP10).second == 0)
1971  {
1972  // delete correspondent entries
1973  auto itMap = m_p10CqiRxed.find((*itP10).first);
1974  NS_ASSERT_MSG(itMap != m_p10CqiRxed.end(),
1975  " Does not find CQI report for user " << (*itP10).first);
1976  NS_LOG_INFO(this << " P10-CQI expired for user " << (*itP10).first);
1977  m_p10CqiRxed.erase(itMap);
1978  auto temp = itP10;
1979  itP10++;
1980  m_p10CqiTimers.erase(temp);
1981  }
1982  else
1983  {
1984  (*itP10).second--;
1985  itP10++;
1986  }
1987  }
1988 
1989  // refresh DL CQI A30 Map
1990  auto itA30 = m_a30CqiTimers.begin();
1991  while (itA30 != m_a30CqiTimers.end())
1992  {
1993  NS_LOG_INFO(this << " A30-CQI for user " << (*itA30).first << " is "
1994  << (uint32_t)(*itA30).second << " thr " << (uint32_t)m_cqiTimersThreshold);
1995  if ((*itA30).second == 0)
1996  {
1997  // delete correspondent entries
1998  auto itMap = m_a30CqiRxed.find((*itA30).first);
1999  NS_ASSERT_MSG(itMap != m_a30CqiRxed.end(),
2000  " Does not find CQI report for user " << (*itA30).first);
2001  NS_LOG_INFO(this << " A30-CQI expired for user " << (*itA30).first);
2002  m_a30CqiRxed.erase(itMap);
2003  auto temp = itA30;
2004  itA30++;
2005  m_a30CqiTimers.erase(temp);
2006  }
2007  else
2008  {
2009  (*itA30).second--;
2010  itA30++;
2011  }
2012  }
2013 }
2014 
2015 void
2017 {
2018  // refresh UL CQI Map
2019  auto itUl = m_ueCqiTimers.begin();
2020  while (itUl != m_ueCqiTimers.end())
2021  {
2022  NS_LOG_INFO(this << " UL-CQI for user " << (*itUl).first << " is "
2023  << (uint32_t)(*itUl).second << " thr " << (uint32_t)m_cqiTimersThreshold);
2024  if ((*itUl).second == 0)
2025  {
2026  // delete correspondent entries
2027  auto itMap = m_ueCqi.find((*itUl).first);
2028  NS_ASSERT_MSG(itMap != m_ueCqi.end(),
2029  " Does not find CQI report for user " << (*itUl).first);
2030  NS_LOG_INFO(this << " UL-CQI exired for user " << (*itUl).first);
2031  (*itMap).second.clear();
2032  m_ueCqi.erase(itMap);
2033  auto temp = itUl;
2034  itUl++;
2035  m_ueCqiTimers.erase(temp);
2036  }
2037  else
2038  {
2039  (*itUl).second--;
2040  itUl++;
2041  }
2042  }
2043 }
2044 
2045 void
2046 TdTbfqFfMacScheduler::UpdateDlRlcBufferInfo(uint16_t rnti, uint8_t lcid, uint16_t size)
2047 {
2048  LteFlowId_t flow(rnti, lcid);
2049  auto it = m_rlcBufferReq.find(flow);
2050  if (it != m_rlcBufferReq.end())
2051  {
2052  NS_LOG_INFO(this << " UE " << rnti << " LC " << (uint16_t)lcid << " txqueue "
2053  << (*it).second.m_rlcTransmissionQueueSize << " retxqueue "
2054  << (*it).second.m_rlcRetransmissionQueueSize << " status "
2055  << (*it).second.m_rlcStatusPduSize << " decrease " << size);
2056  // Update queues: RLC tx order Status, ReTx, Tx
2057  // Update status queue
2058  if (((*it).second.m_rlcStatusPduSize > 0) && (size >= (*it).second.m_rlcStatusPduSize))
2059  {
2060  (*it).second.m_rlcStatusPduSize = 0;
2061  }
2062  else if (((*it).second.m_rlcRetransmissionQueueSize > 0) &&
2063  (size >= (*it).second.m_rlcRetransmissionQueueSize))
2064  {
2065  (*it).second.m_rlcRetransmissionQueueSize = 0;
2066  }
2067  else if ((*it).second.m_rlcTransmissionQueueSize > 0)
2068  {
2069  uint32_t rlcOverhead;
2070  if (lcid == 1)
2071  {
2072  // for SRB1 (using RLC AM) it's better to
2073  // overestimate RLC overhead rather than
2074  // underestimate it and risk unneeded
2075  // segmentation which increases delay
2076  rlcOverhead = 4;
2077  }
2078  else
2079  {
2080  // minimum RLC overhead due to header
2081  rlcOverhead = 2;
2082  }
2083  // update transmission queue
2084  if ((*it).second.m_rlcTransmissionQueueSize <= size - rlcOverhead)
2085  {
2086  (*it).second.m_rlcTransmissionQueueSize = 0;
2087  }
2088  else
2089  {
2090  (*it).second.m_rlcTransmissionQueueSize -= size - rlcOverhead;
2091  }
2092  }
2093  }
2094  else
2095  {
2096  NS_LOG_ERROR(this << " Does not find DL RLC Buffer Report of UE " << rnti);
2097  }
2098 }
2099 
2100 void
2101 TdTbfqFfMacScheduler::UpdateUlRlcBufferInfo(uint16_t rnti, uint16_t size)
2102 {
2103  size = size - 2; // remove the minimum RLC overhead
2104  auto it = m_ceBsrRxed.find(rnti);
2105  if (it != m_ceBsrRxed.end())
2106  {
2107  NS_LOG_INFO(this << " UE " << rnti << " size " << size << " BSR " << (*it).second);
2108  if ((*it).second >= size)
2109  {
2110  (*it).second -= size;
2111  }
2112  else
2113  {
2114  (*it).second = 0;
2115  }
2116  }
2117  else
2118  {
2119  NS_LOG_ERROR(this << " Does not find BSR report info of UE " << rnti);
2120  }
2121 }
2122 
2123 void
2125 {
2126  NS_LOG_FUNCTION(this << " RNTI " << rnti << " txMode " << (uint16_t)txMode);
2128  params.m_rnti = rnti;
2129  params.m_transmissionMode = txMode;
2131 }
2132 
2133 } // namespace ns3
static uint32_t BsrId2BufferSize(uint8_t val)
Convert BSR ID to buffer size.
Definition: lte-common.cc:176
Provides the CSCHED SAP.
FfMacCschedSapUser class.
virtual void 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
Implements the SCHED SAP and CSCHED SAP for a Time Domain Token Bank Fair Queue scheduler.
uint16_t m_nextRntiUl
RNTI of the next user to be served next scheduling in UL.
bool HarqProcessAvailability(uint16_t rnti)
Return the availability of free process for the RNTI specified.
void SetLteFfrSapProvider(LteFfrSapProvider *s) override
Set the Provider part of the LteFfrSap that this Scheduler will interact with.
static TypeId GetTypeId()
Get the type ID.
std::map< uint16_t, uint8_t > m_uesTxMode
txMode of the UEs
std::map< uint16_t, DlHarqProcessesTimer_t > m_dlHarqProcessesTimer
DL HARQ process timer.
void UpdateDlRlcBufferInfo(uint16_t rnti, uint8_t lcid, uint16_t size)
Update DL RLC buffer info function.
void UpdateUlRlcBufferInfo(uint16_t rnti, uint16_t size)
Update UL RLC buffer info function.
~TdTbfqFfMacScheduler() override
Destructor.
FfMacSchedSapProvider * m_schedSapProvider
Sched SAP provider.
std::map< uint16_t, UlHarqProcessesDciBuffer_t > m_ulHarqProcessesDciBuffer
UL HARQ process DCI buffer.
FfMacCschedSapProvider::CschedCellConfigReqParameters m_cschedCellConfig
CSched cell config.
FfMacSchedSapUser * m_schedSapUser
A=Sched SAP user.
unsigned int LcActivePerFlow(uint16_t rnti)
LC active flow size.
std::map< uint16_t, DlHarqProcessesDciBuffer_t > m_dlHarqProcessesDciBuffer
DL HARQ process DCI buffer.
std::map< uint16_t, DlHarqRlcPduListBuffer_t > m_dlHarqProcessesRlcPduListBuffer
DL HARQ process RLC PDU list buffer.
uint32_t m_creditLimit
flow credit limit (byte)
void DoSchedUlMacCtrlInfoReq(const FfMacSchedSapProvider::SchedUlMacCtrlInfoReqParameters &params)
Sched UL MAC control info request.
uint8_t UpdateHarqProcessId(uint16_t rnti)
Update and return a new process Id for the RNTI specified.
void DoSchedUlTriggerReq(const FfMacSchedSapProvider::SchedUlTriggerReqParameters &params)
Sched UL trigger request.
std::map< uint16_t, uint32_t > m_a30CqiTimers
Map of UE's timers on DL CQI A30 received.
std::vector< uint16_t > m_rachAllocationMap
RACH allocation map.
LteFfrSapUser * m_ffrSapUser
FFR SAP user.
std::map< uint16_t, uint32_t > m_ceBsrRxed
Map of UE's buffer status reports received.
int GetRbgSize(int dlbandwidth)
Get RBG size.
std::map< uint16_t, uint32_t > m_p10CqiTimers
Map of UE's timers on DL CQI P01 received.
std::map< uint16_t, uint8_t > m_ulHarqCurrentProcessId
UL HARQ current process ID.
void DoSchedDlPagingBufferReq(const FfMacSchedSapProvider::SchedDlPagingBufferReqParameters &params)
Sched DL paging buffer request.
void RefreshDlCqiMaps()
Refresh DL CQI maps function.
uint8_t m_ulGrantMcs
MCS for UL grant (default 0)
std::map< uint16_t, std::vector< double > > m_ueCqi
Map of UEs' UL-CQI per RBG.
FfMacSchedSapProvider * GetFfMacSchedSapProvider() override
uint32_t m_creditableThreshold
threshold of flow credit
void DoSchedDlTriggerReq(const FfMacSchedSapProvider::SchedDlTriggerReqParameters &params)
Sched DL trigger request.
std::map< uint16_t, tdtbfqsFlowPerf_t > m_flowStatsUl
Map of UE statistics (per RNTI basis)
LteFfrSapUser * GetLteFfrSapUser() override
FfMacCschedSapProvider * GetFfMacCschedSapProvider() override
void DoSchedDlMacBufferReq(const FfMacSchedSapProvider::SchedDlMacBufferReqParameters &params)
Sched DL MAC buffer request.
void DoCschedLcConfigReq(const FfMacCschedSapProvider::CschedLcConfigReqParameters &params)
CSched LC config request.
void TransmissionModeConfigurationUpdate(uint16_t rnti, uint8_t txMode)
Transmission mde configuration update function.
friend class MemberCschedSapProvider< TdTbfqFfMacScheduler >
allow MemberCschedSapProvider<TdTbfqFfMacScheduler> class friend access
void DoSchedDlRachInfoReq(const FfMacSchedSapProvider::SchedDlRachInfoReqParameters &params)
Sched DL RACH info request.
std::map< LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters > m_rlcBufferReq
Vectors of UE's LC info.
FfMacCschedSapProvider * m_cschedSapProvider
CSched SAP provider.
void RefreshUlCqiMaps()
Refresh UL CQI maps function.
void DoSchedUlCqiInfoReq(const FfMacSchedSapProvider::SchedUlCqiInfoReqParameters &params)
Sched UL CQI info request.
void SetFfMacSchedSapUser(FfMacSchedSapUser *s) override
set the user part of the FfMacSchedSap that this Scheduler will interact with.
int m_debtLimit
flow debt limit (byte)
double EstimateUlSinr(uint16_t rnti, uint16_t rb)
Estimate UL SINR function.
std::vector< RachListElement_s > m_rachList
RACH list.
void DoCschedLcReleaseReq(const FfMacCschedSapProvider::CschedLcReleaseReqParameters &params)
CSched LC release request.
LteFfrSapProvider * m_ffrSapProvider
FFR SAP provider.
void DoSchedUlSrInfoReq(const FfMacSchedSapProvider::SchedUlSrInfoReqParameters &params)
Sched UL SR info request.
std::map< uint16_t, uint8_t > m_p10CqiRxed
Map of UE's DL CQI P01 received.
void DoCschedUeConfigReq(const FfMacCschedSapProvider::CschedUeConfigReqParameters &params)
CSched UE config request.
friend class MemberSchedSapProvider< TdTbfqFfMacScheduler >
allow MemberSchedSapProvider<TdTbfqFfMacScheduler> class friend access
uint32_t m_tokenPoolSize
maximum size of token pool (byte)
void DoCschedUeReleaseReq(const FfMacCschedSapProvider::CschedUeReleaseReqParameters &params)
CSched UE release request.
std::map< uint16_t, DlHarqProcessesStatus_t > m_dlHarqProcessesStatus
DL HARQ process status.
void DoSchedDlRlcBufferReq(const FfMacSchedSapProvider::SchedDlRlcBufferReqParameters &params)
Sched DL RLC buffer request.
FfMacCschedSapUser * m_cschedSapUser
CSched SAP user.
std::map< uint16_t, uint32_t > m_ueCqiTimers
Map of UEs' timers on UL-CQI per RBG.
void DoDispose() override
Destructor implementation.
std::map< uint16_t, uint8_t > m_dlHarqCurrentProcessId
DL HARQ current process ID.
std::map< uint16_t, std::vector< uint16_t > > m_allocationMaps
Map of previous allocated UE per RBG (used to retrieve info from UL-CQI)
void RefreshHarqProcesses()
Refresh HARQ processes according to the timers.
void SetFfMacCschedSapUser(FfMacCschedSapUser *s) override
set the user part of the FfMacCschedSap that this Scheduler will interact with.
std::vector< DlInfoListElement_s > m_dlInfoListBuffered
HARQ retx buffered.
void DoSchedUlNoiseInterferenceReq(const FfMacSchedSapProvider::SchedUlNoiseInterferenceReqParameters &params)
Sched UL noise interference request.
std::map< uint16_t, UlHarqProcessesStatus_t > m_ulHarqProcessesStatus
UL HARQ process status.
void DoCschedCellConfigReq(const FfMacCschedSapProvider::CschedCellConfigReqParameters &params)
CSched cell config request.
void DoSchedDlCqiInfoReq(const FfMacSchedSapProvider::SchedDlCqiInfoReqParameters &params)
Sched DL CQI info request.
std::map< uint16_t, tdtbfqsFlowPerf_t > m_flowStatsDl
Map of UE statistics (per RNTI basis) in downlink.
std::map< uint16_t, SbMeasResult_s > m_a30CqiRxed
Map of UE's DL CQI A30 received.
uint64_t bankSize
the number of bytes in token bank
bool m_harqOn
m_harqOn when false inhibit the HARQ mechanisms (by default active)
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...
static const int TdTbfqType0AllocationRbg[4]
TDTBFQ type 0 allocation RBG.
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.
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.
uint32_t tokenPoolSize
current size of token pool (byte)
int debtLimit
counter threshold that the flow cannot further borrow tokens from bank
uint32_t maxTokenPoolSize
maximum size of token pool (byte)
int counter
the number of token borrow or given to token 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)
uint64_t tokenGenerationRate
token generation rate ( byte/s )
Time flowStart
flow start time
uint32_t burstCredit
the maximum number of tokens connection i can borrow from the bank each time