D2dUePhy.h Source File

Simu5G: D2dUePhy.h Source File
Simu5G
D2dUePhy.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_PHY_D2DUEPHY_H_
14#define STACK_D2D_PHY_D2DUEPHY_H_
15
16#include "simu5g/stack/phy/PhyUe.h"
17#include "simu5g/stack/phy/packet/LteFeedbackPkt.h"
18#include "simu5g/stack/rrc/ConnectionControlUe.h"
19#include "simu5g/stack/d2d/phy/D2dUePhyHelper.h"
20#include "simu5g/stack/d2d/binder/D2dBinder.h"
21#include "simu5g/common/LteControlInfoTags_m.h"
22
23namespace simu5g {
24
25using namespace omnetpp;
26
42template<class Base>
43class D2dUePhy : public Base
44{
45 protected:
46 // holds the D2D-specific UE-PHY state and logic:
47 // D2D Tx power and the D2D-multicast capture-effect machinery
48 D2dUePhyHelper d2dHelper_{this};
49
50 // timer for triggering decoding at the end of the TTI. Started when the first
51 // airframe is received. The self-message stays in the module (which owns it);
52 // the captured frames it decodes live in d2dHelper_.
53 cMessage *d2dDecodingTimer_ = nullptr;
54
55 // Interned in initialize() rather than registered by a static initializer, so that
56 // linking the D2D package in cannot shift the signal ids the core assigns. See the
57 // "Signals" note in D2dUeMacBase.h.
58 simsignal_t averageCqiD2DSignal_ = SIMSIGNAL_NULL;
59
60 // the global D2D directory; this PHY registers itself in it so that peers can
61 // resolve it by node id on the one-to-many transmit path
62 inet::ModuleRefByPar<D2dBinder> d2dBinder_;
63
64 void initialize(int stage) override;
65 void handleSelfMessage(cMessage *msg) override;
66
67 // ---- incoming-frame seams (replace the historical handleAirFrame copy) ----
68
70 bool isStaleFrame(const UserControlInfo *lteInfo) override
71 {
72 return lteInfo->getDirection() != D2D && lteInfo->getDirection() != D2D_MULTI
73 && lteInfo->getSourceId() != this->servingNodeId_;
74 }
75
78 void frameAccepted(UserControlInfo *lteInfo) override
79 {
80 if (this->binder_->isInMulticastGroup(this->nodeId_, lteInfo->getPacketMulticastGroupId()))
81 lteInfo->setDestId(this->nodeId_);
82 }
83
85 bool isControlFrameType(LtePhyFrameType type) override
86 {
87 return type == D2DMODESWITCHPKT || Base::isControlFrameType(type);
88 }
89
91 bool interceptIncomingFrame(LteAirFrame *frame, UserControlInfo *lteInfo) override
92 {
93 if (!(d2dHelper_.getMulticastEnableCaptureEffect() && this->binder_->isInMulticastGroup(this->nodeId_, lteInfo->getPacketMulticastGroupId())))
94 return false;
95
96 // If not already started, auto-send a message to signal the presence of data to be decoded
97 if (d2dDecodingTimer_ == nullptr) {
98 d2dDecodingTimer_ = new cMessage("d2dDecodingTimer");
99 d2dDecodingTimer_->setSchedulingPriority(10); // last thing to be performed in this TTI
100 this->scheduleAt(NOW, d2dDecodingTimer_);
101 }
102
103 // Store frame, together with related control info
104 frame->setControlInfo(lteInfo);
105 d2dHelper_.storeAirFrame(frame); // implements the capture effect
106 return true;
107 }
108
109 // ---- outgoing-frame seams (replace the historical handleUpperMessage copy) ----
110
113 void validateOutgoingFrame(const UserControlInfo *info) override {}
114
116 void recordExtraTxCqi(double cqi, const UserControlInfo *info) override
117 {
118 if (info->getDirection() == D2D || info->getDirection() == D2D_MULTI)
119 this->emit(averageCqiD2DSignal_, cqi);
120 }
121
123 const char *airFrameNameFor(const UserControlInfo *info) override
124 {
125 switch (info->getFrameType()) {
126 case HARQPKT:
127 case GRANTPKT:
128 case RACPKT: return "harqFeedback-grant";
129 default: return "airframe";
130 }
131 }
132
133 void stampExtraTxControlInfo(UserControlInfo *info) override
134 {
135 info->setD2dTxPower(d2dHelper_.getD2dTxPower());
136 }
137
139 void transmitFrame(LteAirFrame *frame, const UserControlInfo *info) override
140 {
141 if (info->getDirection() == D2D_MULTI)
142 sendMulticast(frame);
143 else
144 this->sendUnicast(frame);
145 }
146
153 void sendMulticast(LteAirFrame *frame);
154
155 public:
156 double getTxPwr(Direction dir = UNKNOWN_DIRECTION) override
157 {
158 if (dir == D2D)
159 return d2dHelper_.getD2dTxPower();
160 return this->txPower_;
161 }
162};
163
164template<class Base>
165void D2dUePhy<Base>::initialize(int stage)
166{
167 Base::initialize(stage);
168 if (stage == inet::INITSTAGE_LOCAL) {
169 averageCqiD2DSignal_ = cComponent::registerSignal("averageCqiD2D");
170 d2dHelper_.setD2dTxPower(this->par("d2dTxPower"));
171 d2dHelper_.setMulticastEnableCaptureEffect(this->par("d2dMulticastCaptureEffect"));
172 d2dHelper_.setMulticastD2DRangeCheckEnabled(this->par("enableMulticastD2DRangeCheck"));
173 d2dHelper_.setMulticastD2DRange(this->par("multicastD2DRange"));
174 d2dBinder_.reference(this, "d2dBinderModule", true);
175 d2dHelper_.initWatches();
176 }
177 else if (stage == INITSTAGE_SIMU5G_BINDER_ACCESS) {
178 // Publish this PHY under its node id, so that a peer's one-to-many transmit
179 // path can reach it without knowing the NIC's submodule names
180 d2dBinder_->registerD2dPhy(this->nodeId_, this);
181 }
182}
183
184template<class Base>
185void D2dUePhy<Base>::handleSelfMessage(cMessage *msg)
186{
187 if (msg->isName("d2dDecodingTimer")) {
188 // Decode the captured frame (capture effect) and clear the receive buffer.
189 d2dHelper_.decodeStoredFrames();
190
191 delete msg;
192 d2dDecodingTimer_ = nullptr;
193 }
194 else
195 Base::handleSelfMessage(msg);
196}
197
198template<class Base>
199void D2dUePhy<Base>::sendMulticast(LteAirFrame *frame)
200{
201 UserControlInfo *ci = check_and_cast<UserControlInfo *>(frame->getControlInfo());
202
203 // get the group Id
204 MacNodeId groupId = ci->getPacketMulticastGroupId();
205 if (groupId == NODEID_NONE)
206 throw cRuntimeError("D2dUePhy::sendMulticast - Error. Group ID %d is not valid.", num(groupId));
207
208 // transfer control info into airframe fields
209 frame->setAdditionalInfo(*ci);
210 delete frame->removeControlInfo();
211
212 // send the frame to nodes belonging to the multicast group only
213 for (auto [destId, nodeInfo] : this->binder_->getNodeInfoMap()) {
214 // if the node in the list does not use the same LTE/NR technology of this PHY module, skip it
215 if (isNrUe(destId) != this->isNr_)
216 continue;
217
218 if (destId != this->nodeId_ && this->binder_->isInMulticastGroup(destId, groupId)) {
219 EV << NOW << " D2dUePhy::sendMulticast - node " << destId << " is in the multicast group" << endl;
220
221 // get a pointer to receiving module
222 cModule *receiver = nodeInfo.moduleRef;
223
224 if (d2dHelper_.getMulticastD2DRangeCheckEnabled()) {
225 // the peer's PHY registered itself under its node id at init; the
226 // technology already matches, since the loop skipped the other leg above
227 PhyBase *recvPhy = d2dBinder_->getD2dPhy(destId);
228 if (recvPhy == nullptr)
229 throw cRuntimeError("D2dUePhy::sendMulticast - node %d is in multicast group %d but has no registered D2D PHY",
230 num(destId), num(groupId));
231
232 double dist = recvPhy->getCoord().distance(this->getRadioPosition());
233
234 if (dist > d2dHelper_.getMulticastD2DRange()) {
235 EV << NOW << " D2dUePhy::sendMulticast - node too far (" << dist << " > " << d2dHelper_.getMulticastD2DRange() << ". skipping transmission" << endl;
236 continue;
237 }
238 }
239
240 EV << NOW << " D2dUePhy::sendMulticast - sending frame to node " << destId << endl;
241
242 // Create a duplicate frame before sending
243 LteAirFrame *frameToSend = frame->dup();
244 this->sendDirect(frameToSend, 0, frame->getDuration(), receiver, this->getReceiverGateIndex(receiver, destId));
245 }
246 }
247
248 // delete the original frame
249 delete frame;
250}
251
252} //namespace
253
254#endif
Definition D2dUePhy.h:44
void recordExtraTxCqi(double cqi, const UserControlInfo *info) override
D2D CQI accounting for outgoing data packets.
Definition D2dUePhy.h:116
bool isStaleFrame(const UserControlInfo *lteInfo) override
D2D/D2D_MULTI frames legitimately arrive from peers, not the serving cell.
Definition D2dUePhy.h:70
bool isControlFrameType(LtePhyFrameType type) override
D2D mode-switch notifications are control frames too.
Definition D2dUePhy.h:85
void frameAccepted(UserControlInfo *lteInfo) override
Definition D2dUePhy.h:78
void transmitFrame(LteAirFrame *frame, const UserControlInfo *info) override
one-to-many D2D transmissions go out via sendDirect to all group members
Definition D2dUePhy.h:139
void sendMulticast(LteAirFrame *frame)
Definition D2dUePhy.h:199
void validateOutgoingFrame(const UserControlInfo *info) override
Definition D2dUePhy.h:113
bool interceptIncomingFrame(LteAirFrame *frame, UserControlInfo *lteInfo) override
D2D-multicast capture effect: store the frame and decode it at the end of the TTI.
Definition D2dUePhy.h:91
const char * airFrameNameFor(const UserControlInfo *info) override
keep the historical D2D frame naming (all control frames named "harqFeedback-grant")
Definition D2dUePhy.h:123
Definition AlertReceiver.h:24
constexpr MacNodeId NODEID_NONE
MAC node ID.
Definition LteTypes.h:54