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