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