A Discrete-Event Network Simulator
API
fdbet-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/fdbet-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 ("FdBetFfMacScheduler");
37 
39 static const int FdBetType0AllocationRbg[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 (FdBetFfMacScheduler);
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::FdBetFfMacScheduler")
87  .SetGroupName("Lte")
88  .AddConstructor<FdBetFfMacScheduler> ()
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, fdbetsFlowPerf_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  fdbetsFlowPerf_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, fdbetsFlowPerf_t> (params.m_rnti, flowStatsDl));
216  fdbetsFlowPerf_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, fdbetsFlowPerf_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 < FdBetType0AllocationRbg[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 
502  // update UL HARQ proc id
503  std::map <uint16_t, uint8_t>::iterator itProcId;
504  for (itProcId = m_ulHarqCurrentProcessId.begin (); itProcId != m_ulHarqCurrentProcessId.end (); itProcId++)
505  {
506  (*itProcId).second = ((*itProcId).second + 1) % HARQ_PROC_NUM;
507  }
508 
509  // RACH Allocation
511  uint16_t rbStart = 0;
512  std::vector <struct RachListElement_s>::iterator itRach;
513  for (itRach = m_rachList.begin (); itRach != m_rachList.end (); itRach++)
514  {
515  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");
516  BuildRarListElement_s newRar;
517  newRar.m_rnti = (*itRach).m_rnti;
518  // DL-RACH Allocation
519  // Ideal: no needs of configuring m_dci
520  // UL-RACH Allocation
521  newRar.m_grant.m_rnti = newRar.m_rnti;
522  newRar.m_grant.m_mcs = m_ulGrantMcs;
523  uint16_t rbLen = 1;
524  uint16_t tbSizeBits = 0;
525  // find lowest TB size that fits UL grant estimated size
526  while ((tbSizeBits < (*itRach).m_estimatedSize) && (rbStart + rbLen < m_cschedCellConfig.m_ulBandwidth))
527  {
528  rbLen++;
529  tbSizeBits = m_amc->GetUlTbSizeFromMcs (m_ulGrantMcs, rbLen);
530  }
531  if (tbSizeBits < (*itRach).m_estimatedSize)
532  {
533  // no more allocation space: finish allocation
534  break;
535  }
536  newRar.m_grant.m_rbStart = rbStart;
537  newRar.m_grant.m_rbLen = rbLen;
538  newRar.m_grant.m_tbSize = tbSizeBits / 8;
539  newRar.m_grant.m_hopping = false;
540  newRar.m_grant.m_tpc = 0;
541  newRar.m_grant.m_cqiRequest = false;
542  newRar.m_grant.m_ulDelay = false;
543  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);
544  for (uint16_t i = rbStart; i < rbStart + rbLen; i++)
545  {
546  m_rachAllocationMap.at (i) = (*itRach).m_rnti;
547  }
548 
549  if (m_harqOn == true)
550  {
551  // generate UL-DCI for HARQ retransmissions
552  UlDciListElement_s uldci;
553  uldci.m_rnti = newRar.m_rnti;
554  uldci.m_rbLen = rbLen;
555  uldci.m_rbStart = rbStart;
556  uldci.m_mcs = m_ulGrantMcs;
557  uldci.m_tbSize = tbSizeBits / 8;
558  uldci.m_ndi = 1;
559  uldci.m_cceIndex = 0;
560  uldci.m_aggrLevel = 1;
561  uldci.m_ueTxAntennaSelection = 3; // antenna selection OFF
562  uldci.m_hopping = false;
563  uldci.m_n2Dmrs = 0;
564  uldci.m_tpc = 0; // no power control
565  uldci.m_cqiRequest = false; // only period CQI at this stage
566  uldci.m_ulIndex = 0; // TDD parameter
567  uldci.m_dai = 1; // TDD parameter
568  uldci.m_freqHopping = 0;
569  uldci.m_pdcchPowerOffset = 0; // not used
570 
571  uint8_t harqId = 0;
572  std::map <uint16_t, uint8_t>::iterator itProcId;
573  itProcId = m_ulHarqCurrentProcessId.find (uldci.m_rnti);
574  if (itProcId == m_ulHarqCurrentProcessId.end ())
575  {
576  NS_FATAL_ERROR ("No info find in HARQ buffer for UE " << uldci.m_rnti);
577  }
578  harqId = (*itProcId).second;
579  std::map <uint16_t, UlHarqProcessesDciBuffer_t>::iterator itDci = m_ulHarqProcessesDciBuffer.find (uldci.m_rnti);
580  if (itDci == m_ulHarqProcessesDciBuffer.end ())
581  {
582  NS_FATAL_ERROR ("Unable to find RNTI entry in UL DCI HARQ buffer for RNTI " << uldci.m_rnti);
583  }
584  (*itDci).second.at (harqId) = uldci;
585  }
586 
587  rbStart = rbStart + rbLen;
588  ret.m_buildRarList.push_back (newRar);
589  }
590  m_rachList.clear ();
591 
592 
593  // Process DL HARQ feedback
595  // retrieve past HARQ retx buffered
596  if (m_dlInfoListBuffered.size () > 0)
597  {
598  if (params.m_dlInfoList.size () > 0)
599  {
600  NS_LOG_INFO (this << " Received DL-HARQ feedback");
601  m_dlInfoListBuffered.insert (m_dlInfoListBuffered.end (), params.m_dlInfoList.begin (), params.m_dlInfoList.end ());
602  }
603  }
604  else
605  {
606  if (params.m_dlInfoList.size () > 0)
607  {
609  }
610  }
611  if (m_harqOn == false)
612  {
613  // Ignore HARQ feedback
614  m_dlInfoListBuffered.clear ();
615  }
616  std::vector <struct DlInfoListElement_s> dlInfoListUntxed;
617  for (uint16_t i = 0; i < m_dlInfoListBuffered.size (); i++)
618  {
619  std::set <uint16_t>::iterator itRnti = rntiAllocated.find (m_dlInfoListBuffered.at (i).m_rnti);
620  if (itRnti != rntiAllocated.end ())
621  {
622  // RNTI already allocated for retx
623  continue;
624  }
625  uint8_t nLayers = m_dlInfoListBuffered.at (i).m_harqStatus.size ();
626  std::vector <bool> retx;
627  NS_LOG_INFO (this << " Processing DLHARQ feedback");
628  if (nLayers == 1)
629  {
630  retx.push_back (m_dlInfoListBuffered.at (i).m_harqStatus.at (0) == DlInfoListElement_s::NACK);
631  retx.push_back (false);
632  }
633  else
634  {
635  retx.push_back (m_dlInfoListBuffered.at (i).m_harqStatus.at (0) == DlInfoListElement_s::NACK);
636  retx.push_back (m_dlInfoListBuffered.at (i).m_harqStatus.at (1) == DlInfoListElement_s::NACK);
637  }
638  if (retx.at (0) || retx.at (1))
639  {
640  // retrieve HARQ process information
641  uint16_t rnti = m_dlInfoListBuffered.at (i).m_rnti;
642  uint8_t harqId = m_dlInfoListBuffered.at (i).m_harqProcessId;
643  NS_LOG_INFO (this << " HARQ retx RNTI " << rnti << " harqId " << (uint16_t)harqId);
644  std::map <uint16_t, DlHarqProcessesDciBuffer_t>::iterator itHarq = m_dlHarqProcessesDciBuffer.find (rnti);
645  if (itHarq == m_dlHarqProcessesDciBuffer.end ())
646  {
647  NS_FATAL_ERROR ("No info find in HARQ buffer for UE " << rnti);
648  }
649 
650  DlDciListElement_s dci = (*itHarq).second.at (harqId);
651  int rv = 0;
652  if (dci.m_rv.size () == 1)
653  {
654  rv = dci.m_rv.at (0);
655  }
656  else
657  {
658  rv = (dci.m_rv.at (0) > dci.m_rv.at (1) ? dci.m_rv.at (0) : dci.m_rv.at (1));
659  }
660 
661  if (rv == 3)
662  {
663  // maximum number of retx reached -> drop process
664  NS_LOG_INFO ("Maximum number of retransmissions reached -> drop process");
665  std::map <uint16_t, DlHarqProcessesStatus_t>::iterator it = m_dlHarqProcessesStatus.find (rnti);
666  if (it == m_dlHarqProcessesStatus.end ())
667  {
668  NS_LOG_ERROR ("No info find in HARQ buffer for UE (might change eNB) " << m_dlInfoListBuffered.at (i).m_rnti);
669  }
670  (*it).second.at (harqId) = 0;
671  std::map <uint16_t, DlHarqRlcPduListBuffer_t>::iterator itRlcPdu = m_dlHarqProcessesRlcPduListBuffer.find (rnti);
672  if (itRlcPdu == m_dlHarqProcessesRlcPduListBuffer.end ())
673  {
674  NS_FATAL_ERROR ("Unable to find RlcPdcList in HARQ buffer for RNTI " << m_dlInfoListBuffered.at (i).m_rnti);
675  }
676  for (uint16_t k = 0; k < (*itRlcPdu).second.size (); k++)
677  {
678  (*itRlcPdu).second.at (k).at (harqId).clear ();
679  }
680  continue;
681  }
682  // check the feasibility of retransmitting on the same RBGs
683  // translate the DCI to Spectrum framework
684  std::vector <int> dciRbg;
685  uint32_t mask = 0x1;
686  NS_LOG_INFO ("Original RBGs " << dci.m_rbBitmap << " rnti " << dci.m_rnti);
687  for (int j = 0; j < 32; j++)
688  {
689  if (((dci.m_rbBitmap & mask) >> j) == 1)
690  {
691  dciRbg.push_back (j);
692  NS_LOG_INFO ("\t" << j);
693  }
694  mask = (mask << 1);
695  }
696  bool free = true;
697  for (uint8_t j = 0; j < dciRbg.size (); j++)
698  {
699  if (rbgMap.at (dciRbg.at (j)) == true)
700  {
701  free = false;
702  break;
703  }
704  }
705  if (free)
706  {
707  // use the same RBGs for the retx
708  // reserve RBGs
709  for (uint8_t j = 0; j < dciRbg.size (); j++)
710  {
711  rbgMap.at (dciRbg.at (j)) = true;
712  NS_LOG_INFO ("RBG " << dciRbg.at (j) << " assigned");
713  rbgAllocatedNum++;
714  }
715 
716  NS_LOG_INFO (this << " Send retx in the same RBGs");
717  }
718  else
719  {
720  // find RBGs for sending HARQ retx
721  uint8_t j = 0;
722  uint8_t rbgId = (dciRbg.at (dciRbg.size () - 1) + 1) % rbgNum;
723  uint8_t startRbg = dciRbg.at (dciRbg.size () - 1);
724  std::vector <bool> rbgMapCopy = rbgMap;
725  while ((j < dciRbg.size ())&&(startRbg != rbgId))
726  {
727  if (rbgMapCopy.at (rbgId) == false)
728  {
729  rbgMapCopy.at (rbgId) = true;
730  dciRbg.at (j) = rbgId;
731  j++;
732  }
733  rbgId = (rbgId + 1) % rbgNum;
734  }
735  if (j == dciRbg.size ())
736  {
737  // find new RBGs -> update DCI map
738  uint32_t rbgMask = 0;
739  for (uint16_t k = 0; k < dciRbg.size (); k++)
740  {
741  rbgMask = rbgMask + (0x1 << dciRbg.at (k));
742  rbgAllocatedNum++;
743  }
744  dci.m_rbBitmap = rbgMask;
745  rbgMap = rbgMapCopy;
746  NS_LOG_INFO (this << " Move retx in RBGs " << dciRbg.size ());
747  }
748  else
749  {
750  // HARQ retx cannot be performed on this TTI -> store it
751  dlInfoListUntxed.push_back (m_dlInfoListBuffered.at (i));
752  NS_LOG_INFO (this << " No resource for this retx -> buffer it");
753  }
754  }
755  // retrieve RLC PDU list for retx TBsize and update DCI
757  std::map <uint16_t, DlHarqRlcPduListBuffer_t>::iterator itRlcPdu = m_dlHarqProcessesRlcPduListBuffer.find (rnti);
758  if (itRlcPdu == m_dlHarqProcessesRlcPduListBuffer.end ())
759  {
760  NS_FATAL_ERROR ("Unable to find RlcPdcList in HARQ buffer for RNTI " << rnti);
761  }
762  for (uint8_t j = 0; j < nLayers; j++)
763  {
764  if (retx.at (j))
765  {
766  if (j >= dci.m_ndi.size ())
767  {
768  // for avoiding errors in MIMO transient phases
769  dci.m_ndi.push_back (0);
770  dci.m_rv.push_back (0);
771  dci.m_mcs.push_back (0);
772  dci.m_tbsSize.push_back (0);
773  NS_LOG_INFO (this << " layer " << (uint16_t)j << " no txed (MIMO transition)");
774  }
775  else
776  {
777  dci.m_ndi.at (j) = 0;
778  dci.m_rv.at (j)++;
779  (*itHarq).second.at (harqId).m_rv.at (j)++;
780  NS_LOG_INFO (this << " layer " << (uint16_t)j << " RV " << (uint16_t)dci.m_rv.at (j));
781  }
782  }
783  else
784  {
785  // empty TB of layer j
786  dci.m_ndi.at (j) = 0;
787  dci.m_rv.at (j) = 0;
788  dci.m_mcs.at (j) = 0;
789  dci.m_tbsSize.at (j) = 0;
790  NS_LOG_INFO (this << " layer " << (uint16_t)j << " no retx");
791  }
792  }
793  for (uint16_t k = 0; k < (*itRlcPdu).second.at (0).at (dci.m_harqProcess).size (); k++)
794  {
795  std::vector <struct RlcPduListElement_s> rlcPduListPerLc;
796  for (uint8_t j = 0; j < nLayers; j++)
797  {
798  if (retx.at (j))
799  {
800  if (j < dci.m_ndi.size ())
801  {
802  NS_LOG_INFO (" layer " << (uint16_t)j << " tb size " << dci.m_tbsSize.at (j));
803  rlcPduListPerLc.push_back ((*itRlcPdu).second.at (j).at (dci.m_harqProcess).at (k));
804  }
805  }
806  else
807  { // 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
808  NS_LOG_INFO (" layer " << (uint16_t)j << " tb size "<<dci.m_tbsSize.at (j));
809  RlcPduListElement_s emptyElement;
810  emptyElement.m_logicalChannelIdentity = (*itRlcPdu).second.at (j).at (dci.m_harqProcess).at (k).m_logicalChannelIdentity;
811  emptyElement.m_size = 0;
812  rlcPduListPerLc.push_back (emptyElement);
813  }
814  }
815 
816  if (rlcPduListPerLc.size () > 0)
817  {
818  newEl.m_rlcPduList.push_back (rlcPduListPerLc);
819  }
820  }
821  newEl.m_rnti = rnti;
822  newEl.m_dci = dci;
823  (*itHarq).second.at (harqId).m_rv = dci.m_rv;
824  // refresh timer
825  std::map <uint16_t, DlHarqProcessesTimer_t>::iterator itHarqTimer = m_dlHarqProcessesTimer.find (rnti);
826  if (itHarqTimer== m_dlHarqProcessesTimer.end ())
827  {
828  NS_FATAL_ERROR ("Unable to find HARQ timer for RNTI " << (uint16_t)rnti);
829  }
830  (*itHarqTimer).second.at (harqId) = 0;
831  ret.m_buildDataList.push_back (newEl);
832  rntiAllocated.insert (rnti);
833  }
834  else
835  {
836  // update HARQ process status
837  NS_LOG_INFO (this << " HARQ received ACK for UE " << m_dlInfoListBuffered.at (i).m_rnti);
838  std::map <uint16_t, DlHarqProcessesStatus_t>::iterator it = m_dlHarqProcessesStatus.find (m_dlInfoListBuffered.at (i).m_rnti);
839  if (it == m_dlHarqProcessesStatus.end ())
840  {
841  NS_FATAL_ERROR ("No info find in HARQ buffer for UE " << m_dlInfoListBuffered.at (i).m_rnti);
842  }
843  (*it).second.at (m_dlInfoListBuffered.at (i).m_harqProcessId) = 0;
844  std::map <uint16_t, DlHarqRlcPduListBuffer_t>::iterator itRlcPdu = m_dlHarqProcessesRlcPduListBuffer.find (m_dlInfoListBuffered.at (i).m_rnti);
845  if (itRlcPdu == m_dlHarqProcessesRlcPduListBuffer.end ())
846  {
847  NS_FATAL_ERROR ("Unable to find RlcPdcList in HARQ buffer for RNTI " << m_dlInfoListBuffered.at (i).m_rnti);
848  }
849  for (uint16_t k = 0; k < (*itRlcPdu).second.size (); k++)
850  {
851  (*itRlcPdu).second.at (k).at (m_dlInfoListBuffered.at (i).m_harqProcessId).clear ();
852  }
853  }
854  }
855  m_dlInfoListBuffered.clear ();
856  m_dlInfoListBuffered = dlInfoListUntxed;
857 
858  if (rbgAllocatedNum == rbgNum)
859  {
860  // all the RBGs are already allocated -> exit
861  if ((ret.m_buildDataList.size () > 0) || (ret.m_buildRarList.size () > 0))
862  {
864  }
865  return;
866  }
867 
868  std::map <uint16_t, fdbetsFlowPerf_t>::iterator itFlow;
869  std::map <uint16_t, double> estAveThr; // store expected average throughput for UE
870  std::map <uint16_t, double>::iterator itMax = estAveThr.end ();
871  std::map <uint16_t, double>::iterator it;
872  std::map <uint16_t, int> rbgPerRntiLog; // record the number of RBG assigned to UE
873  double metricMax = 0.0;
874  for (itFlow = m_flowStatsDl.begin (); itFlow != m_flowStatsDl.end (); itFlow++)
875  {
876  std::set <uint16_t>::iterator itRnti = rntiAllocated.find ((*itFlow).first);
877  if ((itRnti != rntiAllocated.end ())||(!HarqProcessAvailability ((*itFlow).first)))
878  {
879  // UE already allocated for HARQ or without HARQ process available -> drop it
880  if (itRnti != rntiAllocated.end ())
881  {
882  NS_LOG_DEBUG (this << " RNTI discared for HARQ tx" << (uint16_t)(*itFlow).first);
883  }
884  if (!HarqProcessAvailability ((*itFlow).first))
885  {
886  NS_LOG_DEBUG (this << " RNTI discared for HARQ id" << (uint16_t)(*itFlow).first);
887  }
888  continue;
889  }
890 
891  // check first what are channel conditions for this UE, if CQI!=0
892  std::map <uint16_t,uint8_t>::iterator itCqi;
893  itCqi = m_p10CqiRxed.find ((*itFlow).first);
894  std::map <uint16_t,uint8_t>::iterator itTxMode;
895  itTxMode = m_uesTxMode.find ((*itFlow).first);
896  if (itTxMode == m_uesTxMode.end ())
897  {
898  NS_FATAL_ERROR ("No Transmission Mode info on user " << (*itFlow).first);
899  }
900  int nLayer = TransmissionModesLayers::TxMode2LayerNum ((*itTxMode).second);
901 
902  uint8_t cqiSum = 0;
903  for (uint8_t j = 0; j < nLayer; j++)
904  {
905  if (itCqi == m_p10CqiRxed.end ())
906  {
907  cqiSum += 1; // no info on this user -> lowest MCS
908  }
909  else
910  {
911  cqiSum = (*itCqi).second;
912  }
913  }
914  if (cqiSum != 0)
915  {
916  estAveThr.insert (std::pair <uint16_t, double> ((*itFlow).first, (*itFlow).second.lastAveragedThroughput));
917  }
918  else
919  {
920  NS_LOG_INFO ("Skip this flow, CQI==0, rnti:"<<(*itFlow).first);
921  }
922  }
923 
924  if (estAveThr.size () != 0)
925  {
926  // Find UE with largest priority metric
927  for (it = estAveThr.begin (); it != estAveThr.end (); it++)
928  {
929  double metric = 1 / (*it).second;
930  if (metric > metricMax)
931  {
932  metricMax = metric;
933  itMax = it;
934  }
935  rbgPerRntiLog.insert (std::pair<uint16_t, int> ((*it).first, 1));
936  }
937 
938 
939  // The scheduler tries the best to achieve the equal throughput among all UEs
940  int i = 0;
941  do
942  {
943  NS_LOG_INFO (this << " ALLOCATION for RBG " << i << " of " << rbgNum);
944  if (rbgMap.at (i) == false)
945  {
946  // allocate one RBG to current UE
947  std::map <uint16_t, std::vector <uint16_t> >::iterator itMap;
948  std::vector <uint16_t> tempMap;
949  itMap = allocationMap.find ((*itMax).first);
950  if (itMap == allocationMap.end ())
951  {
952  tempMap.push_back (i);
953  allocationMap.insert (std::pair <uint16_t, std::vector <uint16_t> > ((*itMax).first, tempMap));
954  }
955  else
956  {
957  (*itMap).second.push_back (i);
958  }
959 
960  // calculate expected throughput for current UE
961  std::map <uint16_t,uint8_t>::iterator itCqi;
962  itCqi = m_p10CqiRxed.find ((*itMax).first);
963  std::map <uint16_t,uint8_t>::iterator itTxMode;
964  itTxMode = m_uesTxMode.find ((*itMax).first);
965  if (itTxMode == m_uesTxMode.end ())
966  {
967  NS_FATAL_ERROR ("No Transmission Mode info on user " << (*itMax).first);
968  }
969  int nLayer = TransmissionModesLayers::TxMode2LayerNum ((*itTxMode).second);
970  std::vector <uint8_t> mcs;
971  for (uint8_t j = 0; j < nLayer; j++)
972  {
973  if (itCqi == m_p10CqiRxed.end ())
974  {
975  mcs.push_back (0); // no info on this user -> lowest MCS
976  }
977  else
978  {
979  mcs.push_back (m_amc->GetMcsFromCqi ((*itCqi).second));
980  }
981  }
982 
983  std::map <uint16_t,int>::iterator itRbgPerRntiLog;
984  itRbgPerRntiLog = rbgPerRntiLog.find ((*itMax).first);
985  std::map <uint16_t, fdbetsFlowPerf_t>::iterator itPastAveThr;
986  itPastAveThr = m_flowStatsDl.find ((*itMax).first);
987  uint32_t bytesTxed = 0;
988  for (uint8_t j = 0; j < nLayer; j++)
989  {
990  int tbSize = (m_amc->GetDlTbSizeFromMcs (mcs.at (0), (*itRbgPerRntiLog).second * rbgSize) / 8); // (size of TB in bytes according to table 7.1.7.2.1-1 of 36.213)
991  bytesTxed += tbSize;
992  }
993  double expectedAveThr = ((1.0 - (1.0 / m_timeWindow)) * (*itPastAveThr).second.lastAveragedThroughput) + ((1.0 / m_timeWindow) * (double)(bytesTxed / 0.001));
994 
995  int rbgPerRnti = (*itRbgPerRntiLog).second;
996  rbgPerRnti++;
997  rbgPerRntiLog[(*itMax).first] = rbgPerRnti;
998  estAveThr[(*itMax).first] = expectedAveThr;
999 
1000  // find new UE with largest priority metric
1001  metricMax = 0.0;
1002  for (it = estAveThr.begin (); it != estAveThr.end (); it++)
1003  {
1004  double metric = 1 / (*it).second;
1005  if (metric > metricMax)
1006  {
1007  itMax = it;
1008  metricMax = metric;
1009  }
1010  } // end for estAveThr
1011 
1012  rbgMap.at (i) = true;
1013 
1014  } // end for free RBGs
1015 
1016  i++;
1017 
1018  }
1019  while ( i < rbgNum ); // end for RBGs
1020 
1021  } // end if estAveThr
1022 
1023  // reset TTI stats of users
1024  std::map <uint16_t, fdbetsFlowPerf_t>::iterator itStats;
1025  for (itStats = m_flowStatsDl.begin (); itStats != m_flowStatsDl.end (); itStats++)
1026  {
1027  (*itStats).second.lastTtiBytesTrasmitted = 0;
1028  }
1029 
1030  // generate the transmission opportunities by grouping the RBGs of the same RNTI and
1031  // creating the correspondent DCIs
1032  std::map <uint16_t, std::vector <uint16_t> >::iterator itMap = allocationMap.begin ();
1033  while (itMap != allocationMap.end ())
1034  {
1035  // create new BuildDataListElement_s for this LC
1036  BuildDataListElement_s newEl;
1037  newEl.m_rnti = (*itMap).first;
1038  // create the DlDciListElement_s
1039  DlDciListElement_s newDci;
1040  newDci.m_rnti = (*itMap).first;
1041  newDci.m_harqProcess = UpdateHarqProcessId ((*itMap).first);
1042 
1043  uint16_t lcActives = LcActivePerFlow ((*itMap).first);
1044  NS_LOG_INFO (this << "Allocate user " << newEl.m_rnti << " rbg " << lcActives);
1045  if (lcActives == 0)
1046  {
1047  // Set to max value, to avoid divide by 0 below
1048  lcActives = (uint16_t)65535; // UINT16_MAX;
1049  }
1050  uint16_t RgbPerRnti = (*itMap).second.size ();
1051  std::map <uint16_t,uint8_t>::iterator itCqi;
1052  itCqi = m_p10CqiRxed.find ((*itMap).first);
1053  std::map <uint16_t,uint8_t>::iterator itTxMode;
1054  itTxMode = m_uesTxMode.find ((*itMap).first);
1055  if (itTxMode == m_uesTxMode.end ())
1056  {
1057  NS_FATAL_ERROR ("No Transmission Mode info on user " << (*itMap).first);
1058  }
1059  int nLayer = TransmissionModesLayers::TxMode2LayerNum ((*itTxMode).second);
1060 
1061  uint32_t bytesTxed = 0;
1062  for (uint8_t j = 0; j < nLayer; j++)
1063  {
1064  if (itCqi == m_p10CqiRxed.end ())
1065  {
1066  newDci.m_mcs.push_back (0); // no info on this user -> lowest MCS
1067  }
1068  else
1069  {
1070  newDci.m_mcs.push_back ( m_amc->GetMcsFromCqi ((*itCqi).second) );
1071  }
1072 
1073  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)
1074  newDci.m_tbsSize.push_back (tbSize);
1075  bytesTxed += tbSize;
1076  }
1077 
1078  newDci.m_resAlloc = 0; // only allocation type 0 at this stage
1079  newDci.m_rbBitmap = 0; // TBD (32 bit bitmap see 7.1.6 of 36.213)
1080  uint32_t rbgMask = 0;
1081  for (uint16_t k = 0; k < (*itMap).second.size (); k++)
1082  {
1083  rbgMask = rbgMask + (0x1 << (*itMap).second.at (k));
1084  NS_LOG_INFO (this << " Allocated RBG " << (*itMap).second.at (k));
1085  }
1086  newDci.m_rbBitmap = rbgMask; // (32 bit bitmap see 7.1.6 of 36.213)
1087 
1088  // create the rlc PDUs -> equally divide resources among actives LCs
1089  std::map <LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator itBufReq;
1090  for (itBufReq = m_rlcBufferReq.begin (); itBufReq != m_rlcBufferReq.end (); itBufReq++)
1091  {
1092  if (((*itBufReq).first.m_rnti == (*itMap).first)
1093  && (((*itBufReq).second.m_rlcTransmissionQueueSize > 0)
1094  || ((*itBufReq).second.m_rlcRetransmissionQueueSize > 0)
1095  || ((*itBufReq).second.m_rlcStatusPduSize > 0) ))
1096  {
1097  std::vector <struct RlcPduListElement_s> newRlcPduLe;
1098  for (uint8_t j = 0; j < nLayer; j++)
1099  {
1100  RlcPduListElement_s newRlcEl;
1101  newRlcEl.m_logicalChannelIdentity = (*itBufReq).first.m_lcId;
1102  newRlcEl.m_size = newDci.m_tbsSize.at (j) / lcActives;
1103  NS_LOG_INFO (this << " LCID " << (uint32_t) newRlcEl.m_logicalChannelIdentity << " size " << newRlcEl.m_size << " layer " << (uint16_t)j);
1104  newRlcPduLe.push_back (newRlcEl);
1105  UpdateDlRlcBufferInfo (newDci.m_rnti, newRlcEl.m_logicalChannelIdentity, newRlcEl.m_size);
1106  if (m_harqOn == true)
1107  {
1108  // store RLC PDU list for HARQ
1109  std::map <uint16_t, DlHarqRlcPduListBuffer_t>::iterator itRlcPdu = m_dlHarqProcessesRlcPduListBuffer.find ((*itMap).first);
1110  if (itRlcPdu == m_dlHarqProcessesRlcPduListBuffer.end ())
1111  {
1112  NS_FATAL_ERROR ("Unable to find RlcPdcList in HARQ buffer for RNTI " << (*itMap).first);
1113  }
1114  (*itRlcPdu).second.at (j).at (newDci.m_harqProcess).push_back (newRlcEl);
1115  }
1116  }
1117  newEl.m_rlcPduList.push_back (newRlcPduLe);
1118  }
1119  if ((*itBufReq).first.m_rnti > (*itMap).first)
1120  {
1121  break;
1122  }
1123  }
1124  for (uint8_t j = 0; j < nLayer; j++)
1125  {
1126  newDci.m_ndi.push_back (1);
1127  newDci.m_rv.push_back (0);
1128  }
1129 
1130  newDci.m_tpc = 1; //1 is mapped to 0 in Accumulated Mode and to -1 in Absolute Mode
1131 
1132  newEl.m_dci = newDci;
1133 
1134  if (m_harqOn == true)
1135  {
1136  // store DCI for HARQ
1137  std::map <uint16_t, DlHarqProcessesDciBuffer_t>::iterator itDci = m_dlHarqProcessesDciBuffer.find (newEl.m_rnti);
1138  if (itDci == m_dlHarqProcessesDciBuffer.end ())
1139  {
1140  NS_FATAL_ERROR ("Unable to find RNTI entry in DCI HARQ buffer for RNTI " << newEl.m_rnti);
1141  }
1142  (*itDci).second.at (newDci.m_harqProcess) = newDci;
1143  // refresh timer
1144  std::map <uint16_t, DlHarqProcessesTimer_t>::iterator itHarqTimer = m_dlHarqProcessesTimer.find (newEl.m_rnti);
1145  if (itHarqTimer== m_dlHarqProcessesTimer.end ())
1146  {
1147  NS_FATAL_ERROR ("Unable to find HARQ timer for RNTI " << (uint16_t)newEl.m_rnti);
1148  }
1149  (*itHarqTimer).second.at (newDci.m_harqProcess) = 0;
1150  }
1151 
1152  // ...more parameters -> ignored in this version
1153 
1154  ret.m_buildDataList.push_back (newEl);
1155  // update UE stats
1156  std::map <uint16_t, fdbetsFlowPerf_t>::iterator it;
1157  it = m_flowStatsDl.find ((*itMap).first);
1158  if (it != m_flowStatsDl.end ())
1159  {
1160  (*it).second.lastTtiBytesTrasmitted = bytesTxed;
1161  NS_LOG_INFO (this << " UE total bytes txed " << (*it).second.lastTtiBytesTrasmitted);
1162 
1163 
1164  }
1165  else
1166  {
1167  NS_FATAL_ERROR (this << " No Stats for this allocated UE");
1168  }
1169 
1170  itMap++;
1171  } // end while allocation
1172  ret.m_nrOfPdcchOfdmSymbols = 1;
1173 
1174 
1175  // update UEs stats
1176  NS_LOG_INFO (this << " Update UEs statistics");
1177  for (itStats = m_flowStatsDl.begin (); itStats != m_flowStatsDl.end (); itStats++)
1178  {
1179  (*itStats).second.totalBytesTransmitted += (*itStats).second.lastTtiBytesTrasmitted;
1180  // update average throughput (see eq. 12.3 of Sec 12.3.1.2 of LTE – The UMTS Long Term Evolution, Ed Wiley)
1181  (*itStats).second.lastAveragedThroughput = ((1.0 - (1.0 / m_timeWindow)) * (*itStats).second.lastAveragedThroughput) + ((1.0 / m_timeWindow) * (double)((*itStats).second.lastTtiBytesTrasmitted / 0.001));
1182  NS_LOG_INFO (this << " UE total bytes " << (*itStats).second.totalBytesTransmitted);
1183  NS_LOG_INFO (this << " UE average throughput " << (*itStats).second.lastAveragedThroughput);
1184  (*itStats).second.lastTtiBytesTrasmitted = 0;
1185  }
1186 
1188 
1189 
1190  return;
1191 }
1192 
1193 void
1195 {
1196  NS_LOG_FUNCTION (this);
1197 
1198  m_rachList = params.m_rachList;
1199 
1200  return;
1201 }
1202 
1203 void
1205 {
1206  NS_LOG_FUNCTION (this);
1207 
1208  for (unsigned int i = 0; i < params.m_cqiList.size (); i++)
1209  {
1210  if ( params.m_cqiList.at (i).m_cqiType == CqiListElement_s::P10 )
1211  {
1212  NS_LOG_LOGIC ("wideband CQI " << (uint32_t) params.m_cqiList.at (i).m_wbCqi.at (0) << " reported");
1213  std::map <uint16_t,uint8_t>::iterator it;
1214  uint16_t rnti = params.m_cqiList.at (i).m_rnti;
1215  it = m_p10CqiRxed.find (rnti);
1216  if (it == m_p10CqiRxed.end ())
1217  {
1218  // create the new entry
1219  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)
1220  // generate correspondent timer
1221  m_p10CqiTimers.insert ( std::pair<uint16_t, uint32_t > (rnti, m_cqiTimersThreshold));
1222  }
1223  else
1224  {
1225  // update the CQI value and refresh correspondent timer
1226  (*it).second = params.m_cqiList.at (i).m_wbCqi.at (0);
1227  // update correspondent timer
1228  std::map <uint16_t,uint32_t>::iterator itTimers;
1229  itTimers = m_p10CqiTimers.find (rnti);
1230  (*itTimers).second = m_cqiTimersThreshold;
1231  }
1232  }
1233  else if ( params.m_cqiList.at (i).m_cqiType == CqiListElement_s::A30 )
1234  {
1235  // subband CQI reporting high layer configured
1236  std::map <uint16_t,SbMeasResult_s>::iterator it;
1237  uint16_t rnti = params.m_cqiList.at (i).m_rnti;
1238  it = m_a30CqiRxed.find (rnti);
1239  if (it == m_a30CqiRxed.end ())
1240  {
1241  // create the new entry
1242  m_a30CqiRxed.insert ( std::pair<uint16_t, SbMeasResult_s > (rnti, params.m_cqiList.at (i).m_sbMeasResult) );
1243  m_a30CqiTimers.insert ( std::pair<uint16_t, uint32_t > (rnti, m_cqiTimersThreshold));
1244  }
1245  else
1246  {
1247  // update the CQI value and refresh correspondent timer
1248  (*it).second = params.m_cqiList.at (i).m_sbMeasResult;
1249  std::map <uint16_t,uint32_t>::iterator itTimers;
1250  itTimers = m_a30CqiTimers.find (rnti);
1251  (*itTimers).second = m_cqiTimersThreshold;
1252  }
1253  }
1254  else
1255  {
1256  NS_LOG_ERROR (this << " CQI type unknown");
1257  }
1258  }
1259 
1260  return;
1261 }
1262 
1263 
1264 double
1265 FdBetFfMacScheduler::EstimateUlSinr (uint16_t rnti, uint16_t rb)
1266 {
1267  std::map <uint16_t, std::vector <double> >::iterator itCqi = m_ueCqi.find (rnti);
1268  if (itCqi == m_ueCqi.end ())
1269  {
1270  // no cqi info about this UE
1271  return (NO_SINR);
1272 
1273  }
1274  else
1275  {
1276  // take the average SINR value among the available
1277  double sinrSum = 0;
1278  unsigned int sinrNum = 0;
1279  for (uint32_t i = 0; i < m_cschedCellConfig.m_ulBandwidth; i++)
1280  {
1281  double sinr = (*itCqi).second.at (i);
1282  if (sinr != NO_SINR)
1283  {
1284  sinrSum += sinr;
1285  sinrNum++;
1286  }
1287  }
1288  double estimatedSinr = (sinrNum > 0) ? (sinrSum / sinrNum) : DBL_MAX;
1289  // store the value
1290  (*itCqi).second.at (rb) = estimatedSinr;
1291  return (estimatedSinr);
1292  }
1293 }
1294 
1295 void
1297 {
1298  NS_LOG_FUNCTION (this << " UL - Frame no. " << (params.m_sfnSf >> 4) << " subframe no. " << (0xF & params.m_sfnSf) << " size " << params.m_ulInfoList.size ());
1299 
1300  RefreshUlCqiMaps ();
1301 
1302  // Generate RBs map
1304  std::vector <bool> rbMap;
1305  uint16_t rbAllocatedNum = 0;
1306  std::set <uint16_t> rntiAllocated;
1307  std::vector <uint16_t> rbgAllocationMap;
1308  // update with RACH allocation map
1309  rbgAllocationMap = m_rachAllocationMap;
1310  //rbgAllocationMap.resize (m_cschedCellConfig.m_ulBandwidth, 0);
1311  m_rachAllocationMap.clear ();
1313 
1314  rbMap.resize (m_cschedCellConfig.m_ulBandwidth, false);
1315  // remove RACH allocation
1316  for (uint16_t i = 0; i < m_cschedCellConfig.m_ulBandwidth; i++)
1317  {
1318  if (rbgAllocationMap.at (i) != 0)
1319  {
1320  rbMap.at (i) = true;
1321  NS_LOG_DEBUG (this << " Allocated for RACH " << i);
1322  }
1323  }
1324 
1325 
1326  if (m_harqOn == true)
1327  {
1328  // Process UL HARQ feedback
1329  for (uint16_t i = 0; i < params.m_ulInfoList.size (); i++)
1330  {
1331  if (params.m_ulInfoList.at (i).m_receptionStatus == UlInfoListElement_s::NotOk)
1332  {
1333  // retx correspondent block: retrieve the UL-DCI
1334  uint16_t rnti = params.m_ulInfoList.at (i).m_rnti;
1335  std::map <uint16_t, uint8_t>::iterator itProcId = m_ulHarqCurrentProcessId.find (rnti);
1336  if (itProcId == m_ulHarqCurrentProcessId.end ())
1337  {
1338  NS_LOG_ERROR ("No info find in HARQ buffer for UE (might change eNB) " << rnti);
1339  }
1340  uint8_t harqId = (uint8_t)((*itProcId).second - HARQ_PERIOD) % HARQ_PROC_NUM;
1341  NS_LOG_INFO (this << " UL-HARQ retx RNTI " << rnti << " harqId " << (uint16_t)harqId << " i " << i << " size " << params.m_ulInfoList.size ());
1342  std::map <uint16_t, UlHarqProcessesDciBuffer_t>::iterator itHarq = m_ulHarqProcessesDciBuffer.find (rnti);
1343  if (itHarq == m_ulHarqProcessesDciBuffer.end ())
1344  {
1345  NS_LOG_ERROR ("No info find in HARQ buffer for UE (might change eNB) " << rnti);
1346  continue;
1347  }
1348  UlDciListElement_s dci = (*itHarq).second.at (harqId);
1349  std::map <uint16_t, UlHarqProcessesStatus_t>::iterator itStat = m_ulHarqProcessesStatus.find (rnti);
1350  if (itStat == m_ulHarqProcessesStatus.end ())
1351  {
1352  NS_LOG_ERROR ("No info find in HARQ buffer for UE (might change eNB) " << rnti);
1353  }
1354  if ((*itStat).second.at (harqId) >= 3)
1355  {
1356  NS_LOG_INFO ("Max number of retransmissions reached (UL)-> drop process");
1357  continue;
1358  }
1359  bool free = true;
1360  for (int j = dci.m_rbStart; j < dci.m_rbStart + dci.m_rbLen; j++)
1361  {
1362  if (rbMap.at (j) == true)
1363  {
1364  free = false;
1365  NS_LOG_INFO (this << " BUSY " << j);
1366  }
1367  }
1368  if (free)
1369  {
1370  // retx on the same RBs
1371  for (int j = dci.m_rbStart; j < dci.m_rbStart + dci.m_rbLen; j++)
1372  {
1373  rbMap.at (j) = true;
1374  rbgAllocationMap.at (j) = dci.m_rnti;
1375  NS_LOG_INFO ("\tRB " << j);
1376  rbAllocatedNum++;
1377  }
1378  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);
1379  }
1380  else
1381  {
1382  NS_LOG_INFO ("Cannot allocate retx due to RACH allocations for UE " << rnti);
1383  continue;
1384  }
1385  dci.m_ndi = 0;
1386  // Update HARQ buffers with new HarqId
1387  (*itStat).second.at ((*itProcId).second) = (*itStat).second.at (harqId) + 1;
1388  (*itStat).second.at (harqId) = 0;
1389  (*itHarq).second.at ((*itProcId).second) = dci;
1390  ret.m_dciList.push_back (dci);
1391  rntiAllocated.insert (dci.m_rnti);
1392  }
1393  else
1394  {
1395  NS_LOG_INFO (this << " HARQ-ACK feedback from RNTI " << params.m_ulInfoList.at (i).m_rnti);
1396  }
1397  }
1398  }
1399 
1400  std::map <uint16_t,uint32_t>::iterator it;
1401  int nflows = 0;
1402 
1403  for (it = m_ceBsrRxed.begin (); it != m_ceBsrRxed.end (); it++)
1404  {
1405  std::set <uint16_t>::iterator itRnti = rntiAllocated.find ((*it).first);
1406  // select UEs with queues not empty and not yet allocated for HARQ
1407  if (((*it).second > 0)&&(itRnti == rntiAllocated.end ()))
1408  {
1409  nflows++;
1410  }
1411  }
1412 
1413  if (nflows == 0)
1414  {
1415  if (ret.m_dciList.size () > 0)
1416  {
1417  m_allocationMaps.insert (std::pair <uint16_t, std::vector <uint16_t> > (params.m_sfnSf, rbgAllocationMap));
1419  }
1420 
1421  return; // no flows to be scheduled
1422  }
1423 
1424 
1425  // Divide the remaining resources equally among the active users starting from the subsequent one served last scheduling trigger
1426  uint16_t rbPerFlow = (m_cschedCellConfig.m_ulBandwidth) / (nflows + rntiAllocated.size ());
1427  if (rbPerFlow < 3)
1428  {
1429  rbPerFlow = 3; // at least 3 rbg per flow (till available resource) to ensure TxOpportunity >= 7 bytes
1430  }
1431  int rbAllocated = 0;
1432 
1433  std::map <uint16_t, fdbetsFlowPerf_t>::iterator itStats;
1434  if (m_nextRntiUl != 0)
1435  {
1436  for (it = m_ceBsrRxed.begin (); it != m_ceBsrRxed.end (); it++)
1437  {
1438  if ((*it).first == m_nextRntiUl)
1439  {
1440  break;
1441  }
1442  }
1443  if (it == m_ceBsrRxed.end ())
1444  {
1445  NS_LOG_ERROR (this << " no user found");
1446  }
1447  }
1448  else
1449  {
1450  it = m_ceBsrRxed.begin ();
1451  m_nextRntiUl = (*it).first;
1452  }
1453  do
1454  {
1455  std::set <uint16_t>::iterator itRnti = rntiAllocated.find ((*it).first);
1456  if ((itRnti != rntiAllocated.end ())||((*it).second == 0))
1457  {
1458  // UE already allocated for UL-HARQ -> skip it
1459  NS_LOG_DEBUG (this << " UE already allocated in HARQ -> discared, RNTI " << (*it).first);
1460  it++;
1461  if (it == m_ceBsrRxed.end ())
1462  {
1463  // restart from the first
1464  it = m_ceBsrRxed.begin ();
1465  }
1466  continue;
1467  }
1468  if (rbAllocated + rbPerFlow - 1 > m_cschedCellConfig.m_ulBandwidth)
1469  {
1470  // limit to physical resources last resource assignment
1471  rbPerFlow = m_cschedCellConfig.m_ulBandwidth - rbAllocated;
1472  // at least 3 rbg per flow to ensure TxOpportunity >= 7 bytes
1473  if (rbPerFlow < 3)
1474  {
1475  // terminate allocation
1476  rbPerFlow = 0;
1477  }
1478  }
1479 
1480  UlDciListElement_s uldci;
1481  uldci.m_rnti = (*it).first;
1482  uldci.m_rbLen = rbPerFlow;
1483  bool allocated = false;
1484  NS_LOG_INFO (this << " RB Allocated " << rbAllocated << " rbPerFlow " << rbPerFlow << " flows " << nflows);
1485  while ((!allocated)&&((rbAllocated + rbPerFlow - m_cschedCellConfig.m_ulBandwidth) < 1) && (rbPerFlow != 0))
1486  {
1487  // check availability
1488  bool free = true;
1489  for (uint16_t j = rbAllocated; j < rbAllocated + rbPerFlow; j++)
1490  {
1491  if (rbMap.at (j) == true)
1492  {
1493  free = false;
1494  break;
1495  }
1496  }
1497  if (free)
1498  {
1499  uldci.m_rbStart = rbAllocated;
1500 
1501  for (uint16_t j = rbAllocated; j < rbAllocated + rbPerFlow; j++)
1502  {
1503  rbMap.at (j) = true;
1504  // store info on allocation for managing ul-cqi interpretation
1505  rbgAllocationMap.at (j) = (*it).first;
1506  }
1507  rbAllocated += rbPerFlow;
1508  allocated = true;
1509  break;
1510  }
1511  rbAllocated++;
1512  if (rbAllocated + rbPerFlow - 1 > m_cschedCellConfig.m_ulBandwidth)
1513  {
1514  // limit to physical resources last resource assignment
1515  rbPerFlow = m_cschedCellConfig.m_ulBandwidth - rbAllocated;
1516  // at least 3 rbg per flow to ensure TxOpportunity >= 7 bytes
1517  if (rbPerFlow < 3)
1518  {
1519  // terminate allocation
1520  rbPerFlow = 0;
1521  }
1522  }
1523  }
1524  if (!allocated)
1525  {
1526  // unable to allocate new resource: finish scheduling
1527  m_nextRntiUl = (*it).first;
1528  if (ret.m_dciList.size () > 0)
1529  {
1531  }
1532  m_allocationMaps.insert (std::pair <uint16_t, std::vector <uint16_t> > (params.m_sfnSf, rbgAllocationMap));
1533  return;
1534  }
1535 
1536 
1537 
1538  std::map <uint16_t, std::vector <double> >::iterator itCqi = m_ueCqi.find ((*it).first);
1539  int cqi = 0;
1540  if (itCqi == m_ueCqi.end ())
1541  {
1542  // no cqi info about this UE
1543  uldci.m_mcs = 0; // MCS 0 -> UL-AMC TBD
1544  }
1545  else
1546  {
1547  // take the lowest CQI value (worst RB)
1548  NS_ABORT_MSG_IF ((*itCqi).second.size() == 0, "CQI of RNTI = " << (*it).first << " has expired");
1549  double minSinr = (*itCqi).second.at (uldci.m_rbStart);
1550  if (minSinr == NO_SINR)
1551  {
1552  minSinr = EstimateUlSinr ((*it).first, uldci.m_rbStart);
1553  }
1554  for (uint16_t i = uldci.m_rbStart; i < uldci.m_rbStart + uldci.m_rbLen; i++)
1555  {
1556  double sinr = (*itCqi).second.at (i);
1557  if (sinr == NO_SINR)
1558  {
1559  sinr = EstimateUlSinr ((*it).first, i);
1560  }
1561  if (sinr < minSinr)
1562  {
1563  minSinr = sinr;
1564  }
1565  }
1566 
1567  // translate SINR -> cqi: WILD ACK: same as DL
1568  double s = log2 ( 1 + (
1569  std::pow (10, minSinr / 10 ) /
1570  ( (-std::log (5.0 * 0.00005 )) / 1.5) ));
1571  cqi = m_amc->GetCqiFromSpectralEfficiency (s);
1572  if (cqi == 0)
1573  {
1574  it++;
1575  if (it == m_ceBsrRxed.end ())
1576  {
1577  // restart from the first
1578  it = m_ceBsrRxed.begin ();
1579  }
1580  NS_LOG_DEBUG (this << " UE discarded for CQI = 0, RNTI " << uldci.m_rnti);
1581  // remove UE from allocation map
1582  for (uint16_t i = uldci.m_rbStart; i < uldci.m_rbStart + uldci.m_rbLen; i++)
1583  {
1584  rbgAllocationMap.at (i) = 0;
1585  }
1586  continue; // CQI == 0 means "out of range" (see table 7.2.3-1 of 36.213)
1587  }
1588  uldci.m_mcs = m_amc->GetMcsFromCqi (cqi);
1589  }
1590 
1591  uldci.m_tbSize = (m_amc->GetUlTbSizeFromMcs (uldci.m_mcs, rbPerFlow) / 8);
1592  UpdateUlRlcBufferInfo (uldci.m_rnti, uldci.m_tbSize);
1593  uldci.m_ndi = 1;
1594  uldci.m_cceIndex = 0;
1595  uldci.m_aggrLevel = 1;
1596  uldci.m_ueTxAntennaSelection = 3; // antenna selection OFF
1597  uldci.m_hopping = false;
1598  uldci.m_n2Dmrs = 0;
1599  uldci.m_tpc = 0; // no power control
1600  uldci.m_cqiRequest = false; // only period CQI at this stage
1601  uldci.m_ulIndex = 0; // TDD parameter
1602  uldci.m_dai = 1; // TDD parameter
1603  uldci.m_freqHopping = 0;
1604  uldci.m_pdcchPowerOffset = 0; // not used
1605  ret.m_dciList.push_back (uldci);
1606  // store DCI for HARQ_PERIOD
1607  uint8_t harqId = 0;
1608  if (m_harqOn == true)
1609  {
1610  std::map <uint16_t, uint8_t>::iterator itProcId;
1611  itProcId = m_ulHarqCurrentProcessId.find (uldci.m_rnti);
1612  if (itProcId == m_ulHarqCurrentProcessId.end ())
1613  {
1614  NS_FATAL_ERROR ("No info find in HARQ buffer for UE " << uldci.m_rnti);
1615  }
1616  harqId = (*itProcId).second;
1617  std::map <uint16_t, UlHarqProcessesDciBuffer_t>::iterator itDci = m_ulHarqProcessesDciBuffer.find (uldci.m_rnti);
1618  if (itDci == m_ulHarqProcessesDciBuffer.end ())
1619  {
1620  NS_FATAL_ERROR ("Unable to find RNTI entry in UL DCI HARQ buffer for RNTI " << uldci.m_rnti);
1621  }
1622  (*itDci).second.at (harqId) = uldci;
1623  // Update HARQ process status (RV 0)
1624  std::map <uint16_t, UlHarqProcessesStatus_t>::iterator itStat = m_ulHarqProcessesStatus.find (uldci.m_rnti);
1625  if (itStat == m_ulHarqProcessesStatus.end ())
1626  {
1627  NS_LOG_ERROR ("No info find in HARQ buffer for UE (might change eNB) " << uldci.m_rnti);
1628  }
1629  (*itStat).second.at (harqId) = 0;
1630  }
1631 
1632  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);
1633 
1634  // update TTI UE stats
1635  itStats = m_flowStatsUl.find ((*it).first);
1636  if (itStats != m_flowStatsUl.end ())
1637  {
1638  (*itStats).second.lastTtiBytesTrasmitted = uldci.m_tbSize;
1639  }
1640  else
1641  {
1642  NS_LOG_DEBUG (this << " No Stats for this allocated UE");
1643  }
1644 
1645 
1646  it++;
1647  if (it == m_ceBsrRxed.end ())
1648  {
1649  // restart from the first
1650  it = m_ceBsrRxed.begin ();
1651  }
1652  if ((rbAllocated == m_cschedCellConfig.m_ulBandwidth) || (rbPerFlow == 0))
1653  {
1654  // Stop allocation: no more PRBs
1655  m_nextRntiUl = (*it).first;
1656  break;
1657  }
1658  }
1659  while (((*it).first != m_nextRntiUl)&&(rbPerFlow!=0));
1660 
1661 
1662  // Update global UE stats
1663  // update UEs stats
1664  for (itStats = m_flowStatsUl.begin (); itStats != m_flowStatsUl.end (); itStats++)
1665  {
1666  (*itStats).second.totalBytesTransmitted += (*itStats).second.lastTtiBytesTrasmitted;
1667  // update average throughput (see eq. 12.3 of Sec 12.3.1.2 of LTE – The UMTS Long Term Evolution, Ed Wiley)
1668  (*itStats).second.lastAveragedThroughput = ((1.0 - (1.0 / m_timeWindow)) * (*itStats).second.lastAveragedThroughput) + ((1.0 / m_timeWindow) * (double)((*itStats).second.lastTtiBytesTrasmitted / 0.001));
1669  NS_LOG_INFO (this << " UE total bytes " << (*itStats).second.totalBytesTransmitted);
1670  NS_LOG_INFO (this << " UE average throughput " << (*itStats).second.lastAveragedThroughput);
1671  (*itStats).second.lastTtiBytesTrasmitted = 0;
1672  }
1673  m_allocationMaps.insert (std::pair <uint16_t, std::vector <uint16_t> > (params.m_sfnSf, rbgAllocationMap));
1675 
1676  return;
1677 }
1678 
1679 void
1681 {
1682  NS_LOG_FUNCTION (this);
1683  return;
1684 }
1685 
1686 void
1688 {
1689  NS_LOG_FUNCTION (this);
1690  return;
1691 }
1692 
1693 void
1695 {
1696  NS_LOG_FUNCTION (this);
1697 
1698  std::map <uint16_t,uint32_t>::iterator it;
1699 
1700  for (unsigned int i = 0; i < params.m_macCeList.size (); i++)
1701  {
1702  if ( params.m_macCeList.at (i).m_macCeType == MacCeListElement_s::BSR )
1703  {
1704  // buffer status report
1705  // note that this scheduler does not differentiate the
1706  // allocation according to which LCGs have more/less bytes
1707  // to send.
1708  // Hence the BSR of different LCGs are just summed up to get
1709  // a total queue size that is used for allocation purposes.
1710 
1711  uint32_t buffer = 0;
1712  for (uint8_t lcg = 0; lcg < 4; ++lcg)
1713  {
1714  uint8_t bsrId = params.m_macCeList.at (i).m_macCeValue.m_bufferStatus.at (lcg);
1715  buffer += BufferSizeLevelBsr::BsrId2BufferSize (bsrId);
1716  }
1717 
1718  uint16_t rnti = params.m_macCeList.at (i).m_rnti;
1719  NS_LOG_LOGIC (this << "RNTI=" << rnti << " buffer=" << buffer);
1720  it = m_ceBsrRxed.find (rnti);
1721  if (it == m_ceBsrRxed.end ())
1722  {
1723  // create the new entry
1724  m_ceBsrRxed.insert ( std::pair<uint16_t, uint32_t > (rnti, buffer));
1725  }
1726  else
1727  {
1728  // update the buffer size value
1729  (*it).second = buffer;
1730  }
1731  }
1732  }
1733 
1734  return;
1735 }
1736 
1737 void
1739 {
1740  NS_LOG_FUNCTION (this);
1741 // retrieve the allocation for this subframe
1742  switch (m_ulCqiFilter)
1743  {
1745  {
1746  // filter all the CQIs that are not SRS based
1747  if (params.m_ulCqi.m_type != UlCqi_s::SRS)
1748  {
1749  return;
1750  }
1751  }
1752  break;
1754  {
1755  // filter all the CQIs that are not SRS based
1756  if (params.m_ulCqi.m_type != UlCqi_s::PUSCH)
1757  {
1758  return;
1759  }
1760  }
1761  break;
1762  default:
1763  NS_FATAL_ERROR ("Unknown UL CQI type");
1764  }
1765 
1766  switch (params.m_ulCqi.m_type)
1767  {
1768  case UlCqi_s::PUSCH:
1769  {
1770  std::map <uint16_t, std::vector <uint16_t> >::iterator itMap;
1771  std::map <uint16_t, std::vector <double> >::iterator itCqi;
1772  NS_LOG_DEBUG (this << " Collect PUSCH CQIs of Frame no. " << (params.m_sfnSf >> 4) << " subframe no. " << (0xF & params.m_sfnSf));
1773  itMap = m_allocationMaps.find (params.m_sfnSf);
1774  if (itMap == m_allocationMaps.end ())
1775  {
1776  return;
1777  }
1778  for (uint32_t i = 0; i < (*itMap).second.size (); i++)
1779  {
1780  // convert from fixed point notation Sxxxxxxxxxxx.xxx to double
1781  double sinr = LteFfConverter::fpS11dot3toDouble (params.m_ulCqi.m_sinr.at (i));
1782  itCqi = m_ueCqi.find ((*itMap).second.at (i));
1783  if (itCqi == m_ueCqi.end ())
1784  {
1785  // create a new entry
1786  std::vector <double> newCqi;
1787  for (uint32_t j = 0; j < m_cschedCellConfig.m_ulBandwidth; j++)
1788  {
1789  if (i == j)
1790  {
1791  newCqi.push_back (sinr);
1792  }
1793  else
1794  {
1795  // initialize with NO_SINR value.
1796  newCqi.push_back (NO_SINR);
1797  }
1798 
1799  }
1800  m_ueCqi.insert (std::pair <uint16_t, std::vector <double> > ((*itMap).second.at (i), newCqi));
1801  // generate correspondent timer
1802  m_ueCqiTimers.insert (std::pair <uint16_t, uint32_t > ((*itMap).second.at (i), m_cqiTimersThreshold));
1803  }
1804  else
1805  {
1806  // update the value
1807  (*itCqi).second.at (i) = sinr;
1808  NS_LOG_DEBUG (this << " RNTI " << (*itMap).second.at (i) << " RB " << i << " SINR " << sinr);
1809  // update correspondent timer
1810  std::map <uint16_t, uint32_t>::iterator itTimers;
1811  itTimers = m_ueCqiTimers.find ((*itMap).second.at (i));
1812  (*itTimers).second = m_cqiTimersThreshold;
1813 
1814  }
1815 
1816  }
1817  // remove obsolete info on allocation
1818  m_allocationMaps.erase (itMap);
1819  }
1820  break;
1821  case UlCqi_s::SRS:
1822  {
1823  // get the RNTI from vendor specific parameters
1824  uint16_t rnti = 0;
1825  NS_ASSERT (params.m_vendorSpecificList.size () > 0);
1826  for (uint16_t i = 0; i < params.m_vendorSpecificList.size (); i++)
1827  {
1828  if (params.m_vendorSpecificList.at (i).m_type == SRS_CQI_RNTI_VSP)
1829  {
1830  Ptr<SrsCqiRntiVsp> vsp = DynamicCast<SrsCqiRntiVsp> (params.m_vendorSpecificList.at (i).m_value);
1831  rnti = vsp->GetRnti ();
1832  }
1833  }
1834  std::map <uint16_t, std::vector <double> >::iterator itCqi;
1835  itCqi = m_ueCqi.find (rnti);
1836  if (itCqi == m_ueCqi.end ())
1837  {
1838  // create a new entry
1839  std::vector <double> newCqi;
1840  for (uint32_t j = 0; j < m_cschedCellConfig.m_ulBandwidth; j++)
1841  {
1842  double sinr = LteFfConverter::fpS11dot3toDouble (params.m_ulCqi.m_sinr.at (j));
1843  newCqi.push_back (sinr);
1844  NS_LOG_INFO (this << " RNTI " << rnti << " new SRS-CQI for RB " << j << " value " << sinr);
1845 
1846  }
1847  m_ueCqi.insert (std::pair <uint16_t, std::vector <double> > (rnti, newCqi));
1848  // generate correspondent timer
1849  m_ueCqiTimers.insert (std::pair <uint16_t, uint32_t > (rnti, m_cqiTimersThreshold));
1850  }
1851  else
1852  {
1853  // update the values
1854  for (uint32_t j = 0; j < m_cschedCellConfig.m_ulBandwidth; j++)
1855  {
1856  double sinr = LteFfConverter::fpS11dot3toDouble (params.m_ulCqi.m_sinr.at (j));
1857  (*itCqi).second.at (j) = sinr;
1858  NS_LOG_INFO (this << " RNTI " << rnti << " update SRS-CQI for RB " << j << " value " << sinr);
1859  }
1860  // update correspondent timer
1861  std::map <uint16_t, uint32_t>::iterator itTimers;
1862  itTimers = m_ueCqiTimers.find (rnti);
1863  (*itTimers).second = m_cqiTimersThreshold;
1864 
1865  }
1866 
1867 
1868  }
1869  break;
1870  case UlCqi_s::PUCCH_1:
1871  case UlCqi_s::PUCCH_2:
1872  case UlCqi_s::PRACH:
1873  {
1874  NS_FATAL_ERROR ("FdBetFfMacScheduler supports only PUSCH and SRS UL-CQIs");
1875  }
1876  break;
1877  default:
1878  NS_FATAL_ERROR ("Unknown type of UL-CQI");
1879  }
1880  return;
1881 }
1882 
1883 void
1885 {
1886  // refresh DL CQI P01 Map
1887  std::map <uint16_t,uint32_t>::iterator itP10 = m_p10CqiTimers.begin ();
1888  while (itP10 != m_p10CqiTimers.end ())
1889  {
1890  NS_LOG_INFO (this << " P10-CQI for user " << (*itP10).first << " is " << (uint32_t)(*itP10).second << " thr " << (uint32_t)m_cqiTimersThreshold);
1891  if ((*itP10).second == 0)
1892  {
1893  // delete correspondent entries
1894  std::map <uint16_t,uint8_t>::iterator itMap = m_p10CqiRxed.find ((*itP10).first);
1895  NS_ASSERT_MSG (itMap != m_p10CqiRxed.end (), " Does not find CQI report for user " << (*itP10).first);
1896  NS_LOG_INFO (this << " P10-CQI expired for user " << (*itP10).first);
1897  m_p10CqiRxed.erase (itMap);
1898  std::map <uint16_t,uint32_t>::iterator temp = itP10;
1899  itP10++;
1900  m_p10CqiTimers.erase (temp);
1901  }
1902  else
1903  {
1904  (*itP10).second--;
1905  itP10++;
1906  }
1907  }
1908 
1909  // refresh DL CQI A30 Map
1910  std::map <uint16_t,uint32_t>::iterator itA30 = m_a30CqiTimers.begin ();
1911  while (itA30 != m_a30CqiTimers.end ())
1912  {
1913  NS_LOG_INFO (this << " A30-CQI for user " << (*itA30).first << " is " << (uint32_t)(*itA30).second << " thr " << (uint32_t)m_cqiTimersThreshold);
1914  if ((*itA30).second == 0)
1915  {
1916  // delete correspondent entries
1917  std::map <uint16_t,SbMeasResult_s>::iterator itMap = m_a30CqiRxed.find ((*itA30).first);
1918  NS_ASSERT_MSG (itMap != m_a30CqiRxed.end (), " Does not find CQI report for user " << (*itA30).first);
1919  NS_LOG_INFO (this << " A30-CQI expired for user " << (*itA30).first);
1920  m_a30CqiRxed.erase (itMap);
1921  std::map <uint16_t,uint32_t>::iterator temp = itA30;
1922  itA30++;
1923  m_a30CqiTimers.erase (temp);
1924  }
1925  else
1926  {
1927  (*itA30).second--;
1928  itA30++;
1929  }
1930  }
1931 
1932  return;
1933 }
1934 
1935 
1936 void
1938 {
1939  // refresh UL CQI Map
1940  std::map <uint16_t,uint32_t>::iterator itUl = m_ueCqiTimers.begin ();
1941  while (itUl != m_ueCqiTimers.end ())
1942  {
1943  NS_LOG_INFO (this << " UL-CQI for user " << (*itUl).first << " is " << (uint32_t)(*itUl).second << " thr " << (uint32_t)m_cqiTimersThreshold);
1944  if ((*itUl).second == 0)
1945  {
1946  // delete correspondent entries
1947  std::map <uint16_t, std::vector <double> >::iterator itMap = m_ueCqi.find ((*itUl).first);
1948  NS_ASSERT_MSG (itMap != m_ueCqi.end (), " Does not find CQI report for user " << (*itUl).first);
1949  NS_LOG_INFO (this << " UL-CQI exired for user " << (*itUl).first);
1950  (*itMap).second.clear ();
1951  m_ueCqi.erase (itMap);
1952  std::map <uint16_t,uint32_t>::iterator temp = itUl;
1953  itUl++;
1954  m_ueCqiTimers.erase (temp);
1955  }
1956  else
1957  {
1958  (*itUl).second--;
1959  itUl++;
1960  }
1961  }
1962 
1963  return;
1964 }
1965 
1966 void
1967 FdBetFfMacScheduler::UpdateDlRlcBufferInfo (uint16_t rnti, uint8_t lcid, uint16_t size)
1968 {
1969  std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it;
1970  LteFlowId_t flow (rnti, lcid);
1971  it = m_rlcBufferReq.find (flow);
1972  if (it != m_rlcBufferReq.end ())
1973  {
1974  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);
1975  // Update queues: RLC tx order Status, ReTx, Tx
1976  // Update status queue
1977  if (((*it).second.m_rlcStatusPduSize > 0) && (size >= (*it).second.m_rlcStatusPduSize))
1978  {
1979  (*it).second.m_rlcStatusPduSize = 0;
1980  }
1981  else if (((*it).second.m_rlcRetransmissionQueueSize > 0) && (size >= (*it).second.m_rlcRetransmissionQueueSize))
1982  {
1983  (*it).second.m_rlcRetransmissionQueueSize = 0;
1984  }
1985  else if ((*it).second.m_rlcTransmissionQueueSize > 0)
1986  {
1987  uint32_t rlcOverhead;
1988  if (lcid == 1)
1989  {
1990  // for SRB1 (using RLC AM) it's better to
1991  // overestimate RLC overhead rather than
1992  // underestimate it and risk unneeded
1993  // segmentation which increases delay
1994  rlcOverhead = 4;
1995  }
1996  else
1997  {
1998  // minimum RLC overhead due to header
1999  rlcOverhead = 2;
2000  }
2001  // update transmission queue
2002  if ((*it).second.m_rlcTransmissionQueueSize <= size - rlcOverhead)
2003  {
2004  (*it).second.m_rlcTransmissionQueueSize = 0;
2005  }
2006  else
2007  {
2008  (*it).second.m_rlcTransmissionQueueSize -= size - rlcOverhead;
2009  }
2010  }
2011  }
2012  else
2013  {
2014  NS_LOG_ERROR (this << " Does not find DL RLC Buffer Report of UE " << rnti);
2015  }
2016 }
2017 
2018 void
2019 FdBetFfMacScheduler::UpdateUlRlcBufferInfo (uint16_t rnti, uint16_t size)
2020 {
2021 
2022  size = size - 2; // remove the minimum RLC overhead
2023  std::map <uint16_t,uint32_t>::iterator it = m_ceBsrRxed.find (rnti);
2024  if (it != m_ceBsrRxed.end ())
2025  {
2026  NS_LOG_INFO (this << " UE " << rnti << " size " << size << " BSR " << (*it).second);
2027  if ((*it).second >= size)
2028  {
2029  (*it).second -= size;
2030  }
2031  else
2032  {
2033  (*it).second = 0;
2034  }
2035  }
2036  else
2037  {
2038  NS_LOG_ERROR (this << " Does not find BSR report info of UE " << rnti);
2039  }
2040 
2041 }
2042 
2043 void
2045 {
2046  NS_LOG_FUNCTION (this << " RNTI " << rnti << " txMode " << (uint16_t)txMode);
2048  params.m_rnti = rnti;
2049  params.m_transmissionMode = txMode;
2051 }
2052 
2053 
2054 }
virtual void SetFfMacCschedSapUser(FfMacCschedSapUser *s)
set the user part of the FfMacCschedSap that this Scheduler will interact with.
std::vector< struct UlInfoListElement_s > m_ulInfoList
UL info list.
See section 4.3.1 dlDciListElement.
Definition: ff-mac-common.h:93
Time flowStart
flow start time
void RefreshHarqProcesses()
Refresh HARQ processes according to the timers.
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
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by "...
void UpdateDlRlcBufferInfo(uint16_t rnti, uint8_t lcid, uint16_t size)
Update DL RLC buffer info.
virtual ~FdBetFfMacScheduler()
Destructor.
#define HARQ_PERIOD
Definition: lte-common.h:30
AttributeValue implementation for Boolean.
Definition: boolean.h:36
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition: object-base.h:45
static TypeId GetTypeId(void)
Get the type ID.
Parameters of the CSCHED_UE_CONFIG_CNF primitive.
Parameters of the CSCHED_UE_RELEASE_REQ primitive.
void DoSchedUlMacCtrlInfoReq(const struct FfMacSchedSapProvider::SchedUlMacCtrlInfoReqParameters &params)
Sched UL MAC control info request function.
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:85
void DoSchedUlNoiseInterferenceReq(const struct FfMacSchedSapProvider::SchedUlNoiseInterferenceReqParameters &params)
Sched UL noise interference request function.
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.
LteFfrSapUser * m_ffrSapUser
ffr sap user
uint16_t m_rnti
RNTI.
Definition: ff-mac-common.h:95
void RefreshDlCqiMaps(void)
Refresh DL CQI maps.
virtual void DoDispose(void)
Destructor implementation.
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
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:205
std::vector< uint8_t > m_mcs
MCS.
uint8_t UpdateHarqProcessId(uint16_t rnti)
Update and return a new process Id for the RNTI specified.
virtual void SetFfMacSchedSapUser(FfMacSchedSapUser *s)
set the user part of the FfMacSchedSap that this Scheduler will interact with.
See section 4.3.2 ulDciListElement.
Provides the CSCHED SAP.
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:281
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
Definition: fatal-error.h:165
See section 4.3.10 buildRARListElement.
std::map< uint16_t, fdbetsFlowPerf_t > m_flowStatsDl
Map of UE statistics (per RNTI basis) in downlink.
Parameters of the CSCHED_UE_CONFIG_UPDATE_IND primitive.
Parameters of the CSCHED_LC_RELEASE_REQ primitive.
virtual FfMacSchedSapProvider * GetFfMacSchedSapProvider()
std::vector< std::vector< struct RlcPduListElement_s > > m_rlcPduList
RLC PDU list.
std::map< uint16_t, uint8_t > m_p10CqiRxed
Map of UE&#39;s DL CQI P01 received.
std::vector< uint16_t > m_rachAllocationMap
rach allocation map
Parameters of the SCHED_DL_TRIGGER_REQ primitive.
std::map< uint16_t, DlHarqProcessesDciBuffer_t > m_dlHarqProcessesDciBuffer
DL HARQ process DCI buffer.
uint8_t m_rbLen
length
void DoSchedUlTriggerReq(const struct FfMacSchedSapProvider::SchedUlTriggerReqParameters &params)
Sched UL trigger request function.
uint8_t m_harqProcess
HARQ process.
FfMacSchedSapUser * m_schedSapUser
sched sap user
void DoSchedDlMacBufferReq(const struct FfMacSchedSapProvider::SchedDlMacBufferReqParameters &params)
Sched DL MAC buffer request function.
Implements the SCHED SAP and CSCHED SAP for a Frequency Domain Blind Equal Throughput scheduler...
std::vector< RlcPduList_t > DlHarqRlcPduListBuffer_t
vector of the 8 HARQ processes per UE
Parameters of the SCHED_DL_MAC_BUFFER_REQ primitive.
std::map< uint16_t, uint32_t > m_ueCqiTimers
Map of UEs&#39; timers on UL-CQI per RBG.
Parameters of the SCHED_DL_PAGING_BUFFER_REQ primitive.
void DoSchedUlCqiInfoReq(const struct FfMacSchedSapProvider::SchedUlCqiInfoReqParameters &params)
Sched UL CGI info request function.
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
The aggregation level.
void RefreshUlCqiMaps(void)
Refresh UL CQI maps.
unsigned int LcActivePerFlow(uint16_t rnti)
LC active per flow function.
std::map< uint16_t, UlHarqProcessesDciBuffer_t > m_ulHarqProcessesDciBuffer
UL HARQ process DCI Buffer.
Service Access Point (SAP) offered by the Frequency Reuse algorithm instance to the MAC Scheduler ins...
Definition: lte-ffr-sap.h:39
void DoCschedLcReleaseReq(const struct FfMacCschedSapProvider::CschedLcReleaseReqParameters &params)
CSched LC release request function.
Parameters of the SCHED_UL_TRIGGER_REQ primitive.
uint32_t m_rbBitmap
RB bitmap.
Definition: ff-mac-common.h:96
Hold an unsigned integer type.
Definition: uinteger.h:44
void DoCschedCellConfigReq(const struct FfMacCschedSapProvider::CschedCellConfigReqParameters &params)
CSched cell config request function.
static uint8_t TxMode2LayerNum(uint8_t txMode)
Transmit mode 2 layer number.
Definition: lte-common.cc:212
uint8_t HarqProcessAvailability(uint16_t rnti)
Return the availability of free process for the RNTI specified.
std::map< uint16_t, UlHarqProcessesStatus_t > m_ulHarqProcessesStatus
UL HARQ process status.
bool m_cqiRequest
CQI request.
std::vector< uint8_t > m_ndi
New data indicator.
FfMacCschedSapProvider * m_cschedSapProvider
csched sap provider
std::map< uint16_t, uint8_t > m_dlHarqCurrentProcessId
DL HARQ current process ID.
LteFfrSapProvider * m_ffrSapProvider
ffr sap provider
double lastAveragedThroughput
last averaged throughput
uint8_t m_cceIndex
Control Channel Element index.
unsigned long totalBytesTransmitted
total bytes transmitted
std::map< uint16_t, DlHarqProcessesStatus_t > m_dlHarqProcessesStatus
DL HARQ process status.
Provides the SCHED SAP.
virtual void SetLteFfrSapProvider(LteFfrSapProvider *s)
Set the Provider part of the LteFfrSap that this Scheduler will interact with.
std::map< uint16_t, uint32_t > m_p10CqiTimers
Map of UE&#39;s timers on DL CQI P01 received.
double EstimateUlSinr(uint16_t rnti, uint16_t rb)
Estimate UL SNR.
int8_t m_tpc
Tx power control command.
virtual FfMacCschedSapProvider * GetFfMacCschedSapProvider()
void UpdateUlRlcBufferInfo(uint16_t rnti, uint16_t size)
Update UL RLC buffer info.
virtual void CschedUeConfigCnf(const struct CschedUeConfigCnfParameters &params)=0
CSCHED_UE_CONFIG_CNF.
std::vector< uint8_t > m_logicalChannelIdentity
logical channel identity
#define NS_LOG_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
Definition: log.h:289
Parameters of the SCHED_UL_NOISE_INTERFERENCE_REQ primitive.
uint8_t m_logicalChannelIdentity
logical channel identity
std::vector< struct CqiListElement_s > m_cqiList
CQI list.
std::vector< struct DlInfoListElement_s > m_dlInfoList
DL info list.
std::map< uint16_t, DlHarqRlcPduListBuffer_t > m_dlHarqProcessesRlcPduListBuffer
DL HARQ process RLC PDU List.
FfMacSchedSapProvider * m_schedSapProvider
sched sap provider
virtual void SchedDlConfigInd(const struct SchedDlConfigIndParameters &params)=0
SCHED_DL_CONFIG_IND.
uint8_t m_tpc
Tx power control command.
int8_t m_pdcchPowerOffset
CCH power offset.
int GetRbgSize(int dlbandwidth)
Get RBG size function.
std::vector< uint16_t > m_tbsSize
The TBs size.
Definition: ff-mac-common.h:99
See section 4.3.9 rlcPDU_ListElement.
void DoSchedDlCqiInfoReq(const struct FfMacSchedSapProvider::SchedDlCqiInfoReqParameters &params)
Sched DL CGI info request function.
Every class exported by the ns3 library is enclosed in the ns3 namespace.
FfMacCschedSapUser * m_cschedSapUser
csched sap user
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.
std::map< uint16_t, std::vector< double > > m_ueCqi
Map of UEs&#39; UL-CQI per RBG.
std::map< uint16_t, uint8_t > m_uesTxMode
txMode of the UEs
std::vector< uint8_t > m_rv
Redundancy version.
virtual LteFfrSapUser * GetLteFfrSapUser()
MemberCschedSapProvider class.
virtual void SchedUlConfigInd(const struct SchedUlConfigIndParameters &params)=0
SCHED_UL_CONFIG_IND.
uint8_t m_ulIndex
UL index.
std::map< uint16_t, uint32_t > m_a30CqiTimers
Map of UE&#39;s timers on DL CQI A30 received.
static Time Now(void)
Return the current simulation virtual time.
Definition: simulator.cc:195
std::map< uint16_t, DlHarqProcessesTimer_t > m_dlHarqProcessesTimer
DL HARQ process timer.
uint16_t m_nextRntiUl
RNTI of the next user to be served next scheduling in UL.
UlCqiFilter_t m_ulCqiFilter
UL CQI filter.
std::vector< struct RachListElement_s > m_rachList
rach list
#define SRS_CQI_RNTI_VSP
This abstract base class identifies the interface by means of which the helper object can plug on the...
#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:88
FfMacCschedSapUser class.
uint8_t m_nrOfPdcchOfdmSymbols
number of PDCCH OFDM symbols
Parameters of the SCHED_DL_CQI_INFO_REQ primitive.
std::vector< struct MacCeListElement_s > m_macCeList
MAC CE list.
uint8_t m_ulGrantMcs
MCS for UL grant (default 0)
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< DlInfoListElement_s > m_dlInfoListBuffered
DL HARQ retx buffered.
std::vector< uint8_t > UlHarqProcessesStatus_t
UL HARQ process status vector.
void DoSchedDlRlcBufferReq(const struct FfMacSchedSapProvider::SchedDlRlcBufferReqParameters &params)
Sched DL RLC buffer request function.
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
Definition: abort.h:108
void DoSchedDlRachInfoReq(const struct FfMacSchedSapProvider::SchedDlRachInfoReqParameters &params)
Sched DL RACH info request function.
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
std::map< uint16_t, uint8_t > m_ulHarqCurrentProcessId
UL HARQ current process ID.
LteFlowId structure.
Definition: lte-common.h:36
Parameters of the SCHED_UL_MAC_CTRL_INFO_REQ primitive.
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition: log.h:273
Ptr< const AttributeChecker > MakeBooleanChecker(void)
Definition: boolean.cc:121
static const int FdBetType0AllocationRbg[4]
FdBetType0AllocationRbg array.
void TransmissionModeConfigurationUpdate(uint16_t rnti, uint8_t txMode)
Transmission mode configuration update function.
void DoCschedLcConfigReq(const struct FfMacCschedSapProvider::CschedLcConfigReqParameters &params)
Csched LC config request function.
unsigned int lastTtiBytesTrasmitted
last total bytes transmitted
Parameters of the SCHED_UL_SR_INFO_REQ primitive.
std::map< uint16_t, fdbetsFlowPerf_t > m_flowStatsUl
Map of UE statistics (per RNTI basis)
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 m_harqOn
m_harqOn when false inhibit the HARQ mechanisms (by default active)
#define NS_LOG_ERROR(msg)
Use NS_LOG to output a message of level LOG_ERROR.
Definition: log.h:257
Parameters of the SCHED_DL_RACH_INFO_REQ primitive.
void DoSchedDlPagingBufferReq(const struct FfMacSchedSapProvider::SchedDlPagingBufferReqParameters &params)
Sched DL paging buffer request function.
Parameters of the SCHED_UL_CONFIG_IND primitive.
MemberSchedSapProvider class.
Parameters of the CSCHED_UE_CONFIG_REQ primitive.
uint8_t m_dai
DL assignment index.
void DoCschedUeReleaseReq(const struct FfMacCschedSapProvider::CschedUeReleaseReqParameters &params)
CSched UE release request function.
#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
a unique identifier for an interface.
Definition: type-id.h:58
uint8_t m_resAlloc
The type of resource allocation.
Definition: ff-mac-common.h:98
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:923
std::map< LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters > m_rlcBufferReq
Vectors of UE&#39;s LC info.
#define HARQ_PROC_NUM
FfMacSchedSapUser class.
void DoCschedUeConfigReq(const struct FfMacCschedSapProvider::CschedUeConfigReqParameters &params)
Csched UE config request function.
FfMacCschedSapProvider::CschedCellConfigReqParameters m_cschedCellConfig
csched cell config
std::map< uint16_t, SbMeasResult_s > m_a30CqiRxed
Map of UE&#39;s DL CQI A30 received.
void DoSchedUlSrInfoReq(const struct FfMacSchedSapProvider::SchedUlSrInfoReqParameters &params)
Sched UL SR info request function.
std::vector< struct BuildDataListElement_s > m_buildDataList
build data list
uint8_t m_ueTxAntennaSelection
UE antenna selection.
std::map< uint16_t, uint32_t > m_ceBsrRxed
Map of UE&#39;s buffer status reports received.
void DoSchedDlTriggerReq(const struct FfMacSchedSapProvider::SchedDlTriggerReqParameters &params)
Sched DL trigger request function.
See section 4.3.8 builDataListElement.
fdbetsFlowPerf_t structure