A Discrete-Event Network Simulator
API
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
tdbet-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/tdbet-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 ("TdBetFfMacScheduler");
34 
35 namespace ns3 {
36 
37 int TdBetType0AllocationRbg[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 (TdBetFfMacScheduler);
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  TdBetFfMacScheduler* m_scheduler;
64 };
65 
66 TdBetSchedulerMemberCschedSapProvider::TdBetSchedulerMemberCschedSapProvider ()
67 {
68 }
69 
70 TdBetSchedulerMemberCschedSapProvider::TdBetSchedulerMemberCschedSapProvider (TdBetFfMacScheduler* scheduler) : m_scheduler (scheduler)
71 {
72 }
73 
74 
75 void
77 {
78  m_scheduler->DoCschedCellConfigReq (params);
79 }
80 
81 void
82 TdBetSchedulerMemberCschedSapProvider::CschedUeConfigReq (const struct CschedUeConfigReqParameters& params)
83 {
84  m_scheduler->DoCschedUeConfigReq (params);
85 }
86 
87 
88 void
89 TdBetSchedulerMemberCschedSapProvider::CschedLcConfigReq (const struct CschedLcConfigReqParameters& params)
90 {
91  m_scheduler->DoCschedLcConfigReq (params);
92 }
93 
94 void
95 TdBetSchedulerMemberCschedSapProvider::CschedLcReleaseReq (const struct CschedLcReleaseReqParameters& params)
96 {
97  m_scheduler->DoCschedLcReleaseReq (params);
98 }
99 
100 void
101 TdBetSchedulerMemberCschedSapProvider::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  TdBetFfMacScheduler* m_scheduler;
131 };
132 
133 
134 
135 TdBetSchedulerMemberSchedSapProvider::TdBetSchedulerMemberSchedSapProvider ()
136 {
137 }
138 
139 
140 TdBetSchedulerMemberSchedSapProvider::TdBetSchedulerMemberSchedSapProvider (TdBetFfMacScheduler* scheduler)
141  : m_scheduler (scheduler)
142 {
143 }
144 
145 void
146 TdBetSchedulerMemberSchedSapProvider::SchedDlRlcBufferReq (const struct SchedDlRlcBufferReqParameters& params)
147 {
148  m_scheduler->DoSchedDlRlcBufferReq (params);
149 }
150 
151 void
152 TdBetSchedulerMemberSchedSapProvider::SchedDlPagingBufferReq (const struct SchedDlPagingBufferReqParameters& params)
153 {
154  m_scheduler->DoSchedDlPagingBufferReq (params);
155 }
156 
157 void
158 TdBetSchedulerMemberSchedSapProvider::SchedDlMacBufferReq (const struct SchedDlMacBufferReqParameters& params)
159 {
160  m_scheduler->DoSchedDlMacBufferReq (params);
161 }
162 
163 void
164 TdBetSchedulerMemberSchedSapProvider::SchedDlTriggerReq (const struct SchedDlTriggerReqParameters& params)
165 {
166  m_scheduler->DoSchedDlTriggerReq (params);
167 }
168 
169 void
170 TdBetSchedulerMemberSchedSapProvider::SchedDlRachInfoReq (const struct SchedDlRachInfoReqParameters& params)
171 {
172  m_scheduler->DoSchedDlRachInfoReq (params);
173 }
174 
175 void
176 TdBetSchedulerMemberSchedSapProvider::SchedDlCqiInfoReq (const struct SchedDlCqiInfoReqParameters& params)
177 {
178  m_scheduler->DoSchedDlCqiInfoReq (params);
179 }
180 
181 void
182 TdBetSchedulerMemberSchedSapProvider::SchedUlTriggerReq (const struct SchedUlTriggerReqParameters& params)
183 {
184  m_scheduler->DoSchedUlTriggerReq (params);
185 }
186 
187 void
188 TdBetSchedulerMemberSchedSapProvider::SchedUlNoiseInterferenceReq (const struct SchedUlNoiseInterferenceReqParameters& params)
189 {
190  m_scheduler->DoSchedUlNoiseInterferenceReq (params);
191 }
192 
193 void
194 TdBetSchedulerMemberSchedSapProvider::SchedUlSrInfoReq (const struct SchedUlSrInfoReqParameters& params)
195 {
196  m_scheduler->DoSchedUlSrInfoReq (params);
197 }
198 
199 void
200 TdBetSchedulerMemberSchedSapProvider::SchedUlMacCtrlInfoReq (const struct SchedUlMacCtrlInfoReqParameters& params)
201 {
202  m_scheduler->DoSchedUlMacCtrlInfoReq (params);
203 }
204 
205 void
206 TdBetSchedulerMemberSchedSapProvider::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 TdBetSchedulerMemberCschedSapProvider (this);
223  m_schedSapProvider = new TdBetSchedulerMemberSchedSapProvider (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 TdBetFfMacScheduler::GetTypeId (void)
248 {
249  static TypeId tid = TypeId ("ns3::TdBetFfMacScheduler")
251  .AddConstructor<TdBetFfMacScheduler> ()
252  .AddAttribute ("CqiTimerThreshold",
253  "The number of TTIs a CQI is valid (default 1000 - 1 sec.)",
254  UintegerValue (1000),
255  MakeUintegerAccessor (&TdBetFfMacScheduler::m_cqiTimersThreshold),
256  MakeUintegerChecker<uint32_t> ())
257  .AddAttribute ("HarqEnabled",
258  "Activate/Deactivate the HARQ [by default is active].",
259  BooleanValue (true),
260  MakeBooleanAccessor (&TdBetFfMacScheduler::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 (&TdBetFfMacScheduler::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 TdBetFfMacScheduler::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 TdBetFfMacScheduler::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 TdBetFfMacScheduler::DoCschedLcConfigReq (const struct FfMacCschedSapProvider::CschedLcConfigReqParameters& params)
351 {
352  NS_LOG_FUNCTION (this << " New LC, rnti: " << params.m_rnti);
353 
354  std::map <uint16_t, tdbetsFlowPerf_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  tdbetsFlowPerf_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, tdbetsFlowPerf_t> (params.m_rnti, flowStatsDl));
367  tdbetsFlowPerf_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, tdbetsFlowPerf_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 TdBetFfMacScheduler::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 TdBetFfMacScheduler::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 TdBetFfMacScheduler::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 TdBetFfMacScheduler::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 TdBetFfMacScheduler::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 TdBetFfMacScheduler::GetRbgSize (int dlbandwidth)
491 {
492  for (int i = 0; i < 4; i++)
493  {
494  if (dlbandwidth < TdBetType0AllocationRbg[i])
495  {
496  return (i + 1);
497  }
498  }
499 
500  return (-1);
501 }
502 
503 
504 int
505 TdBetFfMacScheduler::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 TdBetFfMacScheduler::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 
959  std::map <uint16_t, tdbetsFlowPerf_t>::iterator it;
960  std::map <uint16_t, tdbetsFlowPerf_t>::iterator itMax = m_flowStatsDl.end ();
961  double metricMax = 0.0;
962  for (it = m_flowStatsDl.begin (); it != m_flowStatsDl.end (); it++)
963  {
964  std::set <uint16_t>::iterator itRnti = rntiAllocated.find ((*it).first);
965  if ((itRnti != rntiAllocated.end ())||(!HarqProcessAvailability ((*it).first)))
966  {
967  // UE already allocated for HARQ or without HARQ process available -> drop it
968  if (itRnti != rntiAllocated.end ())
969  {
970  NS_LOG_DEBUG (this << " RNTI discared for HARQ tx" << (uint16_t)(*it).first);
971  }
972  if (!HarqProcessAvailability ((*it).first))
973  {
974  NS_LOG_DEBUG (this << " RNTI discared for HARQ id" << (uint16_t)(*it).first);
975  }
976  continue;
977  }
978 
979  double metric = 1 / (*it).second.lastAveragedThroughput;
980 
981  if (metric > metricMax)
982  {
983  metricMax = metric;
984  itMax = it;
985  }
986  } // end for m_flowStatsDl
987 
988 
989  if (itMax == m_flowStatsDl.end ())
990  {
991  // no UE available for downlink
992  return;
993  }
994  else
995  {
996  // assign all RBGs to this UE
997  std::vector <uint16_t> tempMap;
998  for (int i = 0; i < rbgNum; i++)
999  {
1000  tempMap.push_back (i);
1001  }
1002  allocationMap.insert (std::pair <uint16_t, std::vector <uint16_t> > ((*itMax).first, tempMap));
1003  }
1004 
1005 
1006  // reset TTI stats of users
1007  std::map <uint16_t, tdbetsFlowPerf_t>::iterator itStats;
1008  for (itStats = m_flowStatsDl.begin (); itStats != m_flowStatsDl.end (); itStats++)
1009  {
1010  (*itStats).second.lastTtiBytesTrasmitted = 0;
1011  }
1012 
1013  // generate the transmission opportunities by grouping the RBGs of the same RNTI and
1014  // creating the correspondent DCIs
1015  std::map <uint16_t, std::vector <uint16_t> >::iterator itMap = allocationMap.begin ();
1016  while (itMap != allocationMap.end ())
1017  {
1018  // create new BuildDataListElement_s for this LC
1019  BuildDataListElement_s newEl;
1020  newEl.m_rnti = (*itMap).first;
1021  // create the DlDciListElement_s
1022  DlDciListElement_s newDci;
1023  newDci.m_rnti = (*itMap).first;
1024  newDci.m_harqProcess = UpdateHarqProcessId ((*itMap).first);
1025 
1026  uint16_t lcActives = LcActivePerFlow ((*itMap).first);
1027  NS_LOG_INFO (this << "Allocate user " << newEl.m_rnti << " rbg " << lcActives);
1028  uint16_t RgbPerRnti = (*itMap).second.size ();
1029  std::map <uint16_t,uint8_t>::iterator itCqi;
1030  itCqi = m_p10CqiRxed.find ((*itMap).first);
1031  std::map <uint16_t,uint8_t>::iterator itTxMode;
1032  itTxMode = m_uesTxMode.find ((*itMap).first);
1033  if (itTxMode == m_uesTxMode.end ())
1034  {
1035  NS_FATAL_ERROR ("No Transmission Mode info on user " << (*itMap).first);
1036  }
1037  int nLayer = TransmissionModesLayers::TxMode2LayerNum ((*itTxMode).second);
1038 
1039  uint32_t bytesTxed = 0;
1040  for (uint8_t j = 0; j < nLayer; j++)
1041  {
1042  if (itCqi == m_p10CqiRxed.end ())
1043  {
1044  newDci.m_mcs.push_back (0); // no info on this user -> lowest MCS
1045  }
1046  else
1047  {
1048  newDci.m_mcs.push_back ( m_amc->GetMcsFromCqi ((*itCqi).second) );
1049  }
1050 
1051  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)
1052  newDci.m_tbsSize.push_back (tbSize);
1053  bytesTxed += tbSize;
1054  }
1055 
1056  newDci.m_resAlloc = 0; // only allocation type 0 at this stage
1057  newDci.m_rbBitmap = 0; // TBD (32 bit bitmap see 7.1.6 of 36.213)
1058  uint32_t rbgMask = 0;
1059  for (uint16_t k = 0; k < (*itMap).second.size (); k++)
1060  {
1061  rbgMask = rbgMask + (0x1 << (*itMap).second.at (k));
1062  NS_LOG_INFO (this << " Allocated RBG " << (*itMap).second.at (k));
1063  }
1064  newDci.m_rbBitmap = rbgMask; // (32 bit bitmap see 7.1.6 of 36.213)
1065 
1066  // create the rlc PDUs -> equally divide resources among actives LCs
1067  std::map <LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator itBufReq;
1068  for (itBufReq = m_rlcBufferReq.begin (); itBufReq != m_rlcBufferReq.end (); itBufReq++)
1069  {
1070  if (((*itBufReq).first.m_rnti == (*itMap).first)
1071  && (((*itBufReq).second.m_rlcTransmissionQueueSize > 0)
1072  || ((*itBufReq).second.m_rlcRetransmissionQueueSize > 0)
1073  || ((*itBufReq).second.m_rlcStatusPduSize > 0) ))
1074  {
1075  std::vector <struct RlcPduListElement_s> newRlcPduLe;
1076  for (uint8_t j = 0; j < nLayer; j++)
1077  {
1078  RlcPduListElement_s newRlcEl;
1079  newRlcEl.m_logicalChannelIdentity = (*itBufReq).first.m_lcId;
1080  newRlcEl.m_size = newDci.m_tbsSize.at (j) / lcActives;
1081  NS_LOG_INFO (this << " LCID " << (uint32_t) newRlcEl.m_logicalChannelIdentity << " size " << newRlcEl.m_size << " layer " << (uint16_t)j);
1082  newRlcPduLe.push_back (newRlcEl);
1083  UpdateDlRlcBufferInfo (newDci.m_rnti, newRlcEl.m_logicalChannelIdentity, newRlcEl.m_size);
1084  if (m_harqOn == true)
1085  {
1086  // store RLC PDU list for HARQ
1087  std::map <uint16_t, DlHarqRlcPduListBuffer_t>::iterator itRlcPdu = m_dlHarqProcessesRlcPduListBuffer.find ((*itMap).first);
1088  if (itRlcPdu == m_dlHarqProcessesRlcPduListBuffer.end ())
1089  {
1090  NS_FATAL_ERROR ("Unable to find RlcPdcList in HARQ buffer for RNTI " << (*itMap).first);
1091  }
1092  (*itRlcPdu).second.at (j).at (newDci.m_harqProcess).push_back (newRlcEl);
1093  }
1094  }
1095  newEl.m_rlcPduList.push_back (newRlcPduLe);
1096  }
1097  if ((*itBufReq).first.m_rnti > (*itMap).first)
1098  {
1099  break;
1100  }
1101  }
1102  for (uint8_t j = 0; j < nLayer; j++)
1103  {
1104  newDci.m_ndi.push_back (1);
1105  newDci.m_rv.push_back (0);
1106  }
1107 
1108  newEl.m_dci = newDci;
1109 
1110  if (m_harqOn == true)
1111  {
1112  // store DCI for HARQ
1113  std::map <uint16_t, DlHarqProcessesDciBuffer_t>::iterator itDci = m_dlHarqProcessesDciBuffer.find (newEl.m_rnti);
1114  if (itDci == m_dlHarqProcessesDciBuffer.end ())
1115  {
1116  NS_FATAL_ERROR ("Unable to find RNTI entry in DCI HARQ buffer for RNTI " << newEl.m_rnti);
1117  }
1118  (*itDci).second.at (newDci.m_harqProcess) = newDci;
1119  // refresh timer
1120  std::map <uint16_t, DlHarqProcessesTimer_t>::iterator itHarqTimer = m_dlHarqProcessesTimer.find (newEl.m_rnti);
1121  if (itHarqTimer== m_dlHarqProcessesTimer.end ())
1122  {
1123  NS_FATAL_ERROR ("Unable to find HARQ timer for RNTI " << (uint16_t)newEl.m_rnti);
1124  }
1125  (*itHarqTimer).second.at (newDci.m_harqProcess) = 0;
1126  }
1127 
1128  // ...more parameters -> ingored in this version
1129 
1130  ret.m_buildDataList.push_back (newEl);
1131  // update UE stats
1132  std::map <uint16_t, tdbetsFlowPerf_t>::iterator it;
1133  it = m_flowStatsDl.find ((*itMap).first);
1134  if (it != m_flowStatsDl.end ())
1135  {
1136  (*it).second.lastTtiBytesTrasmitted = bytesTxed;
1137  NS_LOG_INFO (this << " UE total bytes txed " << (*it).second.lastTtiBytesTrasmitted);
1138 
1139 
1140  }
1141  else
1142  {
1143  NS_FATAL_ERROR (this << " No Stats for this allocated UE");
1144  }
1145 
1146  itMap++;
1147  } // end while allocation
1148  ret.m_nrOfPdcchOfdmSymbols = 1; // TODO: check correct value according the DCIs txed
1149 
1150 
1151  // update UEs stats
1152  NS_LOG_INFO (this << " Update UEs statistics");
1153  for (itStats = m_flowStatsDl.begin (); itStats != m_flowStatsDl.end (); itStats++)
1154  {
1155  (*itStats).second.totalBytesTransmitted += (*itStats).second.lastTtiBytesTrasmitted;
1156  // update average throughput (see eq. 12.3 of Sec 12.3.1.2 of LTE – The UMTS Long Term Evolution, Ed Wiley)
1157  (*itStats).second.lastAveragedThroughput = ((1.0 - (1.0 / m_timeWindow)) * (*itStats).second.lastAveragedThroughput) + ((1.0 / m_timeWindow) * (double)((*itStats).second.lastTtiBytesTrasmitted / 0.001));
1158  NS_LOG_INFO (this << " UE total bytes " << (*itStats).second.totalBytesTransmitted);
1159  NS_LOG_INFO (this << " UE average throughput " << (*itStats).second.lastAveragedThroughput);
1160  (*itStats).second.lastTtiBytesTrasmitted = 0;
1161  }
1162 
1163  m_schedSapUser->SchedDlConfigInd (ret);
1164 
1165 
1166  return;
1167 }
1168 
1169 void
1170 TdBetFfMacScheduler::DoSchedDlRachInfoReq (const struct FfMacSchedSapProvider::SchedDlRachInfoReqParameters& params)
1171 {
1172  NS_LOG_FUNCTION (this);
1173 
1174  m_rachList = params.m_rachList;
1175 
1176  return;
1177 }
1178 
1179 void
1180 TdBetFfMacScheduler::DoSchedDlCqiInfoReq (const struct FfMacSchedSapProvider::SchedDlCqiInfoReqParameters& params)
1181 {
1182  NS_LOG_FUNCTION (this);
1183 
1184  for (unsigned int i = 0; i < params.m_cqiList.size (); i++)
1185  {
1186  if ( params.m_cqiList.at (i).m_cqiType == CqiListElement_s::P10 )
1187  {
1188  // wideband CQI reporting
1189  std::map <uint16_t,uint8_t>::iterator it;
1190  uint16_t rnti = params.m_cqiList.at (i).m_rnti;
1191  it = m_p10CqiRxed.find (rnti);
1192  if (it == m_p10CqiRxed.end ())
1193  {
1194  // create the new entry
1195  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)
1196  // generate correspondent timer
1197  m_p10CqiTimers.insert ( std::pair<uint16_t, uint32_t > (rnti, m_cqiTimersThreshold));
1198  }
1199  else
1200  {
1201  // update the CQI value and refresh correspondent timer
1202  (*it).second = params.m_cqiList.at (i).m_wbCqi.at (0);
1203  // update correspondent timer
1204  std::map <uint16_t,uint32_t>::iterator itTimers;
1205  itTimers = m_p10CqiTimers.find (rnti);
1206  (*itTimers).second = m_cqiTimersThreshold;
1207  }
1208  }
1209  else if ( params.m_cqiList.at (i).m_cqiType == CqiListElement_s::A30 )
1210  {
1211  // subband CQI reporting high layer configured
1212  std::map <uint16_t,SbMeasResult_s>::iterator it;
1213  uint16_t rnti = params.m_cqiList.at (i).m_rnti;
1214  it = m_a30CqiRxed.find (rnti);
1215  if (it == m_a30CqiRxed.end ())
1216  {
1217  // create the new entry
1218  m_a30CqiRxed.insert ( std::pair<uint16_t, SbMeasResult_s > (rnti, params.m_cqiList.at (i).m_sbMeasResult) );
1219  m_a30CqiTimers.insert ( std::pair<uint16_t, uint32_t > (rnti, m_cqiTimersThreshold));
1220  }
1221  else
1222  {
1223  // update the CQI value and refresh correspondent timer
1224  (*it).second = params.m_cqiList.at (i).m_sbMeasResult;
1225  std::map <uint16_t,uint32_t>::iterator itTimers;
1226  itTimers = m_a30CqiTimers.find (rnti);
1227  (*itTimers).second = m_cqiTimersThreshold;
1228  }
1229  }
1230  else
1231  {
1232  NS_LOG_ERROR (this << " CQI type unknown");
1233  }
1234  }
1235 
1236  return;
1237 }
1238 
1239 
1240 double
1241 TdBetFfMacScheduler::EstimateUlSinr (uint16_t rnti, uint16_t rb)
1242 {
1243  std::map <uint16_t, std::vector <double> >::iterator itCqi = m_ueCqi.find (rnti);
1244  if (itCqi == m_ueCqi.end ())
1245  {
1246  // no cqi info about this UE
1247  return (NO_SINR);
1248 
1249  }
1250  else
1251  {
1252  // take the average SINR value among the available
1253  double sinrSum = 0;
1254  int sinrNum = 0;
1255  for (uint32_t i = 0; i < m_cschedCellConfig.m_ulBandwidth; i++)
1256  {
1257  double sinr = (*itCqi).second.at (i);
1258  if (sinr != NO_SINR)
1259  {
1260  sinrSum += sinr;
1261  sinrNum++;
1262  }
1263  }
1264  double estimatedSinr = sinrSum / (double)sinrNum;
1265  // store the value
1266  (*itCqi).second.at (rb) = estimatedSinr;
1267  return (estimatedSinr);
1268  }
1269 }
1270 
1271 void
1272 TdBetFfMacScheduler::DoSchedUlTriggerReq (const struct FfMacSchedSapProvider::SchedUlTriggerReqParameters& params)
1273 {
1274  NS_LOG_FUNCTION (this << " UL - Frame no. " << (params.m_sfnSf >> 4) << " subframe no. " << (0xF & params.m_sfnSf) << " size " << params.m_ulInfoList.size ());
1275 
1276  RefreshUlCqiMaps ();
1277 
1278  // Generate RBs map
1279  FfMacSchedSapUser::SchedUlConfigIndParameters ret;
1280  std::vector <bool> rbMap;
1281  uint16_t rbAllocatedNum = 0;
1282  std::set <uint16_t> rntiAllocated;
1283  std::vector <uint16_t> rbgAllocationMap;
1284  // update with RACH allocation map
1285  rbgAllocationMap = m_rachAllocationMap;
1286  //rbgAllocationMap.resize (m_cschedCellConfig.m_ulBandwidth, 0);
1287  m_rachAllocationMap.clear ();
1288  m_rachAllocationMap.resize (m_cschedCellConfig.m_ulBandwidth, 0);
1289 
1290  rbMap.resize (m_cschedCellConfig.m_ulBandwidth, false);
1291  // remove RACH allocation
1292  for (uint16_t i = 0; i < m_cschedCellConfig.m_ulBandwidth; i++)
1293  {
1294  if (rbgAllocationMap.at (i) != 0)
1295  {
1296  rbMap.at (i) = true;
1297  NS_LOG_DEBUG (this << " Allocated for RACH " << i);
1298  }
1299  }
1300 
1301 
1302  if (m_harqOn == true)
1303  {
1304  // Process UL HARQ feedback
1305  // update UL HARQ proc id
1306  std::map <uint16_t, uint8_t>::iterator itProcId;
1307  for (itProcId = m_ulHarqCurrentProcessId.begin (); itProcId != m_ulHarqCurrentProcessId.end (); itProcId++)
1308  {
1309  (*itProcId).second = ((*itProcId).second + 1) % HARQ_PROC_NUM;
1310  }
1311 
1312  for (uint16_t i = 0; i < params.m_ulInfoList.size (); i++)
1313  {
1314  if (params.m_ulInfoList.at (i).m_receptionStatus == UlInfoListElement_s::NotOk)
1315  {
1316  // retx correspondent block: retrieve the UL-DCI
1317  uint16_t rnti = params.m_ulInfoList.at (i).m_rnti;
1318  itProcId = m_ulHarqCurrentProcessId.find (rnti);
1319  if (itProcId == m_ulHarqCurrentProcessId.end ())
1320  {
1321  NS_LOG_ERROR ("No info find in HARQ buffer for UE (might change eNB) " << rnti);
1322  }
1323  uint8_t harqId = (uint8_t)((*itProcId).second - HARQ_PERIOD) % HARQ_PROC_NUM;
1324  NS_LOG_INFO (this << " UL-HARQ retx RNTI " << rnti << " harqId " << (uint16_t)harqId << " i " << i << " size " << params.m_ulInfoList.size ());
1325  std::map <uint16_t, UlHarqProcessesDciBuffer_t>::iterator itHarq = m_ulHarqProcessesDciBuffer.find (rnti);
1326  if (itHarq == m_ulHarqProcessesDciBuffer.end ())
1327  {
1328  NS_LOG_ERROR ("No info find in HARQ buffer for UE (might change eNB) " << rnti);
1329  continue;
1330  }
1331  UlDciListElement_s dci = (*itHarq).second.at (harqId);
1332  std::map <uint16_t, UlHarqProcessesStatus_t>::iterator itStat = m_ulHarqProcessesStatus.find (rnti);
1333  if (itStat == m_ulHarqProcessesStatus.end ())
1334  {
1335  NS_LOG_ERROR ("No info find in HARQ buffer for UE (might change eNB) " << rnti);
1336  }
1337  if ((*itStat).second.at (harqId) >= 3)
1338  {
1339  NS_LOG_INFO ("Max number of retransmissions reached (UL)-> drop process");
1340  continue;
1341  }
1342  bool free = true;
1343  for (int j = dci.m_rbStart; j < dci.m_rbStart + dci.m_rbLen; j++)
1344  {
1345  if (rbMap.at (j) == true)
1346  {
1347  free = false;
1348  NS_LOG_INFO (this << " BUSY " << j);
1349  }
1350  }
1351  if (free)
1352  {
1353  // retx on the same RBs
1354  for (int j = dci.m_rbStart; j < dci.m_rbStart + dci.m_rbLen; j++)
1355  {
1356  rbMap.at (j) = true;
1357  rbgAllocationMap.at (j) = dci.m_rnti;
1358  NS_LOG_INFO ("\tRB " << j);
1359  rbAllocatedNum++;
1360  }
1361  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);
1362  }
1363  else
1364  {
1365  NS_LOG_INFO ("Cannot allocate retx due to RACH allocations for UE " << rnti);
1366  continue;
1367  }
1368  dci.m_ndi = 0;
1369  // Update HARQ buffers with new HarqId
1370  (*itStat).second.at ((*itProcId).second) = (*itStat).second.at (harqId) + 1;
1371  (*itStat).second.at (harqId) = 0;
1372  (*itHarq).second.at ((*itProcId).second) = dci;
1373  ret.m_dciList.push_back (dci);
1374  rntiAllocated.insert (dci.m_rnti);
1375  }
1376  else
1377  {
1378  NS_LOG_INFO (this << " HARQ-ACK feedback from RNTI " << params.m_ulInfoList.at (i).m_rnti);
1379  }
1380  }
1381  }
1382 
1383  std::map <uint16_t,uint32_t>::iterator it;
1384  int nflows = 0;
1385 
1386  for (it = m_ceBsrRxed.begin (); it != m_ceBsrRxed.end (); it++)
1387  {
1388  std::set <uint16_t>::iterator itRnti = rntiAllocated.find ((*it).first);
1389  // select UEs with queues not empty and not yet allocated for HARQ
1390  if (((*it).second > 0)&&(itRnti == rntiAllocated.end ()))
1391  {
1392  nflows++;
1393  }
1394  }
1395 
1396  if (nflows == 0)
1397  {
1398  if (ret.m_dciList.size () > 0)
1399  {
1400  m_schedSapUser->SchedUlConfigInd (ret);
1401  }
1402 
1403  return; // no flows to be scheduled
1404  }
1405 
1406 
1407  // Divide the remaining resources equally among the active users starting from the subsequent one served last scheduling trigger
1408  uint16_t rbPerFlow = (m_cschedCellConfig.m_ulBandwidth) / (nflows + rntiAllocated.size ());
1409  if (rbPerFlow < 3)
1410  {
1411  rbPerFlow = 3; // at least 3 rbg per flow (till available resource) to ensure TxOpportunity >= 7 bytes
1412  }
1413  int rbAllocated = 0;
1414 
1415  std::map <uint16_t, tdbetsFlowPerf_t>::iterator itStats;
1416  if (m_nextRntiUl != 0)
1417  {
1418  for (it = m_ceBsrRxed.begin (); it != m_ceBsrRxed.end (); it++)
1419  {
1420  if ((*it).first == m_nextRntiUl)
1421  {
1422  break;
1423  }
1424  }
1425  if (it == m_ceBsrRxed.end ())
1426  {
1427  NS_LOG_ERROR (this << " no user found");
1428  }
1429  }
1430  else
1431  {
1432  it = m_ceBsrRxed.begin ();
1433  m_nextRntiUl = (*it).first;
1434  }
1435  do
1436  {
1437  std::set <uint16_t>::iterator itRnti = rntiAllocated.find ((*it).first);
1438  if ((itRnti != rntiAllocated.end ())||((*it).second == 0))
1439  {
1440  // UE already allocated for UL-HARQ -> skip it
1441  it++;
1442  if (it == m_ceBsrRxed.end ())
1443  {
1444  // restart from the first
1445  it = m_ceBsrRxed.begin ();
1446  }
1447  continue;
1448  }
1449  if (rbAllocated + rbPerFlow - 1 > m_cschedCellConfig.m_ulBandwidth)
1450  {
1451  // limit to physical resources last resource assignment
1452  rbPerFlow = m_cschedCellConfig.m_ulBandwidth - rbAllocated;
1453  // at least 3 rbg per flow to ensure TxOpportunity >= 7 bytes
1454  if (rbPerFlow < 3)
1455  {
1456  // terminate allocation
1457  rbPerFlow = 0;
1458  }
1459  }
1460 
1461  UlDciListElement_s uldci;
1462  uldci.m_rnti = (*it).first;
1463  uldci.m_rbLen = rbPerFlow;
1464  bool allocated = false;
1465  NS_LOG_INFO (this << " RB Allocated " << rbAllocated << " rbPerFlow " << rbPerFlow);
1466  while ((!allocated)&&((rbAllocated + rbPerFlow - 1) < m_cschedCellConfig.m_ulBandwidth) && (rbPerFlow != 0))
1467  {
1468  // check availability
1469  bool free = true;
1470  for (uint16_t j = rbAllocated; j < rbAllocated + rbPerFlow; j++)
1471  {
1472  if (rbMap.at (j) == true)
1473  {
1474  free = false;
1475  break;
1476  }
1477  }
1478  if (free)
1479  {
1480  uldci.m_rbStart = rbAllocated;
1481 
1482  for (uint16_t j = rbAllocated; j < rbAllocated + rbPerFlow; j++)
1483  {
1484  rbMap.at (j) = true;
1485  // store info on allocation for managing ul-cqi interpretation
1486  rbgAllocationMap.at (j) = (*it).first;
1487  }
1488  rbAllocated += rbPerFlow;
1489  allocated = true;
1490  break;
1491  }
1492  rbAllocated++;
1493  if (rbAllocated + rbPerFlow - 1 > m_cschedCellConfig.m_ulBandwidth)
1494  {
1495  // limit to physical resources last resource assignment
1496  rbPerFlow = m_cschedCellConfig.m_ulBandwidth - rbAllocated;
1497  // at least 3 rbg per flow to ensure TxOpportunity >= 7 bytes
1498  if (rbPerFlow < 3)
1499  {
1500  // terminate allocation
1501  rbPerFlow = 0;
1502  }
1503  }
1504  }
1505  if (!allocated)
1506  {
1507  // unable to allocate new resource: finish scheduling
1508  m_nextRntiUl = (*it).first;
1509  if (ret.m_dciList.size () > 0)
1510  {
1511  m_schedSapUser->SchedUlConfigInd (ret);
1512  }
1513  m_allocationMaps.insert (std::pair <uint16_t, std::vector <uint16_t> > (params.m_sfnSf, rbgAllocationMap));
1514  return;
1515  }
1516 
1517 
1518 
1519  std::map <uint16_t, std::vector <double> >::iterator itCqi = m_ueCqi.find ((*it).first);
1520  int cqi = 0;
1521  if (itCqi == m_ueCqi.end ())
1522  {
1523  // no cqi info about this UE
1524  uldci.m_mcs = 0; // MCS 0 -> UL-AMC TBD
1525  }
1526  else
1527  {
1528  // take the lowest CQI value (worst RB)
1529  double minSinr = (*itCqi).second.at (uldci.m_rbStart);
1530  if (minSinr == NO_SINR)
1531  {
1532  minSinr = EstimateUlSinr ((*it).first, uldci.m_rbStart);
1533  }
1534  for (uint16_t i = uldci.m_rbStart; i < uldci.m_rbStart + uldci.m_rbLen; i++)
1535  {
1536  double sinr = (*itCqi).second.at (i);
1537  if (sinr == NO_SINR)
1538  {
1539  sinr = EstimateUlSinr ((*it).first, i);
1540  }
1541  if ((*itCqi).second.at (i) < minSinr)
1542  {
1543  minSinr = (*itCqi).second.at (i);
1544  }
1545  }
1546 
1547  // translate SINR -> cqi: WILD ACK: same as DL
1548  double s = log2 ( 1 + (
1549  pow (10, minSinr / 10 ) /
1550  ( (-log (5.0 * 0.00005 )) / 1.5) ));
1551  cqi = m_amc->GetCqiFromSpectralEfficiency (s);
1552  if (cqi == 0)
1553  {
1554  it++;
1555  if (it == m_ceBsrRxed.end ())
1556  {
1557  // restart from the first
1558  it = m_ceBsrRxed.begin ();
1559  }
1560  continue; // CQI == 0 means "out of range" (see table 7.2.3-1 of 36.213)
1561  }
1562  uldci.m_mcs = m_amc->GetMcsFromCqi (cqi);
1563  }
1564 
1565  uldci.m_tbSize = (m_amc->GetTbSizeFromMcs (uldci.m_mcs, rbPerFlow) / 8);
1566  UpdateUlRlcBufferInfo (uldci.m_rnti, uldci.m_tbSize);
1567  uldci.m_ndi = 1;
1568  uldci.m_cceIndex = 0;
1569  uldci.m_aggrLevel = 1;
1570  uldci.m_ueTxAntennaSelection = 3; // antenna selection OFF
1571  uldci.m_hopping = false;
1572  uldci.m_n2Dmrs = 0;
1573  uldci.m_tpc = 0; // no power control
1574  uldci.m_cqiRequest = false; // only period CQI at this stage
1575  uldci.m_ulIndex = 0; // TDD parameter
1576  uldci.m_dai = 1; // TDD parameter
1577  uldci.m_freqHopping = 0;
1578  uldci.m_pdcchPowerOffset = 0; // not used
1579  ret.m_dciList.push_back (uldci);
1580  // store DCI for HARQ_PERIOD
1581  uint8_t harqId = 0;
1582  if (m_harqOn == true)
1583  {
1584  std::map <uint16_t, uint8_t>::iterator itProcId;
1585  itProcId = m_ulHarqCurrentProcessId.find (uldci.m_rnti);
1586  if (itProcId == m_ulHarqCurrentProcessId.end ())
1587  {
1588  NS_FATAL_ERROR ("No info find in HARQ buffer for UE " << uldci.m_rnti);
1589  }
1590  harqId = (*itProcId).second;
1591  std::map <uint16_t, UlHarqProcessesDciBuffer_t>::iterator itDci = m_ulHarqProcessesDciBuffer.find (uldci.m_rnti);
1592  if (itDci == m_ulHarqProcessesDciBuffer.end ())
1593  {
1594  NS_FATAL_ERROR ("Unable to find RNTI entry in UL DCI HARQ buffer for RNTI " << uldci.m_rnti);
1595  }
1596  (*itDci).second.at (harqId) = uldci;
1597  }
1598 
1599  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);
1600 
1601  // update TTI UE stats
1602  itStats = m_flowStatsUl.find ((*it).first);
1603  if (itStats != m_flowStatsUl.end ())
1604  {
1605  (*itStats).second.lastTtiBytesTrasmitted = uldci.m_tbSize;
1606  }
1607  else
1608  {
1609  NS_LOG_DEBUG (this << " No Stats for this allocated UE");
1610  }
1611 
1612 
1613  it++;
1614  if (it == m_ceBsrRxed.end ())
1615  {
1616  // restart from the first
1617  it = m_ceBsrRxed.begin ();
1618  }
1619  if ((rbAllocated == m_cschedCellConfig.m_ulBandwidth) || (rbPerFlow == 0))
1620  {
1621  // Stop allocation: no more PRBs
1622  m_nextRntiUl = (*it).first;
1623  break;
1624  }
1625  }
1626  while (((*it).first != m_nextRntiUl)&&(rbPerFlow!=0));
1627 
1628 
1629  // Update global UE stats
1630  // update UEs stats
1631  for (itStats = m_flowStatsUl.begin (); itStats != m_flowStatsUl.end (); itStats++)
1632  {
1633  (*itStats).second.totalBytesTransmitted += (*itStats).second.lastTtiBytesTrasmitted;
1634  // update average throughput (see eq. 12.3 of Sec 12.3.1.2 of LTE – The UMTS Long Term Evolution, Ed Wiley)
1635  (*itStats).second.lastAveragedThroughput = ((1.0 - (1.0 / m_timeWindow)) * (*itStats).second.lastAveragedThroughput) + ((1.0 / m_timeWindow) * (double)((*itStats).second.lastTtiBytesTrasmitted / 0.001));
1636  NS_LOG_INFO (this << " UE total bytes " << (*itStats).second.totalBytesTransmitted);
1637  NS_LOG_INFO (this << " UE average throughput " << (*itStats).second.lastAveragedThroughput);
1638  (*itStats).second.lastTtiBytesTrasmitted = 0;
1639  }
1640  m_allocationMaps.insert (std::pair <uint16_t, std::vector <uint16_t> > (params.m_sfnSf, rbgAllocationMap));
1641  m_schedSapUser->SchedUlConfigInd (ret);
1642 
1643  return;
1644 }
1645 
1646 void
1647 TdBetFfMacScheduler::DoSchedUlNoiseInterferenceReq (const struct FfMacSchedSapProvider::SchedUlNoiseInterferenceReqParameters& params)
1648 {
1649  NS_LOG_FUNCTION (this);
1650  return;
1651 }
1652 
1653 void
1654 TdBetFfMacScheduler::DoSchedUlSrInfoReq (const struct FfMacSchedSapProvider::SchedUlSrInfoReqParameters& params)
1655 {
1656  NS_LOG_FUNCTION (this);
1657  return;
1658 }
1659 
1660 void
1661 TdBetFfMacScheduler::DoSchedUlMacCtrlInfoReq (const struct FfMacSchedSapProvider::SchedUlMacCtrlInfoReqParameters& params)
1662 {
1663  NS_LOG_FUNCTION (this);
1664 
1665  std::map <uint16_t,uint32_t>::iterator it;
1666 
1667  for (unsigned int i = 0; i < params.m_macCeList.size (); i++)
1668  {
1669  if ( params.m_macCeList.at (i).m_macCeType == MacCeListElement_s::BSR )
1670  {
1671  // buffer status report
1672  // note that this scheduler does not differentiate the
1673  // allocation according to which LCGs have more/less bytes
1674  // to send.
1675  // Hence the BSR of different LCGs are just summed up to get
1676  // a total queue size that is used for allocation purposes.
1677 
1678  uint32_t buffer = 0;
1679  for (uint8_t lcg = 0; lcg < 4; ++lcg)
1680  {
1681  uint8_t bsrId = params.m_macCeList.at (i).m_macCeValue.m_bufferStatus.at (lcg);
1682  buffer += BufferSizeLevelBsr::BsrId2BufferSize (bsrId);
1683  }
1684 
1685  uint16_t rnti = params.m_macCeList.at (i).m_rnti;
1686  NS_LOG_LOGIC (this << "RNTI=" << rnti << " buffer=" << buffer);
1687  it = m_ceBsrRxed.find (rnti);
1688  if (it == m_ceBsrRxed.end ())
1689  {
1690  // create the new entry
1691  m_ceBsrRxed.insert ( std::pair<uint16_t, uint32_t > (rnti, buffer));
1692  }
1693  else
1694  {
1695  // update the buffer size value
1696  (*it).second = buffer;
1697  }
1698  }
1699  }
1700 
1701  return;
1702 }
1703 
1704 void
1705 TdBetFfMacScheduler::DoSchedUlCqiInfoReq (const struct FfMacSchedSapProvider::SchedUlCqiInfoReqParameters& params)
1706 {
1707  NS_LOG_FUNCTION (this);
1708 // retrieve the allocation for this subframe
1709  switch (m_ulCqiFilter)
1710  {
1711  case FfMacScheduler::SRS_UL_CQI:
1712  {
1713  // filter all the CQIs that are not SRS based
1714  if (params.m_ulCqi.m_type != UlCqi_s::SRS)
1715  {
1716  return;
1717  }
1718  }
1719  break;
1720  case FfMacScheduler::PUSCH_UL_CQI:
1721  {
1722  // filter all the CQIs that are not SRS based
1723  if (params.m_ulCqi.m_type != UlCqi_s::PUSCH)
1724  {
1725  return;
1726  }
1727  }
1728  case FfMacScheduler::ALL_UL_CQI:
1729  break;
1730 
1731  default:
1732  NS_FATAL_ERROR ("Unknown UL CQI type");
1733  }
1734 
1735  switch (params.m_ulCqi.m_type)
1736  {
1737  case UlCqi_s::PUSCH:
1738  {
1739  std::map <uint16_t, std::vector <uint16_t> >::iterator itMap;
1740  std::map <uint16_t, std::vector <double> >::iterator itCqi;
1741  NS_LOG_DEBUG (this << " Collect PUSCH CQIs of Frame no. " << (params.m_sfnSf >> 4) << " subframe no. " << (0xF & params.m_sfnSf));
1742  itMap = m_allocationMaps.find (params.m_sfnSf);
1743  if (itMap == m_allocationMaps.end ())
1744  {
1745  return;
1746  }
1747  for (uint32_t i = 0; i < (*itMap).second.size (); i++)
1748  {
1749  // convert from fixed point notation Sxxxxxxxxxxx.xxx to double
1750  double sinr = LteFfConverter::fpS11dot3toDouble (params.m_ulCqi.m_sinr.at (i));
1751  itCqi = m_ueCqi.find ((*itMap).second.at (i));
1752  if (itCqi == m_ueCqi.end ())
1753  {
1754  // create a new entry
1755  std::vector <double> newCqi;
1756  for (uint32_t j = 0; j < m_cschedCellConfig.m_ulBandwidth; j++)
1757  {
1758  if (i == j)
1759  {
1760  newCqi.push_back (sinr);
1761  }
1762  else
1763  {
1764  // initialize with NO_SINR value.
1765  newCqi.push_back (NO_SINR);
1766  }
1767 
1768  }
1769  m_ueCqi.insert (std::pair <uint16_t, std::vector <double> > ((*itMap).second.at (i), newCqi));
1770  // generate correspondent timer
1771  m_ueCqiTimers.insert (std::pair <uint16_t, uint32_t > ((*itMap).second.at (i), m_cqiTimersThreshold));
1772  }
1773  else
1774  {
1775  // update the value
1776  (*itCqi).second.at (i) = sinr;
1777  NS_LOG_DEBUG (this << " RNTI " << (*itMap).second.at (i) << " RB " << i << " SINR " << sinr);
1778  // update correspondent timer
1779  std::map <uint16_t, uint32_t>::iterator itTimers;
1780  itTimers = m_ueCqiTimers.find ((*itMap).second.at (i));
1781  (*itTimers).second = m_cqiTimersThreshold;
1782 
1783  }
1784 
1785  }
1786  // remove obsolete info on allocation
1787  m_allocationMaps.erase (itMap);
1788  }
1789  break;
1790  case UlCqi_s::SRS:
1791  {
1792  // get the RNTI from vendor specific parameters
1793  uint16_t rnti = 0;
1794  NS_ASSERT (params.m_vendorSpecificList.size () > 0);
1795  for (uint16_t i = 0; i < params.m_vendorSpecificList.size (); i++)
1796  {
1797  if (params.m_vendorSpecificList.at (i).m_type == SRS_CQI_RNTI_VSP)
1798  {
1799  Ptr<SrsCqiRntiVsp> vsp = DynamicCast<SrsCqiRntiVsp> (params.m_vendorSpecificList.at (i).m_value);
1800  rnti = vsp->GetRnti ();
1801  }
1802  }
1803  std::map <uint16_t, std::vector <double> >::iterator itCqi;
1804  itCqi = m_ueCqi.find (rnti);
1805  if (itCqi == m_ueCqi.end ())
1806  {
1807  // create a new entry
1808  std::vector <double> newCqi;
1809  for (uint32_t j = 0; j < m_cschedCellConfig.m_ulBandwidth; j++)
1810  {
1811  double sinr = LteFfConverter::fpS11dot3toDouble (params.m_ulCqi.m_sinr.at (j));
1812  newCqi.push_back (sinr);
1813  NS_LOG_INFO (this << " RNTI " << rnti << " new SRS-CQI for RB " << j << " value " << sinr);
1814 
1815  }
1816  m_ueCqi.insert (std::pair <uint16_t, std::vector <double> > (rnti, newCqi));
1817  // generate correspondent timer
1818  m_ueCqiTimers.insert (std::pair <uint16_t, uint32_t > (rnti, m_cqiTimersThreshold));
1819  }
1820  else
1821  {
1822  // update the values
1823  for (uint32_t j = 0; j < m_cschedCellConfig.m_ulBandwidth; j++)
1824  {
1825  double sinr = LteFfConverter::fpS11dot3toDouble (params.m_ulCqi.m_sinr.at (j));
1826  (*itCqi).second.at (j) = sinr;
1827  NS_LOG_INFO (this << " RNTI " << rnti << " update SRS-CQI for RB " << j << " value " << sinr);
1828  }
1829  // update correspondent timer
1830  std::map <uint16_t, uint32_t>::iterator itTimers;
1831  itTimers = m_ueCqiTimers.find (rnti);
1832  (*itTimers).second = m_cqiTimersThreshold;
1833 
1834  }
1835 
1836 
1837  }
1838  break;
1839  case UlCqi_s::PUCCH_1:
1840  case UlCqi_s::PUCCH_2:
1841  case UlCqi_s::PRACH:
1842  {
1843  NS_FATAL_ERROR ("TdBetFfMacScheduler supports only PUSCH and SRS UL-CQIs");
1844  }
1845  break;
1846  default:
1847  NS_FATAL_ERROR ("Unknown type of UL-CQI");
1848  }
1849  return;
1850 }
1851 
1852 void
1853 TdBetFfMacScheduler::RefreshDlCqiMaps (void)
1854 {
1855  // refresh DL CQI P01 Map
1856  std::map <uint16_t,uint32_t>::iterator itP10 = m_p10CqiTimers.begin ();
1857  while (itP10 != m_p10CqiTimers.end ())
1858  {
1859  NS_LOG_INFO (this << " P10-CQI for user " << (*itP10).first << " is " << (uint32_t)(*itP10).second << " thr " << (uint32_t)m_cqiTimersThreshold);
1860  if ((*itP10).second == 0)
1861  {
1862  // delete correspondent entries
1863  std::map <uint16_t,uint8_t>::iterator itMap = m_p10CqiRxed.find ((*itP10).first);
1864  NS_ASSERT_MSG (itMap != m_p10CqiRxed.end (), " Does not find CQI report for user " << (*itP10).first);
1865  NS_LOG_INFO (this << " P10-CQI expired for user " << (*itP10).first);
1866  m_p10CqiRxed.erase (itMap);
1867  std::map <uint16_t,uint32_t>::iterator temp = itP10;
1868  itP10++;
1869  m_p10CqiTimers.erase (temp);
1870  }
1871  else
1872  {
1873  (*itP10).second--;
1874  itP10++;
1875  }
1876  }
1877 
1878  // refresh DL CQI A30 Map
1879  std::map <uint16_t,uint32_t>::iterator itA30 = m_a30CqiTimers.begin ();
1880  while (itA30 != m_a30CqiTimers.end ())
1881  {
1882  NS_LOG_INFO (this << " A30-CQI for user " << (*itA30).first << " is " << (uint32_t)(*itA30).second << " thr " << (uint32_t)m_cqiTimersThreshold);
1883  if ((*itA30).second == 0)
1884  {
1885  // delete correspondent entries
1886  std::map <uint16_t,SbMeasResult_s>::iterator itMap = m_a30CqiRxed.find ((*itA30).first);
1887  NS_ASSERT_MSG (itMap != m_a30CqiRxed.end (), " Does not find CQI report for user " << (*itA30).first);
1888  NS_LOG_INFO (this << " A30-CQI expired for user " << (*itA30).first);
1889  m_a30CqiRxed.erase (itMap);
1890  std::map <uint16_t,uint32_t>::iterator temp = itA30;
1891  itA30++;
1892  m_a30CqiTimers.erase (temp);
1893  }
1894  else
1895  {
1896  (*itA30).second--;
1897  itA30++;
1898  }
1899  }
1900 
1901  return;
1902 }
1903 
1904 
1905 void
1906 TdBetFfMacScheduler::RefreshUlCqiMaps (void)
1907 {
1908  // refresh UL CQI Map
1909  std::map <uint16_t,uint32_t>::iterator itUl = m_ueCqiTimers.begin ();
1910  while (itUl != m_ueCqiTimers.end ())
1911  {
1912  NS_LOG_INFO (this << " UL-CQI for user " << (*itUl).first << " is " << (uint32_t)(*itUl).second << " thr " << (uint32_t)m_cqiTimersThreshold);
1913  if ((*itUl).second == 0)
1914  {
1915  // delete correspondent entries
1916  std::map <uint16_t, std::vector <double> >::iterator itMap = m_ueCqi.find ((*itUl).first);
1917  NS_ASSERT_MSG (itMap != m_ueCqi.end (), " Does not find CQI report for user " << (*itUl).first);
1918  NS_LOG_INFO (this << " UL-CQI exired for user " << (*itUl).first);
1919  (*itMap).second.clear ();
1920  m_ueCqi.erase (itMap);
1921  std::map <uint16_t,uint32_t>::iterator temp = itUl;
1922  itUl++;
1923  m_ueCqiTimers.erase (temp);
1924  }
1925  else
1926  {
1927  (*itUl).second--;
1928  itUl++;
1929  }
1930  }
1931 
1932  return;
1933 }
1934 
1935 void
1936 TdBetFfMacScheduler::UpdateDlRlcBufferInfo (uint16_t rnti, uint8_t lcid, uint16_t size)
1937 {
1938  std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it;
1939  LteFlowId_t flow (rnti, lcid);
1940  it = m_rlcBufferReq.find (flow);
1941  if (it != m_rlcBufferReq.end ())
1942  {
1943  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);
1944  // Update queues: RLC tx order Status, ReTx, Tx
1945  // Update status queue
1946  if (((*it).second.m_rlcStatusPduSize > 0) && (size >= (*it).second.m_rlcStatusPduSize))
1947  {
1948  (*it).second.m_rlcStatusPduSize = 0;
1949  }
1950  else if (((*it).second.m_rlcRetransmissionQueueSize > 0) && (size >= (*it).second.m_rlcRetransmissionQueueSize))
1951  {
1952  (*it).second.m_rlcRetransmissionQueueSize = 0;
1953  }
1954  else if ((*it).second.m_rlcTransmissionQueueSize > 0)
1955  {
1956  // update transmission queue
1957  if ((*it).second.m_rlcTransmissionQueueSize <= size)
1958  {
1959  (*it).second.m_rlcTransmissionQueueSize = 0;
1960  }
1961  else
1962  {
1963  size -= 2; // remove minimun RLC overhead due to header
1964  (*it).second.m_rlcTransmissionQueueSize -= size;
1965  }
1966  }
1967  }
1968  else
1969  {
1970  NS_LOG_ERROR (this << " Does not find DL RLC Buffer Report of UE " << rnti);
1971  }
1972 }
1973 
1974 void
1975 TdBetFfMacScheduler::UpdateUlRlcBufferInfo (uint16_t rnti, uint16_t size)
1976 {
1977 
1978  size = size - 2; // remove the minimum RLC overhead
1979  std::map <uint16_t,uint32_t>::iterator it = m_ceBsrRxed.find (rnti);
1980  if (it != m_ceBsrRxed.end ())
1981  {
1982  NS_LOG_INFO (this << " UE " << rnti << " size " << size << " BSR " << (*it).second);
1983  if ((*it).second >= size)
1984  {
1985  (*it).second -= size;
1986  }
1987  else
1988  {
1989  (*it).second = 0;
1990  }
1991  }
1992  else
1993  {
1994  NS_LOG_ERROR (this << " Does not find BSR report info of UE " << rnti);
1995  }
1996 
1997 }
1998 
1999 void
2000 TdBetFfMacScheduler::TransmissionModeConfigurationUpdate (uint16_t rnti, uint8_t txMode)
2001 {
2002  NS_LOG_FUNCTION (this << " RNTI " << rnti << " txMode " << (uint16_t)txMode);
2003  FfMacCschedSapUser::CschedUeConfigUpdateIndParameters params;
2004  params.m_rnti = rnti;
2005  params.m_transmissionMode = txMode;
2006  m_cschedSapUser->CschedUeConfigUpdateInd (params);
2007 }
2008 
2009 
2010 }
virtual FfMacSchedSapProvider * GetFfMacSchedSapProvider()
uint8_t HarqProcessAvailability(uint16_t rnti)
Return the availability of free process for the RNTI specified.
#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
virtual FfMacCschedSapProvider * GetFfMacCschedSapProvider()
#define NS_LOG_COMPONENT_DEFINE(name)
Definition: log.h:122
Provides the CSCHED SAP.
#define NS_LOG_INFO(msg)
Definition: log.h:264
See section 4.3.10 buildRARListElement.
#define NS_FATAL_ERROR(msg)
fatal error handling
Definition: fatal-error.h:72
Hold an unsigned integer type.
Definition: uinteger.h:46
void RefreshHarqProcesses()
Refresh HARQ processes according to the timers.
Provides the SCHED SAP.
#define NS_LOG_LOGIC(msg)
Definition: log.h:334
Implements the SCHED SAP and CSCHED SAP for a Time Domain Blind Equal Throughput scheduler.
virtual void SetFfMacCschedSapUser(FfMacCschedSapUser *s)
static Time Now(void)
Definition: simulator.cc:179
#define NS_ASSERT_MSG(condition, message)
Definition: assert.h:86
#define NS_LOG_DEBUG(msg)
Definition: log.h:255
virtual void CschedCellConfigReq(const struct CschedCellConfigReqParameters &params)
CSCHED_CELL_CONFIG_REQ.
#define NS_LOG_ERROR(msg)
Definition: log.h:237
virtual void SetFfMacSchedSapUser(FfMacSchedSapUser *s)
uint8_t UpdateHarqProcessId(uint16_t rnti)
Update and return a new process Id for the RNTI specified.
a unique identifier for an interface.
Definition: type-id.h:44
TypeId SetParent(TypeId tid)
Definition: type-id.cc:471