1#[repr(C)]
2#[derive(Debug, Clone, Copy)]
3pub struct RnsEmbeddedV1NodeError {
4 pub struct_size: usize,
5 pub struct_version: u32,
6 pub code: RnsEmbeddedV1NodeErrorCode,
7 pub reserved: [u8; 16],
8}
9
10impl Default for RnsEmbeddedV1NodeError {
11 fn default() -> Self {
12 Self {
13 struct_size: core::mem::size_of::<Self>(),
14 struct_version: RNS_EMBEDDED_V1_STRUCT_VERSION,
15 code: RnsEmbeddedV1NodeErrorCode::Unknown,
16 reserved: [0; 16],
17 }
18 }
19}
20
21#[repr(C)]
22pub struct RnsEmbeddedV1NodeConfig {
23 pub struct_size: usize,
24 pub struct_version: u32,
25 pub store_identity: [u8; 32],
26 pub lxmf_address: [u8; 16],
27 pub node_mode: RnsEmbeddedNodeMode,
28 pub announce_interval_ms: u64,
29 pub max_outbound_queue: usize,
30 pub max_events: usize,
31 pub capture_default_max_bytes: u32,
32 pub ble_mtu_hint: u16,
33 pub ble_max_inbound_frames: usize,
34 pub ble_max_outbound_frames: usize,
35 pub ble_ordered_delivery: bool,
36 pub tcp_host: [u8; 256],
37 pub tcp_port: u16,
38 pub tcp_listen_port: u16,
39 pub reserved: [u8; 28],
40}
41
42impl Default for RnsEmbeddedV1NodeConfig {
43 fn default() -> Self {
44 let legacy = RnsEmbeddedNodeConfig::default();
45 Self {
46 struct_size: core::mem::size_of::<Self>(),
47 struct_version: RNS_EMBEDDED_V1_STRUCT_VERSION,
48 store_identity: legacy.store_identity,
49 lxmf_address: legacy.lxmf_address,
50 node_mode: legacy.node_mode,
51 announce_interval_ms: legacy.announce_interval_ms,
52 max_outbound_queue: legacy.max_outbound_queue,
53 max_events: legacy.max_events,
54 capture_default_max_bytes: legacy.capture_default_max_bytes,
55 ble_mtu_hint: legacy.ble_mtu_hint,
56 ble_max_inbound_frames: legacy.ble_max_inbound_frames,
57 ble_max_outbound_frames: legacy.ble_max_outbound_frames,
58 ble_ordered_delivery: legacy.ble_ordered_delivery,
59 tcp_host: legacy.tcp_host,
60 tcp_port: legacy.tcp_port,
61 tcp_listen_port: legacy.tcp_listen_port,
62 reserved: [0; 28],
63 }
64 }
65}
66
67#[repr(C)]
68#[derive(Debug, Clone, Copy)]
69pub struct RnsEmbeddedV1NodeStatus {
70 pub struct_size: usize,
71 pub struct_version: u32,
72 pub run_state: RnsEmbeddedV1RunState,
73 pub epoch: u64,
74 pub lifecycle_state: RnsEmbeddedLifecycleState,
75 pub pending_outbound: usize,
76 pub announces_queued: u32,
77 pub outbound_sent: u32,
78 pub outbound_deferred: u32,
79 pub inbound_accepted: u32,
80 pub inbound_rejected: u32,
81 pub announces_received: u32,
82 pub lxmf_messages_received: u32,
83 pub log_level: RnsEmbeddedV1LogLevel,
84 pub reserved: [u8; 24],
85}
86
87impl Default for RnsEmbeddedV1NodeStatus {
88 fn default() -> Self {
89 Self {
90 struct_size: core::mem::size_of::<Self>(),
91 struct_version: RNS_EMBEDDED_V1_STRUCT_VERSION,
92 run_state: RnsEmbeddedV1RunState::Stopped,
93 epoch: 0,
94 lifecycle_state: RnsEmbeddedLifecycleState::Boot,
95 pending_outbound: 0,
96 announces_queued: 0,
97 outbound_sent: 0,
98 outbound_deferred: 0,
99 inbound_accepted: 0,
100 inbound_rejected: 0,
101 announces_received: 0,
102 lxmf_messages_received: 0,
103 log_level: RnsEmbeddedV1LogLevel::Info,
104 reserved: [0; 24],
105 }
106 }
107}
108
109#[repr(C)]
110#[derive(Debug, Clone, Copy)]
111pub struct RnsEmbeddedV1SendReceipt {
112 pub struct_size: usize,
113 pub struct_version: u32,
114 pub operation_id: u64,
115 pub epoch: u64,
116 pub accepted_bytes: usize,
117 pub queued: bool,
118 pub target_count: u32,
119 pub reserved: [u8; 24],
120}
121
122impl Default for RnsEmbeddedV1SendReceipt {
123 fn default() -> Self {
124 Self {
125 struct_size: core::mem::size_of::<Self>(),
126 struct_version: RNS_EMBEDDED_V1_STRUCT_VERSION,
127 operation_id: 0,
128 epoch: 0,
129 accepted_bytes: 0,
130 queued: false,
131 target_count: 0,
132 reserved: [0; 24],
133 }
134 }
135}
136
137#[repr(C)]
138#[derive(Debug, Clone, Copy)]
139pub struct RnsEmbeddedV1Capabilities {
140 pub struct_size: usize,
141 pub struct_version: u32,
142 pub abi_version: u32,
143 pub capability_schema_version: u32,
144 pub known_capability_bits: u64,
145 pub compile_time_capability_bits: u64,
146 pub capability_bits: u64,
147 pub max_event_payload_bytes: u32,
148 pub max_subscriptions: u32,
149 pub max_blocking_timeout_ms: u64,
150 pub driver_tick_target_ms: u32,
151 pub driver_tick_max_ms: u32,
152 pub reserved: [u8; 24],
153}
154
155impl Default for RnsEmbeddedV1Capabilities {
156 fn default() -> Self {
157 let mut compile_time_capability_bits =
158 RNS_EMBEDDED_V1_CAP_BROADCAST_EXPLICIT_LIST | RNS_EMBEDDED_V1_CAP_COMPAT_LEGACY_FFI;
159 if cfg!(feature = "std") {
160 compile_time_capability_bits |=
161 RNS_EMBEDDED_V1_CAP_MANAGED_RUNTIME | RNS_EMBEDDED_V1_CAP_BLOCKING_NEXT;
162 }
163 if cfg!(feature = "std") || cfg!(feature = "alloc") {
164 compile_time_capability_bits |= RNS_EMBEDDED_V1_CAP_EVENT_GAP_SIGNALING;
165 }
166 Self {
167 struct_size: core::mem::size_of::<Self>(),
168 struct_version: RNS_EMBEDDED_V1_STRUCT_VERSION,
169 abi_version: RNS_EMBEDDED_V1_ABI_VERSION,
170 capability_schema_version: RNS_EMBEDDED_V1_CAPABILITY_SCHEMA_VERSION,
171 known_capability_bits: RNS_EMBEDDED_V1_KNOWN_CAPABILITY_BITS,
172 compile_time_capability_bits,
173 capability_bits: compile_time_capability_bits,
174 max_event_payload_bytes: 0,
175 max_subscriptions: 1024,
176 max_blocking_timeout_ms: if cfg!(feature = "std") {
177 RNS_EMBEDDED_V1_MAX_BLOCKING_TIMEOUT_MS
178 } else {
179 0
180 },
181 driver_tick_target_ms: if cfg!(feature = "std") {
182 RNS_EMBEDDED_V1_DRIVER_TICK_TARGET_MS
183 } else {
184 0
185 },
186 driver_tick_max_ms: if cfg!(feature = "std") {
187 RNS_EMBEDDED_V1_DRIVER_TICK_MAX_MS
188 } else {
189 0
190 },
191 reserved: [0; 24],
192 }
193 }
194}
195
196#[repr(C)]
197#[derive(Debug, Clone, Copy)]
198pub struct RnsEmbeddedV1NodeEvent {
199 pub struct_size: usize,
200 pub struct_version: u32,
201 pub kind: RnsEmbeddedV1EventKind,
202 pub event_id: u64,
203 pub epoch: u64,
204 pub occurred_at_ms: u64,
205 pub operation_id: u64,
206 pub has_operation_id: bool,
207 pub run_state: RnsEmbeddedV1RunState,
208 pub lifecycle_state: RnsEmbeddedLifecycleState,
209 pub log_level: RnsEmbeddedV1LogLevel,
210 pub error_code: RnsEmbeddedV1NodeErrorCode,
211 pub frame_kind: u8,
212 pub sequence: u32,
213 pub bytes: usize,
214 pub extension_id: u32,
215 pub value0: u64,
216 pub value1: u64,
217 pub reserved: [u8; 24],
218}
219
220impl Default for RnsEmbeddedV1NodeEvent {
221 fn default() -> Self {
222 Self {
223 struct_size: core::mem::size_of::<Self>(),
224 struct_version: RNS_EMBEDDED_V1_STRUCT_VERSION,
225 kind: RnsEmbeddedV1EventKind::StatusChanged,
226 event_id: 0,
227 epoch: 0,
228 occurred_at_ms: 0,
229 operation_id: 0,
230 has_operation_id: false,
231 run_state: RnsEmbeddedV1RunState::Stopped,
232 lifecycle_state: RnsEmbeddedLifecycleState::Boot,
233 log_level: RnsEmbeddedV1LogLevel::Info,
234 error_code: RnsEmbeddedV1NodeErrorCode::Unknown,
235 frame_kind: 0,
236 sequence: 0,
237 bytes: 0,
238 extension_id: 0,
239 value0: 0,
240 value1: 0,
241 reserved: [0; 24],
242 }
243 }
244}
245
246#[repr(C)]
247#[derive(Debug, Clone, Copy)]
248pub struct RnsEmbeddedV1PollResult {
249 pub struct_size: usize,
250 pub struct_version: u32,
251 pub kind: RnsEmbeddedV1PollResultKind,
252 pub next_event_id: u64,
253 pub epoch: u64,
254 pub reserved: [u8; 24],
255}
256
257impl Default for RnsEmbeddedV1PollResult {
258 fn default() -> Self {
259 Self {
260 struct_size: core::mem::size_of::<Self>(),
261 struct_version: RNS_EMBEDDED_V1_STRUCT_VERSION,
262 kind: RnsEmbeddedV1PollResultKind::Timeout,
263 next_event_id: 0,
264 epoch: 0,
265 reserved: [0; 24],
266 }
267 }
268}
269
270pub struct RnsEmbeddedNode {
271 runtime: EmbeddedNodeRuntime,
272 store: JournaledEmbeddedStore,
273 transport: BleShimTransport,
274}
275
276pub struct RnsEmbeddedV1Node {
277 node: EmbeddedNode,
278}
279
280pub struct RnsEmbeddedEventSubscription {
281 subscription: EventSubscription,
282}
283
284#[cfg(not(feature = "std"))]
285fn ensure_allocator_ready() {
286 unsafe {
289 if !RNS_ALLOCATOR_READY {
290 RNS_ALLOCATOR.init(RNS_ALLOCATOR_HEAP.as_mut_ptr() as usize, RNS_ALLOCATOR_HEAP.len());
291 RNS_ALLOCATOR_READY = true;
292 }
293 }
294}
295
296#[cfg(feature = "std")]
297fn ensure_allocator_ready() {}
298
299#[no_mangle]
300pub extern "C" fn rns_embedded_node_config_default() -> RnsEmbeddedNodeConfig {
301 RnsEmbeddedNodeConfig::default()
302}
303
304#[no_mangle]
305pub extern "C" fn rns_embedded_v1_node_config_default() -> RnsEmbeddedV1NodeConfig {
306 RnsEmbeddedV1NodeConfig::default()
307}
308
309#[no_mangle]
310pub extern "C" fn rns_embedded_v1_abi_version() -> u32 {
311 RNS_EMBEDDED_V1_ABI_VERSION
312}
313
314#[no_mangle]
315pub extern "C" fn rns_embedded_v1_get_capabilities(
316 out_capabilities: *mut RnsEmbeddedV1Capabilities,
317) -> RnsEmbeddedStatus {
318 ffi_status_boundary(|| {
319 if out_capabilities.is_null() {
320 return RnsEmbeddedStatus::InvalidArgument;
321 }
322 unsafe {
325 *out_capabilities = RnsEmbeddedV1Capabilities::default();
326 }
327 RnsEmbeddedStatus::Ok
328 })
329}
330
331#[no_mangle]
332pub extern "C" fn rns_embedded_v1_node_new() -> *mut RnsEmbeddedV1Node {
333 ffi_ptr_boundary(|| {
334 ensure_allocator_ready();
335 Box::into_raw(Box::new(RnsEmbeddedV1Node { node: EmbeddedNode::new() }))
336 })
337}
338
339#[no_mangle]
340pub extern "C" fn rns_embedded_v1_node_free(node: *mut RnsEmbeddedV1Node) {
341 if node.is_null() {
342 return;
343 }
344 unsafe {
347 drop(Box::from_raw(node));
348 }
349}
350
351#[no_mangle]
352pub extern "C" fn rns_embedded_node_new(
353 config: *const RnsEmbeddedNodeConfig,
354) -> *mut RnsEmbeddedNode {
355 ensure_allocator_ready();
356 if config.is_null() {
357 return core::ptr::null_mut();
358 }
359 let config = unsafe { &*config };
362 let runtime = match EmbeddedNodeRuntime::new(RuntimeConfig {
363 store_identity: config.store_identity,
364 lxmf_address: config.lxmf_address,
365 node_mode: match config.node_mode {
366 RnsEmbeddedNodeMode::BleOnly => NodeTransportMode::BleOnly,
367 RnsEmbeddedNodeMode::TcpClient => NodeTransportMode::TcpClient,
368 RnsEmbeddedNodeMode::TcpServer => NodeTransportMode::TcpServer,
369 },
370 announce_interval_ms: config.announce_interval_ms,
371 max_outbound_queue: config.max_outbound_queue,
372 max_events: config.max_events,
373 capture_defaults: CaptureDefaults { max_bytes: config.capture_default_max_bytes },
374 }) {
375 Ok(runtime) => runtime,
376 Err(_) => return core::ptr::null_mut(),
377 };
378 let transport = match BleShimTransport::new(BleShimConfig {
379 mtu_hint: config.ble_mtu_hint,
380 max_inbound_frames: config.ble_max_inbound_frames,
381 max_outbound_frames: config.ble_max_outbound_frames,
382 ordered_delivery: config.ble_ordered_delivery,
383 }) {
384 Ok(transport) => transport,
385 Err(_) => return core::ptr::null_mut(),
386 };
387
388 let node = RnsEmbeddedNode { runtime, store: JournaledEmbeddedStore::new(), transport };
389 Box::into_raw(Box::new(node))
390}
391
392#[no_mangle]
393pub extern "C" fn rns_embedded_node_free(node: *mut RnsEmbeddedNode) {
394 if node.is_null() {
395 return;
396 }
397 unsafe {
400 drop(Box::from_raw(node));
401 }
402}
403
404#[no_mangle]
405pub extern "C" fn rns_embedded_node_set_link_state(
406 node: *mut RnsEmbeddedNode,
407 state: RnsEmbeddedLinkState,
408) -> RnsEmbeddedStatus {
409 let Some(node) = node_mut(node) else {
410 return RnsEmbeddedStatus::InvalidArgument;
411 };
412 node.transport.set_link_state(match state {
413 RnsEmbeddedLinkState::Down => LinkState::Down,
414 RnsEmbeddedLinkState::Connecting => LinkState::Connecting,
415 RnsEmbeddedLinkState::Up => LinkState::Up,
416 });
417 RnsEmbeddedStatus::Ok
418}
419
420#[no_mangle]
421pub extern "C" fn rns_embedded_node_tick(
422 node: *mut RnsEmbeddedNode,
423 now_ms: u64,
424) -> RnsEmbeddedStatus {
425 let Some(node) = node_mut(node) else {
426 return RnsEmbeddedStatus::InvalidArgument;
427 };
428 map_status(node.runtime.tick(now_ms, &mut node.transport, &mut node.store))
429}
430
431#[no_mangle]
432pub extern "C" fn rns_embedded_node_set_network_provisioned(
433 node: *mut RnsEmbeddedNode,
434 provisioned: bool,
435) -> RnsEmbeddedStatus {
436 let Some(node) = node_mut(node) else {
437 return RnsEmbeddedStatus::InvalidArgument;
438 };
439 node.runtime.set_network_provisioned(provisioned);
440 RnsEmbeddedStatus::Ok
441}
442
443#[no_mangle]
444pub extern "C" fn rns_embedded_node_set_ble_recovery_active(
445 node: *mut RnsEmbeddedNode,
446 active: bool,
447) -> RnsEmbeddedStatus {
448 let Some(node) = node_mut(node) else {
449 return RnsEmbeddedStatus::InvalidArgument;
450 };
451 node.runtime.set_ble_recovery_active(active);
452 RnsEmbeddedStatus::Ok
453}