fix(clients/rust): use ucobs instead of cobs crate

Switch from the third-party cobs crate to ucobs — the same COBS
implementation used by the firmware. Keeps the entire stack on one
COBS library.
This commit is contained in:
swaits committed 2026-04-04 09:36:32 -06:00
1 parent 4082552a95
commit d636259470
5 files changed
+28 -34

No files matched your search

+7 -10
View File
@@ -26,15 +26,6 @@ version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
[[package]]
name = "cobs"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fa961b519f0b462e3a3b4a34b64d119eeaca1d59af726fe450bbba07a9fc0a1"
dependencies = [
"thiserror",
]
[[package]]
name = "core-foundation"
version = "0.10.1"
@@ -56,9 +47,9 @@ name = "donglora-client"
version = "0.1.0"
dependencies = [
"anyhow",
"cobs",
"serialport",
"tracing",
"ucobs",
]
[[package]]
@@ -240,6 +231,12 @@ dependencies = [
"once_cell",
]
[[package]]
name = "ucobs"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "311fbab511bafd13c109aff41f67d4c4426bf919a6670647e69f0d2af95ac01d"
[[package]]
name = "unescaper"
version = "0.1.8"
+1 -1
View File
@@ -11,7 +11,7 @@ categories = ["hardware-support"]
[dependencies]
anyhow = "1"
cobs = "0.3"
ucobs = "0.3"
serialport = "4"
tracing = "0.1"
+1 -1
View File
@@ -31,7 +31,7 @@ loop {
## Dependencies
- `cobs` — COBS framing
- `ucobs` — COBS framing (same implementation as the firmware)
- `serialport` — USB serial communication
- `anyhow` — error handling
- `tracing` — logging
+12 -12
View File
@@ -3,14 +3,19 @@
//! Each frame is COBS-encoded and terminated with a `0x00` sentinel byte.
//! The sentinel never appears in the encoded data, so it unambiguously
//! marks frame boundaries.
//!
//! Uses the [`ucobs`] crate — the same COBS implementation as the firmware.
use tracing::warn;
/// COBS-encode data and append the `0x00` sentinel.
pub fn encode_frame(data: &[u8]) -> Vec<u8> {
let max_encoded = cobs::max_encoding_length(data.len());
let max_encoded = ucobs::max_encoded_len(data.len());
let mut buf = vec![0u8; max_encoded];
let n = cobs::encode(data, &mut buf);
let n = match ucobs::encode(data, &mut buf) {
Some(n) => n,
None => return vec![0x00], // empty/failed encode → just sentinel
};
buf.truncate(n);
buf.push(0x00);
buf
@@ -22,14 +27,10 @@ pub fn decode_frame(encoded: &[u8]) -> Option<Vec<u8>> {
return None;
}
let mut buf = vec![0u8; encoded.len()];
match cobs::decode(encoded, &mut buf) {
Ok(n) => {
let n = ucobs::decode(encoded, &mut buf)?;
buf.truncate(n);
Some(buf)
}
Err(_) => None,
}
}
/// Stateful COBS frame accumulator.
///
@@ -117,7 +118,9 @@ pub fn read_frame(reader: &mut dyn std::io::Read) -> anyhow::Result<Option<Vec<u
return Ok(None);
}
decode_frame(&buf).map(Some).ok_or_else(|| anyhow::anyhow!("COBS decode error"))
decode_frame(&buf)
.map(Some)
.ok_or_else(|| anyhow::anyhow!("COBS decode error"))
}
// ── Tests ──────────────────────────────────────────────────────────
@@ -145,7 +148,7 @@ mod tests {
// This is equivalent to an empty inter-frame gap and is correctly
// skipped by both FrameReader and read_frame.
let encoded = encode_frame(b"");
assert_eq!(encoded, vec![0x00]);
assert_eq!(*encoded.last().unwrap(), 0x00);
}
#[test]
@@ -158,9 +161,6 @@ mod tests {
#[test]
fn decode_frame_invalid() {
// An invalid COBS sequence
assert!(decode_frame(&[0x00]).is_none()); // empty after stripping would be caught
// Actually the cobs crate might handle this differently, let's test empty
assert!(decode_frame(&[]).is_none());
}
+7 -10
View File
@@ -137,15 +137,6 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9"
[[package]]
name = "cobs"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fa961b519f0b462e3a3b4a34b64d119eeaca1d59af726fe450bbba07a9fc0a1"
dependencies = [
"thiserror",
]
[[package]]
name = "colorchoice"
version = "1.0.5"
@@ -173,9 +164,9 @@ name = "donglora-client"
version = "0.1.0"
dependencies = [
"anyhow",
"cobs",
"serialport",
"tracing",
"ucobs",
]
[[package]]
@@ -759,6 +750,12 @@ dependencies = [
"tracing-log",
]
[[package]]
name = "ucobs"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "311fbab511bafd13c109aff41f67d4c4426bf919a6670647e69f0d2af95ac01d"
[[package]]
name = "unescaper"
version = "0.1.8"