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