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