From 89e5805633bab91383d55c1464327508439251ab Mon Sep 17 00:00:00 2001 From: Daniel Trnka Date: Sun, 18 Aug 2024 09:19:53 +0200 Subject: [PATCH 1/2] Represent CAN message IDs as embedded_can::Id to support extended IDs --- Cargo.lock | 27 +- Cargo.toml | 3 +- fuzz/Cargo.lock | 25 +- src/includes/errors.rs | 6 +- src/lib.rs | 38 ++- testing/can-embedded/Cargo.toml | 1 + testing/can-messages/Cargo.toml | 3 +- testing/can-messages/src/messages.rs | 453 +++++++++++++++++++-------- testing/can-messages/tests/all.rs | 45 ++- testing/dbc-examples/example.dbc | 3 + testing/rust-integration/Cargo.toml | 1 + testing/rust-integration/src/main.rs | 3 +- 12 files changed, 443 insertions(+), 165 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7eb3f50..a87ae59 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -130,9 +130,9 @@ dependencies = [ [[package]] name = "can-dbc" -version = "5.0.0" +version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c2d32f0a7f3754502f84cb68e493a6765ce0978348a59efcb1bccf2ee19c255" +checksum = "cbe0d033ec316c3bb50e2e53d7ef3d8805e65c5f976d49daea65a12f7e0f9ce8" dependencies = [ "derive-getters", "nom", @@ -144,6 +144,7 @@ version = "0.1.0" dependencies = [ "bitvec", "can-messages", + "embedded-can", ] [[package]] @@ -154,6 +155,7 @@ dependencies = [ "arbitrary", "bitvec", "dbc-codegen", + "embedded-can", ] [[package]] @@ -249,6 +251,7 @@ version = "0.3.0" dependencies = [ "anyhow", "can-dbc", + "embedded-can", "heck 0.4.1", "typed-builder", ] @@ -265,9 +268,9 @@ dependencies = [ [[package]] name = "derive-getters" -version = "0.2.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0122f262bf9c9a367829da84f808d9fb128c10ef283bbe7b0922a77cf07b2747" +checksum = "7a2c35ab6e03642397cdda1dd58abbc05d418aef8e36297f336d5aba060fe8df" dependencies = [ "proc-macro2", "quote", @@ -280,6 +283,15 @@ version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a47c1c47d2f5964e29c61246e81db715514cd532db6b5116a25ea3c03d6780a2" +[[package]] +name = "embedded-can" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9d2e857f87ac832df68fa498d18ddc679175cf3d2e4aa893988e5601baf9438" +dependencies = [ + "nb", +] + [[package]] name = "errno" version = "0.3.9" @@ -396,6 +408,12 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" +[[package]] +name = "nb" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d" + [[package]] name = "nom" version = "7.1.3" @@ -461,6 +479,7 @@ version = "0.1.0" dependencies = [ "approx", "can-messages", + "embedded-can", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 886b385..6fbfd55 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,10 +18,11 @@ rust-version = "1.78.0" std = [] [dependencies] -can-dbc = "5.0.0" +can-dbc = "6.0.0" anyhow = "1.0.68" heck = "0.4.0" typed-builder = "0.18.0" +embedded-can = "0.4.1" [workspace] members = [ diff --git a/fuzz/Cargo.lock b/fuzz/Cargo.lock index 9509997..bac0e1a 100644 --- a/fuzz/Cargo.lock +++ b/fuzz/Cargo.lock @@ -57,9 +57,9 @@ dependencies = [ [[package]] name = "can-dbc" -version = "5.0.0" +version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c2d32f0a7f3754502f84cb68e493a6765ce0978348a59efcb1bccf2ee19c255" +checksum = "cbe0d033ec316c3bb50e2e53d7ef3d8805e65c5f976d49daea65a12f7e0f9ce8" dependencies = [ "derive-getters", "nom", @@ -73,6 +73,7 @@ dependencies = [ "arbitrary", "bitvec", "dbc-codegen", + "embedded-can", ] [[package]] @@ -122,6 +123,7 @@ version = "0.3.0" dependencies = [ "anyhow", "can-dbc", + "embedded-can", "heck", "typed-builder", ] @@ -137,9 +139,9 @@ dependencies = [ [[package]] name = "derive-getters" -version = "0.2.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0122f262bf9c9a367829da84f808d9fb128c10ef283bbe7b0922a77cf07b2747" +checksum = "7a2c35ab6e03642397cdda1dd58abbc05d418aef8e36297f336d5aba060fe8df" dependencies = [ "proc-macro2", "quote", @@ -152,6 +154,15 @@ version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a47c1c47d2f5964e29c61246e81db715514cd532db6b5116a25ea3c03d6780a2" +[[package]] +name = "embedded-can" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9d2e857f87ac832df68fa498d18ddc679175cf3d2e4aa893988e5601baf9438" +dependencies = [ + "nb", +] + [[package]] name = "errno" version = "0.3.9" @@ -264,6 +275,12 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" +[[package]] +name = "nb" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d" + [[package]] name = "nom" version = "7.1.3" diff --git a/src/includes/errors.rs b/src/includes/errors.rs index 7d8eeee..d1eca53 100644 --- a/src/includes/errors.rs +++ b/src/includes/errors.rs @@ -1,17 +1,17 @@ #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum CanError { - UnknownMessageId(u32), + UnknownMessageId(embedded_can::Id), /// Signal parameter is not within the range /// defined in the dbc ParameterOutOfRange { /// dbc message id - message_id: u32, + message_id: embedded_can::Id, }, InvalidPayloadSize, /// Multiplexor value not defined in the dbc InvalidMultiplexor { /// dbc message id - message_id: u32, + message_id: embedded_can::Id, /// Multiplexor value not defined in the dbc multiplexor: u16, }, diff --git a/src/lib.rs b/src/lib.rs index 4ba59ec..3e7142a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -143,6 +143,7 @@ pub fn codegen(config: Config<'_>, out: impl Write) -> Result<()> { writeln!(&mut w)?; writeln!(&mut w, "use core::ops::BitOr;")?; writeln!(&mut w, "use bitvec::prelude::*;")?; + writeln!(&mut w, "use embedded_can::{{Id, StandardId, ExtendedId}};")?; writeln!(w, r##"#[cfg(feature = "arb")]"##)?; writeln!(&mut w, "use arbitrary::{{Arbitrary, Unstructured}};")?; @@ -210,7 +211,7 @@ fn render_root_enum(mut w: impl Write, dbc: &DBC, config: &Config<'_>) -> Result writeln!(w, "#[inline(never)]")?; writeln!( &mut w, - "pub fn from_can_message(id: u32, payload: &[u8]) -> Result {{", + "pub fn from_can_message(id: Id, payload: &[u8]) -> Result {{", )?; { let mut w = PadAdapter::wrap(&mut w); @@ -221,12 +222,11 @@ fn render_root_enum(mut w: impl Write, dbc: &DBC, config: &Config<'_>) -> Result for msg in get_relevant_messages(dbc) { writeln!( w, - "{} => Messages::{1}({1}::try_from(payload)?),", - msg.message_id().0, + "{0}::MESSAGE_ID => Messages::{0}({0}::try_from(payload)?),", type_name(msg.message_name()) )?; } - writeln!(w, r#"n => return Err(CanError::UnknownMessageId(n)),"#)?; + writeln!(w, r#"id => return Err(CanError::UnknownMessageId(id)),"#)?; } writeln!(&mut w, "}};")?; writeln!(&mut w, "Ok(res)")?; @@ -243,7 +243,10 @@ fn render_root_enum(mut w: impl Write, dbc: &DBC, config: &Config<'_>) -> Result fn render_message(mut w: impl Write, config: &Config<'_>, msg: &Message, dbc: &DBC) -> Result<()> { writeln!(w, "/// {}", msg.message_name())?; writeln!(w, "///")?; - writeln!(w, "/// - ID: {0} (0x{0:x})", msg.message_id().0)?; + match msg.message_id() { + can_dbc::MessageId::Standard(id) => writeln!(w, "/// - Standard ID: {0} (0x{0:x})", id), + can_dbc::MessageId::Extended(id) => writeln!(w, "/// - Extended ID: {0} (0x{0:x})", id), + }?; writeln!(w, "/// - Size: {} bytes", msg.message_size())?; if let can_dbc::Transmitter::NodeName(transmitter) = msg.transmitter() { writeln!(w, "/// - Transmitter: {}", transmitter)?; @@ -274,8 +277,18 @@ fn render_message(mut w: impl Write, config: &Config<'_>, msg: &Message, dbc: &D writeln!( &mut w, - "pub const MESSAGE_ID: u32 = {};", - msg.message_id().0 + "pub const MESSAGE_ID: embedded_can::Id = {};", + match msg.message_id() { + // use StandardId::new().unwrap() once const_option is stable + can_dbc::MessageId::Standard(id) => format!( + "Id::Standard(unsafe {{ StandardId::new_unchecked({0:#x})}})", + id + ), + can_dbc::MessageId::Extended(id) => format!( + "Id::Extended(unsafe {{ ExtendedId::new_unchecked({0:#x})}})", + id + ), + } )?; writeln!(w)?; @@ -623,8 +636,8 @@ fn render_set_signal( let mut w = PadAdapter::wrap(&mut w); writeln!( w, - r##"return Err(CanError::ParameterOutOfRange {{ message_id: {message_id} }});"##, - message_id = msg.message_id().0, + r##"return Err(CanError::ParameterOutOfRange {{ message_id: {}::MESSAGE_ID }});"##, + type_name(msg.message_name()) )?; } writeln!(w, r"}}")?; @@ -742,8 +755,8 @@ fn render_multiplexor_signal( } writeln!( &mut w, - "multiplexor => Err(CanError::InvalidMultiplexor {{ message_id: {}, multiplexor: multiplexor.into() }}),", - msg.message_id().0 + "multiplexor => Err(CanError::InvalidMultiplexor {{ message_id: {}::MESSAGE_ID, multiplexor: multiplexor.into() }}),", + type_name(msg.message_name()) )?; } @@ -914,8 +927,7 @@ fn signal_to_payload(mut w: impl Write, signal: &Signal, msg: &Message) -> Resul } writeln!( &mut w, - " .ok_or(CanError::ParameterOutOfRange {{ message_id: {} }})?;", - msg.message_id().0, + " .ok_or(CanError::ParameterOutOfRange {{ message_id: Self::MESSAGE_ID }})?;", )?; writeln!( &mut w, diff --git a/testing/can-embedded/Cargo.toml b/testing/can-embedded/Cargo.toml index 64e441e..9dbdbe3 100644 --- a/testing/can-embedded/Cargo.toml +++ b/testing/can-embedded/Cargo.toml @@ -10,6 +10,7 @@ build-messages = ["dep:can-messages"] [dependencies] bitvec = { version = "1.0", default-features = false } +embedded-can = "0.4.1" # This is optional and default so we can turn it off for the embedded target. diff --git a/testing/can-messages/Cargo.toml b/testing/can-messages/Cargo.toml index 0fa0fc4..1a3b217 100644 --- a/testing/can-messages/Cargo.toml +++ b/testing/can-messages/Cargo.toml @@ -7,6 +7,7 @@ edition = "2021" [dependencies] bitvec = { version = "1.0", default-features = false } arbitrary = { version = "1.0", optional = true } +embedded-can = "0.4.1" [build-dependencies] anyhow = "1.0" @@ -15,4 +16,4 @@ dbc-codegen = { path = "../../" } [features] default = ["arb", "std"] arb = ["arbitrary"] -std = [] \ No newline at end of file +std = [] diff --git a/testing/can-messages/src/messages.rs b/testing/can-messages/src/messages.rs index bf0b6d4..8e096ae 100644 --- a/testing/can-messages/src/messages.rs +++ b/testing/can-messages/src/messages.rs @@ -18,6 +18,7 @@ use arbitrary::{Arbitrary, Unstructured}; use bitvec::prelude::*; use core::ops::BitOr; +use embedded_can::{ExtendedId, Id, StandardId}; /// All messages #[derive(Clone, Debug)] @@ -46,26 +47,41 @@ pub enum Messages { TruncatedBeSignal(TruncatedBeSignal), /// TruncatedLeSignal TruncatedLeSignal(TruncatedLeSignal), + /// MsgExtendedId + MsgExtendedId(MsgExtendedId), } impl Messages { /// Read message from CAN frame #[inline(never)] - pub fn from_can_message(id: u32, payload: &[u8]) -> Result { + pub fn from_can_message(id: Id, payload: &[u8]) -> Result { let res = match id { - 256 => Messages::Foo(Foo::try_from(payload)?), - 512 => Messages::Bar(Bar::try_from(payload)?), - 768 => Messages::X4wd(X4wd::try_from(payload)?), - 1024 => Messages::Amet(Amet::try_from(payload)?), - 1028 => Messages::Dolor(Dolor::try_from(payload)?), - 200 => Messages::MultiplexTest(MultiplexTest::try_from(payload)?), - 1337 => Messages::IntegerFactorOffset(IntegerFactorOffset::try_from(payload)?), - 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)), + Foo::MESSAGE_ID => Messages::Foo(Foo::try_from(payload)?), + Bar::MESSAGE_ID => Messages::Bar(Bar::try_from(payload)?), + X4wd::MESSAGE_ID => Messages::X4wd(X4wd::try_from(payload)?), + Amet::MESSAGE_ID => Messages::Amet(Amet::try_from(payload)?), + Dolor::MESSAGE_ID => Messages::Dolor(Dolor::try_from(payload)?), + MultiplexTest::MESSAGE_ID => Messages::MultiplexTest(MultiplexTest::try_from(payload)?), + IntegerFactorOffset::MESSAGE_ID => { + Messages::IntegerFactorOffset(IntegerFactorOffset::try_from(payload)?) + } + NegativeFactorTest::MESSAGE_ID => { + Messages::NegativeFactorTest(NegativeFactorTest::try_from(payload)?) + } + LargerIntsWithOffsets::MESSAGE_ID => { + Messages::LargerIntsWithOffsets(LargerIntsWithOffsets::try_from(payload)?) + } + MsgWithoutSignals::MESSAGE_ID => { + Messages::MsgWithoutSignals(MsgWithoutSignals::try_from(payload)?) + } + TruncatedBeSignal::MESSAGE_ID => { + Messages::TruncatedBeSignal(TruncatedBeSignal::try_from(payload)?) + } + TruncatedLeSignal::MESSAGE_ID => { + Messages::TruncatedLeSignal(TruncatedLeSignal::try_from(payload)?) + } + MsgExtendedId::MESSAGE_ID => Messages::MsgExtendedId(MsgExtendedId::try_from(payload)?), + id => return Err(CanError::UnknownMessageId(id)), }; Ok(res) } @@ -73,7 +89,7 @@ impl Messages { /// Foo /// -/// - ID: 256 (0x100) +/// - Standard ID: 256 (0x100) /// - Size: 4 bytes /// - Transmitter: Lorem #[derive(Clone, Copy)] @@ -82,7 +98,8 @@ pub struct Foo { } impl Foo { - pub const MESSAGE_ID: u32 = 256; + pub const MESSAGE_ID: embedded_can::Id = + Id::Standard(unsafe { StandardId::new_unchecked(0x100) }); pub const VOLTAGE_MIN: f32 = 0_f32; pub const VOLTAGE_MAX: f32 = 63.9990234375_f32; @@ -134,7 +151,9 @@ impl Foo { #[inline(always)] pub fn set_voltage(&mut self, value: f32) -> Result<(), CanError> { if value < 0_f32 || 63.9990234375_f32 < value { - return Err(CanError::ParameterOutOfRange { message_id: 256 }); + return Err(CanError::ParameterOutOfRange { + message_id: Foo::MESSAGE_ID, + }); } let factor = 0.000976562_f32; let offset = 0_f32; @@ -176,7 +195,9 @@ impl Foo { #[inline(always)] pub fn set_current(&mut self, value: f32) -> Result<(), CanError> { if value < -2048_f32 || 2047.9375_f32 < value { - return Err(CanError::ParameterOutOfRange { message_id: 256 }); + return Err(CanError::ParameterOutOfRange { + message_id: Foo::MESSAGE_ID, + }); } let factor = 0.0625_f32; let offset = 0_f32; @@ -226,7 +247,7 @@ impl<'a> Arbitrary<'a> for Foo { /// Bar /// -/// - ID: 512 (0x200) +/// - Standard ID: 512 (0x200) /// - Size: 8 bytes /// - Transmitter: Ipsum #[derive(Clone, Copy)] @@ -235,7 +256,8 @@ pub struct Bar { } impl Bar { - pub const MESSAGE_ID: u32 = 512; + pub const MESSAGE_ID: embedded_can::Id = + Id::Standard(unsafe { StandardId::new_unchecked(0x200) }); pub const ONE_MIN: u8 = 0_u8; pub const ONE_MAX: u8 = 3_u8; @@ -293,12 +315,14 @@ impl Bar { #[inline(always)] pub fn set_one(&mut self, value: u8) -> Result<(), CanError> { if value < 0_u8 || 3_u8 < value { - return Err(CanError::ParameterOutOfRange { message_id: 512 }); + return Err(CanError::ParameterOutOfRange { + message_id: Bar::MESSAGE_ID, + }); } let factor = 1; - let value = value - .checked_sub(0) - .ok_or(CanError::ParameterOutOfRange { message_id: 512 })?; + let value = value.checked_sub(0).ok_or(CanError::ParameterOutOfRange { + message_id: Self::MESSAGE_ID, + })?; let value = (value / factor) as u8; self.raw.view_bits_mut::()[8..10].store_be(value); @@ -337,7 +361,9 @@ impl Bar { #[inline(always)] pub fn set_two(&mut self, value: f32) -> Result<(), CanError> { if value < 0_f32 || 100_f32 < value { - return Err(CanError::ParameterOutOfRange { message_id: 512 }); + return Err(CanError::ParameterOutOfRange { + message_id: Bar::MESSAGE_ID, + }); } let factor = 0.39_f32; let offset = 0_f32; @@ -386,12 +412,14 @@ impl Bar { #[inline(always)] pub fn set_three(&mut self, value: u8) -> Result<(), CanError> { if value < 0_u8 || 7_u8 < value { - return Err(CanError::ParameterOutOfRange { message_id: 512 }); + return Err(CanError::ParameterOutOfRange { + message_id: Bar::MESSAGE_ID, + }); } let factor = 1; - let value = value - .checked_sub(0) - .ok_or(CanError::ParameterOutOfRange { message_id: 512 })?; + let value = value.checked_sub(0).ok_or(CanError::ParameterOutOfRange { + message_id: Self::MESSAGE_ID, + })?; let value = (value / factor) as u8; self.raw.view_bits_mut::()[10..13].store_be(value); @@ -437,12 +465,14 @@ impl Bar { #[inline(always)] pub fn set_four(&mut self, value: u8) -> Result<(), CanError> { if value < 0_u8 || 3_u8 < value { - return Err(CanError::ParameterOutOfRange { message_id: 512 }); + return Err(CanError::ParameterOutOfRange { + message_id: Bar::MESSAGE_ID, + }); } let factor = 1; - let value = value - .checked_sub(0) - .ok_or(CanError::ParameterOutOfRange { message_id: 512 })?; + let value = value.checked_sub(0).ok_or(CanError::ParameterOutOfRange { + message_id: Self::MESSAGE_ID, + })?; let value = (value / factor) as u8; self.raw.view_bits_mut::()[13..15].store_be(value); @@ -595,7 +625,7 @@ impl From for bool { /// _4WD /// -/// - ID: 768 (0x300) +/// - Standard ID: 768 (0x300) /// - Size: 8 bytes /// - Transmitter: Ipsum #[derive(Clone, Copy)] @@ -604,7 +634,8 @@ pub struct X4wd { } impl X4wd { - pub const MESSAGE_ID: u32 = 768; + pub const MESSAGE_ID: embedded_can::Id = + Id::Standard(unsafe { StandardId::new_unchecked(0x300) }); pub const X4DRIVE_MIN: u8 = 0_u8; pub const X4DRIVE_MAX: u8 = 7_u8; @@ -660,12 +691,14 @@ impl X4wd { #[inline(always)] pub fn set_x4drive(&mut self, value: u8) -> Result<(), CanError> { if value < 0_u8 || 7_u8 < value { - return Err(CanError::ParameterOutOfRange { message_id: 768 }); + return Err(CanError::ParameterOutOfRange { + message_id: X4wd::MESSAGE_ID, + }); } let factor = 1; - let value = value - .checked_sub(0) - .ok_or(CanError::ParameterOutOfRange { message_id: 768 })?; + let value = value.checked_sub(0).ok_or(CanError::ParameterOutOfRange { + message_id: Self::MESSAGE_ID, + })?; let value = (value / factor) as u8; self.raw.view_bits_mut::()[10..13].store_be(value); @@ -730,7 +763,7 @@ impl From for u8 { /// Amet /// -/// - ID: 1024 (0x400) +/// - Standard ID: 1024 (0x400) /// - Size: 8 bytes /// - Transmitter: Sit #[derive(Clone, Copy)] @@ -739,7 +772,8 @@ pub struct Amet { } impl Amet { - pub const MESSAGE_ID: u32 = 1024; + pub const MESSAGE_ID: embedded_can::Id = + Id::Standard(unsafe { StandardId::new_unchecked(0x400) }); pub const ONE_MIN: u8 = 0_u8; pub const ONE_MAX: u8 = 3_u8; @@ -797,12 +831,14 @@ impl Amet { #[inline(always)] pub fn set_one(&mut self, value: u8) -> Result<(), CanError> { if value < 0_u8 || 3_u8 < value { - return Err(CanError::ParameterOutOfRange { message_id: 1024 }); + return Err(CanError::ParameterOutOfRange { + message_id: Amet::MESSAGE_ID, + }); } let factor = 1; - let value = value - .checked_sub(0) - .ok_or(CanError::ParameterOutOfRange { message_id: 1024 })?; + let value = value.checked_sub(0).ok_or(CanError::ParameterOutOfRange { + message_id: Self::MESSAGE_ID, + })?; let value = (value / factor) as u8; self.raw.view_bits_mut::()[8..10].store_be(value); @@ -841,7 +877,9 @@ impl Amet { #[inline(always)] pub fn set_two(&mut self, value: f32) -> Result<(), CanError> { if value < 0_f32 || 100_f32 < value { - return Err(CanError::ParameterOutOfRange { message_id: 1024 }); + return Err(CanError::ParameterOutOfRange { + message_id: Amet::MESSAGE_ID, + }); } let factor = 0.39_f32; let offset = 0_f32; @@ -882,12 +920,14 @@ impl Amet { #[inline(always)] pub fn set_three(&mut self, value: u8) -> Result<(), CanError> { if value < 0_u8 || 7_u8 < value { - return Err(CanError::ParameterOutOfRange { message_id: 1024 }); + return Err(CanError::ParameterOutOfRange { + message_id: Amet::MESSAGE_ID, + }); } let factor = 1; - let value = value - .checked_sub(0) - .ok_or(CanError::ParameterOutOfRange { message_id: 1024 })?; + let value = value.checked_sub(0).ok_or(CanError::ParameterOutOfRange { + message_id: Self::MESSAGE_ID, + })?; let value = (value / factor) as u8; self.raw.view_bits_mut::()[19..22].store_be(value); @@ -925,12 +965,14 @@ impl Amet { #[inline(always)] pub fn set_four(&mut self, value: u8) -> Result<(), CanError> { if value < 0_u8 || 3_u8 < value { - return Err(CanError::ParameterOutOfRange { message_id: 1024 }); + return Err(CanError::ParameterOutOfRange { + message_id: Amet::MESSAGE_ID, + }); } let factor = 1; - let value = value - .checked_sub(0) - .ok_or(CanError::ParameterOutOfRange { message_id: 1024 })?; + let value = value.checked_sub(0).ok_or(CanError::ParameterOutOfRange { + message_id: Self::MESSAGE_ID, + })?; let value = (value / factor) as u8; self.raw.view_bits_mut::()[25..27].store_be(value); @@ -1016,7 +1058,7 @@ impl<'a> Arbitrary<'a> for Amet { /// Dolor /// -/// - ID: 1028 (0x404) +/// - Standard ID: 1028 (0x404) /// - Size: 8 bytes /// - Transmitter: Sit #[derive(Clone, Copy)] @@ -1025,7 +1067,8 @@ pub struct Dolor { } impl Dolor { - pub const MESSAGE_ID: u32 = 1028; + pub const MESSAGE_ID: embedded_can::Id = + Id::Standard(unsafe { StandardId::new_unchecked(0x404) }); pub const ONE_FLOAT_MIN: f32 = 0_f32; pub const ONE_FLOAT_MAX: f32 = 130_f32; @@ -1080,7 +1123,9 @@ impl Dolor { #[inline(always)] pub fn set_one_float(&mut self, value: f32) -> Result<(), CanError> { if value < 0_f32 || 130_f32 < value { - return Err(CanError::ParameterOutOfRange { message_id: 1028 }); + return Err(CanError::ParameterOutOfRange { + message_id: Dolor::MESSAGE_ID, + }); } let factor = 0.5_f32; let offset = 0_f32; @@ -1144,7 +1189,7 @@ impl From for f32 { /// MultiplexTest /// -/// - ID: 200 (0xc8) +/// - Standard ID: 200 (0xc8) /// - Size: 8 bytes /// - Transmitter: SENSOR #[derive(Clone, Copy)] @@ -1153,7 +1198,8 @@ pub struct MultiplexTest { } impl MultiplexTest { - pub const MESSAGE_ID: u32 = 200; + pub const MESSAGE_ID: embedded_can::Id = + Id::Standard(unsafe { StandardId::new_unchecked(0xc8) }); pub const MULTIPLEXOR_MIN: u8 = 0_u8; pub const MULTIPLEXOR_MAX: u8 = 2_u8; @@ -1206,7 +1252,7 @@ impl MultiplexTest { MultiplexTestMultiplexorM1 { raw: self.raw }, )), multiplexor => Err(CanError::InvalidMultiplexor { - message_id: 200, + message_id: MultiplexTest::MESSAGE_ID, multiplexor: multiplexor.into(), }), } @@ -1215,12 +1261,14 @@ impl MultiplexTest { #[inline(always)] fn set_multiplexor(&mut self, value: u8) -> Result<(), CanError> { if value < 0_u8 || 2_u8 < value { - return Err(CanError::ParameterOutOfRange { message_id: 200 }); + return Err(CanError::ParameterOutOfRange { + message_id: MultiplexTest::MESSAGE_ID, + }); } let factor = 1; - let value = value - .checked_sub(0) - .ok_or(CanError::ParameterOutOfRange { message_id: 200 })?; + let value = value.checked_sub(0).ok_or(CanError::ParameterOutOfRange { + message_id: Self::MESSAGE_ID, + })?; let value = (value / factor) as u8; self.raw.view_bits_mut::()[0..4].store_le(value); @@ -1278,12 +1326,14 @@ impl MultiplexTest { #[inline(always)] pub fn set_unmultiplexed_signal(&mut self, value: u8) -> Result<(), CanError> { if value < 0_u8 || 4_u8 < value { - return Err(CanError::ParameterOutOfRange { message_id: 200 }); + return Err(CanError::ParameterOutOfRange { + message_id: MultiplexTest::MESSAGE_ID, + }); } let factor = 1; - let value = value - .checked_sub(0) - .ok_or(CanError::ParameterOutOfRange { message_id: 200 })?; + let value = value.checked_sub(0).ok_or(CanError::ParameterOutOfRange { + message_id: Self::MESSAGE_ID, + })?; let value = (value / factor) as u8; self.raw.view_bits_mut::()[4..12].store_le(value); @@ -1374,7 +1424,9 @@ impl MultiplexTestMultiplexorM0 { #[inline(always)] pub fn set_multiplexed_signal_zero_a(&mut self, value: f32) -> Result<(), CanError> { if value < 0_f32 || 3_f32 < value { - return Err(CanError::ParameterOutOfRange { message_id: 200 }); + return Err(CanError::ParameterOutOfRange { + message_id: MultiplexTest::MESSAGE_ID, + }); } let factor = 0.1_f32; let offset = 0_f32; @@ -1416,7 +1468,9 @@ impl MultiplexTestMultiplexorM0 { #[inline(always)] pub fn set_multiplexed_signal_zero_b(&mut self, value: f32) -> Result<(), CanError> { if value < 0_f32 || 3_f32 < value { - return Err(CanError::ParameterOutOfRange { message_id: 200 }); + return Err(CanError::ParameterOutOfRange { + message_id: MultiplexTest::MESSAGE_ID, + }); } let factor = 0.1_f32; let offset = 0_f32; @@ -1468,7 +1522,9 @@ impl MultiplexTestMultiplexorM1 { #[inline(always)] pub fn set_multiplexed_signal_one_a(&mut self, value: f32) -> Result<(), CanError> { if value < 0_f32 || 6_f32 < value { - return Err(CanError::ParameterOutOfRange { message_id: 200 }); + return Err(CanError::ParameterOutOfRange { + message_id: MultiplexTest::MESSAGE_ID, + }); } let factor = 0.1_f32; let offset = 0_f32; @@ -1510,7 +1566,9 @@ impl MultiplexTestMultiplexorM1 { #[inline(always)] pub fn set_multiplexed_signal_one_b(&mut self, value: f32) -> Result<(), CanError> { if value < 0_f32 || 6_f32 < value { - return Err(CanError::ParameterOutOfRange { message_id: 200 }); + return Err(CanError::ParameterOutOfRange { + message_id: MultiplexTest::MESSAGE_ID, + }); } let factor = 0.1_f32; let offset = 0_f32; @@ -1523,7 +1581,7 @@ impl MultiplexTestMultiplexorM1 { /// IntegerFactorOffset /// -/// - ID: 1337 (0x539) +/// - Standard ID: 1337 (0x539) /// - Size: 8 bytes /// - Transmitter: Sit #[derive(Clone, Copy)] @@ -1532,7 +1590,8 @@ pub struct IntegerFactorOffset { } impl IntegerFactorOffset { - pub const MESSAGE_ID: u32 = 1337; + pub const MESSAGE_ID: embedded_can::Id = + Id::Standard(unsafe { StandardId::new_unchecked(0x539) }); pub const BYTE_WITH_OFFSET_MIN: u16 = 1_u16; pub const BYTE_WITH_OFFSET_MAX: u16 = 256_u16; @@ -1598,12 +1657,14 @@ impl IntegerFactorOffset { #[inline(always)] pub fn set_byte_with_offset(&mut self, value: u16) -> Result<(), CanError> { if value < 1_u16 || 256_u16 < value { - return Err(CanError::ParameterOutOfRange { message_id: 1337 }); + return Err(CanError::ParameterOutOfRange { + message_id: IntegerFactorOffset::MESSAGE_ID, + }); } let factor = 1; - let value = value - .checked_sub(1) - .ok_or(CanError::ParameterOutOfRange { message_id: 1337 })?; + let value = value.checked_sub(1).ok_or(CanError::ParameterOutOfRange { + message_id: Self::MESSAGE_ID, + })?; let value = (value / factor) as u8; self.raw.view_bits_mut::()[0..8].store_le(value); @@ -1641,12 +1702,14 @@ impl IntegerFactorOffset { #[inline(always)] pub fn set_byte_with_factor(&mut self, value: u16) -> Result<(), CanError> { if value < 0_u16 || 1020_u16 < value { - return Err(CanError::ParameterOutOfRange { message_id: 1337 }); + return Err(CanError::ParameterOutOfRange { + message_id: IntegerFactorOffset::MESSAGE_ID, + }); } let factor = 4; - let value = value - .checked_sub(0) - .ok_or(CanError::ParameterOutOfRange { message_id: 1337 })?; + let value = value.checked_sub(0).ok_or(CanError::ParameterOutOfRange { + message_id: Self::MESSAGE_ID, + })?; let value = (value / factor) as u8; self.raw.view_bits_mut::()[8..16].store_le(value); @@ -1684,12 +1747,14 @@ impl IntegerFactorOffset { #[inline(always)] pub fn set_byte_with_both(&mut self, value: u16) -> Result<(), CanError> { if value < 16_u16 || 526_u16 < value { - return Err(CanError::ParameterOutOfRange { message_id: 1337 }); + return Err(CanError::ParameterOutOfRange { + message_id: IntegerFactorOffset::MESSAGE_ID, + }); } let factor = 2; - let value = value - .checked_sub(16) - .ok_or(CanError::ParameterOutOfRange { message_id: 1337 })?; + let value = value.checked_sub(16).ok_or(CanError::ParameterOutOfRange { + message_id: Self::MESSAGE_ID, + })?; let value = (value / factor) as u8; self.raw.view_bits_mut::()[16..24].store_le(value); @@ -1727,12 +1792,14 @@ impl IntegerFactorOffset { #[inline(always)] pub fn set_byte_with_negative_offset(&mut self, value: i16) -> Result<(), CanError> { if value < 0_i16 || 255_i16 < value { - return Err(CanError::ParameterOutOfRange { message_id: 1337 }); + return Err(CanError::ParameterOutOfRange { + message_id: IntegerFactorOffset::MESSAGE_ID, + }); } let factor = 1; - let value = value - .checked_add(1) - .ok_or(CanError::ParameterOutOfRange { message_id: 1337 })?; + let value = value.checked_add(1).ok_or(CanError::ParameterOutOfRange { + message_id: Self::MESSAGE_ID, + })?; let value = (value / factor) as u8; self.raw.view_bits_mut::()[24..32].store_le(value); @@ -1770,12 +1837,14 @@ impl IntegerFactorOffset { #[inline(always)] pub fn set_byte_with_negative_min(&mut self, value: i16) -> Result<(), CanError> { if value < -127_i16 || 127_i16 < value { - return Err(CanError::ParameterOutOfRange { message_id: 1337 }); + return Err(CanError::ParameterOutOfRange { + message_id: IntegerFactorOffset::MESSAGE_ID, + }); } let factor = 1; - let value = value - .checked_add(1) - .ok_or(CanError::ParameterOutOfRange { message_id: 1337 })?; + let value = value.checked_add(1).ok_or(CanError::ParameterOutOfRange { + message_id: Self::MESSAGE_ID, + })?; let value = (value / factor) as u8; self.raw.view_bits_mut::()[32..40].store_le(value); @@ -1839,7 +1908,7 @@ impl<'a> Arbitrary<'a> for IntegerFactorOffset { /// NegativeFactorTest /// -/// - ID: 1344 (0x540) +/// - Standard ID: 1344 (0x540) /// - Size: 4 bytes /// - Transmitter: Sit #[derive(Clone, Copy)] @@ -1848,7 +1917,8 @@ pub struct NegativeFactorTest { } impl NegativeFactorTest { - pub const MESSAGE_ID: u32 = 1344; + pub const MESSAGE_ID: embedded_can::Id = + Id::Standard(unsafe { StandardId::new_unchecked(0x540) }); pub const UNSIGNED_NEGATIVE_FACTOR_SIGNAL_MIN: i32 = -65535_i32; pub const UNSIGNED_NEGATIVE_FACTOR_SIGNAL_MAX: i32 = 0_i32; @@ -1902,12 +1972,14 @@ impl NegativeFactorTest { #[inline(always)] pub fn set_unsigned_negative_factor_signal(&mut self, value: i32) -> Result<(), CanError> { if value < -65535_i32 || 0_i32 < value { - return Err(CanError::ParameterOutOfRange { message_id: 1344 }); + return Err(CanError::ParameterOutOfRange { + message_id: NegativeFactorTest::MESSAGE_ID, + }); } let factor = -1; - let value = value - .checked_sub(0) - .ok_or(CanError::ParameterOutOfRange { message_id: 1344 })?; + let value = value.checked_sub(0).ok_or(CanError::ParameterOutOfRange { + message_id: Self::MESSAGE_ID, + })?; let value = (value / factor) as u16; self.raw.view_bits_mut::()[0..16].store_le(value); @@ -1946,12 +2018,14 @@ impl NegativeFactorTest { #[inline(always)] pub fn set_width_more_than_min_max(&mut self, value: i16) -> Result<(), CanError> { if value < -2_i16 || 2_i16 < value { - return Err(CanError::ParameterOutOfRange { message_id: 1344 }); + return Err(CanError::ParameterOutOfRange { + message_id: NegativeFactorTest::MESSAGE_ID, + }); } let factor = 1; - let value = value - .checked_sub(0) - .ok_or(CanError::ParameterOutOfRange { message_id: 1344 })?; + let value = value.checked_sub(0).ok_or(CanError::ParameterOutOfRange { + message_id: Self::MESSAGE_ID, + })?; let value = (value / factor) as i16; let value = u16::from_ne_bytes(value.to_ne_bytes()); @@ -2004,7 +2078,7 @@ impl<'a> Arbitrary<'a> for NegativeFactorTest { /// LargerIntsWithOffsets /// -/// - ID: 1338 (0x53a) +/// - Standard ID: 1338 (0x53a) /// - Size: 8 bytes /// - Transmitter: Sit #[derive(Clone, Copy)] @@ -2013,7 +2087,8 @@ pub struct LargerIntsWithOffsets { } impl LargerIntsWithOffsets { - pub const MESSAGE_ID: u32 = 1338; + pub const MESSAGE_ID: embedded_can::Id = + Id::Standard(unsafe { StandardId::new_unchecked(0x53a) }); pub const TWELVE_MIN: i16 = -1000_i16; pub const TWELVE_MAX: i16 = 3000_i16; @@ -2067,12 +2142,16 @@ impl LargerIntsWithOffsets { #[inline(always)] pub fn set_twelve(&mut self, value: i16) -> Result<(), CanError> { if value < -1000_i16 || 3000_i16 < value { - return Err(CanError::ParameterOutOfRange { message_id: 1338 }); + return Err(CanError::ParameterOutOfRange { + message_id: LargerIntsWithOffsets::MESSAGE_ID, + }); } let factor = 1; let value = value .checked_add(1000) - .ok_or(CanError::ParameterOutOfRange { message_id: 1338 })?; + .ok_or(CanError::ParameterOutOfRange { + message_id: Self::MESSAGE_ID, + })?; let value = (value / factor) as u16; self.raw.view_bits_mut::()[0..12].store_le(value); @@ -2112,12 +2191,16 @@ impl LargerIntsWithOffsets { #[inline(always)] pub fn set_sixteen(&mut self, value: i32) -> Result<(), CanError> { if value < -1000_i32 || 64535_i32 < value { - return Err(CanError::ParameterOutOfRange { message_id: 1338 }); + return Err(CanError::ParameterOutOfRange { + message_id: LargerIntsWithOffsets::MESSAGE_ID, + }); } let factor = 1; let value = value .checked_add(1000) - .ok_or(CanError::ParameterOutOfRange { message_id: 1338 })?; + .ok_or(CanError::ParameterOutOfRange { + message_id: Self::MESSAGE_ID, + })?; let value = (value / factor) as u16; self.raw.view_bits_mut::()[12..28].store_le(value); @@ -2165,7 +2248,7 @@ impl<'a> Arbitrary<'a> for LargerIntsWithOffsets { /// MsgWithoutSignals /// -/// - ID: 513 (0x201) +/// - Standard ID: 513 (0x201) /// - Size: 8 bytes /// - Transmitter: Ipsum #[derive(Clone, Copy)] @@ -2174,7 +2257,8 @@ pub struct MsgWithoutSignals { } impl MsgWithoutSignals { - pub const MESSAGE_ID: u32 = 513; + pub const MESSAGE_ID: embedded_can::Id = + Id::Standard(unsafe { StandardId::new_unchecked(0x201) }); /// Construct new MsgWithoutSignals from values pub fn new() -> Result { @@ -2221,7 +2305,7 @@ impl<'a> Arbitrary<'a> for MsgWithoutSignals { /// TruncatedBeSignal /// -/// - ID: 9001 (0x2329) +/// - Standard ID: 9001 (0x2329) /// - Size: 8 bytes /// - Transmitter: Ipsum #[derive(Clone, Copy)] @@ -2230,7 +2314,8 @@ pub struct TruncatedBeSignal { } impl TruncatedBeSignal { - pub const MESSAGE_ID: u32 = 9001; + pub const MESSAGE_ID: embedded_can::Id = + Id::Standard(unsafe { StandardId::new_unchecked(0x2329) }); pub const FOO_MIN: i16 = -100_i16; pub const FOO_MAX: i16 = 100_i16; @@ -2279,12 +2364,14 @@ impl TruncatedBeSignal { #[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 }); + return Err(CanError::ParameterOutOfRange { + message_id: TruncatedBeSignal::MESSAGE_ID, + }); } let factor = 1; - let value = value - .checked_sub(0) - .ok_or(CanError::ParameterOutOfRange { message_id: 9001 })?; + let value = value.checked_sub(0).ok_or(CanError::ParameterOutOfRange { + message_id: Self::MESSAGE_ID, + })?; let value = (value / factor) as i16; let value = u16::from_ne_bytes(value.to_ne_bytes()); @@ -2329,7 +2416,7 @@ impl<'a> Arbitrary<'a> for TruncatedBeSignal { /// TruncatedLeSignal /// -/// - ID: 9002 (0x232a) +/// - Standard ID: 9002 (0x232a) /// - Size: 8 bytes /// - Transmitter: Ipsum #[derive(Clone, Copy)] @@ -2338,7 +2425,8 @@ pub struct TruncatedLeSignal { } impl TruncatedLeSignal { - pub const MESSAGE_ID: u32 = 9002; + pub const MESSAGE_ID: embedded_can::Id = + Id::Standard(unsafe { StandardId::new_unchecked(0x232a) }); pub const FOO_MIN: i16 = -100_i16; pub const FOO_MAX: i16 = 100_i16; @@ -2387,12 +2475,14 @@ impl TruncatedLeSignal { #[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 }); + return Err(CanError::ParameterOutOfRange { + message_id: TruncatedLeSignal::MESSAGE_ID, + }); } let factor = 1; - let value = value - .checked_sub(0) - .ok_or(CanError::ParameterOutOfRange { message_id: 9002 })?; + let value = value.checked_sub(0).ok_or(CanError::ParameterOutOfRange { + message_id: Self::MESSAGE_ID, + })?; let value = (value / factor) as i16; let value = u16::from_ne_bytes(value.to_ne_bytes()); @@ -2435,24 +2525,133 @@ impl<'a> Arbitrary<'a> for TruncatedLeSignal { } } +/// MsgExtendedId +/// +/// - Extended ID: 4660 (0x1234) +/// - Size: 8 bytes +/// - Transmitter: Sit +#[derive(Clone, Copy)] +pub struct MsgExtendedId { + raw: [u8; 8], +} + +impl MsgExtendedId { + pub const MESSAGE_ID: embedded_can::Id = + Id::Extended(unsafe { ExtendedId::new_unchecked(0x1234) }); + + pub const DUMMY_MIN: u8 = 0_u8; + pub const DUMMY_MAX: u8 = 3_u8; + + /// Construct new MsgExtendedId from values + pub fn new(dummy: u8) -> Result { + let mut res = Self { raw: [0u8; 8] }; + res.set_dummy(dummy)?; + Ok(res) + } + + /// Access message payload raw value + pub fn raw(&self) -> &[u8; 8] { + &self.raw + } + + /// Dummy + /// + /// - Min: 0 + /// - Max: 3 + /// - Unit: "" + /// - Receivers: XXX + #[inline(always)] + pub fn dummy(&self) -> u8 { + self.dummy_raw() + } + + /// Get raw value of Dummy + /// + /// - Start bit: 15 + /// - Signal size: 2 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: BigEndian + /// - Value type: Unsigned + #[inline(always)] + pub fn dummy_raw(&self) -> u8 { + let signal = self.raw.view_bits::()[8..10].load_be::(); + + let factor = 1; + u8::from(signal).saturating_mul(factor).saturating_add(0) + } + + /// Set value of Dummy + #[inline(always)] + pub fn set_dummy(&mut self, value: u8) -> Result<(), CanError> { + if value < 0_u8 || 3_u8 < value { + return Err(CanError::ParameterOutOfRange { + message_id: MsgExtendedId::MESSAGE_ID, + }); + } + let factor = 1; + let value = value.checked_sub(0).ok_or(CanError::ParameterOutOfRange { + message_id: Self::MESSAGE_ID, + })?; + let value = (value / factor) as u8; + + self.raw.view_bits_mut::()[8..10].store_be(value); + Ok(()) + } +} + +impl core::convert::TryFrom<&[u8]> for MsgExtendedId { + 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 MsgExtendedId { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + if f.alternate() { + f.debug_struct("MsgExtendedId") + .field("dummy", &self.dummy()) + .finish() + } else { + f.debug_tuple("MsgExtendedId").field(&self.raw).finish() + } + } +} + +#[cfg(feature = "arb")] +impl<'a> Arbitrary<'a> for MsgExtendedId { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + let dummy = u.int_in_range(0..=3)?; + MsgExtendedId::new(dummy).map_err(|_| arbitrary::Error::IncorrectFormat) + } +} + /// This is just to make testing easier #[allow(dead_code)] fn main() {} #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum CanError { - UnknownMessageId(u32), + UnknownMessageId(embedded_can::Id), /// Signal parameter is not within the range /// defined in the dbc ParameterOutOfRange { /// dbc message id - message_id: u32, + message_id: embedded_can::Id, }, InvalidPayloadSize, /// Multiplexor value not defined in the dbc InvalidMultiplexor { /// dbc message id - message_id: u32, + message_id: embedded_can::Id, /// Multiplexor value not defined in the dbc multiplexor: u16, }, diff --git a/testing/can-messages/tests/all.rs b/testing/can-messages/tests/all.rs index cdab95c..7a5a248 100644 --- a/testing/can-messages/tests/all.rs +++ b/testing/can-messages/tests/all.rs @@ -1,18 +1,21 @@ #![allow(clippy::float_cmp)] use can_messages::{ - Amet, Bar, BarThree, CanError, Foo, LargerIntsWithOffsets, MultiplexTest, + Amet, Bar, BarThree, CanError, Foo, LargerIntsWithOffsets, MsgExtendedId, MultiplexTest, MultiplexTestMultiplexorIndex, MultiplexTestMultiplexorM0, NegativeFactorTest, TruncatedBeSignal, TruncatedLeSignal, }; +use embedded_can::{ExtendedId, Id, StandardId}; #[test] fn check_range_value_error() { let result = Bar::new(1, 2.0, 3, 4, true); - assert!(matches!( - result, - Err(CanError::ParameterOutOfRange { message_id: 512 }) - )); + assert_eq!( + result.unwrap_err(), + CanError::ParameterOutOfRange { + message_id: Id::Standard(StandardId::new(512).unwrap()) + } + ); } #[test] @@ -118,14 +121,18 @@ fn offset_integers() { assert_eq!(m.sixteen(), -1000); // Setting out of range values - assert!(matches!( + assert_eq!( m.set_twelve(-2000), - Err(CanError::ParameterOutOfRange { message_id: 1338 }) - )); - assert!(matches!( + Err(CanError::ParameterOutOfRange { + message_id: Id::Standard(StandardId::new(1338).unwrap()) + }) + ); + assert_eq!( m.set_sixteen(65536), - Err(CanError::ParameterOutOfRange { message_id: 1338 }) - )); + Err(CanError::ParameterOutOfRange { + message_id: Id::Standard(StandardId::new(1338).unwrap()) + }) + ); } #[test] @@ -170,3 +177,19 @@ fn test_min_max_doesnt_confuse_width() { "This signal should be i16 even though the min/max only needs i8." ) } + +#[test] +fn test_standard_id() { + assert_eq!( + Foo::MESSAGE_ID, + Id::Standard(StandardId::new(0x100).unwrap()) + ) +} + +#[test] +fn test_extended_id() { + assert_eq!( + MsgExtendedId::MESSAGE_ID, + Id::Extended(ExtendedId::new(0x1234).unwrap()) + ) +} diff --git a/testing/dbc-examples/example.dbc b/testing/dbc-examples/example.dbc index fa60111..1492e7f 100644 --- a/testing/dbc-examples/example.dbc +++ b/testing/dbc-examples/example.dbc @@ -63,6 +63,9 @@ BO_ 9001 TruncatedBeSignal: 8 Ipsum BO_ 9002 TruncatedLeSignal: 8 Ipsum SG_ Foo : 0|12@1- (1,0) [-100|100] "" Vector__XXX +BO_ 2147488308 MsgExtendedId: 8 Sit + SG_ Dummy : 15|2@0+ (1,0) [0|3] "" 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"; diff --git a/testing/rust-integration/Cargo.toml b/testing/rust-integration/Cargo.toml index 25bfe78..5780dab 100644 --- a/testing/rust-integration/Cargo.toml +++ b/testing/rust-integration/Cargo.toml @@ -7,3 +7,4 @@ edition = "2021" [dependencies] approx = "0.4" can-messages = { path = "../can-messages" } +embedded-can = "0.4.1" diff --git a/testing/rust-integration/src/main.rs b/testing/rust-integration/src/main.rs index 26b3168..7f33e4a 100644 --- a/testing/rust-integration/src/main.rs +++ b/testing/rust-integration/src/main.rs @@ -1,4 +1,5 @@ use can_messages::Messages; +use embedded_can::{Id, StandardId}; fn main() { let input = std::env::args() @@ -10,7 +11,7 @@ fn main() { let (id, payload) = { let mut s = data.split('#'); let id = s.next().unwrap(); - let id: u32 = u32::from_str_radix(id, 16).unwrap(); + let id = Id::Standard(StandardId::new(u16::from_str_radix(id, 16).unwrap()).unwrap()); let payload = s.next().unwrap(); let payload = (0..(payload.len() / 2)) .map(|i| { From 56c4fcbddce0d27a17a0789413176e1de63ad89b Mon Sep 17 00:00:00 2001 From: Daniel Trnka Date: Mon, 19 Aug 2024 10:33:25 +0200 Subject: [PATCH 2/2] Generate embedded_can::Frame trait for each frame --- src/lib.rs | 56 ++++ testing/can-messages/src/messages.rs | 468 +++++++++++++++++++++++++++ 2 files changed, 524 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 3e7142a..f3a7efb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -74,6 +74,10 @@ pub struct Config<'a> { #[builder(default)] pub impl_error: FeatureConfig<'a>, + /// Optional: Generate `embedded_can::Frame` impl for each frame. Default: `Always` + #[builder(default = FeatureConfig::Always)] + pub impl_embedded_can_frame: FeatureConfig<'a>, + /// Optional: Validate min and max values in generated signal setters. Default: `Always` #[builder(default = FeatureConfig::Always)] pub check_ranges: FeatureConfig<'a>, @@ -428,6 +432,8 @@ fn render_message(mut w: impl Write, config: &Config<'_>, msg: &Message, dbc: &D writeln!(w, "}}")?; writeln!(w)?; + render_embedded_can_frame(&mut w, config, msg)?; + render_debug_impl(&mut w, config, msg)?; render_arbitrary(&mut w, config, msg)?; @@ -1285,6 +1291,56 @@ fn multiplexed_enum_variant_name( )) } +fn render_embedded_can_frame( + w: &mut impl Write, + config: &Config<'_>, + msg: &Message, +) -> Result<(), std::io::Error> { + config.impl_embedded_can_frame.fmt_cfg(w, |w| { + writeln!( + w, + "\ +impl embedded_can::Frame for {0} {{ + 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 + }} +}}", + type_name(msg.message_name()) + ) + }) +} + fn render_debug_impl(mut w: impl Write, config: &Config<'_>, msg: &Message) -> Result<()> { match &config.impl_debug { FeatureConfig::Always => {} diff --git a/testing/can-messages/src/messages.rs b/testing/can-messages/src/messages.rs index 8e096ae..6ee9d84 100644 --- a/testing/can-messages/src/messages.rs +++ b/testing/can-messages/src/messages.rs @@ -223,6 +223,42 @@ impl core::convert::TryFrom<&[u8]> for Foo { } } +impl embedded_can::Frame for Foo { + 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 Foo { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { if f.alternate() { @@ -534,6 +570,42 @@ impl core::convert::TryFrom<&[u8]> for Bar { } } +impl embedded_can::Frame for Bar { + 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 Bar { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { if f.alternate() { @@ -720,6 +792,42 @@ impl core::convert::TryFrom<&[u8]> for X4wd { } } +impl embedded_can::Frame for X4wd { + 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 X4wd { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { if f.alternate() { @@ -1028,6 +1136,42 @@ impl core::convert::TryFrom<&[u8]> for Amet { } } +impl embedded_can::Frame for Amet { + 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 Amet { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { if f.alternate() { @@ -1150,6 +1294,42 @@ impl core::convert::TryFrom<&[u8]> for Dolor { } } +impl embedded_can::Frame for Dolor { + 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 Dolor { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { if f.alternate() { @@ -1355,6 +1535,42 @@ impl core::convert::TryFrom<&[u8]> for MultiplexTest { } } +impl embedded_can::Frame for MultiplexTest { + 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 MultiplexTest { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { if f.alternate() { @@ -1866,6 +2082,42 @@ impl core::convert::TryFrom<&[u8]> for IntegerFactorOffset { } } +impl embedded_can::Frame for IntegerFactorOffset { + 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 IntegerFactorOffset { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { if f.alternate() { @@ -2048,6 +2300,42 @@ impl core::convert::TryFrom<&[u8]> for NegativeFactorTest { } } +impl embedded_can::Frame for NegativeFactorTest { + 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 NegativeFactorTest { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { if f.alternate() { @@ -2222,6 +2510,42 @@ impl core::convert::TryFrom<&[u8]> for LargerIntsWithOffsets { } } +impl embedded_can::Frame for LargerIntsWithOffsets { + 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 LargerIntsWithOffsets { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { if f.alternate() { @@ -2286,6 +2610,42 @@ impl core::convert::TryFrom<&[u8]> for MsgWithoutSignals { } } +impl embedded_can::Frame for MsgWithoutSignals { + 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 MsgWithoutSignals { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { if f.alternate() { @@ -2394,6 +2754,42 @@ impl core::convert::TryFrom<&[u8]> for TruncatedBeSignal { } } +impl embedded_can::Frame for TruncatedBeSignal { + 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 TruncatedBeSignal { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { if f.alternate() { @@ -2505,6 +2901,42 @@ impl core::convert::TryFrom<&[u8]> for TruncatedLeSignal { } } +impl embedded_can::Frame for TruncatedLeSignal { + 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 TruncatedLeSignal { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { if f.alternate() { @@ -2614,6 +3046,42 @@ impl core::convert::TryFrom<&[u8]> for MsgExtendedId { } } +impl embedded_can::Frame for MsgExtendedId { + 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 MsgExtendedId { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { if f.alternate() {