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