A Discrete-Event Network Simulator
API
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
pss-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  * Modification: Dizhi Zhou <dizhi.zhou@gmail.com> // modify codes related to downlink scheduler
20  */
21 
22 #include <ns3/log.h>
23 #include <ns3/pointer.h>
24 #include <ns3/math.h>
25 
26 #include <ns3/simulator.h>
27 #include <ns3/lte-amc.h>
28 #include <ns3/pss-ff-mac-scheduler.h>
29 #include <ns3/lte-vendor-specific-parameters.h>
30 #include <ns3/boolean.h>
31 #include <cfloat>
32 #include <set>
33 #include <ns3/string.h>
34 #include <algorithm>
35 
36 
37 NS_LOG_COMPONENT_DEFINE ("PssFfMacScheduler");
38 
39 namespace ns3 {
40 
41 static const int PssType0AllocationRbg[4] = {
42  10, // RGB size 1
43  26, // RGB size 2
44  63, // RGB size 3
45  110 // RGB size 4
46 }; // see table 7.1.6.1-1 of 36.213
47 
48 
49 NS_OBJECT_ENSURE_REGISTERED (PssFfMacScheduler);
50 
51 
52 
54 {
55 public:
57 
58  // inherited from FfMacCschedSapProvider
59  virtual void CschedCellConfigReq (const struct CschedCellConfigReqParameters& params);
60  virtual void CschedUeConfigReq (const struct CschedUeConfigReqParameters& params);
61  virtual void CschedLcConfigReq (const struct CschedLcConfigReqParameters& params);
62  virtual void CschedLcReleaseReq (const struct CschedLcReleaseReqParameters& params);
63  virtual void CschedUeReleaseReq (const struct CschedUeReleaseReqParameters& params);
64 
65 private:
68 };
69 
71 {
72 }
73 
75 {
76 }
77 
78 
79 void
81 {
83 }
84 
85 void
87 {
89 }
90 
91 
92 void
94 {
96 }
97 
98 void
100 {
102 }
103 
104 void
106 {
108 }
109 
110 
111 
112 
114 {
115 public:
117 
118  // inherited from FfMacSchedSapProvider
119  virtual void SchedDlRlcBufferReq (const struct SchedDlRlcBufferReqParameters& params);
120  virtual void SchedDlPagingBufferReq (const struct SchedDlPagingBufferReqParameters& params);
121  virtual void SchedDlMacBufferReq (const struct SchedDlMacBufferReqParameters& params);
122  virtual void SchedDlTriggerReq (const struct SchedDlTriggerReqParameters& params);
123  virtual void SchedDlRachInfoReq (const struct SchedDlRachInfoReqParameters& params);
124  virtual void SchedDlCqiInfoReq (const struct SchedDlCqiInfoReqParameters& params);
125  virtual void SchedUlTriggerReq (const struct SchedUlTriggerReqParameters& params);
126  virtual void SchedUlNoiseInterferenceReq (const struct SchedUlNoiseInterferenceReqParameters& params);
127  virtual void SchedUlSrInfoReq (const struct SchedUlSrInfoReqParameters& params);
128  virtual void SchedUlMacCtrlInfoReq (const struct SchedUlMacCtrlInfoReqParameters& params);
129  virtual void SchedUlCqiInfoReq (const struct SchedUlCqiInfoReqParameters& params);
130 
131 
132 private:
135 };
136 
137 
138 
140 {
141 }
142 
143 
145  : m_scheduler (scheduler)
146 {
147 }
148 
149 void
151 {
153 }
154 
155 void
157 {
159 }
160 
161 void
163 {
165 }
166 
167 void
169 {
171 }
172 
173 void
175 {
177 }
178 
179 void
181 {
183 }
184 
185 void
187 {
189 }
190 
191 void
193 {
195 }
196 
197 void
199 {
201 }
202 
203 void
205 {
207 }
208 
209 void
211 {
213 }
214 
215 
216 
217 
218 
220  : m_cschedSapUser (0),
221  m_schedSapUser (0),
222  m_timeWindow (99.0),
223  m_nextRntiUl (0)
224 {
225  m_amc = CreateObject <LteAmc> ();
228 }
229 
231 {
232  NS_LOG_FUNCTION (this);
233 }
234 
235 void
237 {
238  NS_LOG_FUNCTION (this);
240  m_dlHarqProcessesTimer.clear ();
242  m_dlInfoListBuffered.clear ();
243  m_ulHarqCurrentProcessId.clear ();
244  m_ulHarqProcessesStatus.clear ();
246  delete m_cschedSapProvider;
247  delete m_schedSapProvider;
248 }
249 
250 TypeId
252 {
253  static TypeId tid = TypeId ("ns3::PssFfMacScheduler")
255  .AddConstructor<PssFfMacScheduler> ()
256  .AddAttribute ("CqiTimerThreshold",
257  "The number of TTIs a CQI is valid (default 1000 - 1 sec.)",
258  UintegerValue (1000),
259  MakeUintegerAccessor (&PssFfMacScheduler::m_cqiTimersThreshold),
260  MakeUintegerChecker<uint32_t> ())
261  .AddAttribute ("PssFdSchedulerType",
262  "FD scheduler in PSS (default value is PFsch)",
263  StringValue ("PFsch"),
264  MakeStringAccessor (&PssFfMacScheduler::m_fdSchedulerType),
265  MakeStringChecker ())
266  .AddAttribute ("nMux",
267  "The number of UE selected by TD scheduler (default value is 0)",
268  UintegerValue (0),
269  MakeUintegerAccessor (&PssFfMacScheduler::m_nMux),
270  MakeUintegerChecker<uint32_t> ())
271  .AddAttribute ("HarqEnabled",
272  "Activate/Deactivate the HARQ [by default is active].",
273  BooleanValue (true),
274  MakeBooleanAccessor (&PssFfMacScheduler::m_harqOn),
275  MakeBooleanChecker ())
276  .AddAttribute ("UlGrantMcs",
277  "The MCS of the UL grant, must be [0..15] (default 0)",
278  UintegerValue (0),
279  MakeUintegerAccessor (&PssFfMacScheduler::m_ulGrantMcs),
280  MakeUintegerChecker<uint8_t> ())
281  ;
282  return tid;
283 }
284 
285 
286 
287 void
289 {
290  m_cschedSapUser = s;
291 }
292 
293 void
295 {
296  m_schedSapUser = s;
297 }
298 
301 {
302  return m_cschedSapProvider;
303 }
304 
307 {
308  return m_schedSapProvider;
309 }
310 
311 void
313 {
314  NS_LOG_FUNCTION (this);
315  // Read the subset of parameters used
316  m_cschedCellConfig = params;
319  cnf.m_result = SUCCESS;
321  return;
322 }
323 
324 void
326 {
327  NS_LOG_FUNCTION (this << " RNTI " << params.m_rnti << " txMode " << (uint16_t)params.m_transmissionMode);
328  std::map <uint16_t,uint8_t>::iterator it = m_uesTxMode.find (params.m_rnti);
329  if (it == m_uesTxMode.end ())
330  {
331  m_uesTxMode.insert (std::pair <uint16_t, double> (params.m_rnti, params.m_transmissionMode));
332  // generate HARQ buffers
333  m_dlHarqCurrentProcessId.insert (std::pair <uint16_t,uint8_t > (params.m_rnti, 0));
334  DlHarqProcessesStatus_t dlHarqPrcStatus;
335  dlHarqPrcStatus.resize (8,0);
336  m_dlHarqProcessesStatus.insert (std::pair <uint16_t, DlHarqProcessesStatus_t> (params.m_rnti, dlHarqPrcStatus));
337  DlHarqProcessesTimer_t dlHarqProcessesTimer;
338  dlHarqProcessesTimer.resize (8,0);
339  m_dlHarqProcessesTimer.insert (std::pair <uint16_t, DlHarqProcessesTimer_t> (params.m_rnti, dlHarqProcessesTimer));
340  DlHarqProcessesDciBuffer_t dlHarqdci;
341  dlHarqdci.resize (8);
342  m_dlHarqProcessesDciBuffer.insert (std::pair <uint16_t, DlHarqProcessesDciBuffer_t> (params.m_rnti, dlHarqdci));
343  DlHarqRlcPduListBuffer_t dlHarqRlcPdu;
344  dlHarqRlcPdu.resize (2);
345  dlHarqRlcPdu.at (0).resize (8);
346  dlHarqRlcPdu.at (1).resize (8);
347  m_dlHarqProcessesRlcPduListBuffer.insert (std::pair <uint16_t, DlHarqRlcPduListBuffer_t> (params.m_rnti, dlHarqRlcPdu));
348  m_ulHarqCurrentProcessId.insert (std::pair <uint16_t,uint8_t > (params.m_rnti, 0));
349  UlHarqProcessesStatus_t ulHarqPrcStatus;
350  ulHarqPrcStatus.resize (8,0);
351  m_ulHarqProcessesStatus.insert (std::pair <uint16_t, UlHarqProcessesStatus_t> (params.m_rnti, ulHarqPrcStatus));
352  UlHarqProcessesDciBuffer_t ulHarqdci;
353  ulHarqdci.resize (8);
354  m_ulHarqProcessesDciBuffer.insert (std::pair <uint16_t, UlHarqProcessesDciBuffer_t> (params.m_rnti, ulHarqdci));
355  }
356  else
357  {
358  (*it).second = params.m_transmissionMode;
359  }
360  return;
361 }
362 
363 void
365 {
366  NS_LOG_FUNCTION (this << " New LC, rnti: " << params.m_rnti);
367 
368  std::map <uint16_t, pssFlowPerf_t>::iterator it;
369  for (uint16_t i = 0; i < params.m_logicalChannelConfigList.size (); i++)
370  {
371  it = m_flowStatsDl.find (params.m_rnti);
372 
373  if (it == m_flowStatsDl.end ())
374  {
375  double tbrDlInBytes = params.m_logicalChannelConfigList.at (i).m_eRabGuaranteedBitrateDl / 8; // byte/s
376  double tbrUlInBytes = params.m_logicalChannelConfigList.at (i).m_eRabGuaranteedBitrateUl / 8; // byte/s
377 
378  pssFlowPerf_t flowStatsDl;
379  flowStatsDl.flowStart = Simulator::Now ();
380  flowStatsDl.totalBytesTransmitted = 0;
381  flowStatsDl.lastTtiBytesTransmitted = 0;
382  flowStatsDl.lastAveragedThroughput = 1;
383  flowStatsDl.secondLastAveragedThroughput = 1;
384  flowStatsDl.targetThroughput = tbrDlInBytes;
385  m_flowStatsDl.insert (std::pair<uint16_t, pssFlowPerf_t> (params.m_rnti, flowStatsDl));
386  pssFlowPerf_t flowStatsUl;
387  flowStatsUl.flowStart = Simulator::Now ();
388  flowStatsUl.totalBytesTransmitted = 0;
389  flowStatsUl.lastTtiBytesTransmitted = 0;
390  flowStatsUl.lastAveragedThroughput = 1;
391  flowStatsUl.secondLastAveragedThroughput = 1;
392  flowStatsUl.targetThroughput = tbrUlInBytes;
393  m_flowStatsUl.insert (std::pair<uint16_t, pssFlowPerf_t> (params.m_rnti, flowStatsUl));
394  }
395  else
396  {
397  // update GBR from UeManager::SetupDataRadioBearer ()
398  double tbrDlInBytes = params.m_logicalChannelConfigList.at (i).m_eRabGuaranteedBitrateDl / 8; // byte/s
399  double tbrUlInBytes = params.m_logicalChannelConfigList.at (i).m_eRabGuaranteedBitrateUl / 8; // byte/s
400  m_flowStatsDl[(*it).first].targetThroughput = tbrDlInBytes;
401  m_flowStatsUl[(*it).first].targetThroughput = tbrUlInBytes;
402  }
403  }
404 
405  return;
406 }
407 
408 void
410 {
411  NS_LOG_FUNCTION (this);
412  for (uint16_t i = 0; i < params.m_logicalChannelIdentity.size (); i++)
413  {
414  std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it = m_rlcBufferReq.begin ();
415  std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator temp;
416  while (it!=m_rlcBufferReq.end ())
417  {
418  if (((*it).first.m_rnti == params.m_rnti) && ((*it).first.m_lcId == params.m_logicalChannelIdentity.at (i)))
419  {
420  temp = it;
421  it++;
422  m_rlcBufferReq.erase (temp);
423  }
424  else
425  {
426  it++;
427  }
428  }
429  }
430  return;
431 }
432 
433 void
435 {
436  NS_LOG_FUNCTION (this);
437 
438  m_uesTxMode.erase (params.m_rnti);
439  m_dlHarqCurrentProcessId.erase (params.m_rnti);
440  m_dlHarqProcessesStatus.erase (params.m_rnti);
441  m_dlHarqProcessesTimer.erase (params.m_rnti);
442  m_dlHarqProcessesDciBuffer.erase (params.m_rnti);
444  m_ulHarqCurrentProcessId.erase (params.m_rnti);
445  m_ulHarqProcessesStatus.erase (params.m_rnti);
446  m_ulHarqProcessesDciBuffer.erase (params.m_rnti);
447  m_flowStatsDl.erase (params.m_rnti);
448  m_flowStatsUl.erase (params.m_rnti);
449  m_ceBsrRxed.erase (params.m_rnti);
450  std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it = m_rlcBufferReq.begin ();
451  std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator temp;
452  while (it!=m_rlcBufferReq.end ())
453  {
454  if ((*it).first.m_rnti == params.m_rnti)
455  {
456  temp = it;
457  it++;
458  m_rlcBufferReq.erase (temp);
459  }
460  else
461  {
462  it++;
463  }
464  }
465  if (m_nextRntiUl == params.m_rnti)
466  {
467  m_nextRntiUl = 0;
468  }
469 
470  return;
471 }
472 
473 
474 void
476 {
477  NS_LOG_FUNCTION (this << params.m_rnti << (uint32_t) params.m_logicalChannelIdentity);
478  // API generated by RLC for updating RLC parameters on a LC (tx and retx queues)
479 
480  std::map <LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it;
481 
482  LteFlowId_t flow (params.m_rnti, params.m_logicalChannelIdentity);
483 
484  it = m_rlcBufferReq.find (flow);
485 
486  if (it == m_rlcBufferReq.end ())
487  {
488  m_rlcBufferReq.insert (std::pair <LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters> (flow, params));
489  }
490  else
491  {
492  (*it).second = params;
493  }
494 
495  return;
496 }
497 
498 void
500 {
501  NS_LOG_FUNCTION (this);
502  NS_FATAL_ERROR ("method not implemented");
503  return;
504 }
505 
506 void
508 {
509  NS_LOG_FUNCTION (this);
510  NS_FATAL_ERROR ("method not implemented");
511  return;
512 }
513 
514 int
516 {
517  for (int i = 0; i < 4; i++)
518  {
519  if (dlbandwidth < PssType0AllocationRbg[i])
520  {
521  return (i + 1);
522  }
523  }
524 
525  return (-1);
526 }
527 
528 
529 int
531 {
532  std::map <LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it;
533  int lcActive = 0;
534  for (it = m_rlcBufferReq.begin (); it != m_rlcBufferReq.end (); it++)
535  {
536  if (((*it).first.m_rnti == rnti) && (((*it).second.m_rlcTransmissionQueueSize > 0)
537  || ((*it).second.m_rlcRetransmissionQueueSize > 0)
538  || ((*it).second.m_rlcStatusPduSize > 0) ))
539  {
540  lcActive++;
541  }
542  if ((*it).first.m_rnti > rnti)
543  {
544  break;
545  }
546  }
547  return (lcActive);
548 
549 }
550 
551 
552 uint8_t
554 {
555  NS_LOG_FUNCTION (this << rnti);
556 
557  std::map <uint16_t, uint8_t>::iterator it = m_dlHarqCurrentProcessId.find (rnti);
558  if (it == m_dlHarqCurrentProcessId.end ())
559  {
560  NS_FATAL_ERROR ("No Process Id found for this RNTI " << rnti);
561  }
562  std::map <uint16_t, DlHarqProcessesStatus_t>::iterator itStat = m_dlHarqProcessesStatus.find (rnti);
563  if (itStat == m_dlHarqProcessesStatus.end ())
564  {
565  NS_FATAL_ERROR ("No Process Id Statusfound for this RNTI " << rnti);
566  }
567  uint8_t i = (*it).second;
568  do
569  {
570  i = (i + 1) % HARQ_PROC_NUM;
571  }
572  while ( ((*itStat).second.at (i) != 0)&&(i != (*it).second));
573  if ((*itStat).second.at (i) == 0)
574  {
575  return (true);
576  }
577  else
578  {
579  return (false); // return a not valid harq proc id
580  }
581 }
582 
583 
584 
585 uint8_t
587 {
588  NS_LOG_FUNCTION (this << rnti);
589 
590  if (m_harqOn == false)
591  {
592  return (0);
593  }
594 
595 
596  std::map <uint16_t, uint8_t>::iterator it = m_dlHarqCurrentProcessId.find (rnti);
597  if (it == m_dlHarqCurrentProcessId.end ())
598  {
599  NS_FATAL_ERROR ("No Process Id found for this RNTI " << rnti);
600  }
601  std::map <uint16_t, DlHarqProcessesStatus_t>::iterator itStat = m_dlHarqProcessesStatus.find (rnti);
602  if (itStat == m_dlHarqProcessesStatus.end ())
603  {
604  NS_FATAL_ERROR ("No Process Id Statusfound for this RNTI " << rnti);
605  }
606  uint8_t i = (*it).second;
607  do
608  {
609  i = (i + 1) % HARQ_PROC_NUM;
610  }
611  while ( ((*itStat).second.at (i) != 0)&&(i != (*it).second));
612  if ((*itStat).second.at (i) == 0)
613  {
614  (*it).second = i;
615  (*itStat).second.at (i) = 1;
616  }
617  else
618  {
619  NS_FATAL_ERROR ("No HARQ process available for RNTI " << rnti << " check before update with HarqProcessAvailability");
620  }
621 
622  return ((*it).second);
623 }
624 
625 
626 void
628 {
629  NS_LOG_FUNCTION (this);
630 
631  std::map <uint16_t, DlHarqProcessesTimer_t>::iterator itTimers;
632  for (itTimers = m_dlHarqProcessesTimer.begin (); itTimers != m_dlHarqProcessesTimer.end (); itTimers ++)
633  {
634  for (uint16_t i = 0; i < HARQ_PROC_NUM; i++)
635  {
636  if ((*itTimers).second.at (i) == HARQ_DL_TIMEOUT)
637  {
638  // reset HARQ process
639 
640  NS_LOG_DEBUG (this << " Reset HARQ proc " << i << " for RNTI " << (*itTimers).first);
641  std::map <uint16_t, DlHarqProcessesStatus_t>::iterator itStat = m_dlHarqProcessesStatus.find ((*itTimers).first);
642  if (itStat == m_dlHarqProcessesStatus.end ())
643  {
644  NS_FATAL_ERROR ("No Process Id Status found for this RNTI " << (*itTimers).first);
645  }
646  (*itStat).second.at (i) = 0;
647  (*itTimers).second.at (i) = 0;
648  }
649  else
650  {
651  (*itTimers).second.at (i)++;
652  }
653  }
654  }
655 
656 }
657 
658 
659 void
661 {
662  NS_LOG_FUNCTION (this << " Frame no. " << (params.m_sfnSf >> 4) << " subframe no. " << (0xF & params.m_sfnSf));
663  // API generated by RLC for triggering the scheduling of a DL subframe
664 
665 
666  // evaluate the relative channel quality indicator for each UE per each RBG
667  // (since we are using allocation type 0 the small unit of allocation is RBG)
668  // Resource allocation type 0 (see sec 7.1.6.1 of 36.213)
669 
670  RefreshDlCqiMaps ();
671 
673  int rbgNum = m_cschedCellConfig.m_dlBandwidth / rbgSize;
674  std::map <uint16_t, std::vector <uint16_t> > allocationMap; // RBs map per RNTI
675  std::vector <bool> rbgMap; // global RBGs map
676  uint16_t rbgAllocatedNum = 0;
677  std::set <uint16_t> rntiAllocated;
678  rbgMap.resize (m_cschedCellConfig.m_dlBandwidth / rbgSize, false);
680 
681  // update UL HARQ proc id
682  std::map <uint16_t, uint8_t>::iterator itProcId;
683  for (itProcId = m_ulHarqCurrentProcessId.begin (); itProcId != m_ulHarqCurrentProcessId.end (); itProcId++)
684  {
685  (*itProcId).second = ((*itProcId).second + 1) % HARQ_PROC_NUM;
686  }
687 
688  // RACH Allocation
690  uint16_t rbStart = 0;
691  std::vector <struct RachListElement_s>::iterator itRach;
692  for (itRach = m_rachList.begin (); itRach != m_rachList.end (); itRach++)
693  {
694  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");
695  BuildRarListElement_s newRar;
696  newRar.m_rnti = (*itRach).m_rnti;
697  // DL-RACH Allocation
698  // Ideal: no needs of configuring m_dci
699  // UL-RACH Allocation
700  newRar.m_grant.m_rnti = newRar.m_rnti;
701  newRar.m_grant.m_mcs = m_ulGrantMcs;
702  uint16_t rbLen = 1;
703  uint16_t tbSizeBits = 0;
704  // find lowest TB size that fits UL grant estimated size
705  while ((tbSizeBits < (*itRach).m_estimatedSize) && (rbStart + rbLen < m_cschedCellConfig.m_ulBandwidth))
706  {
707  rbLen++;
708  tbSizeBits = m_amc->GetTbSizeFromMcs (m_ulGrantMcs, rbLen);
709  }
710  if (tbSizeBits < (*itRach).m_estimatedSize)
711  {
712  // no more allocation space: finish allocation
713  break;
714  }
715  newRar.m_grant.m_rbStart = rbStart;
716  newRar.m_grant.m_rbLen = rbLen;
717  newRar.m_grant.m_tbSize = tbSizeBits / 8;
718  newRar.m_grant.m_hopping = false;
719  newRar.m_grant.m_tpc = 0;
720  newRar.m_grant.m_cqiRequest = false;
721  newRar.m_grant.m_ulDelay = false;
722  NS_LOG_INFO (this << " UL grant allocated to RNTI " << (*itRach).m_rnti << " rbStart " << rbStart << " rbLen " << rbLen << " MCS " << m_ulGrantMcs << " tbSize " << newRar.m_grant.m_tbSize);
723  for (uint16_t i = rbStart; i < rbStart + rbLen; i++)
724  {
725  m_rachAllocationMap.at (i) = (*itRach).m_rnti;
726  }
727  rbStart = rbStart + rbLen;
728 
729  if (m_harqOn == true)
730  {
731  // generate UL-DCI for HARQ retransmissions
732  UlDciListElement_s uldci;
733  uldci.m_rnti = newRar.m_rnti;
734  uldci.m_rbLen = rbLen;
735  uldci.m_rbStart = rbStart;
736  uldci.m_mcs = m_ulGrantMcs;
737  uldci.m_tbSize = tbSizeBits / 8;
738  uldci.m_ndi = 1;
739  uldci.m_cceIndex = 0;
740  uldci.m_aggrLevel = 1;
741  uldci.m_ueTxAntennaSelection = 3; // antenna selection OFF
742  uldci.m_hopping = false;
743  uldci.m_n2Dmrs = 0;
744  uldci.m_tpc = 0; // no power control
745  uldci.m_cqiRequest = false; // only period CQI at this stage
746  uldci.m_ulIndex = 0; // TDD parameter
747  uldci.m_dai = 1; // TDD parameter
748  uldci.m_freqHopping = 0;
749  uldci.m_pdcchPowerOffset = 0; // not used
750 
751  uint8_t harqId = 0;
752  std::map <uint16_t, uint8_t>::iterator itProcId;
753  itProcId = m_ulHarqCurrentProcessId.find (uldci.m_rnti);
754  if (itProcId == m_ulHarqCurrentProcessId.end ())
755  {
756  NS_FATAL_ERROR ("No info find in HARQ buffer for UE " << uldci.m_rnti);
757  }
758  harqId = (*itProcId).second;
759  std::map <uint16_t, UlHarqProcessesDciBuffer_t>::iterator itDci = m_ulHarqProcessesDciBuffer.find (uldci.m_rnti);
760  if (itDci == m_ulHarqProcessesDciBuffer.end ())
761  {
762  NS_FATAL_ERROR ("Unable to find RNTI entry in UL DCI HARQ buffer for RNTI " << uldci.m_rnti);
763  }
764  (*itDci).second.at (harqId) = uldci;
765  }
766 
767  ret.m_buildRarList.push_back (newRar);
768  }
769  m_rachList.clear ();
770 
771 
772  // Process DL HARQ feedback
774  // retrieve past HARQ retx buffered
775  if (m_dlInfoListBuffered.size () > 0)
776  {
777  if (params.m_dlInfoList.size () > 0)
778  {
779  NS_LOG_INFO (this << " Received DL-HARQ feedback");
780  m_dlInfoListBuffered.insert (m_dlInfoListBuffered.end (), params.m_dlInfoList.begin (), params.m_dlInfoList.end ());
781  }
782  }
783  else
784  {
785  if (params.m_dlInfoList.size () > 0)
786  {
788  }
789  }
790  if (m_harqOn == false)
791  {
792  // Ignore HARQ feedback
793  m_dlInfoListBuffered.clear ();
794  }
795  std::vector <struct DlInfoListElement_s> dlInfoListUntxed;
796  for (uint16_t i = 0; i < m_dlInfoListBuffered.size (); i++)
797  {
798  std::set <uint16_t>::iterator itRnti = rntiAllocated.find (m_dlInfoListBuffered.at (i).m_rnti);
799  if (itRnti != rntiAllocated.end ())
800  {
801  // RNTI already allocated for retx
802  continue;
803  }
804  uint8_t nLayers = m_dlInfoListBuffered.at (i).m_harqStatus.size ();
805  std::vector <bool> retx;
806  NS_LOG_INFO (this << " Processing DLHARQ feedback");
807  if (nLayers == 1)
808  {
809  retx.push_back (m_dlInfoListBuffered.at (i).m_harqStatus.at (0) == DlInfoListElement_s::NACK);
810  retx.push_back (false);
811  }
812  else
813  {
814  retx.push_back (m_dlInfoListBuffered.at (i).m_harqStatus.at (0) == DlInfoListElement_s::NACK);
815  retx.push_back (m_dlInfoListBuffered.at (i).m_harqStatus.at (1) == DlInfoListElement_s::NACK);
816  }
817  if (retx.at (0) || retx.at (1))
818  {
819  // retrieve HARQ process information
820  uint16_t rnti = m_dlInfoListBuffered.at (i).m_rnti;
821  uint8_t harqId = m_dlInfoListBuffered.at (i).m_harqProcessId;
822  NS_LOG_INFO (this << " HARQ retx RNTI " << rnti << " harqId " << (uint16_t)harqId);
823  std::map <uint16_t, DlHarqProcessesDciBuffer_t>::iterator itHarq = m_dlHarqProcessesDciBuffer.find (rnti);
824  if (itHarq == m_dlHarqProcessesDciBuffer.end ())
825  {
826  NS_FATAL_ERROR ("No info find in HARQ buffer for UE " << rnti);
827  }
828 
829  DlDciListElement_s dci = (*itHarq).second.at (harqId);
830  int rv = 0;
831  if (dci.m_rv.size () == 1)
832  {
833  rv = dci.m_rv.at (0);
834  }
835  else
836  {
837  rv = (dci.m_rv.at (0) > dci.m_rv.at (1) ? dci.m_rv.at (0) : dci.m_rv.at (1));
838  }
839 
840  if (rv == 3)
841  {
842  // maximum number of retx reached -> drop process
843  NS_LOG_INFO ("Maximum number of retransmissions reached -> drop process");
844  std::map <uint16_t, DlHarqProcessesStatus_t>::iterator it = m_dlHarqProcessesStatus.find (rnti);
845  if (it == m_dlHarqProcessesStatus.end ())
846  {
847  NS_LOG_ERROR ("No info find in HARQ buffer for UE (might change eNB) " << m_dlInfoListBuffered.at (i).m_rnti);
848  }
849  (*it).second.at (harqId) = 0;
850  std::map <uint16_t, DlHarqRlcPduListBuffer_t>::iterator itRlcPdu = m_dlHarqProcessesRlcPduListBuffer.find (rnti);
851  if (itRlcPdu == m_dlHarqProcessesRlcPduListBuffer.end ())
852  {
853  NS_FATAL_ERROR ("Unable to find RlcPdcList in HARQ buffer for RNTI " << m_dlInfoListBuffered.at (i).m_rnti);
854  }
855  for (uint16_t k = 0; k < (*itRlcPdu).second.size (); k++)
856  {
857  (*itRlcPdu).second.at (k).at (harqId).clear ();
858  }
859  continue;
860  }
861  // check the feasibility of retransmitting on the same RBGs
862  // translate the DCI to Spectrum framework
863  std::vector <int> dciRbg;
864  uint32_t mask = 0x1;
865  NS_LOG_INFO ("Original RBGs " << dci.m_rbBitmap << " rnti " << dci.m_rnti);
866  for (int j = 0; j < 32; j++)
867  {
868  if (((dci.m_rbBitmap & mask) >> j) == 1)
869  {
870  dciRbg.push_back (j);
871  NS_LOG_INFO ("\t" << j);
872  }
873  mask = (mask << 1);
874  }
875  bool free = true;
876  for (uint8_t j = 0; j < dciRbg.size (); j++)
877  {
878  if (rbgMap.at (dciRbg.at (j)) == true)
879  {
880  free = false;
881  break;
882  }
883  }
884  if (free)
885  {
886  // use the same RBGs for the retx
887  // reserve RBGs
888  for (uint8_t j = 0; j < dciRbg.size (); j++)
889  {
890  rbgMap.at (dciRbg.at (j)) = true;
891  NS_LOG_INFO ("RBG " << dciRbg.at (j) << " assigned");
892  rbgAllocatedNum++;
893  }
894 
895  NS_LOG_INFO (this << " Send retx in the same RBGs");
896  }
897  else
898  {
899  // find RBGs for sending HARQ retx
900  uint8_t j = 0;
901  uint8_t rbgId = (dciRbg.at (dciRbg.size () - 1) + 1) % rbgNum;
902  uint8_t startRbg = dciRbg.at (dciRbg.size () - 1);
903  std::vector <bool> rbgMapCopy = rbgMap;
904  while ((j < dciRbg.size ())&&(startRbg != rbgId))
905  {
906  if (rbgMapCopy.at (rbgId) == false)
907  {
908  rbgMapCopy.at (rbgId) = true;
909  dciRbg.at (j) = rbgId;
910  j++;
911  }
912  rbgId++;
913  }
914  if (j == dciRbg.size ())
915  {
916  // find new RBGs -> update DCI map
917  uint32_t rbgMask = 0;
918  for (uint16_t k = 0; k < dciRbg.size (); k++)
919  {
920  rbgMask = rbgMask + (0x1 << dciRbg.at (k));
921  rbgAllocatedNum++;
922  }
923  dci.m_rbBitmap = rbgMask;
924  rbgMap = rbgMapCopy;
925  NS_LOG_INFO (this << " Move retx in RBGs " << dciRbg.size ());
926  }
927  else
928  {
929  // HARQ retx cannot be performed on this TTI -> store it
930  dlInfoListUntxed.push_back (params.m_dlInfoList.at (i));
931  NS_LOG_INFO (this << " No resource for this retx -> buffer it");
932  }
933  }
934  // retrieve RLC PDU list for retx TBsize and update DCI
936  std::map <uint16_t, DlHarqRlcPduListBuffer_t>::iterator itRlcPdu = m_dlHarqProcessesRlcPduListBuffer.find (rnti);
937  if (itRlcPdu == m_dlHarqProcessesRlcPduListBuffer.end ())
938  {
939  NS_FATAL_ERROR ("Unable to find RlcPdcList in HARQ buffer for RNTI " << rnti);
940  }
941  for (uint8_t j = 0; j < nLayers; j++)
942  {
943  if (retx.at (j))
944  {
945  if (j >= dci.m_ndi.size ())
946  {
947  // for avoiding errors in MIMO transient phases
948  dci.m_ndi.push_back (0);
949  dci.m_rv.push_back (0);
950  dci.m_mcs.push_back (0);
951  dci.m_tbsSize.push_back (0);
952  NS_LOG_INFO (this << " layer " << (uint16_t)j << " no txed (MIMO transition)");
953  }
954  else
955  {
956  dci.m_ndi.at (j) = 0;
957  dci.m_rv.at (j)++;
958  (*itHarq).second.at (harqId).m_rv.at (j)++;
959  NS_LOG_INFO (this << " layer " << (uint16_t)j << " RV " << (uint16_t)dci.m_rv.at (j));
960  }
961  }
962  else
963  {
964  // empty TB of layer j
965  dci.m_ndi.at (j) = 0;
966  dci.m_rv.at (j) = 0;
967  dci.m_mcs.at (j) = 0;
968  dci.m_tbsSize.at (j) = 0;
969  NS_LOG_INFO (this << " layer " << (uint16_t)j << " no retx");
970  }
971  }
972  for (uint16_t k = 0; k < (*itRlcPdu).second.at (0).at (dci.m_harqProcess).size (); k++)
973  {
974  std::vector <struct RlcPduListElement_s> rlcPduListPerLc;
975  for (uint8_t j = 0; j < nLayers; j++)
976  {
977  if (retx.at (j))
978  {
979  if (j < dci.m_ndi.size ())
980  {
981  rlcPduListPerLc.push_back ((*itRlcPdu).second.at (j).at (dci.m_harqProcess).at (k));
982  }
983  }
984  }
985 
986  if (rlcPduListPerLc.size () > 0)
987  {
988  newEl.m_rlcPduList.push_back (rlcPduListPerLc);
989  }
990  }
991  newEl.m_rnti = rnti;
992  newEl.m_dci = dci;
993  (*itHarq).second.at (harqId).m_rv = dci.m_rv;
994  // refresh timer
995  std::map <uint16_t, DlHarqProcessesTimer_t>::iterator itHarqTimer = m_dlHarqProcessesTimer.find (rnti);
996  if (itHarqTimer== m_dlHarqProcessesTimer.end ())
997  {
998  NS_FATAL_ERROR ("Unable to find HARQ timer for RNTI " << (uint16_t)rnti);
999  }
1000  (*itHarqTimer).second.at (harqId) = 0;
1001  ret.m_buildDataList.push_back (newEl);
1002  rntiAllocated.insert (rnti);
1003  }
1004  else
1005  {
1006  // update HARQ process status
1007  NS_LOG_INFO (this << " HARQ received ACK for UE " << m_dlInfoListBuffered.at (i).m_rnti);
1008  std::map <uint16_t, DlHarqProcessesStatus_t>::iterator it = m_dlHarqProcessesStatus.find (m_dlInfoListBuffered.at (i).m_rnti);
1009  if (it == m_dlHarqProcessesStatus.end ())
1010  {
1011  NS_FATAL_ERROR ("No info find in HARQ buffer for UE " << m_dlInfoListBuffered.at (i).m_rnti);
1012  }
1013  (*it).second.at (m_dlInfoListBuffered.at (i).m_harqProcessId) = 0;
1014  std::map <uint16_t, DlHarqRlcPduListBuffer_t>::iterator itRlcPdu = m_dlHarqProcessesRlcPduListBuffer.find (m_dlInfoListBuffered.at (i).m_rnti);
1015  if (itRlcPdu == m_dlHarqProcessesRlcPduListBuffer.end ())
1016  {
1017  NS_FATAL_ERROR ("Unable to find RlcPdcList in HARQ buffer for RNTI " << m_dlInfoListBuffered.at (i).m_rnti);
1018  }
1019  for (uint16_t k = 0; k < (*itRlcPdu).second.size (); k++)
1020  {
1021  (*itRlcPdu).second.at (k).at (m_dlInfoListBuffered.at (i).m_harqProcessId).clear ();
1022  }
1023  }
1024  }
1025  m_dlInfoListBuffered.clear ();
1026  m_dlInfoListBuffered = dlInfoListUntxed;
1027 
1028  if (rbgAllocatedNum == rbgNum)
1029  {
1030  // all the RBGs are already allocated -> exit
1031  if ((ret.m_buildDataList.size () > 0) || (ret.m_buildRarList.size () > 0))
1032  {
1034  }
1035  return;
1036  }
1037 
1038 
1039  std::map <uint16_t, pssFlowPerf_t>::iterator it;
1040  std::map <uint16_t, pssFlowPerf_t> tdUeSet; // the result of TD scheduler
1041 
1042  // schedulability check
1043  std::map <uint16_t, pssFlowPerf_t> ueSet;
1044  for (it = m_flowStatsDl.begin (); it != m_flowStatsDl.end (); it++)
1045  {
1046  if( LcActivePerFlow ((*it).first) > 0 )
1047  {
1048  ueSet.insert(std::pair <uint16_t, pssFlowPerf_t> ((*it).first, (*it).second));
1049  }
1050  }
1051 
1052  if (ueSet.size() != 0)
1053  { // has data in RLC buffer
1054 
1055  // Time Domain scheduler
1056  std::vector <std::pair<double, uint16_t> > ueSet1;
1057  std::vector <std::pair<double,uint16_t> > ueSet2;
1058  for (it = ueSet.begin (); it != ueSet.end (); it++)
1059  {
1060  std::set <uint16_t>::iterator itRnti = rntiAllocated.find ((*it).first);
1061  if ((itRnti != rntiAllocated.end ())||(!HarqProcessAvailability ((*it).first)))
1062  {
1063  // UE already allocated for HARQ or without HARQ process available -> drop it
1064  if (itRnti != rntiAllocated.end ())
1065  {
1066  NS_LOG_DEBUG (this << " RNTI discared for HARQ tx" << (uint16_t)(*it).first);
1067  }
1068  if (!HarqProcessAvailability ((*it).first))
1069  {
1070  NS_LOG_DEBUG (this << " RNTI discared for HARQ id" << (uint16_t)(*it).first);
1071  }
1072  continue;
1073  }
1074 
1075  double metric = 0.0;
1076  if ((*it).second.lastAveragedThroughput < (*it).second.targetThroughput )
1077  {
1078  // calculate TD BET metric
1079  metric = 1 / (*it).second.lastAveragedThroughput;
1080  ueSet1.push_back(std::pair<double, uint16_t> (metric, (*it).first));
1081  }
1082  else
1083  {
1084  // calculate TD PF metric
1085  std::map <uint16_t,uint8_t>::iterator itCqi;
1086  itCqi = m_p10CqiRxed.find ((*it).first);
1087  std::map <uint16_t,uint8_t>::iterator itTxMode;
1088  itTxMode = m_uesTxMode.find ((*it).first);
1089  if (itTxMode == m_uesTxMode.end())
1090  {
1091  NS_FATAL_ERROR ("No Transmission Mode info on user " << (*it).first);
1092  }
1093  int nLayer = TransmissionModesLayers::TxMode2LayerNum ((*itTxMode).second);
1094  uint8_t wbCqi = 0;
1095  if (itCqi == m_p10CqiRxed.end())
1096  {
1097  wbCqi = 1; // start with lowest value
1098  }
1099  else
1100  {
1101  wbCqi = (*itCqi).second;
1102  }
1103 
1104  if (wbCqi > 0)
1105  {
1106  if (LcActivePerFlow ((*it).first) > 0)
1107  {
1108  // this UE has data to transmit
1109  double achievableRate = 0.0;
1110  for (uint8_t k = 0; k < nLayer; k++)
1111  {
1112  uint8_t mcs = 0;
1113  mcs = m_amc->GetMcsFromCqi (wbCqi);
1114  achievableRate += ((m_amc->GetTbSizeFromMcs (mcs, rbgSize) / 8) / 0.001); // = TB size / TTI
1115  }
1116 
1117  metric = achievableRate / (*it).second.lastAveragedThroughput;
1118  }
1119  } // end of wbCqi
1120 
1121  ueSet2.push_back(std::pair<double, uint16_t> (metric, (*it).first));
1122  }
1123  }// end of ueSet
1124 
1125 
1126  if (ueSet1.size () != 0 || ueSet2.size () != 0)
1127  {
1128  // sorting UE in ueSet1 and ueSet1 in descending order based on their metric value
1129  std::sort (ueSet1.rbegin (), ueSet1.rend ());
1130  std::sort (ueSet2.rbegin (), ueSet2.rend ());
1131 
1132  // select UE set for frequency domain scheduler
1133  uint32_t nMux;
1134  if ( m_nMux > 0)
1135  nMux = m_nMux;
1136  else
1137  {
1138  // select half number of UE
1139  if (ueSet1.size() + ueSet2.size() <=2 )
1140  nMux = 1;
1141  else
1142  nMux = (int)((ueSet1.size() + ueSet2.size()) / 2) ; // TD scheduler only transfers half selected UE per RTT to TD scheduler
1143  }
1144  for (it = m_flowStatsDl.begin (); it != m_flowStatsDl.end (); it--)
1145  {
1146  std::vector <std::pair<double, uint16_t> >::iterator itSet;
1147  for (itSet = ueSet1.begin (); itSet != ueSet1.end () && nMux != 0; itSet++)
1148  {
1149  std::map <uint16_t, pssFlowPerf_t>::iterator itUe;
1150  itUe = m_flowStatsDl.find((*itSet).second);
1151  tdUeSet.insert(std::pair<uint16_t, pssFlowPerf_t> ( (*itUe).first, (*itUe).second ) );
1152  nMux--;
1153  }
1154 
1155  if (nMux == 0)
1156  break;
1157 
1158  for (itSet = ueSet2.begin (); itSet != ueSet2.end () && nMux != 0; itSet++)
1159  {
1160  std::map <uint16_t, pssFlowPerf_t>::iterator itUe;
1161  itUe = m_flowStatsDl.find((*itSet).second);
1162  tdUeSet.insert(std::pair<uint16_t, pssFlowPerf_t> ( (*itUe).first, (*itUe).second ) );
1163  nMux--;
1164  }
1165 
1166  if (nMux == 0)
1167  break;
1168 
1169  } // end of m_flowStatsDl
1170 
1171 
1172  if ( m_fdSchedulerType.compare("CoItA") == 0)
1173  {
1174  // FD scheduler: Carrier over Interference to Average (CoItA)
1175  std::map < uint16_t, uint8_t > sbCqiSum;
1176  for (it = tdUeSet.begin (); it != tdUeSet.end (); it++)
1177  {
1178  uint8_t sum = 0;
1179  for (int i = 0; i < rbgNum; i++)
1180  {
1181  std::map <uint16_t,SbMeasResult_s>::iterator itCqi;
1182  itCqi = m_a30CqiRxed.find ((*it).first);
1183  std::map <uint16_t,uint8_t>::iterator itTxMode;
1184  itTxMode = m_uesTxMode.find ((*it).first);
1185  if (itTxMode == m_uesTxMode.end ())
1186  {
1187  NS_FATAL_ERROR ("No Transmission Mode info on user " << (*it).first);
1188  }
1189  int nLayer = TransmissionModesLayers::TxMode2LayerNum ((*itTxMode).second);
1190  std::vector <uint8_t> sbCqis;
1191  if (itCqi == m_a30CqiRxed.end ())
1192  {
1193  for (uint8_t k = 0; k < nLayer; k++)
1194  {
1195  sbCqis.push_back (1); // start with lowest value
1196  }
1197  }
1198  else
1199  {
1200  sbCqis = (*itCqi).second.m_higherLayerSelected.at (i).m_sbCqi;
1201  }
1202 
1203  uint8_t cqi1 = sbCqis.at (0);
1204  uint8_t cqi2 = 1;
1205  if (sbCqis.size () > 1)
1206  {
1207  cqi2 = sbCqis.at (1);
1208  }
1209 
1210  uint8_t sbCqi;
1211  if ((cqi1 > 0)||(cqi2 > 0)) // CQI == 0 means "out of range" (see table 7.2.3-1 of 36.213)
1212  {
1213  for (uint8_t k = 0; k < nLayer; k++)
1214  {
1215  if (sbCqis.size () > k)
1216  {
1217  sbCqi = sbCqis.at(k);
1218  }
1219  else
1220  {
1221  // no info on this subband
1222  sbCqi = 0;
1223  }
1224  sum += sbCqi;
1225  }
1226  } // end if cqi
1227  }// end of rbgNum
1228 
1229  sbCqiSum.insert (std::pair<uint16_t, uint8_t> ((*it).first, sum));
1230  }// end tdUeSet
1231 
1232  for (int i = 0; i < rbgNum; i++)
1233  {
1234  if (rbgMap.at (i) == true)
1235  continue;
1236 
1237  std::map <uint16_t, pssFlowPerf_t>::iterator itMax = tdUeSet.end ();
1238  double metricMax = 0.0;
1239  for (it = tdUeSet.begin (); it != tdUeSet.end (); it++)
1240  {
1241  // calculate PF weigth
1242  double weight = (*it).second.targetThroughput / (*it).second.lastAveragedThroughput;
1243  if (weight < 1.0)
1244  weight = 1.0;
1245 
1246  std::map < uint16_t, uint8_t>::iterator itSbCqiSum;
1247  itSbCqiSum = sbCqiSum.find((*it).first);
1248 
1249  std::map <uint16_t,SbMeasResult_s>::iterator itCqi;
1250  itCqi = m_a30CqiRxed.find ((*it).first);
1251  std::map <uint16_t,uint8_t>::iterator itTxMode;
1252  itTxMode = m_uesTxMode.find ((*it).first);
1253  if (itTxMode == m_uesTxMode.end())
1254  {
1255  NS_FATAL_ERROR ("No Transmission Mode info on user " << (*it).first);
1256  }
1257  int nLayer = TransmissionModesLayers::TxMode2LayerNum ((*itTxMode).second);
1258  std::vector <uint8_t> sbCqis;
1259  if (itCqi == m_a30CqiRxed.end ())
1260  {
1261  for (uint8_t k = 0; k < nLayer; k++)
1262  {
1263  sbCqis.push_back (1); // start with lowest value
1264  }
1265  }
1266  else
1267  {
1268  sbCqis = (*itCqi).second.m_higherLayerSelected.at (i).m_sbCqi;
1269  }
1270 
1271  uint8_t cqi1 = sbCqis.at( 0);
1272  uint8_t cqi2 = 1;
1273  if (sbCqis.size () > 1)
1274  {
1275  cqi2 = sbCqis.at(1);
1276  }
1277 
1278  uint8_t sbCqi;
1279  double colMetric = 0.0;
1280  if ((cqi1 > 0)||(cqi2 > 0)) // CQI == 0 means "out of range" (see table 7.2.3-1 of 36.213)
1281  {
1282  for (uint8_t k = 0; k < nLayer; k++)
1283  {
1284  if (sbCqis.size () > k)
1285  {
1286  sbCqi = sbCqis.at(k);
1287  }
1288  else
1289  {
1290  // no info on this subband
1291  sbCqi = 0;
1292  }
1293  colMetric += (double)sbCqi / (double)(*itSbCqiSum).second;
1294  }
1295  } // end if cqi
1296 
1297  double metric = 0.0;
1298  if (colMetric != 0)
1299  metric= weight * colMetric;
1300  else
1301  metric = 1;
1302 
1303  if (metric > metricMax )
1304  {
1305  metricMax = metric;
1306  itMax = it;
1307  }
1308  } // end of tdUeSet
1309 
1310  if (itMax == m_flowStatsDl.end ())
1311  {
1312  // no UE available for downlink
1313  return;
1314  }
1315  else
1316  {
1317  allocationMap[(*itMax).first].push_back (i);
1318  rbgMap.at (i) = true;
1319  }
1320  }// end of rbgNum
1321 
1322  }// end of CoIta
1323 
1324 
1325  if ( m_fdSchedulerType.compare("PFsch") == 0)
1326  {
1327  // FD scheduler: Proportional Fair scheduled (PFsch)
1328  for (int i = 0; i < rbgNum; i++)
1329  {
1330  if (rbgMap.at (i) == true)
1331  continue;
1332 
1333  std::map <uint16_t, pssFlowPerf_t>::iterator itMax = tdUeSet.end ();
1334  double metricMax = 0.0;
1335  for (it = tdUeSet.begin (); it != tdUeSet.end (); it++)
1336  {
1337  // calculate PF weigth
1338  double weight = (*it).second.targetThroughput / (*it).second.lastAveragedThroughput;
1339  if (weight < 1.0)
1340  weight = 1.0;
1341 
1342  std::map <uint16_t,SbMeasResult_s>::iterator itCqi;
1343  itCqi = m_a30CqiRxed.find ((*it).first);
1344  std::map <uint16_t,uint8_t>::iterator itTxMode;
1345  itTxMode = m_uesTxMode.find ((*it).first);
1346  if (itTxMode == m_uesTxMode.end())
1347  {
1348  NS_FATAL_ERROR ("No Transmission Mode info on user " << (*it).first);
1349  }
1350  int nLayer = TransmissionModesLayers::TxMode2LayerNum ((*itTxMode).second);
1351  std::vector <uint8_t> sbCqis;
1352  if (itCqi == m_a30CqiRxed.end ())
1353  {
1354  for (uint8_t k = 0; k < nLayer; k++)
1355  {
1356  sbCqis.push_back (1); // start with lowest value
1357  }
1358  }
1359  else
1360  {
1361  sbCqis = (*itCqi).second.m_higherLayerSelected.at (i).m_sbCqi;
1362  }
1363 
1364  uint8_t cqi1 = sbCqis.at(0);
1365  uint8_t cqi2 = 1;
1366  if (sbCqis.size () > 1)
1367  {
1368  cqi2 = sbCqis.at(1);
1369  }
1370 
1371  double schMetric = 0.0;
1372  if ((cqi1 > 0)||(cqi2 > 0)) // CQI == 0 means "out of range" (see table 7.2.3-1 of 36.213)
1373  {
1374  double achievableRate = 0.0;
1375  for (uint8_t k = 0; k < nLayer; k++)
1376  {
1377  uint8_t mcs = 0;
1378  if (sbCqis.size () > k)
1379  {
1380  mcs = m_amc->GetMcsFromCqi (sbCqis.at (k));
1381  }
1382  else
1383  {
1384  // no info on this subband -> worst MCS
1385  mcs = 0;
1386  }
1387  achievableRate += ((m_amc->GetTbSizeFromMcs (mcs, rbgSize) / 8) / 0.001); // = TB size / TTI
1388  }
1389  schMetric = achievableRate / (*it).second.secondLastAveragedThroughput;
1390  } // end if cqi
1391 
1392  double metric = 0.0;
1393  metric= weight * schMetric;
1394 
1395  if (metric > metricMax )
1396  {
1397  metricMax = metric;
1398  itMax = it;
1399  }
1400  } // end of tdUeSet
1401 
1402  if (itMax == m_flowStatsDl.end ())
1403  {
1404  // no UE available for downlink
1405  return;
1406  }
1407  else
1408  {
1409  allocationMap[(*itMax).first].push_back (i);
1410  rbgMap.at (i) = true;
1411  }
1412 
1413  }// end of rbgNum
1414 
1415  } // end of PFsch
1416 
1417  } // end if ueSet1 || ueSet2
1418 
1419  } // end if ueSet
1420 
1421 
1422 
1423  // reset TTI stats of users
1424  std::map <uint16_t, pssFlowPerf_t>::iterator itStats;
1425  for (itStats = m_flowStatsDl.begin (); itStats != m_flowStatsDl.end (); itStats++)
1426  {
1427  (*itStats).second.lastTtiBytesTransmitted = 0;
1428  }
1429 
1430  // generate the transmission opportunities by grouping the RBGs of the same RNTI and
1431  // creating the correspondent DCIs
1432  std::map <uint16_t, std::vector <uint16_t> >::iterator itMap = allocationMap.begin ();
1433  while (itMap != allocationMap.end ())
1434  {
1435  // create new BuildDataListElement_s for this LC
1436  BuildDataListElement_s newEl;
1437  newEl.m_rnti = (*itMap).first;
1438  // create the DlDciListElement_s
1439  DlDciListElement_s newDci;
1440  newDci.m_rnti = (*itMap).first;
1441  newDci.m_harqProcess = UpdateHarqProcessId ((*itMap).first);
1442 
1443  uint16_t lcActives = LcActivePerFlow ((*itMap).first);
1444  NS_LOG_INFO (this << "Allocate user " << newEl.m_rnti << " rbg " << lcActives);
1445  if (lcActives == 0)
1446  {
1447  // Set to max value, to avoid divide by 0 below
1448  lcActives = (uint16_t)65535; // UINT16_MAX;
1449  }
1450  uint16_t RgbPerRnti = (*itMap).second.size ();
1451  std::map <uint16_t,SbMeasResult_s>::iterator itCqi;
1452  itCqi = m_a30CqiRxed.find ((*itMap).first);
1453  std::map <uint16_t,uint8_t>::iterator itTxMode;
1454  itTxMode = m_uesTxMode.find ((*itMap).first);
1455  if (itTxMode == m_uesTxMode.end ())
1456  {
1457  NS_FATAL_ERROR ("No Transmission Mode info on user " << (*itMap).first);
1458  }
1459  int nLayer = TransmissionModesLayers::TxMode2LayerNum ((*itTxMode).second);
1460  std::vector <uint8_t> worstCqi (2, 15);
1461  if (itCqi != m_a30CqiRxed.end ())
1462  {
1463  for (uint16_t k = 0; k < (*itMap).second.size (); k++)
1464  {
1465  if ((*itCqi).second.m_higherLayerSelected.size () > (*itMap).second.at (k))
1466  {
1467  NS_LOG_INFO (this << " RBG " << (*itMap).second.at (k) << " CQI " << (uint16_t)((*itCqi).second.m_higherLayerSelected.at ((*itMap).second.at (k)).m_sbCqi.at (0)) );
1468  for (uint8_t j = 0; j < nLayer; j++)
1469  {
1470  if ((*itCqi).second.m_higherLayerSelected.at ((*itMap).second.at (k)).m_sbCqi.size () > j)
1471  {
1472  if (((*itCqi).second.m_higherLayerSelected.at ((*itMap).second.at (k)).m_sbCqi.at (j)) < worstCqi.at (j))
1473  {
1474  worstCqi.at (j) = ((*itCqi).second.m_higherLayerSelected.at ((*itMap).second.at (k)).m_sbCqi.at (j));
1475  }
1476  }
1477  else
1478  {
1479  // no CQI for this layer of this suband -> worst one
1480  worstCqi.at (j) = 1;
1481  }
1482  }
1483  }
1484  else
1485  {
1486  for (uint8_t j = 0; j < nLayer; j++)
1487  {
1488  worstCqi.at (j) = 1; // try with lowest MCS in RBG with no info on channel
1489  }
1490  }
1491  }
1492  }
1493  else
1494  {
1495  for (uint8_t j = 0; j < nLayer; j++)
1496  {
1497  worstCqi.at (j) = 1; // try with lowest MCS in RBG with no info on channel
1498  }
1499  }
1500  for (uint8_t j = 0; j < nLayer; j++)
1501  {
1502  NS_LOG_INFO (this << " Layer " << (uint16_t)j << " CQI selected " << (uint16_t)worstCqi.at (j));
1503  }
1504  uint32_t bytesTxed = 0;
1505  for (uint8_t j = 0; j < nLayer; j++)
1506  {
1507  newDci.m_mcs.push_back (m_amc->GetMcsFromCqi (worstCqi.at (j)));
1508  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)
1509  newDci.m_tbsSize.push_back (tbSize);
1510  NS_LOG_INFO (this << " Layer " << (uint16_t)j << " MCS selected" << m_amc->GetMcsFromCqi (worstCqi.at (j)));
1511  bytesTxed += tbSize;
1512  }
1513 
1514  newDci.m_resAlloc = 0; // only allocation type 0 at this stage
1515  newDci.m_rbBitmap = 0; // TBD (32 bit bitmap see 7.1.6 of 36.213)
1516  uint32_t rbgMask = 0;
1517  for (uint16_t k = 0; k < (*itMap).second.size (); k++)
1518  {
1519  rbgMask = rbgMask + (0x1 << (*itMap).second.at (k));
1520  NS_LOG_INFO (this << " Allocated RBG " << (*itMap).second.at (k));
1521  }
1522  newDci.m_rbBitmap = rbgMask; // (32 bit bitmap see 7.1.6 of 36.213)
1523 
1524  // create the rlc PDUs -> equally divide resources among actives LCs
1525  std::map <LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator itBufReq;
1526  for (itBufReq = m_rlcBufferReq.begin (); itBufReq != m_rlcBufferReq.end (); itBufReq++)
1527  {
1528  if (((*itBufReq).first.m_rnti == (*itMap).first)
1529  && (((*itBufReq).second.m_rlcTransmissionQueueSize > 0)
1530  || ((*itBufReq).second.m_rlcRetransmissionQueueSize > 0)
1531  || ((*itBufReq).second.m_rlcStatusPduSize > 0) ))
1532  {
1533  std::vector <struct RlcPduListElement_s> newRlcPduLe;
1534  for (uint8_t j = 0; j < nLayer; j++)
1535  {
1536  RlcPduListElement_s newRlcEl;
1537  newRlcEl.m_logicalChannelIdentity = (*itBufReq).first.m_lcId;
1538  newRlcEl.m_size = newDci.m_tbsSize.at (j) / lcActives;
1539  NS_LOG_INFO (this << " LCID " << (uint32_t) newRlcEl.m_logicalChannelIdentity << " size " << newRlcEl.m_size << " layer " << (uint16_t)j);
1540  newRlcPduLe.push_back (newRlcEl);
1541  UpdateDlRlcBufferInfo (newDci.m_rnti, newRlcEl.m_logicalChannelIdentity, newRlcEl.m_size);
1542  if (m_harqOn == true)
1543  {
1544  // store RLC PDU list for HARQ
1545  std::map <uint16_t, DlHarqRlcPduListBuffer_t>::iterator itRlcPdu = m_dlHarqProcessesRlcPduListBuffer.find ((*itMap).first);
1546  if (itRlcPdu == m_dlHarqProcessesRlcPduListBuffer.end ())
1547  {
1548  NS_FATAL_ERROR ("Unable to find RlcPdcList in HARQ buffer for RNTI " << (*itMap).first);
1549  }
1550  (*itRlcPdu).second.at (j).at (newDci.m_harqProcess).push_back (newRlcEl);
1551  }
1552  }
1553  newEl.m_rlcPduList.push_back (newRlcPduLe);
1554  }
1555  if ((*itBufReq).first.m_rnti > (*itMap).first)
1556  {
1557  break;
1558  }
1559  }
1560  for (uint8_t j = 0; j < nLayer; j++)
1561  {
1562  newDci.m_ndi.push_back (1);
1563  newDci.m_rv.push_back (0);
1564  }
1565 
1566  newEl.m_dci = newDci;
1567 
1568  if (m_harqOn == true)
1569  {
1570  // store DCI for HARQ
1571  std::map <uint16_t, DlHarqProcessesDciBuffer_t>::iterator itDci = m_dlHarqProcessesDciBuffer.find (newEl.m_rnti);
1572  if (itDci == m_dlHarqProcessesDciBuffer.end ())
1573  {
1574  NS_FATAL_ERROR ("Unable to find RNTI entry in DCI HARQ buffer for RNTI " << newEl.m_rnti);
1575  }
1576  (*itDci).second.at (newDci.m_harqProcess) = newDci;
1577  // refresh timer
1578  std::map <uint16_t, DlHarqProcessesTimer_t>::iterator itHarqTimer = m_dlHarqProcessesTimer.find (newEl.m_rnti);
1579  if (itHarqTimer== m_dlHarqProcessesTimer.end ())
1580  {
1581  NS_FATAL_ERROR ("Unable to find HARQ timer for RNTI " << (uint16_t)newEl.m_rnti);
1582  }
1583  (*itHarqTimer).second.at (newDci.m_harqProcess) = 0;
1584  }
1585 
1586  // ...more parameters -> ingored in this version
1587 
1588  ret.m_buildDataList.push_back (newEl);
1589  // update UE stats
1590  std::map <uint16_t, pssFlowPerf_t>::iterator it;
1591  it = m_flowStatsDl.find ((*itMap).first);
1592  if (it != m_flowStatsDl.end ())
1593  {
1594  (*it).second.lastTtiBytesTransmitted = bytesTxed;
1595  NS_LOG_INFO (this << " UE total bytes txed " << (*it).second.lastTtiBytesTransmitted);
1596 
1597 
1598  }
1599  else
1600  {
1601  NS_FATAL_ERROR (this << " No Stats for this allocated UE");
1602  }
1603 
1604  itMap++;
1605  } // end while allocation
1606  ret.m_nrOfPdcchOfdmSymbols = 1;
1607 
1608 
1609  // update UEs stats
1610  NS_LOG_INFO (this << " Update UEs statistics");
1611  for (itStats = m_flowStatsDl.begin (); itStats != m_flowStatsDl.end (); itStats++)
1612  {
1613  std::map <uint16_t, pssFlowPerf_t>::iterator itUeScheduleted = tdUeSet.end();
1614  itUeScheduleted = tdUeSet.find((*itStats).first);
1615  if (itUeScheduleted != tdUeSet.end())
1616  {
1617  (*itStats).second.secondLastAveragedThroughput = ((1.0 - (1 / m_timeWindow)) * (*itStats).second.secondLastAveragedThroughput) + ((1 / m_timeWindow) * (double)((*itStats).second.lastTtiBytesTransmitted / 0.001));
1618  }
1619 
1620  (*itStats).second.totalBytesTransmitted += (*itStats).second.lastTtiBytesTransmitted;
1621  // update average throughput (see eq. 12.3 of Sec 12.3.1.2 of LTE – The UMTS Long Term Evolution, Ed Wiley)
1622  (*itStats).second.lastAveragedThroughput = ((1.0 - (1.0 / m_timeWindow)) * (*itStats).second.lastAveragedThroughput) + ((1.0 / m_timeWindow) * (double)((*itStats).second.lastTtiBytesTransmitted / 0.001));
1623  (*itStats).second.lastTtiBytesTransmitted = 0;
1624  }
1625 
1626 
1628 
1629 
1630  return;
1631 }
1632 
1633 void
1635 {
1636  NS_LOG_FUNCTION (this);
1637 
1638  m_rachList = params.m_rachList;
1639 
1640  return;
1641 }
1642 
1643 void
1645 {
1646  NS_LOG_FUNCTION (this);
1647 
1648  for (unsigned int i = 0; i < params.m_cqiList.size (); i++)
1649  {
1650  if ( params.m_cqiList.at (i).m_cqiType == CqiListElement_s::P10 )
1651  {
1652  // wideband CQI reporting
1653  std::map <uint16_t,uint8_t>::iterator it;
1654  uint16_t rnti = params.m_cqiList.at (i).m_rnti;
1655  it = m_p10CqiRxed.find (rnti);
1656  if (it == m_p10CqiRxed.end ())
1657  {
1658  // create the new entry
1659  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)
1660  // generate correspondent timer
1661  m_p10CqiTimers.insert ( std::pair<uint16_t, uint32_t > (rnti, m_cqiTimersThreshold));
1662  }
1663  else
1664  {
1665  // update the CQI value and refresh correspondent timer
1666  (*it).second = params.m_cqiList.at (i).m_wbCqi.at (0);
1667  // update correspondent timer
1668  std::map <uint16_t,uint32_t>::iterator itTimers;
1669  itTimers = m_p10CqiTimers.find (rnti);
1670  (*itTimers).second = m_cqiTimersThreshold;
1671  }
1672  }
1673  else if ( params.m_cqiList.at (i).m_cqiType == CqiListElement_s::A30 )
1674  {
1675  // subband CQI reporting high layer configured
1676  std::map <uint16_t,SbMeasResult_s>::iterator it;
1677  uint16_t rnti = params.m_cqiList.at (i).m_rnti;
1678  it = m_a30CqiRxed.find (rnti);
1679  if (it == m_a30CqiRxed.end ())
1680  {
1681  // create the new entry
1682  m_a30CqiRxed.insert ( std::pair<uint16_t, SbMeasResult_s > (rnti, params.m_cqiList.at (i).m_sbMeasResult) );
1683  m_a30CqiTimers.insert ( std::pair<uint16_t, uint32_t > (rnti, m_cqiTimersThreshold));
1684  }
1685  else
1686  {
1687  // update the CQI value and refresh correspondent timer
1688  (*it).second = params.m_cqiList.at (i).m_sbMeasResult;
1689  std::map <uint16_t,uint32_t>::iterator itTimers;
1690  itTimers = m_a30CqiTimers.find (rnti);
1691  (*itTimers).second = m_cqiTimersThreshold;
1692  }
1693  }
1694  else
1695  {
1696  NS_LOG_ERROR (this << " CQI type unknown");
1697  }
1698  }
1699 
1700  return;
1701 }
1702 
1703 
1704 double
1705 PssFfMacScheduler::EstimateUlSinr (uint16_t rnti, uint16_t rb)
1706 {
1707  std::map <uint16_t, std::vector <double> >::iterator itCqi = m_ueCqi.find (rnti);
1708  if (itCqi == m_ueCqi.end ())
1709  {
1710  // no cqi info about this UE
1711  return (NO_SINR);
1712 
1713  }
1714  else
1715  {
1716  // take the average SINR value among the available
1717  double sinrSum = 0;
1718  int sinrNum = 0;
1719  for (uint32_t i = 0; i < m_cschedCellConfig.m_ulBandwidth; i++)
1720  {
1721  double sinr = (*itCqi).second.at (i);
1722  if (sinr != NO_SINR)
1723  {
1724  sinrSum += sinr;
1725  sinrNum++;
1726  }
1727  }
1728  double estimatedSinr = (sinrNum > 0) ? (sinrSum / sinrNum) : DBL_MAX;
1729  // store the value
1730  (*itCqi).second.at (rb) = estimatedSinr;
1731  return (estimatedSinr);
1732  }
1733 }
1734 
1735 void
1737 {
1738  NS_LOG_FUNCTION (this << " UL - Frame no. " << (params.m_sfnSf >> 4) << " subframe no. " << (0xF & params.m_sfnSf) << " size " << params.m_ulInfoList.size ());
1739 
1740  RefreshUlCqiMaps ();
1741 
1742  // Generate RBs map
1744  std::vector <bool> rbMap;
1745  uint16_t rbAllocatedNum = 0;
1746  std::set <uint16_t> rntiAllocated;
1747  std::vector <uint16_t> rbgAllocationMap;
1748  // update with RACH allocation map
1749  rbgAllocationMap = m_rachAllocationMap;
1750  //rbgAllocationMap.resize (m_cschedCellConfig.m_ulBandwidth, 0);
1751  m_rachAllocationMap.clear ();
1753 
1754  rbMap.resize (m_cschedCellConfig.m_ulBandwidth, false);
1755  // remove RACH allocation
1756  for (uint16_t i = 0; i < m_cschedCellConfig.m_ulBandwidth; i++)
1757  {
1758  if (rbgAllocationMap.at (i) != 0)
1759  {
1760  rbMap.at (i) = true;
1761  NS_LOG_DEBUG (this << " Allocated for RACH " << i);
1762  }
1763  }
1764 
1765 
1766  if (m_harqOn == true)
1767  {
1768  // Process UL HARQ feedback
1769  for (uint16_t i = 0; i < params.m_ulInfoList.size (); i++)
1770  {
1771  if (params.m_ulInfoList.at (i).m_receptionStatus == UlInfoListElement_s::NotOk)
1772  {
1773  // retx correspondent block: retrieve the UL-DCI
1774  uint16_t rnti = params.m_ulInfoList.at (i).m_rnti;
1775  std::map <uint16_t, uint8_t>::iterator itProcId = m_ulHarqCurrentProcessId.find (rnti);
1776  if (itProcId == m_ulHarqCurrentProcessId.end ())
1777  {
1778  NS_LOG_ERROR ("No info find in HARQ buffer for UE (might change eNB) " << rnti);
1779  }
1780  uint8_t harqId = (uint8_t)((*itProcId).second - HARQ_PERIOD) % HARQ_PROC_NUM;
1781  NS_LOG_INFO (this << " UL-HARQ retx RNTI " << rnti << " harqId " << (uint16_t)harqId << " i " << i << " size " << params.m_ulInfoList.size ());
1782  std::map <uint16_t, UlHarqProcessesDciBuffer_t>::iterator itHarq = m_ulHarqProcessesDciBuffer.find (rnti);
1783  if (itHarq == m_ulHarqProcessesDciBuffer.end ())
1784  {
1785  NS_LOG_ERROR ("No info find in HARQ buffer for UE (might change eNB) " << rnti);
1786  continue;
1787  }
1788  UlDciListElement_s dci = (*itHarq).second.at (harqId);
1789  std::map <uint16_t, UlHarqProcessesStatus_t>::iterator itStat = m_ulHarqProcessesStatus.find (rnti);
1790  if (itStat == m_ulHarqProcessesStatus.end ())
1791  {
1792  NS_LOG_ERROR ("No info find in HARQ buffer for UE (might change eNB) " << rnti);
1793  }
1794  if ((*itStat).second.at (harqId) >= 3)
1795  {
1796  NS_LOG_INFO ("Max number of retransmissions reached (UL)-> drop process");
1797  continue;
1798  }
1799  bool free = true;
1800  for (int j = dci.m_rbStart; j < dci.m_rbStart + dci.m_rbLen; j++)
1801  {
1802  if (rbMap.at (j) == true)
1803  {
1804  free = false;
1805  NS_LOG_INFO (this << " BUSY " << j);
1806  }
1807  }
1808  if (free)
1809  {
1810  // retx on the same RBs
1811  for (int j = dci.m_rbStart; j < dci.m_rbStart + dci.m_rbLen; j++)
1812  {
1813  rbMap.at (j) = true;
1814  rbgAllocationMap.at (j) = dci.m_rnti;
1815  NS_LOG_INFO ("\tRB " << j);
1816  rbAllocatedNum++;
1817  }
1818  NS_LOG_INFO (this << " Send retx in the same RBs " << (uint16_t)dci.m_rbStart << " to " << dci.m_rbStart + dci.m_rbLen << " RV " << (*itStat).second.at (harqId) + 1);
1819  }
1820  else
1821  {
1822  NS_LOG_INFO ("Cannot allocate retx due to RACH allocations for UE " << rnti);
1823  continue;
1824  }
1825  dci.m_ndi = 0;
1826  // Update HARQ buffers with new HarqId
1827  (*itStat).second.at ((*itProcId).second) = (*itStat).second.at (harqId) + 1;
1828  (*itStat).second.at (harqId) = 0;
1829  (*itHarq).second.at ((*itProcId).second) = dci;
1830  ret.m_dciList.push_back (dci);
1831  rntiAllocated.insert (dci.m_rnti);
1832  }
1833  else
1834  {
1835  NS_LOG_INFO (this << " HARQ-ACK feedback from RNTI " << params.m_ulInfoList.at (i).m_rnti);
1836  }
1837  }
1838  }
1839 
1840  std::map <uint16_t,uint32_t>::iterator it;
1841  int nflows = 0;
1842 
1843  for (it = m_ceBsrRxed.begin (); it != m_ceBsrRxed.end (); it++)
1844  {
1845  std::set <uint16_t>::iterator itRnti = rntiAllocated.find ((*it).first);
1846  // select UEs with queues not empty and not yet allocated for HARQ
1847  if (((*it).second > 0)&&(itRnti == rntiAllocated.end ()))
1848  {
1849  nflows++;
1850  }
1851  }
1852 
1853  if (nflows == 0)
1854  {
1855  if (ret.m_dciList.size () > 0)
1856  {
1857  m_allocationMaps.insert (std::pair <uint16_t, std::vector <uint16_t> > (params.m_sfnSf, rbgAllocationMap));
1859  }
1860 
1861  return; // no flows to be scheduled
1862  }
1863 
1864 
1865  // Divide the remaining resources equally among the active users starting from the subsequent one served last scheduling trigger
1866  uint16_t rbPerFlow = (m_cschedCellConfig.m_ulBandwidth) / (nflows + rntiAllocated.size ());
1867  if (rbPerFlow < 3)
1868  {
1869  rbPerFlow = 3; // at least 3 rbg per flow (till available resource) to ensure TxOpportunity >= 7 bytes
1870  }
1871  int rbAllocated = 0;
1872 
1873  std::map <uint16_t, pssFlowPerf_t>::iterator itStats;
1874  if (m_nextRntiUl != 0)
1875  {
1876  for (it = m_ceBsrRxed.begin (); it != m_ceBsrRxed.end (); it++)
1877  {
1878  if ((*it).first == m_nextRntiUl)
1879  {
1880  break;
1881  }
1882  }
1883  if (it == m_ceBsrRxed.end ())
1884  {
1885  NS_LOG_ERROR (this << " no user found");
1886  }
1887  }
1888  else
1889  {
1890  it = m_ceBsrRxed.begin ();
1891  m_nextRntiUl = (*it).first;
1892  }
1893  do
1894  {
1895  std::set <uint16_t>::iterator itRnti = rntiAllocated.find ((*it).first);
1896  if ((itRnti != rntiAllocated.end ())||((*it).second == 0))
1897  {
1898  // UE already allocated for UL-HARQ -> skip it
1899  NS_LOG_DEBUG (this << " UE already allocated in HARQ -> discared, RNTI " << (*it).first);
1900  it++;
1901  if (it == m_ceBsrRxed.end ())
1902  {
1903  // restart from the first
1904  it = m_ceBsrRxed.begin ();
1905  }
1906  continue;
1907  }
1908  if (rbAllocated + rbPerFlow - 1 > m_cschedCellConfig.m_ulBandwidth)
1909  {
1910  // limit to physical resources last resource assignment
1911  rbPerFlow = m_cschedCellConfig.m_ulBandwidth - rbAllocated;
1912  // at least 3 rbg per flow to ensure TxOpportunity >= 7 bytes
1913  if (rbPerFlow < 3)
1914  {
1915  // terminate allocation
1916  rbPerFlow = 0;
1917  }
1918  }
1919 
1920  UlDciListElement_s uldci;
1921  uldci.m_rnti = (*it).first;
1922  uldci.m_rbLen = rbPerFlow;
1923  bool allocated = false;
1924  NS_LOG_INFO (this << " RB Allocated " << rbAllocated << " rbPerFlow " << rbPerFlow << " flows " << nflows);
1925  while ((!allocated)&&((rbAllocated + rbPerFlow - m_cschedCellConfig.m_ulBandwidth) < 1) && (rbPerFlow != 0))
1926  {
1927  // check availability
1928  bool free = true;
1929  for (uint16_t j = rbAllocated; j < rbAllocated + rbPerFlow; j++)
1930  {
1931  if (rbMap.at (j) == true)
1932  {
1933  free = false;
1934  break;
1935  }
1936  }
1937  if (free)
1938  {
1939  uldci.m_rbStart = rbAllocated;
1940 
1941  for (uint16_t j = rbAllocated; j < rbAllocated + rbPerFlow; j++)
1942  {
1943  rbMap.at (j) = true;
1944  // store info on allocation for managing ul-cqi interpretation
1945  rbgAllocationMap.at (j) = (*it).first;
1946  }
1947  rbAllocated += rbPerFlow;
1948  allocated = true;
1949  break;
1950  }
1951  rbAllocated++;
1952  if (rbAllocated + rbPerFlow - 1 > m_cschedCellConfig.m_ulBandwidth)
1953  {
1954  // limit to physical resources last resource assignment
1955  rbPerFlow = m_cschedCellConfig.m_ulBandwidth - rbAllocated;
1956  // at least 3 rbg per flow to ensure TxOpportunity >= 7 bytes
1957  if (rbPerFlow < 3)
1958  {
1959  // terminate allocation
1960  rbPerFlow = 0;
1961  }
1962  }
1963  }
1964  if (!allocated)
1965  {
1966  // unable to allocate new resource: finish scheduling
1967  m_nextRntiUl = (*it).first;
1968  if (ret.m_dciList.size () > 0)
1969  {
1971  }
1972  m_allocationMaps.insert (std::pair <uint16_t, std::vector <uint16_t> > (params.m_sfnSf, rbgAllocationMap));
1973  return;
1974  }
1975 
1976 
1977 
1978  std::map <uint16_t, std::vector <double> >::iterator itCqi = m_ueCqi.find ((*it).first);
1979  int cqi = 0;
1980  if (itCqi == m_ueCqi.end ())
1981  {
1982  // no cqi info about this UE
1983  uldci.m_mcs = 0; // MCS 0 -> UL-AMC TBD
1984  }
1985  else
1986  {
1987  // take the lowest CQI value (worst RB)
1988  double minSinr = (*itCqi).second.at (uldci.m_rbStart);
1989  if (minSinr == NO_SINR)
1990  {
1991  minSinr = EstimateUlSinr ((*it).first, uldci.m_rbStart);
1992  }
1993  for (uint16_t i = uldci.m_rbStart; i < uldci.m_rbStart + uldci.m_rbLen; i++)
1994  {
1995  double sinr = (*itCqi).second.at (i);
1996  if (sinr == NO_SINR)
1997  {
1998  sinr = EstimateUlSinr ((*it).first, i);
1999  }
2000  if ((*itCqi).second.at (i) < minSinr)
2001  {
2002  minSinr = (*itCqi).second.at (i);
2003  }
2004  }
2005 
2006  // translate SINR -> cqi: WILD ACK: same as DL
2007  double s = log2 ( 1 + (
2008  std::pow (10, minSinr / 10 ) /
2009  ( (-std::log (5.0 * 0.00005 )) / 1.5) ));
2010  cqi = m_amc->GetCqiFromSpectralEfficiency (s);
2011  if (cqi == 0)
2012  {
2013  it++;
2014  if (it == m_ceBsrRxed.end ())
2015  {
2016  // restart from the first
2017  it = m_ceBsrRxed.begin ();
2018  }
2019  NS_LOG_DEBUG (this << " UE discared for CQI=0, RNTI " << uldci.m_rnti);
2020  // remove UE from allocation map
2021  for (uint16_t i = uldci.m_rbStart; i < uldci.m_rbStart + uldci.m_rbLen; i++)
2022  {
2023  rbgAllocationMap.at (i) = 0;
2024  }
2025  continue; // CQI == 0 means "out of range" (see table 7.2.3-1 of 36.213)
2026  }
2027  uldci.m_mcs = m_amc->GetMcsFromCqi (cqi);
2028  }
2029 
2030  uldci.m_tbSize = (m_amc->GetTbSizeFromMcs (uldci.m_mcs, rbPerFlow) / 8);
2031  UpdateUlRlcBufferInfo (uldci.m_rnti, uldci.m_tbSize);
2032  uldci.m_ndi = 1;
2033  uldci.m_cceIndex = 0;
2034  uldci.m_aggrLevel = 1;
2035  uldci.m_ueTxAntennaSelection = 3; // antenna selection OFF
2036  uldci.m_hopping = false;
2037  uldci.m_n2Dmrs = 0;
2038  uldci.m_tpc = 0; // no power control
2039  uldci.m_cqiRequest = false; // only period CQI at this stage
2040  uldci.m_ulIndex = 0; // TDD parameter
2041  uldci.m_dai = 1; // TDD parameter
2042  uldci.m_freqHopping = 0;
2043  uldci.m_pdcchPowerOffset = 0; // not used
2044  ret.m_dciList.push_back (uldci);
2045  // store DCI for HARQ_PERIOD
2046  uint8_t harqId = 0;
2047  if (m_harqOn == true)
2048  {
2049  std::map <uint16_t, uint8_t>::iterator itProcId;
2050  itProcId = m_ulHarqCurrentProcessId.find (uldci.m_rnti);
2051  if (itProcId == m_ulHarqCurrentProcessId.end ())
2052  {
2053  NS_FATAL_ERROR ("No info find in HARQ buffer for UE " << uldci.m_rnti);
2054  }
2055  harqId = (*itProcId).second;
2056  std::map <uint16_t, UlHarqProcessesDciBuffer_t>::iterator itDci = m_ulHarqProcessesDciBuffer.find (uldci.m_rnti);
2057  if (itDci == m_ulHarqProcessesDciBuffer.end ())
2058  {
2059  NS_FATAL_ERROR ("Unable to find RNTI entry in UL DCI HARQ buffer for RNTI " << uldci.m_rnti);
2060  }
2061  (*itDci).second.at (harqId) = uldci;
2062  }
2063 
2064  NS_LOG_INFO (this << " UE Allocation RNTI " << (*it).first << " startPRB " << (uint32_t)uldci.m_rbStart << " nPRB " << (uint32_t)uldci.m_rbLen << " CQI " << cqi << " MCS " << (uint32_t)uldci.m_mcs << " TBsize " << uldci.m_tbSize << " RbAlloc " << rbAllocated << " harqId " << (uint16_t)harqId);
2065 
2066  it++;
2067  if (it == m_ceBsrRxed.end ())
2068  {
2069  // restart from the first
2070  it = m_ceBsrRxed.begin ();
2071  }
2072  if ((rbAllocated == m_cschedCellConfig.m_ulBandwidth) || (rbPerFlow == 0))
2073  {
2074  // Stop allocation: no more PRBs
2075  m_nextRntiUl = (*it).first;
2076  break;
2077  }
2078  }
2079  while (((*it).first != m_nextRntiUl)&&(rbPerFlow!=0));
2080 
2081  m_allocationMaps.insert (std::pair <uint16_t, std::vector <uint16_t> > (params.m_sfnSf, rbgAllocationMap));
2083 
2084  return;
2085 }
2086 
2087 void
2089 {
2090  NS_LOG_FUNCTION (this);
2091  return;
2092 }
2093 
2094 void
2096 {
2097  NS_LOG_FUNCTION (this);
2098  return;
2099 }
2100 
2101 void
2103 {
2104  NS_LOG_FUNCTION (this);
2105 
2106  std::map <uint16_t,uint32_t>::iterator it;
2107 
2108  for (unsigned int i = 0; i < params.m_macCeList.size (); i++)
2109  {
2110  if ( params.m_macCeList.at (i).m_macCeType == MacCeListElement_s::BSR )
2111  {
2112  // buffer status report
2113  // note that this scheduler does not differentiate the
2114  // allocation according to which LCGs have more/less bytes
2115  // to send.
2116  // Hence the BSR of different LCGs are just summed up to get
2117  // a total queue size that is used for allocation purposes.
2118 
2119  uint32_t buffer = 0;
2120  for (uint8_t lcg = 0; lcg < 4; ++lcg)
2121  {
2122  uint8_t bsrId = params.m_macCeList.at (i).m_macCeValue.m_bufferStatus.at (lcg);
2123  buffer += BufferSizeLevelBsr::BsrId2BufferSize (bsrId);
2124  }
2125 
2126  uint16_t rnti = params.m_macCeList.at (i).m_rnti;
2127  NS_LOG_LOGIC (this << "RNTI=" << rnti << " buffer=" << buffer);
2128  it = m_ceBsrRxed.find (rnti);
2129  if (it == m_ceBsrRxed.end ())
2130  {
2131  // create the new entry
2132  m_ceBsrRxed.insert ( std::pair<uint16_t, uint32_t > (rnti, buffer));
2133  }
2134  else
2135  {
2136  // update the buffer size value
2137  (*it).second = buffer;
2138  }
2139  }
2140  }
2141 
2142  return;
2143 }
2144 
2145 void
2147 {
2148  NS_LOG_FUNCTION (this);
2149 // retrieve the allocation for this subframe
2150  switch (m_ulCqiFilter)
2151  {
2153  {
2154  // filter all the CQIs that are not SRS based
2155  if (params.m_ulCqi.m_type != UlCqi_s::SRS)
2156  {
2157  return;
2158  }
2159  }
2160  break;
2162  {
2163  // filter all the CQIs that are not SRS based
2164  if (params.m_ulCqi.m_type != UlCqi_s::PUSCH)
2165  {
2166  return;
2167  }
2168  }
2170  break;
2171 
2172  default:
2173  NS_FATAL_ERROR ("Unknown UL CQI type");
2174  }
2175 
2176  switch (params.m_ulCqi.m_type)
2177  {
2178  case UlCqi_s::PUSCH:
2179  {
2180  std::map <uint16_t, std::vector <uint16_t> >::iterator itMap;
2181  std::map <uint16_t, std::vector <double> >::iterator itCqi;
2182  NS_LOG_DEBUG (this << " Collect PUSCH CQIs of Frame no. " << (params.m_sfnSf >> 4) << " subframe no. " << (0xF & params.m_sfnSf));
2183  itMap = m_allocationMaps.find (params.m_sfnSf);
2184  if (itMap == m_allocationMaps.end ())
2185  {
2186  return;
2187  }
2188  for (uint32_t i = 0; i < (*itMap).second.size (); i++)
2189  {
2190  // convert from fixed point notation Sxxxxxxxxxxx.xxx to double
2191  double sinr = LteFfConverter::fpS11dot3toDouble (params.m_ulCqi.m_sinr.at (i));
2192  itCqi = m_ueCqi.find ((*itMap).second.at (i));
2193  if (itCqi == m_ueCqi.end ())
2194  {
2195  // create a new entry
2196  std::vector <double> newCqi;
2197  for (uint32_t j = 0; j < m_cschedCellConfig.m_ulBandwidth; j++)
2198  {
2199  if (i == j)
2200  {
2201  newCqi.push_back (sinr);
2202  }
2203  else
2204  {
2205  // initialize with NO_SINR value.
2206  newCqi.push_back (NO_SINR);
2207  }
2208 
2209  }
2210  m_ueCqi.insert (std::pair <uint16_t, std::vector <double> > ((*itMap).second.at (i), newCqi));
2211  // generate correspondent timer
2212  m_ueCqiTimers.insert (std::pair <uint16_t, uint32_t > ((*itMap).second.at (i), m_cqiTimersThreshold));
2213  }
2214  else
2215  {
2216  // update the value
2217  (*itCqi).second.at (i) = sinr;
2218  NS_LOG_DEBUG (this << " RNTI " << (*itMap).second.at (i) << " RB " << i << " SINR " << sinr);
2219  // update correspondent timer
2220  std::map <uint16_t, uint32_t>::iterator itTimers;
2221  itTimers = m_ueCqiTimers.find ((*itMap).second.at (i));
2222  (*itTimers).second = m_cqiTimersThreshold;
2223 
2224  }
2225 
2226  }
2227  // remove obsolete info on allocation
2228  m_allocationMaps.erase (itMap);
2229  }
2230  break;
2231  case UlCqi_s::SRS:
2232  {
2233  // get the RNTI from vendor specific parameters
2234  uint16_t rnti = 0;
2235  NS_ASSERT (params.m_vendorSpecificList.size () > 0);
2236  for (uint16_t i = 0; i < params.m_vendorSpecificList.size (); i++)
2237  {
2238  if (params.m_vendorSpecificList.at (i).m_type == SRS_CQI_RNTI_VSP)
2239  {
2240  Ptr<SrsCqiRntiVsp> vsp = DynamicCast<SrsCqiRntiVsp> (params.m_vendorSpecificList.at (i).m_value);
2241  rnti = vsp->GetRnti ();
2242  }
2243  }
2244  std::map <uint16_t, std::vector <double> >::iterator itCqi;
2245  itCqi = m_ueCqi.find (rnti);
2246  if (itCqi == m_ueCqi.end ())
2247  {
2248  // create a new entry
2249  std::vector <double> newCqi;
2250  for (uint32_t j = 0; j < m_cschedCellConfig.m_ulBandwidth; j++)
2251  {
2252  double sinr = LteFfConverter::fpS11dot3toDouble (params.m_ulCqi.m_sinr.at (j));
2253  newCqi.push_back (sinr);
2254  NS_LOG_INFO (this << " RNTI " << rnti << " new SRS-CQI for RB " << j << " value " << sinr);
2255 
2256  }
2257  m_ueCqi.insert (std::pair <uint16_t, std::vector <double> > (rnti, newCqi));
2258  // generate correspondent timer
2259  m_ueCqiTimers.insert (std::pair <uint16_t, uint32_t > (rnti, m_cqiTimersThreshold));
2260  }
2261  else
2262  {
2263  // update the values
2264  for (uint32_t j = 0; j < m_cschedCellConfig.m_ulBandwidth; j++)
2265  {
2266  double sinr = LteFfConverter::fpS11dot3toDouble (params.m_ulCqi.m_sinr.at (j));
2267  (*itCqi).second.at (j) = sinr;
2268  NS_LOG_INFO (this << " RNTI " << rnti << " update SRS-CQI for RB " << j << " value " << sinr);
2269  }
2270  // update correspondent timer
2271  std::map <uint16_t, uint32_t>::iterator itTimers;
2272  itTimers = m_ueCqiTimers.find (rnti);
2273  (*itTimers).second = m_cqiTimersThreshold;
2274 
2275  }
2276 
2277 
2278  }
2279  break;
2280  case UlCqi_s::PUCCH_1:
2281  case UlCqi_s::PUCCH_2:
2282  case UlCqi_s::PRACH:
2283  {
2284  NS_FATAL_ERROR ("PssFfMacScheduler supports only PUSCH and SRS UL-CQIs");
2285  }
2286  break;
2287  default:
2288  NS_FATAL_ERROR ("Unknown type of UL-CQI");
2289  }
2290  return;
2291 }
2292 
2293 void
2295 {
2296  // refresh DL CQI P01 Map
2297  std::map <uint16_t,uint32_t>::iterator itP10 = m_p10CqiTimers.begin ();
2298  while (itP10 != m_p10CqiTimers.end ())
2299  {
2300  NS_LOG_INFO (this << " P10-CQI for user " << (*itP10).first << " is " << (uint32_t)(*itP10).second << " thr " << (uint32_t)m_cqiTimersThreshold);
2301  if ((*itP10).second == 0)
2302  {
2303  // delete correspondent entries
2304  std::map <uint16_t,uint8_t>::iterator itMap = m_p10CqiRxed.find ((*itP10).first);
2305  NS_ASSERT_MSG (itMap != m_p10CqiRxed.end (), " Does not find CQI report for user " << (*itP10).first);
2306  NS_LOG_INFO (this << " P10-CQI expired for user " << (*itP10).first);
2307  m_p10CqiRxed.erase (itMap);
2308  std::map <uint16_t,uint32_t>::iterator temp = itP10;
2309  itP10++;
2310  m_p10CqiTimers.erase (temp);
2311  }
2312  else
2313  {
2314  (*itP10).second--;
2315  itP10++;
2316  }
2317  }
2318 
2319  // refresh DL CQI A30 Map
2320  std::map <uint16_t,uint32_t>::iterator itA30 = m_a30CqiTimers.begin ();
2321  while (itA30 != m_a30CqiTimers.end ())
2322  {
2323  NS_LOG_INFO (this << " A30-CQI for user " << (*itA30).first << " is " << (uint32_t)(*itA30).second << " thr " << (uint32_t)m_cqiTimersThreshold);
2324  if ((*itA30).second == 0)
2325  {
2326  // delete correspondent entries
2327  std::map <uint16_t,SbMeasResult_s>::iterator itMap = m_a30CqiRxed.find ((*itA30).first);
2328  NS_ASSERT_MSG (itMap != m_a30CqiRxed.end (), " Does not find CQI report for user " << (*itA30).first);
2329  NS_LOG_INFO (this << " A30-CQI expired for user " << (*itA30).first);
2330  m_a30CqiRxed.erase (itMap);
2331  std::map <uint16_t,uint32_t>::iterator temp = itA30;
2332  itA30++;
2333  m_a30CqiTimers.erase (temp);
2334  }
2335  else
2336  {
2337  (*itA30).second--;
2338  itA30++;
2339  }
2340  }
2341 
2342  return;
2343 }
2344 
2345 
2346 void
2348 {
2349  // refresh UL CQI Map
2350  std::map <uint16_t,uint32_t>::iterator itUl = m_ueCqiTimers.begin ();
2351  while (itUl != m_ueCqiTimers.end ())
2352  {
2353  NS_LOG_INFO (this << " UL-CQI for user " << (*itUl).first << " is " << (uint32_t)(*itUl).second << " thr " << (uint32_t)m_cqiTimersThreshold);
2354  if ((*itUl).second == 0)
2355  {
2356  // delete correspondent entries
2357  std::map <uint16_t, std::vector <double> >::iterator itMap = m_ueCqi.find ((*itUl).first);
2358  NS_ASSERT_MSG (itMap != m_ueCqi.end (), " Does not find CQI report for user " << (*itUl).first);
2359  NS_LOG_INFO (this << " UL-CQI exired for user " << (*itUl).first);
2360  (*itMap).second.clear ();
2361  m_ueCqi.erase (itMap);
2362  std::map <uint16_t,uint32_t>::iterator temp = itUl;
2363  itUl++;
2364  m_ueCqiTimers.erase (temp);
2365  }
2366  else
2367  {
2368  (*itUl).second--;
2369  itUl++;
2370  }
2371  }
2372 
2373  return;
2374 }
2375 
2376 void
2377 PssFfMacScheduler::UpdateDlRlcBufferInfo (uint16_t rnti, uint8_t lcid, uint16_t size)
2378 {
2379  std::map<LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it;
2380  LteFlowId_t flow (rnti, lcid);
2381  it = m_rlcBufferReq.find (flow);
2382  if (it != m_rlcBufferReq.end ())
2383  {
2384  NS_LOG_INFO (this << " UE " << rnti << " LC " << (uint16_t)lcid << " txqueue " << (*it).second.m_rlcTransmissionQueueSize << " retxqueue " << (*it).second.m_rlcRetransmissionQueueSize << " status " << (*it).second.m_rlcStatusPduSize << " decrease " << size);
2385  // Update queues: RLC tx order Status, ReTx, Tx
2386  // Update status queue
2387  if (((*it).second.m_rlcStatusPduSize > 0) && (size >= (*it).second.m_rlcStatusPduSize))
2388  {
2389  (*it).second.m_rlcStatusPduSize = 0;
2390  }
2391  else if (((*it).second.m_rlcRetransmissionQueueSize > 0) && (size >= (*it).second.m_rlcRetransmissionQueueSize))
2392  {
2393  (*it).second.m_rlcRetransmissionQueueSize = 0;
2394  }
2395  else if ((*it).second.m_rlcTransmissionQueueSize > 0)
2396  {
2397  uint32_t rlcOverhead;
2398  if (lcid == 1)
2399  {
2400  // for SRB1 (using RLC AM) it's better to
2401  // overestimate RLC overhead rather than
2402  // underestimate it and risk unneeded
2403  // segmentation which increases delay
2404  rlcOverhead = 4;
2405  }
2406  else
2407  {
2408  // minimum RLC overhead due to header
2409  rlcOverhead = 2;
2410  }
2411  // update transmission queue
2412  if ((*it).second.m_rlcTransmissionQueueSize <= size - rlcOverhead)
2413  {
2414  (*it).second.m_rlcTransmissionQueueSize = 0;
2415  }
2416  else
2417  {
2418  (*it).second.m_rlcTransmissionQueueSize -= size - rlcOverhead;
2419  }
2420  }
2421  }
2422  else
2423  {
2424  NS_LOG_ERROR (this << " Does not find DL RLC Buffer Report of UE " << rnti);
2425  }
2426 }
2427 
2428 void
2429 PssFfMacScheduler::UpdateUlRlcBufferInfo (uint16_t rnti, uint16_t size)
2430 {
2431 
2432  size = size - 2; // remove the minimum RLC overhead
2433  std::map <uint16_t,uint32_t>::iterator it = m_ceBsrRxed.find (rnti);
2434  if (it != m_ceBsrRxed.end ())
2435  {
2436  NS_LOG_INFO (this << " UE " << rnti << " size " << size << " BSR " << (*it).second);
2437  if ((*it).second >= size)
2438  {
2439  (*it).second -= size;
2440  }
2441  else
2442  {
2443  (*it).second = 0;
2444  }
2445  }
2446  else
2447  {
2448  NS_LOG_ERROR (this << " Does not find BSR report info of UE " << rnti);
2449  }
2450 
2451 }
2452 
2453 void
2455 {
2456  NS_LOG_FUNCTION (this << " RNTI " << rnti << " txMode " << (uint16_t)txMode);
2458  params.m_rnti = rnti;
2459  params.m_transmissionMode = txMode;
2461 }
2462 
2463 
2464 }
virtual void SchedDlCqiInfoReq(const struct SchedDlCqiInfoReqParameters &params)
std::vector< struct UlInfoListElement_s > m_ulInfoList
See section 4.3.1 dlDciListElement.
Definition: ff-mac-common.h:88
std::map< uint16_t, uint32_t > m_p10CqiTimers
std::map< uint16_t, std::vector< uint16_t > > m_allocationMaps
smart pointer class similar to boost::intrusive_ptr
Definition: ptr.h:60
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by "...
void DoCschedLcConfigReq(const struct FfMacCschedSapProvider::CschedLcConfigReqParameters &params)
#define HARQ_PERIOD
Definition: lte-common.h:30
Hold a bool native type.
Definition: boolean.h:38
std::map< uint16_t, uint8_t > m_uesTxMode
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register the class in the ns-3 factory.
Definition: object-base.h:38
void DoSchedUlSrInfoReq(const struct FfMacSchedSapProvider::SchedUlSrInfoReqParameters &params)
Parameters of the CSCHED_UE_CONFIG_CNF primitive.
hold variables of type string
Definition: string.h:18
int LcActivePerFlow(uint16_t rnti)
Parameters of the CSCHED_UE_RELEASE_REQ primitive.
void DoCschedLcReleaseReq(const struct FfMacCschedSapProvider::CschedLcReleaseReqParameters &params)
void TransmissionModeConfigurationUpdate(uint16_t rnti, uint8_t txMode)
std::map< uint16_t, uint8_t > m_p10CqiRxed
enum ns3::UlCqi_s::Type_e m_type
void UpdateDlRlcBufferInfo(uint16_t rnti, uint8_t lcid, uint16_t size)
std::vector< UlDciListElement_s > UlHarqProcessesDciBuffer_t
std::vector< struct LogicalChannelConfigListElement_s > m_logicalChannelConfigList
std::vector< uint16_t > m_sinr
std::map< uint16_t, pssFlowPerf_t > m_flowStatsUl
std::vector< uint8_t > DlHarqProcessesTimer_t
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file...
Definition: assert.h:61
virtual void SchedUlCqiInfoReq(const struct SchedUlCqiInfoReqParameters &params)
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:170
std::vector< uint8_t > m_mcs
Definition: ff-mac-common.h:95
See section 4.3.2 ulDciListElement.
Provides the CSCHED SAP.
std::map< uint16_t, UlHarqProcessesStatus_t > m_ulHarqProcessesStatus
virtual void SchedDlRachInfoReq(const struct SchedDlRachInfoReqParameters &params)
std::vector< struct UlDciListElement_s > m_dciList
#define NS_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
Definition: log.h:223
#define NS_FATAL_ERROR(msg)
fatal error handling
Definition: fatal-error.h:95
See section 4.3.10 buildRARListElement.
virtual void CschedUeConfigReq(const struct CschedUeConfigReqParameters &params)
Parameters of the CSCHED_UE_CONFIG_UPDATE_IND primitive.
std::map< uint16_t, UlHarqProcessesDciBuffer_t > m_ulHarqProcessesDciBuffer
Parameters of the CSCHED_LC_RELEASE_REQ primitive.
std::vector< std::vector< struct RlcPduListElement_s > > m_rlcPduList
Flow information.
Parameters of the SCHED_DL_TRIGGER_REQ primitive.
static TypeId GetTypeId(void)
std::map< uint16_t, DlHarqProcessesDciBuffer_t > m_dlHarqProcessesDciBuffer
std::map< uint16_t, DlHarqProcessesStatus_t > m_dlHarqProcessesStatus
FfMacCschedSapUser * m_cschedSapUser
void DoSchedUlMacCtrlInfoReq(const struct FfMacSchedSapProvider::SchedUlMacCtrlInfoReqParameters &params)
void DoSchedDlTriggerReq(const struct FfMacSchedSapProvider::SchedDlTriggerReqParameters &params)
std::vector< RlcPduList_t > DlHarqRlcPduListBuffer_t
int GetRbgSize(int dlbandwidth)
Parameters of the SCHED_DL_MAC_BUFFER_REQ primitive.
Parameters of the SCHED_DL_PAGING_BUFFER_REQ primitive.
virtual void CschedUeConfigUpdateInd(const struct CschedUeConfigUpdateIndParameters &params)=0
std::vector< struct VendorSpecificListElement_s > m_vendorSpecificList
void DoSchedDlCqiInfoReq(const struct FfMacSchedSapProvider::SchedDlCqiInfoReqParameters &params)
double secondLastAveragedThroughput
Past average throughput.
virtual FfMacSchedSapProvider * GetFfMacSchedSapProvider()
Parameters of the SCHED_UL_TRIGGER_REQ primitive.
double EstimateUlSinr(uint16_t rnti, uint16_t rb)
Hold an unsigned integer type.
Definition: uinteger.h:46
static uint8_t TxMode2LayerNum(uint8_t txMode)
Definition: lte-common.cc:170
Ptr< SampleEmitter > s
bool m_harqOn
m_harqOn when false inhibit te HARQ mechanisms (by default active)
std::vector< uint8_t > m_ndi
Definition: ff-mac-common.h:96
std::map< LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters > m_rlcBufferReq
void DoSchedDlRlcBufferReq(const struct FfMacSchedSapProvider::SchedDlRlcBufferReqParameters &params)
Provides the SCHED SAP.
virtual void CschedLcReleaseReq(const struct CschedLcReleaseReqParameters &params)
virtual void CschedUeConfigCnf(const struct CschedUeConfigCnfParameters &params)=0
unsigned int lastTtiBytesTransmitted
Total bytes send by eNb for this UE.
#define NS_LOG_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
Definition: log.h:233
Parameters of the SCHED_UL_NOISE_INTERFERENCE_REQ primitive.
friend class PssSchedulerMemberSchedSapProvider
std::vector< struct CqiListElement_s > m_cqiList
std::vector< struct DlInfoListElement_s > m_dlInfoList
virtual void SchedDlRlcBufferReq(const struct SchedDlRlcBufferReqParameters &params)
void DoCschedUeConfigReq(const struct FfMacCschedSapProvider::CschedUeConfigReqParameters &params)
double lastAveragedThroughput
Total bytes send by eNB in last tti for this UE.
virtual void SchedDlConfigInd(const struct SchedDlConfigIndParameters &params)=0
virtual void CschedLcConfigReq(const struct CschedLcConfigReqParameters &params)
std::vector< uint16_t > m_tbsSize
Definition: ff-mac-common.h:94
See section 4.3.9 rlcPDU_ListElement.
std::map< uint16_t, DlHarqRlcPduListBuffer_t > m_dlHarqProcessesRlcPduListBuffer
void DoSchedUlNoiseInterferenceReq(const struct FfMacSchedSapProvider::SchedUlNoiseInterferenceReqParameters &params)
void DoSchedDlPagingBufferReq(const struct FfMacSchedSapProvider::SchedDlPagingBufferReqParameters &params)
unsigned long totalBytesTransmitted
std::vector< DlDciListElement_s > DlHarqProcessesDciBuffer_t
Parameters of the CSCHED_LC_CONFIG_REQ primitive.
std::vector< uint8_t > m_rv
Definition: ff-mac-common.h:97
virtual void SetFfMacSchedSapUser(FfMacSchedSapUser *s)
set the user part of the FfMacSchedSap that this Scheduler will interact with.
std::map< uint16_t, pssFlowPerf_t > m_flowStatsDl
uint8_t HarqProcessAvailability(uint16_t rnti)
Return the availability of free process for the RNTI specified.
std::map< uint16_t, uint8_t > m_ulHarqCurrentProcessId
virtual void CschedUeReleaseReq(const struct CschedUeReleaseReqParameters &params)
static const int PssType0AllocationRbg[4]
virtual void SchedUlConfigInd(const struct SchedUlConfigIndParameters &params)=0
void RefreshHarqProcesses()
Refresh HARQ processes according to the timers.
static Time Now(void)
Return the "current simulation time".
Definition: simulator.cc:180
UlCqiFilter_t m_ulCqiFilter
void DoSchedUlTriggerReq(const struct FfMacSchedSapProvider::SchedUlTriggerReqParameters &params)
std::map< uint16_t, DlHarqProcessesTimer_t > m_dlHarqProcessesTimer
#define SRS_CQI_RNTI_VSP
void UpdateUlRlcBufferInfo(uint16_t rnti, uint16_t size)
This abstract base class identifies the interface by means of which the helper object can plug on the...
uint8_t UpdateHarqProcessId(uint16_t rnti)
Update and return a new process Id for the RNTI specified.
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
Definition: assert.h:84
std::vector< struct RachListElement_s > m_rachList
void DoSchedDlMacBufferReq(const struct FfMacSchedSapProvider::SchedDlMacBufferReqParameters &params)
Parameters of the SCHED_DL_CQI_INFO_REQ primitive.
std::vector< struct MacCeListElement_s > m_macCeList
std::vector< struct RachListElement_s > m_rachList
void DoCschedCellConfigReq(const struct FfMacCschedSapProvider::CschedCellConfigReqParameters &params)
static double fpS11dot3toDouble(uint16_t val)
Definition: lte-common.cc:114
virtual ~PssFfMacScheduler()
Destructor.
std::map< uint16_t, SbMeasResult_s > m_a30CqiRxed
void DoSchedUlCqiInfoReq(const struct FfMacSchedSapProvider::SchedUlCqiInfoReqParameters &params)
std::map< uint16_t, uint32_t > m_ceBsrRxed
std::vector< uint8_t > UlHarqProcessesStatus_t
virtual void DoDispose(void)
This method is called by Object::Dispose or by the object's destructor, whichever comes first...
std::vector< uint8_t > DlHarqProcessesStatus_t
Parameters of the SCHED_UL_CQI_INFO_REQ primitive.
virtual void SchedDlTriggerReq(const struct SchedDlTriggerReqParameters &params)
void DoSchedDlRachInfoReq(const struct FfMacSchedSapProvider::SchedDlRachInfoReqParameters &params)
static uint32_t BsrId2BufferSize(uint8_t val)
Definition: lte-common.cc:142
FfMacCschedSapProvider::CschedCellConfigReqParameters m_cschedCellConfig
virtual void SetFfMacCschedSapUser(FfMacCschedSapUser *s)
set the user part of the FfMacCschedSap that this Scheduler will interact with.
Parameters of the SCHED_UL_MAC_CTRL_INFO_REQ primitive.
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition: log.h:213
virtual void SchedUlTriggerReq(const struct SchedUlTriggerReqParameters &params)
std::vector< uint16_t > m_rachAllocationMap
std::vector< DlInfoListElement_s > m_dlInfoListBuffered
virtual void SchedDlMacBufferReq(const struct SchedDlMacBufferReqParameters &params)
FfMacCschedSapProvider * m_cschedSapProvider
std::map< uint16_t, uint32_t > m_a30CqiTimers
Parameters of the SCHED_UL_SR_INFO_REQ primitive.
virtual void SchedDlPagingBufferReq(const struct SchedDlPagingBufferReqParameters &params)
virtual void SchedUlMacCtrlInfoReq(const struct SchedUlMacCtrlInfoReqParameters &params)
std::map< uint16_t, std::vector< double > > m_ueCqi
std::map< uint16_t, uint32_t > m_ueCqiTimers
#define NS_LOG_ERROR(msg)
Use NS_LOG to output a message of level LOG_ERROR.
Definition: log.h:193
Parameters of the SCHED_DL_RACH_INFO_REQ primitive.
Parameters of the SCHED_UL_CONFIG_IND primitive.
Parameters of the CSCHED_UE_CONFIG_REQ primitive.
#define HARQ_DL_TIMEOUT
void DoCschedUeReleaseReq(const struct FfMacCschedSapProvider::CschedUeReleaseReqParameters &params)
#define NO_SINR
std::map< uint16_t, uint8_t > m_dlHarqCurrentProcessId
struct DlDciListElement_s m_dci
std::vector< struct BuildRarListElement_s > m_buildRarList
virtual FfMacCschedSapProvider * GetFfMacCschedSapProvider()
FfMacSchedSapUser * m_schedSapUser
a unique identifier for an interface.
Definition: type-id.h:49
FfMacSchedSapProvider * m_schedSapProvider
virtual void SchedUlSrInfoReq(const struct SchedUlSrInfoReqParameters &params)
TypeId SetParent(TypeId tid)
Definition: type-id.cc:610
virtual void CschedCellConfigReq(const struct CschedCellConfigReqParameters &params)
CSCHED_CELL_CONFIG_REQ.
#define HARQ_PROC_NUM
std::vector< struct BuildDataListElement_s > m_buildDataList
virtual void SchedUlNoiseInterferenceReq(const struct SchedUlNoiseInterferenceReqParameters &params)
friend class PssSchedulerMemberCschedSapProvider
See section 4.3.8 builDataListElement.
Implements the SCHED SAP and CSCHED SAP for a Priority Set scheduler.