5G-LENA nr-v3.0-32-g83aee33
The 5G/NR module for the ns-3 simulator
Loading...
Searching...
No Matches
nr-gnb-mac.cc
1/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
2
3// Copyright (c) 2019 Centre Tecnologic de Telecomunicacions de Catalunya (CTTC)
4//
5// SPDX-License-Identifier: GPL-2.0-only
6
7#define NS_LOG_APPEND_CONTEXT \
8 do \
9 { \
10 std::clog << " [ CellId " << GetCellId() << ", bwpId " << GetBwpId() << "] "; \
11 } while (false);
12
13#include "nr-gnb-mac.h"
14
15#include "beam-id.h"
16#include "nr-control-messages.h"
17#include "nr-mac-header-fs-ul.h"
18#include "nr-mac-header-vs.h"
19#include "nr-mac-pdu-info.h"
20#include "nr-mac-sched-sap.h"
21#include "nr-mac-scheduler.h"
22#include "nr-mac-short-bsr-ce.h"
23#include "nr-phy-mac-common.h"
24
25#include <ns3/log.h>
26#include <ns3/lte-common.h>
27#include <ns3/lte-radio-bearer-tag.h>
28#include <ns3/spectrum-model.h>
29#include <ns3/uinteger.h>
30
31#include <algorithm>
32
33namespace ns3
34{
35NS_LOG_COMPONENT_DEFINE("NrGnbMac");
36
37NS_OBJECT_ENSURE_REGISTERED(NrGnbMac);
38
39// //////////////////////////////////////
40// member SAP forwarders
41// //////////////////////////////////////
42
43class NrGnbMacMemberEnbCmacSapProvider : public LteEnbCmacSapProvider
44{
45 public:
46 NrGnbMacMemberEnbCmacSapProvider(NrGnbMac* mac);
47
48 // inherited from LteEnbCmacSapProvider
49 void ConfigureMac(uint16_t ulBandwidth, uint16_t dlBandwidth) override;
50 void AddUe(uint16_t rnti) override;
51 void RemoveUe(uint16_t rnti) override;
52 void AddLc(LcInfo lcinfo, LteMacSapUser* msu) override;
53 void ReconfigureLc(LcInfo lcinfo) override;
54 void ReleaseLc(uint16_t rnti, uint8_t lcid) override;
55 void UeUpdateConfigurationReq(UeConfig params) override;
56 RachConfig GetRachConfig() override;
57 AllocateNcRaPreambleReturnValue AllocateNcRaPreamble(uint16_t rnti) override;
58
59 private:
60 NrGnbMac* m_mac;
61};
62
63NrGnbMacMemberEnbCmacSapProvider::NrGnbMacMemberEnbCmacSapProvider(NrGnbMac* mac)
64 : m_mac(mac)
65{
66}
67
68void
69NrGnbMacMemberEnbCmacSapProvider::ConfigureMac(uint16_t ulBandwidth, uint16_t dlBandwidth)
70{
71 m_mac->DoConfigureMac(ulBandwidth, dlBandwidth);
72}
73
74void
75NrGnbMacMemberEnbCmacSapProvider::AddUe(uint16_t rnti)
76{
77 m_mac->DoAddUe(rnti);
78}
79
80void
81NrGnbMacMemberEnbCmacSapProvider::RemoveUe(uint16_t rnti)
82{
83 m_mac->DoRemoveUe(rnti);
84}
85
86void
87NrGnbMacMemberEnbCmacSapProvider::AddLc(LcInfo lcinfo, LteMacSapUser* msu)
88{
89 m_mac->DoAddLc(lcinfo, msu);
90}
91
92void
93NrGnbMacMemberEnbCmacSapProvider::ReconfigureLc(LcInfo lcinfo)
94{
95 m_mac->DoReconfigureLc(lcinfo);
96}
97
98void
99NrGnbMacMemberEnbCmacSapProvider::ReleaseLc(uint16_t rnti, uint8_t lcid)
100{
101 m_mac->DoReleaseLc(rnti, lcid);
102}
103
104void
105NrGnbMacMemberEnbCmacSapProvider::UeUpdateConfigurationReq(UeConfig params)
106{
107 m_mac->UeUpdateConfigurationReq(params);
108}
109
110LteEnbCmacSapProvider::RachConfig
111NrGnbMacMemberEnbCmacSapProvider::GetRachConfig()
112{
113 return m_mac->DoGetRachConfig();
114}
115
116LteEnbCmacSapProvider::AllocateNcRaPreambleReturnValue
117NrGnbMacMemberEnbCmacSapProvider::AllocateNcRaPreamble(uint16_t rnti)
118{
119 return m_mac->DoAllocateNcRaPreamble(rnti);
120}
121
122// SAP interface between ENB PHY AND MAC
123// PHY is provider and MAC is user of its service following OSI model.
124// However, PHY may request some information from MAC.
125class NrMacEnbMemberPhySapUser : public NrGnbPhySapUser
126{
127 public:
128 NrMacEnbMemberPhySapUser(NrGnbMac* mac);
129
130 void ReceivePhyPdu(Ptr<Packet> p) override;
131
132 void ReceiveControlMessage(Ptr<NrControlMessage> msg) override;
133
134 void SlotDlIndication(const SfnSf&, LteNrTddSlotType) override;
135
136 void SlotUlIndication(const SfnSf&, LteNrTddSlotType) override;
137
138 void SetCurrentSfn(const SfnSf&) override;
139
140 void UlCqiReport(NrMacSchedSapProvider::SchedUlCqiInfoReqParameters cqi) override;
141
142 void ReceiveRachPreamble(uint32_t raId) override;
143
144 void UlHarqFeedback(UlHarqInfo params) override;
145
146 void BeamChangeReport(BeamId beamId, uint8_t rnti) override;
147
148 uint32_t GetNumRbPerRbg() const override;
149
150 std::shared_ptr<DciInfoElementTdma> GetDlCtrlDci() const override;
151 std::shared_ptr<DciInfoElementTdma> GetUlCtrlDci() const override;
152
153 uint8_t GetDlCtrlSymbols() const override;
154
155 private:
156 NrGnbMac* m_mac;
157};
158
159NrMacEnbMemberPhySapUser::NrMacEnbMemberPhySapUser(NrGnbMac* mac)
160 : m_mac(mac)
161{
162}
163
164void
165NrMacEnbMemberPhySapUser::ReceivePhyPdu(Ptr<Packet> p)
166{
167 m_mac->DoReceivePhyPdu(p);
168}
169
170void
171NrMacEnbMemberPhySapUser::ReceiveControlMessage(Ptr<NrControlMessage> msg)
172{
173 m_mac->DoReceiveControlMessage(msg);
174}
175
176void
177NrMacEnbMemberPhySapUser::SlotDlIndication(const SfnSf& sfn, LteNrTddSlotType type)
178{
179 m_mac->DoSlotDlIndication(sfn, type);
180}
181
182void
183NrMacEnbMemberPhySapUser::SlotUlIndication(const SfnSf& sfn, LteNrTddSlotType type)
184{
185 m_mac->DoSlotUlIndication(sfn, type);
186}
187
188void
189NrMacEnbMemberPhySapUser::SetCurrentSfn(const SfnSf& sfn)
190{
191 m_mac->SetCurrentSfn(sfn);
192}
193
194void
195NrMacEnbMemberPhySapUser::UlCqiReport(NrMacSchedSapProvider::SchedUlCqiInfoReqParameters ulcqi)
196{
197 m_mac->DoUlCqiReport(ulcqi);
198}
199
200void
201NrMacEnbMemberPhySapUser::ReceiveRachPreamble(uint32_t raId)
202{
203 m_mac->ReceiveRachPreamble(raId);
204}
205
206void
207NrMacEnbMemberPhySapUser::UlHarqFeedback(UlHarqInfo params)
208{
209 m_mac->DoUlHarqFeedback(params);
210}
211
212void
213NrMacEnbMemberPhySapUser::BeamChangeReport(BeamId beamId, uint8_t rnti)
214{
215 m_mac->BeamChangeReport(beamId, rnti);
216}
217
218uint32_t
219NrMacEnbMemberPhySapUser::GetNumRbPerRbg() const
220{
221 return m_mac->GetNumRbPerRbg();
222}
223
224std::shared_ptr<DciInfoElementTdma>
225NrMacEnbMemberPhySapUser::GetDlCtrlDci() const
226{
227 return m_mac->GetDlCtrlDci();
228}
229
230std::shared_ptr<DciInfoElementTdma>
231NrMacEnbMemberPhySapUser::GetUlCtrlDci() const
232{
233 return m_mac->GetUlCtrlDci();
234}
235
236uint8_t
237NrMacEnbMemberPhySapUser::GetDlCtrlSymbols() const
238{
239 return m_mac->GetDlCtrlSyms();
240}
241
242// MAC Sched
243
244class NrMacMemberMacSchedSapUser : public NrMacSchedSapUser
245{
246 public:
247 NrMacMemberMacSchedSapUser(NrGnbMac* mac);
248 void SchedConfigInd(const struct SchedConfigIndParameters& params) override;
249 Ptr<const SpectrumModel> GetSpectrumModel() const override;
250 uint32_t GetNumRbPerRbg() const override;
251 uint8_t GetNumHarqProcess() const override;
252 uint16_t GetBwpId() const override;
253 uint16_t GetCellId() const override;
254 uint32_t GetSymbolsPerSlot() const override;
255 Time GetSlotPeriod() const override;
256
257 private:
258 NrGnbMac* m_mac;
259};
260
261NrMacMemberMacSchedSapUser::NrMacMemberMacSchedSapUser(NrGnbMac* mac)
262 : m_mac(mac)
263{
264 // Some blank spaces
265}
266
267void
268NrMacMemberMacSchedSapUser::SchedConfigInd(const struct SchedConfigIndParameters& params)
269{
270 m_mac->DoSchedConfigIndication(params);
271}
272
273Ptr<const SpectrumModel>
274NrMacMemberMacSchedSapUser::GetSpectrumModel() const
275{
276 return m_mac->m_phySapProvider
277 ->GetSpectrumModel(); // MAC forwards the call from scheduler to PHY; i.e. this function
278 // connects two providers of MAC: scheduler and PHY
279}
280
281uint32_t
282NrMacMemberMacSchedSapUser::GetNumRbPerRbg() const
283{
284 return m_mac->GetNumRbPerRbg();
285}
286
287uint8_t
288NrMacMemberMacSchedSapUser::GetNumHarqProcess() const
289{
290 return m_mac->GetNumHarqProcess();
291}
292
293uint16_t
294NrMacMemberMacSchedSapUser::GetBwpId() const
295{
296 return m_mac->GetBwpId();
297}
298
299uint16_t
300NrMacMemberMacSchedSapUser::GetCellId() const
301{
302 return m_mac->GetCellId();
303}
304
305uint32_t
306NrMacMemberMacSchedSapUser::GetSymbolsPerSlot() const
307{
308 return m_mac->m_phySapProvider->GetSymbolsPerSlot();
309}
310
311Time
312NrMacMemberMacSchedSapUser::GetSlotPeriod() const
313{
314 return m_mac->m_phySapProvider->GetSlotPeriod();
315}
316
317class NrMacMemberMacCschedSapUser : public NrMacCschedSapUser
318{
319 public:
320 NrMacMemberMacCschedSapUser(NrGnbMac* mac);
321
322 void CschedCellConfigCnf(
323 const struct NrMacCschedSapUser::CschedCellConfigCnfParameters& params) override;
324 void CschedUeConfigCnf(
325 const struct NrMacCschedSapUser::CschedUeConfigCnfParameters& params) override;
326 void CschedLcConfigCnf(
327 const struct NrMacCschedSapUser::CschedLcConfigCnfParameters& params) override;
328 void CschedLcReleaseCnf(
329 const struct NrMacCschedSapUser::CschedLcReleaseCnfParameters& params) override;
330 void CschedUeReleaseCnf(
331 const struct NrMacCschedSapUser::CschedUeReleaseCnfParameters& params) override;
332 void CschedUeConfigUpdateInd(
333 const struct NrMacCschedSapUser::CschedUeConfigUpdateIndParameters& params) override;
334 void CschedCellConfigUpdateInd(
335 const struct NrMacCschedSapUser::CschedCellConfigUpdateIndParameters& params) override;
336
337 private:
338 NrGnbMac* m_mac;
339};
340
341NrMacMemberMacCschedSapUser::NrMacMemberMacCschedSapUser(NrGnbMac* mac)
342 : m_mac(mac)
343{
344}
345
346void
347NrMacMemberMacCschedSapUser::CschedCellConfigCnf(const struct CschedCellConfigCnfParameters& params)
348{
349 m_mac->DoCschedCellConfigCnf(params);
350}
351
352void
353NrMacMemberMacCschedSapUser::CschedUeConfigCnf(const struct CschedUeConfigCnfParameters& params)
354{
355 m_mac->DoCschedUeConfigCnf(params);
356}
357
358void
359NrMacMemberMacCschedSapUser::CschedLcConfigCnf(const struct CschedLcConfigCnfParameters& params)
360{
361 m_mac->DoCschedLcConfigCnf(params);
362}
363
364void
365NrMacMemberMacCschedSapUser::CschedLcReleaseCnf(const struct CschedLcReleaseCnfParameters& params)
366{
367 m_mac->DoCschedLcReleaseCnf(params);
368}
369
370void
371NrMacMemberMacCschedSapUser::CschedUeReleaseCnf(const struct CschedUeReleaseCnfParameters& params)
372{
373 m_mac->DoCschedUeReleaseCnf(params);
374}
375
376void
377NrMacMemberMacCschedSapUser::CschedUeConfigUpdateInd(
378 const struct CschedUeConfigUpdateIndParameters& params)
379{
380 m_mac->DoCschedUeConfigUpdateInd(params);
381}
382
383void
384NrMacMemberMacCschedSapUser::CschedCellConfigUpdateInd(
385 const struct CschedCellConfigUpdateIndParameters& params)
386{
387 m_mac->DoCschedCellConfigUpdateInd(params);
388}
389
390TypeId
391NrGnbMac::GetTypeId()
392{
393 static TypeId tid =
394 TypeId("ns3::NrGnbMac")
395 .SetParent<Object>()
396 .AddConstructor<NrGnbMac>()
397 .AddAttribute(
398 "NumRbPerRbg",
399 "Number of resource blocks per resource block group.",
400 UintegerValue(1),
401 MakeUintegerAccessor(&NrGnbMac::SetNumRbPerRbg, &NrGnbMac::GetNumRbPerRbg),
402 MakeUintegerChecker<uint32_t>())
403 .AddAttribute(
404 "NumHarqProcess",
405 "Number of concurrent stop-and-wait Hybrid ARQ processes per user",
406 UintegerValue(16),
407 MakeUintegerAccessor(&NrGnbMac::SetNumHarqProcess, &NrGnbMac::GetNumHarqProcess),
408 MakeUintegerChecker<uint8_t>())
409 .AddTraceSource("DlScheduling",
410 "Information regarding DL scheduling.",
411 MakeTraceSourceAccessor(&NrGnbMac::m_dlScheduling),
412 "ns3::NrGnbMac::DlSchedulingTracedCallback")
413 .AddTraceSource("UlScheduling",
414 "Information regarding UL scheduling.",
415 MakeTraceSourceAccessor(&NrGnbMac::m_ulScheduling),
416 "ns3::NrGnbMac::SchedulingTracedCallback")
417 .AddTraceSource("SrReq",
418 "Information regarding received scheduling request.",
419 MakeTraceSourceAccessor(&NrGnbMac::m_srCallback),
420 "ns3::NrGnbMac::SrTracedCallback")
421 .AddTraceSource("GnbMacRxedCtrlMsgsTrace",
422 "Enb MAC Rxed Control Messages Traces.",
423 MakeTraceSourceAccessor(&NrGnbMac::m_macRxedCtrlMsgsTrace),
424 "ns3::NrMacRxTrace::RxedGnbMacCtrlMsgsTracedCallback")
425 .AddTraceSource("GnbMacTxedCtrlMsgsTrace",
426 "Enb MAC Txed Control Messages Traces.",
427 MakeTraceSourceAccessor(&NrGnbMac::m_macTxedCtrlMsgsTrace),
428 "ns3::NrMacRxTrace::TxedGnbMacCtrlMsgsTracedCallback")
429 .AddTraceSource("DlHarqFeedback",
430 "Harq feedback.",
431 MakeTraceSourceAccessor(&NrGnbMac::m_dlHarqFeedback),
432 "ns3::NrGnbMac::DlHarqFeedbackTracedCallback");
433 return tid;
434}
435
436NrGnbMac::NrGnbMac()
437 : Object()
438{
439 NS_LOG_FUNCTION(this);
440 m_cmacSapProvider = new NrGnbMacMemberEnbCmacSapProvider(this);
441 m_macSapProvider = new EnbMacMemberLteMacSapProvider<NrGnbMac>(this);
442 m_phySapUser = new NrMacEnbMemberPhySapUser(this);
443 m_macSchedSapUser = new NrMacMemberMacSchedSapUser(this);
444 m_macCschedSapUser = new NrMacMemberMacCschedSapUser(this);
445 m_ccmMacSapProvider = new MemberLteCcmMacSapProvider<NrGnbMac>(this);
446}
447
449{
450 NS_LOG_FUNCTION(this);
451}
452
453void
455{
456 NS_LOG_FUNCTION(this);
457 m_dlCqiReceived.clear();
458 m_ulCqiReceived.clear();
459 m_ulCeReceived.clear();
460 m_miDlHarqProcessesPackets.clear();
461 delete m_macSapProvider;
462 delete m_cmacSapProvider;
463 delete m_macSchedSapUser;
464 delete m_macCschedSapUser;
465 delete m_phySapUser;
466 delete m_ccmMacSapProvider;
467}
468
469void
471{
472 NS_ABORT_MSG_IF(m_numRbPerRbg != -1, "This attribute can not be reconfigured");
473 m_numRbPerRbg = rbgSize;
474}
475
476uint32_t
478{
479 return m_numRbPerRbg;
480}
481
482void
483NrGnbMac::SetNumHarqProcess(uint8_t numHarqProcess)
484{
485 m_numHarqProcess = numHarqProcess;
486}
487
491uint8_t
493{
494 return m_numHarqProcess;
495}
496
497uint8_t
499{
500 return m_macSchedSapProvider->GetDlCtrlSyms();
501}
502
503uint8_t
505{
506 return m_macSchedSapProvider->GetUlCtrlSyms();
507}
508
509void
510NrGnbMac::ReceiveRachPreamble(uint32_t raId)
511{
512 Ptr<NrRachPreambleMessage> rachMsg = Create<NrRachPreambleMessage>();
513 rachMsg->SetSourceBwp(GetBwpId());
514 m_macRxedCtrlMsgsTrace(m_currentSlot, GetCellId(), raId, GetBwpId(), rachMsg);
515
516 ++m_receivedRachPreambleCount[raId];
517}
518
519LteMacSapProvider*
520NrGnbMac::GetMacSapProvider()
521{
522 return m_macSapProvider;
523}
524
525LteEnbCmacSapProvider*
526NrGnbMac::GetEnbCmacSapProvider()
527{
528 return m_cmacSapProvider;
529}
530
531void
532NrGnbMac::SetEnbCmacSapUser(LteEnbCmacSapUser* s)
533{
534 m_cmacSapUser = s;
535}
536
537void
539{
540 m_ccmMacSapUser = s;
541}
542
543LteCcmMacSapProvider*
545{
546 NS_LOG_FUNCTION(this);
547 return m_ccmMacSapProvider;
548}
549
550void
552{
553 NS_LOG_FUNCTION(this);
554 m_currentSlot = sfnSf;
555}
556
557void
559{
560 NS_LOG_FUNCTION(this);
561 NS_LOG_LOGIC("Perform things on DL, slot on the air: " << sfnSf);
562
563 // --- DOWNLINK ---
564 // Send Dl-CQI info to the scheduler if(m_dlCqiReceived.size () > 0)
565 {
567 dlCqiInfoReq.m_sfnsf = sfnSf;
568
569 dlCqiInfoReq.m_cqiList.insert(dlCqiInfoReq.m_cqiList.begin(),
570 m_dlCqiReceived.begin(),
571 m_dlCqiReceived.end());
572 m_dlCqiReceived.erase(m_dlCqiReceived.begin(), m_dlCqiReceived.end());
573
574 m_macSchedSapProvider->SchedDlCqiInfoReq(dlCqiInfoReq);
575
576 for (const auto& v : dlCqiInfoReq.m_cqiList)
577 {
578 Ptr<NrDlCqiMessage> msg = Create<NrDlCqiMessage>();
579 msg->SetDlCqi(v);
580 m_macRxedCtrlMsgsTrace(m_currentSlot, GetCellId(), v.m_rnti, GetBwpId(), msg);
581 }
582 }
583
584 if (!m_receivedRachPreambleCount.empty())
585 {
586 // process received RACH preambles and notify the scheduler
588
589 for (auto it = m_receivedRachPreambleCount.begin(); it != m_receivedRachPreambleCount.end();
590 ++it)
591 {
592 uint16_t rnti = m_cmacSapUser->AllocateTemporaryCellRnti();
593
594 NS_LOG_INFO("Informing MAC scheduler of the RACH preamble for RAPID "
595 << static_cast<uint16_t>(it->first) << " in slot " << sfnSf
596 << "; Allocated RNTI: " << rnti);
597 RachListElement_s rachLe;
598 rachLe.m_rnti = rnti;
599 rachLe.m_estimatedSize = 144; // to be confirmed
600 rachInfoReqParams.m_rachList.emplace_back(rachLe);
601
602 m_rapIdRntiMap.insert(std::make_pair(rnti, it->first));
603 }
604 m_receivedRachPreambleCount.clear();
605 m_macSchedSapProvider->SchedDlRachInfoReq(rachInfoReqParams);
606 }
607
609
610 dlParams.m_slotType = type;
611 dlParams.m_snfSf = sfnSf;
612
613 // Forward DL HARQ feedbacks collected during last subframe TTI
614 if (!m_dlHarqInfoReceived.empty())
615 {
616 dlParams.m_dlHarqInfoList = m_dlHarqInfoReceived;
617 // empty local buffer
618 m_dlHarqInfoReceived.clear();
619
620 for (const auto& v : dlParams.m_dlHarqInfoList)
621 {
622 Ptr<NrDlHarqFeedbackMessage> msg = Create<NrDlHarqFeedbackMessage>();
623 msg->SetDlHarqFeedback(v);
624 m_macRxedCtrlMsgsTrace(m_currentSlot, GetCellId(), v.m_rnti, GetBwpId(), msg);
625 }
626 }
627
628 {
629 for (const auto& ue : m_rlcAttached)
630 {
632 params.m_rnti = ue.first;
633 params.m_beamId = m_phySapProvider->GetBeamId(ue.first);
634 params.m_transmissionMode = 0; // set to default value (SISO) for avoiding random
635 // initialization (valgrind error)
636 m_macCschedSapProvider->CschedUeConfigReq(params);
637 }
638 }
639
640 m_macSchedSapProvider->SchedDlTriggerReq(dlParams);
641}
642
643void
645{
646 NS_LOG_FUNCTION(this);
647 NS_LOG_LOGIC("Perform things on UL, slot on the air: " << sfnSf);
648
649 // --- UPLINK ---
650 // Send UL-CQI info to the scheduler
651 for (auto& i : m_ulCqiReceived)
652 {
653 // m_ulCqiReceived.at (i).m_sfnSf = ((0x3FF & frameNum) << 16) | ((0xFF & subframeNum) << 8)
654 // | (0xFF & varTtiNum);
655 m_macSchedSapProvider->SchedUlCqiInfoReq(i);
656 }
657 m_ulCqiReceived.clear();
658
659 // Send SR info to the scheduler
660 {
662 params.m_snfSf = m_currentSlot;
663 params.m_srList.insert(params.m_srList.begin(), m_srRntiList.begin(), m_srRntiList.end());
664 m_srRntiList.clear();
665
666 m_macSchedSapProvider->SchedUlSrInfoReq(params);
667
668 for (const auto& v : params.m_srList)
669 {
670 Ptr<NrSRMessage> msg = Create<NrSRMessage>();
671 msg->SetRNTI(v);
672 m_macRxedCtrlMsgsTrace(m_currentSlot, GetCellId(), v, GetBwpId(), msg);
673 }
674 }
675
676 // Send UL BSR reports to the scheduler
677 if (!m_ulCeReceived.empty())
678 {
680 ulMacReq.m_sfnSf = sfnSf;
681 ulMacReq.m_macCeList.insert(ulMacReq.m_macCeList.begin(),
682 m_ulCeReceived.begin(),
683 m_ulCeReceived.end());
684 m_ulCeReceived.erase(m_ulCeReceived.begin(), m_ulCeReceived.end());
685 m_macSchedSapProvider->SchedUlMacCtrlInfoReq(ulMacReq);
686
687 for (const auto& v : ulMacReq.m_macCeList)
688 {
689 Ptr<NrBsrMessage> msg = Create<NrBsrMessage>();
690 msg->SetBsr(v);
691 m_macRxedCtrlMsgsTrace(m_currentSlot, GetCellId(), v.m_rnti, GetBwpId(), msg);
692 }
693 }
694
696
697 ulParams.m_snfSf = sfnSf;
698 ulParams.m_slotType = type;
699
700 // Forward UL HARQ feebacks collected during last TTI
701 if (!m_ulHarqInfoReceived.empty())
702 {
703 ulParams.m_ulHarqInfoList = m_ulHarqInfoReceived;
704 // empty local buffer
705 m_ulHarqInfoReceived.clear();
706 }
707
708 m_macSchedSapProvider->SchedUlTriggerReq(ulParams);
709}
710
711void
712NrGnbMac::SetForwardUpCallback(Callback<void, Ptr<Packet>> cb)
713{
714 m_forwardUpCallback = cb;
715}
716
717void
718NrGnbMac::ReceiveBsrMessage(MacCeElement bsr)
719{
720 NS_LOG_FUNCTION(this);
721 // in order to use existing SAP interfaces we need to convert MacCeElement to MacCeListElement_s
722
723 MacCeListElement_s mcle;
724 mcle.m_rnti = bsr.m_rnti;
725 mcle.m_macCeValue.m_bufferStatus = bsr.m_macCeValue.m_bufferStatus;
726 mcle.m_macCeValue.m_crnti = bsr.m_macCeValue.m_crnti;
727 mcle.m_macCeValue.m_phr = bsr.m_macCeValue.m_phr;
728 mcle.m_macCeValue.m_bufferStatus = bsr.m_macCeValue.m_bufferStatus;
729
730 if (bsr.m_macCeType == MacCeElement::BSR)
731 {
732 mcle.m_macCeType = MacCeListElement_s::BSR;
733 }
734 else if (bsr.m_macCeType == MacCeElement::CRNTI)
735 {
736 mcle.m_macCeType = MacCeListElement_s::CRNTI;
737 }
738 else if (bsr.m_macCeType == MacCeElement::PHR)
739 {
740 mcle.m_macCeType = MacCeListElement_s::PHR;
741 }
742
743 m_ccmMacSapUser->UlReceiveMacCe(mcle, GetBwpId());
744}
745
746void
747NrGnbMac::DoReportMacCeToScheduler(MacCeListElement_s bsr)
748{
749 NS_LOG_FUNCTION(this);
750 NS_LOG_DEBUG(this << " bsr Size " << (uint16_t)m_ulCeReceived.size());
751 uint32_t size = 0;
752
753 // send to LteCcmMacSapUser
754 // convert MacCeListElement_s to MacCeElement
755
756 MacCeElement mce;
757 mce.m_rnti = bsr.m_rnti;
758 mce.m_macCeValue.m_bufferStatus = bsr.m_macCeValue.m_bufferStatus;
759 mce.m_macCeValue.m_crnti = bsr.m_macCeValue.m_crnti;
760 mce.m_macCeValue.m_phr = bsr.m_macCeValue.m_phr;
761 mce.m_macCeValue.m_bufferStatus = bsr.m_macCeValue.m_bufferStatus;
762
763 if (bsr.m_macCeType == MacCeListElement_s::BSR)
764 {
765 mce.m_macCeType = MacCeElement::BSR;
766 }
767 else if (bsr.m_macCeType == MacCeListElement_s::CRNTI)
768 {
769 mce.m_macCeType = MacCeElement::CRNTI;
770 }
771 else if (bsr.m_macCeType == MacCeListElement_s::PHR)
772 {
773 mce.m_macCeType = MacCeElement::PHR;
774 }
775
776 for (const auto& v : bsr.m_macCeValue.m_bufferStatus)
777 {
778 size += v;
779 }
780
781 m_ulCeReceived.push_back(
782 mce); // this to called when LteUlCcmSapProvider::ReportMacCeToScheduler is called
783 NS_LOG_DEBUG(" Reported by UE " << static_cast<uint32_t>(bsr.m_macCeValue.m_crnti) << " size "
784 << size << " bsr vector ize after push_back "
785 << static_cast<uint32_t>(m_ulCeReceived.size()));
786}
787
788void
789NrGnbMac::DoReportSrToScheduler(uint16_t rnti)
790{
791 NS_LOG_FUNCTION(this);
792 m_srRntiList.push_back(rnti);
793 m_srCallback(GetBwpId(), rnti);
794}
795
796void
797NrGnbMac::DoReceivePhyPdu(Ptr<Packet> p)
798{
799 NS_LOG_FUNCTION(this);
800
801 LteRadioBearerTag tag;
802 p->RemovePacketTag(tag);
803
804 uint16_t rnti = tag.GetRnti();
805 auto rntiIt = m_rlcAttached.find(rnti);
806
807 NS_ASSERT_MSG(rntiIt != m_rlcAttached.end(), "could not find RNTI" << rnti);
808
809 // Try to peek whatever header; in the first byte there will be the LC ID.
810 NrMacHeaderFsUl header;
811 p->PeekHeader(header);
812
813 // Based on LC ID, we know if it is a CE or simply data.
814 if (header.GetLcId() == NrMacHeaderFsUl::SHORT_BSR)
815 {
816 NrMacShortBsrCe bsrHeader;
817 p->RemoveHeader(bsrHeader); // Really remove the header this time
818
819 // Convert our custom header into the structure that the scheduler expects:
820 MacCeElement bsr;
821
822 bsr.m_macCeType = MacCeElement::BSR;
823 bsr.m_rnti = rnti;
824 bsr.m_macCeValue.m_bufferStatus.resize(4);
825 bsr.m_macCeValue.m_bufferStatus[0] = bsrHeader.m_bufferSizeLevel_0;
826 bsr.m_macCeValue.m_bufferStatus[1] = bsrHeader.m_bufferSizeLevel_1;
827 bsr.m_macCeValue.m_bufferStatus[2] = bsrHeader.m_bufferSizeLevel_2;
828 bsr.m_macCeValue.m_bufferStatus[3] = bsrHeader.m_bufferSizeLevel_3;
829
830 ReceiveBsrMessage(bsr); // Here it will be converted again, but our job is done.
831 return;
832 }
833
834 // Ok, we know it is data, so let's extract and pass to RLC.
835
836 NrMacHeaderVs macHeader;
837 p->RemoveHeader(macHeader);
838
839 auto lcidIt = rntiIt->second.find(macHeader.GetLcId());
840
841 LteMacSapUser::ReceivePduParameters rxParams;
842 rxParams.p = p;
843 rxParams.lcid = macHeader.GetLcId();
844 rxParams.rnti = rnti;
845
846 if (rxParams.p->GetSize())
847 {
848 (*lcidIt).second->ReceivePdu(rxParams);
849 }
850}
851
852NrGnbPhySapUser*
853NrGnbMac::GetPhySapUser()
854{
855 return m_phySapUser;
856}
857
858void
859NrGnbMac::SetPhySapProvider(NrPhySapProvider* ptr)
860{
861 m_phySapProvider = ptr;
862}
863
864NrMacSchedSapUser*
865NrGnbMac::GetNrMacSchedSapUser()
866{
867 return m_macSchedSapUser;
868}
869
870void
871NrGnbMac::SetNrMacSchedSapProvider(NrMacSchedSapProvider* ptr)
872{
873 m_macSchedSapProvider = ptr;
874}
875
876NrMacCschedSapUser*
877NrGnbMac::GetNrMacCschedSapUser()
878{
879 return m_macCschedSapUser;
880}
881
882void
883NrGnbMac::SetNrMacCschedSapProvider(NrMacCschedSapProvider* ptr)
884{
885 m_macCschedSapProvider = ptr;
886}
887
888void
889NrGnbMac::DoUlCqiReport(NrMacSchedSapProvider::SchedUlCqiInfoReqParameters ulcqi)
890{
891 if (ulcqi.m_ulCqi.m_type == UlCqiInfo::PUSCH)
892 {
893 NS_LOG_DEBUG(this << " gNB rxed an PUSCH UL-CQI");
894 }
895 else if (ulcqi.m_ulCqi.m_type == UlCqiInfo::SRS)
896 {
897 NS_LOG_DEBUG(this << " gNB rxed an SRS UL-CQI");
898 }
899 NS_LOG_INFO("*** UL CQI report SINR "
900 << LteFfConverter::fpS11dot3toDouble(ulcqi.m_ulCqi.m_sinr[0])
901 << " slot: " << m_currentSlot);
902
903 // NS_ASSERT (ulcqi.m_sfnSf.m_varTtiNum != 0); Now UL data can be the first TTI..
904 m_ulCqiReceived.push_back(ulcqi);
905}
906
907void
908NrGnbMac::DoReceiveControlMessage(Ptr<NrControlMessage> msg)
909{
910 NS_LOG_FUNCTION(this << msg);
911
912 switch (msg->GetMessageType())
913 {
914 case (NrControlMessage::SR): {
915 // Report it to the CCM. Then he will call the right MAC
916 Ptr<NrSRMessage> sr = DynamicCast<NrSRMessage>(msg);
917 m_ccmMacSapUser->UlReceiveSr(sr->GetRNTI(), GetBwpId());
918 break;
919 }
921 Ptr<NrDlCqiMessage> cqi = DynamicCast<NrDlCqiMessage>(msg);
922 DlCqiInfo cqiElement = cqi->GetDlCqi();
923 NS_ASSERT(cqiElement.m_rnti != 0);
924 m_dlCqiReceived.push_back(cqiElement);
925 break;
926 }
928 Ptr<NrDlHarqFeedbackMessage> dlharq = DynamicCast<NrDlHarqFeedbackMessage>(msg);
929 DoDlHarqFeedback(dlharq->GetDlHarqFeedback());
930 break;
931 }
932 default:
933 NS_LOG_WARN("Control message not supported/expected");
934 }
935}
936
937void
938NrGnbMac::DoUlHarqFeedback(const UlHarqInfo& params)
939{
940 NS_LOG_FUNCTION(this);
941 m_ulHarqInfoReceived.push_back(params);
942}
943
944void
945NrGnbMac::DoDlHarqFeedback(const DlHarqInfo& params)
946{
947 NS_LOG_FUNCTION(this);
948 // Update HARQ buffer
949 std::unordered_map<uint16_t, NrDlHarqProcessesBuffer_t>::iterator it =
950 m_miDlHarqProcessesPackets.find(params.m_rnti);
951 NS_ASSERT(it != m_miDlHarqProcessesPackets.end());
952
953 if (params.m_harqStatus == DlHarqInfo::ACK)
954 {
955 // discard buffer
956 Ptr<PacketBurst> emptyBuf = CreateObject<PacketBurst>();
957 (*it).second.at(params.m_harqProcessId).m_pktBurst = emptyBuf;
958 NS_LOG_DEBUG(this << " HARQ-ACK UE RNTI" << params.m_rnti << " HARQ Process ID "
959 << (uint16_t)params.m_harqProcessId);
960 }
961 else if (params.m_harqStatus == DlHarqInfo::NACK)
962 {
963 NS_LOG_DEBUG(this << " HARQ-NACK UE RNTI" << params.m_rnti << " HARQ Process ID "
964 << (uint16_t)params.m_harqProcessId);
965 }
966 else
967 {
968 NS_FATAL_ERROR(" HARQ functionality not implemented");
969 }
970
971 /* trace for HARQ feedback*/
972 m_dlHarqFeedback(params);
973
974 m_dlHarqInfoReceived.push_back(params);
975}
976
977void
978NrGnbMac::DoReportBufferStatus(LteMacSapProvider::ReportBufferStatusParameters params)
979{
980 NS_LOG_FUNCTION(this);
981 NrMacSchedSapProvider::SchedDlRlcBufferReqParameters schedParams;
982 schedParams.m_logicalChannelIdentity = params.lcid;
983 schedParams.m_rlcRetransmissionHolDelay = params.retxQueueHolDelay;
984 schedParams.m_rlcRetransmissionQueueSize = params.retxQueueSize;
985 schedParams.m_rlcStatusPduSize = params.statusPduSize;
986 schedParams.m_rlcTransmissionQueueHolDelay = params.txQueueHolDelay;
987 schedParams.m_rlcTransmissionQueueSize = params.txQueueSize;
988 schedParams.m_rnti = params.rnti;
989
990 NS_LOG_INFO("Reporting RLC buffer status update to MAC Scheduler for RNTI="
991 << params.rnti << ", LCID=" << (uint32_t)params.lcid << ", Transmission Queue Size="
992 << params.txQueueSize << ", Transmission Queue HOL Delay=" << params.txQueueHolDelay
993 << ", Retransmission Queue Size=" << params.retxQueueSize
994 << ", Retransmission Queue HOL delay=" << params.retxQueueHolDelay
995 << ", PDU Size=" << params.statusPduSize);
996
997 m_macSchedSapProvider->SchedDlRlcBufferReq(schedParams);
998}
999
1000// forwarded from LteMacSapProvider
1001void
1002NrGnbMac::DoTransmitPdu(LteMacSapProvider::TransmitPduParameters params)
1003{
1004 // TB UID passed back along with RLC data as HARQ process ID
1005 uint32_t tbMapKey = ((params.rnti & 0xFFFF) << 8) | (params.harqProcessId & 0xFF);
1006 auto harqIt = m_miDlHarqProcessesPackets.find(params.rnti);
1007 auto it = m_macPduMap.find(tbMapKey);
1008
1009 if (it == m_macPduMap.end())
1010 {
1011 NS_FATAL_ERROR("No MAC PDU storage element found for this TB UID/RNTI");
1012 }
1013
1014 NrMacHeaderVs header;
1015 header.SetLcId(params.lcid);
1016 header.SetSize(params.pdu->GetSize());
1017
1018 params.pdu->AddHeader(header);
1019
1020 LteRadioBearerTag bearerTag(params.rnti, params.lcid, 0);
1021 params.pdu->AddPacketTag(bearerTag);
1022
1023 harqIt->second.at(params.harqProcessId).m_pktBurst->AddPacket(params.pdu);
1024
1025 it->second.m_used += params.pdu->GetSize();
1026 NS_ASSERT_MSG(it->second.m_dci->m_tbSize >= it->second.m_used,
1027 "DCI OF " << it->second.m_dci->m_tbSize << " total used " << it->second.m_used);
1028
1029 NS_LOG_INFO("Sending MAC PDU to PHY Layer");
1030 m_phySapProvider->SendMacPdu(params.pdu,
1031 it->second.m_sfnSf,
1032 it->second.m_dci->m_symStart,
1033 params.rnti);
1034}
1035
1036void
1037NrGnbMac::SendRar(const std::vector<BuildRarListElement_s>& rarList)
1038{
1039 NS_LOG_FUNCTION(this);
1040
1041 // Random Access procedure: send RARs
1042 Ptr<NrRarMessage> rarMsg = Create<NrRarMessage>();
1043 uint16_t raRnti = 1; // NO!! 38.321-5.1.3
1044 rarMsg->SetRaRnti(raRnti);
1045 rarMsg->SetSourceBwp(GetBwpId());
1046 for (const auto& rarAllocation : rarList)
1047 {
1048 auto itRapId = m_rapIdRntiMap.find(rarAllocation.m_rnti);
1049 NS_ABORT_IF(itRapId == m_rapIdRntiMap.end());
1050 NrRarMessage::Rar rar;
1051 rar.rapId = itRapId->second;
1052 rar.rarPayload = rarAllocation;
1053 rarMsg->AddRar(rar);
1054 NS_LOG_INFO("In slot " << m_currentSlot << " send to PHY the RAR message for RNTI "
1055 << rarAllocation.m_rnti << " rapId " << itRapId->second);
1056 m_macTxedCtrlMsgsTrace(m_currentSlot,
1057 GetCellId(),
1058 rarAllocation.m_rnti,
1059 GetBwpId(),
1060 rarMsg);
1061 }
1062
1063 if (!rarList.empty())
1064 {
1065 m_phySapProvider->SendControlMessage(rarMsg);
1066 m_rapIdRntiMap.clear();
1067 }
1068}
1069
1070void
1071NrGnbMac::DoSchedConfigIndication(NrMacSchedSapUser::SchedConfigIndParameters ind)
1072{
1073 NS_ASSERT(ind.m_sfnSf.GetNumerology() == m_currentSlot.GetNumerology());
1074 std::sort(ind.m_slotAllocInfo.m_varTtiAllocInfo.begin(),
1075 ind.m_slotAllocInfo.m_varTtiAllocInfo.end());
1076
1077 if (ind.m_slotAllocInfo.ContainsDataAllocation())
1078 {
1079 NS_LOG_INFO("New scheduled allocation: " << ind.m_slotAllocInfo);
1080 }
1081 m_phySapProvider->SetSlotAllocInfo(ind.m_slotAllocInfo);
1082
1083 SendRar(ind.m_buildRarList);
1084
1085 for (auto& varTtiAllocInfo : ind.m_slotAllocInfo.m_varTtiAllocInfo)
1086 {
1087 if (varTtiAllocInfo.m_dci->m_type != DciInfoElementTdma::CTRL &&
1088 varTtiAllocInfo.m_dci->m_format == DciInfoElementTdma::DL)
1089 {
1090 uint16_t rnti = varTtiAllocInfo.m_dci->m_rnti;
1091 auto rntiIt = m_rlcAttached.find(rnti);
1092 NS_ABORT_MSG_IF(rntiIt == m_rlcAttached.end(),
1093 "Scheduled UE " << rntiIt->first << " not attached");
1094
1095 // Call RLC entities to generate RLC PDUs
1096 auto dciElem = varTtiAllocInfo.m_dci;
1097 uint8_t harqId = dciElem->m_harqProcess;
1098
1099 if (ind.m_slotAllocInfo.ContainsDataAllocation())
1100 {
1101 NS_LOG_INFO("New scheduled data TX in DL for HARQ Process ID: "
1102 << (uint32_t)harqId << ", Var. TTI from symbol "
1103 << (uint32_t)varTtiAllocInfo.m_dci->m_symStart << " to "
1104 << (uint32_t)varTtiAllocInfo.m_dci->m_symStart +
1105 (uint32_t)varTtiAllocInfo.m_dci->m_numSym
1106 << ". "
1107 << " TB of size " << varTtiAllocInfo.m_dci->m_tbSize << " with MCS "
1108 << varTtiAllocInfo.m_dci->m_mcs);
1109 }
1110
1111 // update Harq Processes
1112 if (dciElem->m_ndi == 1)
1113 {
1114 NS_ASSERT(dciElem->m_format == DciInfoElementTdma::DL);
1115 std::vector<RlcPduInfo>& rlcPduInfo = varTtiAllocInfo.m_rlcPduInfo;
1116 NS_ASSERT(!rlcPduInfo.empty());
1117 NrMacPduInfo macPduInfo(ind.m_sfnSf, dciElem);
1118 // insert into MAC PDU map
1119 uint32_t tbMapKey = ((rnti & 0xFFFF) << 8) | (harqId & 0xFF);
1120 std::pair<std::unordered_map<uint32_t, struct NrMacPduInfo>::iterator, bool>
1121 mapRet = m_macPduMap.insert(
1122 std::pair<uint32_t, struct NrMacPduInfo>(tbMapKey, macPduInfo));
1123 if (!mapRet.second)
1124 {
1125 NS_FATAL_ERROR("MAC PDU map element exists");
1126 }
1127
1128 // new data -> force emptying correspondent harq pkt buffer
1129 std::unordered_map<uint16_t, NrDlHarqProcessesBuffer_t>::iterator harqIt =
1130 m_miDlHarqProcessesPackets.find(rnti);
1131 NS_ASSERT(harqIt != m_miDlHarqProcessesPackets.end());
1132 Ptr<PacketBurst> pb = CreateObject<PacketBurst>();
1133 harqIt->second.at(harqId).m_pktBurst = pb;
1134 harqIt->second.at(harqId).m_lcidList.clear();
1135
1136 std::unordered_map<uint32_t, struct NrMacPduInfo>::iterator pduMapIt = mapRet.first;
1137 // for each LC j
1138 for (auto& j : rlcPduInfo)
1139 {
1140 NS_ASSERT_MSG(rntiIt != m_rlcAttached.end(), "could not find RNTI" << rnti);
1141 std::unordered_map<uint8_t, LteMacSapUser*>::iterator lcidIt =
1142 rntiIt->second.find(j.m_lcid);
1143 NS_ASSERT_MSG(lcidIt != rntiIt->second.end(),
1144 "could not find LCID" << j.m_lcid);
1145 NS_LOG_INFO("Notifying RLC of TX opportunity for HARQ Process ID "
1146 << (unsigned int)harqId << " LC ID " << +j.m_lcid
1147 << (unsigned int)j.m_size);
1148
1149 (*lcidIt).second->NotifyTxOpportunity(
1150 LteMacSapUser::TxOpportunityParameters((j.m_size),
1151 0,
1152 harqId,
1153 GetBwpId(),
1154 rnti,
1155 j.m_lcid));
1156 harqIt->second.at(harqId).m_lcidList.push_back(j.m_lcid);
1157 }
1158
1159 m_macPduMap.erase(pduMapIt); // delete map entry
1160
1161 NrSchedulingCallbackInfo traceInfo;
1162 traceInfo.m_frameNum = ind.m_sfnSf.GetFrame();
1163 traceInfo.m_subframeNum = ind.m_sfnSf.GetSubframe();
1164 traceInfo.m_slotNum = ind.m_sfnSf.GetSlot();
1165 traceInfo.m_symStart = dciElem->m_symStart;
1166 traceInfo.m_numSym = dciElem->m_numSym;
1167 traceInfo.m_tbSize = dciElem->m_tbSize;
1168 traceInfo.m_mcs = dciElem->m_mcs;
1169 traceInfo.m_rnti = dciElem->m_rnti;
1170 traceInfo.m_bwpId = GetBwpId();
1171 traceInfo.m_ndi = dciElem->m_ndi;
1172 traceInfo.m_rv = dciElem->m_rv;
1173 traceInfo.m_harqId = dciElem->m_harqProcess;
1174 m_dlScheduling(traceInfo);
1175 }
1176 else
1177 {
1178 NS_LOG_INFO("DL retransmission");
1179 if (dciElem->m_tbSize > 0)
1180 {
1181 std::unordered_map<uint16_t, NrDlHarqProcessesBuffer_t>::iterator it =
1182 m_miDlHarqProcessesPackets.find(rnti);
1183 NS_ASSERT(it != m_miDlHarqProcessesPackets.end());
1184 Ptr<PacketBurst> pb = it->second.at(harqId).m_pktBurst;
1185 for (std::list<Ptr<Packet>>::const_iterator j = pb->Begin(); j != pb->End();
1186 ++j)
1187 {
1188 Ptr<Packet> pkt = (*j)->Copy();
1189 m_phySapProvider->SendMacPdu(pkt,
1190 ind.m_sfnSf,
1191 dciElem->m_symStart,
1192 dciElem->m_rnti);
1193 }
1194 }
1195 }
1196 }
1197 else if (varTtiAllocInfo.m_dci->m_type != DciInfoElementTdma::CTRL &&
1198 varTtiAllocInfo.m_dci->m_type != DciInfoElementTdma::SRS &&
1199 varTtiAllocInfo.m_dci->m_format == DciInfoElementTdma::UL)
1200 {
1201 // UL scheduling info trace
1202 // Call RLC entities to generate RLC PDUs
1203 auto dciElem = varTtiAllocInfo.m_dci;
1204 NrSchedulingCallbackInfo traceInfo;
1205 traceInfo.m_frameNum = ind.m_sfnSf.GetFrame();
1206 traceInfo.m_subframeNum = ind.m_sfnSf.GetSubframe();
1207 traceInfo.m_slotNum = ind.m_sfnSf.GetSlot();
1208 traceInfo.m_symStart = dciElem->m_symStart;
1209 traceInfo.m_numSym = dciElem->m_numSym;
1210 traceInfo.m_tbSize = dciElem->m_tbSize;
1211 traceInfo.m_mcs = dciElem->m_mcs;
1212 traceInfo.m_rnti = dciElem->m_rnti;
1213 traceInfo.m_bwpId = GetBwpId();
1214 traceInfo.m_ndi = dciElem->m_ndi;
1215 traceInfo.m_rv = dciElem->m_rv;
1216 traceInfo.m_harqId = dciElem->m_harqProcess;
1217 m_ulScheduling(traceInfo);
1218 }
1219 }
1220}
1221
1222// ////////////////////////////////////////////
1223// CMAC SAP
1224// ////////////////////////////////////////////
1225
1226void
1227NrGnbMac::DoConfigureMac(uint16_t ulBandwidth, uint16_t dlBandwidth)
1228{
1229 NS_LOG_FUNCTION(this);
1230
1231 // The bandwidth arrived in Hz. We need to know it in number of RB, and then
1232 // consider how many RB are inside a single RBG.
1233 uint16_t bw_in_rbg = m_phySapProvider->GetRbNum() / GetNumRbPerRbg();
1234 m_bandwidthInRbg = bw_in_rbg;
1235
1236 NS_LOG_DEBUG("Mac configured. Attributes:"
1237 << std::endl
1238 << "\t NumRbPerRbg: " << m_numRbPerRbg << std::endl
1239 << "\t NumHarqProcess: " << +m_numHarqProcess << std::endl
1240 << "Physical properties: " << std::endl
1241 << "\t Bandwidth provided: " << ulBandwidth * 1000 * 100 << " Hz" << std::endl
1242 << "\t that corresponds to " << bw_in_rbg << " RBG, as we have "
1243 << m_phySapProvider->GetRbNum() << " RB and " << GetNumRbPerRbg()
1244 << " RB per RBG");
1245
1246 NrMacCschedSapProvider::CschedCellConfigReqParameters params;
1247
1248 params.m_ulBandwidth = m_bandwidthInRbg;
1249 params.m_dlBandwidth = m_bandwidthInRbg;
1250
1251 m_macCschedSapProvider->CschedCellConfigReq(params);
1252}
1253
1254void
1256{
1258 params.m_rnti = rnti;
1259 params.m_beamId = beamId;
1260 params.m_transmissionMode =
1261 0; // set to default value (SISO) for avoiding random initialization (valgrind error)
1262 m_macCschedSapProvider->CschedUeConfigReq(params);
1263}
1264
1265uint16_t
1267{
1268 if (m_phySapProvider)
1269 {
1270 return m_phySapProvider->GetBwpId();
1271 }
1272 else
1273 {
1274 return UINT16_MAX;
1275 }
1276}
1277
1278uint16_t
1280{
1281 if (m_phySapProvider)
1282 {
1283 return m_phySapProvider->GetCellId();
1284 }
1285 else
1286 {
1287 return UINT16_MAX;
1288 }
1289}
1290
1291std::shared_ptr<DciInfoElementTdma>
1293{
1294 NS_LOG_FUNCTION(this);
1295
1296 auto bwInRbg = m_phySapProvider->GetRbNum() / GetNumRbPerRbg();
1297 NS_ASSERT(bwInRbg > 0);
1298 std::vector<uint8_t> rbgBitmask(bwInRbg, 1);
1299
1300 return std::make_shared<DciInfoElementTdma>(0,
1301 m_macSchedSapProvider->GetDlCtrlSyms(),
1304 rbgBitmask);
1305}
1306
1307std::shared_ptr<DciInfoElementTdma>
1309{
1310 NS_LOG_FUNCTION(this);
1311
1312 NS_ASSERT(m_bandwidthInRbg > 0);
1313 std::vector<uint8_t> rbgBitmask(m_bandwidthInRbg, 1);
1314
1315 return std::make_shared<DciInfoElementTdma>(0,
1316 m_macSchedSapProvider->GetUlCtrlSyms(),
1319 rbgBitmask);
1320}
1321
1322void
1323NrGnbMac::DoAddUe(uint16_t rnti)
1324{
1325 NS_LOG_FUNCTION(this << " rnti=" << rnti);
1326 std::unordered_map<uint8_t, LteMacSapUser*> empty;
1327 std::pair<std::unordered_map<uint16_t, std::unordered_map<uint8_t, LteMacSapUser*>>::iterator,
1328 bool>
1329 ret = m_rlcAttached.insert(
1330 std::pair<uint16_t, std::unordered_map<uint8_t, LteMacSapUser*>>(rnti, empty));
1331 NS_ASSERT_MSG(ret.second, "element already present, RNTI already existed");
1332
1334 params.m_rnti = rnti;
1335 params.m_beamId = m_phySapProvider->GetBeamId(rnti);
1336 params.m_transmissionMode =
1337 0; // set to default value (SISO) for avoiding random initialization (valgrind error)
1338 m_macCschedSapProvider->CschedUeConfigReq(params);
1339
1340 // Create DL transmission HARQ buffers
1341 NrDlHarqProcessesBuffer_t buf;
1342 uint16_t harqNum = GetNumHarqProcess();
1343 buf.resize(harqNum);
1344 for (uint16_t i = 0; i < harqNum; i++)
1345 {
1346 Ptr<PacketBurst> pb = CreateObject<PacketBurst>();
1347 buf.at(i).m_pktBurst = pb;
1348 }
1349 m_miDlHarqProcessesPackets.insert(std::pair<uint16_t, NrDlHarqProcessesBuffer_t>(rnti, buf));
1350}
1351
1352void
1353NrGnbMac::DoRemoveUe(uint16_t rnti)
1354{
1355 NS_LOG_FUNCTION(this << " rnti=" << rnti);
1356 NrMacCschedSapProvider::CschedUeReleaseReqParameters params;
1357 params.m_rnti = rnti;
1358 m_macCschedSapProvider->CschedUeReleaseReq(params);
1359 m_miDlHarqProcessesPackets.erase(rnti);
1360 m_rlcAttached.erase(rnti);
1361}
1362
1363void
1364NrGnbMac::DoAddLc(LteEnbCmacSapProvider::LcInfo lcinfo, LteMacSapUser* msu)
1365{
1366 NS_LOG_FUNCTION(this);
1367 NS_LOG_FUNCTION(this);
1368
1369 std::unordered_map<uint16_t, std::unordered_map<uint8_t, LteMacSapUser*>>::iterator rntiIt =
1370 m_rlcAttached.find(lcinfo.rnti);
1371 NS_ASSERT_MSG(rntiIt != m_rlcAttached.end(), "RNTI not found");
1372 std::unordered_map<uint8_t, LteMacSapUser*>::iterator lcidIt = rntiIt->second.find(lcinfo.lcId);
1373 if (lcidIt == rntiIt->second.end())
1374 {
1375 rntiIt->second.insert(std::pair<uint8_t, LteMacSapUser*>(lcinfo.lcId, msu));
1376 }
1377 else
1378 {
1379 NS_LOG_ERROR("LC already exists");
1380 }
1381
1382 // CCCH (LCID 0) is pre-configured
1383 // see FF LTE MAC Scheduler
1384 // Interface Specification v1.11,
1385 // 4.3.4 logicalChannelConfigListElement
1386 if (lcinfo.lcId != 0)
1387 {
1388 struct NrMacCschedSapProvider::CschedLcConfigReqParameters params;
1389 params.m_rnti = lcinfo.rnti;
1390 params.m_reconfigureFlag = false;
1391
1392 struct LogicalChannelConfigListElement_s lccle;
1393 lccle.m_logicalChannelIdentity = lcinfo.lcId;
1394 lccle.m_logicalChannelGroup = lcinfo.lcGroup;
1395 lccle.m_direction = LogicalChannelConfigListElement_s::DIR_BOTH;
1396 lccle.m_qci = lcinfo.qci;
1397 lccle.m_eRabMaximulBitrateUl = lcinfo.mbrUl;
1398 lccle.m_eRabMaximulBitrateDl = lcinfo.mbrDl;
1399 lccle.m_eRabGuaranteedBitrateUl = lcinfo.gbrUl;
1400 lccle.m_eRabGuaranteedBitrateDl = lcinfo.gbrDl;
1401
1402 lccle.m_qosBearerType =
1403 static_cast<LogicalChannelConfigListElement_s::QosBearerType_e>(lcinfo.resourceType);
1404
1405 params.m_logicalChannelConfigList.push_back(lccle);
1406
1407 m_macCschedSapProvider->CschedLcConfigReq(params);
1408 }
1409}
1410
1411void
1412NrGnbMac::DoReconfigureLc(LteEnbCmacSapProvider::LcInfo lcinfo)
1413{
1414 NS_FATAL_ERROR("not implemented");
1415}
1416
1417void
1418NrGnbMac::DoReleaseLc(uint16_t rnti, uint8_t lcid)
1419{
1420 // Find user based on rnti and then erase lcid stored against the same
1421 std::unordered_map<uint16_t, std::unordered_map<uint8_t, LteMacSapUser*>>::iterator rntiIt =
1422 m_rlcAttached.find(rnti);
1423 rntiIt->second.erase(lcid);
1424
1425 struct NrMacCschedSapProvider::CschedLcReleaseReqParameters params;
1426 params.m_rnti = rnti;
1427 params.m_logicalChannelIdentity.push_back(lcid);
1428 m_macCschedSapProvider->CschedLcReleaseReq(params);
1429}
1430
1431void
1432NrGnbMac::UeUpdateConfigurationReq(LteEnbCmacSapProvider::UeConfig params)
1433{
1434 NS_LOG_FUNCTION(this);
1435 // propagates to scheduler
1436 NrMacCschedSapProvider::CschedUeConfigReqParameters req;
1437 req.m_rnti = params.m_rnti;
1438 req.m_transmissionMode = params.m_transmissionMode;
1439 req.m_beamId = m_phySapProvider->GetBeamId(params.m_rnti);
1440 req.m_reconfigureFlag = true;
1441 m_macCschedSapProvider->CschedUeConfigReq(req);
1442}
1443
1444LteEnbCmacSapProvider::RachConfig
1445NrGnbMac::DoGetRachConfig()
1446{
1447 // UEs in NR does not choose RACH preambles randomly, therefore,
1448 // it does not rely on the following parameters. However, the
1449 // recent change in LteUeRrc class introduced an assert to
1450 // check the correct value of connEstFailCount parameter.
1451 // Thus, we need to assign dummy but correct values to
1452 // avoid this assert in LteUeRrc class.
1453 LteEnbCmacSapProvider::RachConfig rc;
1454 rc.numberOfRaPreambles = 52;
1455 rc.preambleTransMax = 50;
1456 rc.raResponseWindowSize = 3;
1457 rc.connEstFailCount = 1;
1458 return rc;
1459}
1460
1461LteEnbCmacSapProvider::AllocateNcRaPreambleReturnValue
1462NrGnbMac::DoAllocateNcRaPreamble(uint16_t rnti)
1463{
1464 return LteEnbCmacSapProvider::AllocateNcRaPreambleReturnValue();
1465}
1466
1467// ////////////////////////////////////////////
1468// CSCHED SAP
1469// ////////////////////////////////////////////
1470
1471void
1472NrGnbMac::DoCschedCellConfigCnf(NrMacCschedSapUser::CschedCellConfigCnfParameters params)
1473{
1474 NS_LOG_FUNCTION(this);
1475}
1476
1477void
1478NrGnbMac::DoCschedUeConfigCnf(NrMacCschedSapUser::CschedUeConfigCnfParameters params)
1479{
1480 NS_LOG_FUNCTION(this);
1481}
1482
1483void
1484NrGnbMac::DoCschedLcConfigCnf(NrMacCschedSapUser::CschedLcConfigCnfParameters params)
1485{
1486 NS_LOG_FUNCTION(this);
1487 // Call the CSCHED primitive
1488 // m_cschedSap->LcConfigCompleted();
1489}
1490
1491void
1492NrGnbMac::DoCschedLcReleaseCnf(NrMacCschedSapUser::CschedLcReleaseCnfParameters params)
1493{
1494 NS_LOG_FUNCTION(this);
1495}
1496
1497void
1498NrGnbMac::DoCschedUeReleaseCnf(NrMacCschedSapUser::CschedUeReleaseCnfParameters params)
1499{
1500 NS_LOG_FUNCTION(this);
1501}
1502
1503void
1504NrGnbMac::DoCschedUeConfigUpdateInd(NrMacCschedSapUser::CschedUeConfigUpdateIndParameters params)
1505{
1506 NS_LOG_FUNCTION(this);
1507 // propagates to RRC
1508 LteEnbCmacSapUser::UeConfig ueConfigUpdate;
1509 ueConfigUpdate.m_rnti = params.m_rnti;
1510 ueConfigUpdate.m_transmissionMode = params.m_transmissionMode;
1511 m_cmacSapUser->RrcConfigurationUpdateInd(ueConfigUpdate);
1512}
1513
1514void
1515NrGnbMac::DoCschedCellConfigUpdateInd(
1516 NrMacCschedSapUser::CschedCellConfigUpdateIndParameters params)
1517{
1518 NS_LOG_FUNCTION(this);
1519}
1520
1521} // namespace ns3
Representation of a beam id.
Definition beam-id.h:28
@ DL_HARQ
DL HARQ feedback.
@ SR
Scheduling Request: asking for space.
virtual uint8_t GetUlCtrlSyms() const
Retrieve the number of UL ctrl symbols configured in the scheduler.
uint8_t GetNumHarqProcess() const
virtual void DoSlotDlIndication(const SfnSf &sfnSf, LteNrTddSlotType type)
Perform DL scheduling decision for the indicated slot.
std::shared_ptr< DciInfoElementTdma > GetUlCtrlDci() const
Get a DCI for the UL CTRL symbol.
uint16_t GetBwpId() const
Get the bwp id of this MAC.
void SetNumRbPerRbg(uint32_t rbgSize)
Sets the number of RBs per RBG. Currently it can be configured by the user, while in the future it wi...
void SetNumHarqProcess(uint8_t numHarqProcess)
Sets the number of HARQ processes.
~NrGnbMac() override
~NrGnbMac
std::shared_ptr< DciInfoElementTdma > GetDlCtrlDci() const
Get a DCI for the DL CTRL symbol.
void BeamChangeReport(BeamId beamId, uint8_t rnti)
A Beam for a user has changed.
uint16_t GetCellId() const
Get the cell id of this MAC.
void SetLteCcmMacSapUser(LteCcmMacSapUser *s)
Set the ComponentCarrierManager SAP user.
uint32_t GetNumRbPerRbg() const
virtual void SetCurrentSfn(const SfnSf &sfn)
Set the current sfn.
virtual void DoSlotUlIndication(const SfnSf &sfnSf, LteNrTddSlotType type)
Perform UL scheduling decision for the indicated slot.
LteCcmMacSapProvider * GetLteCcmMacSapProvider()
Get the gNB-ComponentCarrierManager SAP User.
virtual uint8_t GetDlCtrlSyms() const
Retrieve the number of DL ctrl symbols configured in the scheduler.
void DoDispose() override
DoDispose method inherited from Object.
virtual void CschedCellConfigReq(const struct CschedCellConfigReqParameters &params)=0
CSCHED_CELL_CONFIG_REQ.
static const uint8_t SHORT_BSR
Short BSR.
virtual void SchedDlRachInfoReq(const SchedDlRachInfoReqParameters &params)=0
SCHED_DL_RACH_INFO_REQ.
virtual uint8_t GetDlCtrlSyms() const =0
Retrieve the number of DL ctrl symbols configured in the scheduler.
virtual void SchedUlSrInfoReq(const SchedUlSrInfoReqParameters &params)=0
Provides scheduling request reception information to the scheduler.
virtual void SchedUlTriggerReq(const struct SchedUlTriggerReqParameters &params)=0
Starts the UL MAC scheduler for this subframe.
virtual void SchedDlTriggerReq(const struct SchedDlTriggerReqParameters &params)=0
Starts the DL MAC scheduler for this subframe.
virtual uint8_t GetUlCtrlSyms() const =0
Retrieve the number of UL ctrl symbols configured in the scheduler.
virtual BeamId GetBeamId(uint8_t rnti) const =0
Get the beam ID from the RNTI specified. Not in any standard.
virtual void SendMacPdu(const Ptr< Packet > &p, const SfnSf &sfn, uint8_t symStart, uint16_t rnti)=0
Send a Mac PDU.
virtual uint16_t GetCellId() const =0
Retrieve the cell id.
virtual uint32_t GetRbNum() const =0
Retrieve the number of resource blocks.
virtual void SendControlMessage(Ptr< NrControlMessage > msg)=0
Send a control message.
virtual void SetSlotAllocInfo(const SlotAllocInfo &slotAllocInfo)=0
Set a SlotAllocInfo inside the PHY allocations.
virtual uint16_t GetBwpId() const =0
Retrieve the bandwidth part id.
The SfnSf class.
Definition sfnsf.h:34
uint8_t GetNumerology() const
GetNumerology.
Definition sfnsf.cc:172
LteNrTddSlotType
Available TDD slot types. Ordering is important.
NrSchedulingCallbackInfo structure.
uint8_t m_ndi
New data indicator.
uint8_t m_symStart
starting symbol index
uint8_t m_subframeNum
subframe number
uint16_t m_frameNum
frame number
uint8_t m_bwpId
Bandwidth Part ID.
uint16_t m_slotNum
slot number
uint8_t m_numSym
number of symbols
@ CTRL
Used for DL/UL CTRL.
@ SRS
Used for SRS (it would be like DCI format 2_3)
enum ns3::DlHarqInfo::HarqStatus NACK
HARQ status.
std::vector< struct DlCqiInfo > m_cqiList
cqi list
std::vector< struct RachListElement_s > m_rachList
RACH list.
DL HARQ information to be used when scheduling UL data.
std::vector< struct DlHarqInfo > m_dlHarqInfoList
DL HARQ info list.
LteNrTddSlotType m_slotType
Indicate the type of slot requested.
The SchedUlMacCtrlInfoReqParameters struct.
std::vector< struct MacCeElement > m_macCeList
MacCeElement list.
SR received from MAC, to pass to schedulers.
std::vector< uint16_t > m_srList
List of RNTI which asked for a SR.
SfnSf m_snfSf
SnfSf in which the sr where received.
UL HARQ information to be used when scheduling UL data.
std::vector< struct UlHarqInfo > m_ulHarqInfoList
UL HARQ info list.
LteNrTddSlotType m_slotType
Indicate the type of slot requested.