Skip to main content

nros_platform_cffi/
generated.rs

1//! AUTO-GENERATED by scripts/gen-abi-bindings.sh (bindgen 0.72.1) — DO NOT EDIT.
2//!
3//! Source of truth: `packages/platform/nros-platform-api/include/nros/platform*.h` (RFC-0054).
4//! Edit the headers, rerun the script, commit both.
5#![allow(non_camel_case_types, non_snake_case, non_upper_case_globals)]
6#![allow(unsafe_op_in_unsafe_fn, clippy::missing_safety_doc)]
7/* automatically generated by rust-bindgen 0.72.1 */
8
9pub type nros_platform_ret_t = i8;
10pub type nros_platform_log_writer_fn_t = ::core::option::Option<
11    unsafe extern "C" fn(
12        severity: u8,
13        name_ptr: *const u8,
14        name_len: usize,
15        msg_ptr: *const u8,
16        msg_len: usize,
17    ),
18>;
19pub type nros_platform_log_flush_fn_t = ::core::option::Option<unsafe extern "C" fn()>;
20#[doc = " @file platform_timer.h\n @brief Canonical C ABI for the nros platform timer surface.\n\n Companion to `<nros/platform.h>`; sits beside the core 39-symbol\n ABI as the Phase 110.E platform-timer interface. Carved into a\n separate header because bare-metal / single-shot consumers can\n omit timer support without losing the canonical platform symbols.\n\n # Handle model\n\n  Platform timer handles are opaque `void *`. The implementation\n  allocates whatever it needs to track the underlying primitive\n  (`TimerHandle_t` on FreeRTOS, `TX_TIMER *` on ThreadX, `timer_t`\n  on POSIX, `*mut k_timer` on Zephyr); the runtime never inspects\n  the bytes pointed at.\n\n # Return-value conventions\n\n  - `create_periodic` / `create_oneshot` return non-NULL on success\n    and `NULL` on failure (analogous to libc `malloc`).\n  - `cancel` returns 1 when the cancellation prevented the callback\n    from firing, 0 if the callback already fired (or the timer was\n    already cancelled or destroyed), -1 on unrecoverable error.\n  - `destroy` is best-effort; idempotent on already-destroyed handles.\n\n # Threading / context\n\n  Callbacks are invoked from a platform-defined timer context — a\n  direct ISR on Zephyr / bare-metal, deferred to the FreeRTOS timer\n  task on FreeRTOS, a real-time signal on POSIX. Callback bodies\n  must be short, must not call back into nros_platform_* heap or\n  blocking primitives, and must use atomic operations for shared\n  state. `user_data` must outlive the timer handle."]
21pub type nros_platform_timer_callback_t =
22    ::core::option::Option<unsafe extern "C" fn(user_data: *mut core::ffi::c_void)>;
23#[repr(C)]
24#[derive(Debug, Copy, Clone)]
25pub struct nros_platform_task_attr_t {
26    #[doc = " Task name for the kernel's own tables and crash dumps. `NULL` = the\n  port's default. Ports whose kernel has no name concept ignore it."]
27    pub name: *const core::ffi::c_char,
28    #[doc = " Minimum stack size in BYTES. `0` = the port's default.\n\n  A FLOOR, not an exact size (issue 0612). Every port has a minimum of its\n  own — `PTHREAD_STACK_MIN`, `configMINIMAL_STACK_SIZE`, `TX_MINIMUM_STACK`\n  — and those differ by an order of magnitude, and on POSIX differ by\n  ARCHITECTURE (16384 on glibc/x86_64, 131072 on glibc/aarch64). So no\n  portable caller can name a number that is legal everywhere, and a port\n  that treats a small request as an error turns a reasonable ask into a\n  dead capability: that is exactly how `Executor::signal_fd()` returned\n  `NotInitialized` on every Linux host. A port raises this to its own\n  minimum; it never lowers it, and never refuses for being too small.\n\n  Always bytes, never words: FreeRTOS's `xTaskCreate` takes words, and the\n  private struct it replaced called the field `stack_depth` while ThreadX's\n  identically-named field was bytes. The conversion belongs in the one port\n  that needs it, not in every caller."]
29    pub stack_bytes: usize,
30    #[doc = " Caller-provided stack memory, or `NULL` to let the port obtain it.\n\n  ThreadX requires the stack from its caller; POSIX, FreeRTOS and ESP-IDF\n  let the kernel allocate and ignore this. A port that needs memory and is\n  given `NULL` obtains it itself and releases it in `task_free`."]
31    pub stack_mem: *mut core::ffi::c_void,
32    #[doc = " Scheduling priority in the NORMALISED band: `0` = least urgent, larger\n  = more urgent, `NROS_PLATFORM_PRIORITY_INHERIT` = keep the creating\n  task's.\n\n  phase-364 W5. This was \"platform-native\", and the natives disagree: `0`\n  is the HIGHEST priority on ThreadX and the LOWEST on FreeRTOS, while\n  Zephyr runs lower-is-more-urgent with negatives reserved for cooperative\n  threads. A tier priority is authored ONCE, in `system.toml`, and\n  deployed to several of them — so the same number meant \"run me first\" on\n  one board and \"run me last\" on another, with nothing in the ABI\n  recording which convention a port used.\n\n  Each port maps this band onto its own range and documents the map at its\n  `task_init`. Use `NROS_PLATFORM_PRIORITY_RAW(n)` to bypass the band when\n  tuning one RTOS against its own documentation — that is a legitimate\n  thing to do, and the band should not make it impossible."]
33    pub priority: i32,
34    #[doc = " SMP core to pin to, or `-1` for unpinned. Ignored on single-core."]
35    pub core: i8,
36    #[doc = " `NROS_PLATFORM_TASK_*` flags below."]
37    pub flags: u8,
38}
39pub const NROS_PLATFORM_RET_OK: i32 = 0;
40pub const NROS_PLATFORM_RET_ERROR: i32 = -1;
41pub const NROS_PLATFORM_RET_UNSUPPORTED: i32 = -5;
42pub const NROS_PLATFORM_RET_NOMEM: i32 = -6;
43pub const NROS_PLATFORM_RET_INVALID: i32 = -7;
44pub const NROS_PLATFORM_RET_TIMEOUT: i32 = -8;
45pub const NROS_PLATFORM_TASK_DETACHED: i32 = 1;
46pub const NROS_PLATFORM_PRIORITY_MIN: i32 = 0;
47pub const NROS_PLATFORM_PRIORITY_MAX: i32 = 255;
48pub const NROS_PLATFORM_PRIORITY_INHERIT: i32 = -2147483648;
49pub const NROS_PLATFORM_TASK_STORAGE_SIZE: i32 = 512;
50pub const NROS_PLATFORM_MUTEX_STORAGE_SIZE: i32 = 256;
51pub const NROS_PLATFORM_MUTEX_REC_STORAGE_SIZE: i32 = 256;
52pub const NROS_PLATFORM_CONDVAR_STORAGE_SIZE: i32 = 256;
53pub const NROS_PLATFORM_STORAGE_ALIGN: i32 = 8;
54pub const NROS_PLATFORM_PARK_SIGNALLED: i32 = 0;
55pub const NROS_PLATFORM_PARK_EXPIRED: i32 = 1;
56pub const NROS_PLATFORM_PARK_YIELDED: i32 = 2;
57unsafe extern "C" {
58    #[doc = " Monotonic nanoseconds since a platform-defined epoch (boot, program\n  start, …). Never decreases. Wraps after ~584 years.\n\n  Must be backed by a hardware counter or the OS tick — never by a\n  software counter that only advances when polled.\n\n  Available immediately after platform init, before any other nros\n  subsystem. SHOULD be callable from an ISR; a port whose clock is not\n  ISR-safe must say so in its port documentation.\n\n  RFC-0073: this replaced the former `clock_ms` / `clock_us` pair. Ports\n  that can convert without a runtime division should — where the counter\n  frequency divides 1e9 (25/50/100/125/200/250 MHz) a compile-time\n  ns-per-cycle multiply is ~2.5x cheaper than the divide it replaces."]
59    pub fn nros_platform_clock_ns() -> u64;
60}
61unsafe extern "C" {
62    #[doc = " Granularity of `nros_platform_clock_ns`, in nanoseconds: the smallest\n  non-zero difference two successive reads can report.\n\n  Examples: 1000000 for a 1 kHz tick, 40 for a 25 MHz cycle counter,\n  1000 for a microsecond hardware timer.\n\n  Must be non-zero, and constant for the lifetime of the program after\n  platform init. A port whose underlying rate is only known at runtime\n  returns the resolved value; one whose rate can change under it returns\n  the COARSEST value it may exhibit. There is no \"unknown\" encoding — a\n  port that cannot answer honestly is reporting a clock it cannot\n  honestly offer."]
63    pub fn nros_platform_clock_resolution_ns() -> u64;
64}
65unsafe extern "C" {
66    #[doc = " Microseconds since the UNIX EPOCH (1970-01-01T00:00:00Z), or `0` when\n  this platform has no wall-clock source.\n\n  READ THIS BEFORE REACHING FOR `nros_platform_clock_ns` (issue 0758).\n  The two clocks in this header differ by one word in their names and by\n  the only property that matters for interop:\n\n    - `nros_platform_clock_ns` is MONOTONIC and boot-relative. Use it for\n      durations, deadlines, spin gaps, timeouts — anything comparing two\n      readings from THIS image. It is meaningless to a peer.\n    - `nros_platform_epoch_us` is ABSOLUTE. Use it for message stamps and\n      anything a peer will compare against its own clock.\n\n  Reaching for the wrong one does not fail to build and does not fail\n  locally; it fails at a peer, which is the expensive place to find out.\n  The concrete case is the consumer this exists for: an embedded island\n  stamped control commands from its boot epoch and Autoware's\n  `vehicle_cmd_gate` rejected every one as stale, so autonomous mode could\n  never actuate.\n\n  `0` MEANS \"NO WALL CLOCK\", not \"the epoch\". Per this header's clock rule\n  (see the top of file: \"If the platform has no clock, return `0`\") this\n  never errors. A caller that gets `0` knows the image cannot stamp\n  absolute time and should keep publishing boot-relative stamps knowingly,\n  rather than publishing a confidently wrong absolute one. 1970 is not a\n  plausible reading, so the sentinel costs no real value.\n\n  Not required to be monotonic: a platform that acquires its epoch after\n  boot (SNTP, RTC handoff) will JUMP when it does, and may jump backwards.\n  Callers needing monotonicity use `nros_platform_clock_ns`.\n\n  Need not be ISR-safe, and unlike `nros_platform_clock_ns` need not be\n  available immediately after platform init — a port that acquires its\n  epoch over the network necessarily answers `0` until it has."]
67    pub fn nros_platform_epoch_us() -> u64;
68}
69unsafe extern "C" {
70    #[doc = " Allocate `size` bytes; return `NULL` on failure. May be called from\n  any thread."]
71    pub fn nros_platform_alloc(size: usize) -> *mut core::ffi::c_void;
72}
73unsafe extern "C" {
74    #[doc = " Resize the block at `ptr` to `size` bytes. Equivalent to libc\n  `realloc`: `NULL` ptr → fresh alloc; `0` size → free + return `NULL`.\n  Preserves contents up to `min(old, new)`."]
75    pub fn nros_platform_realloc(
76        ptr: *mut core::ffi::c_void,
77        size: usize,
78    ) -> *mut core::ffi::c_void;
79}
80unsafe extern "C" {
81    #[doc = " Free a previously allocated block. `NULL` is a no-op."]
82    pub fn nros_platform_dealloc(ptr: *mut core::ffi::c_void);
83}
84unsafe extern "C" {
85    #[doc = " Bytes currently allocated from the platform heap, or `0` if the port\n  does not instrument it. Phase 230 / RFC-0034 D7: the true unified figure\n  where the platform owns one kernel heap shared by the C side and the\n  Rust `#[global_allocator]`."]
86    pub fn nros_platform_heap_used_bytes() -> usize;
87}
88unsafe extern "C" {
89    #[doc = " Smallest number of bytes ever left unused on the CALLING task's stack, or\n  `0` if this port cannot report it.\n\n  HEADROOM, not usage, because that is what both kernels natively track and\n  it is the number a safety argument needs: how close the worst observed\n  excursion came to the end of the stack.\n\n  The heap has had `nros_platform_heap_used_bytes` since RFC-0034 D7; the\n  stack had nothing, and stack overflow is the classic way one component\n  corrupts another's state. ISO 26262 treats spatial freedom from\n  interference as a first-class requirement and AUTOSAR pairs memory\n  protection with stack monitoring for exactly this reason. Without a\n  portable probe the only recourse is a per-RTOS one: this repo's Zephyr\n  lane greps `thread_analyzer` printk output in CI, which is a text scrape\n  of a debug facility standing in for a platform capability, and reports\n  nothing on any other port.\n\n  SELF only, deliberately. Both kernels answer for the calling task with no\n  handle (`uxTaskGetStackHighWaterMark(NULL)`, `k_thread_stack_space_get`\n  with `k_current_get()`), whereas answering for an arbitrary task needs a\n  native handle this ABI does not carry -- on Zephyr the task storage is a\n  `pthread_t` and the mapping to `k_thread *` is not public. A task\n  reporting its own headroom is also the shape the callers want: each tier\n  says how much of its own stack it has ever needed.\n\n  `0` means \"this port does not instrument it\", matching\n  `nros_platform_heap_used_bytes`. It is not a claim that the stack is\n  full."]
90    pub fn nros_platform_task_stack_unused_bytes() -> usize;
91}
92unsafe extern "C" {
93    #[doc = " The same query, capped: `min(unused, limit)`, reading at most `limit`\n  bytes of the stack (phase-436 E5).\n\n  The executor's `stack-headroom-runtime` rule asks one question, \"are at\n  least `limit` bytes unused?\", and on a painted stack that is true exactly\n  when the `limit` bytes at the stack's deep end still hold the paint. So a\n  port that SCANS (Zephyr walks from `stack_info.start`) answers it by\n  reading those bytes only, never the whole unused region: on the Autoware\n  safety island's FVP image the full scan was a 32.6 ms stall once a second.\n  Below `limit` the scan stops at the first used byte, so the answer is the\n  exact headroom and a breach needs no second, full scan.\n\n  A port with a cheaper or no measurement answers\n  `min(nros_platform_task_stack_unused_bytes(), limit)`. `0` keeps the\n  meaning above: not instrumented."]
94    pub fn nros_platform_task_stack_unused_bytes_upto(limit: usize) -> usize;
95}
96unsafe extern "C" {
97    #[doc = " Total managed heap size in bytes (used + free), or `0` if unknown."]
98    pub fn nros_platform_heap_total_bytes() -> usize;
99}
100unsafe extern "C" {
101    #[doc = " Sleep at least `us` microseconds. Spin if the platform clock has no\n  sub-millisecond timer."]
102    pub fn nros_platform_sleep_us(us: usize);
103}
104unsafe extern "C" {
105    #[doc = " Sleep at least `ms` milliseconds."]
106    pub fn nros_platform_sleep_ms(ms: usize);
107}
108unsafe extern "C" {
109    #[doc = " Sleep at least `s` seconds."]
110    pub fn nros_platform_sleep_s(s: usize);
111}
112unsafe extern "C" {
113    #[doc = " Voluntarily yield the current task / thread. On bare-metal,\n  `core::hint::spin_loop()` is acceptable; on RTOSes use the native\n  cooperative-yield primitive (`k_yield`, `vPortYield`,\n  `tx_thread_relinquish`, `sched_yield`, …). RTOS yields are **not**\n  ISR-safe."]
114    pub fn nros_platform_yield_now();
115}
116unsafe extern "C" {
117    #[doc = " Random `u8`. Cryptographically random where the platform has an\n  entropy source; otherwise a seeded PRNG. Must be deterministic\n  within a single test session for reproducibility."]
118    pub fn nros_platform_random_u8() -> u8;
119}
120unsafe extern "C" {
121    #[doc = " Random `u16`. See `random_u8` notes."]
122    pub fn nros_platform_random_u16() -> u16;
123}
124unsafe extern "C" {
125    #[doc = " Random `u32`. See `random_u8` notes."]
126    pub fn nros_platform_random_u32() -> u32;
127}
128unsafe extern "C" {
129    #[doc = " Random `u64`. See `random_u8` notes."]
130    pub fn nros_platform_random_u64() -> u64;
131}
132unsafe extern "C" {
133    #[doc = " Fill `len` bytes at `buf` with random data."]
134    pub fn nros_platform_random_fill(buf: *mut core::ffi::c_void, len: usize);
135}
136unsafe extern "C" {
137    #[doc = " Wall-clock nanoseconds since the Unix epoch, or `0` if the platform has\n  no real-time clock.\n\n  ONE symbol for one fact, mirroring what RFC-0073 / phase-352 did for the\n  monotonic clock. It replaced `time_now_ms` + `time_since_epoch_secs` +\n  `time_since_epoch_nanos` (issue 0532 item 5).\n\n  Why the split had to go, beyond tidiness: the ABI spent ONE INSTANT over\n  two symbols, and each call sampled the clock separately (the POSIX port\n  issued its own `clock_gettime` in each). A second boundary landing between\n  the two reads paired the OLD second with the NEW sub-second remainder — a\n  timestamp that jumped a full second BACKWARDS, rarely and silently. Both\n  `nros-core` and `nros-node` carried a bounded re-read loop to paper over\n  it; a single read cannot tear, so those loops are gone.\n\n  `u64` ns spans ~584 years from 1970, so it also retires the `uint32_t`\n  seconds field, which overflowed in 2106.\n\n  Ports convert from whatever they have — a port with only seconds returns\n  `secs * 1000000000ULL`, and one with no RTC returns 0. Callers wanting\n  milliseconds divide by 1000000; wanting a `(secs, nanos)` pair, divide and\n  remainder by 1000000000."]
138    pub fn nros_platform_time_now_ns() -> u64;
139}
140unsafe extern "C" {
141    #[doc = " Fill `attr` with the defaults — equivalent to passing `NULL` to\n  `task_init`.\n\n  Callers use this rather than a designated initialiser so that a field added\n  to the struct later stays source-compatible for out-of-tree ports."]
142    pub fn nros_platform_task_attr_init(attr: *mut nros_platform_task_attr_t);
143}
144unsafe extern "C" {
145    #[doc = " Spawn a new task. `task` is opaque caller-provided storage (size from\n  `nros_platform_task_storage_size`); `attr` is a\n  `nros_platform_task_attr_t *`, or `NULL` for every default; `entry` is the\n  task entry point; `arg` is forwarded to `entry`.\n\n  Returns `NROS_PLATFORM_RET_OK`, or `INVALID` (a NULL where storage or an\n  entry is required), `NOMEM` (resources exhausted now — retry may succeed) or\n  `UNSUPPORTED` (this port has no tasks at all)."]
146    pub fn nros_platform_task_init(
147        task: *mut core::ffi::c_void,
148        attr: *mut core::ffi::c_void,
149        entry: ::core::option::Option<
150            unsafe extern "C" fn(arg1: *mut core::ffi::c_void) -> *mut core::ffi::c_void,
151        >,
152        arg: *mut core::ffi::c_void,
153    ) -> i8;
154}
155unsafe extern "C" {
156    #[doc = " Block until `task` exits. Cleans up task storage on success."]
157    pub fn nros_platform_task_join(task: *mut core::ffi::c_void) -> i8;
158}
159unsafe extern "C" {
160    #[doc = " Mark `task` as detached — its storage is reclaimed on exit without\n  a join."]
161    pub fn nros_platform_task_detach(task: *mut core::ffi::c_void) -> i8;
162}
163unsafe extern "C" {
164    #[doc = " Request `task` to terminate at the next cancellation point.\n  Cooperative: a task that never reaches a cancel point will not stop."]
165    pub fn nros_platform_task_cancel(task: *mut core::ffi::c_void) -> i8;
166}
167unsafe extern "C" {
168    #[doc = " Terminate the calling task immediately. Does not return."]
169    pub fn nros_platform_task_exit();
170}
171unsafe extern "C" {
172    #[doc = " Free task storage allocated by `task_init`. Called after `task_join`\n  or `task_detach + exit`."]
173    pub fn nros_platform_task_free(task: *mut *mut core::ffi::c_void);
174}
175unsafe extern "C" {
176    #[doc = " Opaque-storage sizing for `task`, mirroring the wake primitive's\n  probes below. Both are pure functions (no global state) and may be\n  called before `nros_platform_task_init`.\n\n  phase-359 W10 — added because `task_init`'s \"size determined by the\n  implementor\" had no way to ASK. A C caller can write\n  `pthread_t t;` and pass `&t`; a Rust caller cannot, and hard-coding\n  a size is precisely issue 0570 (Rust's 20-byte `pthread_attr_t` met\n  NuttX's 56-byte one and smashed the caller's frame). The wake\n  primitive already solved this the right way; tasks now match it."]
177    pub fn nros_platform_task_storage_size() -> usize;
178}
179unsafe extern "C" {
180    pub fn nros_platform_task_storage_align() -> usize;
181}
182unsafe extern "C" {
183    #[doc = " Opaque-storage sizing for the lock family, matching `wake` and `task`.\n  Pure functions, callable before the corresponding `_init`."]
184    pub fn nros_platform_mutex_storage_size() -> usize;
185}
186unsafe extern "C" {
187    pub fn nros_platform_mutex_storage_align() -> usize;
188}
189unsafe extern "C" {
190    pub fn nros_platform_mutex_rec_storage_size() -> usize;
191}
192unsafe extern "C" {
193    pub fn nros_platform_mutex_rec_storage_align() -> usize;
194}
195unsafe extern "C" {
196    pub fn nros_platform_condvar_storage_size() -> usize;
197}
198unsafe extern "C" {
199    pub fn nros_platform_condvar_storage_align() -> usize;
200}
201unsafe extern "C" {
202    pub fn nros_platform_mutex_init(m: *mut core::ffi::c_void) -> i8;
203}
204unsafe extern "C" {
205    pub fn nros_platform_mutex_drop(m: *mut core::ffi::c_void) -> i8;
206}
207unsafe extern "C" {
208    pub fn nros_platform_mutex_lock(m: *mut core::ffi::c_void) -> i8;
209}
210unsafe extern "C" {
211    pub fn nros_platform_mutex_try_lock(m: *mut core::ffi::c_void) -> i8;
212}
213unsafe extern "C" {
214    pub fn nros_platform_mutex_unlock(m: *mut core::ffi::c_void) -> i8;
215}
216unsafe extern "C" {
217    #[doc = " Initialise a recursive mutex (same-thread re-entry permitted).\n  Required by zenoh-pico."]
218    pub fn nros_platform_mutex_rec_init(m: *mut core::ffi::c_void) -> i8;
219}
220unsafe extern "C" {
221    pub fn nros_platform_mutex_rec_drop(m: *mut core::ffi::c_void) -> i8;
222}
223unsafe extern "C" {
224    pub fn nros_platform_mutex_rec_lock(m: *mut core::ffi::c_void) -> i8;
225}
226unsafe extern "C" {
227    pub fn nros_platform_mutex_rec_try_lock(m: *mut core::ffi::c_void) -> i8;
228}
229unsafe extern "C" {
230    pub fn nros_platform_mutex_rec_unlock(m: *mut core::ffi::c_void) -> i8;
231}
232unsafe extern "C" {
233    pub fn nros_platform_condvar_init(cv: *mut core::ffi::c_void) -> i8;
234}
235unsafe extern "C" {
236    pub fn nros_platform_condvar_drop(cv: *mut core::ffi::c_void) -> i8;
237}
238unsafe extern "C" {
239    pub fn nros_platform_condvar_signal(cv: *mut core::ffi::c_void) -> i8;
240}
241unsafe extern "C" {
242    pub fn nros_platform_condvar_signal_all(cv: *mut core::ffi::c_void) -> i8;
243}
244unsafe extern "C" {
245    #[doc = " Phase 124.B.7.a — ISR-safe signal.\n\n  Callable from interrupt context. `nros_platform_condvar_signal`\n  is NOT ISR-safe on every platform (POSIX `pthread_cond_signal`\n  isn't on the async-signal-safe function list; RTOS condvar\n  primitives often require thread context). Backends MUST use\n  this variant when triggering from an ISR or POSIX signal handler.\n\n  Per-platform implementation:\n  * POSIX: `pipe` write — async-signal-safe; a runtime worker thread\n    forwards to the underlying condvar. (Linux may use `eventfd`\n    instead, which is NOT POSIX — `signalfd`/`eventfd` are Linux\n    syscalls, which is why `nros-node`'s worker is\n    `target_os = \"linux\"`-gated.)\n  * Zephyr: `k_sem_give` on the wake semaphore (ISR-safe).\n  * FreeRTOS: `xSemaphoreGiveFromISR` + `portYIELD_FROM_ISR` on\n    the wake semaphore.\n  * NuttX: `sem_post` (POSIX-safe under NuttX) on the wake sem.\n  * ThreadX: `tx_event_flags_set` on the wake event flag group\n    (ISR-safe).\n  * Bare-metal: atomic flag store + `__SEV()` (Cortex-M).\n\n  Returns non-zero on error (e.g. ISR-unsafe call on a backend\n  that mandates ISR-context-only via a separate primitive).\n  Backends without an ISR-safe path return non-zero so callers\n  can fall back to thread-context signal (with the obvious\n  latency cost)."]
246    pub fn nros_platform_condvar_signal_from_isr(cv: *mut core::ffi::c_void) -> i8;
247}
248unsafe extern "C" {
249    #[doc = " Atomically release `m` and block on `cv` until signalled or until the\n  absolute monotonic deadline `abstime`, in MILLISECONDS on the\n  `nros_platform_clock_ns()` epoch — i.e. `clock_ns() / 1000000`. The mutex\n  is re-acquired before this returns. Returns 0 when signalled, 1 on timeout\n  and -1 on error, the same codes as `nros_platform_wake_wait_ms` (issue\n  1906: FreeRTOS returned -1 on timeout, so a caller could not tell a\n  timeout from a failure). A port rounds the remaining time UP to its tick,\n  so the wait never times out before its deadline.\n\n  This is the ONLY condvar wait in the ABI. The unbounded\n  `nros_platform_condvar_wait` was removed (issue 1196, phase-436 D2): it sat\n  here with a neutral name, every port implemented it with its forever\n  spelling, and \"no unbounded wait\" is only a property of the system if it\n  is a property of the API. A caller whose own contract is unbounded — the\n  zenoh-pico shim's `_z_condvar_wait` was the last one — loops over bounded\n  waits and re-tests its predicate, which a condvar caller must do anyway\n  because of spurious wakeups. `scripts/check-no-unbounded-condvar-wait.sh`\n  keeps the symbol from coming back.\n\n  The unit is spelt out because this said \"`clock_ms` units\" after RFC-0073 /\n  phase-352 W6 retired `nros_platform_clock_ms`; it never changed — every\n  port names the parameter `abstime_ms`."]
250    pub fn nros_platform_condvar_wait_until(
251        cv: *mut core::ffi::c_void,
252        m: *mut core::ffi::c_void,
253        abstime: u64,
254    ) -> i8;
255}
256unsafe extern "C" {
257    pub fn nros_platform_wake_init(w: *mut core::ffi::c_void) -> i8;
258}
259unsafe extern "C" {
260    pub fn nros_platform_wake_drop(w: *mut core::ffi::c_void) -> i8;
261}
262unsafe extern "C" {
263    pub fn nros_platform_wake_wait_ms(w: *mut core::ffi::c_void, timeout_ms: u32) -> i8;
264}
265unsafe extern "C" {
266    pub fn nros_platform_wake_signal(w: *mut core::ffi::c_void) -> i8;
267}
268unsafe extern "C" {
269    pub fn nros_platform_wake_signal_from_isr(w: *mut core::ffi::c_void) -> i8;
270}
271unsafe extern "C" {
272    #[doc = " phase-436 W7 — OPTIONAL microsecond park, the `ParkUntilFn` a port may\n  install through `nros_cpp_executor_set_park_primitive`.\n\n  `nros_platform_wake_wait_ms` above is the required primitive and floors\n  every wait at a millisecond through its own signature; this is the same\n  wait without that floor, for kernels whose timeout type is finer (issue\n  1242). Ports that cannot do better than a millisecond need not define it.\n\n  `w` MUST be the executor's own wake object — the backend's listener signals\n  that one, and a park on anything else cannot be broken by data arriving.\n\n  Returns `NROS_PLATFORM_PARK_SIGNALLED` (0) when signalled,\n  `NROS_PLATFORM_PARK_EXPIRED` (1) when the deadline expired,\n  `NROS_PLATFORM_PARK_YIELDED` (2) when it did not wait but handed the wait\n  to its framework's scheduler, and negative when it cannot park.\n\n  phase-521 W8 (c) (RFC-0113 D9) — YIELDED is the answer of a park slot\n  installed for a tier a FRAMEWORK schedules (a PX4 work item): it arms the\n  framework's wake at `deadline_us` (`ScheduleDelayed`, or `ScheduleClear`\n  with no deadline) and returns at once, and the executor's `spin_once`\n  returns to the framework instead of blocking. A wake already pending when\n  it answers keeps the pass running. A port's own park never yields."]
273    pub fn nros_platform_wake_park_until_us(w: *mut core::ffi::c_void, deadline_us: u64) -> i8;
274}
275unsafe extern "C" {
276    #[doc = " The finest park `nros_platform_wake_park_until_us` can express, in\n  microseconds. An RTOS tick is a coarser limit than the ABI signature and a\n  timespec primitive a finer one, so only the port can answer (issue 1242)."]
277    pub fn nros_platform_wake_park_granularity_us() -> u64;
278}
279unsafe extern "C" {
280    #[doc = " phase-521 W3 (RFC-0113 D3) — park on the wake object AND on OS handles.\n\n  The same park as `nros_platform_wake_park_until_us`, ended also when any\n  of the `n` handles in `handles` becomes readable. A handle is what an RMW\n  session's `readiness_source` reported as `NROS_RMW_READINESS_WAITABLE`: a\n  file descriptor on POSIX and NuttX. The park does not read the handles; the\n  executor drives the session non-blockingly after it returns.\n\n  `w` MUST be the executor's own wake object, as for the park above.\n\n  Returns 0 when signalled or a handle is readable, 1 when the deadline\n  expired, and -1 when this port cannot wait on OS handles. Every port\n  defines it: one with no such handles returns -1, and the executor then\n  keeps the wait it had."]
281    pub fn nros_platform_wake_park_handles_us(
282        w: *mut core::ffi::c_void,
283        handles: *const i32,
284        n: usize,
285        deadline_us: u64,
286    ) -> i8;
287}
288unsafe extern "C" {
289    #[doc = " Opaque-storage sizing. Both helpers are pure functions (no global\n  state) and may be called before `nros_platform_wake_init`."]
290    pub fn nros_platform_wake_storage_size() -> usize;
291}
292unsafe extern "C" {
293    pub fn nros_platform_wake_storage_align() -> usize;
294}
295unsafe extern "C" {
296    pub fn nros_platform_critical_section_acquire() -> u32;
297}
298unsafe extern "C" {
299    pub fn nros_platform_critical_section_release(token: u32);
300}
301unsafe extern "C" {
302    pub fn nros_platform_log_write(
303        severity: u8,
304        name_ptr: *const u8,
305        name_len: usize,
306        msg_ptr: *const u8,
307        msg_len: usize,
308    );
309}
310unsafe extern "C" {
311    pub fn nros_platform_log_flush();
312}
313unsafe extern "C" {
314    pub fn nros_platform_register_log_writer(
315        writer: nros_platform_log_writer_fn_t,
316        flusher: nros_platform_log_flush_fn_t,
317    );
318}
319unsafe extern "C" {
320    pub fn nros_platform_panic(msg: *const core::ffi::c_char, len: usize);
321}
322unsafe extern "C" {
323    #[doc = " Resolve `(address, port)` strings into the caller-allocated endpoint\n  storage at `ep`. Both strings are NUL-terminated."]
324    pub fn nros_platform_tcp_create_endpoint(
325        ep: *mut core::ffi::c_void,
326        address: *const u8,
327        port: *const u8,
328    ) -> i8;
329}
330unsafe extern "C" {
331    #[doc = " Release any resources held by the endpoint at `ep`."]
332    pub fn nros_platform_tcp_free_endpoint(ep: *mut core::ffi::c_void);
333}
334unsafe extern "C" {
335    #[doc = " Open a TCP client connection to `endpoint`."]
336    pub fn nros_platform_tcp_open(
337        sock: *mut core::ffi::c_void,
338        endpoint: *const core::ffi::c_void,
339        timeout_ms: u32,
340    ) -> i8;
341}
342unsafe extern "C" {
343    #[doc = " Open a listening TCP socket bound to `endpoint`."]
344    pub fn nros_platform_tcp_listen(
345        sock: *mut core::ffi::c_void,
346        endpoint: *const core::ffi::c_void,
347    ) -> i8;
348}
349unsafe extern "C" {
350    #[doc = " Close a TCP socket."]
351    pub fn nros_platform_tcp_close(sock: *mut core::ffi::c_void);
352}
353unsafe extern "C" {
354    #[doc = " Read up to `len` bytes. Returns bytes received, or\n  `NROS_PLATFORM_NET_SOCKET_ERROR` on error."]
355    pub fn nros_platform_tcp_read(
356        sock: *const core::ffi::c_void,
357        buf: *mut u8,
358        len: usize,
359    ) -> usize;
360}
361unsafe extern "C" {
362    #[doc = " Read exactly `len` bytes. Returns `len` on success, or\n  `NROS_PLATFORM_NET_SOCKET_ERROR` on error."]
363    pub fn nros_platform_tcp_read_exact(
364        sock: *const core::ffi::c_void,
365        buf: *mut u8,
366        len: usize,
367    ) -> usize;
368}
369unsafe extern "C" {
370    #[doc = " Send `len` bytes. Returns bytes sent, or\n  `NROS_PLATFORM_NET_SOCKET_ERROR` on error."]
371    pub fn nros_platform_tcp_send(
372        sock: *const core::ffi::c_void,
373        buf: *const u8,
374        len: usize,
375    ) -> usize;
376}
377unsafe extern "C" {
378    #[doc = " phase-521 W6 (RFC-0113 D4) — install (`notify != NULL`) or remove the\n  receive notification on a connected TCP socket: the stack calls\n  `notify(ctx)` each time data is queued on it, from the stack's own context\n  (NetX's IP thread), so `notify` must only signal. Data already queued at\n  install calls it once before this returns; once a removal returns, the\n  previous `notify` is never called again. A zenoh session in CALLER mode\n  over `sock` reports this as `NROS_RMW_READINESS_NOTIFY`.\n\n  Returns 0 when installed (or removed), -1 where the stack offers no such\n  hook (every stack whose zenoh sessions read the link on their own thread\n  needs none)."]
379    pub fn nros_platform_tcp_set_rx_notify(
380        sock: *const core::ffi::c_void,
381        notify: ::core::option::Option<unsafe extern "C" fn(ctx: *mut core::ffi::c_void)>,
382        ctx: *mut core::ffi::c_void,
383    ) -> i8;
384}
385unsafe extern "C" {
386    pub fn nros_platform_udp_create_endpoint(
387        ep: *mut core::ffi::c_void,
388        address: *const u8,
389        port: *const u8,
390    ) -> i8;
391}
392unsafe extern "C" {
393    pub fn nros_platform_udp_free_endpoint(ep: *mut core::ffi::c_void);
394}
395unsafe extern "C" {
396    pub fn nros_platform_udp_open(
397        sock: *mut core::ffi::c_void,
398        endpoint: *const core::ffi::c_void,
399        timeout_ms: u32,
400    ) -> i8;
401}
402unsafe extern "C" {
403    #[doc = " Bind a UDP socket in listen / server mode. Optional — return -1\n  on platforms that don't expose a UDP-server primitive."]
404    pub fn nros_platform_udp_listen(
405        sock: *mut core::ffi::c_void,
406        endpoint: *const core::ffi::c_void,
407        timeout_ms: u32,
408    ) -> i8;
409}
410unsafe extern "C" {
411    pub fn nros_platform_udp_close(sock: *mut core::ffi::c_void);
412}
413unsafe extern "C" {
414    pub fn nros_platform_udp_read(
415        sock: *const core::ffi::c_void,
416        buf: *mut u8,
417        len: usize,
418    ) -> usize;
419}
420unsafe extern "C" {
421    pub fn nros_platform_udp_read_exact(
422        sock: *const core::ffi::c_void,
423        buf: *mut u8,
424        len: usize,
425    ) -> usize;
426}
427unsafe extern "C" {
428    #[doc = " Send `len` bytes to `endpoint`."]
429    pub fn nros_platform_udp_send(
430        sock: *const core::ffi::c_void,
431        buf: *const u8,
432        len: usize,
433        endpoint: *const core::ffi::c_void,
434    ) -> usize;
435}
436unsafe extern "C" {
437    #[doc = " Set the recv timeout in milliseconds; `0` means block indefinitely."]
438    pub fn nros_platform_udp_set_recv_timeout(sock: *const core::ffi::c_void, timeout_ms: u32);
439}
440unsafe extern "C" {
441    #[doc = " phase-521 W4 (RFC-0113 D4) — the OS handle that becomes readable when a\n  datagram arrives on `sock`: its file descriptor on POSIX and NuttX. An RMW\n  session reports it as `NROS_RMW_READINESS_WAITABLE`, and the executor parks\n  on it (`nros_platform_wake_park_handles_us`) instead of blocking in\n  `read`. Returns -1 where the stack has no such handle (lwIP, NetX, a\n  bare-metal stack); those report readiness as a Notify instead."]
442    pub fn nros_platform_udp_readiness_handle(sock: *const core::ffi::c_void) -> i32;
443}
444unsafe extern "C" {
445    #[doc = " phase-521 W4 (RFC-0113 D4) — install (`notify != NULL`) or remove the\n  receive notification on `sock`: the stack calls `notify(ctx)` each time a\n  datagram is queued on it, from the stack's own context (lwIP's tcpip\n  thread, NetX's IP thread), so `notify` must only signal. Data already\n  queued at install calls it once before this returns; once a removal\n  returns, the previous `notify` is never called again. An RMW session over\n  `sock` reports this as `NROS_RMW_READINESS_NOTIFY`.\n\n  Returns 0 when installed (or removed), -1 where the stack offers no such\n  hook — POSIX/NuttX, which have `nros_platform_udp_readiness_handle`\n  instead, and stacks not yet given one."]
446    pub fn nros_platform_udp_set_rx_notify(
447        sock: *const core::ffi::c_void,
448        notify: ::core::option::Option<unsafe extern "C" fn(ctx: *mut core::ffi::c_void)>,
449        ctx: *mut core::ffi::c_void,
450    ) -> i8;
451}
452unsafe extern "C" {
453    pub fn nros_platform_udp_mcast_open(
454        sock: *mut core::ffi::c_void,
455        endpoint: *const core::ffi::c_void,
456        lep: *mut core::ffi::c_void,
457        timeout_ms: u32,
458        iface: *const u8,
459    ) -> i8;
460}
461unsafe extern "C" {
462    pub fn nros_platform_udp_mcast_listen(
463        sock: *mut core::ffi::c_void,
464        endpoint: *const core::ffi::c_void,
465        timeout_ms: u32,
466        iface: *const u8,
467        join: *const u8,
468    ) -> i8;
469}
470unsafe extern "C" {
471    pub fn nros_platform_udp_mcast_close(
472        sockrecv: *mut core::ffi::c_void,
473        socksend: *mut core::ffi::c_void,
474        rep: *const core::ffi::c_void,
475        lep: *const core::ffi::c_void,
476    );
477}
478unsafe extern "C" {
479    pub fn nros_platform_udp_mcast_read(
480        sock: *const core::ffi::c_void,
481        buf: *mut u8,
482        len: usize,
483        lep: *const core::ffi::c_void,
484        addr: *mut core::ffi::c_void,
485    ) -> usize;
486}
487unsafe extern "C" {
488    pub fn nros_platform_udp_mcast_read_exact(
489        sock: *const core::ffi::c_void,
490        buf: *mut u8,
491        len: usize,
492        lep: *const core::ffi::c_void,
493        addr: *mut core::ffi::c_void,
494    ) -> usize;
495}
496unsafe extern "C" {
497    pub fn nros_platform_udp_mcast_send(
498        sock: *const core::ffi::c_void,
499        buf: *const u8,
500        len: usize,
501        endpoint: *const core::ffi::c_void,
502    ) -> usize;
503}
504unsafe extern "C" {
505    #[doc = " Switch a socket to non-blocking mode."]
506    pub fn nros_platform_socket_set_non_blocking(sock: *const core::ffi::c_void) -> i8;
507}
508unsafe extern "C" {
509    #[doc = " Accept a pending connection from `sock_in` into `sock_out`."]
510    pub fn nros_platform_socket_accept(
511        sock_in: *const core::ffi::c_void,
512        sock_out: *mut core::ffi::c_void,
513    ) -> i8;
514}
515unsafe extern "C" {
516    #[doc = " Socket-layer shutdown + close. Distinct from\n  `nros_platform_tcp_close` because zenoh-pico's helper layer\n  exposes both."]
517    pub fn nros_platform_socket_close(sock: *mut core::ffi::c_void);
518}
519unsafe extern "C" {
520    #[doc = " Wait for socket events on a multi-peer set. Optional on platforms\n  without a poll/select primitive."]
521    pub fn nros_platform_socket_wait_event(
522        peers: *mut core::ffi::c_void,
523        mutex: *mut core::ffi::c_void,
524    ) -> i8;
525}
526unsafe extern "C" {
527    #[doc = " Pump the underlying network stack to process pending I/O.\n  No-op on platforms with a kernel-driven socket layer (POSIX,\n  Zephyr, lwIP, NetX Duo). Bare-metal smoltcp targets advance\n  the stack from this entry point."]
528    pub fn nros_platform_network_poll();
529}
530unsafe extern "C" {
531    #[doc = " Register a periodic timer that invokes `callback(user_data)` every\n  `period_us` microseconds. Returns the platform-native handle on\n  success, NULL on failure."]
532    pub fn nros_platform_timer_create_periodic(
533        period_us: u32,
534        callback: nros_platform_timer_callback_t,
535        user_data: *mut core::ffi::c_void,
536    ) -> *mut core::ffi::c_void;
537}
538unsafe extern "C" {
539    #[doc = " Register a one-shot timer that invokes `callback(user_data)` once\n  after `timeout_us` microseconds. Returns the platform-native\n  handle on success, NULL on failure."]
540    pub fn nros_platform_timer_create_oneshot(
541        timeout_us: u32,
542        callback: nros_platform_timer_callback_t,
543        user_data: *mut core::ffi::c_void,
544    ) -> *mut core::ffi::c_void;
545}
546unsafe extern "C" {
547    #[doc = " Cancel + free the timer. Drains in-flight callback invocations\n  before returning so `user_data` is no longer accessed. Idempotent\n  on already-destroyed handles."]
548    pub fn nros_platform_timer_destroy(handle: *mut core::ffi::c_void);
549}
550unsafe extern "C" {
551    #[doc = " Cancel a previously-armed timer. Returns:\n\n   - 1 if cancellation prevented the callback from firing,\n   - 0 if the callback already fired (or the timer was already\n     cancelled / destroyed),\n   - -1 on unrecoverable error.\n\n  Distinct from `destroy` — the handle remains valid after\n  `cancel` and may be re-armed by the application's own\n  bookkeeping if the implementation supports it."]
552    pub fn nros_platform_timer_cancel(handle: *mut core::ffi::c_void) -> i8;
553}