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