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