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:
5 files changed
+28
-34
No files matched your search
Generated
+7
-10
@@ -26,15 +26,6 @@ version = "1.0.4"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
|
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cobs"
|
|
||||||
version = "0.3.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "0fa961b519f0b462e3a3b4a34b64d119eeaca1d59af726fe450bbba07a9fc0a1"
|
|
||||||
dependencies = [
|
|
||||||
"thiserror",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "core-foundation"
|
name = "core-foundation"
|
||||||
version = "0.10.1"
|
version = "0.10.1"
|
||||||
@@ -56,9 +47,9 @@ name = "donglora-client"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"cobs",
|
|
||||||
"serialport",
|
"serialport",
|
||||||
"tracing",
|
"tracing",
|
||||||
|
"ucobs",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -240,6 +231,12 @@ dependencies = [
|
|||||||
"once_cell",
|
"once_cell",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ucobs"
|
||||||
|
version = "0.3.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "311fbab511bafd13c109aff41f67d4c4426bf919a6670647e69f0d2af95ac01d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unescaper"
|
name = "unescaper"
|
||||||
version = "0.1.8"
|
version = "0.1.8"
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ categories = ["hardware-support"]
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1"
|
anyhow = "1"
|
||||||
cobs = "0.3"
|
ucobs = "0.3"
|
||||||
serialport = "4"
|
serialport = "4"
|
||||||
tracing = "0.1"
|
tracing = "0.1"
|
||||||
|
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ loop {
|
|||||||
|
|
||||||
## Dependencies
|
## Dependencies
|
||||||
|
|
||||||
- `cobs` — COBS framing
|
- `ucobs` — COBS framing (same implementation as the firmware)
|
||||||
- `serialport` — USB serial communication
|
- `serialport` — USB serial communication
|
||||||
- `anyhow` — error handling
|
- `anyhow` — error handling
|
||||||
- `tracing` — logging
|
- `tracing` — logging
|
||||||
+12
-12
@@ -3,14 +3,19 @@
|
|||||||
//! Each frame is COBS-encoded and terminated with a `0x00` sentinel byte.
|
//! Each frame is COBS-encoded and terminated with a `0x00` sentinel byte.
|
||||||
//! The sentinel never appears in the encoded data, so it unambiguously
|
//! The sentinel never appears in the encoded data, so it unambiguously
|
||||||
//! marks frame boundaries.
|
//! marks frame boundaries.
|
||||||
|
//!
|
||||||
|
//! Uses the [`ucobs`] crate — the same COBS implementation as the firmware.
|
||||||
|
|
||||||
use tracing::warn;
|
use tracing::warn;
|
||||||
|
|
||||||
/// COBS-encode data and append the `0x00` sentinel.
|
/// COBS-encode data and append the `0x00` sentinel.
|
||||||
pub fn encode_frame(data: &[u8]) -> Vec<u8> {
|
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 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.truncate(n);
|
||||||
buf.push(0x00);
|
buf.push(0x00);
|
||||||
buf
|
buf
|
||||||
@@ -22,13 +27,9 @@ pub fn decode_frame(encoded: &[u8]) -> Option<Vec<u8>> {
|
|||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
let mut buf = vec![0u8; encoded.len()];
|
let mut buf = vec![0u8; encoded.len()];
|
||||||
match cobs::decode(encoded, &mut buf) {
|
let n = ucobs::decode(encoded, &mut buf)?;
|
||||||
Ok(n) => {
|
|
||||||
buf.truncate(n);
|
buf.truncate(n);
|
||||||
Some(buf)
|
Some(buf)
|
||||||
}
|
|
||||||
Err(_) => None,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Stateful COBS frame accumulator.
|
/// 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);
|
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 ──────────────────────────────────────────────────────────
|
// ── Tests ──────────────────────────────────────────────────────────
|
||||||
@@ -145,7 +148,7 @@ mod tests {
|
|||||||
// This is equivalent to an empty inter-frame gap and is correctly
|
// This is equivalent to an empty inter-frame gap and is correctly
|
||||||
// skipped by both FrameReader and read_frame.
|
// skipped by both FrameReader and read_frame.
|
||||||
let encoded = encode_frame(b"");
|
let encoded = encode_frame(b"");
|
||||||
assert_eq!(encoded, vec![0x00]);
|
assert_eq!(*encoded.last().unwrap(), 0x00);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -158,9 +161,6 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn decode_frame_invalid() {
|
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());
|
assert!(decode_frame(&[]).is_none());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Generated
+7
-10
@@ -137,15 +137,6 @@ version = "1.1.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9"
|
checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cobs"
|
|
||||||
version = "0.3.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "0fa961b519f0b462e3a3b4a34b64d119eeaca1d59af726fe450bbba07a9fc0a1"
|
|
||||||
dependencies = [
|
|
||||||
"thiserror",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "colorchoice"
|
name = "colorchoice"
|
||||||
version = "1.0.5"
|
version = "1.0.5"
|
||||||
@@ -173,9 +164,9 @@ name = "donglora-client"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"cobs",
|
|
||||||
"serialport",
|
"serialport",
|
||||||
"tracing",
|
"tracing",
|
||||||
|
"ucobs",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -759,6 +750,12 @@ dependencies = [
|
|||||||
"tracing-log",
|
"tracing-log",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ucobs"
|
||||||
|
version = "0.3.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "311fbab511bafd13c109aff41f67d4c4426bf919a6670647e69f0d2af95ac01d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unescaper"
|
name = "unescaper"
|
||||||
version = "0.1.8"
|
version = "0.1.8"
|
||||||
|
|||||||
Reference in new issue
Block a user