From 874f3607cbf9798ae271912c0cdb680c59bfd43a Mon Sep 17 00:00:00 2001 From: Dillon McEwan Date: Wed, 3 Jul 2024 15:09:12 -0700 Subject: [PATCH] Fix issue with decoding signed values of non-standard length --- src/lib.rs | 12 +- testing/can-messages/src/messages.rs | 228 ++++++++++++++++++++++++++- testing/can-messages/tests/all.rs | 19 +++ testing/dbc-examples/example.dbc | 6 + 4 files changed, 251 insertions(+), 14 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index bd3740e..4ba59ec 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -832,7 +832,7 @@ fn signal_from_payload(mut w: impl Write, signal: &Signal, msg: &Message) -> Res format!( "self.raw.view_bits::()[{start}..{end}].load_le::<{typ}>()", - typ = signal_to_rust_uint(signal), + typ = signal_to_rust_int(signal), start = start_bit, end = end_bit, ) @@ -842,7 +842,7 @@ fn signal_from_payload(mut w: impl Write, signal: &Signal, msg: &Message) -> Res format!( "self.raw.view_bits::()[{start}..{end}].load_be::<{typ}>()", - typ = signal_to_rust_uint(signal), + typ = signal_to_rust_int(signal), start = start_bit, end = end_bit ) @@ -852,14 +852,6 @@ fn signal_from_payload(mut w: impl Write, signal: &Signal, msg: &Message) -> Res writeln!(&mut w, r#"let signal = {};"#, read_fn)?; writeln!(&mut w)?; - if *signal.value_type() == can_dbc::ValueType::Signed { - writeln!( - &mut w, - "let signal = {}::from_ne_bytes(signal.to_ne_bytes());", - signal_to_rust_int(signal) - )?; - }; - if signal.signal_size == 1 { writeln!(&mut w, "signal == 1")?; } else if signal_is_float_in_rust(signal) { diff --git a/testing/can-messages/src/messages.rs b/testing/can-messages/src/messages.rs index 98b87cc..bf0b6d4 100644 --- a/testing/can-messages/src/messages.rs +++ b/testing/can-messages/src/messages.rs @@ -42,6 +42,10 @@ pub enum Messages { LargerIntsWithOffsets(LargerIntsWithOffsets), /// MsgWithoutSignals MsgWithoutSignals(MsgWithoutSignals), + /// TruncatedBeSignal + TruncatedBeSignal(TruncatedBeSignal), + /// TruncatedLeSignal + TruncatedLeSignal(TruncatedLeSignal), } impl Messages { @@ -59,6 +63,8 @@ impl Messages { 1344 => Messages::NegativeFactorTest(NegativeFactorTest::try_from(payload)?), 1338 => Messages::LargerIntsWithOffsets(LargerIntsWithOffsets::try_from(payload)?), 513 => Messages::MsgWithoutSignals(MsgWithoutSignals::try_from(payload)?), + 9001 => Messages::TruncatedBeSignal(TruncatedBeSignal::try_from(payload)?), + 9002 => Messages::TruncatedLeSignal(TruncatedLeSignal::try_from(payload)?), n => return Err(CanError::UnknownMessageId(n)), }; Ok(res) @@ -159,9 +165,8 @@ impl Foo { /// - Value type: Signed #[inline(always)] pub fn current_raw(&self) -> f32 { - let signal = self.raw.view_bits::()[0..16].load_le::(); + let signal = self.raw.view_bits::()[0..16].load_le::(); - let signal = i16::from_ne_bytes(signal.to_ne_bytes()); let factor = 0.0625_f32; let offset = 0_f32; (signal as f32) * factor + offset @@ -1930,9 +1935,8 @@ impl NegativeFactorTest { /// - Value type: Signed #[inline(always)] pub fn width_more_than_min_max_raw(&self) -> i16 { - let signal = self.raw.view_bits::()[16..26].load_le::(); + let signal = self.raw.view_bits::()[16..26].load_le::(); - let signal = i16::from_ne_bytes(signal.to_ne_bytes()); let factor = 1; let signal = signal as i16; i16::from(signal).saturating_mul(factor).saturating_add(0) @@ -2215,6 +2219,222 @@ impl<'a> Arbitrary<'a> for MsgWithoutSignals { } } +/// TruncatedBeSignal +/// +/// - ID: 9001 (0x2329) +/// - Size: 8 bytes +/// - Transmitter: Ipsum +#[derive(Clone, Copy)] +pub struct TruncatedBeSignal { + raw: [u8; 8], +} + +impl TruncatedBeSignal { + pub const MESSAGE_ID: u32 = 9001; + + pub const FOO_MIN: i16 = -100_i16; + pub const FOO_MAX: i16 = 100_i16; + + /// Construct new TruncatedBeSignal from values + pub fn new(foo: i16) -> Result { + let mut res = Self { raw: [0u8; 8] }; + res.set_foo(foo)?; + Ok(res) + } + + /// Access message payload raw value + pub fn raw(&self) -> &[u8; 8] { + &self.raw + } + + /// Foo + /// + /// - Min: -100 + /// - Max: 100 + /// - Unit: "" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn foo(&self) -> i16 { + self.foo_raw() + } + + /// Get raw value of Foo + /// + /// - Start bit: 0 + /// - Signal size: 12 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: BigEndian + /// - Value type: Signed + #[inline(always)] + pub fn foo_raw(&self) -> i16 { + let signal = self.raw.view_bits::()[7..19].load_be::(); + + let factor = 1; + let signal = signal as i16; + i16::from(signal).saturating_mul(factor).saturating_add(0) + } + + /// Set value of Foo + #[inline(always)] + pub fn set_foo(&mut self, value: i16) -> Result<(), CanError> { + if value < -100_i16 || 100_i16 < value { + return Err(CanError::ParameterOutOfRange { message_id: 9001 }); + } + let factor = 1; + let value = value + .checked_sub(0) + .ok_or(CanError::ParameterOutOfRange { message_id: 9001 })?; + let value = (value / factor) as i16; + + let value = u16::from_ne_bytes(value.to_ne_bytes()); + self.raw.view_bits_mut::()[7..19].store_be(value); + Ok(()) + } +} + +impl core::convert::TryFrom<&[u8]> for TruncatedBeSignal { + type Error = CanError; + + #[inline(always)] + fn try_from(payload: &[u8]) -> Result { + if payload.len() != 8 { + return Err(CanError::InvalidPayloadSize); + } + let mut raw = [0u8; 8]; + raw.copy_from_slice(&payload[..8]); + Ok(Self { raw }) + } +} + +impl core::fmt::Debug for TruncatedBeSignal { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + if f.alternate() { + f.debug_struct("TruncatedBeSignal") + .field("foo", &self.foo()) + .finish() + } else { + f.debug_tuple("TruncatedBeSignal").field(&self.raw).finish() + } + } +} + +#[cfg(feature = "arb")] +impl<'a> Arbitrary<'a> for TruncatedBeSignal { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + let foo = u.int_in_range(-100..=100)?; + TruncatedBeSignal::new(foo).map_err(|_| arbitrary::Error::IncorrectFormat) + } +} + +/// TruncatedLeSignal +/// +/// - ID: 9002 (0x232a) +/// - Size: 8 bytes +/// - Transmitter: Ipsum +#[derive(Clone, Copy)] +pub struct TruncatedLeSignal { + raw: [u8; 8], +} + +impl TruncatedLeSignal { + pub const MESSAGE_ID: u32 = 9002; + + pub const FOO_MIN: i16 = -100_i16; + pub const FOO_MAX: i16 = 100_i16; + + /// Construct new TruncatedLeSignal from values + pub fn new(foo: i16) -> Result { + let mut res = Self { raw: [0u8; 8] }; + res.set_foo(foo)?; + Ok(res) + } + + /// Access message payload raw value + pub fn raw(&self) -> &[u8; 8] { + &self.raw + } + + /// Foo + /// + /// - Min: -100 + /// - Max: 100 + /// - Unit: "" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn foo(&self) -> i16 { + self.foo_raw() + } + + /// Get raw value of Foo + /// + /// - Start bit: 0 + /// - Signal size: 12 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Signed + #[inline(always)] + pub fn foo_raw(&self) -> i16 { + let signal = self.raw.view_bits::()[0..12].load_le::(); + + let factor = 1; + let signal = signal as i16; + i16::from(signal).saturating_mul(factor).saturating_add(0) + } + + /// Set value of Foo + #[inline(always)] + pub fn set_foo(&mut self, value: i16) -> Result<(), CanError> { + if value < -100_i16 || 100_i16 < value { + return Err(CanError::ParameterOutOfRange { message_id: 9002 }); + } + let factor = 1; + let value = value + .checked_sub(0) + .ok_or(CanError::ParameterOutOfRange { message_id: 9002 })?; + let value = (value / factor) as i16; + + let value = u16::from_ne_bytes(value.to_ne_bytes()); + self.raw.view_bits_mut::()[0..12].store_le(value); + Ok(()) + } +} + +impl core::convert::TryFrom<&[u8]> for TruncatedLeSignal { + type Error = CanError; + + #[inline(always)] + fn try_from(payload: &[u8]) -> Result { + if payload.len() != 8 { + return Err(CanError::InvalidPayloadSize); + } + let mut raw = [0u8; 8]; + raw.copy_from_slice(&payload[..8]); + Ok(Self { raw }) + } +} + +impl core::fmt::Debug for TruncatedLeSignal { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + if f.alternate() { + f.debug_struct("TruncatedLeSignal") + .field("foo", &self.foo()) + .finish() + } else { + f.debug_tuple("TruncatedLeSignal").field(&self.raw).finish() + } + } +} + +#[cfg(feature = "arb")] +impl<'a> Arbitrary<'a> for TruncatedLeSignal { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + let foo = u.int_in_range(-100..=100)?; + TruncatedLeSignal::new(foo).map_err(|_| arbitrary::Error::IncorrectFormat) + } +} + /// This is just to make testing easier #[allow(dead_code)] fn main() {} diff --git a/testing/can-messages/tests/all.rs b/testing/can-messages/tests/all.rs index 2a3d2ab..cdab95c 100644 --- a/testing/can-messages/tests/all.rs +++ b/testing/can-messages/tests/all.rs @@ -3,6 +3,7 @@ use can_messages::{ Amet, Bar, BarThree, CanError, Foo, LargerIntsWithOffsets, MultiplexTest, MultiplexTestMultiplexorIndex, MultiplexTestMultiplexorM0, NegativeFactorTest, + TruncatedBeSignal, TruncatedLeSignal, }; #[test] @@ -75,6 +76,24 @@ fn pack_unpack_message_containing_multiplexed_signals() { } } +#[test] +fn pack_unpack_signed_truncated_signal() { + let result = TruncatedBeSignal::new(42).unwrap(); + assert_eq!(result.foo_raw(), 42); + + let result = TruncatedLeSignal::new(42).unwrap(); + assert_eq!(result.foo_raw(), 42); +} + +#[test] +fn pack_unpack_signed_truncated_signal_negative() { + let result = TruncatedBeSignal::new(-42).unwrap(); + assert_eq!(result.foo_raw(), -42); + + let result = TruncatedLeSignal::new(-42).unwrap(); + assert_eq!(result.foo_raw(), -42); +} + #[test] fn offset_integers() { let mut m = LargerIntsWithOffsets::new(100, 30000).unwrap(); diff --git a/testing/dbc-examples/example.dbc b/testing/dbc-examples/example.dbc index 1c90f45..fa60111 100644 --- a/testing/dbc-examples/example.dbc +++ b/testing/dbc-examples/example.dbc @@ -57,6 +57,12 @@ BO_ 1338 LargerIntsWithOffsets: 8 Sit BO_ 513 MsgWithoutSignals: 8 Ipsum +BO_ 9001 TruncatedBeSignal: 8 Ipsum + SG_ Foo : 0|12@0- (1,0) [-100|100] "" Vector__XXX + +BO_ 9002 TruncatedLeSignal: 8 Ipsum + SG_ Foo : 0|12@1- (1,0) [-100|100] "" Vector__XXX + VAL_ 512 Three 0 "OFF" 1 "ON" 2 "ONER" 3 "ONEST"; VAL_ 512 Four 0 "Off" 1 "On" 2 "Oner" 3 "Onest"; VAL_ 512 Type 0 "0Off" 1 "1On";