From ce4c9b5ffb31cbdf3d176b8a633ef3cf93bad732 Mon Sep 17 00:00:00 2001 From: ezhik452 <64531926+Ezhik452@users.noreply.github.com> Date: Fri, 23 May 2025 15:28:19 +0200 Subject: [PATCH] feat: float32 signal generation Add handling of the float32 extended signal type to the generator. This type of signal are passed as float32 bits packed into bytes based of endianness of the signal. Corresponding tests are provided. --- src/lib.rs | 158 ++++++++++++++------ testing/can-messages/src/messages.rs | 210 +++++++++++++++++++++++++++ testing/can-messages/tests/all.rs | 12 +- testing/dbc-examples/example.dbc | 7 + 4 files changed, 344 insertions(+), 43 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index cb2c37f..cc16d85 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -27,7 +27,10 @@ #![deny(clippy::arithmetic_side_effects)] use anyhow::{anyhow, ensure, Context, Result}; -use can_dbc::{Message, MultiplexIndicator, Signal, ValDescription, ValueDescription, DBC}; +use can_dbc::{ + Message, MultiplexIndicator, Signal, SignalExtendedValueType, ValDescription, ValueDescription, + DBC, +}; use heck::{ToPascalCase, ToSnakeCase}; use pad::PadAdapter; use std::cmp::{max, min}; @@ -297,12 +300,14 @@ fn render_message(mut w: impl Write, config: &Config<'_>, msg: &Message, dbc: &D )?; writeln!(w)?; - for signal in msg - .signals() - .iter() - .filter(|sig| signal_to_rust_type(sig) != "bool") - { - let typ = signal_to_rust_type(signal); + for signal in msg.signals().iter().filter(|sig| { + let extended_signal_value_type = + dbc.extended_value_type_for_signal(*msg.message_id(), sig.name()); + signal_to_rust_type(sig, extended_signal_value_type) != "bool" + }) { + let extended_signal_value_type = + dbc.extended_value_type_for_signal(*msg.message_id(), signal.name()); + let typ = signal_to_rust_type(signal, extended_signal_value_type); writeln!( &mut w, "pub const {sig}_MIN: {typ} = {min}_{typ};", @@ -333,10 +338,12 @@ fn render_message(mut w: impl Write, config: &Config<'_>, msg: &Message, dbc: &D if *signal.multiplexer_indicator() == MultiplexIndicator::Plain || *signal.multiplexer_indicator() == MultiplexIndicator::Multiplexor { + let extended_signal_value_type = + dbc.extended_value_type_for_signal(*msg.message_id(), signal.name()); Some(format!( "{}: {}", field_name(signal.name()), - signal_to_rust_type(signal) + signal_to_rust_type(signal, extended_signal_value_type) )) } else { None @@ -388,7 +395,7 @@ fn render_message(mut w: impl Write, config: &Config<'_>, msg: &Message, dbc: &D MultiplexIndicator::Plain => render_signal(&mut w, config, signal, dbc, msg) .with_context(|| format!("write signal impl `{}`", signal.name()))?, MultiplexIndicator::Multiplexor => { - render_multiplexor_signal(&mut w, config, signal, msg)? + render_multiplexor_signal(&mut w, config, signal, dbc, msg)? } MultiplexIndicator::MultiplexedSignal(_) => {} MultiplexIndicator::MultiplexorAndMultiplexedSignal(_) => {} @@ -439,7 +446,7 @@ fn render_message(mut w: impl Write, config: &Config<'_>, msg: &Message, dbc: &D render_defmt_impl(&mut w, config, msg)?; - render_arbitrary(&mut w, config, msg)?; + render_arbitrary(&mut w, config, dbc, msg)?; let enums_for_this_message = dbc.value_descriptions().iter().filter_map(|x| { if let ValueDescription::Signal { @@ -458,7 +465,7 @@ fn render_message(mut w: impl Write, config: &Config<'_>, msg: &Message, dbc: &D } }); for (signal, variants) in enums_for_this_message { - write_enum(&mut w, config, signal, msg, variants.as_slice())?; + write_enum(&mut w, config, signal, msg, dbc, variants.as_slice())?; } let multiplexor_signal = msg @@ -480,6 +487,9 @@ fn render_signal( dbc: &DBC, msg: &Message, ) -> Result<()> { + let extended_signal_value_type = + dbc.extended_value_type_for_signal(*msg.message_id(), signal.name()); + writeln!(w, "/// {}", signal.name())?; if let Some(comment) = dbc.signal_comment(*msg.message_id(), signal.name()) { writeln!(w, "///")?; @@ -503,11 +513,12 @@ fn render_signal( type_name, )?; { - let match_on_raw_type = match signal_to_rust_type(signal).as_str() { - "bool" => |x: f64| format!("{}", x), - // "f32" => |x: f64| format!("x if approx_eq!(f32, x, {}_f32, ulps = 2)", x), - _ => |x: f64| format!("{}", x), - }; + let match_on_raw_type = + match signal_to_rust_type(signal, extended_signal_value_type).as_str() { + "bool" => |x: f64| format!("{}", x), + // "f32" => |x: f64| format!("x if approx_eq!(f32, x, {}_f32, ulps = 2)", x), + _ => |x: f64| format!("{}", x), + }; let mut w = PadAdapter::wrap(&mut w); let read_fn = match signal.byte_order() { can_dbc::ByteOrder::LittleEndian => { @@ -563,7 +574,7 @@ fn render_signal( w, "pub fn {}(&self) -> {} {{", field_name(signal.name()), - signal_to_rust_type(signal) + signal_to_rust_type(signal, extended_signal_value_type) )?; { let mut w = PadAdapter::wrap(&mut w); @@ -586,16 +597,17 @@ fn render_signal( w, "pub fn {}_raw(&self) -> {} {{", field_name(signal.name()), - signal_to_rust_type(signal) + signal_to_rust_type(signal, extended_signal_value_type) )?; { let mut w = PadAdapter::wrap(&mut w); - signal_from_payload(&mut w, signal, msg).context("signal from payload")?; + signal_from_payload(&mut w, signal, extended_signal_value_type, msg) + .context("signal from payload")?; } writeln!(&mut w, "}}")?; writeln!(w)?; - render_set_signal(&mut w, config, signal, msg)?; + render_set_signal(&mut w, config, signal, extended_signal_value_type, msg)?; Ok(()) } @@ -604,6 +616,7 @@ fn render_set_signal( mut w: impl Write, config: &Config<'_>, signal: &Signal, + extended_signal_value_type: Option<&SignalExtendedValueType>, msg: &Message, ) -> Result<()> { writeln!(&mut w, "/// Set value of {}", signal.name())?; @@ -622,7 +635,7 @@ fn render_set_signal( "{}fn set_{}(&mut self, value: {}) -> Result<(), CanError> {{", visibility, field_name(signal.name()), - signal_to_rust_type(signal) + signal_to_rust_type(signal, extended_signal_value_type) )?; { @@ -637,7 +650,7 @@ fn render_set_signal( writeln!( w, r##"if value < {min}_{typ} || {max}_{typ} < value {{"##, - typ = signal_to_rust_type(signal), + typ = signal_to_rust_type(signal, extended_signal_value_type), min = signal.min(), max = signal.max(), )?; @@ -652,7 +665,8 @@ fn render_set_signal( writeln!(w, r"}}")?; } } - signal_to_payload(&mut w, signal, msg).context("signal to payload")?; + signal_to_payload(&mut w, signal, extended_signal_value_type, msg) + .context("signal to payload")?; } writeln!(&mut w, "}}")?; @@ -701,8 +715,12 @@ fn render_multiplexor_signal( mut w: impl Write, config: &Config<'_>, signal: &Signal, + dbc: &DBC, msg: &Message, ) -> Result<()> { + let extended_signal_value_type = + dbc.extended_value_type_for_signal(*msg.message_id(), signal.name()); + writeln!(w, "/// Get raw value of {}", signal.name())?; writeln!(w, "///")?; writeln!(w, "/// - Start bit: {}", signal.start_bit)?; @@ -716,11 +734,12 @@ fn render_multiplexor_signal( w, "pub fn {}_raw(&self) -> {} {{", field_name(signal.name()), - signal_to_rust_type(signal) + signal_to_rust_type(signal, extended_signal_value_type) )?; { let mut w = PadAdapter::wrap(&mut w); - signal_from_payload(&mut w, signal, msg).context("signal from payload")?; + signal_from_payload(&mut w, signal, extended_signal_value_type, msg) + .context("signal from payload")?; } writeln!(&mut w, "}}")?; writeln!(w)?; @@ -773,7 +792,7 @@ fn render_multiplexor_signal( } writeln!(w, "}}")?; - render_set_signal(&mut w, config, signal, msg)?; + render_set_signal(&mut w, config, signal, extended_signal_value_type, msg)?; let mut multiplexed_signals = BTreeMap::new(); for signal in msg.signals() { @@ -847,9 +866,34 @@ fn le_start_end_bit(signal: &Signal, msg: &Message) -> Result<(u64, u64)> { Ok((start_bit, end_bit)) } -fn signal_from_payload(mut w: impl Write, signal: &Signal, msg: &Message) -> Result<()> { - let read_fn = match signal.byte_order() { - can_dbc::ByteOrder::LittleEndian => { +fn signal_from_payload( + mut w: impl Write, + signal: &Signal, + extended_signal_value_type: Option<&SignalExtendedValueType>, + msg: &Message, +) -> Result<()> { + let read_fn = match (signal.byte_order(), extended_signal_value_type) { + (can_dbc::ByteOrder::LittleEndian, Some(SignalExtendedValueType::IEEEfloat32Bit)) => { + let (start_bit, end_bit) = le_start_end_bit(signal, msg)?; + + format!( + "f32::from_bits(self.raw.view_bits::()[{start}..{end}].load_le::<{typ}>())", + typ = "u32", + start = start_bit, + end = end_bit, + ) + } + (can_dbc::ByteOrder::BigEndian, Some(SignalExtendedValueType::IEEEfloat32Bit)) => { + let (start_bit, end_bit) = be_start_end_bit(signal, msg)?; + + format!( + "f32::from_bits(self.raw.view_bits::()[{start}..{end}].load_be::<{typ}>())", + typ = "u32", + start = start_bit, + end = end_bit, + ) + } + (can_dbc::ByteOrder::LittleEndian, _) => { let (start_bit, end_bit) = le_start_end_bit(signal, msg)?; format!( @@ -859,7 +903,7 @@ fn signal_from_payload(mut w: impl Write, signal: &Signal, msg: &Message) -> Res end = end_bit, ) } - can_dbc::ByteOrder::BigEndian => { + (can_dbc::ByteOrder::BigEndian, _) => { let (start_bit, end_bit) = be_start_end_bit(signal, msg)?; format!( @@ -876,6 +920,10 @@ fn signal_from_payload(mut w: impl Write, signal: &Signal, msg: &Message) -> Res if signal.signal_size == 1 { writeln!(&mut w, "signal == 1")?; + } else if let Some(SignalExtendedValueType::IEEEfloat32Bit) = extended_signal_value_type { + writeln!(&mut w, "let factor = {}_f32;", signal.factor)?; + writeln!(&mut w, "let offset = {}_f32;", signal.offset)?; + writeln!(&mut w, "(signal as f32) * factor + offset")?; } else if signal_is_float_in_rust(signal) { // Scaling is always done on floats writeln!(&mut w, "let factor = {}_f32;", signal.factor)?; @@ -909,7 +957,12 @@ fn signal_from_payload(mut w: impl Write, signal: &Signal, msg: &Message) -> Res Ok(()) } -fn signal_to_payload(mut w: impl Write, signal: &Signal, msg: &Message) -> Result<()> { +fn signal_to_payload( + mut w: impl Write, + signal: &Signal, + extended_signal_value_type: Option<&SignalExtendedValueType>, + msg: &Message, +) -> Result<()> { if signal.signal_size == 1 { // Map boolean to byte so we can pack it writeln!(&mut w, "let value = value as u8;")?; @@ -923,6 +976,11 @@ fn signal_to_payload(mut w: impl Write, signal: &Signal, msg: &Message) -> Resul signal_to_rust_int(signal) )?; writeln!(&mut w)?; + } else if let Some(SignalExtendedValueType::IEEEfloat32Bit) = extended_signal_value_type { + writeln!(&mut w, "let factor = {}_f32;", signal.factor)?; + writeln!(&mut w, "let offset = {}_f32;", signal.offset)?; + writeln!(&mut w, "let value = (value - offset) / factor;")?; + writeln!(&mut w)?; } else { writeln!(&mut w, "let factor = {};", signal.factor)?; if signal.offset >= 0.0 { @@ -985,10 +1043,13 @@ fn write_enum( config: &Config<'_>, signal: &Signal, msg: &Message, + dbc: &DBC, variants: &[ValDescription], ) -> Result<()> { let type_name = enum_name(msg, signal); - let signal_rust_type = signal_to_rust_type(signal); + let extended_signal_value_type = + dbc.extended_value_type_for_signal(*msg.message_id(), signal.name()); + let signal_rust_type = signal_to_rust_type(signal, extended_signal_value_type); writeln!(w, "/// Defined values for {}", signal.name())?; writeln!(w, "#[derive(Clone, Copy, PartialEq)]")?; @@ -1011,11 +1072,12 @@ fn write_enum( writeln!(w, "impl From<{type_name}> for {signal_rust_type} {{")?; { - let match_on_raw_type = match signal_to_rust_type(signal).as_str() { - "bool" => |x: f64| format!("{}", (x as i64) == 1), - "f32" => |x: f64| format!("{}_f32", x), - _ => |x: f64| format!("{}", x as i64), - }; + let match_on_raw_type = + match signal_to_rust_type(signal, extended_signal_value_type).as_str() { + "bool" => |x: f64| format!("{}", (x as i64) == 1), + "f32" => |x: f64| format!("{}_f32", x), + _ => |x: f64| format!("{}", x as i64), + }; let mut w = PadAdapter::wrap(&mut w); writeln!(w, "fn from(val: {type_name}) -> {signal_rust_type} {{")?; @@ -1208,9 +1270,14 @@ fn signal_is_float_in_rust(signal: &Signal) -> bool { signal.offset.fract() != 0.0 || signal.factor.fract() != 0.0 } -fn signal_to_rust_type(signal: &Signal) -> String { +fn signal_to_rust_type( + signal: &Signal, + extended_signal_value_type: Option<&SignalExtendedValueType>, +) -> String { if signal.signal_size == 1 { String::from("bool") + } else if let Some(SignalExtendedValueType::IEEEfloat32Bit) = extended_signal_value_type { + String::from("f32") } else if signal_is_float_in_rust(signal) { // If there is any scaling needed, go for float String::from("f32") @@ -1533,7 +1600,7 @@ fn render_multiplexor_enums( Ok(()) } -fn render_arbitrary(mut w: impl Write, config: &Config<'_>, msg: &Message) -> Result<()> { +fn render_arbitrary(mut w: impl Write, config: &Config<'_>, dbc: &DBC, msg: &Message) -> Result<()> { match &config.impl_arbitrary { FeatureConfig::Always => {} FeatureConfig::Gated(gate) => writeln!(w, r##"#[cfg(feature = {gate:?})]"##)?, @@ -1564,11 +1631,12 @@ fn render_arbitrary(mut w: impl Write, config: &Config<'_>, msg: &Message) -> Re let mut w = PadAdapter::wrap(&mut w); for signal in filtered_signals.iter() { + let extended_value_type_for_signal = dbc.extended_value_type_for_signal(*msg.message_id(), signal.name()); writeln!( w, "let {field_name} = {arbitrary_value};", field_name = field_name(signal.name()), - arbitrary_value = signal_to_arbitrary(signal), + arbitrary_value = signal_to_arbitrary(signal, extended_value_type_for_signal), )?; } @@ -1634,9 +1702,15 @@ fn render_arbitrary_helpers(mut w: impl Write, config: &Config<'_>) -> io::Resul Ok(()) } -fn signal_to_arbitrary(signal: &Signal) -> String { +fn signal_to_arbitrary(signal: &Signal, extended_value_type_for_signal: Option<&SignalExtendedValueType>) -> String { if signal.signal_size == 1 { "u.int_in_range(0..=1)? == 1".to_string() + } else if let Some(SignalExtendedValueType::IEEEfloat32Bit) = extended_value_type_for_signal { + format!( + "u.float_in_range({min}_f32..={max}_f32)?", + min = signal.min(), + max = signal.max() + ) } else if signal_is_float_in_rust(signal) { format!( "u.float_in_range({min}_f32..={max}_f32)?", @@ -1746,4 +1820,4 @@ mod tests { "This shouldn't be valid in a DBC, it's more than 64 bits" ); } -} +} \ No newline at end of file diff --git a/testing/can-messages/src/messages.rs b/testing/can-messages/src/messages.rs index a78d2bd..5bf2094 100644 --- a/testing/can-messages/src/messages.rs +++ b/testing/can-messages/src/messages.rs @@ -37,6 +37,8 @@ pub enum Messages { MultiplexTest(MultiplexTest), /// IntegerFactorOffset IntegerFactorOffset(IntegerFactorOffset), + /// Float32Test + Float32Test(Float32Test), /// NegativeFactorTest NegativeFactorTest(NegativeFactorTest), /// LargerIntsWithOffsets @@ -65,6 +67,7 @@ impl Messages { IntegerFactorOffset::MESSAGE_ID => { Messages::IntegerFactorOffset(IntegerFactorOffset::try_from(payload)?) } + Float32Test::MESSAGE_ID => Messages::Float32Test(Float32Test::try_from(payload)?), NegativeFactorTest::MESSAGE_ID => { Messages::NegativeFactorTest(NegativeFactorTest::try_from(payload)?) } @@ -2232,6 +2235,213 @@ impl<'a> Arbitrary<'a> for IntegerFactorOffset { } } +/// Float32Test +/// +/// - Standard ID: 600 (0x258) +/// - Size: 8 bytes +/// - Transmitter: Ipsum +#[derive(Clone, Copy)] +pub struct Float32Test { + raw: [u8; 8], +} + +impl Float32Test { + pub const MESSAGE_ID: embedded_can::Id = + Id::Standard(unsafe { StandardId::new_unchecked(0x258) }); + + pub const FLOAT32_BIG_ENDIAN_MIN: f32 = -100_f32; + pub const FLOAT32_BIG_ENDIAN_MAX: f32 = 100_f32; + pub const FLOAT32_LITTLE_ENDIAN_MIN: f32 = -100_f32; + pub const FLOAT32_LITTLE_ENDIAN_MAX: f32 = 100_f32; + + /// Construct new Float32Test from values + pub fn new(float32_big_endian: f32, float32_little_endian: f32) -> Result { + let mut res = Self { raw: [0u8; 8] }; + res.set_float32_big_endian(float32_big_endian)?; + res.set_float32_little_endian(float32_little_endian)?; + Ok(res) + } + + /// Access message payload raw value + pub fn raw(&self) -> &[u8; 8] { + &self.raw + } + + /// Float32BigEndian + /// + /// - Min: -100 + /// - Max: 100 + /// - Unit: "" + /// - Receivers: DBG + #[inline(always)] + pub fn float32_big_endian(&self) -> f32 { + self.float32_big_endian_raw() + } + + /// Get raw value of Float32BigEndian + /// + /// - Start bit: 7 + /// - Signal size: 32 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: BigEndian + /// - Value type: Signed + #[inline(always)] + pub fn float32_big_endian_raw(&self) -> f32 { + let signal = f32::from_bits(self.raw.view_bits::()[0..32].load_be::()); + + let factor = 1_f32; + let offset = 0_f32; + (signal as f32) * factor + offset + } + + /// Set value of Float32BigEndian + #[inline(always)] + pub fn set_float32_big_endian(&mut self, value: f32) -> Result<(), CanError> { + if value < -100_f32 || 100_f32 < value { + return Err(CanError::ParameterOutOfRange { + message_id: Float32Test::MESSAGE_ID, + }); + } + let factor = 1_f32; + let offset = 0_f32; + let value = (value - offset) / factor; + + let value = u32::from_ne_bytes(value.to_ne_bytes()); + self.raw.view_bits_mut::()[0..32].store_be(value); + Ok(()) + } + + /// Float32LittleEndian + /// + /// - Min: -100 + /// - Max: 100 + /// - Unit: "" + /// - Receivers: DBG + #[inline(always)] + pub fn float32_little_endian(&self) -> f32 { + self.float32_little_endian_raw() + } + + /// Get raw value of Float32LittleEndian + /// + /// - Start bit: 32 + /// - Signal size: 32 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Signed + #[inline(always)] + pub fn float32_little_endian_raw(&self) -> f32 { + let signal = f32::from_bits(self.raw.view_bits::()[32..64].load_le::()); + + let factor = 1_f32; + let offset = 0_f32; + (signal as f32) * factor + offset + } + + /// Set value of Float32LittleEndian + #[inline(always)] + pub fn set_float32_little_endian(&mut self, value: f32) -> Result<(), CanError> { + if value < -100_f32 || 100_f32 < value { + return Err(CanError::ParameterOutOfRange { + message_id: Float32Test::MESSAGE_ID, + }); + } + let factor = 1_f32; + let offset = 0_f32; + let value = (value - offset) / factor; + + let value = u32::from_ne_bytes(value.to_ne_bytes()); + self.raw.view_bits_mut::()[32..64].store_le(value); + Ok(()) + } +} + +impl core::convert::TryFrom<&[u8]> for Float32Test { + 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 embedded_can::Frame for Float32Test { + fn new(id: impl Into, data: &[u8]) -> Option { + if id.into() != Self::MESSAGE_ID { + None + } else { + data.try_into().ok() + } + } + + fn new_remote(_id: impl Into, _dlc: usize) -> Option { + unimplemented!() + } + + fn is_extended(&self) -> bool { + match self.id() { + Id::Standard(_) => false, + Id::Extended(_) => true, + } + } + + fn is_remote_frame(&self) -> bool { + false + } + + fn id(&self) -> Id { + Self::MESSAGE_ID + } + + fn dlc(&self) -> usize { + self.raw.len() + } + + fn data(&self) -> &[u8] { + &self.raw + } +} +impl core::fmt::Debug for Float32Test { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + if f.alternate() { + f.debug_struct("Float32Test") + .field("float32_big_endian", &self.float32_big_endian()) + .field("float32_little_endian", &self.float32_little_endian()) + .finish() + } else { + f.debug_tuple("Float32Test").field(&self.raw).finish() + } + } +} + +impl defmt::Format for Float32Test { + fn format(&self, f: defmt::Formatter) { + defmt::write!( + f, + "Float32Test {{ Float32BigEndian={:?} Float32LittleEndian={:?} }}", + self.float32_big_endian(), + self.float32_little_endian(), + ); + } +} + +#[cfg(feature = "arb")] +impl<'a> Arbitrary<'a> for Float32Test { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + let float32_big_endian = u.float_in_range(-100_f32..=100_f32)?; + let float32_little_endian = u.float_in_range(-100_f32..=100_f32)?; + Float32Test::new(float32_big_endian, float32_little_endian) + .map_err(|_| arbitrary::Error::IncorrectFormat) + } +} + /// NegativeFactorTest /// /// - Standard ID: 1344 (0x540) diff --git a/testing/can-messages/tests/all.rs b/testing/can-messages/tests/all.rs index 7a5a248..8cd414f 100644 --- a/testing/can-messages/tests/all.rs +++ b/testing/can-messages/tests/all.rs @@ -1,7 +1,7 @@ #![allow(clippy::float_cmp)] use can_messages::{ - Amet, Bar, BarThree, CanError, Foo, LargerIntsWithOffsets, MsgExtendedId, MultiplexTest, + Amet, Bar, BarThree, CanError, Float32Test, Foo, LargerIntsWithOffsets, MsgExtendedId, MultiplexTest, MultiplexTestMultiplexorIndex, MultiplexTestMultiplexorM0, NegativeFactorTest, TruncatedBeSignal, TruncatedLeSignal, }; @@ -135,6 +135,16 @@ fn offset_integers() { ); } +#[test] +fn floats() { + let m = Float32Test::new(42.0, 42.0).unwrap(); + + dbg!(m.raw()); + assert_eq!(m.raw(), b"\x42\x28\x00\x00\x00\x00\x28\x42"); + assert_eq!(m.float32_big_endian_raw(), 42.0); + assert_eq!(m.float32_little_endian_raw(), 42.0); +} + #[test] #[cfg(feature = "debug")] fn debug_impl() { diff --git a/testing/dbc-examples/example.dbc b/testing/dbc-examples/example.dbc index 1492e7f..b4574bb 100644 --- a/testing/dbc-examples/example.dbc +++ b/testing/dbc-examples/example.dbc @@ -47,6 +47,10 @@ BO_ 1337 IntegerFactorOffset: 8 Sit SG_ ByteWithNegativeOffset : 24|8@1+ (1,-1) [0|255] "" Vector__XXX SG_ ByteWithNegativeMin : 32|8@1+ (1,-1) [-127|127] "" Vector__XXX +BO_ 600 Float32Test: 8 Ipsum + SG_ Float32BigEndian : 7|32@0- (1,0) [-100|100] "" DBG + SG_ Float32LittleEndian : 32|32@1- (1,0) [-100|100] "" DBG + BO_ 1344 NegativeFactorTest: 4 Sit SG_ UnsignedNegativeFactorSignal : 0|16@1+ (-1,0) [-65535|0] "" Vector__XXX SG_ WidthMoreThanMinMax : 16|10@1- (1,0) [-2|2] "" Vector__XXX @@ -71,3 +75,6 @@ VAL_ 512 Four 0 "Off" 1 "On" 2 "Oner" 3 "Onest"; VAL_ 512 Type 0 "0Off" 1 "1On"; VAL_ 768 _4DRIVE 0 "OFF" 1 "2WD" 2 "4WD" 3 "ALL"; VAL_ 1028 OneFloat 3 "Dolor" 5 "Other"; + +SIG_VALTYPE_ 600 Float32BigEndian : 1; +SIG_VALTYPE_ 600 Float32LittleEndian : 1;