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