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