5G-LENA nr-v3.0-33-g7aea1e4
The 5G/NR module for the ns-3 simulator
Loading...
Searching...
No Matches
nr-ue-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() << ", rnti " \
11 << m_rnti << "] "; \
12 } while (false);
13
14#include "nr-ue-mac.h"
15
16#include "nr-control-messages.h"
17#include "nr-mac-header-vs.h"
18#include "nr-mac-short-bsr-ce.h"
19#include "nr-phy-sap.h"
20
21#include <ns3/boolean.h>
22#include <ns3/log.h>
23#include <ns3/lte-radio-bearer-tag.h>
24#include <ns3/random-variable-stream.h>
25#include <ns3/uinteger.h>
26
27namespace ns3
28{
29
30NS_LOG_COMPONENT_DEFINE("NrUeMac");
31NS_OBJECT_ENSURE_REGISTERED(NrUeMac);
32
33uint8_t NrUeMac::g_raPreambleId = 0;
34
36// SAP forwarders
38
39class UeMemberNrUeCmacSapProvider : public LteUeCmacSapProvider
40{
41 public:
42 UeMemberNrUeCmacSapProvider(NrUeMac* mac);
43
44 // inherited from LteUeCmacSapProvider
45 void ConfigureRach(RachConfig rc) override;
46 void StartContentionBasedRandomAccessProcedure() override;
47 void StartNonContentionBasedRandomAccessProcedure(uint16_t rnti,
48 uint8_t preambleId,
49 uint8_t prachMask) override;
50 void AddLc(uint8_t lcId,
51 LteUeCmacSapProvider::LogicalChannelConfig lcConfig,
52 LteMacSapUser* msu) override;
53 void RemoveLc(uint8_t lcId) override;
54 void Reset() override;
55 void SetRnti(uint16_t rnti) override;
56 void NotifyConnectionSuccessful() override;
57 void SetImsi(uint64_t imsi) override;
58
59 private:
60 NrUeMac* m_mac;
61};
62
63UeMemberNrUeCmacSapProvider::UeMemberNrUeCmacSapProvider(NrUeMac* mac)
64 : m_mac(mac)
65{
66}
67
68void
69UeMemberNrUeCmacSapProvider::ConfigureRach(RachConfig rc)
70{
71 m_mac->DoConfigureRach(rc);
72}
73
74void
75UeMemberNrUeCmacSapProvider::StartContentionBasedRandomAccessProcedure()
76{
77 m_mac->DoStartContentionBasedRandomAccessProcedure();
78}
79
80void
81UeMemberNrUeCmacSapProvider::StartNonContentionBasedRandomAccessProcedure(uint16_t rnti,
82 uint8_t preambleId,
83 uint8_t prachMask)
84{
85 m_mac->DoStartNonContentionBasedRandomAccessProcedure(rnti, preambleId, prachMask);
86}
87
88void
89UeMemberNrUeCmacSapProvider::AddLc(uint8_t lcId, LogicalChannelConfig lcConfig, LteMacSapUser* msu)
90{
91 m_mac->AddLc(lcId, lcConfig, msu);
92}
93
94void
95UeMemberNrUeCmacSapProvider::RemoveLc(uint8_t lcid)
96{
97 m_mac->DoRemoveLc(lcid);
98}
99
100void
101UeMemberNrUeCmacSapProvider::Reset()
102{
103 m_mac->DoReset();
104}
105
106void
107UeMemberNrUeCmacSapProvider::SetRnti(uint16_t rnti)
108{
109 m_mac->SetRnti(rnti);
110}
111
112void
113UeMemberNrUeCmacSapProvider::NotifyConnectionSuccessful()
114{
115 m_mac->DoNotifyConnectionSuccessful();
116}
117
118void
119UeMemberNrUeCmacSapProvider::SetImsi(uint64_t imsi)
120{
121 m_mac->DoSetImsi(imsi);
122}
123
124class UeMemberNrMacSapProvider : public LteMacSapProvider
125{
126 public:
127 UeMemberNrMacSapProvider(NrUeMac* mac);
128
129 // inherited from LteMacSapProvider
130 void TransmitPdu(TransmitPduParameters params) override;
131 void ReportBufferStatus(ReportBufferStatusParameters params) override;
132
133 private:
134 NrUeMac* m_mac;
135};
136
137UeMemberNrMacSapProvider::UeMemberNrMacSapProvider(NrUeMac* mac)
138 : m_mac(mac)
139{
140}
141
142void
143UeMemberNrMacSapProvider::TransmitPdu(TransmitPduParameters params)
144{
145 m_mac->DoTransmitPdu(params);
146}
147
148void
149UeMemberNrMacSapProvider::ReportBufferStatus(ReportBufferStatusParameters params)
150{
151 m_mac->DoReportBufferStatus(params);
152}
153
154class NrUePhySapUser;
155
156class MacUeMemberPhySapUser : public NrUePhySapUser
157{
158 public:
159 MacUeMemberPhySapUser(NrUeMac* mac);
160
161 void ReceivePhyPdu(Ptr<Packet> p) override;
162
163 void ReceiveControlMessage(Ptr<NrControlMessage> msg) override;
164
165 void SlotIndication(SfnSf sfn) override;
166
167 // virtual void NotifyHarqDeliveryFailure (uint8_t harqId);
168
169 uint8_t GetNumHarqProcess() const override;
170
171 private:
172 NrUeMac* m_mac;
173};
174
175MacUeMemberPhySapUser::MacUeMemberPhySapUser(NrUeMac* mac)
176 : m_mac(mac)
177{
178}
179
180void
181MacUeMemberPhySapUser::ReceivePhyPdu(Ptr<Packet> p)
182{
183 m_mac->DoReceivePhyPdu(p);
184}
185
186void
187MacUeMemberPhySapUser::ReceiveControlMessage(Ptr<NrControlMessage> msg)
188{
189 m_mac->DoReceiveControlMessage(msg);
190}
191
192void
193MacUeMemberPhySapUser::SlotIndication(SfnSf sfn)
194{
195 m_mac->DoSlotIndication(sfn);
196}
197
198uint8_t
199MacUeMemberPhySapUser::GetNumHarqProcess() const
200{
201 return m_mac->GetNumHarqProcess();
202}
203
204//-----------------------------------------------------------------------
205
206TypeId
207NrUeMac::GetTypeId()
208{
209 static TypeId tid =
210 TypeId("ns3::NrUeMac")
211 .SetParent<Object>()
212 .AddConstructor<NrUeMac>()
213 .AddAttribute(
214 "NumHarqProcess",
215 "Number of concurrent stop-and-wait Hybrid ARQ processes per user",
216 UintegerValue(16),
217 MakeUintegerAccessor(&NrUeMac::SetNumHarqProcess, &NrUeMac::GetNumHarqProcess),
218 MakeUintegerChecker<uint8_t>())
219 .AddTraceSource("UeMacRxedCtrlMsgsTrace",
220 "Ue MAC Control Messages Traces.",
221 MakeTraceSourceAccessor(&NrUeMac::m_macRxedCtrlMsgsTrace),
222 "ns3::NrMacRxTrace::RxedUeMacCtrlMsgsTracedCallback")
223 .AddTraceSource("UeMacTxedCtrlMsgsTrace",
224 "Ue MAC Control Messages Traces.",
225 MakeTraceSourceAccessor(&NrUeMac::m_macTxedCtrlMsgsTrace),
226 "ns3::NrMacRxTrace::TxedUeMacCtrlMsgsTracedCallback");
227 return tid;
228}
229
230NrUeMac::NrUeMac()
231 : Object()
232{
233 NS_LOG_FUNCTION(this);
234 m_cmacSapProvider = new UeMemberNrUeCmacSapProvider(this);
235 m_macSapProvider = new UeMemberNrMacSapProvider(this);
236 m_phySapUser = new MacUeMemberPhySapUser(this);
237 m_raPreambleUniformVariable = CreateObject<UniformRandomVariable>();
238}
239
243
244void
246{
247 m_miUlHarqProcessesPacket.clear();
248 m_miUlHarqProcessesPacketTimer.clear();
249 m_ulBsrReceived.clear();
250 m_lcInfoMap.clear();
251 m_raPreambleUniformVariable = nullptr;
252 delete m_macSapProvider;
253 delete m_cmacSapProvider;
254 delete m_phySapUser;
255}
256
257void
258NrUeMac::SetRnti(uint16_t rnti)
259{
260 NS_LOG_FUNCTION(this);
261 m_rnti = rnti;
262}
263
264void
265NrUeMac::DoNotifyConnectionSuccessful()
266{
267 NS_LOG_FUNCTION(this);
268 m_phySapProvider->NotifyConnectionSuccessful();
269}
270
271void
272NrUeMac::DoSetImsi(uint64_t imsi)
273{
274 NS_LOG_FUNCTION(this);
275 m_imsi = imsi;
276}
277
278uint16_t
280{
281 if (m_phySapProvider)
282 {
283 return m_phySapProvider->GetBwpId();
284 }
285 else
286 {
287 return UINT16_MAX;
288 }
289}
290
291uint16_t
293{
294 if (m_phySapProvider)
295 {
296 return m_phySapProvider->GetCellId();
297 }
298 else
299 {
300 return UINT16_MAX;
301 }
302}
303
304uint32_t
305NrUeMac::GetTotalBufSize() const
306{
307 uint32_t ret = 0;
308 for (const auto& it : m_ulBsrReceived)
309 {
310 ret += (it.second.txQueueSize + it.second.retxQueueSize + it.second.statusPduSize);
311 }
312 return ret;
313}
314
319void
320NrUeMac::SetNumHarqProcess(uint8_t numHarqProcess)
321{
322 m_numHarqProcess = numHarqProcess;
323
324 m_miUlHarqProcessesPacket.resize(GetNumHarqProcess());
325 for (auto& i : m_miUlHarqProcessesPacket)
326 {
327 if (i.m_pktBurst == nullptr)
328 {
329 Ptr<PacketBurst> pb = CreateObject<PacketBurst>();
330 i.m_pktBurst = pb;
331 }
332 }
333 m_miUlHarqProcessesPacketTimer.resize(GetNumHarqProcess(), 0);
334}
335
339uint8_t
341{
342 return m_numHarqProcess;
343}
344
345// forwarded from MAC SAP
346void
347NrUeMac::DoTransmitPdu(LteMacSapProvider::TransmitPduParameters params)
348{
349 NS_LOG_FUNCTION(this);
350 NS_ASSERT(m_ulDci->m_harqProcess == params.harqProcessId);
351
352 m_miUlHarqProcessesPacket.at(params.harqProcessId).m_lcidList.push_back(params.lcid);
353
354 NrMacHeaderVs header;
355 header.SetLcId(params.lcid);
356 header.SetSize(params.pdu->GetSize());
357
358 params.pdu->AddHeader(header);
359
360 LteRadioBearerTag bearerTag(params.rnti, params.lcid, 0);
361 params.pdu->AddPacketTag(bearerTag);
362
363 m_miUlHarqProcessesPacket.at(params.harqProcessId).m_pktBurst->AddPacket(params.pdu);
364 m_miUlHarqProcessesPacketTimer.at(params.harqProcessId) = GetNumHarqProcess();
365
366 m_ulDciTotalUsed += params.pdu->GetSize();
367
368 NS_ASSERT_MSG(m_ulDciTotalUsed <= m_ulDci->m_tbSize,
369 "We used more data than the DCI allowed us.");
370
371 m_phySapProvider->SendMacPdu(params.pdu, m_ulDciSfnsf, m_ulDci->m_symStart, m_ulDci->m_rnti);
372}
373
374void
375NrUeMac::DoReportBufferStatus(LteMacSapProvider::ReportBufferStatusParameters params)
376{
377 NS_LOG_FUNCTION(this << static_cast<uint32_t>(params.lcid));
378
379 auto it = m_ulBsrReceived.find(params.lcid);
380
381 NS_LOG_INFO("Received BSR for LC Id" << static_cast<uint32_t>(params.lcid));
382
383 if (it != m_ulBsrReceived.end())
384 {
385 // update entry
386 (*it).second = params;
387 }
388 else
389 {
390 it = m_ulBsrReceived.insert(std::make_pair(params.lcid, params)).first;
391 }
392
393 if (m_srState == INACTIVE)
394 {
395 NS_LOG_INFO("INACTIVE -> TO_SEND, bufSize " << GetTotalBufSize());
396 m_srState = TO_SEND;
397 }
398}
399
400void
401NrUeMac::SendReportBufferStatus(const SfnSf& dataSfn, uint8_t symStart)
402{
403 NS_LOG_FUNCTION(this);
404
405 if (m_rnti == 0)
406 {
407 NS_LOG_INFO("MAC not initialized, BSR deferred");
408 return;
409 }
410
411 if (m_ulBsrReceived.empty())
412 {
413 NS_LOG_INFO("No BSR report to transmit");
414 return;
415 }
416 MacCeElement bsr = MacCeElement();
417 bsr.m_rnti = m_rnti;
418 bsr.m_macCeType = MacCeElement::BSR;
419
420 // BSR is reported for each LCG
421 std::unordered_map<uint8_t, LteMacSapProvider::ReportBufferStatusParameters>::iterator it;
422 std::vector<uint32_t> queue(4, 0); // one value per each of the 4 LCGs, initialized to 0
423 for (it = m_ulBsrReceived.begin(); it != m_ulBsrReceived.end(); it++)
424 {
425 uint8_t lcid = it->first;
426 std::unordered_map<uint8_t, LcInfo>::iterator lcInfoMapIt;
427 lcInfoMapIt = m_lcInfoMap.find(lcid);
428 NS_ASSERT(lcInfoMapIt != m_lcInfoMap.end());
429 NS_ASSERT_MSG((lcid != 0) ||
430 (((*it).second.txQueueSize == 0) && ((*it).second.retxQueueSize == 0) &&
431 ((*it).second.statusPduSize == 0)),
432 "BSR should not be used for LCID 0");
433 uint8_t lcg = lcInfoMapIt->second.lcConfig.logicalChannelGroup;
434 queue.at(lcg) +=
435 ((*it).second.txQueueSize + (*it).second.retxQueueSize + (*it).second.statusPduSize);
436
437 if (queue.at(lcg) != 0)
438 {
439 NS_LOG_DEBUG("Adding 5 bytes for SHORT_BSR.");
440 queue.at(lcg) += 5;
441 }
442 if ((*it).second.txQueueSize > 0)
443 {
444 NS_LOG_DEBUG("Adding 3 bytes for TX subheader.");
445 queue.at(lcg) += 3;
446 }
447 if ((*it).second.retxQueueSize > 0)
448 {
449 NS_LOG_DEBUG("Adding 3 bytes for RX subheader.");
450 queue.at(lcg) += 3;
451 }
452 }
453
454 NS_LOG_INFO("Sending BSR with this info for the LCG: "
455 << queue.at(0) << " " << queue.at(1) << " " << queue.at(2) << " " << queue.at(3));
456 // FF API says that all 4 LCGs are always present
457 bsr.m_macCeValue.m_bufferStatus.push_back(NrMacShortBsrCe::FromBytesToLevel(queue.at(0)));
458 bsr.m_macCeValue.m_bufferStatus.push_back(NrMacShortBsrCe::FromBytesToLevel(queue.at(1)));
459 bsr.m_macCeValue.m_bufferStatus.push_back(NrMacShortBsrCe::FromBytesToLevel(queue.at(2)));
460 bsr.m_macCeValue.m_bufferStatus.push_back(NrMacShortBsrCe::FromBytesToLevel(queue.at(3)));
461
462 // create the message. It is used only for tracing, but we don't send it...
463 Ptr<NrBsrMessage> msg = Create<NrBsrMessage>();
464 msg->SetSourceBwp(GetBwpId());
465 msg->SetBsr(bsr);
466
467 m_macTxedCtrlMsgsTrace(m_currentSlot, GetCellId(), bsr.m_rnti, GetBwpId(), msg);
468
469 // Here we send the real SHORT_BSR, as a subpdu.
470 Ptr<Packet> p = Create<Packet>();
471
472 // Please note that the levels are defined from the standard. In this case,
473 // we have 5 bit available, so use such standard levels. In the future,
474 // when LONG BSR will be implemented, this have to change.
475 NrMacShortBsrCe header;
476 header.m_bufferSizeLevel_0 = NrMacShortBsrCe::FromBytesToLevel(queue.at(0));
477 header.m_bufferSizeLevel_1 = NrMacShortBsrCe::FromBytesToLevel(queue.at(1));
478 header.m_bufferSizeLevel_2 = NrMacShortBsrCe::FromBytesToLevel(queue.at(2));
479 header.m_bufferSizeLevel_3 = NrMacShortBsrCe::FromBytesToLevel(queue.at(3));
480
481 p->AddHeader(header);
482
483 LteRadioBearerTag bearerTag(m_rnti, NrMacHeaderFsUl::SHORT_BSR, 0);
484 p->AddPacketTag(bearerTag);
485
486 m_ulDciTotalUsed += p->GetSize();
487 NS_ASSERT_MSG(m_ulDciTotalUsed <= m_ulDci->m_tbSize,
488 "We used more data than the DCI allowed us.");
489
490 m_phySapProvider->SendMacPdu(p, dataSfn, symStart, m_ulDci->m_rnti);
491}
492
493void
494NrUeMac::SetUeCmacSapUser(LteUeCmacSapUser* s)
495{
496 m_cmacSapUser = s;
497}
498
499LteUeCmacSapProvider*
501{
502 return m_cmacSapProvider;
503}
504
505void
506NrUeMac::RefreshHarqProcessesPacketBuffer()
507{
508 NS_LOG_FUNCTION(this);
509
510 for (std::size_t i = 0; i < m_miUlHarqProcessesPacketTimer.size(); i++)
511 {
512 if (m_miUlHarqProcessesPacketTimer.at(i) == 0 && m_miUlHarqProcessesPacket.at(i).m_pktBurst)
513 {
514 if (m_miUlHarqProcessesPacket.at(i).m_pktBurst->GetSize() > 0)
515 {
516 // timer expired: drop packets in buffer for this process
517 NS_LOG_INFO("HARQ Proc Id " << i << " packets buffer expired");
518 Ptr<PacketBurst> emptyPb = CreateObject<PacketBurst>();
519 m_miUlHarqProcessesPacket.at(i).m_pktBurst = emptyPb;
520 m_miUlHarqProcessesPacket.at(i).m_lcidList.clear();
521 }
522 }
523 else
524 {
525 // m_miUlHarqProcessesPacketTimer.at (i)--; // ignore HARQ timeout
526 }
527 }
528}
529
530void
531NrUeMac::DoSlotIndication(const SfnSf& sfn)
532{
533 NS_LOG_FUNCTION(this);
534 m_currentSlot = sfn;
535 NS_LOG_INFO("Slot " << m_currentSlot);
536
537 RefreshHarqProcessesPacketBuffer();
538
539 if (m_srState == TO_SEND)
540 {
541 NS_LOG_INFO("Sending SR to PHY in slot " << sfn);
542 SendSR();
543 m_srState = ACTIVE;
544 }
545
546 // Feedback missing
547}
548
549void
550NrUeMac::SendSR() const
551{
552 NS_LOG_FUNCTION(this);
553
554 if (m_rnti == 0)
555 {
556 NS_LOG_INFO("MAC not initialized, SR deferred");
557 return;
558 }
559
560 // create the SR to send to the gNB
561 Ptr<NrSRMessage> msg = Create<NrSRMessage>();
562 msg->SetSourceBwp(GetBwpId());
563 msg->SetRNTI(m_rnti);
564
565 m_macTxedCtrlMsgsTrace(m_currentSlot, GetCellId(), m_rnti, GetBwpId(), msg);
566 m_phySapProvider->SendControlMessage(msg);
567}
568
569void
570NrUeMac::DoReceivePhyPdu(Ptr<Packet> p)
571{
572 NS_LOG_FUNCTION(this);
573
574 LteRadioBearerTag tag;
575 p->RemovePacketTag(tag);
576
577 if (tag.GetRnti() != m_rnti) // Packet is for another user
578 {
579 return;
580 }
581
582 NrMacHeaderVs header;
583 p->RemoveHeader(header);
584
585 LteMacSapUser::ReceivePduParameters rxParams;
586 rxParams.p = p;
587 rxParams.rnti = m_rnti;
588 rxParams.lcid = header.GetLcId();
589
590 auto it = m_lcInfoMap.find(header.GetLcId());
591
592 // p can be empty. Well, right now no, but when someone will add CE in downlink,
593 // then p can be empty.
594 if (rxParams.p->GetSize() > 0)
595 {
596 it->second.macSapUser->ReceivePdu(rxParams);
597 }
598}
599
600void
601NrUeMac::RecvRaResponse(BuildRarListElement_s raResponse)
602{
603 NS_LOG_FUNCTION(this);
604 m_waitingForRaResponse = false;
605 m_rnti = raResponse.m_rnti;
606 m_cmacSapUser->SetTemporaryCellRnti(m_rnti);
607 m_cmacSapUser->NotifyRandomAccessSuccessful();
608}
609
610void
611NrUeMac::ProcessUlDci(const Ptr<NrUlDciMessage>& dciMsg)
612{
613 NS_LOG_FUNCTION(this);
614
615 SfnSf dataSfn = m_currentSlot;
616 dataSfn.Add(dciMsg->GetKDelay());
617
618 // Saving the data we need in DoTransmitPdu
619 m_ulDciSfnsf = dataSfn;
620 m_ulDciTotalUsed = 0;
621 m_ulDci = dciMsg->GetDciInfoElement();
622
623 m_macRxedCtrlMsgsTrace(m_currentSlot, GetCellId(), m_rnti, GetBwpId(), dciMsg);
624
625 NS_LOG_INFO("UL DCI received, transmit data in slot "
626 << dataSfn << " Harq Process " << +m_ulDci->m_harqProcess << " TBS "
627 << m_ulDci->m_tbSize << " total queue " << GetTotalBufSize());
628
629 if (m_ulDci->m_ndi == 0)
630 {
631 // This method will retransmit the data saved in the harq buffer
632 TransmitRetx();
633
634 // This method will transmit a new BSR.
635 SendReportBufferStatus(dataSfn, m_ulDci->m_symStart);
636 }
637 else if (m_ulDci->m_ndi == 1)
638 {
639 SendNewData();
640
641 NS_LOG_INFO("After sending NewData, bufSize " << GetTotalBufSize());
642
643 // Send a new BSR. SendNewData() already took into account the size of
644 // the BSR.
645 SendReportBufferStatus(dataSfn, m_ulDci->m_symStart);
646
647 NS_LOG_INFO("UL DCI processing done, sent to PHY a total of "
648 << m_ulDciTotalUsed << " B out of " << m_ulDci->m_tbSize
649 << " allocated bytes ");
650
651 if (GetTotalBufSize() == 0)
652 {
653 m_srState = INACTIVE;
654 NS_LOG_INFO("ACTIVE -> INACTIVE, bufSize " << GetTotalBufSize());
655
656 // the UE may have been scheduled, but we didn't use a single byte
657 // of the allocation. So send an empty PDU. This happens because the
658 // byte reporting in the BSR is not accurate, due to RLC and/or
659 // BSR quantization.
660 if (m_ulDciTotalUsed == 0)
661 {
662 NS_LOG_WARN("No byte used for this UL-DCI, sending empty PDU");
663
664 LteMacSapProvider::TransmitPduParameters txParams;
665
666 txParams.pdu = Create<Packet>();
667 txParams.lcid = 3;
668 txParams.rnti = m_rnti;
669 txParams.layer = 0;
670 txParams.harqProcessId = m_ulDci->m_harqProcess;
671 txParams.componentCarrierId = GetBwpId();
672
673 DoTransmitPdu(txParams);
674 }
675 }
676 }
677}
678
679void
680NrUeMac::TransmitRetx()
681{
682 NS_LOG_FUNCTION(this);
683
684 Ptr<PacketBurst> pb = m_miUlHarqProcessesPacket.at(m_ulDci->m_harqProcess).m_pktBurst;
685
686 if (pb == nullptr)
687 {
688 NS_LOG_WARN(
689 "The previous transmission did not contain any new data; "
690 "probably it was BSR only. To not send an old BSR to the scheduler, "
691 "we don't send anything back in this allocation. Eventually, "
692 "the Harq timer at gnb will expire, and soon this allocation will be forgotten.");
693 return;
694 }
695
696 NS_LOG_DEBUG("UE MAC RETX HARQ " << +m_ulDci->m_harqProcess);
697
698 NS_ASSERT(pb->GetNPackets() > 0);
699
700 for (std::list<Ptr<Packet>>::const_iterator j = pb->Begin(); j != pb->End(); ++j)
701 {
702 Ptr<Packet> pkt = (*j)->Copy();
703 LteRadioBearerTag bearerTag;
704 if (!pkt->PeekPacketTag(bearerTag))
705 {
706 NS_FATAL_ERROR("No radio bearer tag");
707 }
708 m_phySapProvider->SendMacPdu(pkt, m_ulDciSfnsf, m_ulDci->m_symStart, m_ulDci->m_rnti);
709 }
710
711 m_miUlHarqProcessesPacketTimer.at(m_ulDci->m_harqProcess) = GetNumHarqProcess();
712}
713
714void
715NrUeMac::SendRetxData(uint32_t usefulTbs, uint32_t activeLcsRetx)
716{
717 NS_LOG_FUNCTION(this);
718
719 if (activeLcsRetx == 0)
720 {
721 return;
722 }
723
724 uint32_t bytesPerLcId = usefulTbs / activeLcsRetx;
725
726 for (auto& itBsr : m_ulBsrReceived)
727 {
728 auto& bsr = itBsr.second;
729
730 if (m_ulDciTotalUsed + bytesPerLcId <= usefulTbs)
731 {
732 LteMacSapUser::TxOpportunityParameters txParams;
733 txParams.lcid = bsr.lcid;
734 txParams.rnti = m_rnti;
735 txParams.bytes = bytesPerLcId;
736 txParams.layer = 0;
737 txParams.harqId = m_ulDci->m_harqProcess;
738 txParams.componentCarrierId = GetBwpId();
739
740 NS_LOG_INFO("Notifying RLC of LCID " << +bsr.lcid
741 << " of a TxOpp "
742 "of "
743 << bytesPerLcId << " B for a RETX PDU");
744
745 m_lcInfoMap.at(bsr.lcid).macSapUser->NotifyTxOpportunity(txParams);
746 // After this call, m_ulDciTotalUsed has been updated with the
747 // correct amount of bytes... but it is up to us in updating the BSR
748 // value, subtracting the amount of bytes transmitted
749
750 // We need to use std::min here because bytesPerLcId can be
751 // greater than bsr.txQueueSize because scheduler can assign
752 // more bytes than needed due to how TB size is computed.
753 bsr.retxQueueSize -= std::min(bytesPerLcId, bsr.retxQueueSize);
754 }
755 else
756 {
757 NS_LOG_DEBUG("Something wrong with the calculation of overhead."
758 "Active LCS Retx: "
759 << activeLcsRetx << " assigned to this: " << bytesPerLcId
760 << ", with TBS of " << m_ulDci->m_tbSize << " usefulTbs " << usefulTbs
761 << " and total used " << m_ulDciTotalUsed);
762 }
763 }
764}
765
766void
767NrUeMac::SendTxData(uint32_t usefulTbs, uint32_t activeTx)
768{
769 NS_LOG_FUNCTION(this);
770
771 if (activeTx == 0)
772 {
773 return;
774 }
775
776 uint32_t bytesPerLcId = usefulTbs / activeTx;
777
778 for (auto& itBsr : m_ulBsrReceived)
779 {
780 auto& bsr = itBsr.second;
781
782 if (m_ulDciTotalUsed + bytesPerLcId <= usefulTbs)
783 {
784 LteMacSapUser::TxOpportunityParameters txParams;
785 txParams.lcid = bsr.lcid;
786 txParams.rnti = m_rnti;
787 txParams.bytes = bytesPerLcId;
788 txParams.layer = 0;
789 txParams.harqId = m_ulDci->m_harqProcess;
790 txParams.componentCarrierId = GetBwpId();
791
792 NS_LOG_INFO("Notifying RLC of LCID " << +bsr.lcid
793 << " of a TxOpp "
794 "of "
795 << bytesPerLcId << " B for a TX PDU");
796
797 m_lcInfoMap.at(bsr.lcid).macSapUser->NotifyTxOpportunity(txParams);
798 // After this call, m_ulDciTotalUsed has been updated with the
799 // correct amount of bytes... but it is up to us in updating the BSR
800 // value, subtracting the amount of bytes transmitted
801
802 // We need to use std::min here because bytesPerLcId can be
803 // greater than bsr.txQueueSize because scheduler can assign
804 // more bytes than needed due to how TB size is computed.
805 bsr.txQueueSize -= std::min(bytesPerLcId, bsr.txQueueSize);
806 }
807 else
808 {
809 NS_LOG_DEBUG("Something wrong with the calculation of overhead."
810 "Active LCS TX: "
811 << activeTx << " assigned to this: " << bytesPerLcId << ", with TBS of "
812 << m_ulDci->m_tbSize << " usefulTbs " << usefulTbs << " and total used "
813 << m_ulDciTotalUsed);
814 }
815 }
816}
817
818void
819NrUeMac::SendNewData()
820{
821 NS_LOG_FUNCTION(this);
822 // New transmission -> empty pkt buffer queue (for deleting eventual pkts not acked )
823 Ptr<PacketBurst> pb = CreateObject<PacketBurst>();
824 m_miUlHarqProcessesPacket.at(m_ulDci->m_harqProcess).m_pktBurst = pb;
825 m_miUlHarqProcessesPacket.at(m_ulDci->m_harqProcess).m_lcidList.clear();
826 NS_LOG_INFO("Reset HARQP " << +m_ulDci->m_harqProcess);
827
828 // Sending the status data has no boundary: let's try to send the ACK as
829 // soon as possible, filling the TBS, if necessary.
830 SendNewStatusData();
831
832 // Let's count how many LC we have, that are waiting with some data
833 uint16_t activeLcsRetx = 0;
834 uint16_t activeLcsTx = 0;
835 for (const auto& itBsr : m_ulBsrReceived)
836 {
837 if (itBsr.second.retxQueueSize > 0)
838 {
839 activeLcsRetx++;
840 }
841 if (itBsr.second.txQueueSize > 0)
842 {
843 activeLcsTx++;
844 }
845 }
846
847 // Of the TBS we received in the DCI, one part is gone for the status pdu,
848 // where we didn't check much as it is the most important data, that has to go
849 // out. For the rest that we have left, we can use only a part of it because of
850 // the overhead of the SHORT_BSR, which is 5 bytes.
851 NS_ASSERT_MSG(m_ulDciTotalUsed + 5 <= m_ulDci->m_tbSize,
852 "The StatusPDU used " << m_ulDciTotalUsed
853 << " B, we don't have any for the SHORT_BSR.");
854 // reserve some data for the SHORT_BSR
855 uint32_t usefulTbs = m_ulDci->m_tbSize - m_ulDciTotalUsed - 5;
856
857 // Now, we have 3 bytes of overhead for each subPDU. Let's try to serve all
858 // the queues with some RETX data.
859 if (activeLcsRetx == 0 && activeLcsTx == 0 && usefulTbs > 0)
860 {
861 NS_LOG_LOGIC("This UE tx opportunity will be wasted: " << usefulTbs << " bytes.");
862 }
863
864 // this check is needed, because if there are no active LCS we should not
865 // enter into else and call the function SendRetxData
866 if (activeLcsRetx > 0 && usefulTbs > 0) // the queues with some RETX data.
867 {
868 // 10 because 3 bytes will go for MAC subheader
869 // and we should ensure to pass to RLC AM at least 7 bytes
870 if (activeLcsRetx * 10 > usefulTbs)
871 {
872 NS_LOG_DEBUG("The overhead for transmitting retx data is greater than the space for "
873 "transmitting it."
874 "Ignore the TBS of "
875 << usefulTbs << " B.");
876 }
877 else
878 {
879 usefulTbs -= activeLcsRetx * 3;
880 SendRetxData(usefulTbs, activeLcsRetx);
881 }
882 }
883
884 // Now we have to update our useful TBS for the next transmission.
885 // Remember that m_ulDciTotalUsed keep count of data and overhead that we
886 // used till now.
887 NS_ASSERT_MSG(
888 m_ulDciTotalUsed + 5 <= m_ulDci->m_tbSize,
889 "The StatusPDU and RETX sending required all space, we don't have any for the SHORT_BSR.");
890 usefulTbs = m_ulDci->m_tbSize - m_ulDciTotalUsed - 5; // Update the usefulTbs.
891
892 // The last part is for the queues with some non-RETX data. If there is no space left,
893 // then nothing.
894 if (activeLcsTx > 0 && usefulTbs > 0) // the queues with some TX data.
895 {
896 // 10 because 3 bytes will go for MAC subheader
897 // and we should ensure to pass to RLC AM at least 7 bytes
898 if (activeLcsTx * 10 > usefulTbs)
899 {
900 NS_LOG_DEBUG("The overhead for transmitting new data is greater than the space for "
901 "transmitting it."
902 "Ignore the TBS of "
903 << usefulTbs << " B.");
904 }
905 else
906 {
907 usefulTbs -= activeLcsTx * 3;
908 SendTxData(usefulTbs, activeLcsTx);
909 }
910 }
911
912 // If we did not used the packet burst, explicitly signal it to the HARQ
913 // retx, if any.
914 if (m_ulDciTotalUsed == 0)
915 {
916 m_miUlHarqProcessesPacket.at(m_ulDci->m_harqProcess).m_pktBurst = nullptr;
917 m_miUlHarqProcessesPacket.at(m_ulDci->m_harqProcess).m_lcidList.clear();
918 }
919}
920
921void
922NrUeMac::SendNewStatusData()
923{
924 NS_LOG_FUNCTION(this);
925
926 bool hasStatusPdu = false;
927 bool sentOneStatusPdu = false;
928
929 for (auto& bsrIt : m_ulBsrReceived)
930 {
931 auto& bsr = bsrIt.second;
932
933 if (bsr.statusPduSize > 0)
934 {
935 hasStatusPdu = true;
936
937 // Check if we have room to transmit the statusPdu
938 if (m_ulDciTotalUsed + bsr.statusPduSize <= m_ulDci->m_tbSize)
939 {
940 LteMacSapUser::TxOpportunityParameters txParams;
941 txParams.lcid = bsr.lcid;
942 txParams.rnti = m_rnti;
943 txParams.bytes = bsr.statusPduSize;
944 txParams.layer = 0;
945 txParams.harqId = m_ulDci->m_harqProcess;
946 txParams.componentCarrierId = GetBwpId();
947
948 NS_LOG_INFO("Notifying RLC of LCID " << +bsr.lcid
949 << " of a TxOpp "
950 "of "
951 << bsr.statusPduSize << " B for a status PDU");
952
953 m_lcInfoMap.at(bsr.lcid).macSapUser->NotifyTxOpportunity(txParams);
954 // After this call, m_ulDciTotalUsed has been updated with the
955 // correct amount of bytes... but it is up to us in updating the BSR
956 // value, subtracting the amount of bytes transmitted
957 bsr.statusPduSize = 0;
958 sentOneStatusPdu = true;
959 }
960 else
961 {
962 NS_LOG_INFO("Cannot send StatusPdu of " << bsr.statusPduSize
963 << " B, we already used all the TBS");
964 }
965 }
966 }
967
968 NS_ABORT_MSG_IF(hasStatusPdu && !sentOneStatusPdu,
969 "The TBS of size " << m_ulDci->m_tbSize
970 << " doesn't allow us "
971 "to send one status PDU...");
972}
973
974void
975NrUeMac::DoReceiveControlMessage(Ptr<NrControlMessage> msg)
976{
977 NS_LOG_FUNCTION(this << msg);
978
979 switch (msg->GetMessageType())
980 {
982 ProcessUlDci(DynamicCast<NrUlDciMessage>(msg));
983 break;
984 }
985 case (NrControlMessage::RAR): {
986 NS_LOG_INFO("Received RAR in slot " << m_currentSlot);
987
988 m_macRxedCtrlMsgsTrace(m_currentSlot, GetCellId(), m_rnti, GetBwpId(), msg);
989
990 if (m_waitingForRaResponse)
991 {
992 Ptr<NrRarMessage> rarMsg = DynamicCast<NrRarMessage>(msg);
993 NS_LOG_LOGIC("got RAR with RA-RNTI " << +rarMsg->GetRaRnti() << ", expecting "
994 << +m_raRnti);
995 for (auto it = rarMsg->RarListBegin(); it != rarMsg->RarListEnd(); ++it)
996 {
997 if (it->rapId == m_raPreambleId)
998 {
999 RecvRaResponse(it->rarPayload);
1000 }
1001 }
1002 }
1003 break;
1004 }
1005
1006 default:
1007 NS_LOG_LOGIC("Control message not supported/expected");
1008 }
1009}
1010
1011NrUePhySapUser*
1013{
1014 return m_phySapUser;
1015}
1016
1017void
1019{
1020 m_phySapProvider = ptr;
1021}
1022
1023void
1024NrUeMac::DoConfigureRach([[maybe_unused]] LteUeCmacSapProvider::RachConfig rc)
1025{
1026 NS_LOG_FUNCTION(this);
1027}
1028
1029void
1030NrUeMac::DoStartContentionBasedRandomAccessProcedure()
1031{
1032 NS_LOG_FUNCTION(this);
1033 RandomlySelectAndSendRaPreamble();
1034}
1035
1036void
1037NrUeMac::RandomlySelectAndSendRaPreamble()
1038{
1039 NS_LOG_FUNCTION(this);
1040 NS_LOG_DEBUG(m_currentSlot << " Received System Information, send to PHY the RA preamble");
1041 SendRaPreamble(true);
1042}
1043
1044void
1045NrUeMac::SendRaPreamble([[maybe_unused]] bool contention)
1046{
1047 NS_LOG_FUNCTION(this);
1048 // m_raPreambleId = m_raPreambleUniformVariable->GetInteger (0, 64 - 1);
1049 m_raPreambleId = g_raPreambleId++;
1050 /*raRnti should be subframeNo -1 */
1051 m_raRnti = 1;
1052
1053 Ptr<NrRachPreambleMessage> rachMsg = Create<NrRachPreambleMessage>();
1054 rachMsg->SetSourceBwp(GetBwpId());
1055 m_macTxedCtrlMsgsTrace(m_currentSlot, GetCellId(), m_rnti, GetBwpId(), rachMsg);
1056
1057 m_phySapProvider->SendRachPreamble(m_raPreambleId, m_raRnti);
1058}
1059
1060void
1061NrUeMac::DoStartNonContentionBasedRandomAccessProcedure(uint16_t rnti,
1062 [[maybe_unused]] uint8_t preambleId,
1063 uint8_t prachMask)
1064{
1065 NS_LOG_FUNCTION(this << " rnti" << rnti);
1066 NS_ASSERT_MSG(prachMask == 0,
1067 "requested PRACH MASK = " << (uint32_t)prachMask
1068 << ", but only PRACH MASK = 0 is supported");
1069 m_rnti = rnti;
1070}
1071
1072void
1073NrUeMac::AddLc(uint8_t lcId,
1074 LteUeCmacSapProvider::LogicalChannelConfig lcConfig,
1075 LteMacSapUser* msu)
1076{
1077 NS_LOG_FUNCTION(this << " lcId" << (uint32_t)lcId);
1078 NS_ASSERT_MSG(m_lcInfoMap.find(lcId) == m_lcInfoMap.end(),
1079 "cannot add channel because LCID " << lcId << " is already present");
1080
1081 LcInfo lcInfo;
1082 lcInfo.lcConfig = lcConfig;
1083 lcInfo.macSapUser = msu;
1084 m_lcInfoMap[lcId] = lcInfo;
1085}
1086
1087void
1088NrUeMac::DoRemoveLc(uint8_t lcId)
1089{
1090 NS_LOG_FUNCTION(this << " lcId" << lcId);
1091}
1092
1093LteMacSapProvider*
1095{
1096 return m_macSapProvider;
1097}
1098
1099void
1100NrUeMac::DoReset()
1101{
1102 NS_LOG_FUNCTION(this);
1103}
1104
1106
1107int64_t
1109{
1110 NS_LOG_FUNCTION(this << stream);
1111 m_raPreambleUniformVariable->SetStream(stream);
1112 return 1;
1113}
1114
1115} // namespace ns3
@ UL_DCI
The resources allocation map from the BS to the attached UEs (UL)
@ RAR
Random Access Response.
static const uint8_t SHORT_BSR
Short BSR.
Mac variable-size Header.
void SetSize(uint16_t size)
Set the size to store (L in the standard)
virtual void SetLcId(uint8_t lcId)
Set the LC ID.
static uint8_t FromBytesToLevel(uint64_t bufferSize)
Convert a bytes value into the 3GPP-standard level to write in the BSR.
SAP interface between the MAC and the PHY.
Definition nr-phy-sap.h:38
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 void SendControlMessage(Ptr< NrControlMessage > msg)=0
Send a control message.
virtual void NotifyConnectionSuccessful()=0
Notify PHY about the successful RRC connection establishment.
virtual uint16_t GetBwpId() const =0
Retrieve the bandwidth part id.
virtual void SendRachPreamble(uint8_t PreambleId, uint8_t Rnti)=0
Send the RACH preamble.
LteMacSapProvider * GetUeMacSapProvider()
Get the Mac SAP provider (AKA the MAC representation for the RLC)
NrUePhySapUser * GetPhySapUser()
Get the PHY SAP User (AKA the MAC representation for the PHY)
void DoDispose() override
DoDispose method inherited from Object.
Definition nr-ue-mac.cc:245
void SetPhySapProvider(NrPhySapProvider *ptr)
Set PHY SAP provider (AKA the PHY representation for the MAC)
uint8_t GetNumHarqProcess() const
Please remember that this number is obtained by the GNB, the UE cannot configure it.
Definition nr-ue-mac.cc:340
void SetNumHarqProcess(uint8_t numHarqProcesses)
Sets the number of HARQ processes. Called by the helper at the moment of UE attachment.
Definition nr-ue-mac.cc:320
void SetUeCmacSapUser(LteUeCmacSapUser *s)
Set the C MAC SAP user (AKA the RRC representation for the MAC)
Definition nr-ue-mac.cc:494
int64_t AssignStreams(int64_t stream)
Assign a fixed random variable stream number to the random variables used by this model....
uint16_t GetCellId() const
Get the cell id of this MAC.
Definition nr-ue-mac.cc:292
uint16_t GetBwpId() const
Get the bwp id of this MAC.
Definition nr-ue-mac.cc:279
~NrUeMac() override
Deconstructor.
Definition nr-ue-mac.cc:240
LteUeCmacSapProvider * GetUeCmacSapProvider()
Get the C MAC SAP provider (AKA the MAC representation for the RRC)
Definition nr-ue-mac.cc:500
void Add(uint32_t slotN)
Add to this SfnSf a number of slot indicated by the first parameter.
Definition sfnsf.cc:119