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