D2dUeMacBase.h Source File

Simu5G: D2dUeMacBase.h Source File
Simu5G
D2dUeMacBase.h
1//
2// Simu5G
3//
4// Copyright (C) 2012-2021 Giovanni Nardini, Giovanni Stea, Antonio Virdis et al. (University of Pisa)
5// Copyright (C) 2022-2026 Giovanni Nardini, Giovanni Stea et al. (University of Pisa)
6//
7// This file is part of a software released under the license included in file
8// "license.pdf". Please read LICENSE and README files before using it.
9// The above files and the present reference are part of the software itself,
10// and cannot be removed from it.
11//
12
13#ifndef STACK_D2D_MAC_D2DUEMACBASE_H_
14#define STACK_D2D_MAC_D2DUEMACBASE_H_
15
16#include "simu5g/stack/mac/LteMacUe.h"
17#include "simu5g/stack/mac/LteMacEnb.h"
18#include "simu5g/stack/mac/amc/LteAmc.h"
19#include "simu5g/stack/mac/buffer/LteMacBuffer.h"
20#include "simu5g/stack/mac/buffer/LteMacQueue.h"
21#include "simu5g/stack/mac/packet/LteMacPdu.h"
22#include "simu5g/stack/mac/packet/LteRac_m.h"
23#include "simu5g/stack/mac/packet/LteSchedulingGrant.h"
24#include "simu5g/stack/phy/channelmodel/ChannelModelBase.h"
25#include "simu5g/stack/rlc/packet/PdcpTrackingTag_m.h"
26#include "simu5g/stack/d2d/mac/ID2dMacEnb.h"
27#include "simu5g/stack/d2d/mac/ID2dMacUe.h"
28#include "simu5g/stack/d2d/mac/D2dUeMacHelper.h"
29#include "simu5g/stack/d2d/mac/harq/LteHarqBufferRxD2D.h"
30#include "simu5g/stack/d2d/mac/harq/LteHarqBufferTxD2D.h"
31#include "simu5g/stack/d2d/mac/scheduler/LcgSchedulerD2D.h"
32
33namespace simu5g {
34
35using namespace omnetpp;
36
68template<class Base>
69class D2dUeMacBase : public Base, public ID2dMacUe
70{
71 protected:
72 // holds the D2D-specific UE-MAC state and logic
73 D2dUeMacHelper d2dUeHelper_{this};
74
75 // buffer-overflow statistic for the D2D directions; the core MAC owns only the
76 // DL/UL ones. Interned in initialize() -- see the "Signals" note above.
77 simsignal_t macBufferOverflowD2DSignal_ = SIMSIGNAL_NULL;
78
80 void recordBufferOverflow(Direction dir, double sample) override
81 {
82 if (dir == D2D || dir == D2D_MULTI)
83 this->emit(macBufferOverflowD2DSignal_, sample);
84 else
85 Base::recordBufferOverflow(dir, sample);
86 }
87
91 void initialize(int stage) override;
92
97 void handleMessage(cMessage *msg) override;
98
101 bool isBsrPending() const override { return this->bsrTriggered_ || d2dUeHelper_.getBsrD2DMulticastTriggered(); }
102
105 int64_t appendBsr(inet::Ptr<LteMacPdu> macPdu) override
106 {
107 int64_t size = Base::appendBsr(macPdu);
108 d2dUeHelper_.setBsrD2DMulticastTriggered(false);
109 return size;
110 }
111
116 bool buildStandaloneBsr() override;
117
119 MacNodeId pduDestId(MacCid destCid) override { return this->connDescOut_.at(destCid).flowInfo.getDestId(); }
120
123 bool shouldSkipScheduleEntry(unsigned int sduPerCid) const override { return sduPerCid == 0 && !this->isBsrPending(); }
124
125 inet::Packet *createUlMacPdu(MacCid destCid, GHz carrierFreq, MacNodeId destId) override;
126
130 UnitList reserveTxHarqUnits(LteHarqBufferTx *txBuf, Direction dir) override
131 {
132 return dir == D2D_MULTI ? txBuf->getEmptyUnits(this->currentHarq_) : Base::reserveTxHarqUnits(txBuf, dir);
133 }
134
135 void macHandleGrant(cPacket *pkt) override;
136
137 /*
138 * Checks RAC status
139 */
140 void checkRAC() override;
141
142 /*
143 * Receives and handles RAC responses
144 */
145 void macHandleRac(cPacket *pkt) override;
146
147 virtual void macHandleD2DModeSwitch(cPacket *pkt);
148
150 LteHarqBufferRx *createRxHarqBuffer(MacNodeId src, const UserControlInfo *userInfo) override;
151 LteHarqBufferTx *createTxHarqBuffer(MacNodeId destId, Direction dir) override;
152
155
156 public:
157 void doHandover(MacNodeId targetEnb) override;
158};
159
160template<class Base>
162{
163 Base::initialize(stage);
164 if (stage == inet::INITSTAGE_LOCAL) {
165 macBufferOverflowD2DSignal_ = cComponent::registerSignal("macBufferOverFlowD2D");
166 d2dUeHelper_.initWatches();
167 }
168
169 if (stage == INITSTAGE_SIMU5G_AMC_ATTACHUSER) {
170 // get parameters
171 d2dUeHelper_.setUsePreconfiguredTxParams(this->par("usePreconfiguredTxParams"));
172
173 if (this->cellId_ != NODEID_NONE) {
174 d2dUeHelper_.rebuildPreconfiguredTxParams(this->binder_);
175
176 // get the reference to the eNB
177 d2dUeHelper_.setEnb(check_and_cast<ID2dMacEnb *>(this->binder_->getMacByNodeId(this->cellId_)));
178
179 LteAmc *amc = check_and_cast<LteMacEnb *>(this->binder_->getMacByNodeId(this->cellId_))->getAmc();
180 amc->attachUser(this->nodeId_, D2D);
181 }
182 }
183}
184
185template<class Base>
187{
188 // UE is in D2D mode but it received an UL grant (for BSR)
189 for (auto& [carrierFreq, grant] : this->schedulingGrant_) {
190 // skip if this is not the turn of this carrier
191 if (!this->isCarrierActive(carrierFreq))
192 continue;
193
194 if (grant != nullptr && grant->getDirection() == UL && this->emptyScheduleList_) {
195 if (this->bsrTriggered_ || d2dUeHelper_.getBsrD2DMulticastTriggered()) {
196 // Compute BSR size taking into account only DM flows
197 int64_t sizeBsr = 0;
198 for (const auto& [cid, connInfo] : this->connDescOut_) {
199 Direction connDir = connInfo.flowInfo.getDirection();
200
201 // if the bsr was triggered by D2D (D2D_MULTI), only account for D2D (D2D_MULTI) connections
202 if (this->bsrTriggered_ && connDir != D2D)
203 continue;
204 if (d2dUeHelper_.getBsrD2DMulticastTriggered() && connDir != D2D_MULTI)
205 continue;
206
207 sizeBsr += this->computeConnectionBacklog(cid);
208 }
209
210 if (sizeBsr > 0) {
211 // Call the appropriate function to make a BSR for a D2D communication
212 LogicalCid bsrType = d2dUeHelper_.getBsrD2DMulticastTriggered() ? D2D_MULTI_SHORT_BSR : D2D_SHORT_BSR;
213 d2dUeHelper_.setBsrD2DMulticastTriggered(false);
214 inet::Packet *macPktBsr = d2dUeHelper_.makeBsr(sizeBsr);
215 auto info = macPktBsr->getTagForUpdate<UserControlInfo>();
216 info->setPacketLcid(bsrType);
217 info->setCarrierFrequency(carrierFreq);
218 info->setUserTxParams(grant->getUserTxParams()->dup());
219
220 // Add the created BSR to the PDU List
221 // select channel model for the given carrier frequency
222 ChannelModelBase *channelModel = this->phy_->getChannelModel(carrierFreq);
223 if (channelModel == nullptr)
224 throw cRuntimeError("D2dUeMacBase::buildStandaloneBsr - channel model is a null pointer");
225 this->macPduList_[channelModel->getCarrierFrequency()][{this->getMacCellId(), 0}] = macPktBsr;
226 EV << "D2dUeMacBase::buildStandaloneBsr - BSR D2D created with size " << sizeBsr << " bytes created" << endl;
227
228 this->bsrRtxTimer_ = this->bsrRtxTimerStart_; // this prevents the UE from sending an unnecessary RAC request
229 return true;
230 }
231 else {
232 d2dUeHelper_.setBsrD2DMulticastTriggered(false);
233 this->bsrTriggered_ = false;
234 this->bsrRtxTimer_ = 0;
235 }
236 }
237 // the first carrier whose grant matched decides; the historical loop
238 // broke out here whether or not a BSR was actually built
239 return false;
240 }
241 }
242 return false;
243}
244
245template<class Base>
246Packet *D2dUeMacBase<Base>::createUlMacPdu(MacCid destCid, GHz carrierFreq, MacNodeId destId)
247{
248 auto macPkt = new inet::Packet("LteMacPdu");
249 auto header = inet::makeShared<LteMacPdu>();
250 header->setHeaderLength(MAC_HEADER);
251 macPkt->insertAtFront(header);
252
253 // the direction is the flow's (UL, D2D or D2D_MULTI), not a constant
254 auto info = macPkt->template addTagIfAbsent<UserControlInfo>();
255 info->setSourceId(this->getMacNodeId());
256 info->setDestId(destId);
257 info->setDirection(this->connDescOut_.at(destCid).flowInfo.getDirection());
258 info->setPacketLcid(SHORT_BSR);
259 info->setCarrierFrequency(carrierFreq);
260 info->setGrantId(this->schedulingGrant_[carrierFreq]->getGrantId());
261
262 // a D2D transmitter may be configured to ignore the grant's parameters
263 if (d2dUeHelper_.getUsePreconfiguredTxParams())
264 info->setUserTxParams(d2dUeHelper_.getPreconfiguredTxParams()->dup());
265 else
266 info->setUserTxParams(this->schedulingGrant_[carrierFreq]->getUserTxParams()->dup());
267
268 return macPkt;
269}
270
271template<class Base>
272LteHarqBufferRx *D2dUeMacBase<Base>::createRxHarqBuffer(MacNodeId src, const UserControlInfo *userInfo)
273{
274 Direction dir = (Direction)userInfo->getDirection();
275 if (dir == D2D || dir == D2D_MULTI)
276 return new LteHarqBufferRxD2D(this->harqProcesses_, this, this->binder_, src, (dir == D2D_MULTI));
277 return Base::createRxHarqBuffer(src, userInfo);
278}
279
280template<class Base>
281LteHarqBufferTx *D2dUeMacBase<Base>::createTxHarqBuffer(MacNodeId destId, Direction dir)
282{
283 // NOTE: unlike the base class, the UL buffer is paired with the MAC of destId, not of the serving cell
284 if (dir == UL)
285 return new LteHarqBufferTx(this->binder_, (unsigned int)this->harqProcesses_, this, check_and_cast<LteMacBase *>(this->binder_->getMacByNodeId(destId)));
286 else // D2D or D2D_MULTI
287 return new LteHarqBufferTxD2D(this->binder_, (unsigned int)this->harqProcesses_, this, check_and_cast<LteMacBase *>(this->binder_->getMacByNodeId(destId)));
288}
289
290template<class Base>
295
296template<class Base>
298{
299 if (msg->isSelfMessage()) {
300 Base::handleMessage(msg);
301 return;
302 }
303
304 auto pkt = check_and_cast<inet::Packet *>(msg);
305 cGate *incoming = pkt->getArrivalGate();
306
307 if (incoming == this->downInGate_) {
308 auto userInfo = pkt->getTag<UserControlInfo>();
309
310 if (userInfo->getFrameType() == D2DMODESWITCHPKT) {
311 EV << "D2dUeMacBase::handleMessage - Received packet " << pkt->getName() <<
312 " from port " << pkt->getArrivalGate()->getName() << endl;
313
314 // message from phyIn gate (from the lower layer)
315 this->emit(this->receivedPacketFromLowerLayerSignal_, pkt);
316
317 // call handler
318 macHandleD2DModeSwitch(pkt);
319
320 return;
321 }
322 }
323
324 Base::handleMessage(msg);
325}
326
327template<class Base>
328void D2dUeMacBase<Base>::macHandleGrant(cPacket *pktAux)
329{
330 EV << NOW << " D2dUeMacBase::macHandleGrant - UE [" << this->nodeId_ << "] - Grant received " << endl;
331
332 // extract grant
333 auto pkt = check_and_cast<inet::Packet *>(pktAux);
334 auto grant = pkt->popAtFront<LteSchedulingGrant>();
335
336 auto userInfo = pkt->getTag<UserControlInfo>();
337 GHz carrierFrequency = userInfo->getCarrierFrequency();
338 EV << NOW << " D2dUeMacBase::macHandleGrant - Direction: " << dirToA(grant->getDirection()) << " Carrier: " << carrierFrequency << endl;
339
340 // delete old grant
341 if (this->schedulingGrant_.find(carrierFrequency) != this->schedulingGrant_.end() && this->schedulingGrant_[carrierFrequency] != nullptr) {
342 this->schedulingGrant_[carrierFrequency] = nullptr;
343 }
344
345 // store received grant
346 this->schedulingGrant_[carrierFrequency] = grant;
347 if (grant->getPeriodic()) {
348 this->periodCounter_[carrierFrequency] = grant->getPeriod();
349 this->expirationCounter_[carrierFrequency] = grant->getExpiration();
350 }
351
352 EV << NOW << " Node " << this->nodeId_ << " received grant of blocks " << grant->getTotalGrantedBlocks()
353 << ", bytes " << grant->getGrantedCwBytes(0) << " Direction: " << dirToA(grant->getDirection()) << endl;
354
355 // clearing pending RAC requests
356 this->racRequested_ = false;
357 d2dUeHelper_.setRacD2DMulticastRequested(false);
358
359 delete pkt;
360}
361
362template<class Base>
363void D2dUeMacBase<Base>::checkRAC()
364{
365 EV << NOW << " D2dUeMacBase::checkRAC , Ue " << this->nodeId_ << ", racTimer : " << this->racBackoffTimer_ << " maxRacTryOuts : " << this->maxRacTryouts_
366 << ", raRespTimer:" << this->raRespTimer_ << endl;
367
368 if (this->racBackoffTimer_ > 0) {
369 this->racBackoffTimer_--;
370 return;
371 }
372
373 if (this->raRespTimer_ > 0) {
374 // decrease RAC response timer
375 this->raRespTimer_--;
376 EV << NOW << " D2dUeMacBase::checkRAC - waiting for previous RAC requests to complete (timer=" << this->raRespTimer_ << ")" << endl;
377 return;
378 }
379
380 if (this->bsrRtxTimer_ > 0) {
381 // decrease BSR timer
382 this->bsrRtxTimer_--;
383 EV << NOW << " D2dUeMacBase::checkRAC - waiting for a grant, BSR rtx timer has not expired yet (timer=" << this->bsrRtxTimer_ << ")" << endl;
384
385 return;
386 }
387
388 // Avoids double requests within the same TTI window
389 if (this->racRequested_) {
390 EV << NOW << " D2dUeMacBase::checkRAC - double RAC request" << endl;
391 this->racRequested_ = false;
392 return;
393 }
394 if (d2dUeHelper_.getRacD2DMulticastRequested()) {
395 EV << NOW << " D2dUeMacBase::checkRAC - double RAC request" << endl;
396 d2dUeHelper_.setRacD2DMulticastRequested(false);
397 return;
398 }
399
400 bool trigger = false;
401 bool triggerD2DMulticast = false;
402
403 for (auto [cid, connInfo] : this->connDescOut_) {
404 if (!(connInfo.buffer->isEmpty())) {
405 if (connInfo.flowInfo.getDirection() == D2D_MULTI)
406 triggerD2DMulticast = true;
407 else
408 trigger = true;
409 break;
410 }
411 }
412
413 if (!trigger && !triggerD2DMulticast) {
414 EV << NOW << " D2dUeMacBase::checkRAC , Ue " << this->nodeId_ << ", RAC aborted, no data in queues " << endl;
415 }
416
417 this->racRequested_ = trigger;
418 bool racD2DMulticastRequested = d2dUeHelper_.getRacD2DMulticastRequested();
419 if (!this->racRequested_)
420 racD2DMulticastRequested = triggerD2DMulticast;
421 d2dUeHelper_.setRacD2DMulticastRequested(racD2DMulticastRequested);
422 if (this->racRequested_ || racD2DMulticastRequested) {
423 auto pkt = new inet::Packet("RacRequest");
424 GHz carrierFrequency = this->phy_->getPrimaryChannelModel()->getCarrierFrequency();
425 pkt->addTagIfAbsent<UserControlInfo>()->setCarrierFrequency(carrierFrequency);
426 pkt->addTagIfAbsent<UserControlInfo>()->setSourceId(this->getMacNodeId());
427 pkt->addTagIfAbsent<UserControlInfo>()->setDestId(this->getMacCellId());
428 pkt->addTagIfAbsent<UserControlInfo>()->setDirection(UL);
429 pkt->addTagIfAbsent<UserControlInfo>()->setFrameType(RACPKT);
430
431 auto racReq = inet::makeShared<LteRac>();
432 racReq->setPreambleIndex(this->intuniform(0, this->numPreambles_ - 1));
433
434 pkt->insertAtFront(racReq);
435 this->sendLowerPackets(pkt);
436
437 EV << NOW << " Ue " << this->nodeId_ << " cell " << this->cellId_ << ", RAC request sent to PHY (preamble="
438 << racReq->getPreambleIndex() << ")" << endl;
439
440 // wait at least "raRespWinStart_" TTIs before another RAC request
441 this->raRespTimer_ = this->raRespWinStart_;
442 }
443}
444
445template<class Base>
447{
448 auto pkt = check_and_cast<inet::Packet *>(pktAux);
449 auto racPkt = pkt->peekAtFront<LteRac>();
450
451 if (racPkt->getSuccess()) {
452 EV << "D2dUeMacBase::macHandleRac - Ue " << this->nodeId_ << " won RAC" << endl;
453 // if RAC is won, BSR has to be sent
454 if (d2dUeHelper_.getRacD2DMulticastRequested())
455 d2dUeHelper_.setBsrD2DMulticastTriggered(true);
456 else
457 this->bsrTriggered_ = true;
458
459 // reset RAC counter
460 this->currentRacTry_ = 0;
461 //reset RAC backoff timer
462 this->racBackoffTimer_ = 0;
463 }
464 else {
465 // RAC has failed
466 if (++this->currentRacTry_ >= this->maxRacTryouts_) {
467 EV << NOW << " Ue " << this->nodeId_ << ", RAC reached max attempts : " << this->currentRacTry_ << endl;
468 // no more RAC allowed
470 //reset RAC counter
471 this->currentRacTry_ = 0;
472 //reset RAC backoff timer
473 this->racBackoffTimer_ = 0;
474 }
475 else {
476 // recompute backoff timer
477 this->racBackoffTimer_ = this->uniform(this->minRacBackoff_, this->maxRacBackoff_);
478 EV << NOW << " Ue " << this->nodeId_ << " RAC attempt failed, backoff extracted : " << this->racBackoffTimer_ << endl;
479 }
480 }
481 delete pkt;
482}
483
484template<class Base>
485void D2dUeMacBase<Base>::macHandleD2DModeSwitch(cPacket *pkt)
486{
487 d2dUeHelper_.macHandleD2DModeSwitch(pkt);
488}
489
490template<class Base>
491void D2dUeMacBase<Base>::doHandover(MacNodeId targetEnb)
492{
493 if (targetEnb == NODEID_NONE)
494 d2dUeHelper_.setEnb(nullptr);
495 else {
496 d2dUeHelper_.rebuildPreconfiguredTxParams(this->binder_);
497 d2dUeHelper_.setEnb(check_and_cast<ID2dMacEnb *>(this->binder_->getMacByNodeId(targetEnb)));
498 }
499 Base::doHandover(targetEnb);
500}
501
502} //namespace
503
504#endif
Definition ChannelModelBase.h:145
Definition D2dUeMacBase.h:70
int64_t appendBsr(inet::Ptr< LteMacPdu > macPdu) override
Definition D2dUeMacBase.h:105
LteHarqBufferRx * createRxHarqBuffer(MacNodeId src, const UserControlInfo *userInfo) override
HARQ buffer factories: add support for the D2D and D2D_MULTI directions.
Definition D2dUeMacBase.h:272
UnitList reserveTxHarqUnits(LteHarqBufferTx *txBuf, Direction dir) override
Definition D2dUeMacBase.h:130
bool shouldSkipScheduleEntry(unsigned int sduPerCid) const override
Definition D2dUeMacBase.h:123
LcgScheduler * createLcgScheduler() override
Factory override: use the D2D-capable LCG scheduler.
Definition D2dUeMacBase.h:291
void handleMessage(cMessage *msg) override
Definition D2dUeMacBase.h:297
void initialize(int stage) override
Definition D2dUeMacBase.h:161
bool isBsrPending() const override
Definition D2dUeMacBase.h:101
void recordBufferOverflow(Direction dir, double sample) override
The D2D directions are serviced here; everything else defers to the core MAC.
Definition D2dUeMacBase.h:80
bool buildStandaloneBsr() override
Definition D2dUeMacBase.h:186
void macHandleRac(cPacket *pkt) override
Definition D2dUeMacBase.h:446
MacNodeId pduDestId(MacCid destCid) override
D2D bearers are peer-addressed: the destination comes from the flow, not the cell.
Definition D2dUeMacBase.h:119
Definition LcgSchedulerD2D.h:29
Definition LcgScheduler.h:43
Lte AMC module for Omnet++ simulator.
Definition LteAmc.h:45
Definition LteHarqBufferRxD2D.h:36
Definition LteHarqBufferRx.h:37
Definition LteTypes.h:153
Definition AlertReceiver.h:24
constexpr LogicalCid SHORT_BSR
Special LogicalCid values for Buffer Status Reports.
Definition LteTypes.h:112
std::pair< unsigned char, CwList > UnitList
Pair of acid, list of unit ids.
Definition LteCommon.h:395
constexpr MacNodeId NODEID_NONE
MAC node ID.
Definition LteTypes.h:54