msrt-ffi
C ABI bindings for MSRT.
This crate is intended to be shipped as source. C users build a target-specific static library from this crate, then link that library into their C application or MCU firmware.
msrt_ffi.h is portable.
libmsrt_ffi.a is target-specific.
There is no universal .a, .so, or .dylib that works on every host and MCU.
What The C Side Owns
msrt-ffi does not open serial ports, sockets, USB devices, or UART drivers.
The C application owns real IO:
transport read bytes -> msrt_endpoint_receive()
msrt_endpoint_poll() -> write MSRT_POLL_TRANSMIT bytes to transport
MSRT_POLL_MESSAGE -> deliver application payload
Build For Host
Build a host static library:
Outputs:
target/release/libmsrt_ffi.a
crates/msrt-ffi/include/msrt_ffi.h
Example macOS link command:
Example Linux link command:
Native libraries vary by toolchain and target.
Build For MCU
Build a no-std static library for a specific MCU target:
When compiling C code against a no-heap MCU build, define MSRT_FFI_NO_HEAP so
the host-only msrt_endpoint_new/free declarations are hidden:
Output:
target/thumbv7em-none-eabihf/release/libmsrt_ffi.a
That .a is only for that target. A Cortex-M0, Cortex-M4 hard-float, RISC-V MCU,
Linux host, and macOS host each need their own build.
The MCU C firmware link step usually looks like:
C application objects
+ vendor HAL/startup objects
+ target/<mcu-target>/release/libmsrt_ffi.a
+ linker script
-> firmware.elf
-> firmware.bin / firmware.hex
Use your MCU toolchain's linker flags for section garbage collection, for
example -ffunction-sections, -fdata-sections, and -Wl,--gc-sections.
MCU-Friendly Storage API
The primary API does not require heap allocation. C owns endpoint storage:
msrt_endpoint_storage_t storage;
msrt_endpoint_t *endpoint = NULL;
int32_t status = ;
if
/* Use endpoint. */
;
msrt_endpoint_storage_t is opaque. Do not read or write its fields directly.
The header defines conservative storage for the endpoint. At runtime or startup, you may compare:
size_t need = ;
size_t align = ;
If the storage compiled into the header is not enough for this Rust build,
msrt_endpoint_init() returns MSRT_STATUS_INVALID_STORAGE.
Host Convenience API
When built with default features, host programs may also use heap allocation:
msrt_endpoint_t *endpoint = ;
;
This API is not available in --no-default-features MCU builds. Portable C code
should prefer msrt_endpoint_init() and msrt_endpoint_deinit().
Endpoint Roles
Use MSRT_ROLE_CLIENT for the active side. A client must call
msrt_endpoint_connect() before sending messages.
Use MSRT_ROLE_PASSIVE for a single-peer passive side, such as an MCU waiting
for a host. A passive endpoint creates its protocol session when bytes arrive,
so it does not call msrt_endpoint_connect().
Custom Configuration
msrt_config_t config;
;
config.role = MSRT_ROLE_PASSIVE;
config.integrity = MSRT_INTEGRITY_CRC32;
config.retransmit_timeout_ms = 100;
msrt_endpoint_storage_t storage;
msrt_endpoint_t *endpoint = NULL;
;
Both peers must use the same integrity setting.
Driving The Endpoint
Call receive whenever bytes arrive. Input does not need to be packet-aligned.
uint8_t rx;
size_t rx_len = ;
if
Queue an application message:
const uint8_t payload = "hello";
;
Poll until idle. MSRT returns one action per call.
msrt_poll_event_t event;
while
Main Loop Shape
while
Status Codes
MSRT_STATUS_OK success
MSRT_STATUS_NULL required pointer was NULL
MSRT_STATUS_INVALID_SLICE byte pointer was NULL while length was non-zero
MSRT_STATUS_PROTOCOL_ERROR MSRT rejected or could not process input
MSRT_STATUS_UNSUPPORTED unsupported role or option
MSRT_STATUS_NO_SESSION send was requested without an active session
MSRT_STATUS_INVALID_STORAGE storage is too small or incorrectly aligned
Example
examples/loopback.c shows a small in-process client/passive exchange. It feeds
MSRT_POLL_TRANSMIT bytes from one endpoint into the other endpoint. In a real
program, replace that transfer with UART, USB CDC, socket, or another byte
transport.