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