26inline std::optional<uint32_t> opt_u32(
int v) {
27 if (v < 0)
return std::nullopt;
28 return static_cast<uint32_t
>(v);
35 queue(queue_capacity) {}
37 std::unique_ptr<libe3::E3Agent>
agent;
42 std::atomic<unsigned long long>
dropped{0};
52 const uint64_t kind =
static_cast<uint64_t
>(ev.
kind);
57 if (
queue.push(std::move(ev)) != libe3::ErrorCode::SUCCESS) {
58 dropped.fetch_add(1, std::memory_order_relaxed);
68 impl_ = std::make_unique<Impl>(std::move(config), queue_capacity);
69 Impl* impl = impl_.get();
70 auto& agent = *impl->
agent;
104 std::lock_guard<std::mutex> lk(impl->
setup_mu);
127 impl_->queue.shutdown();
128 if (impl_->agent) impl_->agent->stop();
136 impl_->queue.rearm();
137 return static_cast<int>(impl_->agent->start());
141 return static_cast<int>(
142 impl_->agent->wait_for_setup(std::chrono::milliseconds(timeout_ms)));
146 return static_cast<int>(impl_->agent->release());
150 impl_->queue.shutdown();
151 impl_->agent->stop();
155 auto id = impl_->agent->dapp_id();
156 return id ?
static_cast<long>(*id) : -1;
160 std::lock_guard<std::mutex> lk(impl_->setup_mu);
161 return impl_->have_setup ? impl_->setup.ran_identifier : std::string{};
165 std::lock_guard<std::mutex> lk(impl_->setup_mu);
166 if (!impl_->have_setup)
return -1;
167 return static_cast<int>(impl_->setup.response_code);
171 std::lock_guard<std::mutex> lk(impl_->setup_mu);
172 return impl_->have_setup ? impl_->setup.ran_function_list.size() : 0;
176 std::lock_guard<std::mutex> lk(impl_->setup_mu);
177 if (!impl_->have_setup || i >= impl_->setup.ran_function_list.size())
return 0;
178 return impl_->setup.ran_function_list[i].ran_function_identifier;
182 std::lock_guard<std::mutex> lk(impl_->setup_mu);
183 if (!impl_->have_setup || i >= impl_->setup.ran_function_list.size())
return {};
184 return impl_->setup.ran_function_list[i].telemetry_identifier_list;
188 std::lock_guard<std::mutex> lk(impl_->setup_mu);
189 if (!impl_->have_setup || i >= impl_->setup.ran_function_list.size())
return {};
190 return impl_->setup.ran_function_list[i].control_identifier_list;
194 std::lock_guard<std::mutex> lk(impl_->setup_mu);
195 if (!impl_->have_setup || i >= impl_->setup.ran_function_list.size())
return {};
196 return impl_->setup.ran_function_list[i].ran_function_data;
200 std::vector<uint32_t> telemetry_ids,
201 std::vector<uint32_t> control_ids,
204 uint32_t request_id = 0;
206 ran_function_id, std::move(telemetry_ids), std::move(control_ids),
207 opt_u32(sub_time_ms), opt_u32(periodicity), &request_id);
211 if (rc == ErrorCode::SUCCESS) {
212 return static_cast<int64_t
>(request_id);
214 return static_cast<int64_t
>(rc);
218 return static_cast<int>(impl_->agent->unsubscribe(ran_function_id));
222 std::vector<uint8_t> action_data,
223 uint32_t sequence_id) {
224 uint32_t message_id = 0;
225 ErrorCode rc = impl_->agent->send_control(
226 ran_function_id, control_id, std::move(action_data), sequence_id, &message_id);
230 if (rc == ErrorCode::SUCCESS) {
231 return static_cast<int64_t
>(message_id);
233 return static_cast<int64_t
>(rc);
237 uint32_t sequence_id) {
238 uint32_t message_id = 0;
239 ErrorCode rc = impl_->agent->send_report(
240 ran_function_id, std::move(report_data), sequence_id, &message_id);
242 if (rc == ErrorCode::SUCCESS) {
243 return static_cast<int64_t
>(message_id);
245 return static_cast<int64_t
>(rc);
249 return static_cast<int>(impl_->agent->send_message_ack(
254 std::vector<E3Event> out;
255 if (max_batch == 0)
return out;
256 auto& queue = impl_->queue;
264 std::optional<E3Event> first =
265 (timeout_ms <= 0) ? queue.try_pop()
266 : queue.pop(std::chrono::milliseconds(timeout_ms));
267 if (!first)
return out;
269 out.reserve(std::min(max_batch, queue.capacity()));
270 out.push_back(std::move(*first));
271 while (out.size() < max_batch) {
272 auto next = queue.try_pop();
274 out.push_back(std::move(*next));
278 for (std::size_t i = 0; i < out.size(); ++i) {
285 return impl_->dropped.load(std::memory_order_relaxed);
E3Agent - Main façade for RAN vendor integration.
Lock-free bounded blocking queue.
uint32_t setup_ran_function_id(std::size_t i) const
RAN function id of advertised entry i (0 if out of range).
int setup_response_code() const
SetupResponse code: 0=positive, 1=negative, -1=not received.
int unsubscribe(uint32_t ran_function_id)
Delete a previously created subscription.
std::vector< E3Event > poll_events(std::size_t max_batch, int timeout_ms)
Drain up to max_batch inbound events, waiting up to timeout_ms for the first.
std::vector< uint8_t > setup_ran_function_data(std::size_t i) const
Opaque ranFunctionData bytes of advertised entry i.
std::vector< uint32_t > setup_ran_function_telemetry(std::size_t i) const
Telemetry ids of advertised entry i.
std::string ran_identifier() const
RAN identifier from the SetupResponse, or "" if none.
unsigned long long dropped_events() const
Total inbound events dropped due to ring overflow (backpressure).
void stop()
Stop the agent and shut down the ring so a blocked poll_events returns an empty batch (i....
int release()
Send a ReleaseMessage (session keeps running until stop).
int send_message_ack(uint32_t request_id, int response_code)
Acknowledge a request.
int start()
Start the agent, re-arming the inbound ring so a stop()->start() cycle works again.
int wait_for_setup(int timeout_ms)
Block until the setup handshake completes.
int64_t send_report(uint32_t ran_function_id, std::vector< uint8_t > report_data, uint32_t sequence_id)
Send a dApp report to the RAN.
long dapp_id() const
dApp id assigned at setup, or -1 if not yet assigned.
int64_t subscribe(uint32_t ran_function_id, std::vector< uint32_t > telemetry_ids, std::vector< uint32_t > control_ids, int sub_time_ms, int periodicity)
Subscribe to a RAN function (after a positive setup).
std::size_t setup_ran_function_count() const
Number of RAN functions advertised in the SetupResponse.
DAppSession(libe3::E3Config config, std::size_t queue_capacity=8192)
Construct the session and register all inbound handlers.
std::vector< uint32_t > setup_ran_function_control(std::size_t i) const
Control ids of advertised entry i.
int64_t send_control(uint32_t ran_function_id, uint32_t control_id, std::vector< uint8_t > action_data, uint32_t sequence_id=0)
Send a dApp control action to the RAN.
E3Agent - Main façade class for RAN vendors.
Python-facing dApp session over libe3 — batched, low-latency seam.
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_tnow(void)
static uint64_t latrec_seq_next(void)
static void latrec_tstamp_at(uint64_t seq, uint8_t stage, uint64_t aux, uint64_t aux2, uint64_t t_ns)
static latrec_t * latrec_tls_open_as(const char *role)
@ LATREC_DROP_SESSION_QUEUE
Lock-free bounded blocking queue for the E3AP hot paths.
@ E3_EVENT_SUBSCRIPTION_RESPONSE
RAN → dApp SubscriptionResponse.
@ E3_EVENT_SETUP_RESPONSE
RAN → dApp SetupResponse.
@ E3_EVENT_INDICATION
RAN → dApp IndicationMessage.
@ E3_EVENT_XAPP_CONTROL
xApp → dApp XAppControlAction
@ E3_EVENT_MESSAGE_ACK
RAN → dApp MessageAck.
ErrorCode
Error codes returned by libe3 operations Use shared error-code list (see libe3/error_codes....
@ DAPP
dApp (connects to a RAN agent)
ResponseCode
E3AP response codes.
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.
E3AP Setup Response structure.
E3AP Subscription Response structure.
std::optional< uint32_t > subscription_id
Subscription ID (optional).
uint32_t request_id
ID of the corresponding SubscriptionRequest.
uint32_t dapp_identifier
dApp identifier
ResponseCode response_code
Response code (positive/negative).
E3AP xApp Control Action structure.
std::vector< uint8_t > xapp_control_data
uint32_t ran_function_identifier
libe3::SetupResponse setup
std::atomic< unsigned long long > dropped
std::unique_ptr< libe3::E3Agent > agent
Impl(libe3::E3Config config, std::size_t queue_capacity)
libe3::LockFreeQueue< E3Event > queue
One inbound E3AP event, POD-flat for a clean SWIG crossing.
uint32_t ran_function_id
RAN function (indication / xApp control).
uint32_t sequence_id
loop correlation id (xApp control); echo it on the control you re-issue
int kind
one of E3EventKind
uint32_t dapp_id
dApp identifier the message targets
uint32_t request_id
request/message id (subscription response / ack / xApp control)
uint32_t subscription_id
subscription id (subscription response)
int response_code
0=positive, 1=negative, -1=n/a
uint64_t trace_seq
set when queued; keys the [latrec] LQ-stage records
std::vector< uint8_t > payload
opaque E3SM bytes (indication / xApp control)