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.
This commit is contained in:
19 files changed
+2897
-1605
No files matched your search
+61
-28
@@ -1,43 +1,76 @@
|
||||
//! DongLoRa host library — connect, configure, send/receive LoRa packets.
|
||||
//!
|
||||
//! Implements the DongLoRa USB protocol (COBS-framed fixed-size LE).
|
||||
//! See the [`protocol`] module for wire types and constants.
|
||||
//! Implements the DongLoRa Protocol v2 on top of the
|
||||
//! [`donglora-protocol`](donglora_protocol) wire crate. All I/O is
|
||||
//! async via tokio; the public surface mirrors the Python client in
|
||||
//! `client-py/`.
|
||||
//!
|
||||
//! # Quick start
|
||||
//!
|
||||
//! ```no_run
|
||||
//! use donglora_client::*;
|
||||
//! # async fn demo() -> Result<(), donglora_client::ClientError> {
|
||||
//! use donglora_client::{
|
||||
//! connect, LoRaBandwidth, LoRaCodingRate, LoRaConfig, LoRaHeaderMode, Modulation,
|
||||
//! };
|
||||
//!
|
||||
//! 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());
|
||||
//! }
|
||||
//! }
|
||||
//! # Ok::<(), anyhow::Error>(())
|
||||
//! let dongle = connect().await?;
|
||||
//! dongle.set_config(Modulation::LoRa(LoRaConfig {
|
||||
//! freq_hz: 910_525_000,
|
||||
//! sf: 7,
|
||||
//! bw: LoRaBandwidth::Khz62,
|
||||
//! cr: LoRaCodingRate::Cr4_5,
|
||||
//! preamble_len: 16,
|
||||
//! sync_word: 0x1424,
|
||||
//! tx_power_dbm: 20,
|
||||
//! header_mode: LoRaHeaderMode::Explicit,
|
||||
//! payload_crc: true,
|
||||
//! iq_invert: false,
|
||||
//! })).await?;
|
||||
//! dongle.tx(b"hello world").await?;
|
||||
//! # Ok(()) }
|
||||
//! ```
|
||||
//!
|
||||
//! # Module layout
|
||||
//!
|
||||
//! - [`connect`] — auto-discovery + [`ConnectOptions`] builder.
|
||||
//! - [`dongle`] — public [`Dongle`] radio session type.
|
||||
//! - [`session`] — internal async plumbing (not public).
|
||||
//! - [`transport`] — tokio-based byte-stream transports.
|
||||
//! - [`errors`] — [`ClientError`] taxonomy.
|
||||
//! - [`retry`] — [`RetryPolicy`] + [`TxOutcome`] for `tx_with_retry`.
|
||||
//! - [`discovery`] — USB VID/PID scan + async `wait_for_device`.
|
||||
|
||||
#![forbid(unsafe_code)]
|
||||
|
||||
pub mod client;
|
||||
pub mod codec;
|
||||
pub mod connect;
|
||||
pub mod discovery;
|
||||
pub mod protocol;
|
||||
pub mod dongle;
|
||||
pub mod errors;
|
||||
pub mod retry;
|
||||
pub mod session;
|
||||
pub mod transport;
|
||||
|
||||
// Flat re-exports for convenience
|
||||
pub use client::Client;
|
||||
pub use codec::{FrameReader, decode_frame, encode_frame, read_frame};
|
||||
pub use connect::{connect, connect_default, connect_mux_auto, default_socket_path, try_connect};
|
||||
pub use discovery::{USB_PID, USB_VID, find_port, wait_for_device};
|
||||
pub use protocol::{
|
||||
Bandwidth, Command, ErrorCode, MAX_PAYLOAD, PREAMBLE_DEFAULT, RADIO_CONFIG_SIZE, RadioConfig, Response,
|
||||
TX_POWER_MAX,
|
||||
};
|
||||
pub use transport::{AnyTransport, MuxTransport, SerialTransport, Transport};
|
||||
// ── Flat re-exports for convenience ─────────────────────────────────
|
||||
|
||||
#[cfg(unix)]
|
||||
pub use connect::mux_connect;
|
||||
pub use connect::mux_tcp_connect;
|
||||
pub use connect::mux_unix_connect;
|
||||
pub use connect::{
|
||||
ConnectOptions, connect, connect_mux_auto, connect_mux_auto_with, connect_with, default_socket_path,
|
||||
find_mux_socket, mux_tcp_connect, try_connect, try_connect_with,
|
||||
};
|
||||
pub use discovery::{USB_PID, USB_VID, find_port, wait_for_device};
|
||||
pub use dongle::{Dongle, KEEPALIVE_INTERVAL, TransportKind};
|
||||
pub use errors::{ClientError, ClientResult};
|
||||
pub use retry::{RetryPolicy, TxAttempt, TxOutcome};
|
||||
#[cfg(unix)]
|
||||
pub use transport::UnixSocketTransport;
|
||||
pub use transport::{AnyTransport, SerialTransport, TcpTransport, Transport};
|
||||
|
||||
// Re-export the protocol crate's user-facing types so callers don't need
|
||||
// to add `donglora-protocol` as a direct dep.
|
||||
pub use donglora_protocol::{
|
||||
Command, DeviceMessage, ErrorCode, FlrcBitrate, FlrcBt, FlrcCodingRate, FlrcConfig, FlrcPreambleLen, FskConfig,
|
||||
Info, LoRaBandwidth, LoRaCodingRate, LoRaConfig, LoRaHeaderMode, LrFhssBandwidth, LrFhssCodingRate, LrFhssConfig,
|
||||
LrFhssGrid, Modulation, ModulationId, OkPayload, Owner, RadioChipId, RxOrigin, RxPayload, SetConfigResult,
|
||||
SetConfigResultCode, TxDonePayload, TxFlags, TxResult, cap,
|
||||
};
|
||||
Reference in new issue
Block a user