swaits 6937ad47ba feat!: Protocol v2 client rewrite with Dongle/Session model
The full 1.0 client surface, matching the protocol v2 wire definitions from donglora-protocol 1.0.0.

* Public API is now async. The blocking Client<T: Transport> is replaced by Dongle (from donglora_client::connect / connect_with / ConnectOptions).

* src/client.rs and src/codec.rs are removed in favor of src/dongle.rs (high-level surface), src/session.rs (per-client tag/slot state), src/retry.rs (RetryPolicy + tx_with_retry), src/errors.rs (thiserror-based ClientError / ClientResult). src/protocol.rs is replaced by direct donglora-protocol imports.

* Transport is now tokio-serial for USB and tokio::net::{UnixStream, TcpStream} for mux, replacing the blocking serial + shim model.

* Dongle::tx_with_retry(data, &RetryPolicy) implements PROTOCOL.md §6.10 randomized backoff for CHANNEL_BUSY / EBUSY, returning a TxOutcome with per-attempt trace.

* Background keepalive task pings every 500 ms on host idle, tracking the 1 s inactivity timeout from §3.4 with 2x margin. Disable via ConnectOptions::keepalive(false).

* Auto-recovery from ERR(ENOTCONFIGURED): the Dongle caches the last SET_CONFIG and silently re-applies on session drop, retrying once.

* Error taxonomy switches from anyhow to thiserror. Transport-level conditions (Timeout, TransportClosed, ReaderExited, BadFrame) are first-class.

* Examples rewritten for the async API: examples/ping.rs, examples/tx.rs, examples/rx.rs all target the MeshCore US preset (910.525 MHz / BW 62.5 / SF 7 / CR 4/5 / sync 0x1424 / 20 dBm). examples/common/mod.rs holds the shared helper.

* tests/vectors.rs gains protocol-level roundtrip coverage anchored to the published donglora-protocol 1.0.0 types.
2026-04-22 09:45:38 -06:00
2026-04-06 21:15:35 -06:00

DongLoRa Rust Client

Rust client library for talking to a DongLoRa device — either directly over USB or through a mux daemon.

Install

[dependencies]
donglora-client = "0.2"

Quick Start

use donglora_client::*;

let mut client = connect_default()?;
client.set_config(RadioConfig::default())?;
client.start_rx()?;

loop {
    if let Some(Response::RxPacket { rssi, snr, payload }) = client.recv()? {
        println!("RX rssi={rssi} snr={snr} len={}", payload.len());
    }
}

All connect functions automatically validate the device by pinging it, so you'll get a clear error immediately if the port isn't a real DongLoRa.

What's in Here

  • src/protocol.rs — wire protocol types (RadioConfig, Command, Response, ErrorCode)
  • src/codec.rs — COBS framing, frame accumulator
  • src/discovery.rs — USB VID:PID device discovery
  • src/transport.rs — serial and mux socket transports
  • src/client.rs — high-level Client<T> with send/recv
  • src/connect.rs — auto-detection (mux socket, TCP, direct USB)

Connection Priority

[connect] and [try_connect] try these in order:

  1. TCP mux — via DONGLORA_MUX_TCP env var
  2. Unix socket mux — checks $XDG_RUNTIME_DIR/donglora/mux.sock or /tmp/donglora-mux.sock
  3. Direct USB serial — auto-detects by VID:PID

try_connect returns an error immediately if no device is found. connect blocks until a USB device appears.

Dependencies

  • ucobs — COBS framing (same implementation as the firmware)
  • serialport — USB serial communication
  • anyhow — error handling
  • tracing — logging
S
Description
No description provided
Readme MIT
128 KiB
0 Stars 1 Watchers 0 Forks
Languages
Rust 99.3%
Just 0.7%