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