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