A Discrete-Event Network Simulator
API
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
pf-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 
25 #include <ns3/simulator.h>
26 #include <ns3/lte-amc.h>
27 #include <ns3/pf-ff-mac-scheduler.h>
28 #include <ns3/lte-vendor-specific-parameters.h>
29 
30 NS_LOG_COMPONENT_DEFINE ("PfFfMacScheduler");
31 
32 namespace ns3 {
33 
35  10, // RGB size 1
36  26, // RGB size 2
37  63, // RGB size 3
38  110 // RGB size 4
39 }; // see table 7.1.6.1-1 of 36.213
40 
41 
42 NS_OBJECT_ENSURE_REGISTERED (PfFfMacScheduler);
43 
44 
45 
47 {
48 public:
50 
51  // inherited from FfMacCschedSapProvider
52  virtual void CschedCellConfigReq (const struct CschedCellConfigReqParameters& params);
53  virtual void CschedUeConfigReq (const struct CschedUeConfigReqParameters& params);
54  virtual void CschedLcConfigReq (const struct CschedLcConfigReqParameters& params);
55  virtual void CschedLcReleaseReq (const struct CschedLcReleaseReqParameters& params);
56  virtual void CschedUeReleaseReq (const struct CschedUeReleaseReqParameters& params);
57 
58 private:
61 };
62 
64 {
65 }
66 
68 {
69 }
70 
71 
72 void
74 {
76 }
77 
78 void
80 {
82 }
83 
84 
85 void
87 {
89 }
90 
91 void
93 {
95 }
96 
97 void
99 {
101 }
102 
103 
104 
105 
107 {
108 public:
110 
111  // inherited from FfMacSchedSapProvider
112  virtual void SchedDlRlcBufferReq (const struct SchedDlRlcBufferReqParameters& params);
113  virtual void SchedDlPagingBufferReq (const struct SchedDlPagingBufferReqParameters& params);
114  virtual void SchedDlMacBufferReq (const struct SchedDlMacBufferReqParameters& params);
115  virtual void SchedDlTriggerReq (const struct SchedDlTriggerReqParameters& params);
116  virtual void SchedDlRachInfoReq (const struct SchedDlRachInfoReqParameters& params);
117  virtual void SchedDlCqiInfoReq (const struct SchedDlCqiInfoReqParameters& params);
118  virtual void SchedUlTriggerReq (const struct SchedUlTriggerReqParameters& params);
119  virtual void SchedUlNoiseInterferenceReq (const struct SchedUlNoiseInterferenceReqParameters& params);
120  virtual void SchedUlSrInfoReq (const struct SchedUlSrInfoReqParameters& params);
121  virtual void SchedUlMacCtrlInfoReq (const struct SchedUlMacCtrlInfoReqParameters& params);
122  virtual void SchedUlCqiInfoReq (const struct SchedUlCqiInfoReqParameters& params);
123 
124 
125 private:
128 };
129 
130 
131 
133 {
134 }
135 
136 
138  : m_scheduler (scheduler)
139 {
140 }
141 
142 void
144 {
146 }
147 
148 void
150 {
152 }
153 
154 void
156 {
158 }
159 
160 void
162 {
164 }
165 
166 void
168 {
170 }
171 
172 void
174 {
176 }
177 
178 void
180 {
182 }
183 
184 void
186 {
188 }
189 
190 void
192 {
194 }
195 
196 void
198 {
200 }
201 
202 void
204 {
206 }
207 
208 
209 
210 
211 
213  : m_cschedSapUser (0),
214  m_schedSapUser (0),
215  m_timeWindow (99.0),
216  m_nextRntiUl (0)
217 {
218  m_amc = CreateObject <LteAmc> ();
221 }
222 
224 {
225  NS_LOG_FUNCTION (this);
226 }
227 
228 void
230 {
231  NS_LOG_FUNCTION (this);
232  delete m_cschedSapProvider;
233  delete m_schedSapProvider;
234 }
235 
236 TypeId
238 {
239  static TypeId tid = TypeId ("ns3::PfFfMacScheduler")
241  .AddConstructor<PfFfMacScheduler> ()
242  .AddAttribute ("CqiTimerThreshold",
243  "The number of TTIs a CQI is valid (default 1000 - 1 sec.)",
244  UintegerValue (1000),
245  MakeUintegerAccessor (&PfFfMacScheduler::m_cqiTimersThreshold),
246  MakeUintegerChecker<uint32_t> ())
247  ;
248  return tid;
249 }
250 
251 
252 
253 void
255 {
256  m_cschedSapUser = s;
257 }
258 
259 void
261 {
262  m_schedSapUser = s;
263 }
264 
267 {
268  return m_cschedSapProvider;
269 }
270 
273 {
274  return m_schedSapProvider;
275 }
276 
277 void
279 {
280  NS_LOG_FUNCTION (this);
281  // Read the subset of parameters used
282  m_cschedCellConfig = params;
284  cnf.m_result = SUCCESS;
286  return;
287 }
288 
289 void
291 {
292  NS_LOG_FUNCTION (this << " RNTI " << params.m_rnti << " txMode " << (uint16_t)params.m_transmissionMode);
293  std::map <uint16_t,uint8_t>::iterator it = m_uesTxMode.find (params.m_rnti);
294  if (it==m_uesTxMode.end ())
295  {
296  m_uesTxMode.insert (std::pair <uint16_t, double> (params.m_rnti, params.m_transmissionMode));
297  }
298  else
299  {
300  (*it).second = params.m_transmissionMode;
301  }
302  return;
303 }
304 
305 void
307 {
308  NS_LOG_FUNCTION (this << " New LC, rnti: " << params.m_rnti);
309 
310  std::map <uint16_t, pfsFlowPerf_t>::iterator it;
311  for (uint16_t i = 0; i < params.m_logicalChannelConfigList.size (); i++)
312  {
313  it = m_flowStatsDl.find (params.m_rnti);
314 
315  if (it == m_flowStatsDl.end ())
316  {
317  pfsFlowPerf_t flowStatsDl;
318  flowStatsDl.flowStart = Simulator::Now ();
319  flowStatsDl.totalBytesTransmitted = 0;
320  flowStatsDl.lastTtiBytesTrasmitted = 0;
321  flowStatsDl.lastAveragedThroughput = 1;
322  m_flowStatsDl.insert (std::pair<uint16_t, pfsFlowPerf_t> (params.m_rnti, flowStatsDl));
323  pfsFlowPerf_t flowStatsUl;
324  flowStatsUl.flowStart = Simulator::Now ();
325  flowStatsUl.totalBytesTransmitted = 0;
326  flowStatsUl.lastTtiBytesTrasmitted = 0;
327  flowStatsUl.lastAveragedThroughput = 1;
328  m_flowStatsUl.insert (std::pair<uint16_t, pfsFlowPerf_t> (params.m_rnti, flowStatsUl));
329  }
330  else
331  {
332  NS_LOG_ERROR ("RNTI already exists");
333  }
334  }
335 
336  return;
337 }
338 
339 void
341 {
342  NS_LOG_FUNCTION (this);
343  NS_FATAL_ERROR ("method not implemented");
344  return;
345 }
346 
347 void
349 {
350  NS_LOG_FUNCTION (this);
351  NS_FATAL_ERROR ("method not implemented");
352  return;
353 }
354 
355 
356 void
358 {
359  NS_LOG_FUNCTION (this << params.m_rnti << (uint32_t) params.m_logicalChannelIdentity);
360  // API generated by RLC for updating RLC parameters on a LC (tx and retx queues)
361 
362  std::map <LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it;
363 
364  LteFlowId_t flow (params.m_rnti, params.m_logicalChannelIdentity);
365 
366  it = m_rlcBufferReq.find (flow);
367 
368  if (it == m_rlcBufferReq.end ())
369  {
370  m_rlcBufferReq.insert (std::pair <LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters> (flow, params));
371  }
372  else
373  {
374  (*it).second = params;
375  }
376 
377  return;
378 }
379 
380 void
382 {
383  NS_LOG_FUNCTION (this);
384  NS_FATAL_ERROR ("method not implemented");
385  return;
386 }
387 
388 void
390 {
391  NS_LOG_FUNCTION (this);
392  NS_FATAL_ERROR ("method not implemented");
393  return;
394 }
395 
396 int
398 {
399  for (int i = 0; i < 4; i++)
400  {
401  if (dlbandwidth < PfType0AllocationRbg[i])
402  {
403  return (i + 1);
404  }
405  }
406 
407  return (-1);
408 }
409 
410 
411 int
413 {
414  std::map <LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it;
415  int lcActive = 0;
416  for (it = m_rlcBufferReq.begin (); it != m_rlcBufferReq.end (); it++)
417  {
418  if (((*it).first.m_rnti == rnti) && (((*it).second.m_rlcTransmissionQueueSize > 0)
419  || ((*it).second.m_rlcRetransmissionQueueSize > 0)
420  || ((*it).second.m_rlcStatusPduSize > 0) ))
421  {
422  lcActive++;
423  }
424  if ((*it).first.m_rnti > rnti)
425  {
426  break;
427  }
428  }
429  return (lcActive);
430 
431 }
432 
433 
434 void
436 {
437  NS_LOG_FUNCTION (this << " Frame no. " << (params.m_sfnSf >> 4) << " subframe no. " << (0xF & params.m_sfnSf));
438  // API generated by RLC for triggering the scheduling of a DL subframe
439 
440 
441  // evaluate the relative channel quality indicator for each UE per each RBG
442  // (since we are using allocation type 0 the small unit of allocation is RBG)
443  // Resource allocation type 0 (see sec 7.1.6.1 of 36.213)
444 
445  RefreshDlCqiMaps ();
446 
448  int rbgNum = m_cschedCellConfig.m_dlBandwidth / rbgSize;
449  std::map <uint16_t, std::vector <uint16_t> > allocationMap;
450  for (int i = 0; i < rbgNum; i++)
451  {
452 // NS_LOG_DEBUG (this << " ALLOCATION for RBG " << i << " of " << rbgNum);
453  std::map <uint16_t, pfsFlowPerf_t>::iterator it;
454  std::map <uint16_t, pfsFlowPerf_t>::iterator itMax = m_flowStatsDl.end ();
455  double rcqiMax = 0.0;
456  for (it = m_flowStatsDl.begin (); it != m_flowStatsDl.end (); it++)
457  {
458  std::map <uint16_t,SbMeasResult_s>::iterator itCqi;
459  itCqi = m_a30CqiRxed.find ((*it).first);
460  std::map <uint16_t,uint8_t>::iterator itTxMode;
461  itTxMode = m_uesTxMode.find ((*it).first);
462  if (itTxMode == m_uesTxMode.end())
463  {
464  NS_FATAL_ERROR ("No Transmission Mode info on user " << (*it).first);
465  }
466  int nLayer = TransmissionModesLayers::TxMode2LayerNum ((*itTxMode).second);
467  std::vector <uint8_t> sbCqi;
468  if (itCqi == m_a30CqiRxed.end ())
469  {
470 // NS_LOG_DEBUG (this << " No DL-CQI for this UE " << (*it).first);
471  for (uint8_t k = 0; k < nLayer; k++)
472  {
473  sbCqi.push_back (1); // start with lowest value
474  }
475  }
476  else
477  {
478  sbCqi = (*itCqi).second.m_higherLayerSelected.at (i).m_sbCqi;
479 // NS_LOG_INFO (this << " CQI " << (uint32_t)cqi);
480  }
481  uint8_t cqi1 = sbCqi.at(0);
482  uint8_t cqi2 = 1;
483  if (sbCqi.size () > 1)
484  {
485  cqi2 = sbCqi.at(1);
486  }
487 
488  if ((cqi1 > 0)||(cqi2 > 0)) // CQI == 0 means "out of range" (see table 7.2.3-1 of 36.213)
489  {
490 // NS_LOG_DEBUG (this << " LC active " << LcActivePerFlow ((*it).first));
491  if (LcActivePerFlow ((*it).first) > 0)
492  {
493  // this UE has data to transmit
494  double achievableRate = 0.0;
495  for (uint8_t k = 0; k < nLayer; k++)
496  {
497  uint8_t mcs = 0;
498  if (sbCqi.size () > k)
499  {
500  mcs = m_amc->GetMcsFromCqi (sbCqi.at (k));
501  }
502  else
503  {
504  // no info on this subband -> worst MCS
505  mcs = 0;
506  }
507  achievableRate += ((m_amc->GetTbSizeFromMcs (mcs, rbgSize) / 8) / 0.001); // = TB size / TTI
508  }
509 
510  double rcqi = achievableRate / (*it).second.lastAveragedThroughput;
511 // NS_LOG_DEBUG (this << " RNTI " << (*it).first << " MCS " << (uint32_t)mcs << " achievableRate " << achievableRate << " avgThr " << (*it).second.lastAveragedThroughput << " RCQI " << rcqi);
512 
513  if (rcqi > rcqiMax)
514  {
515  rcqiMax = rcqi;
516  itMax = it;
517  }
518  }
519  } // end if cqi
520  } // end for m_rlcBufferReq
521 
522  if (itMax == m_flowStatsDl.end ())
523  {
524  // no UE available for this RB
525  NS_LOG_DEBUG (this << " no UE found");
526  }
527  else
528  {
529  std::map <uint16_t, std::vector <uint16_t> >::iterator itMap;
530  itMap = allocationMap.find ((*itMax).first);
531  if (itMap == allocationMap.end ())
532  {
533  // insert new element
534  std::vector <uint16_t> tempMap;
535  tempMap.push_back (i);
536  allocationMap.insert (std::pair <uint16_t, std::vector <uint16_t> > ((*itMax).first, tempMap));
537  }
538  else
539  {
540  (*itMap).second.push_back (i);
541  }
542 // NS_LOG_DEBUG (this << " UE assigned " << (*itMax).first);
543  }
544  } // end for RBGs
545 
546  // reset TTI stats of users
547  std::map <uint16_t, pfsFlowPerf_t>::iterator itStats;
548  for (itStats = m_flowStatsDl.begin (); itStats != m_flowStatsDl.end (); itStats++)
549  {
550  (*itStats).second.lastTtiBytesTrasmitted = 0;
551  }
552 
553  // generate the transmission opportunities by grouping the RBGs of the same RNTI and
554  // creating the correspondent DCIs
556  std::map <uint16_t, std::vector <uint16_t> >::iterator itMap = allocationMap.begin ();
557  while (itMap != allocationMap.end ())
558  {
559  // create new BuildDataListElement_s for this LC
561  newEl.m_rnti = (*itMap).first;
562  // create the DlDciListElement_s
563  DlDciListElement_s newDci;
564  std::vector <struct RlcPduListElement_s> newRlcPduLe;
565  newDci.m_rnti = (*itMap).first;
566 
567  uint16_t lcActives = LcActivePerFlow ((*itMap).first);
568 // NS_LOG_DEBUG (this << "Allocate user " << newEl.m_rnti << " rbg " << lcActives);
569  uint16_t RgbPerRnti = (*itMap).second.size ();
570  std::map <uint16_t,SbMeasResult_s>::iterator itCqi;
571  itCqi = m_a30CqiRxed.find ((*itMap).first);
572  std::map <uint16_t,uint8_t>::iterator itTxMode;
573  itTxMode = m_uesTxMode.find ((*itMap).first);
574  if (itTxMode == m_uesTxMode.end())
575  {
576  NS_FATAL_ERROR ("No Transmission Mode info on user " << (*itMap).first);
577  }
578  int nLayer = TransmissionModesLayers::TxMode2LayerNum ((*itTxMode).second);
579  std::vector <uint8_t> worstCqi (2, 15);
580  if (itCqi != m_a30CqiRxed.end ())
581  {
582  for (uint16_t k = 0; k < (*itMap).second.size (); k++)
583  {
584  if ((*itCqi).second.m_higherLayerSelected.size () > (*itMap).second.at (k))
585  {
586 // NS_LOG_DEBUG (this << " RBG " << (*itMap).second.at (k) << " CQI " << (uint16_t)((*itCqi).second.m_higherLayerSelected.at ((*itMap).second.at (k)).m_sbCqi.at (0)) );
587  for (uint8_t j = 0; j < nLayer; j++)
588  {
589  if ((*itCqi).second.m_higherLayerSelected.at ((*itMap).second.at (k)).m_sbCqi.size ()> j)
590  {
591  if (((*itCqi).second.m_higherLayerSelected.at ((*itMap).second.at (k)).m_sbCqi.at (j)) < worstCqi.at (j))
592  {
593  worstCqi.at (j) = ((*itCqi).second.m_higherLayerSelected.at ((*itMap).second.at (k)).m_sbCqi.at (j));
594  }
595  }
596  else
597  {
598  // no CQI for this layer of this suband -> worst one
599  worstCqi.at (j) = 1;
600  }
601  }
602  }
603  else
604  {
605  for (uint8_t j = 0; j < nLayer; j++)
606  {
607  worstCqi.at (j) = 1; // try with lowest MCS in RBG with no info on channel
608  }
609  }
610  }
611  }
612  else
613  {
614  for (uint8_t j = 0; j < nLayer; j++)
615  {
616  worstCqi.at (j) = 1; // try with lowest MCS in RBG with no info on channel
617  }
618  }
619 // NS_LOG_DEBUG (this << " CQI " << (uint16_t)worstCqi);
620  uint32_t bytesTxed = 0;
621  for (uint8_t j = 0; j < nLayer; j++)
622  {
623  newDci.m_mcs.push_back (m_amc->GetMcsFromCqi (worstCqi.at (j)));
624  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)
625  newDci.m_tbsSize.push_back (tbSize);
626  NS_LOG_DEBUG (this << " MCS " << m_amc->GetMcsFromCqi (worstCqi.at (j)));
627  bytesTxed += tbSize;
628  }
629 
630  newDci.m_resAlloc = 0; // only allocation type 0 at this stage
631  newDci.m_rbBitmap = 0; // TBD (32 bit bitmap see 7.1.6 of 36.213)
632  uint32_t rbgMask = 0;
633  for (uint16_t k = 0; k < (*itMap).second.size (); k++)
634  {
635  rbgMask = rbgMask + (0x1 << (*itMap).second.at (k));
636 // NS_LOG_DEBUG (this << " Allocated PRB " << (*itMap).second.at (k));
637  }
638  newDci.m_rbBitmap = rbgMask; // (32 bit bitmap see 7.1.6 of 36.213)
639 
640  // create the rlc PDUs -> equally divide resources among actives LCs
641  std::map <LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator itBufReq;
642  for (itBufReq = m_rlcBufferReq.begin (); itBufReq != m_rlcBufferReq.end (); itBufReq++)
643  {
644  if (((*itBufReq).first.m_rnti == (*itMap).first) &&
645  (((*itBufReq).second.m_rlcTransmissionQueueSize > 0)
646  || ((*itBufReq).second.m_rlcRetransmissionQueueSize > 0)
647  || ((*itBufReq).second.m_rlcStatusPduSize > 0) ))
648  {
649  for (uint8_t j = 0; j < nLayer; j++)
650  {
651  RlcPduListElement_s newRlcEl;
652  newRlcEl.m_logicalChannelIdentity = (*itBufReq).first.m_lcId;
653  newRlcEl.m_size = newDci.m_tbsSize.at (j) / lcActives;
654  NS_LOG_DEBUG (this << " LCID " << (uint32_t) newRlcEl.m_logicalChannelIdentity << " size " << newRlcEl.m_size << " layer " << (uint16_t)j);
655  newRlcPduLe.push_back (newRlcEl);
656  UpdateDlRlcBufferInfo (newDci.m_rnti, newRlcEl.m_logicalChannelIdentity, newRlcEl.m_size);
657  }
658  }
659  if ((*itBufReq).first.m_rnti > (*itMap).first)
660  {
661  break;
662  }
663  }
664  newDci.m_ndi.push_back (1); // TBD (new data indicator)
665  newDci.m_rv.push_back (0); // TBD (redundancy version)
666 
667  newEl.m_dci = newDci;
668  // ...more parameters -> ingored in this version
669 
670  newEl.m_rlcPduList.push_back (newRlcPduLe);
671  ret.m_buildDataList.push_back (newEl);
672 
673  // update UE stats
674  std::map <uint16_t, pfsFlowPerf_t>::iterator it;
675  it = m_flowStatsDl.find ((*itMap).first);
676  if (it != m_flowStatsDl.end ())
677  {
678  (*it).second.lastTtiBytesTrasmitted = bytesTxed;
679 // NS_LOG_DEBUG (this << " UE bytes txed " << (*it).second.lastTtiBytesTrasmitted);
680 
681 
682  }
683  else
684  {
685  NS_LOG_DEBUG (this << " No Stats for this allocated UE");
686  }
687 
688  itMap++;
689  } // end while allocation
690  ret.m_nrOfPdcchOfdmSymbols = 1; // TODO: check correct value according the DCIs txed
691 
692 
693  // update UEs stats
694  for (itStats = m_flowStatsDl.begin (); itStats != m_flowStatsDl.end (); itStats++)
695  {
696  (*itStats).second.totalBytesTransmitted += (*itStats).second.lastTtiBytesTrasmitted;
697  // update average throughput (see eq. 12.3 of Sec 12.3.1.2 of LTE – The UMTS Long Term Evolution, Ed Wiley)
698  (*itStats).second.lastAveragedThroughput = ((1.0 - (1.0 / m_timeWindow)) * (*itStats).second.lastAveragedThroughput) + ((1.0 / m_timeWindow) * (double)((*itStats).second.lastTtiBytesTrasmitted / 0.001));
699 // NS_LOG_DEBUG (this << " UE tot bytes " << (*itStats).second.totalBytesTransmitted);
700 // NS_LOG_DEBUG (this << " UE avg thr " << (*itStats).second.lastAveragedThroughput);
701  (*itStats).second.lastTtiBytesTrasmitted = 0;
702  }
703 
705 
706 
707  return;
708 }
709 
710 void
712 {
713  NS_LOG_FUNCTION (this);
714  NS_FATAL_ERROR ("method not implemented");
715  return;
716 }
717 
718 void
720 {
721  NS_LOG_FUNCTION (this);
722 
723  for (unsigned int i = 0; i < params.m_cqiList.size (); i++)
724  {
725  if ( params.m_cqiList.at (i).m_cqiType == CqiListElement_s::P10 )
726  {
727  // wideband CQI reporting
728  std::map <uint16_t,uint8_t>::iterator it;
729  uint16_t rnti = params.m_cqiList.at (i).m_rnti;
730  it = m_p10CqiRxed.find (rnti);
731  if (it == m_p10CqiRxed.end ())
732  {
733  // create the new entry
734  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)
735  // generate correspondent timer
736  m_p10CqiTimers.insert ( std::pair<uint16_t, uint32_t > (rnti, m_cqiTimersThreshold));
737  }
738  else
739  {
740  // update the CQI value and refresh correspondent timer
741  (*it).second = params.m_cqiList.at (i).m_wbCqi.at (0);
742  // update correspondent timer
743  std::map <uint16_t,uint32_t>::iterator itTimers;
744  itTimers = m_p10CqiTimers.find (rnti);
745  (*itTimers).second = m_cqiTimersThreshold;
746  }
747  }
748  else if ( params.m_cqiList.at (i).m_cqiType == CqiListElement_s::A30 )
749  {
750  // subband CQI reporting high layer configured
751  std::map <uint16_t,SbMeasResult_s>::iterator it;
752  uint16_t rnti = params.m_cqiList.at (i).m_rnti;
753  it = m_a30CqiRxed.find (rnti);
754  if (it == m_a30CqiRxed.end ())
755  {
756  // create the new entry
757  m_a30CqiRxed.insert ( std::pair<uint16_t, SbMeasResult_s > (rnti, params.m_cqiList.at (i).m_sbMeasResult) );
758  m_a30CqiTimers.insert ( std::pair<uint16_t, uint32_t > (rnti, m_cqiTimersThreshold));
759  }
760  else
761  {
762  // update the CQI value and refresh correspondent timer
763  (*it).second = params.m_cqiList.at (i).m_sbMeasResult;
764  std::map <uint16_t,uint32_t>::iterator itTimers;
765  itTimers = m_a30CqiTimers.find (rnti);
766  (*itTimers).second = m_cqiTimersThreshold;
767  }
768  }
769  else
770  {
771  NS_LOG_ERROR (this << " CQI type unknown");
772  }
773  }
774 
775  return;
776 }
777 
778 
779 double
780 PfFfMacScheduler::EstimateUlSinr (uint16_t rnti, uint16_t rb)
781 {
782  std::map <uint16_t, std::vector <double> >::iterator itCqi = m_ueCqi.find (rnti);
783  if (itCqi == m_ueCqi.end ())
784  {
785  // no cqi info about this UE
786  return (NO_SINR);
787 
788  }
789  else
790  {
791  // take the average SINR value among the available
792  double sinrSum = 0;
793  int sinrNum = 0;
794  for (uint32_t i = 0; i < m_cschedCellConfig.m_ulBandwidth; i++)
795  {
796  double sinr = (*itCqi).second.at (i);
797  if (sinr != NO_SINR)
798  {
799  sinrSum += sinr;
800  sinrNum++;
801  }
802  }
803  double estimatedSinr = sinrSum / (double)sinrNum;
804  // store the value
805  (*itCqi).second.at (rb) = estimatedSinr;
806  return (estimatedSinr);
807  }
808 }
809 
810 void
812 {
813  NS_LOG_FUNCTION (this << " UL - Frame no. " << (params.m_sfnSf >> 4) << " subframe no. " << (0xF & params.m_sfnSf));
814 
815  RefreshUlCqiMaps ();
816 
817  std::map <uint16_t,uint32_t>::iterator it;
818  int nflows = 0;
819 
820  for (it = m_ceBsrRxed.begin (); it != m_ceBsrRxed.end (); it++)
821  {
822  // remove old entries of this UE-LC
823  if ((*it).second > 0)
824  {
825  nflows++;
826  }
827  }
828 
829  if (nflows == 0)
830  {
831  return ; // no flows to be scheduled
832  }
833 
834 
835  // Divide the resource equally among the active users
836  int rbPerFlow = m_cschedCellConfig.m_ulBandwidth / nflows;
837  if (rbPerFlow == 0)
838  {
839  rbPerFlow = 1; // at least 1 rbg per flow (till available resource)
840  }
841  int rbAllocated = 0;
842 
844  std::vector <uint16_t> rbgAllocationMap;
845  std::map <uint16_t, pfsFlowPerf_t>::iterator itStats;
846  if (m_nextRntiUl != 0)
847  {
848  for (it = m_ceBsrRxed.begin (); it != m_ceBsrRxed.end (); it++)
849  {
850  if ((*it).first == m_nextRntiUl)
851  {
852  break;
853  }
854  }
855  if (it == m_ceBsrRxed.end ())
856  {
857  NS_LOG_ERROR (this << " no user found");
858  }
859  }
860  else
861  {
862  it = m_ceBsrRxed.begin ();
863  m_nextRntiUl = (*it).first;
864  }
865  do
866  {
867  if (rbAllocated + rbPerFlow > m_cschedCellConfig.m_ulBandwidth)
868  {
869  // limit to physical resources last resource assignment
870  rbPerFlow = m_cschedCellConfig.m_ulBandwidth - rbAllocated;
871  }
872 
873  UlDciListElement_s uldci;
874  uldci.m_rnti = (*it).first;
875  uldci.m_rbStart = rbAllocated;
876  uldci.m_rbLen = rbPerFlow;
877  std::map <uint16_t, std::vector <double> >::iterator itCqi = m_ueCqi.find ((*it).first);
878  int cqi = 0;
879  if (itCqi == m_ueCqi.end ())
880  {
881  // no cqi info about this UE
882  uldci.m_mcs = 0; // MCS 0 -> UL-AMC TBD
883 // NS_LOG_DEBUG (this << " UE does not have ULCQI " << (*it).first );
884  }
885  else
886  {
887  // take the lowest CQI value (worst RB)
888  double minSinr = (*itCqi).second.at (uldci.m_rbStart);
889  if (minSinr == NO_SINR)
890  {
891  minSinr = EstimateUlSinr ((*it).first, uldci.m_rbStart);
892  }
893  for (uint16_t i = uldci.m_rbStart; i < uldci.m_rbStart + uldci.m_rbLen; i++)
894  {
895 // NS_LOG_DEBUG (this << " UE " << (*it).first << " has SINR " << (*itCqi).second.at(i));
896  double sinr = (*itCqi).second.at (i);
897  if (sinr == NO_SINR)
898  {
899  sinr = EstimateUlSinr ((*it).first, i);
900  }
901  if ((*itCqi).second.at (i) < minSinr)
902  {
903  minSinr = (*itCqi).second.at (i);
904  }
905  }
906 
907  // translate SINR -> cqi: WILD ACK: same as DL
908  double s = log2 ( 1 + (
909  std::pow (10, minSinr / 10 ) /
910  ( (-std::log (5.0 * 0.00005 )) / 1.5) ));
912  if (cqi == 0)
913  {
914  it++;
915  if (it == m_ceBsrRxed.end ())
916  {
917  // restart from the first
918  it = m_ceBsrRxed.begin ();
919  }
920  continue; // CQI == 0 means "out of range" (see table 7.2.3-1 of 36.213)
921  }
922  uldci.m_mcs = m_amc->GetMcsFromCqi (cqi);
923 // NS_LOG_DEBUG (this << " UE " << (*it).first << " minsinr " << minSinr << " -> mcs " << (uint16_t)uldci.m_mcs);
924 
925  }
926 
927  rbAllocated += rbPerFlow;
928  // store info on allocation for managing ul-cqi interpretation
929  for (int i = 0; i < rbPerFlow; i++)
930  {
931  rbgAllocationMap.push_back ((*it).first);
932  }
933  uldci.m_tbSize = (m_amc->GetTbSizeFromMcs (uldci.m_mcs, rbPerFlow) / 8);
934  NS_LOG_DEBUG (this << " 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 << " RbAlloc " << rbAllocated);
935  UpdateUlRlcBufferInfo (uldci.m_rnti, uldci.m_tbSize);
936  uldci.m_ndi = 1;
937  uldci.m_cceIndex = 0;
938  uldci.m_aggrLevel = 1;
939  uldci.m_ueTxAntennaSelection = 3; // antenna selection OFF
940  uldci.m_hopping = false;
941  uldci.m_n2Dmrs = 0;
942  uldci.m_tpc = 0; // no power control
943  uldci.m_cqiRequest = false; // only period CQI at this stage
944  uldci.m_ulIndex = 0; // TDD parameter
945  uldci.m_dai = 1; // TDD parameter
946  uldci.m_freqHopping = 0;
947  uldci.m_pdcchPowerOffset = 0; // not used
948  ret.m_dciList.push_back (uldci);
949 
950  // update TTI UE stats
951  itStats = m_flowStatsUl.find ((*it).first);
952  if (itStats != m_flowStatsUl.end ())
953  {
954  (*itStats).second.lastTtiBytesTrasmitted = uldci.m_tbSize;
955 // NS_LOG_DEBUG (this << " UE bytes txed " << (*it).second.lastTtiBytesTrasmitted);
956 
957 
958  }
959  else
960  {
961  NS_LOG_DEBUG (this << " No Stats for this allocated UE");
962  }
963 
964 
965  it++;
966  if (it == m_ceBsrRxed.end ())
967  {
968  // restart from the first
969  it = m_ceBsrRxed.begin ();
970  }
971  if (rbAllocated == m_cschedCellConfig.m_ulBandwidth)
972  {
973  // Stop allocation: no more PRBs
974  m_nextRntiUl = (*it).first;
975  break;
976  }
977  }
978  while ((*it).first != m_nextRntiUl);
979 
980 
981  // Update global UE stats
982  // update UEs stats
983  for (itStats = m_flowStatsUl.begin (); itStats != m_flowStatsUl.end (); itStats++)
984  {
985  (*itStats).second.totalBytesTransmitted += (*itStats).second.lastTtiBytesTrasmitted;
986  // update average throughput (see eq. 12.3 of Sec 12.3.1.2 of LTE – The UMTS Long Term Evolution, Ed Wiley)
987  (*itStats).second.lastAveragedThroughput = ((1.0 - (1.0 / m_timeWindow)) * (*itStats).second.lastAveragedThroughput) + ((1.0 / m_timeWindow) * (double)((*itStats).second.lastTtiBytesTrasmitted / 0.001));
988  // NS_LOG_DEBUG (this << " UE tot bytes " << (*itStats).second.totalBytesTransmitted);
989  // NS_LOG_DEBUG (this << " UE avg thr " << (*itStats).second.lastAveragedThroughput);
990  (*itStats).second.lastTtiBytesTrasmitted = 0;
991  }
992  m_allocationMaps.insert (std::pair <uint16_t, std::vector <uint16_t> > (params.m_sfnSf, rbgAllocationMap));
994  return;
995 }
996 
997 void
999 {
1000  NS_LOG_FUNCTION (this);
1001  // TODO: Implementation of the API
1002  return;
1003 }
1004 
1005 void
1007 {
1008  NS_LOG_FUNCTION (this);
1009  // TODO: Implementation of the API
1010  return;
1011 }
1012 
1013 void
1015 {
1016  NS_LOG_FUNCTION (this);
1017 
1018  std::map <uint16_t,uint32_t>::iterator it;
1019 
1020  for (unsigned int i = 0; i < params.m_macCeList.size (); i++)
1021  {
1022  if ( params.m_macCeList.at (i).m_macCeType == MacCeListElement_s::BSR )
1023  {
1024  // buffer status report
1025  // note that we only consider LCG 0, the other three LCGs are neglected
1026  // this is consistent with the assumption in LteUeMac that the first LCG gathers all LCs
1027  uint16_t rnti = params.m_macCeList.at (i).m_rnti;
1028  it = m_ceBsrRxed.find (rnti);
1029  if (it == m_ceBsrRxed.end ())
1030  {
1031  // create the new entry
1032  uint8_t bsrId = params.m_macCeList.at (i).m_macCeValue.m_bufferStatus.at (0);
1033  int buffer = BufferSizeLevelBsr::BsrId2BufferSize (bsrId);
1034  m_ceBsrRxed.insert ( std::pair<uint16_t, uint32_t > (rnti, buffer));
1035  }
1036  else
1037  {
1038  // update the buffer size value
1039  (*it).second = BufferSizeLevelBsr::BsrId2BufferSize (params.m_macCeList.at (i).m_macCeValue.m_bufferStatus.at (0));
1040  }
1041  }
1042  }
1043 
1044  return;
1045 }
1046 
1047 void
1049 {
1050  NS_LOG_FUNCTION (this);
1051 // NS_LOG_DEBUG (this << " RX SFNID " << params.m_sfnSf);
1052  // retrieve the allocation for this subframe
1053  switch (m_ulCqiFilter)
1054  {
1056  {
1057  // filter all the CQIs that are not SRS based
1058  if (params.m_ulCqi.m_type!=UlCqi_s::SRS)
1059  {
1060  return;
1061  }
1062  }
1063  break;
1065  {
1066  // filter all the CQIs that are not SRS based
1067  if (params.m_ulCqi.m_type!=UlCqi_s::PUSCH)
1068  {
1069  return;
1070  }
1071  }
1073  break;
1074 
1075  default:
1076  NS_FATAL_ERROR ("Unknown UL CQI type");
1077  }
1078 
1079  switch (params.m_ulCqi.m_type)
1080  {
1081  case UlCqi_s::PUSCH:
1082  {
1083  std::map <uint16_t, std::vector <uint16_t> >::iterator itMap;
1084  std::map <uint16_t, std::vector <double> >::iterator itCqi;
1085  itMap = m_allocationMaps.find (params.m_sfnSf);
1086  if (itMap == m_allocationMaps.end ())
1087  {
1088  NS_LOG_DEBUG (this << " Does not find info on allocation, size : " << m_allocationMaps.size ());
1089  return;
1090  }
1091  for (uint32_t i = 0; i < (*itMap).second.size (); i++)
1092  {
1093  // convert from fixed point notation Sxxxxxxxxxxx.xxx to double
1094  // NS_LOG_INFO (this << " i " << i << " size " << params.m_ulCqi.m_sinr.size () << " mapSIze " << (*itMap).second.size ());
1095  double sinr = LteFfConverter::fpS11dot3toDouble (params.m_ulCqi.m_sinr.at (i));
1096  //NS_LOG_DEBUG (this << " UE " << (*itMap).second.at (i) << " SINRfp " << params.m_ulCqi.m_sinr.at (i) << " sinrdb " << sinr);
1097  itCqi = m_ueCqi.find ((*itMap).second.at (i));
1098  if (itCqi == m_ueCqi.end ())
1099  {
1100  // create a new entry
1101  std::vector <double> newCqi;
1102  for (uint32_t j = 0; j < m_cschedCellConfig.m_ulBandwidth; j++)
1103  {
1104  if (i == j)
1105  {
1106  newCqi.push_back (sinr);
1107  }
1108  else
1109  {
1110  // initialize with NO_SINR value.
1111  newCqi.push_back (NO_SINR);
1112  }
1113 
1114  }
1115  m_ueCqi.insert (std::pair <uint16_t, std::vector <double> > ((*itMap).second.at (i), newCqi));
1116  // generate correspondent timer
1117  m_ueCqiTimers.insert (std::pair <uint16_t, uint32_t > ((*itMap).second.at (i), m_cqiTimersThreshold));
1118  }
1119  else
1120  {
1121  // update the value
1122  (*itCqi).second.at (i) = sinr;
1123  // update correspondent timer
1124  std::map <uint16_t, uint32_t>::iterator itTimers;
1125  itTimers = m_ueCqiTimers.find ((*itMap).second.at (i));
1126  (*itTimers).second = m_cqiTimersThreshold;
1127 
1128  }
1129 
1130  }
1131  // remove obsolete info on allocation
1132  m_allocationMaps.erase (itMap);
1133  }
1134  break;
1135  case UlCqi_s::SRS:
1136  {
1137  // get the RNTI from vendor specific parameters
1138  uint16_t rnti = 0;
1139  NS_ASSERT (params.m_vendorSpecificList.size () > 0);
1140  for (uint16_t i = 0; i < params.m_vendorSpecificList.size (); i++)
1141  {
1142  if (params.m_vendorSpecificList.at (i).m_type == SRS_CQI_RNTI_VSP)
1143  {
1144  Ptr<SrsCqiRntiVsp> vsp = DynamicCast<SrsCqiRntiVsp> (params.m_vendorSpecificList.at (i).m_value);
1145  rnti = vsp->GetRnti ();
1146  }
1147  }
1148  std::map <uint16_t, std::vector <double> >::iterator itCqi;
1149  itCqi = m_ueCqi.find (rnti);
1150  if (itCqi == m_ueCqi.end ())
1151  {
1152  // create a new entry
1153  std::vector <double> newCqi;
1154  for (uint32_t j = 0; j < m_cschedCellConfig.m_ulBandwidth; j++)
1155  {
1156  double sinr = LteFfConverter::fpS11dot3toDouble (params.m_ulCqi.m_sinr.at (j));
1157  newCqi.push_back (sinr);
1158  NS_LOG_DEBUG (this << " RNTI " << rnti << " new SRS-CQI for RB " << j << " value " << sinr);
1159 
1160  }
1161  m_ueCqi.insert (std::pair <uint16_t, std::vector <double> > (rnti, newCqi));
1162  // generate correspondent timer
1163  m_ueCqiTimers.insert (std::pair <uint16_t, uint32_t > (rnti, m_cqiTimersThreshold));
1164  }
1165  else
1166  {
1167  // update the values
1168  for (uint32_t j = 0; j < m_cschedCellConfig.m_ulBandwidth; j++)
1169  {
1170  double sinr = LteFfConverter::fpS11dot3toDouble (params.m_ulCqi.m_sinr.at (j));
1171  (*itCqi).second.at (j) = sinr;
1172  NS_LOG_DEBUG (this << " RNTI " << rnti << " update SRS-CQI for RB " << j << " value " << sinr);
1173  }
1174  // update correspondent timer
1175  std::map <uint16_t, uint32_t>::iterator itTimers;
1176  itTimers = m_ueCqiTimers.find (rnti);
1177  (*itTimers).second = m_cqiTimersThreshold;
1178 
1179  }
1180 
1181 
1182  }
1183  break;
1184  case UlCqi_s::PUCCH_1:
1185  case UlCqi_s::PUCCH_2:
1186  case UlCqi_s::PRACH:
1187  {
1188  NS_FATAL_ERROR ("PfFfMacScheduler supports only PUSCH and SRS UL-CQIs");
1189  }
1190  break;
1191  default:
1192  NS_FATAL_ERROR ("Unknown type of UL-CQI");
1193  }
1194  return;
1195 }
1196 
1197 void
1199 {
1200  // refresh DL CQI P01 Map
1201  std::map <uint16_t,uint32_t>::iterator itP10 = m_p10CqiTimers.begin ();
1202  while (itP10!=m_p10CqiTimers.end ())
1203  {
1204 // NS_LOG_INFO (this << " P10-CQI for user " << (*itP10).first << " is " << (uint32_t)(*itP10).second << " thr " << (uint32_t)m_cqiTimersThreshold);
1205  if ((*itP10).second == 0)
1206  {
1207  // delete correspondent entries
1208  std::map <uint16_t,uint8_t>::iterator itMap = m_p10CqiRxed.find ((*itP10).first);
1209  NS_ASSERT_MSG (itMap != m_p10CqiRxed.end (), " Does not find CQI report for user " << (*itP10).first);
1210  NS_LOG_INFO (this << " P10-CQI exired for user " << (*itP10).first);
1211  m_p10CqiRxed.erase (itMap);
1212  std::map <uint16_t,uint32_t>::iterator temp = itP10;
1213  itP10++;
1214  m_p10CqiTimers.erase (temp);
1215  }
1216  else
1217  {
1218  (*itP10).second--;
1219  itP10++;
1220  }
1221  }
1222 
1223  // refresh DL CQI A30 Map
1224  std::map <uint16_t,uint32_t>::iterator itA30 = m_a30CqiTimers.begin ();
1225  while (itA30!=m_a30CqiTimers.end ())
1226  {
1227 // NS_LOG_INFO (this << " A30-CQI for user " << (*itA30).first << " is " << (uint32_t)(*itA30).second << " thr " << (uint32_t)m_cqiTimersThreshold);
1228  if ((*itA30).second == 0)
1229  {
1230  // delete correspondent entries
1231  std::map <uint16_t,SbMeasResult_s>::iterator itMap = m_a30CqiRxed.find ((*itA30).first);
1232  NS_ASSERT_MSG (itMap != m_a30CqiRxed.end (), " Does not find CQI report for user " << (*itA30).first);
1233  NS_LOG_INFO (this << " A30-CQI exired for user " << (*itA30).first);
1234  m_a30CqiRxed.erase (itMap);
1235  std::map <uint16_t,uint32_t>::iterator temp = itA30;
1236  itA30++;
1237  m_a30CqiTimers.erase (temp);
1238  }
1239  else
1240  {
1241  (*itA30).second--;
1242  itA30++;
1243  }
1244  }
1245 
1246  return;
1247 }
1248 
1249 
1250 void
1252 {
1253  // refresh UL CQI Map
1254  std::map <uint16_t,uint32_t>::iterator itUl = m_ueCqiTimers.begin ();
1255  while (itUl!=m_ueCqiTimers.end ())
1256  {
1257 // NS_LOG_INFO (this << " UL-CQI for user " << (*itUl).first << " is " << (uint32_t)(*itUl).second << " thr " << (uint32_t)m_cqiTimersThreshold);
1258  if ((*itUl).second == 0)
1259  {
1260  // delete correspondent entries
1261  std::map <uint16_t, std::vector <double> >::iterator itMap = m_ueCqi.find ((*itUl).first);
1262  NS_ASSERT_MSG (itMap != m_ueCqi.end (), " Does not find CQI report for user " << (*itUl).first);
1263  NS_LOG_INFO (this << " UL-CQI exired for user " << (*itUl).first);
1264  (*itMap).second.clear ();
1265  m_ueCqi.erase (itMap);
1266  std::map <uint16_t,uint32_t>::iterator temp = itUl;
1267  itUl++;
1268  m_ueCqiTimers.erase (temp);
1269  }
1270  else
1271  {
1272  (*itUl).second--;
1273  itUl++;
1274  }
1275  }
1276 
1277  return;
1278 }
1279 
1280 void
1281 PfFfMacScheduler::UpdateDlRlcBufferInfo (uint16_t rnti, uint8_t lcid, uint16_t size)
1282 {
1283  size = size - 2; // remove the minimum RLC overhead
1284  std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it;
1285  LteFlowId_t flow (rnti, lcid);
1286  it = m_rlcBufferReq.find (flow);
1287  if (it!=m_rlcBufferReq.end ())
1288  {
1289 // NS_LOG_DEBUG (this << " UE " << rnti << " LC " << (uint16_t)lcid << " txqueue " << (*it).second.m_rlcTransmissionQueueSize << " retxqueue " << (*it).second.m_rlcRetransmissionQueueSize << " status " << (*it).second.m_rlcStatusPduSize << " decrease " << size);
1290  // Update queues: RLC tx order Status, ReTx, Tx
1291  // Update status queue
1292  if ((*it).second.m_rlcStatusPduSize <= size)
1293  {
1294  size -= (*it).second.m_rlcStatusPduSize;
1295  (*it).second.m_rlcStatusPduSize = 0;
1296  }
1297  else
1298  {
1299  (*it).second.m_rlcStatusPduSize -= size;
1300  return;
1301  }
1302  // update retransmission queue
1303  if ((*it).second.m_rlcRetransmissionQueueSize <= size)
1304  {
1305  size -= (*it).second.m_rlcRetransmissionQueueSize;
1306  (*it).second.m_rlcRetransmissionQueueSize = 0;
1307  }
1308  else
1309  {
1310  (*it).second.m_rlcRetransmissionQueueSize -= size;
1311  return;
1312  }
1313  // update transmission queue
1314  if ((*it).second.m_rlcTransmissionQueueSize <= size)
1315  {
1316  size -= (*it).second.m_rlcTransmissionQueueSize;
1317  (*it).second.m_rlcTransmissionQueueSize = 0;
1318  }
1319  else
1320  {
1321  (*it).second.m_rlcTransmissionQueueSize -= size;
1322  return;
1323  }
1324  }
1325  else
1326  {
1327  NS_LOG_ERROR (this << " Does not find DL RLC Buffer Report of UE " << rnti);
1328  }
1329 }
1330 
1331 void
1332 PfFfMacScheduler::UpdateUlRlcBufferInfo (uint16_t rnti, uint16_t size)
1333 {
1334 
1335  size = size - 2; // remove the minimum RLC overhead
1336  std::map <uint16_t,uint32_t>::iterator it = m_ceBsrRxed.find (rnti);
1337  if (it!=m_ceBsrRxed.end ())
1338  {
1339 // NS_LOG_DEBUG (this << " UE " << rnti << " size " << size << " BSR " << (*it).second);
1340  if ((*it).second >= size)
1341  {
1342  (*it).second -= size;
1343  }
1344  else
1345  {
1346  (*it).second = 0;
1347  }
1348  }
1349  else
1350  {
1351  NS_LOG_ERROR (this << " Does not find BSR report info of UE " << rnti);
1352  }
1353 
1354 }
1355 
1356 void
1358 {
1359  NS_LOG_FUNCTION (this << " RNTI " << rnti << " txMode " << (uint16_t)txMode);
1361  params.m_rnti = rnti;
1362  params.m_transmissionMode = txMode;
1364 }
1365 
1366 
1367 }