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