refactor: consume donglora-protocol as a path dep
Pulls the wire protocol types and COBS framing out of firmware and into the sibling ../protocol crate so client-rs, mux-rs, and bridge can share them. Firmware's src/protocol.rs is now a thin re-export shim preserving every crate::protocol::\* call site; src/host/framing.rs drops the in-tree CobsDecoder / cobs_encode_response and re-exports the codec, keeping only route_command (which needs embassy channels). All seven board features still build clean, cargo fmt clean, cargo test green.
This commit is contained in:
4 files changed
+27
-781
No files matched your search
+5
-75
@@ -2,86 +2,16 @@
|
||||
//!
|
||||
//! Both `usb_task` and `uart_task` use these helpers for frame
|
||||
//! accumulation, response encoding, and command routing.
|
||||
//!
|
||||
//! The actual codec lives in `donglora-protocol` so host crates can
|
||||
//! reuse it; this module re-exports the codec and owns the
|
||||
//! firmware-only [`route_command`] (which touches embassy channels).
|
||||
|
||||
use defmt::warn;
|
||||
pub use donglora_protocol::framing::{cobs_encode_response, CobsDecoder, MAX_FRAME};
|
||||
|
||||
use crate::channel::{CommandChannel, DisplayCommand, DisplayCommandChannel, ResponseChannel};
|
||||
use crate::protocol::{Command, ErrorCode, Response};
|
||||
|
||||
/// Maximum COBS frame size (bytes).
|
||||
pub const MAX_FRAME: usize = 512;
|
||||
|
||||
// Worst case: tag(1) + rssi(2) + snr(2) + len(2) + payload(256) = 263 bytes.
|
||||
// COBS adds ceil(263/254)+1 = 3 bytes. 266 < 512. Plenty of room.
|
||||
const _: () = assert!(
|
||||
MAX_FRAME >= crate::protocol::MAX_PAYLOAD + 64,
|
||||
"MAX_FRAME too small for max payload + COBS overhead"
|
||||
);
|
||||
|
||||
/// Decodes COBS-framed commands from a byte stream.
|
||||
pub struct CobsDecoder {
|
||||
buf: [u8; MAX_FRAME],
|
||||
len: usize,
|
||||
}
|
||||
|
||||
impl CobsDecoder {
|
||||
pub const fn new() -> Self {
|
||||
Self {
|
||||
buf: [0u8; MAX_FRAME],
|
||||
len: 0,
|
||||
}
|
||||
}
|
||||
|
||||
/// Reset the accumulator (discard partial frame).
|
||||
pub fn reset(&mut self) {
|
||||
self.len = 0;
|
||||
}
|
||||
|
||||
/// Feed a chunk of bytes, calling `on_command` for each decoded command.
|
||||
pub fn feed(&mut self, data: &[u8], mut on_command: impl FnMut(Command)) {
|
||||
for &byte in data {
|
||||
if byte == 0x00 {
|
||||
// End of COBS frame — decode and dispatch
|
||||
if self.len > 0 {
|
||||
let mut decode_buf = [0u8; MAX_FRAME];
|
||||
if let Some(decoded_len) = ucobs::decode(&self.buf[..self.len], &mut decode_buf)
|
||||
{
|
||||
if let Some(cmd) = Command::from_bytes(&decode_buf[..decoded_len]) {
|
||||
on_command(cmd);
|
||||
}
|
||||
}
|
||||
}
|
||||
self.len = 0;
|
||||
} else if self.len < MAX_FRAME {
|
||||
self.buf[self.len] = byte;
|
||||
self.len += 1;
|
||||
} else {
|
||||
// Frame too large — discard
|
||||
self.len = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// COBS-encode a response into `encode_buf` with trailing 0x00 sentinel.
|
||||
///
|
||||
/// Returns the slice to send (encoded frame + sentinel), or `None` on overflow.
|
||||
pub fn cobs_encode_response<'a>(
|
||||
response: Response,
|
||||
write_buf: &mut [u8; MAX_FRAME],
|
||||
encode_buf: &'a mut [u8; MAX_FRAME],
|
||||
) -> Option<&'a [u8]> {
|
||||
let raw_len = response.write_to(write_buf);
|
||||
let encoded_len = ucobs::encode(&write_buf[..raw_len], encode_buf).unwrap_or(0);
|
||||
if encoded_len < encode_buf.len() {
|
||||
encode_buf[encoded_len] = 0x00;
|
||||
Some(&encode_buf[..encoded_len + 1])
|
||||
} else {
|
||||
warn!("COBS encode buffer overflow");
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Route a parsed command to the appropriate handler.
|
||||
///
|
||||
/// Display and MAC commands are handled locally (response sent immediately).
|
||||
|
||||
Reference in new issue
Block a user