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