SEDSnet
A Rust networking stack with compact packets, runtime schema, discovery, routing, reliability, managed state sync, P2P service ports/streams, optional E2E payload cryptography, and C/Python bindings for distributed embedded and host systems.
Crate API docs are published on docs.rs. The implementation-level wiki, including wire/discovery formats and binding guides, is mirrored in docs/wiki and on the project wiki.
Authors
- @Rylan-Meilutis (Original Author, Maintainer, and co-creator of the protocol)
- @origami-yoda (Co-creator of the protocol and co-author of the original C++ implementation)
About
This library started out as a Rust rewrite of the earlier SEDS telemetry C++ implementation.
After the initial rewrite, many improvements were made to the rust implementation including better safety, easier extension, and improved performance. This caused the C++ implementation to be rewritten to keep feature parity with the rust version. After about of month of this, we decided that we were no longer going to use the C++ version, and thus the project was archived and is no longer being maintained. With the Rust version being the sole implementation, we have continued to improve it and add new features like python bindings, packet compression, and a bitmap for endpoints to further reduce packet size. This library is now being used in multiple projects including embedded code on the rocket and on the rust based ground station. SEDSnet is now capable of acting as a new network, passing telemetry data to endpoints across hardware and software networks (uart, can ethernet, etc.) and across differing platforms and protocols (tcp, udp, etc.).
Overview
This library provides a safe and efficient way to handle telemetry data including serializing, routing, and converting into strings for logging. The purpose of this library is to provide an easy and consistent way to create and transport any data to any destination without needing to implement the core routing on every platform, the library handles the creation and routing of the data while allowing for easy extension to support new data types and destinations. The user of the library is responsible for implementing 2 core functions and one function per local data endpoint. The core functions are as follows:
- A function to send raw bytes to the all other nodes (e.g. UART, SPI, I2C, CAN, etc.)
- A function to receive raw bytes from all other nodes and passes the packet to the router (e.g. UART, SPI, I2C, CAN, etc.)
- A function to handle local data endpoints (e.g. logging to console, writing to file, sending over radio, etc.) (Note: each local endpoint needs its own function)
SEDSnet also provides helpers to convert the telemetry data into strings for logging purposes. The library also handles packing telemetry packets to wire frames and unpacking received frames.
SEDSnet is platform-agnostic and can be used on any platform that supports Rust. The library is primarily designed to be used in embedded systems and used by a C program, but can also be used in desktop applications and other rust codebases.
SEDSnet also supports python bindings via pyo3. to use you need maturin installed to build the python package.
With the optional discovery feature, routers and relays can exchange built-in discovery packets, learn which
endpoints are reachable through which sides, adapt the announce rate as the topology changes, and export a live topology
snapshot for inspection. When timesync is also enabled, discovery can advertise concrete time source sender IDs so
SEDSNET_TIME_SYNC requests prefer exact source paths instead of generic endpoint flooding. Once discovery topology exists,
unknown user-data routes are not blindly flooded across low-bandwidth links; discovery/control traffic still propagates,
and explicit route policy can intentionally select a side. SEDSNET_DISCOVERY and SEDSNET_TIME_SYNC are reserved internal router
endpoints: applications can use the discovery and time-sync APIs, but must not register local endpoint handlers for
those endpoints or try to override their built-in handling.
Discovery and time-sync maintenance also throttle themselves across measured slow links. Link-probe or driver timing samples mark constrained sides, after which routers and relays send mostly minimal reachability pings across those sides and reserve full schema/topology/time-source refreshes for a much slower cadence. Router-managed time sync keeps its normal cadence on fast sides while each measured slow side independently receives sparse time-sync traffic, keeping asymmetric or time-sliced radio links available for user payloads.
Discovery also assigns and advertises compact node addresses and hostnames for point-to-point service traffic. A router can bind a SEDSnet service port and receive opaque byte payloads targeted by hostname or address, or open a P2P stream with connect/accept/data/close events. Protocols such as HTTP can be carried over SEDSnet links without IP being the underlying transport. Broadcast endpoint delivery remains available for telemetry data types; P2P service frames use discovery identity and ports for board-to-board traffic.
Queue memory is bounded by the compile-time MAX_QUEUE_BUDGET. Router and relay internals share that budget
dynamically across RX work, TX work, reliable replay/out-of-order buffers, recent packet ID tracking, and learned
discovery topology state. The recent packet ID cache preallocates its final storage because it is expected to fill
during normal operation, so its reserved bytes come out of the shared budget immediately. If one active queue area is
idle, another can use more of the remaining budget; if several areas fill at once, older queued state is evicted so
total queue-owned memory stays bounded.
Reliable delivery uses internal ACK/request control packets. Ordered reliable receivers buffer out-of-order packets, partial-ACK packets that arrived after a gap, request the missing sequence, and then release the buffered run as soon as the gap is filled. A partial ACK suppresses timeout retransmission for that exact packet, but an explicit packet request can still retransmit it later.
Routers can also cache selected data types as managed network variables. A board that restarts can request the current
cached value and receive it through the normal endpoint handler path instead of waiting for the next publisher update.
For sensitive state or commands, the default cryptography feature lets data types prefer or require end-to-end payload
cryptography while the application supplies a C provider, Rust provider, OS/hardware crypto wrapper, or registered software key.
When topology or schema changes are propagating, packets already on the wire now carry a compact frozen delivery and decode contract. New packets immediately use the latest schema-default endpoint view, while in-flight packets continue to route only to their original intended holders and remain decodable against the shape they were packed with. The contract is encoded compactly with bitmap-oriented metadata and sender hashes so header growth stays small.
Packed packets use compact varint fields, schema-derived endpoints, a compact source address instead of a repeated
sender hostname, and optional per-side header templates. Hostnames and endpoint holders are learned through discovery
and network configuration; the packet header carries only the source address needed for identity/routing. Per-side
templates can then replace repeated header fields with a compact template ID on small-packet transports, keeping the
header-to-payload ratio reasonable for small payloads such as three floats or a few u8 values.
Recent changelog milestones
Version 4.0.0 highlights
- User telemetry schema is now runtime-only.
build.rsno longer generates Rust enum variants or binding constants fromtelemetry_config.json. - Endpoints and data types can be registered, looked up by name, exported, synced through discovery, and removed at runtime.
- Rust code can use readable runtime references such as
DataEndpoint::named("RADIO")andDataType::named("GPS_DATA")instead of raw numeric IDs. - C and Python expose matching schema register/info/info-by-name/remove APIs.
- Managed network variables let restarted boards request the latest cached state through normal endpoint handlers, and update callbacks can run when an inbound network update changes the cache.
- Discovery-backed P2P service ports support datagrams and lightweight stream sessions with connect/accept/data/close/reset events for byte protocols that need board-to-board sessions.
- End-to-end payload cryptography is enabled by default and can be preferred or required per data type; routers choose whether to encrypt required, preferred, or all user data.
- Crypto providers can be supplied as C callbacks, Rust providers, or registered software fallback keys, and compact managed credentials support master-root deployments without user-managed cert files.
- Fixed-size packed sides transparently split/reassemble packets for CAN, I2C, and fixed-frame radios, while link-probe samples seed adaptive routing for asymmetric or time-sliced links.
- Discovery-aware forwarding avoids blind unknown-route user-data flooding once topology exists, protecting low-bandwidth sides unless explicit route policy selects them.
- Discovery and time-sync control traffic is dynamically throttled per measured slow link, using minimal reachability pings between infrequent full topology/schema refreshes.
- Routers and relays export topology as a board graph with named endpoint fields, side names,
deduplicated
links, and filtered SEDSnet control endpoints. They also expose memory-layout and per-client stats snapshots for profiling and diagnostics. - Routers and relays announce
SEDSNET_DISCOVERY_LEAVEduring explicit leave/shutdown so peers can prune topology immediately instead of waiting for expiry. - Optional JSON config is applied at runtime through env/path/bytes APIs. The repo does not carry a
default user schema. Embedded users that want compiled-in seed bytes must provide their own local
telemetry_config.jsonbefore building. - Schema registry memory counts against the same shared
MAX_QUEUE_BUDGETas other router/relay queue-backed state. - Optional C and C++ convenience wrappers can be enabled from CMake, while raw-ABI users can keep the static runtime-schema header only.
- Full changelog: CHANGELOG.md
Version 3.12.0 highlights
- Router and relay queue-backed state now shares one dynamic
MAX_QUEUE_BUDGETinstead of using isolated per-queue caps. MAX_QUEUE_SIZEhas been renamed toMAX_QUEUE_BUDGET; the old environment name remains accepted as a legacy alias.- Recent packet ID caches, reliable replay/out-of-order buffers, and discovery topology state now
count against the same shared budget, with topology eviction warnings in
stdbuilds. - Ordered reliable receive paths now partial-ACK out-of-order packets to reduce timeout retransmission traffic while still allowing explicit packet requests.
- Router and relay side-TX contention is now retried as transient backpressure instead of surfacing intermittent handler failures.
- Full changelog: CHANGELOG.md
Version 3.11.1 highlights
- Discovery now propagates a full router graph with
SEDSNET_DISCOVERY_TOPOLOGY, so routers and relays keep track of which sender IDs own which endpoints and how remote routers connect to each other. export_topology()now includes router-level topology plus per-side announcer detail instead of only aggregated reachable endpoint lists.- Topology export is now available to clients across all supported surfaces:
Rust
export_topology(), PythonRouter.export_topology()/Relay.export_topology(), and C JSON exports viaseds_router_export_topology*/seds_relay_export_topology*. - Full changelog: CHANGELOG.md
Version 3.11.0 highlights
- Removed
RouterModefrom the active router model. Routers now use the same runtime routing-rule model as relays, and with no explicit route rules they default to a full forwarding mesh. - Discovery-driven multi-path routing now defaults to adaptive load balancing for normal traffic, while reliable discovered traffic still fans out across all known candidate paths.
- Reliable delivery is now end-to-end verified in addition to the existing per-link ACK/retransmit layer. Destination routers emit directed end-to-end acknowledgements, and discovery-informed return-path learning routes those ACKs only toward the source instead of flooding them.
- When a discovered destination holder disappears from topology, the source retires that holder from the in-flight obligation set instead of replaying forever toward a vanished board.
- Relays also prune their learned holder-ACK state against discovery expiry so stale confirmations do not keep affecting later discovered routing choices.
- Reliable streams still stay non-blocking while those end-to-end acknowledgements are outstanding.
- Added expanded testing documentation covering unit tests, Rust system tests, C system tests, local coverage reporting, and the new end-to-end reliability regression tests.
- Full changelog: CHANGELOG.md
Version 3.10.0 highlights
- Reliable delivery in both
RouterandRelaynow uses built-in internalRELIABLE_ACKandRELIABLE_PACKET_REQUESTpacket types instead of wire-only ACK-only frames. - Reliable streams no longer block on one missing reliable packet. Ordered gaps are requested explicitly, out-of-order packets are buffered, and retransmits are requeued with elevated priority.
- This improves recovery on asymmetric links and multi-destination fanout where different boards progress at different rates.
- Full changelog: CHANGELOG.md
Version 3.9.1 highlights
- Reserved the built-in
SEDSNET_DISCOVERYandSEDSNET_TIME_SYNCendpoints for router-owned control traffic. - User handlers can no longer shadow internal discovery or time-sync behavior through Rust or C configuration APIs.
- Queue timeout handling was tightened so TX/RX work shares nonzero budgets more predictably.
- Full changelog: CHANGELOG.md
Version 3.0.0 highlights
- Introduced internal router-side tracking so most applications can use the plain RX APIs and only opt into side-aware ingress when they actually need it.
- Added TCP-like reliable delivery for schema types marked
reliableorreliable_mode, with ACKs, retransmits, and optional ordering. - This established the modern router/reliability model that later releases expanded.
- Full changelog: v2.4.0...v3.0.0
Version 1.0.0 highlights
- First stable release with routing, packet packing, and packet creation across Rust, C, and Python.
- Marked the API as stable and established the base wire-format and packet model the later versions built on.
Building
To build the library in a C project, just include the library as a submodule or subtree and link it in your cmakelists.txt as shown below. For other build systems, you can build the library as a static or dynamic library using cargo and link it to your project.
Building with python bindings can be done with the build script on posix systems:
./build.py release maturin-develop
When building in an embedded environment the library will compile to a static library that can be linked to your C code. this library takes up about 100kb of flash and does require heap allocation to be available through either freertos, or by creating providers that expose pvPortMalloc and vPortFree.
Embedded hooks
For embedded integrations, treat the router or relay as a single owner context. The normal application loop should call
periodic(...) and feed ingress bytes into the queued RX APIs.
Rules that matter in practice:
- Do not call router, relay, or packet-to-string APIs from an ISR. Queue the bytes and hand them to a task or worker.
- If you wrap router calls with a lock, that lock must be recursive-safe because side TX callbacks can trigger deferred queue work in the same logical call chain.
SEDSNET_DISCOVERYandSEDSNET_TIME_SYNCare reserved internal endpoints. Do not register local handlers for them and do not emit those packets manually from application code. Use the time-sync and discovery APIs instead.- When the
timesyncfeature is enabled,periodic(...)is the expected maintenance entry point. Only usepoll_timesync(...)/poll_discovery(...)directly when you intentionally need manual phase control.
build.py usage
./build.py [OPTIONS]
Options:
release Build in release mode.
check Run cargo clippy with -D warnings for default, python, and embedded builds.
test Run the clippy checks, nextest/cargo tests, a stable Criterion benchmark smoke pass, and also validate python plus embedded builds when the cross C toolchain exists.
embedded Build for the embedded target (enables embedded feature).
python Build with Python bindings (enables python feature).
timesync Build with time sync helpers (enables timesync feature).
maturin-build Run maturin build with the .pyi .gitignore hack.
maturin-develop Run maturin develop with the .pyi .gitignore hack.
maturin-install Build wheel and install it with uv pip install.
target=<triple> Set Rust compilation target (e.g. target=thumbv7em-none-eabihf).
device_id=<id> Set DEVICE_IDENTIFIER env var for the build.
static_schema_path=<path> Set SEDSNET_STATIC_SCHEMA_PATH for runtime registry seeding.
static_ipc_schema_path=<path> Set SEDSNET_STATIC_IPC_SCHEMA_PATH for a runtime IPC/link-local seed.
max_queue_budget=<n> Set MAX_QUEUE_BUDGET for the shared router/relay queue budget.
max_recent_rx_ids=<n> Set MAX_RECENT_RX_IDS for the preallocated recent-ID cache.
max_stack_payload=<n> Set MAX_STACK_PAYLOAD for define_stack_payload!(env="MAX_STACK_PAYLOAD", ...).
env:KEY=VALUE Set arbitrary environment variable(s) for the build (repeatable).
Examples:
./build.py release
./build.py check
./build.py check release
./build.py embedded release target=thumbv7em-none-eabihf device_id=FC
./build.py python
./build.py test release
./build.py maturin-install max_recent_rx_ids=256 env:MAX_STACK_PAYLOAD=128
Dependencies
- Rust → https://rustup.rs/
- CMake
- A C++ compiler
- A C compiler
Performance benchmarking
Criterion benchmarks are available through Cargo benches. The current benchmark targets exercise packet construction, packing, header peeking, unpacking, and router/relay flows that mirror the Rust system-test path under the default host feature set.
Run:
If you want profiler-friendly output while iterating locally:
./build.py test now starts with the same strict clippy checks as ./build.py check, then runs:
cargo nextest run --features timesyncwhencargo-nextestis installed, otherwisecargo test --features timesync, covering the unit tests insrc/tests.rs, the Rust system tests undertests/rust-system-test/, and the C integration tests undertests/c-system-test/cargo test --doc --features timesyncwhen nextest is used, since nextest does not run doctests- a stable Criterion smoke pass for
packet_pathsandrouter_system_paths - a
cargo buildvalidation for thepythonfeature - a
cargo buildvalidation for theembeddedfeature when a matching cross C toolchain is available
The benchmark smoke pass uses Cargo --profile release, saves into a dedicated sedsnet_smoke baseline, disables
plot generation, and uses a longer timing window plus a wider smoke-test noise threshold so host variance does not print
alternating regression/improvement noise. The C system-test harness waits for all asserted endpoint hits before exiting,
so it does not fail early while one side is still draining forwarded traffic.
Coverage is regression-oriented rather than percentage-gated in CI today. If you want a local line/branch coverage number, the supported path is:
That writes an HTML report under target/llvm-cov/html/ when cargo-llvm-cov is installed.
More detail on the test layers, what each suite covers, and the intended commands is in docs/wiki/Testing.md.
Usage
Linking from a C/C++ CMake project
# Example: building for an embedded target
set(SEDSNET_TARGET "thumbv7m-none-eabi" CACHE STRING "" FORCE)
set(SEDSNET_EMBEDDED_BUILD ON CACHE BOOL "" FORCE)
# Optional: always build the Rust crate in release mode, even if the parent CMake
# configuration is Debug. Useful when your top-level project stays Debug but you
# want an optimized telemetry library.
# set(SEDSNET_FORCE_RELEASE ON CACHE BOOL "" FORCE)
# set the sender name
set(SEDSNET_DEVICE_IDENTIFIER "FC26_MAIN" CACHE STRING "" FORCE)
# optional compile-time env overrides
set(SEDSNET_MAX_STACK_PAYLOAD "256" CACHE STRING "" FORCE)
set(SEDSNET_MAX_QUEUE_BUDGET "65536" CACHE STRING "" FORCE)
set(SEDSNET_MAX_RECENT_RX_IDS "256" CACHE STRING "" FORCE)
set(SEDSNET_ENABLE_CRYPTOGRAPHY ON CACHE BOOL "" FORCE)
# optional wrapper targets; leave both OFF to use only the raw static ABI header
set(SEDSNET_ENABLE_C_WRAPPER ON CACHE BOOL "" FORCE)
set(SEDSNET_ENABLE_CPP_WRAPPER OFF CACHE BOOL "" FORCE)
# Use the provided CMake glue
add_subdirectory(${CMAKE_SOURCE_DIR}/sedsnet sedsnet_build)
# Optional: prefer static linking even on host builds
# set(SEDSNET_PREFER_DYNAMIC OFF CACHE BOOL "" FORCE)
# Link against the imported target
target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE sedsnet::sedsnet)
# Optional convenience wrappers when enabled above:
# target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE sedsnet::c_wrapper)
# target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE sedsnet::cpp_wrapper)
Host CMake builds now prefer the shared Rust library when supported. Embedded builds still use the static library.
If you want the Rust crate to use the release profile regardless of the parent CMake config,
set SEDSNET_FORCE_RELEASE=ON before add_subdirectory(...). Otherwise the wrapper follows
CMAKE_BUILD_TYPE for single-config generators and defaults to debug for Debug builds.
- Configure telemetry schema at runtime. The default build contains only built-in internal endpoints/types for telemetry errors, reliable control, discovery, and time sync. Applications add user endpoints/types through the runtime APIs, by passing a JSON schema path/bytes to the registry, or by letting discovery sync schema entries from peers.
- The raw C ABI is always available through the static runtime-schema header. The C and C++ convenience wrappers are opt-in CMake targets for projects that want global router/relay helper APIs without passing raw handles through every application function.
Setting the device / platform name
Each build of sedsnet embeds a device identifier which appears in every telemetry packet header.
Rust resolves it using:
pub const DEVICE_IDENTIFIER: &str = match option_env!("DEVICE_IDENTIFIER") {
Some(v) => v,
None => "TEST_PLATFORM",
};
Set it globally using .cargo/config.toml (recommended)
Create:
# .cargo/config.toml
[env]
DEVICE_IDENTIFIER = "GROUND_STATION_26"
After this, any cargo build, cargo run, or CI build will embed "GROUND_STATION_26" automatically.
No build script changes required.
Setting the name from CMake
set(SEDSNET_DEVICE_IDENTIFIER "FC26_MAIN" CACHE STRING "" FORCE)
Note: This must be set before including the sedsnet CMake as a subdirectory.
Typical examples:
# Flight computer firmware
set(SEDSNET_DEVICE_IDENTIFIER "FC26_MAIN" CACHE STRING "" FORCE)
set(SEDSNET_TARGET "thumbv7em-none-eabihf" CACHE STRING "" FORCE)
set(SEDSNET_EMBEDDED_BUILD ON CACHE BOOL "" FORCE)
set(SEDSNET_MAX_STACK_PAYLOAD "256" CACHE STRING "" FORCE)
set(SEDSNET_MAX_QUEUE_BUDGET "65536" CACHE STRING "" FORCE)
set(SEDSNET_MAX_RECENT_RX_IDS "256" CACHE STRING "" FORCE)
# or
# Ground station app
set(SEDSNET_DEVICE_IDENTIFIER "GS26" CACHE STRING "" FORCE)
set(SEDSNET_TARGET "" CACHE STRING "" FORCE)
set(SEDSNET_EMBEDDED_BUILD OFF CACHE BOOL "" FORCE)
set(SEDSNET_MAX_QUEUE_BUDGET "65536" CACHE STRING "" FORCE)
set(SEDSNET_MAX_RECENT_RX_IDS "256" CACHE STRING "" FORCE)
Manually via build.py
# Host build
# Embedded build
Runtime telemetry schema
In v4, user telemetry schema is runtime state. DataEndpoint and DataType are stable numeric IDs
on the wire, but applications should normally look them up by string:
use ;
let radio = named;
let gps = named;
You can add schema entries directly:
use ;
let radio = register_endpoint_id_with_description?;
register_data_type_id_with_description?;
Or seed from JSON at runtime. Host builds can use:
SEDSNET_STATIC_SCHEMA_PATH=/path/to/telemetry_config.jsonSEDSNET_STATIC_IPC_SCHEMA_PATH=/path/to/ipc_config.json- Rust
register_schema_json_path(...)/register_schema_json_bytes(...) - C
seds_schema_register_json_file(...)/seds_schema_register_json_bytes(...) - Python
register_schema_json_file(...)/register_schema_json_bytes(...)
Default builds do not compile application JSON into the crate. Embedded builds can include
telemetry_config.json bytes only when the application provides that file locally before building;
those bytes are decoded through the normal runtime JSON parser.
The GUI editor still edits JSON schema files:
For board-local IPC/software-bus endpoints, seed a second JSON file with
SEDSNET_STATIC_IPC_SCHEMA_PATH or the explicit JSON registration API. IPC seed entries are
applied at runtime and treated as link-local when loaded through the IPC path.
Built-in internal endpoint/type names for telemetry errors, reliable control, discovery, and time
sync are reserved. Do not register user handlers for SEDSNET_DISCOVERY or SEDSNET_TIME_SYNC.
Network variables and E2E payloads
Network variables are latest-value caches keyed by data type. After registering or seeding schema, enable a type on the router and use the getter/setter pair:
let flight_state = named;
router.enable_network_variable?;
router.set_network_variable?;
let cached = router.get_network_variable?;
The setter commits the value to the network when permissions allow. The getter reads the cached copy
and internally requests the value if the cache has never seen it or is stale; user code does not
register a separate endpoint for network variables. Caches are tiered: any router that has enabled
or seen the variable can answer the refresh from its local cache, so reconnecting boards can resync
from a nearby node instead of always reaching the original producer/master. If a peer has the value,
the current packet is replayed through the normal endpoint handler so resync still looks like an
ordinary update. Register on_network_variable_update(...) when code needs a callback whenever an
inbound network update changes a variable cache.
Data types can also choose an E2E payload cryptography policy:
PreferOff: plaintext unless the router forces cryptographyPreferOn: encrypt when router crypto support is availableRequireOn: reject send/subscribe paths unless cryptography support is available
Router E2E modes are Disabled, RequiredOnly, Preferred, and ForceAll. With the default
cryptography feature, the default is Preferred; minimal builds that explicitly omit it default
to Disabled. Crypto providers are tried in this order: registered C provider, registered Rust provider, then
registered software fallback key. The provider path is intended for OS crypto, hardware accelerators,
secure elements, and Rust-only embedded projects. Compact managed credential helpers are available
for deployments where a master/root node issues short-lived board credentials instead of users
managing certificate files.
Routers and relays can export JSON memory-layout snapshots to profile queue pressure at runtime, including shared allocation, per-queue used/allocated bytes, reliable buffers, schema/discovery state, and network-variable cache bytes.
Topology exports describe the board graph directly: routers contains each discovered board and
its connected peers, while links contains deduplicated {source, target} edges for visual graph
rendering. SEDSnet-owned control endpoints such as SEDSNET_TIME_SYNC, SEDSNET_DISCOVERY, and
SEDSNET_ERROR are filtered out of user endpoint reachability fields.
Routers and relays can also export per-client stats by sender ID. The snapshot reports whether the
client is still connected, which sides currently reach it, last-seen/age timing, named reachable
endpoints, and packet/byte counters aggregated from the side(s) used to reach that client.
Explicit announce_leave(...) calls, and best-effort C free paths, send a
SEDSNET_DISCOVERY_LEAVE control packet so peers can remove a departing sender from topology right
away.
Note: The editor uses Tkinter. On some Linux distros you may need to install it
(e.g. sudo apt install python3-tk).
Example application schema JSON:
Example CMakeLists.txt
cmake_minimum_required(VERSION 3.22)
project(my_app C CXX)
add_executable(my_app
src/main.c
)
# ---- sedsnet configuration ----
set(SEDSNET_DEVICE_IDENTIFIER "FC26_MAIN" CACHE STRING "" FORCE)
set(SEDSNET_TARGET "thumbv7em-none-eabihf" CACHE STRING "" FORCE)
set(SEDSNET_EMBEDDED_BUILD ON CACHE BOOL "" FORCE)
set(SEDSNET_MAX_STACK_PAYLOAD "256" CACHE STRING "" FORCE)
set(SEDSNET_MAX_QUEUE_BUDGET "65536" CACHE STRING "" FORCE)
set(SEDSNET_MAX_RECENT_RX_IDS "256" CACHE STRING "" FORCE)
# Add the submodule/subtree root (adjust path as needed)
add_subdirectory(${CMAKE_SOURCE_DIR}/sedsnet sedsnet_build)
target_link_libraries(my_app PRIVATE sedsnet::sedsnet)
Using this repo as a subtree
git remote add sedsnet-upstream https://github.com/Rylan-Meilutis/sedsnet.git
git fetch sedsnet-upstream
git config subtree.sedsnet.remote sedsnet-upstream
git config subtree.sedsnet.branch main
git subtree add --prefix=sedsnet sedsnet-upstream main
To Switch branches:
Update:
Helper scripts:
Using this repo as a submodule
If you prefer a submodule instead of a subtree:
Initialize:
Update using helper scripts:
The scripts:
- read
submodule.sedsnet.branch - fetch
origin/<branch> - fast-forward the submodule repo
- stage & commit the updated submodule pointer in the parent repo
Embedded allocator + lock hook examples (C)
For embedded (--features embedded) builds, provide these symbols:
void *telemetryMalloc(size_t)void telemetryFree(void *)void telemetry_lock(void)void telemetry_unlock(void)void seds_error_msg(const char *, size_t)void telemetry_panic_hook(const char *, size_t)
Notes:
telemetry_lock/telemetry_unlockmust be recursive-safe.- Do not call router/logging APIs from ISR context (hooks may block).
- Keep allocator non-blocking/fail-fast on RTOS targets (
NO_WAITstyle).
// telemetry_hooks.c
/*
* Rust expects these functions to exist for heap allocations:
*
* void *telemetryMalloc(size_t);
* void telemetryFree(void *);
* void telemetry_lock(void);
* void telemetry_unlock(void);
* void seds_error_msg(const char *, const size_t);
* void telemetry_panic_hook(const char *, const size_t);
*
*/
void
void
void *
void
void
void
FreeRTOS example
// telemetry_hooks_freertos.c
/* Example allocator backend; replace with heap_4/5 or your own allocator. */
void *;
void ;
static SemaphoreHandle_t g_telemetry_lock = NULL;
void
void
void
void *
void
void
void
ThreadX example
// telemetry_hooks_threadx.c
static TX_BYTE_POOL *rust_byte_pool_external = NULL;
static TX_MUTEX g_telemetry_mutex;
static UINT g_telemetry_mutex_ready = 0U;
static TX_THREAD *g_telemetry_mutex_owner = TX_NULL;
static UINT g_telemetry_mutex_recursion = 0U;
void
void
void
void
void *
void
void
void
Call telemetry_init_lock() and telemetry_set_byte_pool(...) before any telemetry/router API usage.