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