Simple SOME/IP is a Rust library implementing the SOME/IP automotive communication protocol — remote procedure calls, event notifications, and wire format serialization. Based on the Open SOME/IP Specification.
The library supports both std and no_std environments, making it suitable for embedded targets as well as host-side tooling and scripting.
no_stdcompatible —protocol,traits,transport, ande2emodules work without the standard library- Service Discovery — SD entry/option encoding and decoding via fixed-capacity
heaplesscollections (no heap allocation) - End-to-End protection — Profile 4 (CRC-32) and Profile 5 (CRC-16) with zero-allocation APIs
- Executor-agnostic transport traits —
TransportSocket,TransportFactory,Timer,Spawner(defaulttokioimpls behind feature gates) - Async client and server — tokio-based, gated behind optional feature flags
embedded-iotraits for serialization — abstracts overstd::io::Read/Write
protocol— Wire format layer: SOME/IP header,MessageId,MessageType,ReturnCode, SD entries/optionstraits—WireFormatandPayloadWireFormattraits for custom message typestransport— Executor-agnostic UDP socket / factory / timer / spawner traits (no_std-compatible)e2e— End-to-End protection profiles (always available, no heap allocation)tokio_transport— Defaultstd + tokioimpls of the transport traits (requiresfeature = "client-tokio"orfeature = "server-tokio")client— High-level async client trait surface (requiresfeature = "client"; addclient-tokiofor theClient::newconvenience constructor)server— Async server with SD announcements and event publishing (requiresfeature = "server"; addserver-tokiofor theServer::newconvenience constructor)
Add to your Cargo.toml:
[dependencies]
# Default — includes std, thiserror, and tracing
simple-someip = "0.8"
# no_std only (protocol/transport/E2E/traits, no heap allocation)
simple-someip = { version = "0.8", default-features = false }
# Client only (with tokio convenience constructors)
simple-someip = { version = "0.8", features = ["client-tokio"] }
# Server only (with tokio convenience constructors)
simple-someip = { version = "0.8", features = ["server-tokio"] }
# Both client and server
simple-someip = { version = "0.8", features = ["client-tokio", "server-tokio"] }| Feature | Default | Description |
|---|---|---|
std |
yes | Enables thiserror, tracing, and embedded-io/std. The Arc<Mutex<E2ERegistry>> / Arc<RwLock<…>> default lock-handle impls (used by the tokio backends) live behind this gate. |
client |
no | Client trait surface. Pure no_std-clean (does not pull extern crate alloc). Caller supplies trait impls for transport / channels / spawner / timer / lock handles. |
client-tokio |
no | Adds Client::new / TokioSpawner / TokioTransport defaults; implies client + std + tokio + socket2. |
server |
no | Server trait surface. Pulls extern crate alloc (for Arc<EventPublisher> / Arc<F::Socket>); on no_std, downstream consumers must provide a #[global_allocator]. |
server-tokio |
no | Adds Server::new / TokioTimer / TokioTransport defaults; implies server + std + tokio + socket2. |
bare_metal |
no | Activates embassy-sync, no-alloc static_channels module, AtomicInterfaceHandle, StaticE2EHandle, and StaticSubscriptionHandle — all five pure no_std (no allocator required). See examples/bare_metal_client and examples/bare_metal_server; verify with cargo build -p bare_metal_client (NOT cargo build --workspace, which can unify features). |
embassy_channels |
no | Heap-backed EmbassySyncChannels (implies bare_metal + alloc). Useful for tests before sizing static pools. |
By default the crate enables std. To use in a no_std environment (e.g., embedded targets), disable default features with default-features = false. In that mode the protocol, traits, transport, and e2e modules are always available; client / server are usable too (the trait surfaces compile in pure no_std), but the tokio convenience defaults (Client::new, Server::new) live behind client-tokio / server-tokio and require std. The cargo build --target thumbv7em-none-eabihf --no-default-features --features client,server,bare_metal cross-build is verified in CI on every PR.
These examples require the client-tokio and server-tokio features respectively.
use simple_someip::{Client, ClientUpdate, RawPayload};
use std::net::Ipv4Addr;
#[tokio::main]
async fn main() {
// Client::new returns a Clone-able handle, an update stream, and
// the run-loop future. The future must be actively driven — either
// spawned on the runtime as shown below, or awaited alongside your
// own work in a `tokio::select!`. If the future is never polled,
// Client method calls that send commands over the control channel
// will hang indefinitely waiting on their oneshot response.
// `Error::Shutdown` is returned only once the run-loop future has
// been dropped or its task cancelled.
let (client, mut updates, run) =
Client::<RawPayload, _, _, _>::new(Ipv4Addr::new(192, 168, 1, 100));
let _run_task = tokio::spawn(run);
// Bind the SD multicast socket to discover services
client.bind_discovery().await.unwrap();
// Receive discovery, unicast, and error updates
while let Some(update) = updates.recv().await {
match update {
ClientUpdate::DiscoveryUpdated(msg) => { /* SD message */ }
ClientUpdate::Unicast { message, e2e_status } => { /* unicast reply */ }
ClientUpdate::SenderRebooted(addr) => { /* remote reboot detected */ }
ClientUpdate::Error(err) => { /* error */ }
}
}
}use simple_someip::server::{Server, ServerConfig};
use std::net::Ipv4Addr;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let config = ServerConfig::new(Ipv4Addr::new(192, 168, 1, 200), 30500, 0x1234, 1);
let mut server = Server::new(config).await?;
let announce_handle = tokio::spawn(server.announcement_loop()?);
let publisher = server.publisher();
let run_handle = tokio::spawn(async move { server.run().await });
// Publish events to subscribers, e.g.:
// publisher.publish_event(0x1234, 1, 0x01, &message).await?;
tokio::select! {
res = announce_handle => eprintln!("announcement loop exited unexpectedly: {res:?}"),
res = run_handle => eprintln!("server run loop exited: {res:?}"),
}
Ok(())
}Examples are provided in the examples/ directory. To run the discovery client example:
cargo run -p discovery_client