13#include "libe3/version.hpp"
18constexpr const char* LOG_TAG =
"E3Agent";
42 : impl_(std::make_unique<
Impl>(std::move(
config)))
44 E3_LOG_INFO(LOG_TAG) <<
"E3Agent created (version " << LIBE3_VERSION_STRING <<
")";
60 if (impl_->interface) {
61 E3_LOG_WARN(LOG_TAG) <<
"Agent already initialized";
62 return ErrorCode::ALREADY_INITIALIZED;
67 impl_->interface = std::make_unique<E3Interface>(impl_->config);
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: "
77 if (impl_->dapp_report_handler) {
78 impl_->interface->set_dapp_report_handler(impl_->dapp_report_handler);
81 if (impl_->dapp_status_changed_handler) {
82 impl_->interface->set_dapp_status_changed_handler(impl_->dapp_status_changed_handler);
85 if (impl_->setup_response_handler) {
86 impl_->interface->set_setup_response_handler(impl_->setup_response_handler);
88 if (impl_->subscription_response_handler) {
89 impl_->interface->set_subscription_response_handler(impl_->subscription_response_handler);
91 if (impl_->indication_handler) {
92 impl_->interface->set_indication_handler(impl_->indication_handler);
94 if (impl_->xapp_control_handler) {
95 impl_->interface->set_xapp_control_handler(impl_->xapp_control_handler);
97 if (impl_->message_ack_handler) {
98 impl_->interface->set_message_ack_handler(impl_->message_ack_handler);
101 E3_LOG_INFO(LOG_TAG) <<
"E3Agent initialized successfully";
102 return ErrorCode::SUCCESS;
107 if (!impl_->interface) {
109 if (init_result != ErrorCode::SUCCESS) {
116 ErrorCode result = impl_->interface->start();
117 if (result != ErrorCode::SUCCESS) {
123 E3_LOG_INFO(LOG_TAG) <<
"E3Agent started successfully";
124 return ErrorCode::SUCCESS;
128 if (!impl_ || !impl_->interface) {
133 impl_->interface->stop();
138 if (!impl_ || !impl_->interface) {
141 return impl_->interface->state();
145 return impl_ && impl_->interface && impl_->interface->is_running();
154 return ErrorCode::INVALID_PARAM;
157 E3_LOG_ERROR(LOG_TAG) <<
"register_sm() is only valid on RAN role";
158 return ErrorCode::STATE_ERROR;
162 if (!impl_->interface) {
164 if (init_result != ErrorCode::SUCCESS) {
169 return impl_->interface->register_sm(std::move(sm));
173 if (!impl_->interface) {
176 return impl_->interface->get_available_ran_functions();
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);
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);
199 uint32_t ran_function_id,
200 const std::vector<uint8_t>& data
203 return ErrorCode::STATE_ERROR;
205 if (!impl_->interface || !impl_->interface->is_running()) {
206 return ErrorCode::NOT_INITIALIZED;
215 uint32_t mid = impl_->interface->generate_message_id();
223 return impl_->interface->queue_outbound(std::move(pdu));
228 uint32_t ran_function_id,
229 const std::vector<uint8_t>& control_data,
233 return ErrorCode::STATE_ERROR;
235 if (!impl_->interface || !impl_->interface->is_running()) {
236 return ErrorCode::NOT_INITIALIZED;
239 pdu.
message_id = impl_->interface->generate_message_id();
246 return impl_->interface->queue_outbound(std::move(pdu));
250 if (!impl_->interface || !impl_->interface->is_running()) {
251 return ErrorCode::NOT_INITIALIZED;
254 pdu.
message_id = impl_->interface->generate_message_id();
259 return impl_->interface->queue_outbound(std::move(pdu));
263 if (!impl_->interface || impl_->config.role !=
E3Role::RAN) {
266 return impl_->interface->subscription_manager().get_registered_dapps();
270 if (!impl_->interface || impl_->config.role !=
E3Role::RAN) {
273 return impl_->interface->subscription_manager().get_dapp_subscriptions(
dapp_id);
277 if (!impl_->interface || impl_->config.role !=
E3Role::RAN) {
280 return impl_->interface->subscription_manager().get_subscribed_dapps(ran_function_id);
284 if (!impl_->interface || impl_->config.role !=
E3Role::RAN) {
287 return impl_->interface->subscription_manager().get_active_ran_functions();
291 if (!impl_->interface) {
294 const auto* details = impl_->interface->subscription_manager()
295 .get_subscription_details(
dapp_id, ran_function_id);
296 return details ? details->periodicity_us : 0;
300 if (!impl_->interface) {
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>{};
309 if (!impl_->interface) {
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>{};
322 return impl_->config;
330 if (!impl_->interface) {
334 return impl_->interface->subscription_manager().dapp_count();
338 return impl_->interface->dapp_id().has_value() ? 1u : 0u;
342 if (!impl_->interface) {
346 return impl_->interface->subscription_manager().subscription_count();
348 return impl_->interface->active_subscription_ids().size();
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);
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);
370 impl_->indication_handler = std::move(handler);
371 if (impl_->interface && impl_->indication_handler) {
372 impl_->interface->set_indication_handler(impl_->indication_handler);
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);
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);
391 if (!impl_->interface || impl_->config.role !=
E3Role::DAPP)
return std::nullopt;
392 return impl_->interface->dapp_id();
396 if (!impl_->interface || impl_->config.role !=
E3Role::DAPP)
return {};
397 return impl_->interface->subscribed_ran_functions();
401 if (!impl_->interface || impl_->config.role !=
E3Role::DAPP)
return {};
402 return impl_->interface->active_subscription_ids();
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);
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,
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);
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);
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);
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();
E3Agent - Main façade for RAN vendor integration.
std::vector< uint32_t > get_registered_dapps() const
Get list of registered dApp IDs.
void stop()
Stop the agent.
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.
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.
void set_xapp_control_handler(XAppControlHandler handler)
void set_setup_response_handler(SetupResponseHandler handler)
ErrorCode wait_for_setup(std::chrono::milliseconds timeout)
Block until the dApp setup handshake completes.
bool is_running() const noexcept
Check if agent is running.
std::vector< uint32_t > subscribed_ran_functions() const
void set_dapp_status_changed_handler(DAppStatusChangedHandler handler)
Set callback for dApp status changes. Called when a dApp connects, disconnects, subscribes,...
std::optional< uint32_t > dapp_id() const noexcept
dApp identifier assigned by the RAN in SetupResponse.
std::vector< uint32_t > get_available_ran_functions() const
Get available RAN function IDs.
std::vector< uint32_t > get_dapp_subscriptions(uint32_t dapp_id) const
Get subscriptions for a dApp.
E3Agent(E3Config config=E3Config{})
Construct an E3Agent with configuration.
std::vector< uint32_t > active_subscription_ids() const
std::vector< uint32_t > get_ran_function_subscribers(uint32_t ran_function_id) const
Get subscribers for a RAN function.
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.
ErrorCode register_sm(std::unique_ptr< ServiceModel > sm)
Register a Service Model.
ErrorCode unsubscribe(uint32_t ran_function_id)
size_t dapp_count() const
Get number of registered dApps.
void set_subscription_response_handler(SubscriptionResponseHandler handler)
~E3Agent()
Destructor - ensures clean shutdown.
const E3Config & config() const noexcept
Get current configuration.
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.
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.
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.
std::vector< uint32_t > get_active_ran_functions() const
Get the RAN functions that currently have at least one subscriber.
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.
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.
void set_indication_handler(IndicationHandler handler)
AgentState state() const noexcept
Get current agent state.
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...
ErrorCode init()
Initialize the agent.
void set_message_ack_handler(MessageAckHandler handler)
size_t subscription_count() const
Get total number of active subscriptions.
ErrorCode start()
Start the agent.
ErrorCode send_message_ack(uint32_t request_id, ResponseCode response_code)
Send a message acknowledgment (e.g. ack a control/request from dApp).
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)
static uint64_t latrec_seq_next(void)
static uint64_t latrec_ctx(void)
Logging facility for libe3.
#define E3_LOG_INFO(component)
#define E3_LOG_ERROR(component)
std::function< void(const SubscriptionResponse &)> SubscriptionResponseHandler
ErrorCode
Error codes returned by libe3 operations Use shared error-code list (see libe3/error_codes....
std::function< void(const XAppControlAction &)> XAppControlHandler
AgentState
Agent state machine states.
@ UNINITIALIZED
Agent not yet initialized.
std::function< void()> DAppStatusChangedHandler
@ RAN
RAN function (binds sockets; today's only behaviour).
@ DAPP
dApp (connects to a RAN agent)
ResponseCode
E3AP response codes.
std::function< void(const DAppReport &)> DAppReportHandler
std::function< void(const SetupResponse &)> SetupResponseHandler
std::function< void(const MessageAck &)> MessageAckHandler
const char * error_code_to_string(ErrorCode code) noexcept
Convert ErrorCode to string representation.
std::function< void(const IndicationMessage &)> IndicationHandler
E3Agent implementation details.
XAppControlHandler xapp_control_handler
MessageAckHandler message_ack_handler
IndicationHandler indication_handler
SubscriptionResponseHandler subscription_response_handler
SetupResponseHandler setup_response_handler
DAppReportHandler dapp_report_handler
DAppStatusChangedHandler dapp_status_changed_handler
std::unique_ptr< E3Interface > interface
Configuration for E3Agent.
E3AP Indication Message structure.
uint32_t ran_function_identifier
RAN function identifier.
std::vector< uint8_t > protocol_data
E3AP Message Acknowledgment structure.
ResponseCode response_code
Response code (positive/negative).
uint32_t request_id
ID of the request being acknowledged.
Generic E3AP PDU structure.
uint64_t enqueue_seq
Set by queue_outbound; keys the [latrec] L-stage records.
uint32_t message_id
Unique message identifier.
E3AP xApp Control Action structure.
std::vector< uint8_t > xapp_control_data
uint32_t ran_function_identifier