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