From 3bb6c936c8dbae1c153ee1ca40ef1db8a085bb86 Mon Sep 17 00:00:00 2001 From: Mikkeli Date: Thu, 15 Oct 2026 21:21:49 +0900 Subject: [PATCH] decoder: signed layouts (two's complement, lengths 8 and 16) Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01DDwfd6Ki8UfG4hK6W5YpJz --- src/decoder/layout.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/decoder/layout.rs b/src/decoder/layout.rs index 32ed075..2159afe 100644 --- a/src/decoder/layout.rs +++ b/src/decoder/layout.rs @@ -21,6 +21,8 @@ pub struct Layout { pub bit: u32, /// Length 16 only: true = `byte` is the most significant. pub big: bool, + /// Lengths 8 and 16: two's complement (`"signed": true` in the can block). + pub signed: bool, pub scale: f64, pub offset: f64, pub kind: Kind, @@ -48,7 +50,12 @@ impl Layout { Some(match self.kind { Kind::Bool => Value::Bool(raw != 0), Kind::Number => { - let v = raw as f64 * self.scale + self.offset; + let raw = match (self.signed, self.length) { + (true, 8) => raw as u8 as i8 as f64, + (true, 16) => raw as u16 as i16 as f64, + _ => raw as f64, + }; + let v = raw * self.scale + self.offset; // Three decimals: 0.4 × 98 should read 39.2, not 39.200000000000003. let v = (v * 1000.0).round() / 1000.0; serde_json::Number::from_f64(v).map(Value::Number).unwrap_or(Value::Null) @@ -97,6 +104,7 @@ pub fn load(registry: &str) -> Result, String> { length, bit, big, + signed: c["signed"].as_bool().unwrap_or(false), scale: c["scale"].as_f64().unwrap_or(1.0), offset: c["offset"].as_f64().unwrap_or(0.0), kind, @@ -136,6 +144,10 @@ mod tests { let pedal = &one(json!({"id": "0x210", "byte": 0, "length": 8, "scale": 0.4}), "number").unwrap()[0]; assert_eq!(pedal.value(&[0xFA]), Some(json!(100.0))); assert_eq!(pedal.value(&[98]), Some(json!(39.2))); + // Signed: 0C0's steering angle, 0.1° per count, little-endian two's complement. + let steer = &one(json!({"id": "0x0C0", "byte": 0, "length": 16, "order": "little", "signed": true, "scale": 0.1}), "number").unwrap()[0]; + assert_eq!(steer.value(&[0x41, 0xED]), Some(json!(-479.9))); // 0xED41 = -4799 + assert_eq!(steer.value(&[0x69, 0x12]), Some(json!(471.3))); // 0x1269 = 4713 let brake = &one(json!({"id": "0x231", "byte": 4, "bit": 1, "length": 1}), "boolean").unwrap()[0]; assert_eq!(brake.value(&[0, 0, 0, 0, 0x02]), Some(json!(true))); assert_eq!(brake.value(&[0, 0, 0, 0, 0xFD]), Some(json!(false)));