libe3 0.2.5
C++ library for E3AP RAN vendor integration
Loading...
Searching...
No Matches
e3_agent.cpp
Go to the documentation of this file.
1/**
2 * @file e3_agent.cpp
3 * @brief E3Agent façade implementation
4 *
5 * SPDX-FileCopyrightText: Copyright (c) 2026 Northeastern University
6 * SPDX-License-Identifier: Apache-2.0
7 */
8
9#include "libe3/e3_agent.hpp"
11#include "libe3/latrec.h"
12#include "libe3/logger.hpp"
13#include "libe3/version.hpp"
14
15namespace libe3 {
16
17namespace {
18constexpr const char* LOG_TAG = "E3Agent";
19}
20
21/**
22 * @brief E3Agent implementation details
23 */
40
42 : impl_(std::make_unique<Impl>(std::move(config)))
43{
44 E3_LOG_INFO(LOG_TAG) << "E3Agent created (version " << LIBE3_VERSION_STRING << ")";
45}
46
48 stop();
49 E3_LOG_INFO(LOG_TAG) << "E3Agent destroyed";
50}
51
52E3Agent::E3Agent(E3Agent&&) noexcept = default;
53E3Agent& E3Agent::operator=(E3Agent&&) noexcept = default;
54
55// =========================================================================
56// Lifecycle Management
57// =========================================================================
58
60 if (impl_->interface) {
61 E3_LOG_WARN(LOG_TAG) << "Agent already initialized";
62 return ErrorCode::ALREADY_INITIALIZED;
63 }
64
65 E3_LOG_INFO(LOG_TAG) << "Initializing E3Agent";
66
67 impl_->interface = std::make_unique<E3Interface>(impl_->config);
68
69 ErrorCode result = impl_->interface->init();
70 if (result != ErrorCode::SUCCESS) {
71 impl_->interface.reset();
72 E3_LOG_ERROR(LOG_TAG) << "Failed to initialize interface: "
73 << error_code_to_string(result);
74 return result;
75 }
76
77 if (impl_->dapp_report_handler) {
78 impl_->interface->set_dapp_report_handler(impl_->dapp_report_handler);
79 }
80
81 if (impl_->dapp_status_changed_handler) {
82 impl_->interface->set_dapp_status_changed_handler(impl_->dapp_status_changed_handler);
83 }
84
85 if (impl_->setup_response_handler) {
86 impl_->interface->set_setup_response_handler(impl_->setup_response_handler);
87 }
88 if (impl_->subscription_response_handler) {
89 impl_->interface->set_subscription_response_handler(impl_->subscription_response_handler);
90 }
91 if (impl_->indication_handler) {
92 impl_->interface->set_indication_handler(impl_->indication_handler);
93 }
94 if (impl_->xapp_control_handler) {
95 impl_->interface->set_xapp_control_handler(impl_->xapp_control_handler);
96 }
97 if (impl_->message_ack_handler) {
98 impl_->interface->set_message_ack_handler(impl_->message_ack_handler);
99 }
100
101 E3_LOG_INFO(LOG_TAG) << "E3Agent initialized successfully";
102 return ErrorCode::SUCCESS;
103}
104
106 // Initialize if not already done
107 if (!impl_->interface) {
108 ErrorCode init_result = init();
109 if (init_result != ErrorCode::SUCCESS) {
110 return init_result;
111 }
112 }
113
114 E3_LOG_INFO(LOG_TAG) << "Starting E3Agent";
115
116 ErrorCode result = impl_->interface->start();
117 if (result != ErrorCode::SUCCESS) {
118 E3_LOG_ERROR(LOG_TAG) << "Failed to start interface: "
119 << error_code_to_string(result);
120 return result;
121 }
122
123 E3_LOG_INFO(LOG_TAG) << "E3Agent started successfully";
124 return ErrorCode::SUCCESS;
125}
126
128 if (!impl_ || !impl_->interface) {
129 return;
130 }
131
132 E3_LOG_INFO(LOG_TAG) << "Stopping E3Agent";
133 impl_->interface->stop();
134 E3_LOG_INFO(LOG_TAG) << "E3Agent stopped";
135}
136
137AgentState E3Agent::state() const noexcept {
138 if (!impl_ || !impl_->interface) {
140 }
141 return impl_->interface->state();
142}
143
144bool E3Agent::is_running() const noexcept {
145 return impl_ && impl_->interface && impl_->interface->is_running();
146}
147
148// =========================================================================
149// Service Model Registration
150// =========================================================================
151
152ErrorCode E3Agent::register_sm(std::unique_ptr<ServiceModel> sm) {
153 if (!sm) {
154 return ErrorCode::INVALID_PARAM;
155 }
156 if (impl_->config.role != E3Role::RAN) {
157 E3_LOG_ERROR(LOG_TAG) << "register_sm() is only valid on RAN role";
158 return ErrorCode::STATE_ERROR;
159 }
160
161 // Initialize interface if needed
162 if (!impl_->interface) {
163 ErrorCode init_result = init();
164 if (init_result != ErrorCode::SUCCESS) {
165 return init_result;
166 }
167 }
168
169 return impl_->interface->register_sm(std::move(sm));
170}
171
172std::vector<uint32_t> E3Agent::get_available_ran_functions() const {
173 if (!impl_->interface) {
174 return {};
175 }
176 return impl_->interface->get_available_ran_functions();
177}
178
180 impl_->dapp_report_handler = std::move(handler);
181 if (impl_->interface && impl_->dapp_report_handler) {
182 impl_->interface->set_dapp_report_handler(impl_->dapp_report_handler);
183 }
184}
185
187 impl_->dapp_status_changed_handler = std::move(handler);
188 if (impl_->interface && impl_->dapp_status_changed_handler) {
189 impl_->interface->set_dapp_status_changed_handler(impl_->dapp_status_changed_handler);
190 }
191}
192
193// =========================================================================
194// Manual Operations
195// =========================================================================
196
198 uint32_t dapp_id,
199 uint32_t ran_function_id,
200 const std::vector<uint8_t>& data
201) {
202 if (impl_->config.role != E3Role::RAN) {
203 return ErrorCode::STATE_ERROR;
204 }
205 if (!impl_->interface || !impl_->interface->is_running()) {
206 return ErrorCode::NOT_INITIALIZED;
207 }
208
210 // As in e3_service_model_emit_indication: the outbound leg starts at this
211 // boundary whichever API the producer used.
213 latrec_tstamp(pdu.enqueue_seq, LATREC_EMIT_ENTER, latrec_ctx(), ran_function_id);
214
215 uint32_t mid = impl_->interface->generate_message_id();
216 pdu.message_id = mid;
219 msg.ran_function_identifier = ran_function_id;
220 msg.protocol_data = data;
221 pdu.choice = msg;
222
223 return impl_->interface->queue_outbound(std::move(pdu));
224}
225
227 uint32_t dapp_id,
228 uint32_t ran_function_id,
229 const std::vector<uint8_t>& control_data,
230 uint32_t sequence_id
231) {
232 if (impl_->config.role != E3Role::RAN) {
233 return ErrorCode::STATE_ERROR;
234 }
235 if (!impl_->interface || !impl_->interface->is_running()) {
236 return ErrorCode::NOT_INITIALIZED;
237 }
239 pdu.message_id = impl_->interface->generate_message_id();
240 XAppControlAction action;
241 action.dapp_identifier = dapp_id;
242 action.ran_function_identifier = ran_function_id;
243 action.xapp_control_data = control_data;
244 action.sequence_id = sequence_id;
245 pdu.choice = action;
246 return impl_->interface->queue_outbound(std::move(pdu));
247}
248
249ErrorCode E3Agent::send_message_ack(uint32_t request_id, ResponseCode response_code) {
250 if (!impl_->interface || !impl_->interface->is_running()) {
251 return ErrorCode::NOT_INITIALIZED;
252 }
254 pdu.message_id = impl_->interface->generate_message_id();
255 MessageAck ack;
256 ack.request_id = request_id;
257 ack.response_code = response_code;
258 pdu.choice = ack;
259 return impl_->interface->queue_outbound(std::move(pdu));
260}
261
262std::vector<uint32_t> E3Agent::get_registered_dapps() const {
263 if (!impl_->interface || impl_->config.role != E3Role::RAN) {
264 return {};
265 }
266 return impl_->interface->subscription_manager().get_registered_dapps();
267}
268
269std::vector<uint32_t> E3Agent::get_dapp_subscriptions(uint32_t dapp_id) const {
270 if (!impl_->interface || impl_->config.role != E3Role::RAN) {
271 return {};
272 }
273 return impl_->interface->subscription_manager().get_dapp_subscriptions(dapp_id);
274}
275
276std::vector<uint32_t> E3Agent::get_ran_function_subscribers(uint32_t ran_function_id) const {
277 if (!impl_->interface || impl_->config.role != E3Role::RAN) {
278 return {};
279 }
280 return impl_->interface->subscription_manager().get_subscribed_dapps(ran_function_id);
281}
282
283std::vector<uint32_t> E3Agent::get_active_ran_functions() const {
284 if (!impl_->interface || impl_->config.role != E3Role::RAN) {
285 return {};
286 }
287 return impl_->interface->subscription_manager().get_active_ran_functions();
288}
289
290uint32_t E3Agent::get_subscription_periodicity(uint32_t dapp_id, uint32_t ran_function_id) const {
291 if (!impl_->interface) {
292 return 0;
293 }
294 const auto* details = impl_->interface->subscription_manager()
295 .get_subscription_details(dapp_id, ran_function_id);
296 return details ? details->periodicity_us : 0;
297}
298
299std::vector<uint32_t> E3Agent::get_subscription_telemetry_ids(uint32_t dapp_id, uint32_t ran_function_id) const {
300 if (!impl_->interface) {
301 return {};
302 }
303 const auto* details = impl_->interface->subscription_manager()
304 .get_subscription_details(dapp_id, ran_function_id);
305 return details ? details->telemetry_ids : std::vector<uint32_t>{};
306}
307
308std::vector<uint32_t> E3Agent::get_subscription_control_ids(uint32_t dapp_id, uint32_t ran_function_id) const {
309 if (!impl_->interface) {
310 return {};
311 }
312 const auto* details = impl_->interface->subscription_manager()
313 .get_subscription_details(dapp_id, ran_function_id);
314 return details ? details->control_ids : std::vector<uint32_t>{};
315}
316
317// =========================================================================
318// Configuration
319// =========================================================================
320
321const E3Config& E3Agent::config() const noexcept {
322 return impl_->config;
323}
324
325// =========================================================================
326// Statistics
327// =========================================================================
328
329size_t E3Agent::dapp_count() const {
330 if (!impl_->interface) {
331 return 0;
332 }
333 if (impl_->config.role == E3Role::RAN) {
334 return impl_->interface->subscription_manager().dapp_count();
335 }
336 // On the dApp role, "dapp_count" is 0/1 depending on whether we have a
337 // dApp identifier assigned.
338 return impl_->interface->dapp_id().has_value() ? 1u : 0u;
339}
340
342 if (!impl_->interface) {
343 return 0;
344 }
345 if (impl_->config.role == E3Role::RAN) {
346 return impl_->interface->subscription_manager().subscription_count();
347 }
348 return impl_->interface->active_subscription_ids().size();
349}
350
351// =========================================================================
352// dApp-role API
353// =========================================================================
354
356 impl_->setup_response_handler = std::move(handler);
357 if (impl_->interface && impl_->setup_response_handler) {
358 impl_->interface->set_setup_response_handler(impl_->setup_response_handler);
359 }
360}
361
363 impl_->subscription_response_handler = std::move(handler);
364 if (impl_->interface && impl_->subscription_response_handler) {
365 impl_->interface->set_subscription_response_handler(impl_->subscription_response_handler);
366 }
367}
368
370 impl_->indication_handler = std::move(handler);
371 if (impl_->interface && impl_->indication_handler) {
372 impl_->interface->set_indication_handler(impl_->indication_handler);
373 }
374}
375
377 impl_->xapp_control_handler = std::move(handler);
378 if (impl_->interface && impl_->xapp_control_handler) {
379 impl_->interface->set_xapp_control_handler(impl_->xapp_control_handler);
380 }
381}
382
384 impl_->message_ack_handler = std::move(handler);
385 if (impl_->interface && impl_->message_ack_handler) {
386 impl_->interface->set_message_ack_handler(impl_->message_ack_handler);
387 }
388}
389
390std::optional<uint32_t> E3Agent::dapp_id() const noexcept {
391 if (!impl_->interface || impl_->config.role != E3Role::DAPP) return std::nullopt;
392 return impl_->interface->dapp_id();
393}
394
395std::vector<uint32_t> E3Agent::subscribed_ran_functions() const {
396 if (!impl_->interface || impl_->config.role != E3Role::DAPP) return {};
397 return impl_->interface->subscribed_ran_functions();
398}
399
400std::vector<uint32_t> E3Agent::active_subscription_ids() const {
401 if (!impl_->interface || impl_->config.role != E3Role::DAPP) return {};
402 return impl_->interface->active_subscription_ids();
403}
404
405ErrorCode E3Agent::wait_for_setup(std::chrono::milliseconds timeout) {
406 if (impl_->config.role != E3Role::DAPP) return ErrorCode::INVALID_PARAM;
407 if (!impl_->interface) return ErrorCode::NOT_INITIALIZED;
408 return impl_->interface->wait_for_setup(timeout);
409}
410
411ErrorCode E3Agent::subscribe(uint32_t ran_function_id,
412 std::vector<uint32_t> telemetry_ids,
413 std::vector<uint32_t> control_ids,
414 std::optional<uint32_t> sub_time,
415 std::optional<uint32_t> periodicity,
416 uint32_t* out_request_id) {
417 if (impl_->config.role != E3Role::DAPP) return ErrorCode::STATE_ERROR;
418 if (!impl_->interface || !impl_->interface->is_running()) return ErrorCode::NOT_INITIALIZED;
419 return impl_->interface->queue_subscription_request(
420 ran_function_id, std::move(telemetry_ids), std::move(control_ids), sub_time, periodicity,
421 out_request_id);
422}
423
424ErrorCode E3Agent::unsubscribe(uint32_t ran_function_id) {
425 if (impl_->config.role != E3Role::DAPP) return ErrorCode::STATE_ERROR;
426 if (!impl_->interface || !impl_->interface->is_running()) return ErrorCode::NOT_INITIALIZED;
427 return impl_->interface->queue_subscription_delete(ran_function_id);
428}
429
430ErrorCode E3Agent::send_control(uint32_t ran_function_id,
431 uint32_t control_id,
432 std::vector<uint8_t> action_data,
433 uint32_t sequence_id,
434 uint32_t* out_message_id) {
435 if (impl_->config.role != E3Role::DAPP) return ErrorCode::STATE_ERROR;
436 if (!impl_->interface || !impl_->interface->is_running()) return ErrorCode::NOT_INITIALIZED;
437 return impl_->interface->queue_dapp_control_action(
438 ran_function_id, control_id, std::move(action_data), sequence_id, out_message_id);
439}
440
441ErrorCode E3Agent::send_report(uint32_t ran_function_id,
442 std::vector<uint8_t> report_data,
443 uint32_t sequence_id,
444 uint32_t* out_message_id) {
445 if (impl_->config.role != E3Role::DAPP) return ErrorCode::STATE_ERROR;
446 if (!impl_->interface || !impl_->interface->is_running()) return ErrorCode::NOT_INITIALIZED;
447 return impl_->interface->queue_dapp_report(
448 ran_function_id, std::move(report_data), sequence_id, out_message_id);
449}
450
452 if (impl_->config.role != E3Role::DAPP) return ErrorCode::STATE_ERROR;
453 if (!impl_->interface || !impl_->interface->is_running()) return ErrorCode::NOT_INITIALIZED;
454 return impl_->interface->queue_release_message();
455}
456
457} // namespace libe3
E3Agent - Main façade for RAN vendor integration.
Definition e3_agent.hpp:85
std::vector< uint32_t > get_registered_dapps() const
Get list of registered dApp IDs.
Definition e3_agent.cpp:262
void stop()
Stop the agent.
Definition e3_agent.cpp:127
ErrorCode subscribe(uint32_t ran_function_id, std::vector< uint32_t > telemetry_ids, std::vector< uint32_t > control_ids, std::optional< uint32_t > sub_time=std::nullopt, std::optional< uint32_t > periodicity=std::nullopt, uint32_t *out_request_id=nullptr)
Subscribe to a RAN function. Must be called after a positive setup.
Definition e3_agent.cpp:411
std::vector< uint32_t > get_subscription_telemetry_ids(uint32_t dapp_id, uint32_t ran_function_id) const
Get the telemetry IDs a dApp requested for a RAN function.
Definition e3_agent.cpp:299
void set_xapp_control_handler(XAppControlHandler handler)
Definition e3_agent.cpp:376
void set_setup_response_handler(SetupResponseHandler handler)
Definition e3_agent.cpp:355
ErrorCode wait_for_setup(std::chrono::milliseconds timeout)
Block until the dApp setup handshake completes.
Definition e3_agent.cpp:405
bool is_running() const noexcept
Check if agent is running.
Definition e3_agent.cpp:144
std::vector< uint32_t > subscribed_ran_functions() const
Definition e3_agent.cpp:395
void set_dapp_status_changed_handler(DAppStatusChangedHandler handler)
Set callback for dApp status changes. Called when a dApp connects, disconnects, subscribes,...
Definition e3_agent.cpp:186
std::optional< uint32_t > dapp_id() const noexcept
dApp identifier assigned by the RAN in SetupResponse.
Definition e3_agent.cpp:390
std::vector< uint32_t > get_available_ran_functions() const
Get available RAN function IDs.
Definition e3_agent.cpp:172
std::vector< uint32_t > get_dapp_subscriptions(uint32_t dapp_id) const
Get subscriptions for a dApp.
Definition e3_agent.cpp:269
E3Agent(E3Config config=E3Config{})
Construct an E3Agent with configuration.
Definition e3_agent.cpp:41
ErrorCode release()
Definition e3_agent.cpp:451
std::vector< uint32_t > active_subscription_ids() const
Definition e3_agent.cpp:400
std::vector< uint32_t > get_ran_function_subscribers(uint32_t ran_function_id) const
Get subscribers for a RAN function.
Definition e3_agent.cpp:276
uint32_t get_subscription_periodicity(uint32_t dapp_id, uint32_t ran_function_id) const
Get the reporting periodicity a dApp requested for a RAN function.
Definition e3_agent.cpp:290
ErrorCode register_sm(std::unique_ptr< ServiceModel > sm)
Register a Service Model.
Definition e3_agent.cpp:152
ErrorCode unsubscribe(uint32_t ran_function_id)
Definition e3_agent.cpp:424
size_t dapp_count() const
Get number of registered dApps.
Definition e3_agent.cpp:329
void set_subscription_response_handler(SubscriptionResponseHandler handler)
Definition e3_agent.cpp:362
~E3Agent()
Destructor - ensures clean shutdown.
Definition e3_agent.cpp:47
const E3Config & config() const noexcept
Get current configuration.
Definition e3_agent.cpp:321
std::vector< uint32_t > get_subscription_control_ids(uint32_t dapp_id, uint32_t ran_function_id) const
Get the control IDs a dApp requested for a RAN function.
Definition e3_agent.cpp:308
ErrorCode send_report(uint32_t ran_function_id, std::vector< uint8_t > report_data, uint32_t sequence_id, uint32_t *out_message_id=nullptr)
Send a dApp report to the RAN.
Definition e3_agent.cpp:441
ErrorCode send_indication(uint32_t dapp_id, uint32_t ran_function_id, const std::vector< uint8_t > &data)
Send an indication message to a specific dApp.
Definition e3_agent.cpp:197
std::vector< uint32_t > get_active_ran_functions() const
Get the RAN functions that currently have at least one subscriber.
Definition e3_agent.cpp:283
ErrorCode send_xapp_control(uint32_t dapp_id, uint32_t ran_function_id, const std::vector< uint8_t > &control_data, uint32_t sequence_id)
Send an xApp control action to a specific dApp coming from the E2SM-DAPP.
Definition e3_agent.cpp:226
ErrorCode send_control(uint32_t ran_function_id, uint32_t control_id, std::vector< uint8_t > action_data, uint32_t sequence_id=0, uint32_t *out_message_id=nullptr)
Send a dApp control action to the RAN.
Definition e3_agent.cpp:430
void set_indication_handler(IndicationHandler handler)
Definition e3_agent.cpp:369
AgentState state() const noexcept
Get current agent state.
Definition e3_agent.cpp:137
void set_dapp_report_handler(DAppReportHandler handler)
Set callback for incoming dApp reports (dApp → RAN). Call before start(). When a dApp sends a DApp re...
Definition e3_agent.cpp:179
ErrorCode init()
Initialize the agent.
Definition e3_agent.cpp:59
void set_message_ack_handler(MessageAckHandler handler)
Definition e3_agent.cpp:383
size_t subscription_count() const
Get total number of active subscriptions.
Definition e3_agent.cpp:341
ErrorCode start()
Start the agent.
Definition e3_agent.cpp:105
ErrorCode send_message_ack(uint32_t request_id, ResponseCode response_code)
Send a message acknowledgment (e.g. ack a control/request from dApp).
Definition e3_agent.cpp:249
E3Agent - Main façade class for RAN vendors.
E3Interface - Internal protocol coordination layer.
Lock-free per-thread latency stamp recorder (header-only, C99).
static void latrec_tstamp(uint64_t seq, uint8_t stage, uint64_t aux, uint64_t aux2)
Definition latrec.h:685
static uint64_t latrec_seq_next(void)
Definition latrec.h:684
@ LATREC_EMIT_ENTER
Definition latrec.h:174
static uint64_t latrec_ctx(void)
Definition latrec.h:697
Logging facility for libe3.
#define E3_LOG_INFO(component)
Definition logger.hpp:227
#define E3_LOG_ERROR(component)
Definition logger.hpp:225
std::function< void(const SubscriptionResponse &)> SubscriptionResponseHandler
Definition e3_agent.hpp:37
ErrorCode
Error codes returned by libe3 operations Use shared error-code list (see libe3/error_codes....
Definition types.hpp:141
std::function< void(const XAppControlAction &)> XAppControlHandler
Definition e3_agent.hpp:39
AgentState
Agent state machine states.
Definition types.hpp:126
@ UNINITIALIZED
Agent not yet initialized.
Definition types.hpp:127
std::function< void()> DAppStatusChangedHandler
Definition e3_agent.hpp:33
@ RAN
RAN function (binds sockets; today's only behaviour).
Definition types.hpp:76
@ DAPP
dApp (connects to a RAN agent)
Definition types.hpp:77
ResponseCode
E3AP response codes.
Definition types.hpp:101
std::function< void(const DAppReport &)> DAppReportHandler
Definition e3_agent.hpp:30
@ XAPP_CONTROL_ACTION
Definition types.hpp:118
std::function< void(const SetupResponse &)> SetupResponseHandler
Definition e3_agent.hpp:36
std::function< void(const MessageAck &)> MessageAckHandler
Definition e3_agent.hpp:40
const char * error_code_to_string(ErrorCode code) noexcept
Convert ErrorCode to string representation.
Definition types.hpp:558
std::function< void(const IndicationMessage &)> IndicationHandler
Definition e3_agent.hpp:38
E3Agent implementation details.
Definition e3_agent.cpp:24
XAppControlHandler xapp_control_handler
Definition e3_agent.cpp:35
Impl(E3Config cfg)
Definition e3_agent.cpp:38
MessageAckHandler message_ack_handler
Definition e3_agent.cpp:36
IndicationHandler indication_handler
Definition e3_agent.cpp:34
SubscriptionResponseHandler subscription_response_handler
Definition e3_agent.cpp:33
SetupResponseHandler setup_response_handler
Definition e3_agent.cpp:32
DAppReportHandler dapp_report_handler
Definition e3_agent.cpp:27
DAppStatusChangedHandler dapp_status_changed_handler
Definition e3_agent.cpp:28
std::unique_ptr< E3Interface > interface
Definition e3_agent.cpp:26
Configuration for E3Agent.
Definition types.hpp:390
E3AP Indication Message structure.
Definition types.hpp:263
uint32_t ran_function_identifier
RAN function identifier.
Definition types.hpp:265
std::vector< uint8_t > protocol_data
Definition types.hpp:266
E3AP Message Acknowledgment structure.
Definition types.hpp:285
ResponseCode response_code
Response code (positive/negative).
Definition types.hpp:287
uint32_t request_id
ID of the request being acknowledged.
Definition types.hpp:286
Generic E3AP PDU structure.
Definition types.hpp:345
uint64_t enqueue_seq
Set by queue_outbound; keys the [latrec] L-stage records.
Definition types.hpp:349
PduChoice choice
Definition types.hpp:347
uint32_t message_id
Unique message identifier.
Definition types.hpp:348
E3AP xApp Control Action structure.
Definition types.hpp:306
std::vector< uint8_t > xapp_control_data
Definition types.hpp:309
uint32_t ran_function_identifier
Definition types.hpp:308