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