A Discrete-Event Network Simulator
API
tdbet-ff-mac-scheduler.cc
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2011 Centre Tecnologic de Telecomunicacions de Catalunya (CTTC)
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation;
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17  *
18  * Author: Marco Miozzo <marco.miozzo@cttc.es>
19  * Modification: Dizhi Zhou <dizhi.zhou@gmail.com> // modify codes related to downlink scheduler
20  */
21 
22 #include <ns3/log.h>
23 #include <ns3/pointer.h>
24 #include <ns3/math.h>
25 
26 #include <ns3/simulator.h>
27 #include <ns3/lte-amc.h>
28 #include <ns3/tdbet-ff-mac-scheduler.h>
29 #include <ns3/lte-vendor-specific-parameters.h>
30 #include <ns3/boolean.h>
31 #include <set>
32 #include <cfloat>
33 
34 namespace ns3 {
35 
36 NS_LOG_COMPONENT_DEFINE ("TdBetFfMacScheduler");
37 
39 static const int TdBetType0AllocationRbg[4] = {
40  10, // RGB size 1
41  26, // RGB size 2
42  63, // RGB size 3
43  110 // RGB size 4
44 }; // see table 7.1.6.1-1 of 36.213
45 
46 
47 NS_OBJECT_ENSURE_REGISTERED (TdBetFfMacScheduler);
48 
49 
50 
52  : m_cschedSapUser (0),
53  m_schedSapUser (0),
54  m_timeWindow (99.0),
55  m_nextRntiUl (0)
56 {
57  m_amc = CreateObject <LteAmc> ();
60 }
61 
63 {
64  NS_LOG_FUNCTION (this);
65 }
66 
67 void
69 {
70  NS_LOG_FUNCTION (this);
72  m_dlHarqProcessesTimer.clear ();
74  m_dlInfoListBuffered.clear ();
75  m_ulHarqCurrentProcessId.clear ();
76  m_ulHarqProcessesStatus.clear ();
78  delete m_cschedSapProvider;
79  delete m_schedSapProvider;
80 }
81 
82 TypeId
84 {
85  static TypeId tid = TypeId ("ns3::TdBetFfMacScheduler")
87  .SetGroupName("Lte")
88  .AddConstructor<TdBetFfMacScheduler> ()
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  ;
105  return tid;
106 }
107 
108 
109 
110 void
112 {
113  m_cschedSapUser = s;
114 }
115 
116 void
118 {
119  m_schedSapUser = s;
120 }
121 
124 {
125  return m_cschedSapProvider;
126 }
127 
130 {
131  return m_schedSapProvider;
132 }
133 
134 void
136 {
137  m_ffrSapProvider = s;
138 }
139 
142 {
143  return m_ffrSapUser;
144 }
145 
146 void
148 {
149  NS_LOG_FUNCTION (this);
150  // Read the subset of parameters used
151  m_cschedCellConfig = params;
154  cnf.m_result = SUCCESS;
156  return;
157 }
158 
159 void
161 {
162  NS_LOG_FUNCTION (this << " RNTI " << params.m_rnti << " txMode " << (uint16_t)params.m_transmissionMode);
163  std::map <uint16_t,uint8_t>::iterator it = m_uesTxMode.find (params.m_rnti);
164  if (it == m_uesTxMode.end ())
165  {
166  m_uesTxMode.insert (std::pair <uint16_t, double> (params.m_rnti, params.m_transmissionMode));
167  // generate HARQ buffers
168  m_dlHarqCurrentProcessId.insert (std::pair <uint16_t,uint8_t > (params.m_rnti, 0));
169  DlHarqProcessesStatus_t dlHarqPrcStatus;
170  dlHarqPrcStatus.resize (8,0);
171  m_dlHarqProcessesStatus.insert (std::pair <uint16_t, DlHarqProcessesStatus_t> (params.m_rnti, dlHarqPrcStatus));
172  DlHarqProcessesTimer_t dlHarqProcessesTimer;
173  dlHarqProcessesTimer.resize (8,0);
174  m_dlHarqProcessesTimer.insert (std::pair <uint16_t, DlHarqProcessesTimer_t> (params.m_rnti, dlHarqProcessesTimer));
175  DlHarqProcessesDciBuffer_t dlHarqdci;
176  dlHarqdci.resize (8);
177  m_dlHarqProcessesDciBuffer.insert (std::pair <uint16_t, DlHarqProcessesDciBuffer_t> (params.m_rnti, dlHarqdci));
178  DlHarqRlcPduListBuffer_t dlHarqRlcPdu;
179  dlHarqRlcPdu.resize (2);
180  dlHarqRlcPdu.at (0).resize (8);
181  dlHarqRlcPdu.at (1).resize (8);
182  m_dlHarqProcessesRlcPduListBuffer.insert (std::pair <uint16_t, DlHarqRlcPduListBuffer_t> (params.m_rnti, dlHarqRlcPdu));
183  m_ulHarqCurrentProcessId.insert (std::pair <uint16_t,uint8_t > (params.m_rnti, 0));
184  UlHarqProcessesStatus_t ulHarqPrcStatus;
185  ulHarqPrcStatus.resize (8,0);
186  m_ulHarqProcessesStatus.insert (std::pair <uint16_t, UlHarqProcessesStatus_t> (params.m_rnti, ulHarqPrcStatus));
187  UlHarqProcessesDciBuffer_t ulHarqdci;
188  ulHarqdci.resize (8);
189  m_ulHarqProcessesDciBuffer.insert (std::pair <uint16_t, UlHarqProcessesDciBuffer_t> (params.m_rnti, ulHarqdci));
190  }
191  else
192  {
193  (*it).second = params.m_transmissionMode;
194  }
195  return;
196 }
197 
198 void
200 {
201  NS_LOG_FUNCTION (this << " New LC, rnti: " << params.m_rnti);
202 
203  std::map <uint16_t, tdbetsFlowPerf_t>::iterator it;
204  for (uint16_t i = 0; i < params.m_logicalChannelConfigList.size (); i++)
205  {
206  it = m_flowStatsDl.find (params.m_rnti);
207 
208  if (it == m_flowStatsDl.end ())
209  {
210  tdbetsFlowPerf_t flowStatsDl;
211  flowStatsDl.flowStart = Simulator::Now ();
212  flowStatsDl.totalBytesTransmitted = 0;
213  flowStatsDl.lastTtiBytesTrasmitted = 0;
214  flowStatsDl.lastAveragedThroughput = 1;
215  m_flowStatsDl.insert (std::pair<uint16_t, tdbetsFlowPerf_t> (params.m_rnti, flowStatsDl));
216  tdbetsFlowPerf_t flowStatsUl;
217  flowStatsUl.flowStart = Simulator::Now ();
218  flowStatsUl.totalBytesTransmitted = 0;
219  flowStatsUl.lastTtiBytesTrasmitted = 0;
220  flowStatsUl.lastAveragedThroughput = 1;
221  m_flowStatsUl.insert (std::pair<uint16_t, tdbetsFlowPerf_t> (params.m_rnti, flowStatsUl));
222  }
223  }
224 
225  return;
226 }
227 
228 void
230 {
231  NS_LOG_FUNCTION (this);
232  for (uint16_t i = 0; i < params.m_logicalChannelIdentity.size (); i++)
233  {
234  std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it = m_rlcBufferReq.begin ();
235  std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator temp;
236  while (it!=m_rlcBufferReq.end ())
237  {
238  if (((*it).first.m_rnti == params.m_rnti) && ((*it).first.m_lcId == params.m_logicalChannelIdentity.at (i)))
239  {
240  temp = it;
241  it++;
242  m_rlcBufferReq.erase (temp);
243  }
244  else
245  {
246  it++;
247  }
248  }
249  }
250  return;
251 }
252 
253 void
255 {
256  NS_LOG_FUNCTION (this);
257 
258  m_uesTxMode.erase (params.m_rnti);
259  m_dlHarqCurrentProcessId.erase (params.m_rnti);
260  m_dlHarqProcessesStatus.erase (params.m_rnti);
261  m_dlHarqProcessesTimer.erase (params.m_rnti);
262  m_dlHarqProcessesDciBuffer.erase (params.m_rnti);
264  m_ulHarqCurrentProcessId.erase (params.m_rnti);
265  m_ulHarqProcessesStatus.erase (params.m_rnti);
266  m_ulHarqProcessesDciBuffer.erase (params.m_rnti);
267  m_flowStatsDl.erase (params.m_rnti);
268  m_flowStatsUl.erase (params.m_rnti);
269  m_ceBsrRxed.erase (params.m_rnti);
270  std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it = m_rlcBufferReq.begin ();
271  std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator temp;
272  while (it!=m_rlcBufferReq.end ())
273  {
274  if ((*it).first.m_rnti == params.m_rnti)
275  {
276  temp = it;
277  it++;
278  m_rlcBufferReq.erase (temp);
279  }
280  else
281  {
282  it++;
283  }
284  }
285  if (m_nextRntiUl == params.m_rnti)
286  {
287  m_nextRntiUl = 0;
288  }
289 
290  return;
291 }
292 
293 
294 void
296 {
297  NS_LOG_FUNCTION (this << params.m_rnti << (uint32_t) params.m_logicalChannelIdentity);
298  // API generated by RLC for updating RLC parameters on a LC (tx and retx queues)
299 
300  std::map <LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it;
301 
302  LteFlowId_t flow (params.m_rnti, params.m_logicalChannelIdentity);
303 
304  it = m_rlcBufferReq.find (flow);
305 
306  if (it == m_rlcBufferReq.end ())
307  {
308  m_rlcBufferReq.insert (std::pair <LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters> (flow, params));
309  }
310  else
311  {
312  (*it).second = params;
313  }
314 
315  return;
316 }
317 
318 void
320 {
321  NS_LOG_FUNCTION (this);
322  NS_FATAL_ERROR ("method not implemented");
323  return;
324 }
325 
326 void
328 {
329  NS_LOG_FUNCTION (this);
330  NS_FATAL_ERROR ("method not implemented");
331  return;
332 }
333 
334 int
336 {
337  for (int i = 0; i < 4; i++)
338  {
339  if (dlbandwidth < TdBetType0AllocationRbg[i])
340  {
341  return (i + 1);
342  }
343  }
344 
345  return (-1);
346 }
347 
348 
349 unsigned int
351 {
352  std::map <LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it;
353  unsigned int lcActive = 0;
354  for (it = m_rlcBufferReq.begin (); it != m_rlcBufferReq.end (); it++)
355  {
356  if (((*it).first.m_rnti == rnti) && (((*it).second.m_rlcTransmissionQueueSize > 0)
357  || ((*it).second.m_rlcRetransmissionQueueSize > 0)
358  || ((*it).second.m_rlcStatusPduSize > 0) ))
359  {
360  lcActive++;
361  }
362  if ((*it).first.m_rnti > rnti)
363  {
364  break;
365  }
366  }
367  return (lcActive);
368 
369 }
370 
371 
372 uint8_t
374 {
375  NS_LOG_FUNCTION (this << rnti);
376 
377  std::map <uint16_t, uint8_t>::iterator it = m_dlHarqCurrentProcessId.find (rnti);
378  if (it == m_dlHarqCurrentProcessId.end ())
379  {
380  NS_FATAL_ERROR ("No Process Id found for this RNTI " << rnti);
381  }
382  std::map <uint16_t, DlHarqProcessesStatus_t>::iterator itStat = m_dlHarqProcessesStatus.find (rnti);
383  if (itStat == m_dlHarqProcessesStatus.end ())
384  {
385  NS_FATAL_ERROR ("No Process Id Statusfound for this RNTI " << rnti);
386  }
387  uint8_t i = (*it).second;
388  do
389  {
390  i = (i + 1) % HARQ_PROC_NUM;
391  }
392  while ( ((*itStat).second.at (i) != 0)&&(i != (*it).second));
393  if ((*itStat).second.at (i) == 0)
394  {
395  return (true);
396  }
397  else
398  {
399  return (false); // return a not valid harq proc id
400  }
401 }
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 
416  std::map <uint16_t, uint8_t>::iterator it = m_dlHarqCurrentProcessId.find (rnti);
417  if (it == m_dlHarqCurrentProcessId.end ())
418  {
419  NS_FATAL_ERROR ("No Process Id found for this RNTI " << rnti);
420  }
421  std::map <uint16_t, DlHarqProcessesStatus_t>::iterator itStat = 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  }
431  while ( ((*itStat).second.at (i) != 0)&&(i != (*it).second));
432  if ((*itStat).second.at (i) == 0)
433  {
434  (*it).second = i;
435  (*itStat).second.at (i) = 1;
436  }
437  else
438  {
439  NS_FATAL_ERROR ("No HARQ process available for RNTI " << rnti << " check before update with HarqProcessAvailability");
440  }
441 
442  return ((*it).second);
443 }
444 
445 
446 void
448 {
449  NS_LOG_FUNCTION (this);
450 
451  std::map <uint16_t, DlHarqProcessesTimer_t>::iterator itTimers;
452  for (itTimers = m_dlHarqProcessesTimer.begin (); itTimers != m_dlHarqProcessesTimer.end (); 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 = m_dlHarqProcessesStatus.find ((*itTimers).first);
462  if (itStat == m_dlHarqProcessesStatus.end ())
463  {
464  NS_FATAL_ERROR ("No Process Id Status found for this RNTI " << (*itTimers).first);
465  }
466  (*itStat).second.at (i) = 0;
467  (*itTimers).second.at (i) = 0;
468  }
469  else
470  {
471  (*itTimers).second.at (i)++;
472  }
473  }
474  }
475 
476 }
477 
478 
479 void
481 {
482  NS_LOG_FUNCTION (this << " Frame no. " << (params.m_sfnSf >> 4) << " subframe no. " << (0xF & params.m_sfnSf));
483  // API generated by RLC for triggering the scheduling of a DL subframe
484 
485 
486  // evaluate the relative channel quality indicator for each UE per each RBG
487  // (since we are using allocation type 0 the small unit of allocation is RBG)
488  // Resource allocation type 0 (see sec 7.1.6.1 of 36.213)
489 
490  RefreshDlCqiMaps ();
491 
493  int rbgNum = m_cschedCellConfig.m_dlBandwidth / rbgSize;
494  std::map <uint16_t, std::vector <uint16_t> > allocationMap; // RBs map per RNTI
495  std::vector <bool> rbgMap; // global RBGs map
496  uint16_t rbgAllocatedNum = 0;
497  std::set <uint16_t> rntiAllocated;
498  rbgMap.resize (m_cschedCellConfig.m_dlBandwidth / rbgSize, false);
500 
501  // update UL HARQ proc id
502  std::map <uint16_t, uint8_t>::iterator itProcId;
503  for (itProcId = m_ulHarqCurrentProcessId.begin (); itProcId != m_ulHarqCurrentProcessId.end (); itProcId++)
504  {
505  (*itProcId).second = ((*itProcId).second + 1) % HARQ_PROC_NUM;
506  }
507 
508  // RACH Allocation
510  uint16_t rbStart = 0;
511  std::vector <struct RachListElement_s>::iterator itRach;
512  for (itRach = m_rachList.begin (); itRach != m_rachList.end (); itRach++)
513  {
514  NS_ASSERT_MSG (m_amc->GetUlTbSizeFromMcs (m_ulGrantMcs, m_cschedCellConfig.m_ulBandwidth) > (*itRach).m_estimatedSize, " Default UL Grant MCS does not allow to send RACH messages");
515  BuildRarListElement_s newRar;
516  newRar.m_rnti = (*itRach).m_rnti;
517  // DL-RACH Allocation
518  // Ideal: no needs of configuring m_dci
519  // UL-RACH Allocation
520  newRar.m_grant.m_rnti = newRar.m_rnti;
521  newRar.m_grant.m_mcs = m_ulGrantMcs;
522  uint16_t rbLen = 1;
523  uint16_t tbSizeBits = 0;
524  // find lowest TB size that fits UL grant estimated size
525  while ((tbSizeBits < (*itRach).m_estimatedSize) && (rbStart + rbLen < m_cschedCellConfig.m_ulBandwidth))
526  {
527  rbLen++;
528  tbSizeBits = m_amc->GetUlTbSizeFromMcs (m_ulGrantMcs, rbLen);
529  }
530  if (tbSizeBits < (*itRach).m_estimatedSize)
531  {
532  // no more allocation space: finish allocation
533  break;
534  }
535  newRar.m_grant.m_rbStart = rbStart;
536  newRar.m_grant.m_rbLen = rbLen;
537  newRar.m_grant.m_tbSize = tbSizeBits / 8;
538  newRar.m_grant.m_hopping = false;
539  newRar.m_grant.m_tpc = 0;
540  newRar.m_grant.m_cqiRequest = false;
541  newRar.m_grant.m_ulDelay = false;
542  NS_LOG_INFO (this << " UL grant allocated to RNTI " << (*itRach).m_rnti << " rbStart " << rbStart << " rbLen " << rbLen << " MCS " << m_ulGrantMcs << " tbSize " << newRar.m_grant.m_tbSize);
543  for (uint16_t i = rbStart; i < rbStart + rbLen; i++)
544  {
545  m_rachAllocationMap.at (i) = (*itRach).m_rnti;
546  }
547 
548  if (m_harqOn == true)
549  {
550  // generate UL-DCI for HARQ retransmissions
551  UlDciListElement_s uldci;
552  uldci.m_rnti = newRar.m_rnti;
553  uldci.m_rbLen = rbLen;
554  uldci.m_rbStart = rbStart;
555  uldci.m_mcs = m_ulGrantMcs;
556  uldci.m_tbSize = tbSizeBits / 8;
557  uldci.m_ndi = 1;
558  uldci.m_cceIndex = 0;
559  uldci.m_aggrLevel = 1;
560  uldci.m_ueTxAntennaSelection = 3; // antenna selection OFF
561  uldci.m_hopping = false;
562  uldci.m_n2Dmrs = 0;
563  uldci.m_tpc = 0; // no power control
564  uldci.m_cqiRequest = false; // only period CQI at this stage
565  uldci.m_ulIndex = 0; // TDD parameter
566  uldci.m_dai = 1; // TDD parameter
567  uldci.m_freqHopping = 0;
568  uldci.m_pdcchPowerOffset = 0; // not used
569 
570  uint8_t harqId = 0;
571  std::map <uint16_t, uint8_t>::iterator itProcId;
572  itProcId = m_ulHarqCurrentProcessId.find (uldci.m_rnti);
573  if (itProcId == m_ulHarqCurrentProcessId.end ())
574  {
575  NS_FATAL_ERROR ("No info find in HARQ buffer for UE " << uldci.m_rnti);
576  }
577  harqId = (*itProcId).second;
578  std::map <uint16_t, UlHarqProcessesDciBuffer_t>::iterator itDci = m_ulHarqProcessesDciBuffer.find (uldci.m_rnti);
579  if (itDci == m_ulHarqProcessesDciBuffer.end ())
580  {
581  NS_FATAL_ERROR ("Unable to find RNTI entry in UL DCI HARQ buffer for RNTI " << uldci.m_rnti);
582  }
583  (*itDci).second.at (harqId) = uldci;
584  }
585 
586  rbStart = rbStart + rbLen;
587  ret.m_buildRarList.push_back (newRar);
588  }
589  m_rachList.clear ();
590 
591 
592  // Process DL HARQ feedback
594  // retrieve past HARQ retx buffered
595  if (m_dlInfoListBuffered.size () > 0)
596  {
597  if (params.m_dlInfoList.size () > 0)
598  {
599  NS_LOG_INFO (this << " Received DL-HARQ feedback");
600  m_dlInfoListBuffered.insert (m_dlInfoListBuffered.end (), params.m_dlInfoList.begin (), params.m_dlInfoList.end ());
601  }
602  }
603  else
604  {
605  if (params.m_dlInfoList.size () > 0)
606  {
608  }
609  }
610  if (m_harqOn == false)
611  {
612  // Ignore HARQ feedback
613  m_dlInfoListBuffered.clear ();
614  }
615  std::vector <struct DlInfoListElement_s> dlInfoListUntxed;
616  for (uint16_t i = 0; i < m_dlInfoListBuffered.size (); i++)
617  {
618  std::set <uint16_t>::iterator itRnti = rntiAllocated.find (m_dlInfoListBuffered.at (i).m_rnti);
619  if (itRnti != rntiAllocated.end ())
620  {
621  // RNTI already allocated for retx
622  continue;
623  }
624  uint8_t nLayers = m_dlInfoListBuffered.at (i).m_harqStatus.size ();
625  std::vector <bool> retx;
626  NS_LOG_INFO (this << " Processing DLHARQ feedback");
627  if (nLayers == 1)
628  {
629  retx.push_back (m_dlInfoListBuffered.at (i).m_harqStatus.at (0) == DlInfoListElement_s::NACK);
630  retx.push_back (false);
631  }
632  else
633  {
634  retx.push_back (m_dlInfoListBuffered.at (i).m_harqStatus.at (0) == DlInfoListElement_s::NACK);
635  retx.push_back (m_dlInfoListBuffered.at (i).m_harqStatus.at (1) == DlInfoListElement_s::NACK);
636  }
637  if (retx.at (0) || retx.at (1))
638  {
639  // retrieve HARQ process information
640  uint16_t rnti = m_dlInfoListBuffered.at (i).m_rnti;
641  uint8_t harqId = m_dlInfoListBuffered.at (i).m_harqProcessId;
642  NS_LOG_INFO (this << " HARQ retx RNTI " << rnti << " harqId " << (uint16_t)harqId);
643  std::map <uint16_t, DlHarqProcessesDciBuffer_t>::iterator itHarq = m_dlHarqProcessesDciBuffer.find (rnti);
644  if (itHarq == m_dlHarqProcessesDciBuffer.end ())
645  {
646  NS_FATAL_ERROR ("No info find in HARQ buffer for UE " << rnti);
647  }
648 
649  DlDciListElement_s dci = (*itHarq).second.at (harqId);
650  int rv = 0;
651  if (dci.m_rv.size () == 1)
652  {
653  rv = dci.m_rv.at (0);
654  }
655  else
656  {
657  rv = (dci.m_rv.at (0) > dci.m_rv.at (1) ? dci.m_rv.at (0) : dci.m_rv.at (1));
658  }
659 
660  if (rv == 3)
661  {
662  // maximum number of retx reached -> drop process
663  NS_LOG_INFO ("Maximum number of retransmissions reached -> drop process");
664  std::map <uint16_t, DlHarqProcessesStatus_t>::iterator it = m_dlHarqProcessesStatus.find (rnti);
665  if (it == m_dlHarqProcessesStatus.end ())
666  {
667  NS_LOG_ERROR ("No info find in HARQ buffer for UE (might change eNB) " << m_dlInfoListBuffered.at (i).m_rnti);
668  }
669  (*it).second.at (harqId) = 0;
670  std::map <uint16_t, DlHarqRlcPduListBuffer_t>::iterator itRlcPdu = m_dlHarqProcessesRlcPduListBuffer.find (rnti);
671  if (itRlcPdu == m_dlHarqProcessesRlcPduListBuffer.end ())
672  {
673  NS_FATAL_ERROR ("Unable to find RlcPdcList in HARQ buffer for RNTI " << m_dlInfoListBuffered.at (i).m_rnti);
674  }
675  for (uint16_t k = 0; k < (*itRlcPdu).second.size (); k++)
676  {
677  (*itRlcPdu).second.at (k).at (harqId).clear ();
678  }
679  continue;
680  }
681  // check the feasibility of retransmitting on the same RBGs
682  // translate the DCI to Spectrum framework
683  std::vector <int> dciRbg;
684  uint32_t mask = 0x1;
685  NS_LOG_INFO ("Original RBGs " << dci.m_rbBitmap << " rnti " << dci.m_rnti);
686  for (int j = 0; j < 32; j++)
687  {
688  if (((dci.m_rbBitmap & mask) >> j) == 1)
689  {
690  dciRbg.push_back (j);
691  NS_LOG_INFO ("\t" << j);
692  }
693  mask = (mask << 1);
694  }
695  bool free = true;
696  for (uint8_t j = 0; j < dciRbg.size (); j++)
697  {
698  if (rbgMap.at (dciRbg.at (j)) == true)
699  {
700  free = false;
701  break;
702  }
703  }
704  if (free)
705  {
706  // use the same RBGs for the retx
707  // reserve RBGs
708  for (uint8_t j = 0; j < dciRbg.size (); j++)
709  {
710  rbgMap.at (dciRbg.at (j)) = true;
711  NS_LOG_INFO ("RBG " << dciRbg.at (j) << " assigned");
712  rbgAllocatedNum++;
713  }
714 
715  NS_LOG_INFO (this << " Send retx in the same RBGs");
716  }
717  else
718  {
719  // find RBGs for sending HARQ retx
720  uint8_t j = 0;
721  uint8_t rbgId = (dciRbg.at (dciRbg.size () - 1) + 1) % rbgNum;
722  uint8_t startRbg = dciRbg.at (dciRbg.size () - 1);
723  std::vector <bool> rbgMapCopy = rbgMap;
724  while ((j < dciRbg.size ())&&(startRbg != rbgId))
725  {
726  if (rbgMapCopy.at (rbgId) == false)
727  {
728  rbgMapCopy.at (rbgId) = true;
729  dciRbg.at (j) = rbgId;
730  j++;
731  }
732  rbgId = (rbgId + 1) % rbgNum;
733  }
734  if (j == dciRbg.size ())
735  {
736  // find new RBGs -> update DCI map
737  uint32_t rbgMask = 0;
738  for (uint16_t k = 0; k < dciRbg.size (); k++)
739  {
740  rbgMask = rbgMask + (0x1 << dciRbg.at (k));
741  rbgAllocatedNum++;
742  }
743  dci.m_rbBitmap = rbgMask;
744  rbgMap = rbgMapCopy;
745  NS_LOG_INFO (this << " Move retx in RBGs " << dciRbg.size ());
746  }
747  else
748  {
749  // HARQ retx cannot be performed on this TTI -> store it
750  dlInfoListUntxed.push_back (m_dlInfoListBuffered.at (i));
751  NS_LOG_INFO (this << " No resource for this retx -> buffer it");
752  }
753  }
754  // retrieve RLC PDU list for retx TBsize and update DCI
756  std::map <uint16_t, DlHarqRlcPduListBuffer_t>::iterator itRlcPdu = m_dlHarqProcessesRlcPduListBuffer.find (rnti);
757  if (itRlcPdu == m_dlHarqProcessesRlcPduListBuffer.end ())
758  {
759  NS_FATAL_ERROR ("Unable to find RlcPdcList in HARQ buffer for RNTI " << rnti);
760  }
761  for (uint8_t j = 0; j < nLayers; j++)
762  {
763  if (retx.at (j))
764  {
765  if (j >= dci.m_ndi.size ())
766  {
767  // for avoiding errors in MIMO transient phases
768  dci.m_ndi.push_back (0);
769  dci.m_rv.push_back (0);
770  dci.m_mcs.push_back (0);
771  dci.m_tbsSize.push_back (0);
772  NS_LOG_INFO (this << " layer " << (uint16_t)j << " no txed (MIMO transition)");
773  }
774  else
775  {
776  dci.m_ndi.at (j) = 0;
777  dci.m_rv.at (j)++;
778  (*itHarq).second.at (harqId).m_rv.at (j)++;
779  NS_LOG_INFO (this << " layer " << (uint16_t)j << " RV " << (uint16_t)dci.m_rv.at (j));
780  }
781  }
782  else
783  {
784  // empty TB of layer j
785  dci.m_ndi.at (j) = 0;
786  dci.m_rv.at (j) = 0;
787  dci.m_mcs.at (j) = 0;
788  dci.m_tbsSize.at (j) = 0;
789  NS_LOG_INFO (this << " layer " << (uint16_t)j << " no retx");
790  }
791  }
792  for (uint16_t k = 0; k < (*itRlcPdu).second.at (0).at (dci.m_harqProcess).size (); k++)
793  {
794  std::vector <struct RlcPduListElement_s> rlcPduListPerLc;
795  for (uint8_t j = 0; j < nLayers; j++)
796  {
797  if (retx.at (j))
798  {
799  if (j < dci.m_ndi.size ())
800  {
801  NS_LOG_INFO (" layer " << (uint16_t)j << " tb size " << dci.m_tbsSize.at (j));
802  rlcPduListPerLc.push_back ((*itRlcPdu).second.at (j).at (dci.m_harqProcess).at (k));
803  }
804  }
805  else
806  { // if no retx needed on layer j, push an RlcPduListElement_s object with m_size=0 to keep the size of rlcPduListPerLc vector = 2 in case of MIMO
807  NS_LOG_INFO (" layer " << (uint16_t)j << " tb size "<<dci.m_tbsSize.at (j));
808  RlcPduListElement_s emptyElement;
809  emptyElement.m_logicalChannelIdentity = (*itRlcPdu).second.at (j).at (dci.m_harqProcess).at (k).m_logicalChannelIdentity;
810  emptyElement.m_size = 0;
811  rlcPduListPerLc.push_back (emptyElement);
812  }
813  }
814 
815  if (rlcPduListPerLc.size () > 0)
816  {
817  newEl.m_rlcPduList.push_back (rlcPduListPerLc);
818  }
819  }
820  newEl.m_rnti = rnti;
821  newEl.m_dci = dci;
822  (*itHarq).second.at (harqId).m_rv = dci.m_rv;
823  // refresh timer
824  std::map <uint16_t, DlHarqProcessesTimer_t>::iterator itHarqTimer = m_dlHarqProcessesTimer.find (rnti);
825  if (itHarqTimer== m_dlHarqProcessesTimer.end ())
826  {
827  NS_FATAL_ERROR ("Unable to find HARQ timer for RNTI " << (uint16_t)rnti);
828  }
829  (*itHarqTimer).second.at (harqId) = 0;
830  ret.m_buildDataList.push_back (newEl);
831  rntiAllocated.insert (rnti);
832  }
833  else
834  {
835  // update HARQ process status
836  NS_LOG_INFO (this << " HARQ received ACK for UE " << m_dlInfoListBuffered.at (i).m_rnti);
837  std::map <uint16_t, DlHarqProcessesStatus_t>::iterator it = m_dlHarqProcessesStatus.find (m_dlInfoListBuffered.at (i).m_rnti);
838  if (it == m_dlHarqProcessesStatus.end ())
839  {
840  NS_FATAL_ERROR ("No info find in HARQ buffer for UE " << m_dlInfoListBuffered.at (i).m_rnti);
841  }
842  (*it).second.at (m_dlInfoListBuffered.at (i).m_harqProcessId) = 0;
843  std::map <uint16_t, DlHarqRlcPduListBuffer_t>::iterator itRlcPdu = m_dlHarqProcessesRlcPduListBuffer.find (m_dlInfoListBuffered.at (i).m_rnti);
844  if (itRlcPdu == m_dlHarqProcessesRlcPduListBuffer.end ())
845  {
846  NS_FATAL_ERROR ("Unable to find RlcPdcList in HARQ buffer for RNTI " << m_dlInfoListBuffered.at (i).m_rnti);
847  }
848  for (uint16_t k = 0; k < (*itRlcPdu).second.size (); k++)
849  {
850  (*itRlcPdu).second.at (k).at (m_dlInfoListBuffered.at (i).m_harqProcessId).clear ();
851  }
852  }
853  }
854  m_dlInfoListBuffered.clear ();
855  m_dlInfoListBuffered = dlInfoListUntxed;
856 
857  if (rbgAllocatedNum == rbgNum)
858  {
859  // all the RBGs are already allocated -> exit
860  if ((ret.m_buildDataList.size () > 0) || (ret.m_buildRarList.size () > 0))
861  {
863  }
864  return;
865  }
866 
867 
868  std::map <uint16_t, tdbetsFlowPerf_t>::iterator it;
869  std::map <uint16_t, tdbetsFlowPerf_t>::iterator itMax = m_flowStatsDl.end ();
870  double metricMax = 0.0;
871  for (it = m_flowStatsDl.begin (); it != m_flowStatsDl.end (); it++)
872  {
873 
874  // check first what are channel conditions for this UE, if CQI!=0
875  std::map <uint16_t,uint8_t>::iterator itCqi;
876  itCqi = m_p10CqiRxed.find ((*it).first);
877  std::map <uint16_t,uint8_t>::iterator itTxMode;
878  itTxMode = m_uesTxMode.find ((*it).first);
879  if (itTxMode == m_uesTxMode.end ())
880  {
881  NS_FATAL_ERROR ("No Transmission Mode info on user " << (*it).first);
882  }
883  int nLayer = TransmissionModesLayers::TxMode2LayerNum ((*itTxMode).second);
884 
885  uint8_t cqiSum = 0;
886  for (uint8_t j = 0; j < nLayer; j++)
887  {
888  if (itCqi == m_p10CqiRxed.end ())
889  {
890  cqiSum += 1; // no info on this user -> lowest MCS
891  }
892  else
893  {
894  cqiSum = (*itCqi).second;
895  }
896  }
897  if (cqiSum == 0)
898  {
899  NS_LOG_INFO ("Skip this flow, CQI==0, rnti:"<<(*it).first);
900  continue;
901  }
902 
903  std::set <uint16_t>::iterator itRnti = rntiAllocated.find ((*it).first);
904  if ((itRnti != rntiAllocated.end ())||(!HarqProcessAvailability ((*it).first)))
905  {
906  // UE already allocated for HARQ or without HARQ process available -> drop it
907  if (itRnti != rntiAllocated.end ())
908  {
909  NS_LOG_DEBUG (this << " RNTI discared for HARQ tx" << (uint16_t)(*it).first);
910  }
911  if (!HarqProcessAvailability ((*it).first))
912  {
913  NS_LOG_DEBUG (this << " RNTI discared for HARQ id" << (uint16_t)(*it).first);
914  }
915  continue;
916  }
917 
918  double metric = 1 / (*it).second.lastAveragedThroughput;
919 
920  if (metric > metricMax)
921  {
922  metricMax = metric;
923  itMax = it;
924  }
925  } // end for m_flowStatsDl
926 
927 
928  if (itMax == m_flowStatsDl.end ())
929  {
930  // no UE available for downlink
931  return;
932  }
933  else
934  {
935  // assign all RBGs to this UE
936  std::vector <uint16_t> tempMap;
937  for (int i = 0; i < rbgNum; i++)
938  {
939  tempMap.push_back (i);
940  }
941  allocationMap.insert (std::pair <uint16_t, std::vector <uint16_t> > ((*itMax).first, tempMap));
942  }
943 
944 
945  // reset TTI stats of users
946  std::map <uint16_t, tdbetsFlowPerf_t>::iterator itStats;
947  for (itStats = m_flowStatsDl.begin (); itStats != m_flowStatsDl.end (); itStats++)
948  {
949  (*itStats).second.lastTtiBytesTrasmitted = 0;
950  }
951 
952  // generate the transmission opportunities by grouping the RBGs of the same RNTI and
953  // creating the correspondent DCIs
954  std::map <uint16_t, std::vector <uint16_t> >::iterator itMap = allocationMap.begin ();
955  while (itMap != allocationMap.end ())
956  {
957  // create new BuildDataListElement_s for this LC
959  newEl.m_rnti = (*itMap).first;
960  // create the DlDciListElement_s
961  DlDciListElement_s newDci;
962  newDci.m_rnti = (*itMap).first;
963  newDci.m_harqProcess = UpdateHarqProcessId ((*itMap).first);
964 
965  uint16_t lcActives = LcActivePerFlow ((*itMap).first);
966  NS_LOG_INFO (this << "Allocate user " << newEl.m_rnti << " rbg " << lcActives);
967  if (lcActives == 0)
968  {
969  // Set to max value, to avoid divide by 0 below
970  lcActives = (uint16_t)65535; // UINT16_MAX;
971  }
972  uint16_t RgbPerRnti = (*itMap).second.size ();
973  std::map <uint16_t,uint8_t>::iterator itCqi;
974  itCqi = m_p10CqiRxed.find ((*itMap).first);
975  std::map <uint16_t,uint8_t>::iterator itTxMode;
976  itTxMode = m_uesTxMode.find ((*itMap).first);
977  if (itTxMode == m_uesTxMode.end ())
978  {
979  NS_FATAL_ERROR ("No Transmission Mode info on user " << (*itMap).first);
980  }
981  int nLayer = TransmissionModesLayers::TxMode2LayerNum ((*itTxMode).second);
982 
983  uint32_t bytesTxed = 0;
984  for (uint8_t j = 0; j < nLayer; j++)
985  {
986  if (itCqi == m_p10CqiRxed.end ())
987  {
988  newDci.m_mcs.push_back (0); // no info on this user -> lowest MCS
989  }
990  else
991  {
992  newDci.m_mcs.push_back ( m_amc->GetMcsFromCqi ((*itCqi).second) );
993  }
994 
995  int tbSize = (m_amc->GetDlTbSizeFromMcs (newDci.m_mcs.at (j), RgbPerRnti * rbgSize) / 8); // (size of TB in bytes according to table 7.1.7.2.1-1 of 36.213)
996  newDci.m_tbsSize.push_back (tbSize);
997  bytesTxed += tbSize;
998  }
999 
1000  newDci.m_resAlloc = 0; // only allocation type 0 at this stage
1001  newDci.m_rbBitmap = 0; // TBD (32 bit bitmap see 7.1.6 of 36.213)
1002  uint32_t rbgMask = 0;
1003  for (uint16_t k = 0; k < (*itMap).second.size (); k++)
1004  {
1005  rbgMask = rbgMask + (0x1 << (*itMap).second.at (k));
1006  NS_LOG_INFO (this << " Allocated RBG " << (*itMap).second.at (k));
1007  }
1008  newDci.m_rbBitmap = rbgMask; // (32 bit bitmap see 7.1.6 of 36.213)
1009 
1010  // create the rlc PDUs -> equally divide resources among actives LCs
1011  std::map <LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator itBufReq;
1012  for (itBufReq = m_rlcBufferReq.begin (); itBufReq != m_rlcBufferReq.end (); itBufReq++)
1013  {
1014  if (((*itBufReq).first.m_rnti == (*itMap).first)
1015  && (((*itBufReq).second.m_rlcTransmissionQueueSize > 0)
1016  || ((*itBufReq).second.m_rlcRetransmissionQueueSize > 0)
1017  || ((*itBufReq).second.m_rlcStatusPduSize > 0) ))
1018  {
1019  std::vector <struct RlcPduListElement_s> newRlcPduLe;
1020  for (uint8_t j = 0; j < nLayer; j++)
1021  {
1022  RlcPduListElement_s newRlcEl;
1023  newRlcEl.m_logicalChannelIdentity = (*itBufReq).first.m_lcId;
1024  newRlcEl.m_size = newDci.m_tbsSize.at (j) / lcActives;
1025  NS_LOG_INFO (this << " LCID " << (uint32_t) newRlcEl.m_logicalChannelIdentity << " size " << newRlcEl.m_size << " layer " << (uint16_t)j);
1026  newRlcPduLe.push_back (newRlcEl);
1027  UpdateDlRlcBufferInfo (newDci.m_rnti, newRlcEl.m_logicalChannelIdentity, newRlcEl.m_size);
1028  if (m_harqOn == true)
1029  {
1030  // store RLC PDU list for HARQ
1031  std::map <uint16_t, DlHarqRlcPduListBuffer_t>::iterator itRlcPdu = m_dlHarqProcessesRlcPduListBuffer.find ((*itMap).first);
1032  if (itRlcPdu == m_dlHarqProcessesRlcPduListBuffer.end ())
1033  {
1034  NS_FATAL_ERROR ("Unable to find RlcPdcList in HARQ buffer for RNTI " << (*itMap).first);
1035  }
1036  (*itRlcPdu).second.at (j).at (newDci.m_harqProcess).push_back (newRlcEl);
1037  }
1038  }
1039  newEl.m_rlcPduList.push_back (newRlcPduLe);
1040  }
1041  if ((*itBufReq).first.m_rnti > (*itMap).first)
1042  {
1043  break;
1044  }
1045  }
1046  for (uint8_t j = 0; j < nLayer; j++)
1047  {
1048  newDci.m_ndi.push_back (1);
1049  newDci.m_rv.push_back (0);
1050  }
1051 
1052  newDci.m_tpc = 1; //1 is mapped to 0 in Accumulated Mode and to -1 in Absolute Mode
1053 
1054  newEl.m_dci = newDci;
1055 
1056  if (m_harqOn == true)
1057  {
1058  // store DCI for HARQ
1059  std::map <uint16_t, DlHarqProcessesDciBuffer_t>::iterator itDci = m_dlHarqProcessesDciBuffer.find (newEl.m_rnti);
1060  if (itDci == m_dlHarqProcessesDciBuffer.end ())
1061  {
1062  NS_FATAL_ERROR ("Unable to find RNTI entry in DCI HARQ buffer for RNTI " << newEl.m_rnti);
1063  }
1064  (*itDci).second.at (newDci.m_harqProcess) = newDci;
1065  // refresh timer
1066  std::map <uint16_t, DlHarqProcessesTimer_t>::iterator itHarqTimer = m_dlHarqProcessesTimer.find (newEl.m_rnti);
1067  if (itHarqTimer== m_dlHarqProcessesTimer.end ())
1068  {
1069  NS_FATAL_ERROR ("Unable to find HARQ timer for RNTI " << (uint16_t)newEl.m_rnti);
1070  }
1071  (*itHarqTimer).second.at (newDci.m_harqProcess) = 0;
1072  }
1073 
1074  // ...more parameters -> ignored in this version
1075 
1076  ret.m_buildDataList.push_back (newEl);
1077  // update UE stats
1078  std::map <uint16_t, tdbetsFlowPerf_t>::iterator it;
1079  it = m_flowStatsDl.find ((*itMap).first);
1080  if (it != m_flowStatsDl.end ())
1081  {
1082  (*it).second.lastTtiBytesTrasmitted = bytesTxed;
1083  NS_LOG_INFO (this << " UE total bytes txed " << (*it).second.lastTtiBytesTrasmitted);
1084 
1085 
1086  }
1087  else
1088  {
1089  NS_FATAL_ERROR (this << " No Stats for this allocated UE");
1090  }
1091 
1092  itMap++;
1093  } // end while allocation
1094  ret.m_nrOfPdcchOfdmSymbols = 1;
1095 
1096 
1097  // update UEs stats
1098  NS_LOG_INFO (this << " Update UEs statistics");
1099  for (itStats = m_flowStatsDl.begin (); itStats != m_flowStatsDl.end (); itStats++)
1100  {
1101  (*itStats).second.totalBytesTransmitted += (*itStats).second.lastTtiBytesTrasmitted;
1102  // update average throughput (see eq. 12.3 of Sec 12.3.1.2 of LTE – The UMTS Long Term Evolution, Ed Wiley)
1103  (*itStats).second.lastAveragedThroughput = ((1.0 - (1.0 / m_timeWindow)) * (*itStats).second.lastAveragedThroughput) + ((1.0 / m_timeWindow) * (double)((*itStats).second.lastTtiBytesTrasmitted / 0.001));
1104  NS_LOG_INFO (this << " UE total bytes " << (*itStats).second.totalBytesTransmitted);
1105  NS_LOG_INFO (this << " UE average throughput " << (*itStats).second.lastAveragedThroughput);
1106  (*itStats).second.lastTtiBytesTrasmitted = 0;
1107  }
1108 
1110 
1111 
1112  return;
1113 }
1114 
1115 void
1117 {
1118  NS_LOG_FUNCTION (this);
1119 
1120  m_rachList = params.m_rachList;
1121 
1122  return;
1123 }
1124 
1125 void
1127 {
1128  NS_LOG_FUNCTION (this);
1129 
1130  for (unsigned int i = 0; i < params.m_cqiList.size (); i++)
1131  {
1132  if ( params.m_cqiList.at (i).m_cqiType == CqiListElement_s::P10 )
1133  {
1134  NS_LOG_LOGIC ("wideband CQI " << (uint32_t) params.m_cqiList.at (i).m_wbCqi.at (0) << " reported");
1135  std::map <uint16_t,uint8_t>::iterator it;
1136  uint16_t rnti = params.m_cqiList.at (i).m_rnti;
1137  it = m_p10CqiRxed.find (rnti);
1138  if (it == m_p10CqiRxed.end ())
1139  {
1140  // create the new entry
1141  m_p10CqiRxed.insert ( std::pair<uint16_t, uint8_t > (rnti, params.m_cqiList.at (i).m_wbCqi.at (0)) ); // only codeword 0 at this stage (SISO)
1142  // generate correspondent timer
1143  m_p10CqiTimers.insert ( std::pair<uint16_t, uint32_t > (rnti, m_cqiTimersThreshold));
1144  }
1145  else
1146  {
1147  // update the CQI value and refresh correspondent timer
1148  (*it).second = params.m_cqiList.at (i).m_wbCqi.at (0);
1149  // update correspondent timer
1150  std::map <uint16_t,uint32_t>::iterator itTimers;
1151  itTimers = m_p10CqiTimers.find (rnti);
1152  (*itTimers).second = m_cqiTimersThreshold;
1153  }
1154  }
1155  else if ( params.m_cqiList.at (i).m_cqiType == CqiListElement_s::A30 )
1156  {
1157  // subband CQI reporting high layer configured
1158  std::map <uint16_t,SbMeasResult_s>::iterator it;
1159  uint16_t rnti = params.m_cqiList.at (i).m_rnti;
1160  it = m_a30CqiRxed.find (rnti);
1161  if (it == m_a30CqiRxed.end ())
1162  {
1163  // create the new entry
1164  m_a30CqiRxed.insert ( std::pair<uint16_t, SbMeasResult_s > (rnti, params.m_cqiList.at (i).m_sbMeasResult) );
1165  m_a30CqiTimers.insert ( std::pair<uint16_t, uint32_t > (rnti, m_cqiTimersThreshold));
1166  }
1167  else
1168  {
1169  // update the CQI value and refresh correspondent timer
1170  (*it).second = params.m_cqiList.at (i).m_sbMeasResult;
1171  std::map <uint16_t,uint32_t>::iterator itTimers;
1172  itTimers = m_a30CqiTimers.find (rnti);
1173  (*itTimers).second = m_cqiTimersThreshold;
1174  }
1175  }
1176  else
1177  {
1178  NS_LOG_ERROR (this << " CQI type unknown");
1179  }
1180  }
1181 
1182  return;
1183 }
1184 
1185 
1186 double
1187 TdBetFfMacScheduler::EstimateUlSinr (uint16_t rnti, uint16_t rb)
1188 {
1189  std::map <uint16_t, std::vector <double> >::iterator itCqi = m_ueCqi.find (rnti);
1190  if (itCqi == m_ueCqi.end ())
1191  {
1192  // no cqi info about this UE
1193  return (NO_SINR);
1194 
1195  }
1196  else
1197  {
1198  // take the average SINR value among the available
1199  double sinrSum = 0;
1200  unsigned int sinrNum = 0;
1201  for (uint32_t i = 0; i < m_cschedCellConfig.m_ulBandwidth; i++)
1202  {
1203  double sinr = (*itCqi).second.at (i);
1204  if (sinr != NO_SINR)
1205  {
1206  sinrSum += sinr;
1207  sinrNum++;
1208  }
1209  }
1210  double estimatedSinr = (sinrNum > 0) ? (sinrSum / sinrNum) : DBL_MAX;
1211  // store the value
1212  (*itCqi).second.at (rb) = estimatedSinr;
1213  return (estimatedSinr);
1214  }
1215 }
1216 
1217 void
1219 {
1220  NS_LOG_FUNCTION (this << " UL - Frame no. " << (params.m_sfnSf >> 4) << " subframe no. " << (0xF & params.m_sfnSf) << " size " << params.m_ulInfoList.size ());
1221 
1222  RefreshUlCqiMaps ();
1223 
1224  // Generate RBs map
1226  std::vector <bool> rbMap;
1227  uint16_t rbAllocatedNum = 0;
1228  std::set <uint16_t> rntiAllocated;
1229  std::vector <uint16_t> rbgAllocationMap;
1230  // update with RACH allocation map
1231  rbgAllocationMap = m_rachAllocationMap;
1232  //rbgAllocationMap.resize (m_cschedCellConfig.m_ulBandwidth, 0);
1233  m_rachAllocationMap.clear ();
1235 
1236  rbMap.resize (m_cschedCellConfig.m_ulBandwidth, false);
1237  // remove RACH allocation
1238  for (uint16_t i = 0; i < m_cschedCellConfig.m_ulBandwidth; i++)
1239  {
1240  if (rbgAllocationMap.at (i) != 0)
1241  {
1242  rbMap.at (i) = true;
1243  NS_LOG_DEBUG (this << " Allocated for RACH " << i);
1244  }
1245  }
1246 
1247 
1248  if (m_harqOn == true)
1249  {
1250  // Process UL HARQ feedback
1251  for (uint16_t i = 0; i < params.m_ulInfoList.size (); i++)
1252  {
1253  if (params.m_ulInfoList.at (i).m_receptionStatus == UlInfoListElement_s::NotOk)
1254  {
1255  // retx correspondent block: retrieve the UL-DCI
1256  uint16_t rnti = params.m_ulInfoList.at (i).m_rnti;
1257  std::map <uint16_t, uint8_t>::iterator itProcId = m_ulHarqCurrentProcessId.find (rnti);
1258  if (itProcId == m_ulHarqCurrentProcessId.end ())
1259  {
1260  NS_LOG_ERROR ("No info find in HARQ buffer for UE (might change eNB) " << rnti);
1261  }
1262  uint8_t harqId = (uint8_t)((*itProcId).second - HARQ_PERIOD) % HARQ_PROC_NUM;
1263  NS_LOG_INFO (this << " UL-HARQ retx RNTI " << rnti << " harqId " << (uint16_t)harqId << " i " << i << " size " << params.m_ulInfoList.size ());
1264  std::map <uint16_t, UlHarqProcessesDciBuffer_t>::iterator itHarq = m_ulHarqProcessesDciBuffer.find (rnti);
1265  if (itHarq == m_ulHarqProcessesDciBuffer.end ())
1266  {
1267  NS_LOG_ERROR ("No info find in HARQ buffer for UE (might change eNB) " << rnti);
1268  continue;
1269  }
1270  UlDciListElement_s dci = (*itHarq).second.at (harqId);
1271  std::map <uint16_t, UlHarqProcessesStatus_t>::iterator itStat = m_ulHarqProcessesStatus.find (rnti);
1272  if (itStat == m_ulHarqProcessesStatus.end ())
1273  {
1274  NS_LOG_ERROR ("No info find in HARQ buffer for UE (might change eNB) " << rnti);
1275  }
1276  if ((*itStat).second.at (harqId) >= 3)
1277  {
1278  NS_LOG_INFO ("Max number of retransmissions reached (UL)-> drop process");
1279  continue;
1280  }
1281  bool free = true;
1282  for (int j = dci.m_rbStart; j < dci.m_rbStart + dci.m_rbLen; j++)
1283  {
1284  if (rbMap.at (j) == true)
1285  {
1286  free = false;
1287  NS_LOG_INFO (this << " BUSY " << j);
1288  }
1289  }
1290  if (free)
1291  {
1292  // retx on the same RBs
1293  for (int j = dci.m_rbStart; j < dci.m_rbStart + dci.m_rbLen; j++)
1294  {
1295  rbMap.at (j) = true;
1296  rbgAllocationMap.at (j) = dci.m_rnti;
1297  NS_LOG_INFO ("\tRB " << j);
1298  rbAllocatedNum++;
1299  }
1300  NS_LOG_INFO (this << " Send retx in the same RBs " << (uint16_t)dci.m_rbStart << " to " << dci.m_rbStart + dci.m_rbLen << " RV " << (*itStat).second.at (harqId) + 1);
1301  }
1302  else
1303  {
1304  NS_LOG_INFO ("Cannot allocate retx due to RACH allocations for UE " << rnti);
1305  continue;
1306  }
1307  dci.m_ndi = 0;
1308  // Update HARQ buffers with new HarqId
1309  (*itStat).second.at ((*itProcId).second) = (*itStat).second.at (harqId) + 1;
1310  (*itStat).second.at (harqId) = 0;
1311  (*itHarq).second.at ((*itProcId).second) = dci;
1312  ret.m_dciList.push_back (dci);
1313  rntiAllocated.insert (dci.m_rnti);
1314  }
1315  else
1316  {
1317  NS_LOG_INFO (this << " HARQ-ACK feedback from RNTI " << params.m_ulInfoList.at (i).m_rnti);
1318  }
1319  }
1320  }
1321 
1322  std::map <uint16_t,uint32_t>::iterator it;
1323  int nflows = 0;
1324 
1325  for (it = m_ceBsrRxed.begin (); it != m_ceBsrRxed.end (); it++)
1326  {
1327  std::set <uint16_t>::iterator itRnti = rntiAllocated.find ((*it).first);
1328  // select UEs with queues not empty and not yet allocated for HARQ
1329  if (((*it).second > 0)&&(itRnti == rntiAllocated.end ()))
1330  {
1331  nflows++;
1332  }
1333  }
1334 
1335  if (nflows == 0)
1336  {
1337  if (ret.m_dciList.size () > 0)
1338  {
1339  m_allocationMaps.insert (std::pair <uint16_t, std::vector <uint16_t> > (params.m_sfnSf, rbgAllocationMap));
1341  }
1342 
1343  return; // no flows to be scheduled
1344  }
1345 
1346 
1347  // Divide the remaining resources equally among the active users starting from the subsequent one served last scheduling trigger
1348  uint16_t rbPerFlow = (m_cschedCellConfig.m_ulBandwidth) / (nflows + rntiAllocated.size ());
1349  if (rbPerFlow < 3)
1350  {
1351  rbPerFlow = 3; // at least 3 rbg per flow (till available resource) to ensure TxOpportunity >= 7 bytes
1352  }
1353  int rbAllocated = 0;
1354 
1355  std::map <uint16_t, tdbetsFlowPerf_t>::iterator itStats;
1356  if (m_nextRntiUl != 0)
1357  {
1358  for (it = m_ceBsrRxed.begin (); it != m_ceBsrRxed.end (); it++)
1359  {
1360  if ((*it).first == m_nextRntiUl)
1361  {
1362  break;
1363  }
1364  }
1365  if (it == m_ceBsrRxed.end ())
1366  {
1367  NS_LOG_ERROR (this << " no user found");
1368  }
1369  }
1370  else
1371  {
1372  it = m_ceBsrRxed.begin ();
1373  m_nextRntiUl = (*it).first;
1374  }
1375  do
1376  {
1377  std::set <uint16_t>::iterator itRnti = rntiAllocated.find ((*it).first);
1378  if ((itRnti != rntiAllocated.end ())||((*it).second == 0))
1379  {
1380  // UE already allocated for UL-HARQ -> skip it
1381  NS_LOG_DEBUG (this << " UE already allocated in HARQ -> discared, RNTI " << (*it).first);
1382  it++;
1383  if (it == m_ceBsrRxed.end ())
1384  {
1385  // restart from the first
1386  it = m_ceBsrRxed.begin ();
1387  }
1388  continue;
1389  }
1390  if (rbAllocated + rbPerFlow - 1 > m_cschedCellConfig.m_ulBandwidth)
1391  {
1392  // limit to physical resources last resource assignment
1393  rbPerFlow = m_cschedCellConfig.m_ulBandwidth - rbAllocated;
1394  // at least 3 rbg per flow to ensure TxOpportunity >= 7 bytes
1395  if (rbPerFlow < 3)
1396  {
1397  // terminate allocation
1398  rbPerFlow = 0;
1399  }
1400  }
1401 
1402  UlDciListElement_s uldci;
1403  uldci.m_rnti = (*it).first;
1404  uldci.m_rbLen = rbPerFlow;
1405  bool allocated = false;
1406  NS_LOG_INFO (this << " RB Allocated " << rbAllocated << " rbPerFlow " << rbPerFlow << " flows " << nflows);
1407  while ((!allocated)&&((rbAllocated + rbPerFlow - m_cschedCellConfig.m_ulBandwidth) < 1) && (rbPerFlow != 0))
1408  {
1409  // check availability
1410  bool free = true;
1411  for (uint16_t j = rbAllocated; j < rbAllocated + rbPerFlow; j++)
1412  {
1413  if (rbMap.at (j) == true)
1414  {
1415  free = false;
1416  break;
1417  }
1418  }
1419  if (free)
1420  {
1421  uldci.m_rbStart = rbAllocated;
1422 
1423  for (uint16_t j = rbAllocated; j < rbAllocated + rbPerFlow; j++)
1424  {
1425  rbMap.at (j) = true;
1426  // store info on allocation for managing ul-cqi interpretation
1427  rbgAllocationMap.at (j) = (*it).first;
1428  }
1429  rbAllocated += rbPerFlow;
1430  allocated = true;
1431  break;
1432  }
1433  rbAllocated++;
1434  if (rbAllocated + rbPerFlow - 1 > m_cschedCellConfig.m_ulBandwidth)
1435  {
1436  // limit to physical resources last resource assignment
1437  rbPerFlow = m_cschedCellConfig.m_ulBandwidth - rbAllocated;
1438  // at least 3 rbg per flow to ensure TxOpportunity >= 7 bytes
1439  if (rbPerFlow < 3)
1440  {
1441  // terminate allocation
1442  rbPerFlow = 0;
1443  }
1444  }
1445  }
1446  if (!allocated)
1447  {
1448  // unable to allocate new resource: finish scheduling
1449  m_nextRntiUl = (*it).first;
1450  if (ret.m_dciList.size () > 0)
1451  {
1453  }
1454  m_allocationMaps.insert (std::pair <uint16_t, std::vector <uint16_t> > (params.m_sfnSf, rbgAllocationMap));
1455  return;
1456  }
1457 
1458 
1459 
1460  std::map <uint16_t, std::vector <double> >::iterator itCqi = m_ueCqi.find ((*it).first);
1461  int cqi = 0;
1462  if (itCqi == m_ueCqi.end ())
1463  {
1464  // no cqi info about this UE
1465  uldci.m_mcs = 0; // MCS 0 -> UL-AMC TBD
1466  }
1467  else
1468  {
1469  // take the lowest CQI value (worst RB)
1470  double minSinr = (*itCqi).second.at (uldci.m_rbStart);
1471  if (minSinr == NO_SINR)
1472  {
1473  minSinr = EstimateUlSinr ((*it).first, uldci.m_rbStart);
1474  }
1475  for (uint16_t i = uldci.m_rbStart; i < uldci.m_rbStart + uldci.m_rbLen; i++)
1476  {
1477  double sinr = (*itCqi).second.at (i);
1478  if (sinr == NO_SINR)
1479  {
1480  sinr = EstimateUlSinr ((*it).first, i);
1481  }
1482  if (sinr < minSinr)
1483  {
1484  minSinr = sinr;
1485  }
1486  }
1487 
1488  // translate SINR -> cqi: WILD ACK: same as DL
1489  double s = log2 ( 1 + (
1490  std::pow (10, minSinr / 10 ) /
1491  ( (-std::log (5.0 * 0.00005 )) / 1.5) ));
1492  cqi = m_amc->GetCqiFromSpectralEfficiency (s);
1493  if (cqi == 0)
1494  {
1495  it++;
1496  if (it == m_ceBsrRxed.end ())
1497  {
1498  // restart from the first
1499  it = m_ceBsrRxed.begin ();
1500  }
1501  NS_LOG_DEBUG (this << " UE discared for CQI=0, RNTI " << uldci.m_rnti);
1502  // remove UE from allocation map
1503  for (uint16_t i = uldci.m_rbStart; i < uldci.m_rbStart + uldci.m_rbLen; i++)
1504  {
1505  rbgAllocationMap.at (i) = 0;
1506  }
1507  continue; // CQI == 0 means "out of range" (see table 7.2.3-1 of 36.213)
1508  }
1509  uldci.m_mcs = m_amc->GetMcsFromCqi (cqi);
1510  }
1511 
1512  uldci.m_tbSize = (m_amc->GetUlTbSizeFromMcs (uldci.m_mcs, rbPerFlow) / 8);
1513  UpdateUlRlcBufferInfo (uldci.m_rnti, uldci.m_tbSize);
1514  uldci.m_ndi = 1;
1515  uldci.m_cceIndex = 0;
1516  uldci.m_aggrLevel = 1;
1517  uldci.m_ueTxAntennaSelection = 3; // antenna selection OFF
1518  uldci.m_hopping = false;
1519  uldci.m_n2Dmrs = 0;
1520  uldci.m_tpc = 0; // no power control
1521  uldci.m_cqiRequest = false; // only period CQI at this stage
1522  uldci.m_ulIndex = 0; // TDD parameter
1523  uldci.m_dai = 1; // TDD parameter
1524  uldci.m_freqHopping = 0;
1525  uldci.m_pdcchPowerOffset = 0; // not used
1526  ret.m_dciList.push_back (uldci);
1527  // store DCI for HARQ_PERIOD
1528  uint8_t harqId = 0;
1529  if (m_harqOn == true)
1530  {
1531  std::map <uint16_t, uint8_t>::iterator itProcId;
1532  itProcId = m_ulHarqCurrentProcessId.find (uldci.m_rnti);
1533  if (itProcId == m_ulHarqCurrentProcessId.end ())
1534  {
1535  NS_FATAL_ERROR ("No info find in HARQ buffer for UE " << uldci.m_rnti);
1536  }
1537  harqId = (*itProcId).second;
1538  std::map <uint16_t, UlHarqProcessesDciBuffer_t>::iterator itDci = m_ulHarqProcessesDciBuffer.find (uldci.m_rnti);
1539  if (itDci == m_ulHarqProcessesDciBuffer.end ())
1540  {
1541  NS_FATAL_ERROR ("Unable to find RNTI entry in UL DCI HARQ buffer for RNTI " << uldci.m_rnti);
1542  }
1543  (*itDci).second.at (harqId) = uldci;
1544  // Update HARQ process status (RV 0)
1545  std::map <uint16_t, UlHarqProcessesStatus_t>::iterator itStat = m_ulHarqProcessesStatus.find (uldci.m_rnti);
1546  if (itStat == m_ulHarqProcessesStatus.end ())
1547  {
1548  NS_LOG_ERROR ("No info find in HARQ buffer for UE (might change eNB) " << uldci.m_rnti);
1549  }
1550  (*itStat).second.at (harqId) = 0;
1551  }
1552 
1553  NS_LOG_INFO (this << " UE Allocation RNTI " << (*it).first << " startPRB " << (uint32_t)uldci.m_rbStart << " nPRB " << (uint32_t)uldci.m_rbLen << " CQI " << cqi << " MCS " << (uint32_t)uldci.m_mcs << " TBsize " << uldci.m_tbSize << " RbAlloc " << rbAllocated << " harqId " << (uint16_t)harqId);
1554 
1555  // update TTI UE stats
1556  itStats = m_flowStatsUl.find ((*it).first);
1557  if (itStats != m_flowStatsUl.end ())
1558  {
1559  (*itStats).second.lastTtiBytesTrasmitted = uldci.m_tbSize;
1560  }
1561  else
1562  {
1563  NS_LOG_DEBUG (this << " No Stats for this allocated UE");
1564  }
1565 
1566 
1567  it++;
1568  if (it == m_ceBsrRxed.end ())
1569  {
1570  // restart from the first
1571  it = m_ceBsrRxed.begin ();
1572  }
1573  if ((rbAllocated == m_cschedCellConfig.m_ulBandwidth) || (rbPerFlow == 0))
1574  {
1575  // Stop allocation: no more PRBs
1576  m_nextRntiUl = (*it).first;
1577  break;
1578  }
1579  }
1580  while (((*it).first != m_nextRntiUl)&&(rbPerFlow!=0));
1581 
1582 
1583  // Update global UE stats
1584  // update UEs stats
1585  for (itStats = m_flowStatsUl.begin (); itStats != m_flowStatsUl.end (); itStats++)
1586  {
1587  (*itStats).second.totalBytesTransmitted += (*itStats).second.lastTtiBytesTrasmitted;
1588  // update average throughput (see eq. 12.3 of Sec 12.3.1.2 of LTE – The UMTS Long Term Evolution, Ed Wiley)
1589  (*itStats).second.lastAveragedThroughput = ((1.0 - (1.0 / m_timeWindow)) * (*itStats).second.lastAveragedThroughput) + ((1.0 / m_timeWindow) * (double)((*itStats).second.lastTtiBytesTrasmitted / 0.001));
1590  NS_LOG_INFO (this << " UE total bytes " << (*itStats).second.totalBytesTransmitted);
1591  NS_LOG_INFO (this << " UE average throughput " << (*itStats).second.lastAveragedThroughput);
1592  (*itStats).second.lastTtiBytesTrasmitted = 0;
1593  }
1594  m_allocationMaps.insert (std::pair <uint16_t, std::vector <uint16_t> > (params.m_sfnSf, rbgAllocationMap));
1596 
1597  return;
1598 }
1599 
1600 void
1602 {
1603  NS_LOG_FUNCTION (this);
1604  return;
1605 }
1606 
1607 void
1609 {
1610  NS_LOG_FUNCTION (this);
1611  return;
1612 }
1613 
1614 void
1616 {
1617  NS_LOG_FUNCTION (this);
1618 
1619  std::map <uint16_t,uint32_t>::iterator it;
1620 
1621  for (unsigned int i = 0; i < params.m_macCeList.size (); i++)
1622  {
1623  if ( params.m_macCeList.at (i).m_macCeType == MacCeListElement_s::BSR )
1624  {
1625  // buffer status report
1626  // note that this scheduler does not differentiate the
1627  // allocation according to which LCGs have more/less bytes
1628  // to send.
1629  // Hence the BSR of different LCGs are just summed up to get
1630  // a total queue size that is used for allocation purposes.
1631 
1632  uint32_t buffer = 0;
1633  for (uint8_t lcg = 0; lcg < 4; ++lcg)
1634  {
1635  uint8_t bsrId = params.m_macCeList.at (i).m_macCeValue.m_bufferStatus.at (lcg);
1636  buffer += BufferSizeLevelBsr::BsrId2BufferSize (bsrId);
1637  }
1638 
1639  uint16_t rnti = params.m_macCeList.at (i).m_rnti;
1640  NS_LOG_LOGIC (this << "RNTI=" << rnti << " buffer=" << buffer);
1641  it = m_ceBsrRxed.find (rnti);
1642  if (it == m_ceBsrRxed.end ())
1643  {
1644  // create the new entry
1645  m_ceBsrRxed.insert ( std::pair<uint16_t, uint32_t > (rnti, buffer));
1646  }
1647  else
1648  {
1649  // update the buffer size value
1650  (*it).second = buffer;
1651  }
1652  }
1653  }
1654 
1655  return;
1656 }
1657 
1658 void
1660 {
1661  NS_LOG_FUNCTION (this);
1662 // retrieve the allocation for this subframe
1663  switch (m_ulCqiFilter)
1664  {
1666  {
1667  // filter all the CQIs that are not SRS based
1668  if (params.m_ulCqi.m_type != UlCqi_s::SRS)
1669  {
1670  return;
1671  }
1672  }
1673  break;
1675  {
1676  // filter all the CQIs that are not SRS based
1677  if (params.m_ulCqi.m_type != UlCqi_s::PUSCH)
1678  {
1679  return;
1680  }
1681  }
1683  break;
1684 
1685  default:
1686  NS_FATAL_ERROR ("Unknown UL CQI type");
1687  }
1688 
1689  switch (params.m_ulCqi.m_type)
1690  {
1691  case UlCqi_s::PUSCH:
1692  {
1693  std::map <uint16_t, std::vector <uint16_t> >::iterator itMap;
1694  std::map <uint16_t, std::vector <double> >::iterator itCqi;
1695  NS_LOG_DEBUG (this << " Collect PUSCH CQIs of Frame no. " << (params.m_sfnSf >> 4) << " subframe no. " << (0xF & params.m_sfnSf));
1696  itMap = m_allocationMaps.find (params.m_sfnSf);
1697  if (itMap == m_allocationMaps.end ())
1698  {
1699  return;
1700  }
1701  for (uint32_t i = 0; i < (*itMap).second.size (); i++)
1702  {
1703  // convert from fixed point notation Sxxxxxxxxxxx.xxx to double
1704  double sinr = LteFfConverter::fpS11dot3toDouble (params.m_ulCqi.m_sinr.at (i));
1705  itCqi = m_ueCqi.find ((*itMap).second.at (i));
1706  if (itCqi == m_ueCqi.end ())
1707  {
1708  // create a new entry
1709  std::vector <double> newCqi;
1710  for (uint32_t j = 0; j < m_cschedCellConfig.m_ulBandwidth; j++)
1711  {
1712  if (i == j)
1713  {
1714  newCqi.push_back (sinr);
1715  }
1716  else
1717  {
1718  // initialize with NO_SINR value.
1719  newCqi.push_back (NO_SINR);
1720  }
1721 
1722  }
1723  m_ueCqi.insert (std::pair <uint16_t, std::vector <double> > ((*itMap).second.at (i), newCqi));
1724  // generate correspondent timer
1725  m_ueCqiTimers.insert (std::pair <uint16_t, uint32_t > ((*itMap).second.at (i), m_cqiTimersThreshold));
1726  }
1727  else
1728  {
1729  // update the value
1730  (*itCqi).second.at (i) = sinr;
1731  NS_LOG_DEBUG (this << " RNTI " << (*itMap).second.at (i) << " RB " << i << " SINR " << sinr);
1732  // update correspondent timer
1733  std::map <uint16_t, uint32_t>::iterator itTimers;
1734  itTimers = m_ueCqiTimers.find ((*itMap).second.at (i));
1735  (*itTimers).second = m_cqiTimersThreshold;
1736 
1737  }
1738 
1739  }
1740  // remove obsolete info on allocation
1741  m_allocationMaps.erase (itMap);
1742  }
1743  break;
1744  case UlCqi_s::SRS:
1745  {
1746  // get the RNTI from vendor specific parameters
1747  uint16_t rnti = 0;
1748  NS_ASSERT (params.m_vendorSpecificList.size () > 0);
1749  for (uint16_t i = 0; i < params.m_vendorSpecificList.size (); i++)
1750  {
1751  if (params.m_vendorSpecificList.at (i).m_type == SRS_CQI_RNTI_VSP)
1752  {
1753  Ptr<SrsCqiRntiVsp> vsp = DynamicCast<SrsCqiRntiVsp> (params.m_vendorSpecificList.at (i).m_value);
1754  rnti = vsp->GetRnti ();
1755  }
1756  }
1757  std::map <uint16_t, std::vector <double> >::iterator itCqi;
1758  itCqi = m_ueCqi.find (rnti);
1759  if (itCqi == m_ueCqi.end ())
1760  {
1761  // create a new entry
1762  std::vector <double> newCqi;
1763  for (uint32_t j = 0; j < m_cschedCellConfig.m_ulBandwidth; j++)
1764  {
1765  double sinr = LteFfConverter::fpS11dot3toDouble (params.m_ulCqi.m_sinr.at (j));
1766  newCqi.push_back (sinr);
1767  NS_LOG_INFO (this << " RNTI " << rnti << " new SRS-CQI for RB " << j << " value " << sinr);
1768 
1769  }
1770  m_ueCqi.insert (std::pair <uint16_t, std::vector <double> > (rnti, newCqi));
1771  // generate correspondent timer
1772  m_ueCqiTimers.insert (std::pair <uint16_t, uint32_t > (rnti, m_cqiTimersThreshold));
1773  }
1774  else
1775  {
1776  // update the values
1777  for (uint32_t j = 0; j < m_cschedCellConfig.m_ulBandwidth; j++)
1778  {
1779  double sinr = LteFfConverter::fpS11dot3toDouble (params.m_ulCqi.m_sinr.at (j));
1780  (*itCqi).second.at (j) = sinr;
1781  NS_LOG_INFO (this << " RNTI " << rnti << " update SRS-CQI for RB " << j << " value " << sinr);
1782  }
1783  // update correspondent timer
1784  std::map <uint16_t, uint32_t>::iterator itTimers;
1785  itTimers = m_ueCqiTimers.find (rnti);
1786  (*itTimers).second = m_cqiTimersThreshold;
1787 
1788  }
1789 
1790 
1791  }
1792  break;
1793  case UlCqi_s::PUCCH_1:
1794  case UlCqi_s::PUCCH_2:
1795  case UlCqi_s::PRACH:
1796  {
1797  NS_FATAL_ERROR ("TdBetFfMacScheduler supports only PUSCH and SRS UL-CQIs");
1798  }
1799  break;
1800  default:
1801  NS_FATAL_ERROR ("Unknown type of UL-CQI");
1802  }
1803  return;
1804 }
1805 
1806 void
1808 {
1809  // refresh DL CQI P01 Map
1810  std::map <uint16_t,uint32_t>::iterator itP10 = m_p10CqiTimers.begin ();
1811  while (itP10 != m_p10CqiTimers.end ())
1812  {
1813  NS_LOG_INFO (this << " P10-CQI for user " << (*itP10).first << " is " << (uint32_t)(*itP10).second << " thr " << (uint32_t)m_cqiTimersThreshold);
1814  if ((*itP10).second == 0)
1815  {
1816  // delete correspondent entries
1817  std::map <uint16_t,uint8_t>::iterator itMap = m_p10CqiRxed.find ((*itP10).first);
1818  NS_ASSERT_MSG (itMap != m_p10CqiRxed.end (), " Does not find CQI report for user " << (*itP10).first);
1819  NS_LOG_INFO (this << " P10-CQI expired for user " << (*itP10).first);
1820  m_p10CqiRxed.erase (itMap);
1821  std::map <uint16_t,uint32_t>::iterator temp = itP10;
1822  itP10++;
1823  m_p10CqiTimers.erase (temp);
1824  }
1825  else
1826  {
1827  (*itP10).second--;
1828  itP10++;
1829  }
1830  }
1831 
1832  // refresh DL CQI A30 Map
1833  std::map <uint16_t,uint32_t>::iterator itA30 = m_a30CqiTimers.begin ();
1834  while (itA30 != m_a30CqiTimers.end ())
1835  {
1836  NS_LOG_INFO (this << " A30-CQI for user " << (*itA30).first << " is " << (uint32_t)(*itA30).second << " thr " << (uint32_t)m_cqiTimersThreshold);
1837  if ((*itA30).second == 0)
1838  {
1839  // delete correspondent entries
1840  std::map <uint16_t,SbMeasResult_s>::iterator itMap = m_a30CqiRxed.find ((*itA30).first);
1841  NS_ASSERT_MSG (itMap != m_a30CqiRxed.end (), " Does not find CQI report for user " << (*itA30).first);
1842  NS_LOG_INFO (this << " A30-CQI expired for user " << (*itA30).first);
1843  m_a30CqiRxed.erase (itMap);
1844  std::map <uint16_t,uint32_t>::iterator temp = itA30;
1845  itA30++;
1846  m_a30CqiTimers.erase (temp);
1847  }
1848  else
1849  {
1850  (*itA30).second--;
1851  itA30++;
1852  }
1853  }
1854 
1855  return;
1856 }
1857 
1858 
1859 void
1861 {
1862  // refresh UL CQI Map
1863  std::map <uint16_t,uint32_t>::iterator itUl = m_ueCqiTimers.begin ();
1864  while (itUl != m_ueCqiTimers.end ())
1865  {
1866  NS_LOG_INFO (this << " UL-CQI for user " << (*itUl).first << " is " << (uint32_t)(*itUl).second << " thr " << (uint32_t)m_cqiTimersThreshold);
1867  if ((*itUl).second == 0)
1868  {
1869  // delete correspondent entries
1870  std::map <uint16_t, std::vector <double> >::iterator itMap = m_ueCqi.find ((*itUl).first);
1871  NS_ASSERT_MSG (itMap != m_ueCqi.end (), " Does not find CQI report for user " << (*itUl).first);
1872  NS_LOG_INFO (this << " UL-CQI exired for user " << (*itUl).first);
1873  (*itMap).second.clear ();
1874  m_ueCqi.erase (itMap);
1875  std::map <uint16_t,uint32_t>::iterator temp = itUl;
1876  itUl++;
1877  m_ueCqiTimers.erase (temp);
1878  }
1879  else
1880  {
1881  (*itUl).second--;
1882  itUl++;
1883  }
1884  }
1885 
1886  return;
1887 }
1888 
1889 void
1890 TdBetFfMacScheduler::UpdateDlRlcBufferInfo (uint16_t rnti, uint8_t lcid, uint16_t size)
1891 {
1892  std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it;
1893  LteFlowId_t flow (rnti, lcid);
1894  it = m_rlcBufferReq.find (flow);
1895  if (it != m_rlcBufferReq.end ())
1896  {
1897  NS_LOG_INFO (this << " UE " << rnti << " LC " << (uint16_t)lcid << " txqueue " << (*it).second.m_rlcTransmissionQueueSize << " retxqueue " << (*it).second.m_rlcRetransmissionQueueSize << " status " << (*it).second.m_rlcStatusPduSize << " decrease " << size);
1898  // Update queues: RLC tx order Status, ReTx, Tx
1899  // Update status queue
1900  if (((*it).second.m_rlcStatusPduSize > 0) && (size >= (*it).second.m_rlcStatusPduSize))
1901  {
1902  (*it).second.m_rlcStatusPduSize = 0;
1903  }
1904  else if (((*it).second.m_rlcRetransmissionQueueSize > 0) && (size >= (*it).second.m_rlcRetransmissionQueueSize))
1905  {
1906  (*it).second.m_rlcRetransmissionQueueSize = 0;
1907  }
1908  else if ((*it).second.m_rlcTransmissionQueueSize > 0)
1909  {
1910  uint32_t rlcOverhead;
1911  if (lcid == 1)
1912  {
1913  // for SRB1 (using RLC AM) it's better to
1914  // overestimate RLC overhead rather than
1915  // underestimate it and risk unneeded
1916  // segmentation which increases delay
1917  rlcOverhead = 4;
1918  }
1919  else
1920  {
1921  // minimum RLC overhead due to header
1922  rlcOverhead = 2;
1923  }
1924  // update transmission queue
1925  if ((*it).second.m_rlcTransmissionQueueSize <= size - rlcOverhead)
1926  {
1927  (*it).second.m_rlcTransmissionQueueSize = 0;
1928  }
1929  else
1930  {
1931  (*it).second.m_rlcTransmissionQueueSize -= size - rlcOverhead;
1932  }
1933  }
1934  }
1935  else
1936  {
1937  NS_LOG_ERROR (this << " Does not find DL RLC Buffer Report of UE " << rnti);
1938  }
1939 }
1940 
1941 void
1942 TdBetFfMacScheduler::UpdateUlRlcBufferInfo (uint16_t rnti, uint16_t size)
1943 {
1944 
1945  size = size - 2; // remove the minimum RLC overhead
1946  std::map <uint16_t,uint32_t>::iterator it = m_ceBsrRxed.find (rnti);
1947  if (it != m_ceBsrRxed.end ())
1948  {
1949  NS_LOG_INFO (this << " UE " << rnti << " size " << size << " BSR " << (*it).second);
1950  if ((*it).second >= size)
1951  {
1952  (*it).second -= size;
1953  }
1954  else
1955  {
1956  (*it).second = 0;
1957  }
1958  }
1959  else
1960  {
1961  NS_LOG_ERROR (this << " Does not find BSR report info of UE " << rnti);
1962  }
1963 
1964 }
1965 
1966 void
1968 {
1969  NS_LOG_FUNCTION (this << " RNTI " << rnti << " txMode " << (uint16_t)txMode);
1971  params.m_rnti = rnti;
1972  params.m_transmissionMode = txMode;
1974 }
1975 
1976 
1977 }
tdbetsFlowPerf_t structure
unsigned long totalBytesTransmitted
total bytes transmitted
FfMacCschedSapUser * m_cschedSapUser
CSched SAP user.
std::vector< struct UlInfoListElement_s > m_ulInfoList
UL info list.
See section 4.3.1 dlDciListElement.
Definition: ff-mac-common.h:93
virtual FfMacSchedSapProvider * GetFfMacSchedSapProvider()
uint8_t HarqProcessAvailability(uint16_t rnti)
Return the availability of free process for the RNTI specified.
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:73
Service Access Point (SAP) offered by the eNodeB RRC instance to the Frequency Reuse algorithm instan...
Definition: lte-ffr-sap.h:138
std::map< uint16_t, tdbetsFlowPerf_t > m_flowStatsUl
Map of UE statistics (per RNTI basis)
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by "...
void DoCschedLcConfigReq(const struct FfMacCschedSapProvider::CschedLcConfigReqParameters &params)
CSched LC config request.
std::map< uint16_t, UlHarqProcessesDciBuffer_t > m_ulHarqProcessesDciBuffer
UL HARQ process DCI buffer.
#define HARQ_PERIOD
Definition: lte-common.h:30
void DoSchedDlTriggerReq(const struct FfMacSchedSapProvider::SchedDlTriggerReqParameters &params)
Sched DL trigger request.
AttributeValue implementation for Boolean.
Definition: boolean.h:36
std::map< uint16_t, UlHarqProcessesStatus_t > m_ulHarqProcessesStatus
UL HARQ process status.
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition: object-base.h:45
void TransmissionModeConfigurationUpdate(uint16_t rnti, uint8_t txMode)
Transmission mode configuration update function.
NS_ASSERT_MSG(false, "Ipv4AddressGenerator::MaskToIndex(): Impossible")
Parameters of the CSCHED_UE_CONFIG_CNF primitive.
Parameters of the CSCHED_UE_RELEASE_REQ primitive.
enum ns3::UlCqi_s::Type_e m_type
type
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:84
void DoSchedUlNoiseInterferenceReq(const struct FfMacSchedSapProvider::SchedUlNoiseInterferenceReqParameters &params)
Sched UL noise interference request.
std::vector< UlDciListElement_s > UlHarqProcessesDciBuffer_t
UL HARQ process DCI buffer vector.
std::vector< struct LogicalChannelConfigListElement_s > m_logicalChannelConfigList
logicalChannelConfigList
std::vector< uint16_t > m_sinr
SINR.
uint16_t m_rnti
RNTI.
Definition: ff-mac-common.h:95
std::vector< uint8_t > DlHarqProcessesTimer_t
DL HARQ process timer vector typedef.
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file...
Definition: assert.h:67
std::vector< struct RachListElement_s > m_rachList
RACH list.
virtual FfMacCschedSapProvider * GetFfMacCschedSapProvider()
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:202
std::map< uint16_t, uint8_t > m_p10CqiRxed
Map of UE&#39;s DL CQI P01 received.
std::vector< uint8_t > m_mcs
mcs
See section 4.3.2 ulDciListElement.
Provides the CSCHED SAP.
std::map< uint16_t, uint8_t > m_uesTxMode
txMode of the UEs
std::vector< struct UlDciListElement_s > m_dciList
DCI list.
#define NS_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
Definition: log.h:278
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
Definition: fatal-error.h:162
See section 4.3.10 buildRARListElement.
void DoSchedDlCqiInfoReq(const struct FfMacSchedSapProvider::SchedDlCqiInfoReqParameters &params)
Sched DL CQI info request.
Parameters of the CSCHED_UE_CONFIG_UPDATE_IND primitive.
void DoCschedUeConfigReq(const struct FfMacCschedSapProvider::CschedUeConfigReqParameters &params)
CSched UE config request.
Parameters of the CSCHED_LC_RELEASE_REQ primitive.
void DoSchedDlRachInfoReq(const struct FfMacSchedSapProvider::SchedDlRachInfoReqParameters &params)
Sched DL RACH info request.
void DoSchedUlMacCtrlInfoReq(const struct FfMacSchedSapProvider::SchedUlMacCtrlInfoReqParameters &params)
Sched UL MAC control info request.
std::vector< std::vector< struct RlcPduListElement_s > > m_rlcPduList
RLC PDU list.
Parameters of the SCHED_DL_TRIGGER_REQ primitive.
FfMacSchedSapUser * m_schedSapUser
Sched SAP user.
uint8_t m_rbLen
length
uint8_t m_harqProcess
HARQ process.
std::map< uint16_t, DlHarqProcessesStatus_t > m_dlHarqProcessesStatus
DL HARQ process status.
void DoSchedUlCqiInfoReq(const struct FfMacSchedSapProvider::SchedUlCqiInfoReqParameters &params)
Sched UL CQI info request.
std::vector< DlInfoListElement_s > m_dlInfoListBuffered
HARQ retx buffered.
std::vector< RlcPduList_t > DlHarqRlcPduListBuffer_t
vector of the 8 HARQ processes per UE
Parameters of the SCHED_DL_MAC_BUFFER_REQ primitive.
Parameters of the SCHED_DL_PAGING_BUFFER_REQ primitive.
std::map< uint16_t, uint32_t > m_a30CqiTimers
Map of UE&#39;s timers on DL CQI A30 received.
virtual void CschedUeConfigUpdateInd(const struct CschedUeConfigUpdateIndParameters &params)=0
CSCHED_UE_UPDATE_IND.
std::vector< struct VendorSpecificListElement_s > m_vendorSpecificList
vendor specific list
uint8_t m_aggrLevel
aggr level
std::map< uint16_t, tdbetsFlowPerf_t > m_flowStatsDl
Map of UE statistics (per RNTI basis) in downlink.
std::map< uint16_t, uint8_t > m_dlHarqCurrentProcessId
DL HARQ process ID.
virtual LteFfrSapUser * GetLteFfrSapUser()
void DoCschedCellConfigReq(const struct FfMacCschedSapProvider::CschedCellConfigReqParameters &params)
CSched cell config request.
FfMacCschedSapProvider::CschedCellConfigReqParameters m_cschedCellConfig
CSched cell config.
Service Access Point (SAP) offered by the Frequency Reuse algorithm instance to the MAC Scheduler ins...
Definition: lte-ffr-sap.h:39
Parameters of the SCHED_UL_TRIGGER_REQ primitive.
void RefreshUlCqiMaps(void)
Refresh UL CQI maps function.
uint32_t m_rbBitmap
rb bitmap
Definition: ff-mac-common.h:96
unsigned int LcActivePerFlow(uint16_t rnti)
LC active flow function.
Hold an unsigned integer type.
Definition: uinteger.h:44
static uint8_t TxMode2LayerNum(uint8_t txMode)
Transmit mode 2 layer number.
Definition: lte-common.cc:212
static const int TdBetType0AllocationRbg[4]
TDBET type 0 allocation RBG.
void RefreshHarqProcesses()
Refresh HARQ processes according to the timers.
bool m_cqiRequest
CQI request.
std::vector< uint8_t > m_ndi
ndi
double EstimateUlSinr(uint16_t rnti, uint16_t rb)
Estimate UL SINR function.
uint8_t m_cceIndex
CCE index.
void DoSchedUlSrInfoReq(const struct FfMacSchedSapProvider::SchedUlSrInfoReqParameters &params)
Sched UL SR info request.
Provides the SCHED SAP.
void DoSchedDlMacBufferReq(const struct FfMacSchedSapProvider::SchedDlMacBufferReqParameters &params)
Sched DL MAC buffer request.
std::map< uint16_t, DlHarqRlcPduListBuffer_t > m_dlHarqProcessesRlcPduListBuffer
DL HARQ process RLC PDU list buffer.
virtual void CschedUeConfigCnf(const struct CschedUeConfigCnfParameters &params)=0
CSCHED_UE_CONFIG_CNF.
Time flowStart
flow start time
uint32_t m_cqiTimersThreshold
of TTIs for which a CQI can be considered valid
std::vector< uint8_t > m_logicalChannelIdentity
logical channel identity
Parameters of the SCHED_UL_NOISE_INTERFERENCE_REQ primitive.
uint8_t m_logicalChannelIdentity
logical channel indentity
std::vector< struct CqiListElement_s > m_cqiList
CQI list.
std::vector< struct DlInfoListElement_s > m_dlInfoList
DL info list.
FfMacSchedSapProvider * m_schedSapProvider
Sched SAP provider.
void DoSchedUlTriggerReq(const struct FfMacSchedSapProvider::SchedUlTriggerReqParameters &params)
Sched UL trigger request.
virtual void SchedDlConfigInd(const struct SchedDlConfigIndParameters &params)=0
SCHED_DL_CONFIG_IND.
void RefreshDlCqiMaps(void)
Refresh DL CQI maps function.
int8_t m_pdcchPowerOffset
CCH power offset.
uint8_t m_ulGrantMcs
MCS for UL grant (default 0)
std::vector< uint16_t > m_tbsSize
tbs size
Definition: ff-mac-common.h:99
See section 4.3.9 rlcPDU_ListElement.
Every class exported by the ns3 library is enclosed in the ns3 namespace.
std::map< uint16_t, uint32_t > m_ceBsrRxed
Map of UE&#39;s buffer status reports received.
std::map< uint16_t, uint32_t > m_ueCqiTimers
Map of UEs&#39; timers on UL-CQI per RBG.
std::map< uint16_t, uint8_t > m_ulHarqCurrentProcessId
UL HARQ current process ID.
Ptr< const AttributeChecker > MakeBooleanChecker(void)
Definition: boolean.cc:121
void DoSchedDlPagingBufferReq(const struct FfMacSchedSapProvider::SchedDlPagingBufferReqParameters &params)
Sched DL paging buffer request.
uint8_t m_freqHopping
freq hopping
std::vector< DlDciListElement_s > DlHarqProcessesDciBuffer_t
DL HARQ process DCI buffer vector typedef.
Parameters of the CSCHED_LC_CONFIG_REQ primitive.
Implements the SCHED SAP and CSCHED SAP for a Time Domain Blind Equal Throughput scheduler.
void UpdateUlRlcBufferInfo(uint16_t rnti, uint16_t size)
Update UL RLC buffer info function.
std::vector< uint8_t > m_rv
rv
virtual void SetLteFfrSapProvider(LteFfrSapProvider *s)
Set the Provider part of the LteFfrSap that this Scheduler will interact with.
virtual void SetFfMacCschedSapUser(FfMacCschedSapUser *s)
set the user part of the FfMacCschedSap that this Scheduler will interact with.
MemberCschedSapProvider class.
std::map< uint16_t, DlHarqProcessesDciBuffer_t > m_dlHarqProcessesDciBuffer
DL HARQ process DCI buffer.
void UpdateDlRlcBufferInfo(uint16_t rnti, uint8_t lcid, uint16_t size)
Update DL RLC buffer info function.
virtual void SchedUlConfigInd(const struct SchedUlConfigIndParameters &params)=0
SCHED_UL_CONFIG_IND.
uint8_t m_ulIndex
UL index.
static Time Now(void)
Return the current simulation virtual time.
Definition: simulator.cc:249
NS_LOG_LOGIC("Net device "<< nd<< " is not bridged")
virtual ~TdBetFfMacScheduler()
Destructor.
UlCqiFilter_t m_ulCqiFilter
UL CQI filter.
#define SRS_CQI_RNTI_VSP
This abstract base class identifies the interface by means of which the helper object can plug on the...
std::map< uint16_t, std::vector< double > > m_ueCqi
Map of UEs&#39; UL-CQI per RBG.
FfMacCschedSapUser class.
uint8_t m_nrOfPdcchOfdmSymbols
number of PDCCH OFDM symbols
static TypeId GetTypeId(void)
Get the type ID.
unsigned int lastTtiBytesTrasmitted
last total bytes transmitted
Parameters of the SCHED_DL_CQI_INFO_REQ primitive.
std::vector< struct MacCeListElement_s > m_macCeList
MAC CE list.
std::vector< struct RachListElement_s > m_rachList
RACH list.
static double fpS11dot3toDouble(uint16_t val)
Convert from fixed point S11.3 notation to double.
Definition: lte-common.cc:155
uint8_t m_n2Dmrs
n2 DMRS
std::vector< uint8_t > UlHarqProcessesStatus_t
UL HARQ process status vector.
std::vector< uint8_t > DlHarqProcessesStatus_t
DL HARQ process status vector typedef.
Parameters of the SCHED_UL_CQI_INFO_REQ primitive.
static uint32_t BsrId2BufferSize(uint8_t val)
Convert BSR ID to buffer size.
Definition: lte-common.cc:184
LteFlowId structure.
Definition: lte-common.h:36
int GetRbgSize(int dlbandwidth)
Get RBG size function.
Parameters of the SCHED_UL_MAC_CTRL_INFO_REQ primitive.
std::map< uint16_t, SbMeasResult_s > m_a30CqiRxed
Map of UE&#39;s DL CQI A30 received.
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition: log.h:270
std::map< uint16_t, uint32_t > m_p10CqiTimers
Map of UE&#39;s timers on DL CQI P01 received.
LteFfrSapUser * m_ffrSapUser
FFR SAP user.
void DoCschedLcReleaseReq(const struct FfMacCschedSapProvider::CschedLcReleaseReqParameters &params)
CSched LC release request.
Parameters of the SCHED_UL_SR_INFO_REQ primitive.
uint16_t m_nextRntiUl
RNTI of the next user to be served next scheduling in UL.
#define NS_LOG_ERROR(msg)
Use NS_LOG to output a message of level LOG_ERROR.
Definition: log.h:254
Parameters of the SCHED_DL_RACH_INFO_REQ primitive.
Parameters of the SCHED_UL_CONFIG_IND primitive.
bool m_harqOn
m_harqOn when false inhibit the HARQ mechanisms (by default active)
virtual void SetFfMacSchedSapUser(FfMacSchedSapUser *s)
set the user part of the FfMacSchedSap that this Scheduler will interact with.
MemberSchedSapProvider class.
Parameters of the CSCHED_UE_CONFIG_REQ primitive.
uint8_t UpdateHarqProcessId(uint16_t rnti)
Update and return a new process Id for the RNTI specified.
std::map< uint16_t, DlHarqProcessesTimer_t > m_dlHarqProcessesTimer
DL HARQ process timer.
void DoSchedDlRlcBufferReq(const struct FfMacSchedSapProvider::SchedDlRlcBufferReqParameters &params)
Sched DL RLC buffer request.
#define HARQ_DL_TIMEOUT
#define NO_SINR
struct DlDciListElement_s m_dci
DCI.
std::vector< struct BuildRarListElement_s > m_buildRarList
build rar list
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:45
double lastAveragedThroughput
last average throughput
a unique identifier for an interface.
Definition: type-id.h:58
uint8_t m_resAlloc
res allocate
Definition: ff-mac-common.h:98
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:915
std::vector< uint16_t > m_rachAllocationMap
RACH allocation map.
#define HARQ_PROC_NUM
LteFfrSapProvider * m_ffrSapProvider
FFR SAP provider.
FfMacCschedSapProvider * m_cschedSapProvider
CSched SAP provider.
FfMacSchedSapUser class.
std::map< LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters > m_rlcBufferReq
Vectors of UE&#39;s LC info.
std::map< uint16_t, std::vector< uint16_t > > m_allocationMaps
Map of previous allocated UE per RBG (used to retrieve info from UL-CQI)
std::vector< struct BuildDataListElement_s > m_buildDataList
build data list
void DoCschedUeReleaseReq(const struct FfMacCschedSapProvider::CschedUeReleaseReqParameters &params)
CSched UE release request.
uint8_t m_ueTxAntennaSelection
UE antenna selection.
See section 4.3.8 builDataListElement.
virtual void DoDispose(void)
Destructor implementation.