A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
tdtbfq-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 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 * Author: Marco Miozzo <marco.miozzo@cttc.es>
7 * Modification: Dizhi Zhou <dizhi.zhou@gmail.com> // modify codes related to downlink scheduler
8 */
9
11
12#include "lte-amc.h"
14
15#include "ns3/boolean.h"
16#include "ns3/integer.h"
17#include "ns3/log.h"
18#include "ns3/math.h"
19#include "ns3/pointer.h"
20#include "ns3/simulator.h"
21
22#include <cfloat>
23#include <set>
24
25namespace ns3
26{
27
28NS_LOG_COMPONENT_DEFINE("TdTbfqFfMacScheduler");
29
30/// TDTBFQ type 0 allocation RBG (see table 7.1.6.1-1 of 36.213)
31static const int TdTbfqType0AllocationRbg[4] = {
32 10, // RBG size 1
33 26, // RBG size 2
34 63, // RBG size 3
35 110, // RBG size 4
36};
37
38NS_OBJECT_ENSURE_REGISTERED(TdTbfqFfMacScheduler);
39
52
57
58void
73
76{
77 static TypeId tid =
78 TypeId("ns3::TdTbfqFfMacScheduler")
80 .SetGroupName("Lte")
81 .AddConstructor<TdTbfqFfMacScheduler>()
82 .AddAttribute("CqiTimerThreshold",
83 "The number of TTIs a CQI is valid (default 1000 - 1 sec.)",
84 UintegerValue(1000),
87 .AddAttribute("DebtLimit",
88 "Flow debt limit (default -625000 bytes)",
89 IntegerValue(-625000),
92 .AddAttribute("CreditLimit",
93 "Flow credit limit (default 625000 bytes)",
94 UintegerValue(625000),
97 .AddAttribute("TokenPoolSize",
98 "The maximum value of flow token pool (default 1 bytes)",
102 .AddAttribute("CreditableThreshold",
103 "Threshold of flow credit (default 0 bytes)",
104 UintegerValue(0),
107
108 .AddAttribute("HarqEnabled",
109 "Activate/Deactivate the HARQ [by default is active].",
110 BooleanValue(true),
113 .AddAttribute("UlGrantMcs",
114 "The MCS of the UL grant, must be [0..15] (default 0)",
115 UintegerValue(0),
118 return tid;
119}
120
121void
126
127void
132
138
144
145void
150
156
157void
160{
161 NS_LOG_FUNCTION(this);
162 // Read the subset of parameters used
163 m_cschedCellConfig = params;
164 m_rachAllocationMap.resize(m_cschedCellConfig.m_ulBandwidth, 0);
166 cnf.m_result = SUCCESS;
167 m_cschedSapUser->CschedUeConfigCnf(cnf);
168}
169
170void
173{
174 NS_LOG_FUNCTION(this << " RNTI " << params.m_rnti << " txMode "
175 << (uint16_t)params.m_transmissionMode);
176 auto it = m_uesTxMode.find(params.m_rnti);
177 if (it == m_uesTxMode.end())
178 {
179 m_uesTxMode[params.m_rnti] = params.m_transmissionMode;
180 // generate HARQ buffers
181 m_dlHarqCurrentProcessId[params.m_rnti] = 0;
182 DlHarqProcessesStatus_t dlHarqPrcStatus;
183 dlHarqPrcStatus.resize(8, 0);
184 m_dlHarqProcessesStatus[params.m_rnti] = dlHarqPrcStatus;
185 DlHarqProcessesTimer_t dlHarqProcessesTimer;
186 dlHarqProcessesTimer.resize(8, 0);
187 m_dlHarqProcessesTimer[params.m_rnti] = dlHarqProcessesTimer;
189 dlHarqdci.resize(8);
190 m_dlHarqProcessesDciBuffer[params.m_rnti] = dlHarqdci;
191 DlHarqRlcPduListBuffer_t dlHarqRlcPdu;
192 dlHarqRlcPdu.resize(2);
193 dlHarqRlcPdu.at(0).resize(8);
194 dlHarqRlcPdu.at(1).resize(8);
195 m_dlHarqProcessesRlcPduListBuffer[params.m_rnti] = dlHarqRlcPdu;
196 m_ulHarqCurrentProcessId[params.m_rnti] = 0;
197 UlHarqProcessesStatus_t ulHarqPrcStatus;
198 ulHarqPrcStatus.resize(8, 0);
199 m_ulHarqProcessesStatus[params.m_rnti] = ulHarqPrcStatus;
201 ulHarqdci.resize(8);
202 m_ulHarqProcessesDciBuffer[params.m_rnti] = ulHarqdci;
203 }
204 else
205 {
206 (*it).second = params.m_transmissionMode;
207 }
208}
209
210void
213{
214 NS_LOG_FUNCTION(this << " New LC, rnti: " << params.m_rnti);
215
216 for (std::size_t i = 0; i < params.m_logicalChannelConfigList.size(); i++)
217 {
218 auto it = m_flowStatsDl.find(params.m_rnti);
219
220 if (it == m_flowStatsDl.end())
221 {
222 uint64_t mbrDlInBytes =
223 params.m_logicalChannelConfigList.at(i).m_eRabMaximulBitrateDl / 8; // byte/s
224 uint64_t mbrUlInBytes =
225 params.m_logicalChannelConfigList.at(i).m_eRabMaximulBitrateUl / 8; // byte/s
226
227 tdtbfqsFlowPerf_t flowStatsDl;
228 flowStatsDl.flowStart = Simulator::Now();
229 flowStatsDl.packetArrivalRate = 0;
230 flowStatsDl.tokenGenerationRate = mbrDlInBytes;
231 flowStatsDl.tokenPoolSize = 0;
232 flowStatsDl.maxTokenPoolSize = m_tokenPoolSize;
233 flowStatsDl.counter = 0;
234 flowStatsDl.burstCredit = m_creditLimit; // bytes
235 flowStatsDl.debtLimit = m_debtLimit; // bytes
237 m_flowStatsDl[params.m_rnti] = flowStatsDl;
238 tdtbfqsFlowPerf_t flowStatsUl;
239 flowStatsUl.flowStart = Simulator::Now();
240 flowStatsUl.packetArrivalRate = 0;
241 flowStatsUl.tokenGenerationRate = mbrUlInBytes;
242 flowStatsUl.tokenPoolSize = 0;
243 flowStatsUl.maxTokenPoolSize = m_tokenPoolSize;
244 flowStatsUl.counter = 0;
245 flowStatsUl.burstCredit = m_creditLimit; // bytes
246 flowStatsUl.debtLimit = m_debtLimit; // bytes
248 m_flowStatsUl[params.m_rnti] = flowStatsUl;
249 }
250 else
251 {
252 // update MBR and GBR from UeManager::SetupDataRadioBearer ()
253 uint64_t mbrDlInBytes =
254 params.m_logicalChannelConfigList.at(i).m_eRabMaximulBitrateDl / 8; // byte/s
255 uint64_t mbrUlInBytes =
256 params.m_logicalChannelConfigList.at(i).m_eRabMaximulBitrateUl / 8; // byte/s
257 m_flowStatsDl[(*it).first].tokenGenerationRate = mbrDlInBytes;
258 m_flowStatsUl[(*it).first].tokenGenerationRate = mbrUlInBytes;
259 }
260 }
261}
262
263void
266{
267 NS_LOG_FUNCTION(this);
268 for (std::size_t i = 0; i < params.m_logicalChannelIdentity.size(); i++)
269 {
270 auto it = m_rlcBufferReq.begin();
271 while (it != m_rlcBufferReq.end())
272 {
273 if (((*it).first.m_rnti == params.m_rnti) &&
274 ((*it).first.m_lcId == params.m_logicalChannelIdentity.at(i)))
275 {
276 auto temp = it;
277 it++;
278 m_rlcBufferReq.erase(temp);
279 }
280 else
281 {
282 it++;
283 }
284 }
285 }
286}
287
288void
291{
292 NS_LOG_FUNCTION(this);
293
294 m_uesTxMode.erase(params.m_rnti);
295 m_dlHarqCurrentProcessId.erase(params.m_rnti);
296 m_dlHarqProcessesStatus.erase(params.m_rnti);
297 m_dlHarqProcessesTimer.erase(params.m_rnti);
298 m_dlHarqProcessesDciBuffer.erase(params.m_rnti);
299 m_dlHarqProcessesRlcPduListBuffer.erase(params.m_rnti);
300 m_ulHarqCurrentProcessId.erase(params.m_rnti);
301 m_ulHarqProcessesStatus.erase(params.m_rnti);
302 m_ulHarqProcessesDciBuffer.erase(params.m_rnti);
303 m_flowStatsDl.erase(params.m_rnti);
304 m_flowStatsUl.erase(params.m_rnti);
305 m_ceBsrRxed.erase(params.m_rnti);
306 auto it = m_rlcBufferReq.begin();
307 while (it != m_rlcBufferReq.end())
308 {
309 if ((*it).first.m_rnti == params.m_rnti)
310 {
311 auto temp = it;
312 it++;
313 m_rlcBufferReq.erase(temp);
314 }
315 else
316 {
317 it++;
318 }
319 }
320 if (m_nextRntiUl == params.m_rnti)
321 {
322 m_nextRntiUl = 0;
323 }
324}
325
326void
329{
330 NS_LOG_FUNCTION(this << params.m_rnti << (uint32_t)params.m_logicalChannelIdentity);
331 // API generated by RLC for updating RLC parameters on a LC (tx and retx queues)
332
333 LteFlowId_t flow(params.m_rnti, params.m_logicalChannelIdentity);
334
335 auto it = m_rlcBufferReq.find(flow);
336
337 if (it == m_rlcBufferReq.end())
338 {
339 m_rlcBufferReq[flow] = params;
340 }
341 else
342 {
343 (*it).second = params;
344 }
345}
346
347void
354
355void
362
363int
365{
366 for (int i = 0; i < 4; i++)
367 {
368 if (dlbandwidth < TdTbfqType0AllocationRbg[i])
369 {
370 return i + 1;
371 }
372 }
373
374 return -1;
375}
376
377unsigned int
379{
380 unsigned int lcActive = 0;
381 for (auto it = m_rlcBufferReq.begin(); it != m_rlcBufferReq.end(); it++)
382 {
383 if (((*it).first.m_rnti == rnti) && (((*it).second.m_rlcTransmissionQueueSize > 0) ||
384 ((*it).second.m_rlcRetransmissionQueueSize > 0) ||
385 ((*it).second.m_rlcStatusPduSize > 0)))
386 {
387 lcActive++;
388 }
389 if ((*it).first.m_rnti > rnti)
390 {
391 break;
392 }
393 }
394 return lcActive;
395}
396
397bool
399{
400 NS_LOG_FUNCTION(this << rnti);
401
402 auto it = m_dlHarqCurrentProcessId.find(rnti);
403 if (it == m_dlHarqCurrentProcessId.end())
404 {
405 NS_FATAL_ERROR("No Process Id found for this RNTI " << rnti);
406 }
407 auto itStat = m_dlHarqProcessesStatus.find(rnti);
408 if (itStat == m_dlHarqProcessesStatus.end())
409 {
410 NS_FATAL_ERROR("No Process Id Statusfound for this RNTI " << rnti);
411 }
412 uint8_t i = (*it).second;
413 do
414 {
415 i = (i + 1) % HARQ_PROC_NUM;
416 } while (((*itStat).second.at(i) != 0) && (i != (*it).second));
417
418 return (*itStat).second.at(i) == 0;
419}
420
421uint8_t
423{
424 NS_LOG_FUNCTION(this << rnti);
425
426 if (!m_harqOn)
427 {
428 return 0;
429 }
430
431 auto 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 auto itStat = m_dlHarqProcessesStatus.find(rnti);
437 if (itStat == m_dlHarqProcessesStatus.end())
438 {
439 NS_FATAL_ERROR("No Process Id Statusfound for this RNTI " << rnti);
440 }
441 uint8_t i = (*it).second;
442 do
443 {
444 i = (i + 1) % HARQ_PROC_NUM;
445 } while (((*itStat).second.at(i) != 0) && (i != (*it).second));
446 if ((*itStat).second.at(i) == 0)
447 {
448 (*it).second = i;
449 (*itStat).second.at(i) = 1;
450 }
451 else
452 {
453 NS_FATAL_ERROR("No HARQ process available for RNTI "
454 << rnti << " check before update with HarqProcessAvailability");
455 }
456
457 return (*it).second;
458}
459
460void
462{
463 NS_LOG_FUNCTION(this);
464
465 for (auto itTimers = m_dlHarqProcessesTimer.begin(); itTimers != m_dlHarqProcessesTimer.end();
466 itTimers++)
467 {
468 for (uint16_t i = 0; i < HARQ_PROC_NUM; i++)
469 {
470 if ((*itTimers).second.at(i) == HARQ_DL_TIMEOUT)
471 {
472 // reset HARQ process
473
474 NS_LOG_DEBUG(this << " Reset HARQ proc " << i << " for RNTI " << (*itTimers).first);
475 auto itStat = m_dlHarqProcessesStatus.find((*itTimers).first);
476 if (itStat == m_dlHarqProcessesStatus.end())
477 {
478 NS_FATAL_ERROR("No Process Id Status found for this RNTI "
479 << (*itTimers).first);
480 }
481 (*itStat).second.at(i) = 0;
482 (*itTimers).second.at(i) = 0;
483 }
484 else
485 {
486 (*itTimers).second.at(i)++;
487 }
488 }
489 }
490}
491
492void
495{
496 NS_LOG_FUNCTION(this << " Frame no. " << (params.m_sfnSf >> 4) << " subframe no. "
497 << (0xF & params.m_sfnSf));
498 // API generated by RLC for triggering the scheduling of a DL subframe
499
500 // evaluate the relative channel quality indicator for each UE per each RBG
501 // (since we are using allocation type 0 the small unit of allocation is RBG)
502 // Resource allocation type 0 (see sec 7.1.6.1 of 36.213)
503
505
506 int rbgSize = GetRbgSize(m_cschedCellConfig.m_dlBandwidth);
507 int rbgNum = m_cschedCellConfig.m_dlBandwidth / rbgSize;
508 std::map<uint16_t, std::vector<uint16_t>> allocationMap; // RBs map per RNTI
509 std::vector<bool> rbgMap; // global RBGs map
510 uint16_t rbgAllocatedNum = 0;
511 std::set<uint16_t> rntiAllocated;
512 rbgMap.resize(m_cschedCellConfig.m_dlBandwidth / rbgSize, false);
513
514 rbgMap = m_ffrSapProvider->GetAvailableDlRbg();
515 for (auto it = rbgMap.begin(); it != rbgMap.end(); it++)
516 {
517 if (*it)
518 {
519 rbgAllocatedNum++;
520 }
521 }
522
524
525 // update UL HARQ proc id
526 for (auto itProcId = m_ulHarqCurrentProcessId.begin();
527 itProcId != m_ulHarqCurrentProcessId.end();
528 itProcId++)
529 {
530 (*itProcId).second = ((*itProcId).second + 1) % HARQ_PROC_NUM;
531 }
532
533 // RACH Allocation
534 std::vector<bool> ulRbMap;
535 ulRbMap.resize(m_cschedCellConfig.m_ulBandwidth, false);
536 ulRbMap = m_ffrSapProvider->GetAvailableUlRbg();
537 uint8_t maxContinuousUlBandwidth = 0;
538 uint8_t tmpMinBandwidth = 0;
539 uint16_t ffrRbStartOffset = 0;
540 uint16_t tmpFfrRbStartOffset = 0;
541 uint16_t index = 0;
542
543 for (auto it = ulRbMap.begin(); it != ulRbMap.end(); it++)
544 {
545 if (*it)
546 {
547 if (tmpMinBandwidth > maxContinuousUlBandwidth)
548 {
549 maxContinuousUlBandwidth = tmpMinBandwidth;
550 ffrRbStartOffset = tmpFfrRbStartOffset;
551 }
552 tmpMinBandwidth = 0;
553 }
554 else
555 {
556 if (tmpMinBandwidth == 0)
557 {
558 tmpFfrRbStartOffset = index;
559 }
560 tmpMinBandwidth++;
561 }
562 index++;
563 }
564
565 if (tmpMinBandwidth > maxContinuousUlBandwidth)
566 {
567 maxContinuousUlBandwidth = tmpMinBandwidth;
568 ffrRbStartOffset = tmpFfrRbStartOffset;
569 }
570
571 m_rachAllocationMap.resize(m_cschedCellConfig.m_ulBandwidth, 0);
572 uint16_t rbStart = 0;
573 rbStart = ffrRbStartOffset;
574 for (auto itRach = m_rachList.begin(); itRach != m_rachList.end(); itRach++)
575 {
576 NS_ASSERT_MSG(m_amc->GetUlTbSizeFromMcs(m_ulGrantMcs, m_cschedCellConfig.m_ulBandwidth) >
577 (*itRach).m_estimatedSize,
578 " Default UL Grant MCS does not allow to send RACH messages");
580 newRar.m_rnti = (*itRach).m_rnti;
581 // DL-RACH Allocation
582 // Ideal: no needs of configuring m_dci
583 // UL-RACH Allocation
584 newRar.m_grant.m_rnti = newRar.m_rnti;
585 newRar.m_grant.m_mcs = m_ulGrantMcs;
586 uint16_t rbLen = 1;
587 uint16_t tbSizeBits = 0;
588 // find lowest TB size that fits UL grant estimated size
589 while ((tbSizeBits < (*itRach).m_estimatedSize) &&
590 (rbStart + rbLen < (ffrRbStartOffset + maxContinuousUlBandwidth)))
591 {
592 rbLen++;
593 tbSizeBits = m_amc->GetUlTbSizeFromMcs(m_ulGrantMcs, rbLen);
594 }
595 if (tbSizeBits < (*itRach).m_estimatedSize)
596 {
597 // no more allocation space: finish allocation
598 break;
599 }
600 newRar.m_grant.m_rbStart = rbStart;
601 newRar.m_grant.m_rbLen = rbLen;
602 newRar.m_grant.m_tbSize = tbSizeBits / 8;
603 newRar.m_grant.m_hopping = false;
604 newRar.m_grant.m_tpc = 0;
605 newRar.m_grant.m_cqiRequest = false;
606 newRar.m_grant.m_ulDelay = false;
607 NS_LOG_INFO(this << " UL grant allocated to RNTI " << (*itRach).m_rnti << " rbStart "
608 << rbStart << " rbLen " << rbLen << " MCS " << m_ulGrantMcs << " tbSize "
609 << newRar.m_grant.m_tbSize);
610 for (uint16_t i = rbStart; i < rbStart + rbLen; i++)
611 {
612 m_rachAllocationMap.at(i) = (*itRach).m_rnti;
613 }
614
615 if (m_harqOn)
616 {
617 // generate UL-DCI for HARQ retransmissions
618 UlDciListElement_s uldci;
619 uldci.m_rnti = newRar.m_rnti;
620 uldci.m_rbLen = rbLen;
621 uldci.m_rbStart = rbStart;
622 uldci.m_mcs = m_ulGrantMcs;
623 uldci.m_tbSize = tbSizeBits / 8;
624 uldci.m_ndi = 1;
625 uldci.m_cceIndex = 0;
626 uldci.m_aggrLevel = 1;
627 uldci.m_ueTxAntennaSelection = 3; // antenna selection OFF
628 uldci.m_hopping = false;
629 uldci.m_n2Dmrs = 0;
630 uldci.m_tpc = 0; // no power control
631 uldci.m_cqiRequest = false; // only period CQI at this stage
632 uldci.m_ulIndex = 0; // TDD parameter
633 uldci.m_dai = 1; // TDD parameter
634 uldci.m_freqHopping = 0;
635 uldci.m_pdcchPowerOffset = 0; // not used
636
637 uint8_t harqId = 0;
638 auto itProcId = m_ulHarqCurrentProcessId.find(uldci.m_rnti);
639 if (itProcId == m_ulHarqCurrentProcessId.end())
640 {
641 NS_FATAL_ERROR("No info find in HARQ buffer for UE " << uldci.m_rnti);
642 }
643 harqId = (*itProcId).second;
644 auto itDci = m_ulHarqProcessesDciBuffer.find(uldci.m_rnti);
645 if (itDci == m_ulHarqProcessesDciBuffer.end())
646 {
647 NS_FATAL_ERROR("Unable to find RNTI entry in UL DCI HARQ buffer for RNTI "
648 << uldci.m_rnti);
649 }
650 (*itDci).second.at(harqId) = uldci;
651 }
652
653 rbStart = rbStart + rbLen;
654 ret.m_buildRarList.push_back(newRar);
655 }
656 m_rachList.clear();
657
658 // Process DL HARQ feedback
660 // retrieve past HARQ retx buffered
661 if (!m_dlInfoListBuffered.empty())
662 {
663 if (!params.m_dlInfoList.empty())
664 {
665 NS_LOG_INFO(this << " Received DL-HARQ feedback");
667 params.m_dlInfoList.begin(),
668 params.m_dlInfoList.end());
669 }
670 }
671 else
672 {
673 if (!params.m_dlInfoList.empty())
674 {
675 m_dlInfoListBuffered = params.m_dlInfoList;
676 }
677 }
678 if (!m_harqOn)
679 {
680 // Ignore HARQ feedback
681 m_dlInfoListBuffered.clear();
682 }
683 std::vector<DlInfoListElement_s> dlInfoListUntxed;
684 for (std::size_t i = 0; i < m_dlInfoListBuffered.size(); i++)
685 {
686 auto itRnti = rntiAllocated.find(m_dlInfoListBuffered.at(i).m_rnti);
687 if (itRnti != rntiAllocated.end())
688 {
689 // RNTI already allocated for retx
690 continue;
691 }
692 auto nLayers = m_dlInfoListBuffered.at(i).m_harqStatus.size();
693 std::vector<bool> retx;
694 retx.reserve(2);
695 NS_LOG_INFO(this << " Processing DLHARQ feedback");
696 if (nLayers == 1)
697 {
698 retx.emplace_back(m_dlInfoListBuffered.at(i).m_harqStatus.at(0) ==
700 retx.emplace_back(false);
701 }
702 else
703 {
704 retx.emplace_back(m_dlInfoListBuffered.at(i).m_harqStatus.at(0) ==
706 retx.emplace_back(m_dlInfoListBuffered.at(i).m_harqStatus.at(1) ==
708 }
709 if (retx.at(0) || retx.at(1))
710 {
711 // retrieve HARQ process information
712 uint16_t rnti = m_dlInfoListBuffered.at(i).m_rnti;
713 uint8_t harqId = m_dlInfoListBuffered.at(i).m_harqProcessId;
714 NS_LOG_INFO(this << " HARQ retx RNTI " << rnti << " harqId " << (uint16_t)harqId);
715 auto itHarq = m_dlHarqProcessesDciBuffer.find(rnti);
716 if (itHarq == m_dlHarqProcessesDciBuffer.end())
717 {
718 NS_FATAL_ERROR("No info find in HARQ buffer for UE " << rnti);
719 }
720
721 DlDciListElement_s dci = (*itHarq).second.at(harqId);
722 int rv = 0;
723 if (dci.m_rv.size() == 1)
724 {
725 rv = dci.m_rv.at(0);
726 }
727 else
728 {
729 rv = (dci.m_rv.at(0) > dci.m_rv.at(1) ? dci.m_rv.at(0) : dci.m_rv.at(1));
730 }
731
732 if (rv == 3)
733 {
734 // maximum number of retx reached -> drop process
735 NS_LOG_INFO("Maximum number of retransmissions reached -> drop process");
736 auto it = m_dlHarqProcessesStatus.find(rnti);
737 if (it == m_dlHarqProcessesStatus.end())
738 {
739 NS_LOG_ERROR("No info find in HARQ buffer for UE (might change eNB) "
740 << m_dlInfoListBuffered.at(i).m_rnti);
741 }
742 (*it).second.at(harqId) = 0;
743 auto itRlcPdu = m_dlHarqProcessesRlcPduListBuffer.find(rnti);
744 if (itRlcPdu == m_dlHarqProcessesRlcPduListBuffer.end())
745 {
746 NS_FATAL_ERROR("Unable to find RlcPdcList in HARQ buffer for RNTI "
747 << m_dlInfoListBuffered.at(i).m_rnti);
748 }
749 for (std::size_t k = 0; k < (*itRlcPdu).second.size(); k++)
750 {
751 (*itRlcPdu).second.at(k).at(harqId).clear();
752 }
753 continue;
754 }
755 // check the feasibility of retransmitting on the same RBGs
756 // translate the DCI to Spectrum framework
757 std::vector<int> dciRbg;
758 uint32_t mask = 0x1;
759 NS_LOG_INFO("Original RBGs " << dci.m_rbBitmap << " rnti " << dci.m_rnti);
760 for (int j = 0; j < 32; j++)
761 {
762 if (((dci.m_rbBitmap & mask) >> j) == 1)
763 {
764 dciRbg.push_back(j);
765 NS_LOG_INFO("\t" << j);
766 }
767 mask = (mask << 1);
768 }
769 bool free = true;
770 for (std::size_t j = 0; j < dciRbg.size(); j++)
771 {
772 if (rbgMap.at(dciRbg.at(j)))
773 {
774 free = false;
775 break;
776 }
777 }
778 if (free)
779 {
780 // use the same RBGs for the retx
781 // reserve RBGs
782 for (std::size_t j = 0; j < dciRbg.size(); j++)
783 {
784 rbgMap.at(dciRbg.at(j)) = true;
785 NS_LOG_INFO("RBG " << dciRbg.at(j) << " assigned");
786 rbgAllocatedNum++;
787 }
788
789 NS_LOG_INFO(this << " Send retx in the same RBGs");
790 }
791 else
792 {
793 // find RBGs for sending HARQ retx
794 uint8_t j = 0;
795 uint8_t rbgId = (dciRbg.at(dciRbg.size() - 1) + 1) % rbgNum;
796 uint8_t startRbg = dciRbg.at(dciRbg.size() - 1);
797 std::vector<bool> rbgMapCopy = rbgMap;
798 while ((j < dciRbg.size()) && (startRbg != rbgId))
799 {
800 if (!rbgMapCopy.at(rbgId))
801 {
802 rbgMapCopy.at(rbgId) = true;
803 dciRbg.at(j) = rbgId;
804 j++;
805 }
806 rbgId = (rbgId + 1) % rbgNum;
807 }
808 if (j == dciRbg.size())
809 {
810 // find new RBGs -> update DCI map
811 uint32_t rbgMask = 0;
812 for (std::size_t k = 0; k < dciRbg.size(); k++)
813 {
814 rbgMask = rbgMask + (0x1 << dciRbg.at(k));
815 rbgAllocatedNum++;
816 }
817 dci.m_rbBitmap = rbgMask;
818 rbgMap = rbgMapCopy;
819 NS_LOG_INFO(this << " Move retx in RBGs " << dciRbg.size());
820 }
821 else
822 {
823 // HARQ retx cannot be performed on this TTI -> store it
824 dlInfoListUntxed.push_back(m_dlInfoListBuffered.at(i));
825 NS_LOG_INFO(this << " No resource for this retx -> buffer it");
826 }
827 }
828 // retrieve RLC PDU list for retx TBsize and update DCI
830 auto itRlcPdu = m_dlHarqProcessesRlcPduListBuffer.find(rnti);
831 if (itRlcPdu == m_dlHarqProcessesRlcPduListBuffer.end())
832 {
833 NS_FATAL_ERROR("Unable to find RlcPdcList in HARQ buffer for RNTI " << rnti);
834 }
835 for (std::size_t j = 0; j < nLayers; j++)
836 {
837 if (retx.at(j))
838 {
839 if (j >= dci.m_ndi.size())
840 {
841 // for avoiding errors in MIMO transient phases
842 dci.m_ndi.push_back(0);
843 dci.m_rv.push_back(0);
844 dci.m_mcs.push_back(0);
845 dci.m_tbsSize.push_back(0);
846 NS_LOG_INFO(this << " layer " << (uint16_t)j
847 << " no txed (MIMO transition)");
848 }
849 else
850 {
851 dci.m_ndi.at(j) = 0;
852 dci.m_rv.at(j)++;
853 (*itHarq).second.at(harqId).m_rv.at(j)++;
854 NS_LOG_INFO(this << " layer " << (uint16_t)j << " RV "
855 << (uint16_t)dci.m_rv.at(j));
856 }
857 }
858 else
859 {
860 // empty TB of layer j
861 dci.m_ndi.at(j) = 0;
862 dci.m_rv.at(j) = 0;
863 dci.m_mcs.at(j) = 0;
864 dci.m_tbsSize.at(j) = 0;
865 NS_LOG_INFO(this << " layer " << (uint16_t)j << " no retx");
866 }
867 }
868 for (std::size_t k = 0; k < (*itRlcPdu).second.at(0).at(dci.m_harqProcess).size(); k++)
869 {
870 std::vector<RlcPduListElement_s> rlcPduListPerLc;
871 for (std::size_t j = 0; j < nLayers; j++)
872 {
873 if (retx.at(j))
874 {
875 if (j < dci.m_ndi.size())
876 {
877 NS_LOG_INFO(" layer " << (uint16_t)j << " tb size "
878 << dci.m_tbsSize.at(j));
879 rlcPduListPerLc.push_back(
880 (*itRlcPdu).second.at(j).at(dci.m_harqProcess).at(k));
881 }
882 }
883 else
884 { // if no retx needed on layer j, push an RlcPduListElement_s object with
885 // m_size=0 to keep the size of rlcPduListPerLc vector = 2 in case of MIMO
886 NS_LOG_INFO(" layer " << (uint16_t)j << " tb size " << dci.m_tbsSize.at(j));
887 RlcPduListElement_s emptyElement;
888 emptyElement.m_logicalChannelIdentity = (*itRlcPdu)
889 .second.at(j)
890 .at(dci.m_harqProcess)
891 .at(k)
892 .m_logicalChannelIdentity;
893 emptyElement.m_size = 0;
894 rlcPduListPerLc.push_back(emptyElement);
895 }
896 }
897
898 if (!rlcPduListPerLc.empty())
899 {
900 newEl.m_rlcPduList.push_back(rlcPduListPerLc);
901 }
902 }
903 newEl.m_rnti = rnti;
904 newEl.m_dci = dci;
905 (*itHarq).second.at(harqId).m_rv = dci.m_rv;
906 // refresh timer
907 auto itHarqTimer = m_dlHarqProcessesTimer.find(rnti);
908 if (itHarqTimer == m_dlHarqProcessesTimer.end())
909 {
910 NS_FATAL_ERROR("Unable to find HARQ timer for RNTI " << (uint16_t)rnti);
911 }
912 (*itHarqTimer).second.at(harqId) = 0;
913 ret.m_buildDataList.push_back(newEl);
914 rntiAllocated.insert(rnti);
915 }
916 else
917 {
918 // update HARQ process status
919 NS_LOG_INFO(this << " HARQ received ACK for UE " << m_dlInfoListBuffered.at(i).m_rnti);
920 auto it = m_dlHarqProcessesStatus.find(m_dlInfoListBuffered.at(i).m_rnti);
921 if (it == m_dlHarqProcessesStatus.end())
922 {
923 NS_FATAL_ERROR("No info find in HARQ buffer for UE "
924 << m_dlInfoListBuffered.at(i).m_rnti);
925 }
926 (*it).second.at(m_dlInfoListBuffered.at(i).m_harqProcessId) = 0;
927 auto itRlcPdu =
929 if (itRlcPdu == m_dlHarqProcessesRlcPduListBuffer.end())
930 {
931 NS_FATAL_ERROR("Unable to find RlcPdcList in HARQ buffer for RNTI "
932 << m_dlInfoListBuffered.at(i).m_rnti);
933 }
934 for (std::size_t k = 0; k < (*itRlcPdu).second.size(); k++)
935 {
936 (*itRlcPdu).second.at(k).at(m_dlInfoListBuffered.at(i).m_harqProcessId).clear();
937 }
938 }
939 }
940 m_dlInfoListBuffered.clear();
941 m_dlInfoListBuffered = dlInfoListUntxed;
942
943 if (rbgAllocatedNum == rbgNum)
944 {
945 // all the RBGs are already allocated -> exit
946 if (!ret.m_buildDataList.empty() || !ret.m_buildRarList.empty())
947 {
948 m_schedSapUser->SchedDlConfigInd(ret);
949 }
950 return;
951 }
952
953 // update token pool, counter and bank size
954 for (auto itStats = m_flowStatsDl.begin(); itStats != m_flowStatsDl.end(); itStats++)
955 {
956 if ((*itStats).second.tokenGenerationRate / 1000 + (*itStats).second.tokenPoolSize >
957 (*itStats).second.maxTokenPoolSize)
958 {
959 (*itStats).second.counter +=
960 (*itStats).second.tokenGenerationRate / 1000 -
961 ((*itStats).second.maxTokenPoolSize - (*itStats).second.tokenPoolSize);
962 (*itStats).second.tokenPoolSize = (*itStats).second.maxTokenPoolSize;
963 bankSize += (*itStats).second.tokenGenerationRate / 1000 -
964 ((*itStats).second.maxTokenPoolSize - (*itStats).second.tokenPoolSize);
965 }
966 else
967 {
968 (*itStats).second.tokenPoolSize += (*itStats).second.tokenGenerationRate / 1000;
969 }
970 }
971
972 // select UE with largest metric
973 auto itMax = m_flowStatsDl.end();
974 double metricMax = 0.0;
975 bool firstRnti = true;
976 for (auto it = m_flowStatsDl.begin(); it != m_flowStatsDl.end(); it++)
977 {
978 auto itRnti = rntiAllocated.find((*it).first);
979 if ((itRnti != rntiAllocated.end()) || (!HarqProcessAvailability((*it).first)))
980 {
981 // UE already allocated for HARQ or without HARQ process available -> drop it
982 if (itRnti != rntiAllocated.end())
983 {
984 NS_LOG_DEBUG(this << " RNTI discarded for HARQ tx" << (uint16_t)(*it).first);
985 }
986 if (!HarqProcessAvailability((*it).first))
987 {
988 NS_LOG_DEBUG(this << " RNTI discarded for HARQ id" << (uint16_t)(*it).first);
989 }
990 continue;
991 }
992
993 // check first the channel conditions for this UE, if CQI!=0
994 auto itCqi = m_a30CqiRxed.find((*it).first);
995 auto itTxMode = m_uesTxMode.find((*it).first);
996 if (itTxMode == m_uesTxMode.end())
997 {
998 NS_FATAL_ERROR("No Transmission Mode info on user " << (*it).first);
999 }
1000 auto nLayer = TransmissionModesLayers::TxMode2LayerNum((*itTxMode).second);
1001
1002 uint8_t cqiSum = 0;
1003 for (int k = 0; k < rbgNum; k++)
1004 {
1005 for (uint8_t j = 0; j < nLayer; j++)
1006 {
1007 if (itCqi == m_a30CqiRxed.end())
1008 {
1009 cqiSum += 1; // no info on this user -> lowest MCS
1010 }
1011 else
1012 {
1013 cqiSum += (*itCqi).second.m_higherLayerSelected.at(k).m_sbCqi.at(j);
1014 }
1015 }
1016 }
1017
1018 if (cqiSum == 0)
1019 {
1020 NS_LOG_INFO("Skip this flow, CQI==0, rnti:" << (*it).first);
1021 continue;
1022 }
1023
1024 /*
1025 if (LcActivePerFlow ((*it).first) == 0)
1026 {
1027 continue;
1028 }
1029 */
1030
1031 double metric =
1032 (((double)(*it).second.counter) / ((double)(*it).second.tokenGenerationRate));
1033
1034 if (firstRnti)
1035 {
1036 metricMax = metric;
1037 itMax = it;
1038 firstRnti = false;
1039 continue;
1040 }
1041 if (metric > metricMax)
1042 {
1043 metricMax = metric;
1044 itMax = it;
1045 }
1046 }
1047
1048 if (itMax == m_flowStatsDl.end())
1049 {
1050 // all UEs are allocated RBG or all UEs already allocated for HARQ or without HARQ process
1051 // available
1052 return;
1053 }
1054 else
1055 {
1056 // assign all RBGs to this UE
1057 std::vector<uint16_t> tempMap;
1058 for (int i = 0; i < rbgNum; i++)
1059 {
1060 if (rbgMap.at(i))
1061 { // this RBG is allocated in RACH procedure
1062 continue;
1063 }
1064
1065 if (!m_ffrSapProvider->IsDlRbgAvailableForUe(i, (*itMax).first))
1066 {
1067 continue;
1068 }
1069
1070 tempMap.push_back(i);
1071 rbgMap.at(i) = true;
1072 }
1073 if (!tempMap.empty())
1074 {
1075 allocationMap[(*itMax).first] = tempMap;
1076 }
1077 }
1078
1079 // generate the transmission opportunities by grouping the RBGs of the same RNTI and
1080 // creating the correspondent DCIs
1081 auto itMap = allocationMap.begin();
1082 while (itMap != allocationMap.end())
1083 {
1084 // create new BuildDataListElement_s for this LC
1086 newEl.m_rnti = (*itMap).first;
1087 // create the DlDciListElement_s
1088 DlDciListElement_s newDci;
1089 newDci.m_rnti = (*itMap).first;
1090 newDci.m_harqProcess = UpdateHarqProcessId((*itMap).first);
1091
1092 uint16_t lcActives = LcActivePerFlow((*itMap).first);
1093 NS_LOG_INFO(this << "Allocate user " << newEl.m_rnti << " rbg " << lcActives);
1094 if (lcActives == 0)
1095 {
1096 // Set to max value, to avoid divide by 0 below
1097 lcActives = (uint16_t)65535; // UINT16_MAX;
1098 }
1099 uint16_t RbgPerRnti = (*itMap).second.size();
1100 auto itCqi = m_a30CqiRxed.find((*itMap).first);
1101 auto itTxMode = m_uesTxMode.find((*itMap).first);
1102 if (itTxMode == m_uesTxMode.end())
1103 {
1104 NS_FATAL_ERROR("No Transmission Mode info on user " << (*itMap).first);
1105 }
1106 auto nLayer = TransmissionModesLayers::TxMode2LayerNum((*itTxMode).second);
1107 std::vector<uint8_t> worstCqi(2, 15);
1108 if (itCqi != m_a30CqiRxed.end())
1109 {
1110 for (std::size_t k = 0; k < (*itMap).second.size(); k++)
1111 {
1112 if ((*itCqi).second.m_higherLayerSelected.size() > (*itMap).second.at(k))
1113 {
1114 for (uint8_t j = 0; j < nLayer; j++)
1115 {
1116 if ((*itCqi)
1117 .second.m_higherLayerSelected.at((*itMap).second.at(k))
1118 .m_sbCqi.size() > j)
1119 {
1120 if (((*itCqi)
1121 .second.m_higherLayerSelected.at((*itMap).second.at(k))
1122 .m_sbCqi.at(j)) < worstCqi.at(j))
1123 {
1124 worstCqi.at(j) =
1125 ((*itCqi)
1126 .second.m_higherLayerSelected.at((*itMap).second.at(k))
1127 .m_sbCqi.at(j));
1128 }
1129 }
1130 else
1131 {
1132 // no CQI for this layer of this suband -> worst one
1133 worstCqi.at(j) = 1;
1134 }
1135 }
1136 }
1137 else
1138 {
1139 for (uint8_t j = 0; j < nLayer; j++)
1140 {
1141 worstCqi.at(j) = 1; // try with lowest MCS in RBG with no info on channel
1142 }
1143 }
1144 }
1145 }
1146 else
1147 {
1148 for (uint8_t j = 0; j < nLayer; j++)
1149 {
1150 worstCqi.at(j) = 1; // try with lowest MCS in RBG with no info on channel
1151 }
1152 }
1153 uint32_t bytesTxed = 0;
1154 for (uint8_t j = 0; j < nLayer; j++)
1155 {
1156 newDci.m_mcs.push_back(m_amc->GetMcsFromCqi(worstCqi.at(j)));
1157 int tbSize = (m_amc->GetDlTbSizeFromMcs(newDci.m_mcs.at(j), RbgPerRnti * rbgSize) /
1158 8); // (size of TB in bytes according to table 7.1.7.2.1-1 of 36.213)
1159 newDci.m_tbsSize.push_back(tbSize);
1160 bytesTxed += tbSize;
1161 }
1162
1163 newDci.m_resAlloc = 0; // only allocation type 0 at this stage
1164 newDci.m_rbBitmap = 0; // TBD (32 bit bitmap see 7.1.6 of 36.213)
1165 uint32_t rbgMask = 0;
1166 for (std::size_t k = 0; k < (*itMap).second.size(); k++)
1167 {
1168 rbgMask = rbgMask + (0x1 << (*itMap).second.at(k));
1169 NS_LOG_INFO(this << " Allocated RBG " << (*itMap).second.at(k));
1170 }
1171 newDci.m_rbBitmap = rbgMask; // (32 bit bitmap see 7.1.6 of 36.213)
1172
1173 // create the rlc PDUs -> equally divide resources among actives LCs
1174 for (auto itBufReq = m_rlcBufferReq.begin(); itBufReq != m_rlcBufferReq.end(); itBufReq++)
1175 {
1176 if (((*itBufReq).first.m_rnti == (*itMap).first) &&
1177 (((*itBufReq).second.m_rlcTransmissionQueueSize > 0) ||
1178 ((*itBufReq).second.m_rlcRetransmissionQueueSize > 0) ||
1179 ((*itBufReq).second.m_rlcStatusPduSize > 0)))
1180 {
1181 std::vector<RlcPduListElement_s> newRlcPduLe;
1182 for (uint8_t j = 0; j < nLayer; j++)
1183 {
1184 RlcPduListElement_s newRlcEl;
1185 newRlcEl.m_logicalChannelIdentity = (*itBufReq).first.m_lcId;
1186 newRlcEl.m_size = newDci.m_tbsSize.at(j) / lcActives;
1187 NS_LOG_INFO(this << " LCID " << (uint32_t)newRlcEl.m_logicalChannelIdentity
1188 << " size " << newRlcEl.m_size << " layer " << (uint16_t)j);
1189 newRlcPduLe.push_back(newRlcEl);
1191 newRlcEl.m_logicalChannelIdentity,
1192 newRlcEl.m_size);
1193 if (m_harqOn)
1194 {
1195 // store RLC PDU list for HARQ
1196 auto itRlcPdu = m_dlHarqProcessesRlcPduListBuffer.find((*itMap).first);
1197 if (itRlcPdu == m_dlHarqProcessesRlcPduListBuffer.end())
1198 {
1199 NS_FATAL_ERROR("Unable to find RlcPdcList in HARQ buffer for RNTI "
1200 << (*itMap).first);
1201 }
1202 (*itRlcPdu).second.at(j).at(newDci.m_harqProcess).push_back(newRlcEl);
1203 }
1204 }
1205 newEl.m_rlcPduList.push_back(newRlcPduLe);
1206 }
1207 if ((*itBufReq).first.m_rnti > (*itMap).first)
1208 {
1209 break;
1210 }
1211 }
1212 for (uint8_t j = 0; j < nLayer; j++)
1213 {
1214 newDci.m_ndi.push_back(1);
1215 newDci.m_rv.push_back(0);
1216 }
1217
1218 newDci.m_tpc = m_ffrSapProvider->GetTpc((*itMap).first);
1219
1220 newEl.m_dci = newDci;
1221
1222 if (m_harqOn)
1223 {
1224 // store DCI for HARQ
1225 auto itDci = m_dlHarqProcessesDciBuffer.find(newEl.m_rnti);
1226 if (itDci == m_dlHarqProcessesDciBuffer.end())
1227 {
1228 NS_FATAL_ERROR("Unable to find RNTI entry in DCI HARQ buffer for RNTI "
1229 << newEl.m_rnti);
1230 }
1231 (*itDci).second.at(newDci.m_harqProcess) = newDci;
1232 // refresh timer
1233 auto itHarqTimer = m_dlHarqProcessesTimer.find(newEl.m_rnti);
1234 if (itHarqTimer == m_dlHarqProcessesTimer.end())
1235 {
1236 NS_FATAL_ERROR("Unable to find HARQ timer for RNTI " << (uint16_t)newEl.m_rnti);
1237 }
1238 (*itHarqTimer).second.at(newDci.m_harqProcess) = 0;
1239 }
1240
1241 // update UE stats
1242 if (bytesTxed <= (*itMax).second.tokenPoolSize)
1243 {
1244 (*itMax).second.tokenPoolSize -= bytesTxed;
1245 }
1246 else
1247 {
1248 (*itMax).second.counter =
1249 (*itMax).second.counter - (bytesTxed - (*itMax).second.tokenPoolSize);
1250 (*itMax).second.tokenPoolSize = 0;
1251 if (bankSize <= (bytesTxed - (*itMax).second.tokenPoolSize))
1252 {
1253 bankSize = 0;
1254 }
1255 else
1256 {
1257 bankSize = bankSize - (bytesTxed - (*itMax).second.tokenPoolSize);
1258 }
1259 }
1260
1261 // ...more parameters -> ignored in this version
1262
1263 ret.m_buildDataList.push_back(newEl);
1264
1265 itMap++;
1266 }
1267 ret.m_nrOfPdcchOfdmSymbols = 1; /// \todo check correct value according the DCIs txed
1268
1269 m_schedSapUser->SchedDlConfigInd(ret);
1270}
1271
1272void
1280
1281void
1284{
1285 NS_LOG_FUNCTION(this);
1286 m_ffrSapProvider->ReportDlCqiInfo(params);
1287
1288 for (unsigned int i = 0; i < params.m_cqiList.size(); i++)
1289 {
1290 if (params.m_cqiList.at(i).m_cqiType == CqiListElement_s::P10)
1291 {
1292 NS_LOG_LOGIC("wideband CQI " << (uint32_t)params.m_cqiList.at(i).m_wbCqi.at(0)
1293 << " reported");
1294 uint16_t rnti = params.m_cqiList.at(i).m_rnti;
1295 auto it = m_p10CqiRxed.find(rnti);
1296 if (it == m_p10CqiRxed.end())
1297 {
1298 // create the new entry
1299 m_p10CqiRxed[rnti] =
1300 params.m_cqiList.at(i).m_wbCqi.at(0); // only codeword 0 at this stage (SISO)
1301 // generate correspondent timer
1303 }
1304 else
1305 {
1306 // update the CQI value and refresh correspondent timer
1307 (*it).second = params.m_cqiList.at(i).m_wbCqi.at(0);
1308 // update correspondent timer
1309 auto itTimers = m_p10CqiTimers.find(rnti);
1310 (*itTimers).second = m_cqiTimersThreshold;
1311 }
1312 }
1313 else if (params.m_cqiList.at(i).m_cqiType == CqiListElement_s::A30)
1314 {
1315 // subband CQI reporting high layer configured
1316 uint16_t rnti = params.m_cqiList.at(i).m_rnti;
1317 auto it = m_a30CqiRxed.find(rnti);
1318 if (it == m_a30CqiRxed.end())
1319 {
1320 // create the new entry
1321 m_a30CqiRxed[rnti] = params.m_cqiList.at(i).m_sbMeasResult;
1323 }
1324 else
1325 {
1326 // update the CQI value and refresh correspondent timer
1327 (*it).second = params.m_cqiList.at(i).m_sbMeasResult;
1328 auto itTimers = m_a30CqiTimers.find(rnti);
1329 (*itTimers).second = m_cqiTimersThreshold;
1330 }
1331 }
1332 else
1333 {
1334 NS_LOG_ERROR(this << " CQI type unknown");
1335 }
1336 }
1337}
1338
1339double
1340TdTbfqFfMacScheduler::EstimateUlSinr(uint16_t rnti, uint16_t rb)
1341{
1342 auto itCqi = m_ueCqi.find(rnti);
1343 if (itCqi == m_ueCqi.end())
1344 {
1345 // no cqi info about this UE
1346 return NO_SINR;
1347 }
1348 else
1349 {
1350 // take the average SINR value among the available
1351 double sinrSum = 0;
1352 unsigned int sinrNum = 0;
1353 for (uint32_t i = 0; i < m_cschedCellConfig.m_ulBandwidth; i++)
1354 {
1355 double sinr = (*itCqi).second.at(i);
1356 if (sinr != NO_SINR)
1357 {
1358 sinrSum += sinr;
1359 sinrNum++;
1360 }
1361 }
1362 double estimatedSinr = (sinrNum > 0) ? (sinrSum / sinrNum) : DBL_MAX;
1363 // store the value
1364 (*itCqi).second.at(rb) = estimatedSinr;
1365 return estimatedSinr;
1366 }
1367}
1368
1369void
1372{
1373 NS_LOG_FUNCTION(this << " UL - Frame no. " << (params.m_sfnSf >> 4) << " subframe no. "
1374 << (0xF & params.m_sfnSf) << " size " << params.m_ulInfoList.size());
1375
1377 m_ffrSapProvider->ReportUlCqiInfo(m_ueCqi);
1378
1379 // Generate RBs map
1381 std::vector<bool> rbMap;
1382 uint16_t rbAllocatedNum = 0;
1383 std::set<uint16_t> rntiAllocated;
1384 std::vector<uint16_t> rbgAllocationMap;
1385 // update with RACH allocation map
1386 rbgAllocationMap = m_rachAllocationMap;
1387 // rbgAllocationMap.resize (m_cschedCellConfig.m_ulBandwidth, 0);
1388 m_rachAllocationMap.clear();
1389 m_rachAllocationMap.resize(m_cschedCellConfig.m_ulBandwidth, 0);
1390
1391 rbMap.resize(m_cschedCellConfig.m_ulBandwidth, false);
1392
1393 rbMap = m_ffrSapProvider->GetAvailableUlRbg();
1394
1395 for (auto it = rbMap.begin(); it != rbMap.end(); it++)
1396 {
1397 if (*it)
1398 {
1399 rbAllocatedNum++;
1400 }
1401 }
1402
1403 uint8_t minContinuousUlBandwidth = m_ffrSapProvider->GetMinContinuousUlBandwidth();
1404 uint8_t ffrUlBandwidth = m_cschedCellConfig.m_ulBandwidth - rbAllocatedNum;
1405
1406 // remove RACH allocation
1407 for (uint16_t i = 0; i < m_cschedCellConfig.m_ulBandwidth; i++)
1408 {
1409 if (rbgAllocationMap.at(i) != 0)
1410 {
1411 rbMap.at(i) = true;
1412 NS_LOG_DEBUG(this << " Allocated for RACH " << i);
1413 }
1414 }
1415
1416 if (m_harqOn)
1417 {
1418 // Process UL HARQ feedback
1419 for (std::size_t i = 0; i < params.m_ulInfoList.size(); i++)
1420 {
1421 if (params.m_ulInfoList.at(i).m_receptionStatus == UlInfoListElement_s::NotOk)
1422 {
1423 // retx correspondent block: retrieve the UL-DCI
1424 uint16_t rnti = params.m_ulInfoList.at(i).m_rnti;
1425 auto itProcId = m_ulHarqCurrentProcessId.find(rnti);
1426 if (itProcId == m_ulHarqCurrentProcessId.end())
1427 {
1428 NS_LOG_ERROR("No info find in HARQ buffer for UE (might change eNB) " << rnti);
1429 }
1430 uint8_t harqId = (uint8_t)((*itProcId).second - HARQ_PERIOD) % HARQ_PROC_NUM;
1431 NS_LOG_INFO(this << " UL-HARQ retx RNTI " << rnti << " harqId " << (uint16_t)harqId
1432 << " i " << i << " size " << params.m_ulInfoList.size());
1433 auto itHarq = m_ulHarqProcessesDciBuffer.find(rnti);
1434 if (itHarq == m_ulHarqProcessesDciBuffer.end())
1435 {
1436 NS_LOG_ERROR("No info find in HARQ buffer for UE (might change eNB) " << rnti);
1437 continue;
1438 }
1439 UlDciListElement_s dci = (*itHarq).second.at(harqId);
1440 auto itStat = m_ulHarqProcessesStatus.find(rnti);
1441 if (itStat == m_ulHarqProcessesStatus.end())
1442 {
1443 NS_LOG_ERROR("No info find in HARQ buffer for UE (might change eNB) " << rnti);
1444 }
1445 if ((*itStat).second.at(harqId) >= 3)
1446 {
1447 NS_LOG_INFO("Max number of retransmissions reached (UL)-> drop process");
1448 continue;
1449 }
1450 bool free = true;
1451 for (int j = dci.m_rbStart; j < dci.m_rbStart + dci.m_rbLen; j++)
1452 {
1453 if (rbMap.at(j))
1454 {
1455 free = false;
1456 NS_LOG_INFO(this << " BUSY " << j);
1457 }
1458 }
1459 if (free)
1460 {
1461 // retx on the same RBs
1462 for (int j = dci.m_rbStart; j < dci.m_rbStart + dci.m_rbLen; j++)
1463 {
1464 rbMap.at(j) = true;
1465 rbgAllocationMap.at(j) = dci.m_rnti;
1466 NS_LOG_INFO("\tRB " << j);
1467 rbAllocatedNum++;
1468 }
1469 NS_LOG_INFO(this << " Send retx in the same RBs " << (uint16_t)dci.m_rbStart
1470 << " to " << dci.m_rbStart + dci.m_rbLen << " RV "
1471 << (*itStat).second.at(harqId) + 1);
1472 }
1473 else
1474 {
1475 NS_LOG_INFO("Cannot allocate retx due to RACH allocations for UE " << rnti);
1476 continue;
1477 }
1478 dci.m_ndi = 0;
1479 // Update HARQ buffers with new HarqId
1480 (*itStat).second.at((*itProcId).second) = (*itStat).second.at(harqId) + 1;
1481 (*itStat).second.at(harqId) = 0;
1482 (*itHarq).second.at((*itProcId).second) = dci;
1483 ret.m_dciList.push_back(dci);
1484 rntiAllocated.insert(dci.m_rnti);
1485 }
1486 else
1487 {
1488 NS_LOG_INFO(this << " HARQ-ACK feedback from RNTI "
1489 << params.m_ulInfoList.at(i).m_rnti);
1490 }
1491 }
1492 }
1493
1494 std::map<uint16_t, uint32_t>::iterator it;
1495 int nflows = 0;
1496
1497 for (it = m_ceBsrRxed.begin(); it != m_ceBsrRxed.end(); it++)
1498 {
1499 auto itRnti = rntiAllocated.find((*it).first);
1500 // select UEs with queues not empty and not yet allocated for HARQ
1501 if (((*it).second > 0) && (itRnti == rntiAllocated.end()))
1502 {
1503 nflows++;
1504 }
1505 }
1506
1507 if (nflows == 0)
1508 {
1509 if (!ret.m_dciList.empty())
1510 {
1511 m_allocationMaps[params.m_sfnSf] = rbgAllocationMap;
1512 m_schedSapUser->SchedUlConfigInd(ret);
1513 }
1514
1515 return; // no flows to be scheduled
1516 }
1517
1518 // Divide the remaining resources equally among the active users starting from the subsequent
1519 // one served last scheduling trigger
1520 uint16_t tempRbPerFlow = (ffrUlBandwidth) / (nflows + rntiAllocated.size());
1521 uint16_t rbPerFlow =
1522 (minContinuousUlBandwidth < tempRbPerFlow) ? minContinuousUlBandwidth : tempRbPerFlow;
1523
1524 if (rbPerFlow < 3)
1525 {
1526 rbPerFlow = 3; // at least 3 rbg per flow (till available resource) to ensure TxOpportunity
1527 // >= 7 bytes
1528 }
1529 int rbAllocated = 0;
1530
1531 if (m_nextRntiUl != 0)
1532 {
1533 for (it = m_ceBsrRxed.begin(); it != m_ceBsrRxed.end(); it++)
1534 {
1535 if ((*it).first == m_nextRntiUl)
1536 {
1537 break;
1538 }
1539 }
1540 if (it == m_ceBsrRxed.end())
1541 {
1542 NS_LOG_ERROR(this << " no user found");
1543 }
1544 }
1545 else
1546 {
1547 it = m_ceBsrRxed.begin();
1548 m_nextRntiUl = (*it).first;
1549 }
1550 do
1551 {
1552 auto itRnti = rntiAllocated.find((*it).first);
1553 if ((itRnti != rntiAllocated.end()) || ((*it).second == 0))
1554 {
1555 // UE already allocated for UL-HARQ -> skip it
1556 NS_LOG_DEBUG(this << " UE already allocated in HARQ -> discarded, RNTI "
1557 << (*it).first);
1558 it++;
1559 if (it == m_ceBsrRxed.end())
1560 {
1561 // restart from the first
1562 it = m_ceBsrRxed.begin();
1563 }
1564 continue;
1565 }
1566 if (rbAllocated + rbPerFlow - 1 > m_cschedCellConfig.m_ulBandwidth)
1567 {
1568 // limit to physical resources last resource assignment
1569 rbPerFlow = m_cschedCellConfig.m_ulBandwidth - rbAllocated;
1570 // at least 3 rbg per flow to ensure TxOpportunity >= 7 bytes
1571 if (rbPerFlow < 3)
1572 {
1573 // terminate allocation
1574 rbPerFlow = 0;
1575 }
1576 }
1577
1578 rbAllocated = 0;
1579 UlDciListElement_s uldci;
1580 uldci.m_rnti = (*it).first;
1581 uldci.m_rbLen = rbPerFlow;
1582 bool allocated = false;
1583 NS_LOG_INFO(this << " RB Allocated " << rbAllocated << " rbPerFlow " << rbPerFlow
1584 << " flows " << nflows);
1585 while ((!allocated) && ((rbAllocated + rbPerFlow - m_cschedCellConfig.m_ulBandwidth) < 1) &&
1586 (rbPerFlow != 0))
1587 {
1588 // check availability
1589 bool free = true;
1590 for (int j = rbAllocated; j < rbAllocated + rbPerFlow; j++)
1591 {
1592 if (rbMap.at(j))
1593 {
1594 free = false;
1595 break;
1596 }
1597 if (!m_ffrSapProvider->IsUlRbgAvailableForUe(j, (*it).first))
1598 {
1599 free = false;
1600 break;
1601 }
1602 }
1603 if (free)
1604 {
1605 NS_LOG_INFO(this << "RNTI: " << (*it).first << " RB Allocated " << rbAllocated
1606 << " rbPerFlow " << rbPerFlow << " flows " << nflows);
1607 uldci.m_rbStart = rbAllocated;
1608
1609 for (int j = rbAllocated; j < rbAllocated + rbPerFlow; j++)
1610 {
1611 rbMap.at(j) = true;
1612 // store info on allocation for managing ul-cqi interpretation
1613 rbgAllocationMap.at(j) = (*it).first;
1614 }
1615 rbAllocated += rbPerFlow;
1616 allocated = true;
1617 break;
1618 }
1619 rbAllocated++;
1620 if (rbAllocated + rbPerFlow - 1 > m_cschedCellConfig.m_ulBandwidth)
1621 {
1622 // limit to physical resources last resource assignment
1623 rbPerFlow = m_cschedCellConfig.m_ulBandwidth - rbAllocated;
1624 // at least 3 rbg per flow to ensure TxOpportunity >= 7 bytes
1625 if (rbPerFlow < 3)
1626 {
1627 // terminate allocation
1628 rbPerFlow = 0;
1629 }
1630 }
1631 }
1632 if (!allocated)
1633 {
1634 // unable to allocate new resource: finish scheduling
1635 // m_nextRntiUl = (*it).first;
1636 // if (ret.m_dciList.size () > 0)
1637 // {
1638 // m_schedSapUser->SchedUlConfigInd (ret);
1639 // }
1640 // m_allocationMaps[params.m_sfnSf] = rbgAllocationMap; return;
1641 break;
1642 }
1643
1644 auto itCqi = m_ueCqi.find((*it).first);
1645 int cqi = 0;
1646 if (itCqi == m_ueCqi.end())
1647 {
1648 // no cqi info about this UE
1649 uldci.m_mcs = 0; // MCS 0 -> UL-AMC TBD
1650 }
1651 else
1652 {
1653 // take the lowest CQI value (worst RB)
1654 NS_ABORT_MSG_IF((*itCqi).second.empty(),
1655 "CQI of RNTI = " << (*it).first << " has expired");
1656 double minSinr = (*itCqi).second.at(uldci.m_rbStart);
1657 if (minSinr == NO_SINR)
1658 {
1659 minSinr = EstimateUlSinr((*it).first, uldci.m_rbStart);
1660 }
1661 for (uint16_t i = uldci.m_rbStart; i < uldci.m_rbStart + uldci.m_rbLen; i++)
1662 {
1663 double sinr = (*itCqi).second.at(i);
1664 if (sinr == NO_SINR)
1665 {
1666 sinr = EstimateUlSinr((*it).first, i);
1667 }
1668 if (sinr < minSinr)
1669 {
1670 minSinr = sinr;
1671 }
1672 }
1673
1674 // translate SINR -> cqi: WILD ACK: same as DL
1675 double s = log2(1 + (std::pow(10, minSinr / 10) / ((-std::log(5.0 * 0.00005)) / 1.5)));
1676 cqi = m_amc->GetCqiFromSpectralEfficiency(s);
1677 if (cqi == 0)
1678 {
1679 it++;
1680 if (it == m_ceBsrRxed.end())
1681 {
1682 // restart from the first
1683 it = m_ceBsrRxed.begin();
1684 }
1685 NS_LOG_DEBUG(this << " UE discarded for CQI = 0, RNTI " << uldci.m_rnti);
1686 // remove UE from allocation map
1687 for (uint16_t i = uldci.m_rbStart; i < uldci.m_rbStart + uldci.m_rbLen; i++)
1688 {
1689 rbgAllocationMap.at(i) = 0;
1690 }
1691 continue; // CQI == 0 means "out of range" (see table 7.2.3-1 of 36.213)
1692 }
1693 uldci.m_mcs = m_amc->GetMcsFromCqi(cqi);
1694 }
1695
1696 uldci.m_tbSize = (m_amc->GetUlTbSizeFromMcs(uldci.m_mcs, rbPerFlow) / 8);
1698 uldci.m_ndi = 1;
1699 uldci.m_cceIndex = 0;
1700 uldci.m_aggrLevel = 1;
1701 uldci.m_ueTxAntennaSelection = 3; // antenna selection OFF
1702 uldci.m_hopping = false;
1703 uldci.m_n2Dmrs = 0;
1704 uldci.m_tpc = 0; // no power control
1705 uldci.m_cqiRequest = false; // only period CQI at this stage
1706 uldci.m_ulIndex = 0; // TDD parameter
1707 uldci.m_dai = 1; // TDD parameter
1708 uldci.m_freqHopping = 0;
1709 uldci.m_pdcchPowerOffset = 0; // not used
1710 ret.m_dciList.push_back(uldci);
1711 // store DCI for HARQ_PERIOD
1712 uint8_t harqId = 0;
1713 if (m_harqOn)
1714 {
1715 auto itProcId = m_ulHarqCurrentProcessId.find(uldci.m_rnti);
1716 if (itProcId == m_ulHarqCurrentProcessId.end())
1717 {
1718 NS_FATAL_ERROR("No info find in HARQ buffer for UE " << uldci.m_rnti);
1719 }
1720 harqId = (*itProcId).second;
1721 auto itDci = m_ulHarqProcessesDciBuffer.find(uldci.m_rnti);
1722 if (itDci == m_ulHarqProcessesDciBuffer.end())
1723 {
1724 NS_FATAL_ERROR("Unable to find RNTI entry in UL DCI HARQ buffer for RNTI "
1725 << uldci.m_rnti);
1726 }
1727 (*itDci).second.at(harqId) = uldci;
1728 // Update HARQ process status (RV 0)
1729 auto itStat = m_ulHarqProcessesStatus.find(uldci.m_rnti);
1730 if (itStat == m_ulHarqProcessesStatus.end())
1731 {
1732 NS_LOG_ERROR("No info find in HARQ buffer for UE (might change eNB) "
1733 << uldci.m_rnti);
1734 }
1735 (*itStat).second.at(harqId) = 0;
1736 }
1737
1738 NS_LOG_INFO(this << " UE Allocation RNTI " << (*it).first << " startPRB "
1739 << (uint32_t)uldci.m_rbStart << " nPRB " << (uint32_t)uldci.m_rbLen
1740 << " CQI " << cqi << " MCS " << (uint32_t)uldci.m_mcs << " TBsize "
1741 << uldci.m_tbSize << " RbAlloc " << rbAllocated << " harqId "
1742 << (uint16_t)harqId);
1743
1744 it++;
1745 if (it == m_ceBsrRxed.end())
1746 {
1747 // restart from the first
1748 it = m_ceBsrRxed.begin();
1749 }
1750 if ((rbAllocated == m_cschedCellConfig.m_ulBandwidth) || (rbPerFlow == 0))
1751 {
1752 // Stop allocation: no more PRBs
1753 m_nextRntiUl = (*it).first;
1754 break;
1755 }
1756 } while (((*it).first != m_nextRntiUl) && (rbPerFlow != 0));
1757
1758 m_allocationMaps[params.m_sfnSf] = rbgAllocationMap;
1759 m_schedSapUser->SchedUlConfigInd(ret);
1760}
1761
1762void
1768
1769void
1775
1776void
1779{
1780 NS_LOG_FUNCTION(this);
1781
1782 for (unsigned int i = 0; i < params.m_macCeList.size(); i++)
1783 {
1784 if (params.m_macCeList.at(i).m_macCeType == MacCeListElement_s::BSR)
1785 {
1786 // buffer status report
1787 // note that this scheduler does not differentiate the
1788 // allocation according to which LCGs have more/less bytes
1789 // to send.
1790 // Hence the BSR of different LCGs are just summed up to get
1791 // a total queue size that is used for allocation purposes.
1792
1793 uint32_t buffer = 0;
1794 for (uint8_t lcg = 0; lcg < 4; ++lcg)
1795 {
1796 uint8_t bsrId = params.m_macCeList.at(i).m_macCeValue.m_bufferStatus.at(lcg);
1797 buffer += BufferSizeLevelBsr::BsrId2BufferSize(bsrId);
1798 }
1799
1800 uint16_t rnti = params.m_macCeList.at(i).m_rnti;
1801 NS_LOG_LOGIC(this << "RNTI=" << rnti << " buffer=" << buffer);
1802 auto it = m_ceBsrRxed.find(rnti);
1803 if (it == m_ceBsrRxed.end())
1804 {
1805 // create the new entry
1806 m_ceBsrRxed[rnti] = buffer;
1807 }
1808 else
1809 {
1810 // update the buffer size value
1811 (*it).second = buffer;
1812 }
1813 }
1814 }
1815}
1816
1817void
1820{
1821 NS_LOG_FUNCTION(this);
1822 // retrieve the allocation for this subframe
1823 switch (m_ulCqiFilter)
1824 {
1826 // filter all the CQIs that are not SRS based
1827 if (params.m_ulCqi.m_type != UlCqi_s::SRS)
1828 {
1829 return;
1830 }
1831 }
1832 break;
1834 // filter all the CQIs that are not SRS based
1835 if (params.m_ulCqi.m_type != UlCqi_s::PUSCH)
1836 {
1837 return;
1838 }
1839 }
1840 break;
1841 default:
1842 NS_FATAL_ERROR("Unknown UL CQI type");
1843 }
1844
1845 switch (params.m_ulCqi.m_type)
1846 {
1847 case UlCqi_s::PUSCH: {
1848 NS_LOG_DEBUG(this << " Collect PUSCH CQIs of Frame no. " << (params.m_sfnSf >> 4)
1849 << " subframe no. " << (0xF & params.m_sfnSf));
1850 auto itMap = m_allocationMaps.find(params.m_sfnSf);
1851 if (itMap == m_allocationMaps.end())
1852 {
1853 return;
1854 }
1855 for (uint32_t i = 0; i < (*itMap).second.size(); i++)
1856 {
1857 // convert from fixed point notation Sxxxxxxxxxxx.xxx to double
1858 double sinr = LteFfConverter::fpS11dot3toDouble(params.m_ulCqi.m_sinr.at(i));
1859 auto itCqi = m_ueCqi.find((*itMap).second.at(i));
1860 if (itCqi == m_ueCqi.end())
1861 {
1862 // create a new entry
1863 std::vector<double> newCqi;
1864 for (uint32_t j = 0; j < m_cschedCellConfig.m_ulBandwidth; j++)
1865 {
1866 if (i == j)
1867 {
1868 newCqi.push_back(sinr);
1869 }
1870 else
1871 {
1872 // initialize with NO_SINR value.
1873 newCqi.push_back(NO_SINR);
1874 }
1875 }
1876 m_ueCqi[(*itMap).second.at(i)] = newCqi;
1877 // generate correspondent timer
1878 m_ueCqiTimers[(*itMap).second.at(i)] = m_cqiTimersThreshold;
1879 }
1880 else
1881 {
1882 // update the value
1883 (*itCqi).second.at(i) = sinr;
1884 NS_LOG_DEBUG(this << " RNTI " << (*itMap).second.at(i) << " RB " << i << " SINR "
1885 << sinr);
1886 // update correspondent timer
1887 auto itTimers = m_ueCqiTimers.find((*itMap).second.at(i));
1888 (*itTimers).second = m_cqiTimersThreshold;
1889 }
1890 }
1891 // remove obsolete info on allocation
1892 m_allocationMaps.erase(itMap);
1893 }
1894 break;
1895 case UlCqi_s::SRS: {
1896 // get the RNTI from vendor specific parameters
1897 uint16_t rnti = 0;
1898 NS_ASSERT(!params.m_vendorSpecificList.empty());
1899 for (std::size_t i = 0; i < params.m_vendorSpecificList.size(); i++)
1900 {
1901 if (params.m_vendorSpecificList.at(i).m_type == SRS_CQI_RNTI_VSP)
1902 {
1903 Ptr<SrsCqiRntiVsp> vsp =
1904 DynamicCast<SrsCqiRntiVsp>(params.m_vendorSpecificList.at(i).m_value);
1905 rnti = vsp->GetRnti();
1906 }
1907 }
1908 auto itCqi = m_ueCqi.find(rnti);
1909 if (itCqi == m_ueCqi.end())
1910 {
1911 // create a new entry
1912 std::vector<double> newCqi;
1913 for (uint32_t j = 0; j < m_cschedCellConfig.m_ulBandwidth; j++)
1914 {
1915 double sinr = LteFfConverter::fpS11dot3toDouble(params.m_ulCqi.m_sinr.at(j));
1916 newCqi.push_back(sinr);
1917 NS_LOG_INFO(this << " RNTI " << rnti << " new SRS-CQI for RB " << j << " value "
1918 << sinr);
1919 }
1920 m_ueCqi[rnti] = newCqi;
1921 // generate correspondent timer
1923 }
1924 else
1925 {
1926 // update the values
1927 for (uint32_t j = 0; j < m_cschedCellConfig.m_ulBandwidth; j++)
1928 {
1929 double sinr = LteFfConverter::fpS11dot3toDouble(params.m_ulCqi.m_sinr.at(j));
1930 (*itCqi).second.at(j) = sinr;
1931 NS_LOG_INFO(this << " RNTI " << rnti << " update SRS-CQI for RB " << j << " value "
1932 << sinr);
1933 }
1934 // update correspondent timer
1935 auto itTimers = m_ueCqiTimers.find(rnti);
1936 (*itTimers).second = m_cqiTimersThreshold;
1937 }
1938 }
1939 break;
1940 case UlCqi_s::PUCCH_1:
1941 case UlCqi_s::PUCCH_2:
1942 case UlCqi_s::PRACH: {
1943 NS_FATAL_ERROR("TdTbfqFfMacScheduler supports only PUSCH and SRS UL-CQIs");
1944 }
1945 break;
1946 default:
1947 NS_FATAL_ERROR("Unknown type of UL-CQI");
1948 }
1949}
1950
1951void
1953{
1954 // refresh DL CQI P01 Map
1955 auto itP10 = m_p10CqiTimers.begin();
1956 while (itP10 != m_p10CqiTimers.end())
1957 {
1958 NS_LOG_INFO(this << " P10-CQI for user " << (*itP10).first << " is "
1959 << (uint32_t)(*itP10).second << " thr " << (uint32_t)m_cqiTimersThreshold);
1960 if ((*itP10).second == 0)
1961 {
1962 // delete correspondent entries
1963 auto itMap = m_p10CqiRxed.find((*itP10).first);
1964 NS_ASSERT_MSG(itMap != m_p10CqiRxed.end(),
1965 " Does not find CQI report for user " << (*itP10).first);
1966 NS_LOG_INFO(this << " P10-CQI expired for user " << (*itP10).first);
1967 m_p10CqiRxed.erase(itMap);
1968 auto temp = itP10;
1969 itP10++;
1970 m_p10CqiTimers.erase(temp);
1971 }
1972 else
1973 {
1974 (*itP10).second--;
1975 itP10++;
1976 }
1977 }
1978
1979 // refresh DL CQI A30 Map
1980 auto itA30 = m_a30CqiTimers.begin();
1981 while (itA30 != m_a30CqiTimers.end())
1982 {
1983 NS_LOG_INFO(this << " A30-CQI for user " << (*itA30).first << " is "
1984 << (uint32_t)(*itA30).second << " thr " << (uint32_t)m_cqiTimersThreshold);
1985 if ((*itA30).second == 0)
1986 {
1987 // delete correspondent entries
1988 auto itMap = m_a30CqiRxed.find((*itA30).first);
1989 NS_ASSERT_MSG(itMap != m_a30CqiRxed.end(),
1990 " Does not find CQI report for user " << (*itA30).first);
1991 NS_LOG_INFO(this << " A30-CQI expired for user " << (*itA30).first);
1992 m_a30CqiRxed.erase(itMap);
1993 auto temp = itA30;
1994 itA30++;
1995 m_a30CqiTimers.erase(temp);
1996 }
1997 else
1998 {
1999 (*itA30).second--;
2000 itA30++;
2001 }
2002 }
2003}
2004
2005void
2007{
2008 // refresh UL CQI Map
2009 auto itUl = m_ueCqiTimers.begin();
2010 while (itUl != m_ueCqiTimers.end())
2011 {
2012 NS_LOG_INFO(this << " UL-CQI for user " << (*itUl).first << " is "
2013 << (uint32_t)(*itUl).second << " thr " << (uint32_t)m_cqiTimersThreshold);
2014 if ((*itUl).second == 0)
2015 {
2016 // delete correspondent entries
2017 auto itMap = m_ueCqi.find((*itUl).first);
2018 NS_ASSERT_MSG(itMap != m_ueCqi.end(),
2019 " Does not find CQI report for user " << (*itUl).first);
2020 NS_LOG_INFO(this << " UL-CQI exired for user " << (*itUl).first);
2021 (*itMap).second.clear();
2022 m_ueCqi.erase(itMap);
2023 auto temp = itUl;
2024 itUl++;
2025 m_ueCqiTimers.erase(temp);
2026 }
2027 else
2028 {
2029 (*itUl).second--;
2030 itUl++;
2031 }
2032 }
2033}
2034
2035void
2036TdTbfqFfMacScheduler::UpdateDlRlcBufferInfo(uint16_t rnti, uint8_t lcid, uint16_t size)
2037{
2038 LteFlowId_t flow(rnti, lcid);
2039 auto it = m_rlcBufferReq.find(flow);
2040 if (it != m_rlcBufferReq.end())
2041 {
2042 NS_LOG_INFO(this << " UE " << rnti << " LC " << (uint16_t)lcid << " txqueue "
2043 << (*it).second.m_rlcTransmissionQueueSize << " retxqueue "
2044 << (*it).second.m_rlcRetransmissionQueueSize << " status "
2045 << (*it).second.m_rlcStatusPduSize << " decrease " << size);
2046 // Update queues: RLC tx order Status, ReTx, Tx
2047 // Update status queue
2048 if (((*it).second.m_rlcStatusPduSize > 0) && (size >= (*it).second.m_rlcStatusPduSize))
2049 {
2050 (*it).second.m_rlcStatusPduSize = 0;
2051 }
2052 else if (((*it).second.m_rlcRetransmissionQueueSize > 0) &&
2053 (size >= (*it).second.m_rlcRetransmissionQueueSize))
2054 {
2055 (*it).second.m_rlcRetransmissionQueueSize = 0;
2056 }
2057 else if ((*it).second.m_rlcTransmissionQueueSize > 0)
2058 {
2059 uint32_t rlcOverhead;
2060 if (lcid == 1)
2061 {
2062 // for SRB1 (using RLC AM) it's better to
2063 // overestimate RLC overhead rather than
2064 // underestimate it and risk unneeded
2065 // segmentation which increases delay
2066 rlcOverhead = 4;
2067 }
2068 else
2069 {
2070 // minimum RLC overhead due to header
2071 rlcOverhead = 2;
2072 }
2073 // update transmission queue
2074 if ((*it).second.m_rlcTransmissionQueueSize <= size - rlcOverhead)
2075 {
2076 (*it).second.m_rlcTransmissionQueueSize = 0;
2077 }
2078 else
2079 {
2080 (*it).second.m_rlcTransmissionQueueSize -= size - rlcOverhead;
2081 }
2082 }
2083 }
2084 else
2085 {
2086 NS_LOG_ERROR(this << " Does not find DL RLC Buffer Report of UE " << rnti);
2087 }
2088}
2089
2090void
2092{
2093 size = size - 2; // remove the minimum RLC overhead
2094 auto it = m_ceBsrRxed.find(rnti);
2095 if (it != m_ceBsrRxed.end())
2096 {
2097 NS_LOG_INFO(this << " UE " << rnti << " size " << size << " BSR " << (*it).second);
2098 if ((*it).second >= size)
2099 {
2100 (*it).second -= size;
2101 }
2102 else
2103 {
2104 (*it).second = 0;
2105 }
2106 }
2107 else
2108 {
2109 NS_LOG_ERROR(this << " Does not find BSR report info of UE " << rnti);
2110 }
2111}
2112
2113void
2115{
2116 NS_LOG_FUNCTION(this << " RNTI " << rnti << " txMode " << (uint16_t)txMode);
2118 params.m_rnti = rnti;
2119 params.m_transmissionMode = txMode;
2120 m_cschedSapUser->CschedUeConfigUpdateInd(params);
2121}
2122
2123} // namespace ns3
static uint32_t BsrId2BufferSize(uint8_t val)
Convert BSR ID to buffer size.
Provides the CSCHED SAP.
FfMacCschedSapUser class.
Provides the SCHED SAP.
FfMacSchedSapUser class.
FfMacScheduler()
constructor
UlCqiFilter_t m_ulCqiFilter
UL CQI filter.
Hold a signed integer type.
Definition integer.h:34
static double fpS11dot3toDouble(uint16_t val)
Convert from fixed point S11.3 notation to double.
Service Access Point (SAP) offered by the Frequency Reuse algorithm instance to the MAC Scheduler ins...
Definition lte-ffr-sap.h:29
Service Access Point (SAP) offered by the eNodeB RRC instance to the Frequency Reuse algorithm instan...
Template for the implementation of the LteFfrSapUser as a member of an owner class of type C to which...
Smart pointer class similar to boost::intrusive_ptr.
Definition ptr.h:70
static Time Now()
Return the current simulation virtual time.
Definition simulator.cc:191
uint16_t m_nextRntiUl
RNTI of the next user to be served next scheduling in UL.
bool HarqProcessAvailability(uint16_t rnti)
Return the availability of free process for the RNTI specified.
void SetLteFfrSapProvider(LteFfrSapProvider *s) override
Set the Provider part of the LteFfrSap that this Scheduler will interact with.
static TypeId GetTypeId()
Get the type ID.
std::map< uint16_t, uint8_t > m_uesTxMode
txMode of the UEs
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.
void UpdateUlRlcBufferInfo(uint16_t rnti, uint16_t size)
Update UL RLC buffer info function.
~TdTbfqFfMacScheduler() override
Destructor.
FfMacSchedSapProvider * m_schedSapProvider
Sched SAP provider.
std::map< uint16_t, UlHarqProcessesDciBuffer_t > m_ulHarqProcessesDciBuffer
UL HARQ process DCI buffer.
FfMacCschedSapProvider::CschedCellConfigReqParameters m_cschedCellConfig
CSched cell config.
FfMacSchedSapUser * m_schedSapUser
A=Sched SAP user.
unsigned int LcActivePerFlow(uint16_t rnti)
LC active flow size.
std::map< uint16_t, DlHarqProcessesDciBuffer_t > m_dlHarqProcessesDciBuffer
DL HARQ process DCI buffer.
std::map< uint16_t, DlHarqRlcPduListBuffer_t > m_dlHarqProcessesRlcPduListBuffer
DL HARQ process RLC PDU list buffer.
uint32_t m_creditLimit
flow credit limit (byte)
void DoSchedUlMacCtrlInfoReq(const FfMacSchedSapProvider::SchedUlMacCtrlInfoReqParameters &params)
Sched UL MAC control info request.
uint8_t UpdateHarqProcessId(uint16_t rnti)
Update and return a new process Id for the RNTI specified.
void DoSchedUlTriggerReq(const FfMacSchedSapProvider::SchedUlTriggerReqParameters &params)
Sched UL trigger request.
std::map< uint16_t, uint32_t > m_a30CqiTimers
Map of UE's timers on DL CQI A30 received.
std::vector< uint16_t > m_rachAllocationMap
RACH allocation map.
LteFfrSapUser * m_ffrSapUser
FFR SAP user.
std::map< uint16_t, uint32_t > m_ceBsrRxed
Map of UE's buffer status reports received.
int GetRbgSize(int dlbandwidth)
Get RBG size.
std::map< uint16_t, uint32_t > m_p10CqiTimers
Map of UE's timers on DL CQI P01 received.
std::map< uint16_t, uint8_t > m_ulHarqCurrentProcessId
UL HARQ current process ID.
void DoSchedDlPagingBufferReq(const FfMacSchedSapProvider::SchedDlPagingBufferReqParameters &params)
Sched DL paging buffer request.
void RefreshDlCqiMaps()
Refresh DL CQI maps function.
uint8_t m_ulGrantMcs
MCS for UL grant (default 0).
std::map< uint16_t, std::vector< double > > m_ueCqi
Map of UEs' UL-CQI per RBG.
FfMacSchedSapProvider * GetFfMacSchedSapProvider() override
uint32_t m_creditableThreshold
threshold of flow credit
void DoSchedDlTriggerReq(const FfMacSchedSapProvider::SchedDlTriggerReqParameters &params)
Sched DL trigger request.
std::map< uint16_t, tdtbfqsFlowPerf_t > m_flowStatsUl
Map of UE statistics (per RNTI basis).
LteFfrSapUser * GetLteFfrSapUser() override
FfMacCschedSapProvider * GetFfMacCschedSapProvider() override
void DoSchedDlMacBufferReq(const FfMacSchedSapProvider::SchedDlMacBufferReqParameters &params)
Sched DL MAC buffer request.
void DoCschedLcConfigReq(const FfMacCschedSapProvider::CschedLcConfigReqParameters &params)
CSched LC config request.
void TransmissionModeConfigurationUpdate(uint16_t rnti, uint8_t txMode)
Transmission mde configuration update function.
friend class MemberCschedSapProvider< TdTbfqFfMacScheduler >
allow MemberCschedSapProvider<TdTbfqFfMacScheduler> class friend access
void DoSchedDlRachInfoReq(const FfMacSchedSapProvider::SchedDlRachInfoReqParameters &params)
Sched DL RACH info request.
std::map< LteFlowId_t, FfMacSchedSapProvider::SchedDlRlcBufferReqParameters > m_rlcBufferReq
Vectors of UE's LC info.
FfMacCschedSapProvider * m_cschedSapProvider
CSched SAP provider.
void RefreshUlCqiMaps()
Refresh UL CQI maps function.
void DoSchedUlCqiInfoReq(const FfMacSchedSapProvider::SchedUlCqiInfoReqParameters &params)
Sched UL CQI info request.
void SetFfMacSchedSapUser(FfMacSchedSapUser *s) override
set the user part of the FfMacSchedSap that this Scheduler will interact with.
int m_debtLimit
flow debt limit (byte)
double EstimateUlSinr(uint16_t rnti, uint16_t rb)
Estimate UL SINR function.
std::vector< RachListElement_s > m_rachList
RACH list.
void DoCschedLcReleaseReq(const FfMacCschedSapProvider::CschedLcReleaseReqParameters &params)
CSched LC release request.
LteFfrSapProvider * m_ffrSapProvider
FFR SAP provider.
void DoSchedUlSrInfoReq(const FfMacSchedSapProvider::SchedUlSrInfoReqParameters &params)
Sched UL SR info request.
std::map< uint16_t, uint8_t > m_p10CqiRxed
Map of UE's DL CQI P01 received.
void DoCschedUeConfigReq(const FfMacCschedSapProvider::CschedUeConfigReqParameters &params)
CSched UE config request.
friend class MemberSchedSapProvider< TdTbfqFfMacScheduler >
allow MemberSchedSapProvider<TdTbfqFfMacScheduler> class friend access
uint32_t m_tokenPoolSize
maximum size of token pool (byte)
void DoCschedUeReleaseReq(const FfMacCschedSapProvider::CschedUeReleaseReqParameters &params)
CSched UE release request.
std::map< uint16_t, DlHarqProcessesStatus_t > m_dlHarqProcessesStatus
DL HARQ process status.
void DoSchedDlRlcBufferReq(const FfMacSchedSapProvider::SchedDlRlcBufferReqParameters &params)
Sched DL RLC buffer request.
FfMacCschedSapUser * m_cschedSapUser
CSched SAP user.
std::map< uint16_t, uint32_t > m_ueCqiTimers
Map of UEs' timers on UL-CQI per RBG.
void DoDispose() override
Destructor implementation.
std::map< uint16_t, uint8_t > m_dlHarqCurrentProcessId
DL HARQ current process ID.
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 RefreshHarqProcesses()
Refresh HARQ processes according to the timers.
void SetFfMacCschedSapUser(FfMacCschedSapUser *s) override
set the user part of the FfMacCschedSap that this Scheduler will interact with.
std::vector< DlInfoListElement_s > m_dlInfoListBuffered
HARQ retx buffered.
void DoSchedUlNoiseInterferenceReq(const FfMacSchedSapProvider::SchedUlNoiseInterferenceReqParameters &params)
Sched UL noise interference request.
std::map< uint16_t, UlHarqProcessesStatus_t > m_ulHarqProcessesStatus
UL HARQ process status.
void DoCschedCellConfigReq(const FfMacCschedSapProvider::CschedCellConfigReqParameters &params)
CSched cell config request.
void DoSchedDlCqiInfoReq(const FfMacSchedSapProvider::SchedDlCqiInfoReqParameters &params)
Sched DL CQI info request.
std::map< uint16_t, tdtbfqsFlowPerf_t > m_flowStatsDl
Map of UE statistics (per RNTI basis) in downlink.
std::map< uint16_t, SbMeasResult_s > m_a30CqiRxed
Map of UE's DL CQI A30 received.
uint64_t bankSize
the number of bytes in token bank
bool m_harqOn
m_harqOn when false inhibit the HARQ mechanisms (by default active)
static uint8_t TxMode2LayerNum(uint8_t txMode)
Transmit mode 2 layer number.
a unique identifier for an interface.
Definition type-id.h:50
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition type-id.cc:999
Hold an unsigned integer type.
Definition uinteger.h:34
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition assert.h:55
#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:75
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
Definition abort.h:97
#define NS_LOG_ERROR(msg)
Use NS_LOG to output a message of level LOG_ERROR.
Definition log.h:246
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition log.h:194
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition log.h:260
#define NS_LOG_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
Definition log.h:274
#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:267
Ptr< T > CreateObject(Args &&... args)
Create an object by type, with varying number of constructor parameters.
Definition object.h:627
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition object-base.h:35
#define HARQ_PERIOD
Definition lte-common.h:19
#define SRS_CQI_RNTI_VSP
Every class exported by the ns3 library is enclosed in the ns3 namespace.
Ptr< const AttributeChecker > MakeBooleanChecker()
Definition boolean.cc:113
std::vector< uint8_t > DlHarqProcessesTimer_t
DL HARQ process timer vector.
Ptr< const AttributeChecker > MakeIntegerChecker()
Definition integer.h:99
Ptr< const AttributeAccessor > MakeIntegerAccessor(T1 a1)
Definition integer.h:35
Ptr< const AttributeChecker > MakeUintegerChecker()
Definition uinteger.h:85
constexpr double NO_SINR
Value for SINR outside the range defined by FF-API, used to indicate that there is no CQI for this el...
static const int TdTbfqType0AllocationRbg[4]
TDTBFQ type 0 allocation RBG (see table 7.1.6.1-1 of 36.213).
Ptr< const AttributeAccessor > MakeUintegerAccessor(T1 a1)
Definition uinteger.h:35
std::vector< uint8_t > UlHarqProcessesStatus_t
UL HARQ process status vector.
std::vector< uint8_t > DlHarqProcessesStatus_t
DL HARQ process status vector.
Ptr< T1 > DynamicCast(const Ptr< T2 > &p)
Cast a Ptr.
Definition ptr.h:643
std::vector< DlDciListElement_s > DlHarqProcessesDciBuffer_t
DL HARQ process DCI buffer vector.
@ SUCCESS
constexpr uint32_t HARQ_DL_TIMEOUT
HARQ DL timeout.
constexpr uint32_t HARQ_PROC_NUM
Number of HARQ processes.
Ptr< const AttributeAccessor > MakeBooleanAccessor(T1 a1)
Definition boolean.h:70
std::vector< RlcPduList_t > DlHarqRlcPduListBuffer_t
Vector of the 8 HARQ processes per UE.
std::vector< UlDciListElement_s > UlHarqProcessesDciBuffer_t
UL HARQ process DCI buffer vector.
See section 4.3.8 buildDataListElement.
std::vector< std::vector< struct RlcPduListElement_s > > m_rlcPduList
RLC PDU list.
struct DlDciListElement_s m_dci
DCI.
See section 4.3.10 buildRARListElement.
See section 4.3.1 dlDciListElement.
std::vector< uint8_t > m_ndi
New data indicator.
uint8_t m_harqProcess
HARQ process.
uint32_t m_rbBitmap
RB bitmap.
std::vector< uint8_t > m_mcs
MCS.
uint8_t m_resAlloc
The type of resource allocation.
std::vector< uint16_t > m_tbsSize
The TBs size.
std::vector< uint8_t > m_rv
Redundancy version.
uint8_t m_tpc
Tx power control command.
Parameters of the CSCHED_LC_CONFIG_REQ primitive.
Parameters of the CSCHED_LC_RELEASE_REQ primitive.
Parameters of the CSCHED_UE_CONFIG_REQ primitive.
Parameters of the CSCHED_UE_RELEASE_REQ primitive.
Parameters of the CSCHED_UE_CONFIG_CNF primitive.
Parameters of the CSCHED_UE_CONFIG_UPDATE_IND primitive.
Parameters of the SCHED_DL_CQI_INFO_REQ primitive.
Parameters of the SCHED_DL_MAC_BUFFER_REQ primitive.
Parameters of the SCHED_DL_PAGING_BUFFER_REQ primitive.
Parameters of the SCHED_DL_RACH_INFO_REQ primitive.
Parameters of the SCHED_DL_TRIGGER_REQ primitive.
Parameters of the SCHED_UL_CQI_INFO_REQ primitive.
Parameters of the SCHED_UL_MAC_CTRL_INFO_REQ primitive.
Parameters of the SCHED_UL_NOISE_INTERFERENCE_REQ primitive.
Parameters of the SCHED_UL_SR_INFO_REQ primitive.
Parameters of the SCHED_UL_TRIGGER_REQ primitive.
std::vector< BuildDataListElement_s > m_buildDataList
build data list
std::vector< BuildRarListElement_s > m_buildRarList
build rar list
uint8_t m_nrOfPdcchOfdmSymbols
number of PDCCH OFDM symbols
Parameters of the SCHED_UL_CONFIG_IND primitive.
std::vector< UlDciListElement_s > m_dciList
DCI list.
LteFlowId structure.
Definition lte-common.h:32
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_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.
uint32_t tokenPoolSize
current size of token pool (byte)
int debtLimit
counter threshold that the flow cannot further borrow tokens from bank
uint32_t maxTokenPoolSize
maximum size of token pool (byte)
int counter
the number of token borrow or given to token 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)
uint64_t tokenGenerationRate
token generation rate ( byte/s )
uint32_t burstCredit
the maximum number of tokens connection i can borrow from the bank each time