From 6f2eba891325f1dc0848afd0e8ec2d8aed91f762 Mon Sep 17 00:00:00 2001 From: Daniel Shoshin Date: Tue, 16 Sep 2025 18:42:14 -0500 Subject: [PATCH 1/2] Using PgnLibrary to parse dbc --- solar_rust/Cargo.lock | 200 +++++++++++++++++++++++++++++++++++++++++ solar_rust/Cargo.toml | 8 ++ solar_rust/example.dbc | 8 ++ solar_rust/src/main.rs | 17 ++++ 4 files changed, 233 insertions(+) create mode 100644 solar_rust/Cargo.lock create mode 100644 solar_rust/Cargo.toml create mode 100644 solar_rust/example.dbc create mode 100644 solar_rust/src/main.rs diff --git a/solar_rust/Cargo.lock b/solar_rust/Cargo.lock new file mode 100644 index 0000000..f93bc1d --- /dev/null +++ b/solar_rust/Cargo.lock @@ -0,0 +1,200 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "canparse" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fee87221d4a3133ec0583b3d666b47334436bfe7a5204d1194b2688d354210fe" +dependencies = [ + "byteorder", + "encoding", + "enum_primitive", + "lazy_static", + "nom", + "regex", + "rustc-serialize", +] + +[[package]] +name = "encoding" +version = "0.2.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b0d943856b990d12d3b55b359144ff341533e516d94098b1d3fc1ac666d36ec" +dependencies = [ + "encoding-index-japanese", + "encoding-index-korean", + "encoding-index-simpchinese", + "encoding-index-singlebyte", + "encoding-index-tradchinese", +] + +[[package]] +name = "encoding-index-japanese" +version = "1.20141219.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04e8b2ff42e9a05335dbf8b5c6f7567e5591d0d916ccef4e0b1710d32a0d0c91" +dependencies = [ + "encoding_index_tests", +] + +[[package]] +name = "encoding-index-korean" +version = "1.20141219.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dc33fb8e6bcba213fe2f14275f0963fd16f0a02c878e3095ecfdf5bee529d81" +dependencies = [ + "encoding_index_tests", +] + +[[package]] +name = "encoding-index-simpchinese" +version = "1.20141219.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d87a7194909b9118fc707194baa434a4e3b0fb6a5a757c73c3adb07aa25031f7" +dependencies = [ + "encoding_index_tests", +] + +[[package]] +name = "encoding-index-singlebyte" +version = "1.20141219.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3351d5acffb224af9ca265f435b859c7c01537c0849754d3db3fdf2bfe2ae84a" +dependencies = [ + "encoding_index_tests", +] + +[[package]] +name = "encoding-index-tradchinese" +version = "1.20141219.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd0e20d5688ce3cab59eb3ef3a2083a5c77bf496cb798dc6fcdb75f323890c18" +dependencies = [ + "encoding_index_tests", +] + +[[package]] +name = "encoding_index_tests" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a246d82be1c9d791c5dfde9a2bd045fc3cbba3fa2b11ad558f27d01712f00569" + +[[package]] +name = "enum_primitive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4551092f4d519593039259a9ed8daedf0da12e5109c5280338073eaeb81180" +dependencies = [ + "num-traits 0.1.43", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "memchr" +version = "2.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" + +[[package]] +name = "nom" +version = "4.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ad2a91a8e869eeb30b9cb3119ae87773a8f4ae617f41b1eb9c154b2905f7bd6" +dependencies = [ + "memchr", + "version_check", +] + +[[package]] +name = "num-traits" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31" +dependencies = [ + "num-traits 0.2.19", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "regex" +version = "1.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23d7fd106d8c02486a8d64e778353d1cffe08ce79ac2e82f540c86d0facf6912" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b9458fa0bfeeac22b5ca447c63aaf45f28439a709ccd244698632f9aa6394d6" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001" + +[[package]] +name = "rustc-serialize" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe834bc780604f4674073badbad26d7219cadfb4a2275802db12cbae17498401" + +[[package]] +name = "solar_rust" +version = "0.1.0" +dependencies = [ + "canparse", +] + +[[package]] +name = "version_check" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" diff --git a/solar_rust/Cargo.toml b/solar_rust/Cargo.toml new file mode 100644 index 0000000..bc3a7d0 --- /dev/null +++ b/solar_rust/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "solar_rust" +version = "0.1.0" +edition = "2024" + +[dependencies] +canparse = "0.1" + diff --git a/solar_rust/example.dbc b/solar_rust/example.dbc new file mode 100644 index 0000000..91d9446 --- /dev/null +++ b/solar_rust/example.dbc @@ -0,0 +1,8 @@ +VERSION "A version string°" + +BO_ 2364539904 EEC1 : 8 Vector__XXX +CM_ BO_ 2364539904 "Engine Controller"; +BA_ "SingleFrame" BO_ 2364539904 0; + SG_ Engine_Speed : 24|16@1+ (0.125,0) [0|8031.88] "rpm" Vector__XXX +CM_ SG_ 2364539904 Engine_Speed "A description for Engine speed."; +BA_ "SPN" SG_ 2364539904 Engine_Speed 190; \ No newline at end of file diff --git a/solar_rust/src/main.rs b/solar_rust/src/main.rs new file mode 100644 index 0000000..eccce3b --- /dev/null +++ b/solar_rust/src/main.rs @@ -0,0 +1,17 @@ +use canparse::pgn::{PgnLibrary, SpnDefinition, ParseMessage}; + +fn main() { + + // Parse dbc file into PgnLibrary + let lib = PgnLibrary::from_dbc_file("./example.dbc").unwrap(); + + // Pull signal definition for engine speed + let enginespeed_def: &SpnDefinition = lib + .get_spn("Engine_Speed").unwrap(); + + // Parse frame containing engine speed + let msg: [u8; 8] = [0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88]; + let engine_speed: f32 = enginespeed_def.parse_message(&msg).unwrap(); + + println!("Engine speed: {}", engine_speed); +} \ No newline at end of file From 40fd5505b70f971727b3c82b33d6048d8b290216 Mon Sep 17 00:00:00 2001 From: Daniel Shoshin Date: Sun, 5 Oct 2025 12:27:57 -0500 Subject: [PATCH 2/2] added parsing for mulitiple dbc files into multiple out files --- solar_rust/Cargo.lock | 203 +- solar_rust/Cargo.toml | 4 +- solar_rust/drivercontroller.dbc | 106 + solar_rust/example.dbc | 8 - solar_rust/motorcontroller.dbc | 204 + solar_rust/mppt.dbc | 112 + solar_rust/src/main.rs | 79 +- solar_rust/src/messages_drivercontroller.rs | 1492 +++++++ solar_rust/src/messages_motorcontroller.rs | 4240 +++++++++++++++++++ solar_rust/src/messages_mppt.rs | 2381 +++++++++++ 10 files changed, 8686 insertions(+), 143 deletions(-) create mode 100644 solar_rust/drivercontroller.dbc delete mode 100644 solar_rust/example.dbc create mode 100644 solar_rust/motorcontroller.dbc create mode 100644 solar_rust/mppt.dbc create mode 100644 solar_rust/src/messages_drivercontroller.rs create mode 100644 solar_rust/src/messages_motorcontroller.rs create mode 100644 solar_rust/src/messages_mppt.rs diff --git a/solar_rust/Cargo.lock b/solar_rust/Cargo.lock index f93bc1d..19779a1 100644 --- a/solar_rust/Cargo.lock +++ b/solar_rust/Cargo.lock @@ -3,198 +3,157 @@ version = 4 [[package]] -name = "aho-corasick" -version = "1.1.3" +name = "anyhow" +version = "1.0.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" -dependencies = [ - "memchr", -] - -[[package]] -name = "autocfg" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" +checksum = "b0674a1ddeecb70197781e945de4b3b8ffb61fa939a5597bcf48503737663100" [[package]] -name = "byteorder" -version = "1.5.0" +name = "can-dbc" +version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - -[[package]] -name = "canparse" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fee87221d4a3133ec0583b3d666b47334436bfe7a5204d1194b2688d354210fe" +checksum = "cbe0d033ec316c3bb50e2e53d7ef3d8805e65c5f976d49daea65a12f7e0f9ce8" dependencies = [ - "byteorder", - "encoding", - "enum_primitive", - "lazy_static", + "derive-getters", "nom", - "regex", - "rustc-serialize", ] [[package]] -name = "encoding" -version = "0.2.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b0d943856b990d12d3b55b359144ff341533e516d94098b1d3fc1ac666d36ec" +name = "dbc-codegen" +version = "0.3.0" +source = "git+https://github.com/technocreatives/dbc-codegen.git?rev=5b9d3d0670563ac91f303ef689e0357b198dbc32#5b9d3d0670563ac91f303ef689e0357b198dbc32" dependencies = [ - "encoding-index-japanese", - "encoding-index-korean", - "encoding-index-simpchinese", - "encoding-index-singlebyte", - "encoding-index-tradchinese", + "anyhow", + "can-dbc", + "embedded-can", + "heck", + "typed-builder", ] [[package]] -name = "encoding-index-japanese" -version = "1.20141219.5" +name = "derive-getters" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04e8b2ff42e9a05335dbf8b5c6f7567e5591d0d916ccef4e0b1710d32a0d0c91" +checksum = "7a2c35ab6e03642397cdda1dd58abbc05d418aef8e36297f336d5aba060fe8df" dependencies = [ - "encoding_index_tests", + "proc-macro2", + "quote", + "syn 1.0.109", ] [[package]] -name = "encoding-index-korean" -version = "1.20141219.5" +name = "embedded-can" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dc33fb8e6bcba213fe2f14275f0963fd16f0a02c878e3095ecfdf5bee529d81" +checksum = "e9d2e857f87ac832df68fa498d18ddc679175cf3d2e4aa893988e5601baf9438" dependencies = [ - "encoding_index_tests", + "nb", ] [[package]] -name = "encoding-index-simpchinese" -version = "1.20141219.5" +name = "heck" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d87a7194909b9118fc707194baa434a4e3b0fb6a5a757c73c3adb07aa25031f7" -dependencies = [ - "encoding_index_tests", -] +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] -name = "encoding-index-singlebyte" -version = "1.20141219.5" +name = "memchr" +version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3351d5acffb224af9ca265f435b859c7c01537c0849754d3db3fdf2bfe2ae84a" -dependencies = [ - "encoding_index_tests", -] +checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" [[package]] -name = "encoding-index-tradchinese" -version = "1.20141219.5" +name = "minimal-lexical" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd0e20d5688ce3cab59eb3ef3a2083a5c77bf496cb798dc6fcdb75f323890c18" -dependencies = [ - "encoding_index_tests", -] +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] -name = "encoding_index_tests" -version = "0.1.4" +name = "nb" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a246d82be1c9d791c5dfde9a2bd045fc3cbba3fa2b11ad558f27d01712f00569" +checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d" [[package]] -name = "enum_primitive" -version = "0.1.1" +name = "nom" +version = "7.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be4551092f4d519593039259a9ed8daedf0da12e5109c5280338073eaeb81180" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" dependencies = [ - "num-traits 0.1.43", + "memchr", + "minimal-lexical", ] [[package]] -name = "lazy_static" -version = "1.5.0" +name = "proc-macro2" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" - -[[package]] -name = "memchr" -version = "2.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" - -[[package]] -name = "nom" -version = "4.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ad2a91a8e869eeb30b9cb3119ae87773a8f4ae617f41b1eb9c154b2905f7bd6" +checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" dependencies = [ - "memchr", - "version_check", + "unicode-ident", ] [[package]] -name = "num-traits" -version = "0.1.43" +name = "quote" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" dependencies = [ - "num-traits 0.2.19", + "proc-macro2", ] [[package]] -name = "num-traits" -version = "0.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +name = "solar_rust" +version = "0.1.0" dependencies = [ - "autocfg", + "anyhow", + "dbc-codegen", ] [[package]] -name = "regex" -version = "1.11.2" +name = "syn" +version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23d7fd106d8c02486a8d64e778353d1cffe08ce79ac2e82f540c86d0facf6912" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ - "aho-corasick", - "memchr", - "regex-automata", - "regex-syntax", + "proc-macro2", + "quote", + "unicode-ident", ] [[package]] -name = "regex-automata" -version = "0.4.10" +name = "syn" +version = "2.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b9458fa0bfeeac22b5ca447c63aaf45f28439a709ccd244698632f9aa6394d6" +checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", + "proc-macro2", + "quote", + "unicode-ident", ] [[package]] -name = "regex-syntax" -version = "0.8.6" +name = "typed-builder" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001" +checksum = "77739c880e00693faef3d65ea3aad725f196da38b22fdc7ea6ded6e1ce4d3add" +dependencies = [ + "typed-builder-macro", +] [[package]] -name = "rustc-serialize" -version = "0.3.25" +name = "typed-builder-macro" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe834bc780604f4674073badbad26d7219cadfb4a2275802db12cbae17498401" - -[[package]] -name = "solar_rust" -version = "0.1.0" +checksum = "1f718dfaf347dcb5b983bfc87608144b0bad87970aebcbea5ce44d2a30c08e63" dependencies = [ - "canparse", + "proc-macro2", + "quote", + "syn 2.0.106", ] [[package]] -name = "version_check" -version = "0.1.5" +name = "unicode-ident" +version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" +checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" diff --git a/solar_rust/Cargo.toml b/solar_rust/Cargo.toml index bc3a7d0..0d9fb3d 100644 --- a/solar_rust/Cargo.toml +++ b/solar_rust/Cargo.toml @@ -4,5 +4,7 @@ version = "0.1.0" edition = "2024" [dependencies] -canparse = "0.1" +anyhow = "1.0.99" +dbc-codegen = { git = "https://github.com/technocreatives/dbc-codegen.git", rev = "5b9d3d0670563ac91f303ef689e0357b198dbc32" } + diff --git a/solar_rust/drivercontroller.dbc b/solar_rust/drivercontroller.dbc new file mode 100644 index 0000000..b15552b --- /dev/null +++ b/solar_rust/drivercontroller.dbc @@ -0,0 +1,106 @@ +VERSION "" + + +NS_ : + NS_DESC_ + CM_ + BA_DEF_ + BA_ + VAL_ + CAT_DEF_ + CAT_ + FILTER + BA_DEF_DEF_ + EV_DATA_ + ENVVAR_DATA_ + SGTYPE_ + SGTYPE_VAL_ + BA_DEF_SGTYPE_ + BA_SGTYPE_ + SIG_TYPE_REF_ + VAL_TABLE_ + SIG_GROUP_ + SIG_VALTYPE_ + SIGTYPE_VALTYPE_ + BO_TX_BU_ + BA_DEF_REL_ + BA_REL_ + BA_DEF_DEF_REL_ + BU_SG_REL_ + BU_EV_REL_ + BU_BO_REL_ + SG_MUL_VAL_ + +BS_: + +BU_: DriverControl + + +BO_ 1280 IDInfo: 8 DriverControl +SG_ TritiumID : 0|32@1+ (1,0) [0|0] "" Vector__XXX +SG_ SerialNumber : 32|32@1+ (1,0) [0|0] "" Vector__XXX + +BO_ 1281 Drive: 8 DriverControl +SG_ SetpointMotorVelocity : 0|32@1- (1,0) [0|0] "rpm" Vector__XXX +SG_ SetpointMotorCurrent : 32|32@1- (100,0) [0|0] "%" Vector__XXX + +BO_ 1282 Power: 8 DriverControl +SG_ Reserved : 0|32@1- (1,0) [0|0] "" Vector__XXX +SG_ SetpointBusCurrent : 32|32@1- (100,0) [0|0] "%" Vector__XXX + +BO_ 1283 Reset: 8 DriverControl +SG_ Unused : 0|32@1- (1,0) [0|0] "" Vector__XXX +SG_ Unused : 32|32@1- (1,0) [0|0] "" Vector__XXX + +BO_ 1285 Switch: 8 DriverControl +SG_ IgnitionRun : 5|1@1+ (1,0) [0|0] "Selected" Vector__XXX +SG_ Flags : 48|8@1+ (1,0) [0|0] "" Vector__XXX +SG_ State : 56|8@1+ (1,0) [0|0] "" Vector__XXX +SG_ Brake : 7|1@1+ (1,0) [0|0] "On / Off" Vector__XXX +SG_ ModeRegen : 2|1@1+ (1,0) [0|0] "Selected" Vector__XXX +SG_ ChargePort : 8|1@1+ (1,0) [0|0] "Connected / Disconnected" Vector__XXX +SG_ IgnitionStart : 6|1@1+ (1,0) [0|0] "Selected" Vector__XXX +SG_ IgnitionAccesories : 4|1@1+ (1,0) [0|0] "Selected" Vector__XXX +SG_ ModeDrive : 3|1@1+ (1,0) [0|0] "Selected" Vector__XXX +SG_ ModeNetural : 1|1@1+ (1,0) [0|0] "Selected" Vector__XXX +SG_ ModeReverse : 0|1@1+ (1,0) [0|0] "Selected" Vector__XXX + + +CM_ SG_ 1280 TritiumID "Device identifier. 0x00004003"; +CM_ SG_ 1280 SerialNumber "Device serial number, allocated at manufacture."; +CM_ SG_ 1281 SetpointMotorVelocity "Desired motor velocity set point in rpm"; +CM_ SG_ 1281 SetpointMotorCurrent "Desired motor current set point as a percentage of maximum current setting."; +CM_ SG_ 1282 SetpointBusCurrent "Desired set point of current drawn from the bus by the controller as a percentage of absolute bus current limit."; +CM_ SG_ 1285 IgnitionRun "Ignition key is in the run position"; +CM_ SG_ 1285 Flags "Flags currently being reported by the Driver Controller, check the code for more details."; +CM_ SG_ 1285 State "Latest state as being reported by the Driver Controller, check the code for more detail on valid states"; +CM_ SG_ 1285 Brake "Brake pedal is currently being pressed if flag is set (1 set / 0 unset)"; +CM_ SG_ 1285 ModeRegen "Car is regerating power from the motor if set (1 set / 0 unset)"; +CM_ SG_ 1285 ChargePort "Charge point is currently open if set (1 set / 0 unset), port must be closed for car to drive."; +CM_ SG_ 1285 IgnitionStart "Ignition key is in the start position"; +CM_ SG_ 1285 IgnitionAccesories "Ignition key is in the accesories position"; +CM_ SG_ 1285 ModeDrive "Car is in drive mode if set (1 set / 0 unset)"; +CM_ SG_ 1285 ModeNetural "Car is in netural if set (1 set / 0 unset)"; +CM_ SG_ 1285 ModeReverse "Car is in reverse if set (1 set / 0 unset)"; +BA_DEF_ BO_ "GenMsgCycleTime" INT 2 50000; +BA_DEF_ BU_ "GenNodAutoGenSnd" ENUM "No","Yes"; +BA_DEF_ BU_ "GenNodAutoGenDsp" ENUM "No","Yes"; +BA_DEF_ "GenEnvVarEndingDsp" STRING ; +BA_DEF_ "GenEnvVarEndingSnd" STRING ; +BA_DEF_ "GenEnvVarPrefix" STRING ; +BA_DEF_DEF_ "GenMsgCycleTime" 100; +BA_DEF_DEF_ "GenNodAutoGenSnd" "Yes"; +BA_DEF_DEF_ "GenNodAutoGenDsp" "Yes"; +BA_DEF_DEF_ "GenEnvVarEndingDsp" "Dsp"; +BA_DEF_DEF_ "GenEnvVarEndingSnd" "Snd"; +BA_DEF_DEF_ "GenEnvVarPrefix" "Env"; +BA_ "GenMsgCycleTime" BO_ 1280 1000; +BA_ "GenMsgCycleTime" BO_ 1281 200; +BA_ "GenMsgCycleTime" BO_ 1282 200; +BA_ "GenMsgCycleTime" BO_ 1283 200; +BA_ "GenMsgCycleTime" BO_ 1285 200; +SIG_VALTYPE_ 1281 SetpointMotorVelocity : 1; +SIG_VALTYPE_ 1281 SetpointMotorCurrent : 1; +SIG_VALTYPE_ 1282 Reserved : 1; +SIG_VALTYPE_ 1282 SetpointBusCurrent : 1; +SIG_VALTYPE_ 1283 Unused : 1; diff --git a/solar_rust/example.dbc b/solar_rust/example.dbc deleted file mode 100644 index 91d9446..0000000 --- a/solar_rust/example.dbc +++ /dev/null @@ -1,8 +0,0 @@ -VERSION "A version string°" - -BO_ 2364539904 EEC1 : 8 Vector__XXX -CM_ BO_ 2364539904 "Engine Controller"; -BA_ "SingleFrame" BO_ 2364539904 0; - SG_ Engine_Speed : 24|16@1+ (0.125,0) [0|8031.88] "rpm" Vector__XXX -CM_ SG_ 2364539904 Engine_Speed "A description for Engine speed."; -BA_ "SPN" SG_ 2364539904 Engine_Speed 190; \ No newline at end of file diff --git a/solar_rust/motorcontroller.dbc b/solar_rust/motorcontroller.dbc new file mode 100644 index 0000000..ff0272b --- /dev/null +++ b/solar_rust/motorcontroller.dbc @@ -0,0 +1,204 @@ +VERSION "" + + +NS_ : + NS_DESC_ + CM_ + BA_DEF_ + BA_ + VAL_ + CAT_DEF_ + CAT_ + FILTER + BA_DEF_DEF_ + EV_DATA_ + ENVVAR_DATA_ + SGTYPE_ + SGTYPE_VAL_ + BA_DEF_SGTYPE_ + BA_SGTYPE_ + SIG_TYPE_REF_ + VAL_TABLE_ + SIG_GROUP_ + SIG_VALTYPE_ + SIGTYPE_VALTYPE_ + BO_TX_BU_ + BA_DEF_REL_ + BA_REL_ + BA_DEF_DEF_REL_ + BU_SG_REL_ + BU_EV_REL_ + BU_BO_REL_ + SG_MUL_VAL_ + +BS_: + +BU_: WaveSculptor22 + + +BO_ 128 IDInfo: 8 WaveSculptor22 +SG_ TritiumID : 0|32@1+ (1,0) [0|0] "" Vector__XXX +SG_ SerialNumber : 32|32@1+ (1,0) [0|0] "" Vector__XXX + +BO_ 129 Status: 8 WaveSculptor22 +SG_ LimitReserved : 7|9@1+ (1,0) [0|511] "On / Off" Vector__XXX +SG_ LimitIpmOrMotorTemp : 6|1@1+ (1,0) [0|1] "On / Off" Vector__XXX +SG_ LimitBusVoltageLower : 5|1@1+ (1,0) [0|1] "On / Off" Vector__XXX +SG_ LimitBusVoltageUpper : 4|1@1+ (1,0) [0|1] "On / Off" Vector__XXX +SG_ LimitBusCurrent : 3|1@1+ (1,0) [0|1] "On / Off" Vector__XXX +SG_ LimitVelocity : 2|1@1+ (1,0) [0|1] "On / Off" Vector__XXX +SG_ LimitMotorCurrent : 1|1@1+ (1,0) [0|1] "On / Off" Vector__XXX +SG_ LimitOutputVoltagePWM : 0|1@1+ (1,0) [0|1] "On / Off" Vector__XXX +SG_ ErrorReserved : 25|7@1+ (1,0) [0|0] "On / Off" Vector__XXX +SG_ ErrorMotorOverSpeed : 24|1@1+ (1,0) [0|1] "On / Off" Vector__XXX +SG_ ErrorDesaturationFault : 23|1@1+ (1,0) [0|1] "On / Off" Vector__XXX +SG_ Error15vRailUnderVoltage : 22|1@1+ (1,0) [0|1] "On / Off" Vector__XXX +SG_ ErrorConfigRead : 21|1@1+ (1,0) [0|1] "On / Off" Vector__XXX +SG_ ErrorWatchdogCausedLastReset : 20|1@1+ (1,0) [0|1] "On / Off" Vector__XXX +SG_ ErrorBadMotorPositionHallSeq : 19|1@1+ (1,0) [0|1] "On / Off" Vector__XXX +SG_ ErrorDcBusOverVoltage : 18|1@1+ (1,0) [0|1] "On / Off" Vector__XXX +SG_ ErrorSoftwareOverCurrent : 17|1@1+ (1,0) [0|1] "On / Off" Vector__XXX +SG_ ErrorHardwareOverCurrent : 16|1@1+ (1,0) [0|1] "On / Off" Vector__XXX +SG_ ActiveMotor : 32|16@1+ (1,0) [0|0] "" Vector__XXX +SG_ TxErrorCount : 48|8@1+ (1,0) [0|0] "" Vector__XXX +SG_ RxErrorCount : 56|8@1+ (1,0) [0|0] "" Vector__XXX + +BO_ 130 BusMeasurement: 8 WaveSculptor22 +SG_ BusVoltage : 0|32@1- (1,0) [0|0] "V" Vector__XXX +SG_ BusCurrent : 32|32@1- (1,0) [0|0] "A" Vector__XXX + +BO_ 131 VelocityMeasurement: 8 WaveSculptor22 +SG_ MotorVelocity : 0|32@1- (1,0) [0|0] "rpm" Vector__XXX +SG_ VehicleVelocity : 32|32@1- (1,0) [0|0] "m/s" Vector__XXX + +BO_ 132 PhaseCurrentMeasurement: 8 WaveSculptor22 +SG_ PhaseCurrentB : 0|32@1- (1,0) [0|0] "A_rms" Vector__XXX +SG_ PhaseCurrentC : 32|32@1- (1,0) [0|0] "A_rms" Vector__XXX + +BO_ 133 MotorVoltageVectorMeasurement: 8 WaveSculptor22 +SG_ Vq : 0|32@1- (1,0) [0|0] "V" Vector__XXX +SG_ Vd : 32|32@1- (1,0) [0|0] "V" Vector__XXX + +BO_ 134 MotorCurrentVectorMeasurement: 8 WaveSculptor22 +SG_ Iq : 0|32@1- (1,0) [0|0] "A" Vector__XXX +SG_ Id : 32|32@1- (1,0) [0|0] "A" Vector__XXX + +BO_ 135 BackEMFMeasurementPrediction: 8 WaveSculptor22 +SG_ BEMFq : 0|32@1- (1,0) [0|0] "V" Vector__XXX +SG_ BEMFd : 32|32@1- (1,0) [0|0] "V" Vector__XXX + +BO_ 136 VoltageRail15VMeasurement: 8 WaveSculptor22 +SG_ Supply15V : 32|32@1- (1,0) [0|0] "V" Vector__XXX +SG_ ReservedSupply15V : 0|32@1- (1,0) [0|0] "" Vector__XXX + +BO_ 137 VoltageRail3V31V9Measurement: 8 WaveSculptor22 +SG_ Supply1V9 : 0|32@1- (1,0) [0|0] "V" Vector__XXX +SG_ Supply3V3 : 32|32@1- (1,0) [0|0] "V" Vector__XXX + +BO_ 138 Reserved0A: 8 WaveSculptor22 +SG_ Reserved0A0 : 0|32@1- (1,0) [0|0] "" Vector__XXX +SG_ Reserved0A1 : 32|32@1- (1,0) [0|0] "" Vector__XXX + +BO_ 139 HeatsinkMotorTempMeasurement: 8 WaveSculptor22 +SG_ MotorTemp : 0|32@1- (1,0) [0|0] "C" Vector__XXX +SG_ HeatsinkTemp : 32|32@1- (1,0) [0|0] "C" Vector__XXX + +BO_ 140 DspBoardTempMeasurement: 8 WaveSculptor22 +SG_ DspBoardTemp : 0|32@1- (1,0) [0|0] "C" Vector__XXX +SG_ ReservedDspBoardTemp : 32|32@1- (1,0) [0|0] "" Vector__XXX + +BO_ 141 Reserved0D: 8 WaveSculptor22 +SG_ Reserved0D0 : 0|32@1- (1,0) [0|0] "" Vector__XXX +SG_ Reserved0D1 : 32|32@1- (1,0) [0|0] "" Vector__XXX + +BO_ 142 OdometerBusAhMeasurement: 8 WaveSculptor22 +SG_ Odometer : 0|32@1- (1,0) [0|0] "m" Vector__XXX +SG_ DCBusAh : 32|32@1- (1,0) [0|0] "Ah" Vector__XXX + +BO_ 151 SlipSpeedMeasurement: 8 WaveSculptor22 +SG_ SlipSpeed : 0|32@1- (1,0) [0|0] "Hz" Vector__XXX +SG_ ReservedSlipSpeed : 32|32@1- (1,0) [0|0] "" Vector__XXX + + +CM_ SG_ 128 TritiumID "Device identifier. 0x00004003"; +CM_ SG_ 128 SerialNumber "Device serial number, allocated at manufacture."; +CM_ SG_ 129 ActiveMotor "The index of the active motor currently being used."; +CM_ SG_ 129 TxErrorCount "The DSP CAN transmission error counter (CAN 2.0)"; +CM_ SG_ 129 RxErrorCount "The DSP CAN receive error counter (CAN 2.0)"; +CM_ SG_ 130 BusVoltage "DC bus voltage at the controller."; +CM_ SG_ 130 BusCurrent "Current drawn from the DC bus by the controller."; +CM_ SG_ 131 MotorVelocity "Motor angular frequency in revolutions per minute."; +CM_ SG_ 131 VehicleVelocity "Vehicle velocity in metres / second."; +CM_ SG_ 132 PhaseCurrentB "RMS current in motor Phase B."; +CM_ SG_ 132 PhaseCurrentC "RMS current in motor Phase C."; +CM_ SG_ 133 Vq "Imaginary component of the applied non-rotating voltage vector to the motor."; +CM_ SG_ 133 Vd "Real component of the applied non-rotating voltage vector to the motor."; +CM_ SG_ 134 Iq "Imaginary component of the applied non-rotating current vector to the motor. This current produces torque in the motor and should be in phase with the back-EMF of the motor"; +CM_ SG_ 134 Id "Real component of the applied non-rotating current vector to the motor. This vector represents the field current of the motor."; +CM_ SG_ 135 BEMFq "The peak of the phase to neutral motor voltage."; +CM_ SG_ 135 BEMFd "By definition this value is always 0V."; +CM_ SG_ 136 Supply15V "Actual voltage level of the 15V power rail."; +CM_ SG_ 137 Supply1V9 "Actual voltage level of the 1.9V DSP power rail."; +CM_ SG_ 137 Supply3V3 "Actual voltage level of the 3.3V power rail."; +CM_ SG_ 139 MotorTemp "Internal temperature of the motor"; +CM_ SG_ 139 HeatsinkTemp "Internal temperature of Heat-sink (case)."; +CM_ SG_ 140 DspBoardTemp "Temperature of the DSP board."; +CM_ SG_ 142 Odometer "Distance the vehicle has travelled since reset."; +CM_ SG_ 142 DCBusAh "Charge flow into the controller DC bus from the time of reset."; +CM_ SG_ 151 SlipSpeed "Slip speed when driving an induction motor."; +BA_DEF_ BO_ "GenMsgCycleTime" INT 2 50000; +BA_DEF_ BU_ "GenNodAutoGenSnd" ENUM "No","Yes"; +BA_DEF_ BU_ "GenNodAutoGenDsp" ENUM "No","Yes"; +BA_DEF_ "GenEnvVarEndingDsp" STRING ; +BA_DEF_ "GenEnvVarEndingSnd" STRING ; +BA_DEF_ "GenEnvVarPrefix" STRING ; +BA_DEF_DEF_ "GenMsgCycleTime" 100; +BA_DEF_DEF_ "GenNodAutoGenSnd" "Yes"; +BA_DEF_DEF_ "GenNodAutoGenDsp" "Yes"; +BA_DEF_DEF_ "GenEnvVarEndingDsp" "Dsp"; +BA_DEF_DEF_ "GenEnvVarEndingSnd" "Snd"; +BA_DEF_DEF_ "GenEnvVarPrefix" "Env"; +BA_ "GenMsgCycleTime" BO_ 128 1000; +BA_ "GenMsgCycleTime" BO_ 129 200; +BA_ "GenMsgCycleTime" BO_ 130 200; +BA_ "GenMsgCycleTime" BO_ 131 200; +BA_ "GenMsgCycleTime" BO_ 132 200; +BA_ "GenMsgCycleTime" BO_ 133 200; +BA_ "GenMsgCycleTime" BO_ 134 200; +BA_ "GenMsgCycleTime" BO_ 135 200; +BA_ "GenMsgCycleTime" BO_ 136 1000; +BA_ "GenMsgCycleTime" BO_ 137 1000; +BA_ "GenMsgCycleTime" BO_ 138 0; +BA_ "GenMsgCycleTime" BO_ 139 1000; +BA_ "GenMsgCycleTime" BO_ 140 1000; +BA_ "GenMsgCycleTime" BO_ 141 1000; +BA_ "GenMsgCycleTime" BO_ 142 1000; +BA_ "GenMsgCycleTime" BO_ 151 200; +SIG_VALTYPE_ 130 BusVoltage : 1; +SIG_VALTYPE_ 130 BusCurrent : 1; +SIG_VALTYPE_ 131 MotorVelocity : 1; +SIG_VALTYPE_ 131 VehicleVelocity : 1; +SIG_VALTYPE_ 132 PhaseCurrentB : 1; +SIG_VALTYPE_ 132 PhaseCurrentC : 1; +SIG_VALTYPE_ 133 Vq : 1; +SIG_VALTYPE_ 133 Vd : 1; +SIG_VALTYPE_ 134 Iq : 1; +SIG_VALTYPE_ 134 Id : 1; +SIG_VALTYPE_ 135 BEMFq : 1; +SIG_VALTYPE_ 135 BEMFd : 1; +SIG_VALTYPE_ 136 Supply15V : 1; +SIG_VALTYPE_ 136 ReservedSupply15V : 1; +SIG_VALTYPE_ 137 Supply1V9 : 1; +SIG_VALTYPE_ 137 Supply3V3 : 1; +SIG_VALTYPE_ 138 Reserved0A0 : 1; +SIG_VALTYPE_ 138 Reserved0A1 : 1; +SIG_VALTYPE_ 139 MotorTemp : 1; +SIG_VALTYPE_ 139 HeatsinkTemp : 1; +SIG_VALTYPE_ 140 DspBoardTemp : 1; +SIG_VALTYPE_ 140 ReservedDspBoardTemp : 1; +SIG_VALTYPE_ 141 Reserved0D0 : 1; +SIG_VALTYPE_ 141 Reserved0D1 : 1; +SIG_VALTYPE_ 142 Odometer : 1; +SIG_VALTYPE_ 142 DCBusAh : 1; +SIG_VALTYPE_ 151 SlipSpeed : 1; +SIG_VALTYPE_ 151 ReservedSlipSpeed : 1; diff --git a/solar_rust/mppt.dbc b/solar_rust/mppt.dbc new file mode 100644 index 0000000..82cc01a --- /dev/null +++ b/solar_rust/mppt.dbc @@ -0,0 +1,112 @@ +VERSION "" + + +NS_ : + NS_DESC_ + CM_ + BA_DEF_ + BA_ + VAL_ + CAT_DEF_ + CAT_ + FILTER + BA_DEF_DEF_ + EV_DATA_ + ENVVAR_DATA_ + SGTYPE_ + SGTYPE_VAL_ + BA_DEF_SGTYPE_ + BA_SGTYPE_ + SIG_TYPE_REF_ + VAL_TABLE_ + SIG_GROUP_ + SIG_VALTYPE_ + SIGTYPE_VALTYPE_ + BO_TX_BU_ + BA_DEF_REL_ + BA_REL_ + BA_DEF_DEF_REL_ + BU_SG_REL_ + BU_EV_REL_ + BU_BO_REL_ + SG_MUL_VAL_ + +BS_: + +BU_: ElmarSolarMPPT + + +BO_ 1536 PowerInput: 8 ElmarSolarMPPT +SG_ InputVoltage : 0|32@1- (1,0) [0|0] "V" Vector__XXX +SG_ InputCurrent : 32|32@1- (1,0) [0|0] "A" Vector__XXX + +BO_ 1537 PowerOutput: 8 ElmarSolarMPPT +SG_ OutputVoltage : 0|32@1- (1,0) [0|0] "V" Vector__XXX +SG_ OutputCurrent : 32|32@1- (1,0) [0|0] "A" Vector__XXX + +BO_ 1538 Temperature: 8 ElmarSolarMPPT +SG_ MosfetTemperature : 0|32@1- (1,0) [0|0] "C" Vector__XXX +SG_ ControllerTemperature : 32|32@1- (1,0) [0|0] "C" Vector__XXX + +BO_ 1539 AuxillaryPowerSupply: 8 ElmarSolarMPPT +SG_ TwelveVolt : 0|32@1- (1,0) [0|0] "V" Vector__XXX +SG_ ThreeVolt : 32|32@1- (1,0) [0|0] "V" Vector__XXX + +BO_ 1540 Limits: 8 ElmarSolarMPPT +SG_ MaxOutputVoltage : 0|32@1- (1,0) [0|0] "V" Vector__XXX +SG_ MaxInputCurrent : 32|32@1- (1,0) [0|0] "A" Vector__XXX + +BO_ 1541 Status: 8 ElmarSolarMPPT +SG_ ErrorReserved : 29|1@1+ (1,0) [0|1] "On / Off" Vector__XXX +SG_ ErrorMosfetOverheat : 25|1@1+ (1,0) [0|1] "On / Off" Vector__XXX +SG_ ErrorLowArrowPower : 24|1@1+ (1,0) [0|1] "On / Off" Vector__XXX +SG_ ErrorHwOverVoltage : 31|1@1+ (1,0) [0|1] "On / Off" Vector__XXX +SG_ ErrorHwOverCurrent : 30|1@1+ (1,0) [0|1] "On / Off" Vector__XXX +SG_ ErrorBatteryLow : 26|1@1+ (1,0) [0|1] "On / Off" Vector__XXX +SG_ ErrorBatteryFull : 27|1@1+ (1,0) [0|1] "On / Off" Vector__XXX +SG_ Error12vUndervoltage : 28|1@1+ (1,0) [0|1] "On / Off" Vector__XXX +SG_ LimitOutputVoltageMax : 34|1@1+ (1,0) [0|1] "On / Off" Vector__XXX +SG_ LimitMosfetTemperature : 35|1@1+ (1,0) [0|1] "On / Off" Vector__XXX +SG_ LimitLocalMPPT : 38|1@1+ (1,0) [0|1] "On / Off" Vector__XXX +SG_ LimitInputCurrentMin : 32|1@1+ (1,0) [0|1] "On / Off" Vector__XXX +SG_ LimitInputCurrentMax : 33|1@1+ (1,0) [0|1] "On / Off" Vector__XXX +SG_ LimitGlobalMPPT : 39|1@1+ (1,0) [0|1] "On / Off" Vector__XXX +SG_ LimitDutyCycleMax : 37|1@1+ (1,0) [0|1] "On / Off" Vector__XXX +SG_ LimitDuryCycleMin : 36|1@1+ (1,0) [0|1] "On / Off" Vector__XXX +SG_ CanRXErrorCounter : 0|8@1+ (1,0) [0|0] "" Vector__XXX +SG_ CanTXErrorCounter : 8|8@1+ (1,0) [0|0] "" Vector__XXX +SG_ CanTXOverflowCounter : 16|8@1+ (1,0) [0|0] "" Vector__XXX +SG_ Mode : 40|8@1+ (1,0) [0|1] "" Vector__XXX +SG_ Reserved : 48|8@1+ (1,0) [0|0] "" Vector__XXX +SG_ TestCounter : 56|8@1+ (1,0) [0|0] "" Vector__XXX + +BO_ 1542 PowerConnector: 8 ElmarSolarMPPT +SG_ OutputVoltageBatterySide : 0|32@1- (1,0) [0|0] "V" Vector__XXX +SG_ PowerConnectorTemp : 32|32@1- (1,0) [0|0] "C" Vector__XXX + + +CM_ BU_ ElmarSolarMPPT "MPPT created by Elmar solar, either Series A or B"; +CM_ SG_ 1536 InputVoltage "Input Voltage on the MPPT"; +CM_ SG_ 1536 InputCurrent "Input Current on the MPPT"; +CM_ SG_ 1537 OutputVoltage "Output Voltage from the MPPT"; +CM_ SG_ 1537 OutputCurrent "Output Current from the MPPT"; +CM_ SG_ 1538 MosfetTemperature "Temperature as measured at the Mosfet"; +CM_ SG_ 1538 ControllerTemperature "Temperature as measured at the controller"; +CM_ SG_ 1539 TwelveVolt "Voltage as measured at the 12v power auxillary supply"; +CM_ SG_ 1539 ThreeVolt "Voltage as measured at the 3v power supply"; +CM_ SG_ 1540 MaxOutputVoltage "Maximim Output voltage configured for the device"; +CM_ SG_ 1540 MaxInputCurrent "Maximum Input current configured for the device"; +CM_ SG_ 1542 OutputVoltageBatterySide "Output Voltage (Battery side of fuse)"; +CM_ SG_ 1542 PowerConnectorTemp "Power connector temperature"; +SIG_VALTYPE_ 1536 InputVoltage : 1; +SIG_VALTYPE_ 1536 InputCurrent : 1; +SIG_VALTYPE_ 1537 OutputVoltage : 1; +SIG_VALTYPE_ 1537 OutputCurrent : 1; +SIG_VALTYPE_ 1538 MosfetTemperature : 1; +SIG_VALTYPE_ 1538 ControllerTemperature : 1; +SIG_VALTYPE_ 1539 TwelveVolt : 1; +SIG_VALTYPE_ 1539 ThreeVolt : 1; +SIG_VALTYPE_ 1540 MaxOutputVoltage : 1; +SIG_VALTYPE_ 1540 MaxInputCurrent : 1; +SIG_VALTYPE_ 1542 OutputVoltageBatterySide : 1; +SIG_VALTYPE_ 1542 PowerConnectorTemp : 1; diff --git a/solar_rust/src/main.rs b/solar_rust/src/main.rs index eccce3b..0eec089 100644 --- a/solar_rust/src/main.rs +++ b/solar_rust/src/main.rs @@ -1,17 +1,72 @@ -use canparse::pgn::{PgnLibrary, SpnDefinition, ParseMessage}; +use anyhow::{anyhow, Result}; +use std::{ + fs::{self, File}, + io::{BufWriter, Write}, + process::Command, + path::Path, +}; -fn main() { +use dbc_codegen::*; - // Parse dbc file into PgnLibrary - let lib = PgnLibrary::from_dbc_file("./example.dbc").unwrap(); +fn main() -> Result<()> { + // tuples of dbc files : message files + let jobs = [ + ("./drivercontroller.dbc", "src/messages_drivercontroller.rs"), + ("./motorcontroller.dbc", "src/messages_motorcontroller.rs"), + ("./mppt.dbc", "src/messages_mppt.rs"), + ]; - // Pull signal definition for engine speed - let enginespeed_def: &SpnDefinition = lib - .get_spn("Engine_Speed").unwrap(); + let mut errors: Vec = Vec::new(); - // Parse frame containing engine speed - let msg: [u8; 8] = [0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88]; - let engine_speed: f32 = enginespeed_def.parse_message(&msg).unwrap(); + for (dbc_path, out_path) in &jobs { + match process_one(dbc_path, out_path) { + Ok(_) => println!("wrote {}", out_path), + Err(e) => { + eprintln!("failed to process {} -> {}: {}", dbc_path, out_path, e); + errors.push(e); + } + } + } - println!("Engine speed: {}", engine_speed); -} \ No newline at end of file + if errors.is_empty() { + Ok(()) + } else { + Err(anyhow!("one or more DBCs failed (see stderr)")) + } +} + +fn process_one(dbc_path: &str, out_path: &str) -> Result<()> { + let dbc_bytes = fs::read(dbc_path)?; + let mut out = BufWriter::new(File::create(out_path)?); + + let dbc_name = Path::new(dbc_path) + .file_name() + .and_then(|s| s.to_str()) + .unwrap_or("unknown.dbc"); + + let config = Config::builder() + .dbc_name(dbc_name) + .dbc_content(&dbc_bytes) + .impl_debug(FeatureConfig::Always) + .impl_defmt(FeatureConfig::Always) + .impl_error(FeatureConfig::Gated("std")) + .impl_arbitrary(FeatureConfig::Gated("arb")) + .check_ranges(FeatureConfig::Never) + .build(); + + dbc_codegen::codegen(config, &mut out)?; + out.flush()?; + + // run rustfmt on the generated file + let status = Command::new("rustfmt") + .arg("--edition") + .arg("2021") + .arg(out_path) + .status()?; + + if !status.success() { + eprintln!("rustfmt failed for {} (exit {})", out_path, status); + } + + Ok(()) +} diff --git a/solar_rust/src/messages_drivercontroller.rs b/solar_rust/src/messages_drivercontroller.rs new file mode 100644 index 0000000..6d02a6d --- /dev/null +++ b/solar_rust/src/messages_drivercontroller.rs @@ -0,0 +1,1492 @@ +// Generated code! +#![allow(unused_comparisons, unreachable_patterns, unused_imports)] +#![allow(clippy::let_and_return, clippy::eq_op)] +#![allow(clippy::useless_conversion, clippy::unnecessary_cast)] +#![allow( + clippy::excessive_precision, + clippy::manual_range_contains, + clippy::absurd_extreme_comparisons, + clippy::too_many_arguments +)] +#![deny(clippy::arithmetic_side_effects)] + +//! Message definitions from file `"drivercontroller.dbc"` +//! +//! - Version: `Version("")` + +#[cfg(feature = "arb")] +use arbitrary::{Arbitrary, Unstructured}; +use bitvec::prelude::*; +use core::ops::BitOr; +use embedded_can::{ExtendedId, Id, StandardId}; + +/// All messages +#[derive(Clone, Debug, defmt::Format)] +pub enum Messages { + /// IDInfo + IdInfo(IdInfo), + /// Drive + Drive(Drive), + /// Power + Power(Power), + /// Reset + Reset(Reset), + /// Switch + Switch(Switch), +} + +impl Messages { + /// Read message from CAN frame + #[inline(never)] + pub fn from_can_message(id: Id, payload: &[u8]) -> Result { + let res = match id { + IdInfo::MESSAGE_ID => Messages::IdInfo(IdInfo::try_from(payload)?), + Drive::MESSAGE_ID => Messages::Drive(Drive::try_from(payload)?), + Power::MESSAGE_ID => Messages::Power(Power::try_from(payload)?), + Reset::MESSAGE_ID => Messages::Reset(Reset::try_from(payload)?), + Switch::MESSAGE_ID => Messages::Switch(Switch::try_from(payload)?), + id => return Err(CanError::UnknownMessageId(id)), + }; + Ok(res) + } +} + +/// IDInfo +/// +/// - Standard ID: 1280 (0x500) +/// - Size: 8 bytes +/// - Transmitter: DriverControl +#[derive(Clone, Copy)] +pub struct IdInfo { + raw: [u8; 8], +} + +impl IdInfo { + pub const MESSAGE_ID: embedded_can::Id = + Id::Standard(unsafe { StandardId::new_unchecked(0x500) }); + + pub const TRITIUM_ID_MIN: u32 = 0_u32; + pub const TRITIUM_ID_MAX: u32 = 0_u32; + pub const SERIAL_NUMBER_MIN: u32 = 0_u32; + pub const SERIAL_NUMBER_MAX: u32 = 0_u32; + + /// Construct new IDInfo from values + pub fn new(tritium_id: u32, serial_number: u32) -> Result { + let mut res = Self { raw: [0u8; 8] }; + res.set_tritium_id(tritium_id)?; + res.set_serial_number(serial_number)?; + Ok(res) + } + + /// Access message payload raw value + pub fn raw(&self) -> &[u8; 8] { + &self.raw + } + + /// TritiumID + /// + /// Device identifier. 0x00004003 + /// + /// - Min: 0 + /// - Max: 0 + /// - Unit: "" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn tritium_id(&self) -> u32 { + self.tritium_id_raw() + } + + /// Get raw value of TritiumID + /// + /// - Start bit: 0 + /// - Signal size: 32 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Unsigned + #[inline(always)] + pub fn tritium_id_raw(&self) -> u32 { + let signal = self.raw.view_bits::()[0..32].load_le::(); + + let factor = 1; + u32::from(signal).saturating_mul(factor).saturating_add(0) + } + + /// Set value of TritiumID + #[inline(always)] + pub fn set_tritium_id(&mut self, value: u32) -> Result<(), CanError> { + let factor = 1; + let value = value.checked_sub(0).ok_or(CanError::ParameterOutOfRange { + message_id: IdInfo::MESSAGE_ID, + })?; + let value = (value / factor) as u32; + + self.raw.view_bits_mut::()[0..32].store_le(value); + Ok(()) + } + + /// SerialNumber + /// + /// Device serial number, allocated at manufacture. + /// + /// - Min: 0 + /// - Max: 0 + /// - Unit: "" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn serial_number(&self) -> u32 { + self.serial_number_raw() + } + + /// Get raw value of SerialNumber + /// + /// - Start bit: 32 + /// - Signal size: 32 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Unsigned + #[inline(always)] + pub fn serial_number_raw(&self) -> u32 { + let signal = self.raw.view_bits::()[32..64].load_le::(); + + let factor = 1; + u32::from(signal).saturating_mul(factor).saturating_add(0) + } + + /// Set value of SerialNumber + #[inline(always)] + pub fn set_serial_number(&mut self, value: u32) -> Result<(), CanError> { + let factor = 1; + let value = value.checked_sub(0).ok_or(CanError::ParameterOutOfRange { + message_id: IdInfo::MESSAGE_ID, + })?; + let value = (value / factor) as u32; + + self.raw.view_bits_mut::()[32..64].store_le(value); + Ok(()) + } +} + +impl core::convert::TryFrom<&[u8]> for IdInfo { + 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 IdInfo { + 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 IdInfo { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + if f.alternate() { + f.debug_struct("IdInfo") + .field("tritium_id", &self.tritium_id()) + .field("serial_number", &self.serial_number()) + .finish() + } else { + f.debug_tuple("IdInfo").field(&self.raw).finish() + } + } +} + +impl defmt::Format for IdInfo { + fn format(&self, f: defmt::Formatter) { + defmt::write!( + f, + "IdInfo {{ TritiumID={:?} SerialNumber={:?} }}", + self.tritium_id(), + self.serial_number(), + ); + } +} + +#[cfg(feature = "arb")] +impl<'a> Arbitrary<'a> for IdInfo { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + let tritium_id = u.int_in_range(0..=0)?; + let serial_number = u.int_in_range(0..=0)?; + IdInfo::new(tritium_id, serial_number).map_err(|_| arbitrary::Error::IncorrectFormat) + } +} + +/// Drive +/// +/// - Standard ID: 1281 (0x501) +/// - Size: 8 bytes +/// - Transmitter: DriverControl +#[derive(Clone, Copy)] +pub struct Drive { + raw: [u8; 8], +} + +impl Drive { + pub const MESSAGE_ID: embedded_can::Id = + Id::Standard(unsafe { StandardId::new_unchecked(0x501) }); + + pub const SETPOINT_MOTOR_VELOCITY_MIN: i32 = 0_i32; + pub const SETPOINT_MOTOR_VELOCITY_MAX: i32 = 0_i32; + pub const SETPOINT_MOTOR_CURRENT_MIN: i64 = 0_i64; + pub const SETPOINT_MOTOR_CURRENT_MAX: i64 = 0_i64; + + /// Construct new Drive from values + pub fn new( + setpoint_motor_velocity: i32, + setpoint_motor_current: i64, + ) -> Result { + let mut res = Self { raw: [0u8; 8] }; + res.set_setpoint_motor_velocity(setpoint_motor_velocity)?; + res.set_setpoint_motor_current(setpoint_motor_current)?; + Ok(res) + } + + /// Access message payload raw value + pub fn raw(&self) -> &[u8; 8] { + &self.raw + } + + /// SetpointMotorVelocity + /// + /// Desired motor velocity set point in rpm + /// + /// - Min: 0 + /// - Max: 0 + /// - Unit: "rpm" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn setpoint_motor_velocity(&self) -> i32 { + self.setpoint_motor_velocity_raw() + } + + /// Get raw value of SetpointMotorVelocity + /// + /// - Start bit: 0 + /// - Signal size: 32 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Signed + #[inline(always)] + pub fn setpoint_motor_velocity_raw(&self) -> i32 { + let signal = self.raw.view_bits::()[0..32].load_le::(); + + let factor = 1; + let signal = signal as i32; + i32::from(signal).saturating_mul(factor).saturating_add(0) + } + + /// Set value of SetpointMotorVelocity + #[inline(always)] + pub fn set_setpoint_motor_velocity(&mut self, value: i32) -> Result<(), CanError> { + let factor = 1; + let value = value.checked_sub(0).ok_or(CanError::ParameterOutOfRange { + message_id: Drive::MESSAGE_ID, + })?; + let value = (value / factor) as i32; + + let value = u32::from_ne_bytes(value.to_ne_bytes()); + self.raw.view_bits_mut::()[0..32].store_le(value); + Ok(()) + } + + /// SetpointMotorCurrent + /// + /// Desired motor current set point as a percentage of maximum current setting. + /// + /// - Min: 0 + /// - Max: 0 + /// - Unit: "%" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn setpoint_motor_current(&self) -> i64 { + self.setpoint_motor_current_raw() + } + + /// Get raw value of SetpointMotorCurrent + /// + /// - Start bit: 32 + /// - Signal size: 32 bits + /// - Factor: 100 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Signed + #[inline(always)] + pub fn setpoint_motor_current_raw(&self) -> i64 { + let signal = self.raw.view_bits::()[32..64].load_le::(); + + let factor = 100; + i64::from(signal).saturating_mul(factor).saturating_add(0) + } + + /// Set value of SetpointMotorCurrent + #[inline(always)] + pub fn set_setpoint_motor_current(&mut self, value: i64) -> Result<(), CanError> { + let factor = 100; + let value = value.checked_sub(0).ok_or(CanError::ParameterOutOfRange { + message_id: Drive::MESSAGE_ID, + })?; + let value = (value / factor) as i32; + + 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 Drive { + 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 Drive { + 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 Drive { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + if f.alternate() { + f.debug_struct("Drive") + .field("setpoint_motor_velocity", &self.setpoint_motor_velocity()) + .field("setpoint_motor_current", &self.setpoint_motor_current()) + .finish() + } else { + f.debug_tuple("Drive").field(&self.raw).finish() + } + } +} + +impl defmt::Format for Drive { + fn format(&self, f: defmt::Formatter) { + defmt::write!( + f, + "Drive {{ SetpointMotorVelocity={:?} SetpointMotorCurrent={:?} }}", + self.setpoint_motor_velocity(), + self.setpoint_motor_current(), + ); + } +} + +#[cfg(feature = "arb")] +impl<'a> Arbitrary<'a> for Drive { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + let setpoint_motor_velocity = u.int_in_range(0..=0)?; + let setpoint_motor_current = u.int_in_range(0..=0)?; + Drive::new(setpoint_motor_velocity, setpoint_motor_current) + .map_err(|_| arbitrary::Error::IncorrectFormat) + } +} + +/// Power +/// +/// - Standard ID: 1282 (0x502) +/// - Size: 8 bytes +/// - Transmitter: DriverControl +#[derive(Clone, Copy)] +pub struct Power { + raw: [u8; 8], +} + +impl Power { + pub const MESSAGE_ID: embedded_can::Id = + Id::Standard(unsafe { StandardId::new_unchecked(0x502) }); + + pub const RESERVED_MIN: i32 = 0_i32; + pub const RESERVED_MAX: i32 = 0_i32; + pub const SETPOINT_BUS_CURRENT_MIN: i64 = 0_i64; + pub const SETPOINT_BUS_CURRENT_MAX: i64 = 0_i64; + + /// Construct new Power from values + pub fn new(reserved: i32, setpoint_bus_current: i64) -> Result { + let mut res = Self { raw: [0u8; 8] }; + res.set_reserved(reserved)?; + res.set_setpoint_bus_current(setpoint_bus_current)?; + Ok(res) + } + + /// Access message payload raw value + pub fn raw(&self) -> &[u8; 8] { + &self.raw + } + + /// Reserved + /// + /// - Min: 0 + /// - Max: 0 + /// - Unit: "" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn reserved(&self) -> i32 { + self.reserved_raw() + } + + /// Get raw value of Reserved + /// + /// - Start bit: 0 + /// - Signal size: 32 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Signed + #[inline(always)] + pub fn reserved_raw(&self) -> i32 { + let signal = self.raw.view_bits::()[0..32].load_le::(); + + let factor = 1; + let signal = signal as i32; + i32::from(signal).saturating_mul(factor).saturating_add(0) + } + + /// Set value of Reserved + #[inline(always)] + pub fn set_reserved(&mut self, value: i32) -> Result<(), CanError> { + let factor = 1; + let value = value.checked_sub(0).ok_or(CanError::ParameterOutOfRange { + message_id: Power::MESSAGE_ID, + })?; + let value = (value / factor) as i32; + + let value = u32::from_ne_bytes(value.to_ne_bytes()); + self.raw.view_bits_mut::()[0..32].store_le(value); + Ok(()) + } + + /// SetpointBusCurrent + /// + /// Desired set point of current drawn from the bus by the controller as a percentage of absolute bus current limit. + /// + /// - Min: 0 + /// - Max: 0 + /// - Unit: "%" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn setpoint_bus_current(&self) -> i64 { + self.setpoint_bus_current_raw() + } + + /// Get raw value of SetpointBusCurrent + /// + /// - Start bit: 32 + /// - Signal size: 32 bits + /// - Factor: 100 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Signed + #[inline(always)] + pub fn setpoint_bus_current_raw(&self) -> i64 { + let signal = self.raw.view_bits::()[32..64].load_le::(); + + let factor = 100; + i64::from(signal).saturating_mul(factor).saturating_add(0) + } + + /// Set value of SetpointBusCurrent + #[inline(always)] + pub fn set_setpoint_bus_current(&mut self, value: i64) -> Result<(), CanError> { + let factor = 100; + let value = value.checked_sub(0).ok_or(CanError::ParameterOutOfRange { + message_id: Power::MESSAGE_ID, + })?; + let value = (value / factor) as i32; + + 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 Power { + 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 Power { + 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 Power { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + if f.alternate() { + f.debug_struct("Power") + .field("reserved", &self.reserved()) + .field("setpoint_bus_current", &self.setpoint_bus_current()) + .finish() + } else { + f.debug_tuple("Power").field(&self.raw).finish() + } + } +} + +impl defmt::Format for Power { + fn format(&self, f: defmt::Formatter) { + defmt::write!( + f, + "Power {{ Reserved={:?} SetpointBusCurrent={:?} }}", + self.reserved(), + self.setpoint_bus_current(), + ); + } +} + +#[cfg(feature = "arb")] +impl<'a> Arbitrary<'a> for Power { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + let reserved = u.int_in_range(0..=0)?; + let setpoint_bus_current = u.int_in_range(0..=0)?; + Power::new(reserved, setpoint_bus_current).map_err(|_| arbitrary::Error::IncorrectFormat) + } +} + +/// Reset +/// +/// - Standard ID: 1283 (0x503) +/// - Size: 8 bytes +/// - Transmitter: DriverControl +#[derive(Clone, Copy)] +pub struct Reset { + raw: [u8; 8], +} + +impl Reset { + pub const MESSAGE_ID: embedded_can::Id = + Id::Standard(unsafe { StandardId::new_unchecked(0x503) }); + + pub const UNUSED_MIN: i32 = 0_i32; + pub const UNUSED_MAX: i32 = 0_i32; + pub const UNUSED_MIN: i32 = 0_i32; + pub const UNUSED_MAX: i32 = 0_i32; + + /// Construct new Reset from values + pub fn new(unused: i32, unused: i32) -> Result { + let mut res = Self { raw: [0u8; 8] }; + res.set_unused(unused)?; + res.set_unused(unused)?; + Ok(res) + } + + /// Access message payload raw value + pub fn raw(&self) -> &[u8; 8] { + &self.raw + } + + /// Unused + /// + /// - Min: 0 + /// - Max: 0 + /// - Unit: "" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn unused(&self) -> i32 { + self.unused_raw() + } + + /// Get raw value of Unused + /// + /// - Start bit: 0 + /// - Signal size: 32 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Signed + #[inline(always)] + pub fn unused_raw(&self) -> i32 { + let signal = self.raw.view_bits::()[0..32].load_le::(); + + let factor = 1; + let signal = signal as i32; + i32::from(signal).saturating_mul(factor).saturating_add(0) + } + + /// Set value of Unused + #[inline(always)] + pub fn set_unused(&mut self, value: i32) -> Result<(), CanError> { + let factor = 1; + let value = value.checked_sub(0).ok_or(CanError::ParameterOutOfRange { + message_id: Reset::MESSAGE_ID, + })?; + let value = (value / factor) as i32; + + let value = u32::from_ne_bytes(value.to_ne_bytes()); + self.raw.view_bits_mut::()[0..32].store_le(value); + Ok(()) + } + + /// Unused + /// + /// - Min: 0 + /// - Max: 0 + /// - Unit: "" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn unused(&self) -> i32 { + self.unused_raw() + } + + /// Get raw value of Unused + /// + /// - Start bit: 32 + /// - Signal size: 32 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Signed + #[inline(always)] + pub fn unused_raw(&self) -> i32 { + let signal = self.raw.view_bits::()[32..64].load_le::(); + + let factor = 1; + let signal = signal as i32; + i32::from(signal).saturating_mul(factor).saturating_add(0) + } + + /// Set value of Unused + #[inline(always)] + pub fn set_unused(&mut self, value: i32) -> Result<(), CanError> { + let factor = 1; + let value = value.checked_sub(0).ok_or(CanError::ParameterOutOfRange { + message_id: Reset::MESSAGE_ID, + })?; + let value = (value / factor) as i32; + + 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 Reset { + 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 Reset { + 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 Reset { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + if f.alternate() { + f.debug_struct("Reset") + .field("unused", &self.unused()) + .field("unused", &self.unused()) + .finish() + } else { + f.debug_tuple("Reset").field(&self.raw).finish() + } + } +} + +impl defmt::Format for Reset { + fn format(&self, f: defmt::Formatter) { + defmt::write!( + f, + "Reset {{ Unused={:?} Unused={:?} }}", + self.unused(), + self.unused(), + ); + } +} + +#[cfg(feature = "arb")] +impl<'a> Arbitrary<'a> for Reset { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + let unused = u.int_in_range(0..=0)?; + let unused = u.int_in_range(0..=0)?; + Reset::new(unused, unused).map_err(|_| arbitrary::Error::IncorrectFormat) + } +} + +/// Switch +/// +/// - Standard ID: 1285 (0x505) +/// - Size: 8 bytes +/// - Transmitter: DriverControl +#[derive(Clone, Copy)] +pub struct Switch { + raw: [u8; 8], +} + +impl Switch { + pub const MESSAGE_ID: embedded_can::Id = + Id::Standard(unsafe { StandardId::new_unchecked(0x505) }); + + pub const FLAGS_MIN: u8 = 0_u8; + pub const FLAGS_MAX: u8 = 0_u8; + pub const STATE_MIN: u8 = 0_u8; + pub const STATE_MAX: u8 = 0_u8; + + /// Construct new Switch from values + pub fn new( + ignition_run: bool, + flags: u8, + state: u8, + brake: bool, + mode_regen: bool, + charge_port: bool, + ignition_start: bool, + ignition_accesories: bool, + mode_drive: bool, + mode_netural: bool, + mode_reverse: bool, + ) -> Result { + let mut res = Self { raw: [0u8; 8] }; + res.set_ignition_run(ignition_run)?; + res.set_flags(flags)?; + res.set_state(state)?; + res.set_brake(brake)?; + res.set_mode_regen(mode_regen)?; + res.set_charge_port(charge_port)?; + res.set_ignition_start(ignition_start)?; + res.set_ignition_accesories(ignition_accesories)?; + res.set_mode_drive(mode_drive)?; + res.set_mode_netural(mode_netural)?; + res.set_mode_reverse(mode_reverse)?; + Ok(res) + } + + /// Access message payload raw value + pub fn raw(&self) -> &[u8; 8] { + &self.raw + } + + /// IgnitionRun + /// + /// Ignition key is in the run position + /// + /// - Min: 0 + /// - Max: 0 + /// - Unit: "Selected" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn ignition_run(&self) -> bool { + self.ignition_run_raw() + } + + /// Get raw value of IgnitionRun + /// + /// - Start bit: 5 + /// - Signal size: 1 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Unsigned + #[inline(always)] + pub fn ignition_run_raw(&self) -> bool { + let signal = self.raw.view_bits::()[5..6].load_le::(); + + signal == 1 + } + + /// Set value of IgnitionRun + #[inline(always)] + pub fn set_ignition_run(&mut self, value: bool) -> Result<(), CanError> { + let value = value as u8; + self.raw.view_bits_mut::()[5..6].store_le(value); + Ok(()) + } + + /// Flags + /// + /// Flags currently being reported by the Driver Controller, check the code for more details. + /// + /// - Min: 0 + /// - Max: 0 + /// - Unit: "" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn flags(&self) -> u8 { + self.flags_raw() + } + + /// Get raw value of Flags + /// + /// - Start bit: 48 + /// - Signal size: 8 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Unsigned + #[inline(always)] + pub fn flags_raw(&self) -> u8 { + let signal = self.raw.view_bits::()[48..56].load_le::(); + + let factor = 1; + u8::from(signal).saturating_mul(factor).saturating_add(0) + } + + /// Set value of Flags + #[inline(always)] + pub fn set_flags(&mut self, value: u8) -> Result<(), CanError> { + let factor = 1; + let value = value.checked_sub(0).ok_or(CanError::ParameterOutOfRange { + message_id: Switch::MESSAGE_ID, + })?; + let value = (value / factor) as u8; + + self.raw.view_bits_mut::()[48..56].store_le(value); + Ok(()) + } + + /// State + /// + /// Latest state as being reported by the Driver Controller, check the code for more detail on valid states + /// + /// - Min: 0 + /// - Max: 0 + /// - Unit: "" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn state(&self) -> u8 { + self.state_raw() + } + + /// Get raw value of State + /// + /// - Start bit: 56 + /// - Signal size: 8 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Unsigned + #[inline(always)] + pub fn state_raw(&self) -> u8 { + let signal = self.raw.view_bits::()[56..64].load_le::(); + + let factor = 1; + u8::from(signal).saturating_mul(factor).saturating_add(0) + } + + /// Set value of State + #[inline(always)] + pub fn set_state(&mut self, value: u8) -> Result<(), CanError> { + let factor = 1; + let value = value.checked_sub(0).ok_or(CanError::ParameterOutOfRange { + message_id: Switch::MESSAGE_ID, + })?; + let value = (value / factor) as u8; + + self.raw.view_bits_mut::()[56..64].store_le(value); + Ok(()) + } + + /// Brake + /// + /// Brake pedal is currently being pressed if flag is set (1 set / 0 unset) + /// + /// - Min: 0 + /// - Max: 0 + /// - Unit: "On / Off" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn brake(&self) -> bool { + self.brake_raw() + } + + /// Get raw value of Brake + /// + /// - Start bit: 7 + /// - Signal size: 1 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Unsigned + #[inline(always)] + pub fn brake_raw(&self) -> bool { + let signal = self.raw.view_bits::()[7..8].load_le::(); + + signal == 1 + } + + /// Set value of Brake + #[inline(always)] + pub fn set_brake(&mut self, value: bool) -> Result<(), CanError> { + let value = value as u8; + self.raw.view_bits_mut::()[7..8].store_le(value); + Ok(()) + } + + /// ModeRegen + /// + /// Car is regerating power from the motor if set (1 set / 0 unset) + /// + /// - Min: 0 + /// - Max: 0 + /// - Unit: "Selected" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn mode_regen(&self) -> bool { + self.mode_regen_raw() + } + + /// Get raw value of ModeRegen + /// + /// - Start bit: 2 + /// - Signal size: 1 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Unsigned + #[inline(always)] + pub fn mode_regen_raw(&self) -> bool { + let signal = self.raw.view_bits::()[2..3].load_le::(); + + signal == 1 + } + + /// Set value of ModeRegen + #[inline(always)] + pub fn set_mode_regen(&mut self, value: bool) -> Result<(), CanError> { + let value = value as u8; + self.raw.view_bits_mut::()[2..3].store_le(value); + Ok(()) + } + + /// ChargePort + /// + /// Charge point is currently open if set (1 set / 0 unset), port must be closed for car to drive. + /// + /// - Min: 0 + /// - Max: 0 + /// - Unit: "Connected / Disconnected" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn charge_port(&self) -> bool { + self.charge_port_raw() + } + + /// Get raw value of ChargePort + /// + /// - Start bit: 8 + /// - Signal size: 1 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Unsigned + #[inline(always)] + pub fn charge_port_raw(&self) -> bool { + let signal = self.raw.view_bits::()[8..9].load_le::(); + + signal == 1 + } + + /// Set value of ChargePort + #[inline(always)] + pub fn set_charge_port(&mut self, value: bool) -> Result<(), CanError> { + let value = value as u8; + self.raw.view_bits_mut::()[8..9].store_le(value); + Ok(()) + } + + /// IgnitionStart + /// + /// Ignition key is in the start position + /// + /// - Min: 0 + /// - Max: 0 + /// - Unit: "Selected" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn ignition_start(&self) -> bool { + self.ignition_start_raw() + } + + /// Get raw value of IgnitionStart + /// + /// - Start bit: 6 + /// - Signal size: 1 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Unsigned + #[inline(always)] + pub fn ignition_start_raw(&self) -> bool { + let signal = self.raw.view_bits::()[6..7].load_le::(); + + signal == 1 + } + + /// Set value of IgnitionStart + #[inline(always)] + pub fn set_ignition_start(&mut self, value: bool) -> Result<(), CanError> { + let value = value as u8; + self.raw.view_bits_mut::()[6..7].store_le(value); + Ok(()) + } + + /// IgnitionAccesories + /// + /// Ignition key is in the accesories position + /// + /// - Min: 0 + /// - Max: 0 + /// - Unit: "Selected" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn ignition_accesories(&self) -> bool { + self.ignition_accesories_raw() + } + + /// Get raw value of IgnitionAccesories + /// + /// - Start bit: 4 + /// - Signal size: 1 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Unsigned + #[inline(always)] + pub fn ignition_accesories_raw(&self) -> bool { + let signal = self.raw.view_bits::()[4..5].load_le::(); + + signal == 1 + } + + /// Set value of IgnitionAccesories + #[inline(always)] + pub fn set_ignition_accesories(&mut self, value: bool) -> Result<(), CanError> { + let value = value as u8; + self.raw.view_bits_mut::()[4..5].store_le(value); + Ok(()) + } + + /// ModeDrive + /// + /// Car is in drive mode if set (1 set / 0 unset) + /// + /// - Min: 0 + /// - Max: 0 + /// - Unit: "Selected" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn mode_drive(&self) -> bool { + self.mode_drive_raw() + } + + /// Get raw value of ModeDrive + /// + /// - Start bit: 3 + /// - Signal size: 1 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Unsigned + #[inline(always)] + pub fn mode_drive_raw(&self) -> bool { + let signal = self.raw.view_bits::()[3..4].load_le::(); + + signal == 1 + } + + /// Set value of ModeDrive + #[inline(always)] + pub fn set_mode_drive(&mut self, value: bool) -> Result<(), CanError> { + let value = value as u8; + self.raw.view_bits_mut::()[3..4].store_le(value); + Ok(()) + } + + /// ModeNetural + /// + /// Car is in netural if set (1 set / 0 unset) + /// + /// - Min: 0 + /// - Max: 0 + /// - Unit: "Selected" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn mode_netural(&self) -> bool { + self.mode_netural_raw() + } + + /// Get raw value of ModeNetural + /// + /// - Start bit: 1 + /// - Signal size: 1 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Unsigned + #[inline(always)] + pub fn mode_netural_raw(&self) -> bool { + let signal = self.raw.view_bits::()[1..2].load_le::(); + + signal == 1 + } + + /// Set value of ModeNetural + #[inline(always)] + pub fn set_mode_netural(&mut self, value: bool) -> Result<(), CanError> { + let value = value as u8; + self.raw.view_bits_mut::()[1..2].store_le(value); + Ok(()) + } + + /// ModeReverse + /// + /// Car is in reverse if set (1 set / 0 unset) + /// + /// - Min: 0 + /// - Max: 0 + /// - Unit: "Selected" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn mode_reverse(&self) -> bool { + self.mode_reverse_raw() + } + + /// Get raw value of ModeReverse + /// + /// - Start bit: 0 + /// - Signal size: 1 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Unsigned + #[inline(always)] + pub fn mode_reverse_raw(&self) -> bool { + let signal = self.raw.view_bits::()[0..1].load_le::(); + + signal == 1 + } + + /// Set value of ModeReverse + #[inline(always)] + pub fn set_mode_reverse(&mut self, value: bool) -> Result<(), CanError> { + let value = value as u8; + self.raw.view_bits_mut::()[0..1].store_le(value); + Ok(()) + } +} + +impl core::convert::TryFrom<&[u8]> for Switch { + 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 Switch { + 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 Switch { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + if f.alternate() { + f.debug_struct("Switch") + .field("ignition_run", &self.ignition_run()) + .field("flags", &self.flags()) + .field("state", &self.state()) + .field("brake", &self.brake()) + .field("mode_regen", &self.mode_regen()) + .field("charge_port", &self.charge_port()) + .field("ignition_start", &self.ignition_start()) + .field("ignition_accesories", &self.ignition_accesories()) + .field("mode_drive", &self.mode_drive()) + .field("mode_netural", &self.mode_netural()) + .field("mode_reverse", &self.mode_reverse()) + .finish() + } else { + f.debug_tuple("Switch").field(&self.raw).finish() + } + } +} + +impl defmt::Format for Switch { + fn format(&self, f: defmt::Formatter) { + defmt::write!(f, + "Switch {{ IgnitionRun={:?} Flags={:?} State={:?} Brake={:?} ModeRegen={:?} ChargePort={:?} IgnitionStart={:?} IgnitionAccesories={:?} ModeDrive={:?} ModeNetural={:?} ModeReverse={:?} }}", + self.ignition_run(), + self.flags(), + self.state(), + self.brake(), + self.mode_regen(), + self.charge_port(), + self.ignition_start(), + self.ignition_accesories(), + self.mode_drive(), + self.mode_netural(), + self.mode_reverse(), + ); + } +} + +#[cfg(feature = "arb")] +impl<'a> Arbitrary<'a> for Switch { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + let ignition_run = u.int_in_range(0..=1)? == 1; + let flags = u.int_in_range(0..=0)?; + let state = u.int_in_range(0..=0)?; + let brake = u.int_in_range(0..=1)? == 1; + let mode_regen = u.int_in_range(0..=1)? == 1; + let charge_port = u.int_in_range(0..=1)? == 1; + let ignition_start = u.int_in_range(0..=1)? == 1; + let ignition_accesories = u.int_in_range(0..=1)? == 1; + let mode_drive = u.int_in_range(0..=1)? == 1; + let mode_netural = u.int_in_range(0..=1)? == 1; + let mode_reverse = u.int_in_range(0..=1)? == 1; + Switch::new( + ignition_run, + flags, + state, + brake, + mode_regen, + charge_port, + ignition_start, + ignition_accesories, + mode_drive, + mode_netural, + mode_reverse, + ) + .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(embedded_can::Id), + /// Signal parameter is not within the range + /// defined in the dbc + ParameterOutOfRange { + /// dbc message id + message_id: embedded_can::Id, + }, + InvalidPayloadSize, + /// Multiplexor value not defined in the dbc + InvalidMultiplexor { + /// dbc message id + message_id: embedded_can::Id, + /// Multiplexor value not defined in the dbc + multiplexor: u16, + }, +} + +impl core::fmt::Display for CanError { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:?}", self) + } +} +#[cfg(feature = "std")] +impl std::error::Error for CanError {} +#[cfg(feature = "arb")] +trait UnstructuredFloatExt { + fn float_in_range(&mut self, range: core::ops::RangeInclusive) -> arbitrary::Result; +} + +#[cfg(feature = "arb")] +impl UnstructuredFloatExt for arbitrary::Unstructured<'_> { + fn float_in_range(&mut self, range: core::ops::RangeInclusive) -> arbitrary::Result { + let min = range.start(); + let max = range.end(); + let steps = u32::MAX; + let factor = (max - min) / (steps as f32); + let random_int: u32 = self.int_in_range(0..=steps)?; + let random = min + factor * (random_int as f32); + Ok(random) + } +} diff --git a/solar_rust/src/messages_motorcontroller.rs b/solar_rust/src/messages_motorcontroller.rs new file mode 100644 index 0000000..7b4e40d --- /dev/null +++ b/solar_rust/src/messages_motorcontroller.rs @@ -0,0 +1,4240 @@ +// Generated code! +#![allow(unused_comparisons, unreachable_patterns, unused_imports)] +#![allow(clippy::let_and_return, clippy::eq_op)] +#![allow(clippy::useless_conversion, clippy::unnecessary_cast)] +#![allow( + clippy::excessive_precision, + clippy::manual_range_contains, + clippy::absurd_extreme_comparisons, + clippy::too_many_arguments +)] +#![deny(clippy::arithmetic_side_effects)] + +//! Message definitions from file `"motorcontroller.dbc"` +//! +//! - Version: `Version("")` + +#[cfg(feature = "arb")] +use arbitrary::{Arbitrary, Unstructured}; +use bitvec::prelude::*; +use core::ops::BitOr; +use embedded_can::{ExtendedId, Id, StandardId}; + +/// All messages +#[derive(Clone, Debug, defmt::Format)] +pub enum Messages { + /// IDInfo + IdInfo(IdInfo), + /// Status + Status(Status), + /// BusMeasurement + BusMeasurement(BusMeasurement), + /// VelocityMeasurement + VelocityMeasurement(VelocityMeasurement), + /// PhaseCurrentMeasurement + PhaseCurrentMeasurement(PhaseCurrentMeasurement), + /// MotorVoltageVectorMeasurement + MotorVoltageVectorMeasurement(MotorVoltageVectorMeasurement), + /// MotorCurrentVectorMeasurement + MotorCurrentVectorMeasurement(MotorCurrentVectorMeasurement), + /// BackEMFMeasurementPrediction + BackEmfMeasurementPrediction(BackEmfMeasurementPrediction), + /// VoltageRail15VMeasurement + VoltageRail15VMeasurement(VoltageRail15VMeasurement), + /// VoltageRail3V31V9Measurement + VoltageRail3V31v9Measurement(VoltageRail3V31v9Measurement), + /// Reserved0A + Reserved0A(Reserved0A), + /// HeatsinkMotorTempMeasurement + HeatsinkMotorTempMeasurement(HeatsinkMotorTempMeasurement), + /// DspBoardTempMeasurement + DspBoardTempMeasurement(DspBoardTempMeasurement), + /// Reserved0D + Reserved0D(Reserved0D), + /// OdometerBusAhMeasurement + OdometerBusAhMeasurement(OdometerBusAhMeasurement), + /// SlipSpeedMeasurement + SlipSpeedMeasurement(SlipSpeedMeasurement), +} + +impl Messages { + /// Read message from CAN frame + #[inline(never)] + pub fn from_can_message(id: Id, payload: &[u8]) -> Result { + let res = match id { + IdInfo::MESSAGE_ID => Messages::IdInfo(IdInfo::try_from(payload)?), + Status::MESSAGE_ID => Messages::Status(Status::try_from(payload)?), + BusMeasurement::MESSAGE_ID => { + Messages::BusMeasurement(BusMeasurement::try_from(payload)?) + } + VelocityMeasurement::MESSAGE_ID => { + Messages::VelocityMeasurement(VelocityMeasurement::try_from(payload)?) + } + PhaseCurrentMeasurement::MESSAGE_ID => { + Messages::PhaseCurrentMeasurement(PhaseCurrentMeasurement::try_from(payload)?) + } + MotorVoltageVectorMeasurement::MESSAGE_ID => Messages::MotorVoltageVectorMeasurement( + MotorVoltageVectorMeasurement::try_from(payload)?, + ), + MotorCurrentVectorMeasurement::MESSAGE_ID => Messages::MotorCurrentVectorMeasurement( + MotorCurrentVectorMeasurement::try_from(payload)?, + ), + BackEmfMeasurementPrediction::MESSAGE_ID => Messages::BackEmfMeasurementPrediction( + BackEmfMeasurementPrediction::try_from(payload)?, + ), + VoltageRail15VMeasurement::MESSAGE_ID => { + Messages::VoltageRail15VMeasurement(VoltageRail15VMeasurement::try_from(payload)?) + } + VoltageRail3V31v9Measurement::MESSAGE_ID => Messages::VoltageRail3V31v9Measurement( + VoltageRail3V31v9Measurement::try_from(payload)?, + ), + Reserved0A::MESSAGE_ID => Messages::Reserved0A(Reserved0A::try_from(payload)?), + HeatsinkMotorTempMeasurement::MESSAGE_ID => Messages::HeatsinkMotorTempMeasurement( + HeatsinkMotorTempMeasurement::try_from(payload)?, + ), + DspBoardTempMeasurement::MESSAGE_ID => { + Messages::DspBoardTempMeasurement(DspBoardTempMeasurement::try_from(payload)?) + } + Reserved0D::MESSAGE_ID => Messages::Reserved0D(Reserved0D::try_from(payload)?), + OdometerBusAhMeasurement::MESSAGE_ID => { + Messages::OdometerBusAhMeasurement(OdometerBusAhMeasurement::try_from(payload)?) + } + SlipSpeedMeasurement::MESSAGE_ID => { + Messages::SlipSpeedMeasurement(SlipSpeedMeasurement::try_from(payload)?) + } + id => return Err(CanError::UnknownMessageId(id)), + }; + Ok(res) + } +} + +/// IDInfo +/// +/// - Standard ID: 128 (0x80) +/// - Size: 8 bytes +/// - Transmitter: WaveSculptor22 +#[derive(Clone, Copy)] +pub struct IdInfo { + raw: [u8; 8], +} + +impl IdInfo { + pub const MESSAGE_ID: embedded_can::Id = + Id::Standard(unsafe { StandardId::new_unchecked(0x80) }); + + pub const TRITIUM_ID_MIN: u32 = 0_u32; + pub const TRITIUM_ID_MAX: u32 = 0_u32; + pub const SERIAL_NUMBER_MIN: u32 = 0_u32; + pub const SERIAL_NUMBER_MAX: u32 = 0_u32; + + /// Construct new IDInfo from values + pub fn new(tritium_id: u32, serial_number: u32) -> Result { + let mut res = Self { raw: [0u8; 8] }; + res.set_tritium_id(tritium_id)?; + res.set_serial_number(serial_number)?; + Ok(res) + } + + /// Access message payload raw value + pub fn raw(&self) -> &[u8; 8] { + &self.raw + } + + /// TritiumID + /// + /// Device identifier. 0x00004003 + /// + /// - Min: 0 + /// - Max: 0 + /// - Unit: "" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn tritium_id(&self) -> u32 { + self.tritium_id_raw() + } + + /// Get raw value of TritiumID + /// + /// - Start bit: 0 + /// - Signal size: 32 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Unsigned + #[inline(always)] + pub fn tritium_id_raw(&self) -> u32 { + let signal = self.raw.view_bits::()[0..32].load_le::(); + + let factor = 1; + u32::from(signal).saturating_mul(factor).saturating_add(0) + } + + /// Set value of TritiumID + #[inline(always)] + pub fn set_tritium_id(&mut self, value: u32) -> Result<(), CanError> { + let factor = 1; + let value = value.checked_sub(0).ok_or(CanError::ParameterOutOfRange { + message_id: IdInfo::MESSAGE_ID, + })?; + let value = (value / factor) as u32; + + self.raw.view_bits_mut::()[0..32].store_le(value); + Ok(()) + } + + /// SerialNumber + /// + /// Device serial number, allocated at manufacture. + /// + /// - Min: 0 + /// - Max: 0 + /// - Unit: "" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn serial_number(&self) -> u32 { + self.serial_number_raw() + } + + /// Get raw value of SerialNumber + /// + /// - Start bit: 32 + /// - Signal size: 32 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Unsigned + #[inline(always)] + pub fn serial_number_raw(&self) -> u32 { + let signal = self.raw.view_bits::()[32..64].load_le::(); + + let factor = 1; + u32::from(signal).saturating_mul(factor).saturating_add(0) + } + + /// Set value of SerialNumber + #[inline(always)] + pub fn set_serial_number(&mut self, value: u32) -> Result<(), CanError> { + let factor = 1; + let value = value.checked_sub(0).ok_or(CanError::ParameterOutOfRange { + message_id: IdInfo::MESSAGE_ID, + })?; + let value = (value / factor) as u32; + + self.raw.view_bits_mut::()[32..64].store_le(value); + Ok(()) + } +} + +impl core::convert::TryFrom<&[u8]> for IdInfo { + 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 IdInfo { + 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 IdInfo { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + if f.alternate() { + f.debug_struct("IdInfo") + .field("tritium_id", &self.tritium_id()) + .field("serial_number", &self.serial_number()) + .finish() + } else { + f.debug_tuple("IdInfo").field(&self.raw).finish() + } + } +} + +impl defmt::Format for IdInfo { + fn format(&self, f: defmt::Formatter) { + defmt::write!( + f, + "IdInfo {{ TritiumID={:?} SerialNumber={:?} }}", + self.tritium_id(), + self.serial_number(), + ); + } +} + +#[cfg(feature = "arb")] +impl<'a> Arbitrary<'a> for IdInfo { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + let tritium_id = u.int_in_range(0..=0)?; + let serial_number = u.int_in_range(0..=0)?; + IdInfo::new(tritium_id, serial_number).map_err(|_| arbitrary::Error::IncorrectFormat) + } +} + +/// Status +/// +/// - Standard ID: 129 (0x81) +/// - Size: 8 bytes +/// - Transmitter: WaveSculptor22 +#[derive(Clone, Copy)] +pub struct Status { + raw: [u8; 8], +} + +impl Status { + pub const MESSAGE_ID: embedded_can::Id = + Id::Standard(unsafe { StandardId::new_unchecked(0x81) }); + + pub const LIMIT_RESERVED_MIN: u16 = 0_u16; + pub const LIMIT_RESERVED_MAX: u16 = 511_u16; + pub const ERROR_RESERVED_MIN: u8 = 0_u8; + pub const ERROR_RESERVED_MAX: u8 = 0_u8; + pub const ACTIVE_MOTOR_MIN: u16 = 0_u16; + pub const ACTIVE_MOTOR_MAX: u16 = 0_u16; + pub const TX_ERROR_COUNT_MIN: u8 = 0_u8; + pub const TX_ERROR_COUNT_MAX: u8 = 0_u8; + pub const RX_ERROR_COUNT_MIN: u8 = 0_u8; + pub const RX_ERROR_COUNT_MAX: u8 = 0_u8; + + /// Construct new Status from values + pub fn new( + limit_reserved: u16, + limit_ipm_or_motor_temp: bool, + limit_bus_voltage_lower: bool, + limit_bus_voltage_upper: bool, + limit_bus_current: bool, + limit_velocity: bool, + limit_motor_current: bool, + limit_output_voltage_pwm: bool, + error_reserved: u8, + error_motor_over_speed: bool, + error_desaturation_fault: bool, + error15v_rail_under_voltage: bool, + error_config_read: bool, + error_watchdog_caused_last_reset: bool, + error_bad_motor_position_hall_seq: bool, + error_dc_bus_over_voltage: bool, + error_software_over_current: bool, + error_hardware_over_current: bool, + active_motor: u16, + tx_error_count: u8, + rx_error_count: u8, + ) -> Result { + let mut res = Self { raw: [0u8; 8] }; + res.set_limit_reserved(limit_reserved)?; + res.set_limit_ipm_or_motor_temp(limit_ipm_or_motor_temp)?; + res.set_limit_bus_voltage_lower(limit_bus_voltage_lower)?; + res.set_limit_bus_voltage_upper(limit_bus_voltage_upper)?; + res.set_limit_bus_current(limit_bus_current)?; + res.set_limit_velocity(limit_velocity)?; + res.set_limit_motor_current(limit_motor_current)?; + res.set_limit_output_voltage_pwm(limit_output_voltage_pwm)?; + res.set_error_reserved(error_reserved)?; + res.set_error_motor_over_speed(error_motor_over_speed)?; + res.set_error_desaturation_fault(error_desaturation_fault)?; + res.set_error15v_rail_under_voltage(error15v_rail_under_voltage)?; + res.set_error_config_read(error_config_read)?; + res.set_error_watchdog_caused_last_reset(error_watchdog_caused_last_reset)?; + res.set_error_bad_motor_position_hall_seq(error_bad_motor_position_hall_seq)?; + res.set_error_dc_bus_over_voltage(error_dc_bus_over_voltage)?; + res.set_error_software_over_current(error_software_over_current)?; + res.set_error_hardware_over_current(error_hardware_over_current)?; + res.set_active_motor(active_motor)?; + res.set_tx_error_count(tx_error_count)?; + res.set_rx_error_count(rx_error_count)?; + Ok(res) + } + + /// Access message payload raw value + pub fn raw(&self) -> &[u8; 8] { + &self.raw + } + + /// LimitReserved + /// + /// - Min: 0 + /// - Max: 511 + /// - Unit: "On / Off" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn limit_reserved(&self) -> u16 { + self.limit_reserved_raw() + } + + /// Get raw value of LimitReserved + /// + /// - Start bit: 7 + /// - Signal size: 9 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Unsigned + #[inline(always)] + pub fn limit_reserved_raw(&self) -> u16 { + let signal = self.raw.view_bits::()[7..16].load_le::(); + + let factor = 1; + u16::from(signal).saturating_mul(factor).saturating_add(0) + } + + /// Set value of LimitReserved + #[inline(always)] + pub fn set_limit_reserved(&mut self, value: u16) -> Result<(), CanError> { + let factor = 1; + let value = value.checked_sub(0).ok_or(CanError::ParameterOutOfRange { + message_id: Status::MESSAGE_ID, + })?; + let value = (value / factor) as u16; + + self.raw.view_bits_mut::()[7..16].store_le(value); + Ok(()) + } + + /// LimitIpmOrMotorTemp + /// + /// - Min: 0 + /// - Max: 1 + /// - Unit: "On / Off" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn limit_ipm_or_motor_temp(&self) -> bool { + self.limit_ipm_or_motor_temp_raw() + } + + /// Get raw value of LimitIpmOrMotorTemp + /// + /// - Start bit: 6 + /// - Signal size: 1 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Unsigned + #[inline(always)] + pub fn limit_ipm_or_motor_temp_raw(&self) -> bool { + let signal = self.raw.view_bits::()[6..7].load_le::(); + + signal == 1 + } + + /// Set value of LimitIpmOrMotorTemp + #[inline(always)] + pub fn set_limit_ipm_or_motor_temp(&mut self, value: bool) -> Result<(), CanError> { + let value = value as u8; + self.raw.view_bits_mut::()[6..7].store_le(value); + Ok(()) + } + + /// LimitBusVoltageLower + /// + /// - Min: 0 + /// - Max: 1 + /// - Unit: "On / Off" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn limit_bus_voltage_lower(&self) -> bool { + self.limit_bus_voltage_lower_raw() + } + + /// Get raw value of LimitBusVoltageLower + /// + /// - Start bit: 5 + /// - Signal size: 1 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Unsigned + #[inline(always)] + pub fn limit_bus_voltage_lower_raw(&self) -> bool { + let signal = self.raw.view_bits::()[5..6].load_le::(); + + signal == 1 + } + + /// Set value of LimitBusVoltageLower + #[inline(always)] + pub fn set_limit_bus_voltage_lower(&mut self, value: bool) -> Result<(), CanError> { + let value = value as u8; + self.raw.view_bits_mut::()[5..6].store_le(value); + Ok(()) + } + + /// LimitBusVoltageUpper + /// + /// - Min: 0 + /// - Max: 1 + /// - Unit: "On / Off" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn limit_bus_voltage_upper(&self) -> bool { + self.limit_bus_voltage_upper_raw() + } + + /// Get raw value of LimitBusVoltageUpper + /// + /// - Start bit: 4 + /// - Signal size: 1 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Unsigned + #[inline(always)] + pub fn limit_bus_voltage_upper_raw(&self) -> bool { + let signal = self.raw.view_bits::()[4..5].load_le::(); + + signal == 1 + } + + /// Set value of LimitBusVoltageUpper + #[inline(always)] + pub fn set_limit_bus_voltage_upper(&mut self, value: bool) -> Result<(), CanError> { + let value = value as u8; + self.raw.view_bits_mut::()[4..5].store_le(value); + Ok(()) + } + + /// LimitBusCurrent + /// + /// - Min: 0 + /// - Max: 1 + /// - Unit: "On / Off" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn limit_bus_current(&self) -> bool { + self.limit_bus_current_raw() + } + + /// Get raw value of LimitBusCurrent + /// + /// - Start bit: 3 + /// - Signal size: 1 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Unsigned + #[inline(always)] + pub fn limit_bus_current_raw(&self) -> bool { + let signal = self.raw.view_bits::()[3..4].load_le::(); + + signal == 1 + } + + /// Set value of LimitBusCurrent + #[inline(always)] + pub fn set_limit_bus_current(&mut self, value: bool) -> Result<(), CanError> { + let value = value as u8; + self.raw.view_bits_mut::()[3..4].store_le(value); + Ok(()) + } + + /// LimitVelocity + /// + /// - Min: 0 + /// - Max: 1 + /// - Unit: "On / Off" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn limit_velocity(&self) -> bool { + self.limit_velocity_raw() + } + + /// Get raw value of LimitVelocity + /// + /// - Start bit: 2 + /// - Signal size: 1 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Unsigned + #[inline(always)] + pub fn limit_velocity_raw(&self) -> bool { + let signal = self.raw.view_bits::()[2..3].load_le::(); + + signal == 1 + } + + /// Set value of LimitVelocity + #[inline(always)] + pub fn set_limit_velocity(&mut self, value: bool) -> Result<(), CanError> { + let value = value as u8; + self.raw.view_bits_mut::()[2..3].store_le(value); + Ok(()) + } + + /// LimitMotorCurrent + /// + /// - Min: 0 + /// - Max: 1 + /// - Unit: "On / Off" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn limit_motor_current(&self) -> bool { + self.limit_motor_current_raw() + } + + /// Get raw value of LimitMotorCurrent + /// + /// - Start bit: 1 + /// - Signal size: 1 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Unsigned + #[inline(always)] + pub fn limit_motor_current_raw(&self) -> bool { + let signal = self.raw.view_bits::()[1..2].load_le::(); + + signal == 1 + } + + /// Set value of LimitMotorCurrent + #[inline(always)] + pub fn set_limit_motor_current(&mut self, value: bool) -> Result<(), CanError> { + let value = value as u8; + self.raw.view_bits_mut::()[1..2].store_le(value); + Ok(()) + } + + /// LimitOutputVoltagePWM + /// + /// - Min: 0 + /// - Max: 1 + /// - Unit: "On / Off" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn limit_output_voltage_pwm(&self) -> bool { + self.limit_output_voltage_pwm_raw() + } + + /// Get raw value of LimitOutputVoltagePWM + /// + /// - Start bit: 0 + /// - Signal size: 1 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Unsigned + #[inline(always)] + pub fn limit_output_voltage_pwm_raw(&self) -> bool { + let signal = self.raw.view_bits::()[0..1].load_le::(); + + signal == 1 + } + + /// Set value of LimitOutputVoltagePWM + #[inline(always)] + pub fn set_limit_output_voltage_pwm(&mut self, value: bool) -> Result<(), CanError> { + let value = value as u8; + self.raw.view_bits_mut::()[0..1].store_le(value); + Ok(()) + } + + /// ErrorReserved + /// + /// - Min: 0 + /// - Max: 0 + /// - Unit: "On / Off" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn error_reserved(&self) -> u8 { + self.error_reserved_raw() + } + + /// Get raw value of ErrorReserved + /// + /// - Start bit: 25 + /// - Signal size: 7 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Unsigned + #[inline(always)] + pub fn error_reserved_raw(&self) -> u8 { + let signal = self.raw.view_bits::()[25..32].load_le::(); + + let factor = 1; + u8::from(signal).saturating_mul(factor).saturating_add(0) + } + + /// Set value of ErrorReserved + #[inline(always)] + pub fn set_error_reserved(&mut self, value: u8) -> Result<(), CanError> { + let factor = 1; + let value = value.checked_sub(0).ok_or(CanError::ParameterOutOfRange { + message_id: Status::MESSAGE_ID, + })?; + let value = (value / factor) as u8; + + self.raw.view_bits_mut::()[25..32].store_le(value); + Ok(()) + } + + /// ErrorMotorOverSpeed + /// + /// - Min: 0 + /// - Max: 1 + /// - Unit: "On / Off" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn error_motor_over_speed(&self) -> bool { + self.error_motor_over_speed_raw() + } + + /// Get raw value of ErrorMotorOverSpeed + /// + /// - Start bit: 24 + /// - Signal size: 1 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Unsigned + #[inline(always)] + pub fn error_motor_over_speed_raw(&self) -> bool { + let signal = self.raw.view_bits::()[24..25].load_le::(); + + signal == 1 + } + + /// Set value of ErrorMotorOverSpeed + #[inline(always)] + pub fn set_error_motor_over_speed(&mut self, value: bool) -> Result<(), CanError> { + let value = value as u8; + self.raw.view_bits_mut::()[24..25].store_le(value); + Ok(()) + } + + /// ErrorDesaturationFault + /// + /// - Min: 0 + /// - Max: 1 + /// - Unit: "On / Off" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn error_desaturation_fault(&self) -> bool { + self.error_desaturation_fault_raw() + } + + /// Get raw value of ErrorDesaturationFault + /// + /// - Start bit: 23 + /// - Signal size: 1 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Unsigned + #[inline(always)] + pub fn error_desaturation_fault_raw(&self) -> bool { + let signal = self.raw.view_bits::()[23..24].load_le::(); + + signal == 1 + } + + /// Set value of ErrorDesaturationFault + #[inline(always)] + pub fn set_error_desaturation_fault(&mut self, value: bool) -> Result<(), CanError> { + let value = value as u8; + self.raw.view_bits_mut::()[23..24].store_le(value); + Ok(()) + } + + /// Error15vRailUnderVoltage + /// + /// - Min: 0 + /// - Max: 1 + /// - Unit: "On / Off" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn error15v_rail_under_voltage(&self) -> bool { + self.error15v_rail_under_voltage_raw() + } + + /// Get raw value of Error15vRailUnderVoltage + /// + /// - Start bit: 22 + /// - Signal size: 1 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Unsigned + #[inline(always)] + pub fn error15v_rail_under_voltage_raw(&self) -> bool { + let signal = self.raw.view_bits::()[22..23].load_le::(); + + signal == 1 + } + + /// Set value of Error15vRailUnderVoltage + #[inline(always)] + pub fn set_error15v_rail_under_voltage(&mut self, value: bool) -> Result<(), CanError> { + let value = value as u8; + self.raw.view_bits_mut::()[22..23].store_le(value); + Ok(()) + } + + /// ErrorConfigRead + /// + /// - Min: 0 + /// - Max: 1 + /// - Unit: "On / Off" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn error_config_read(&self) -> bool { + self.error_config_read_raw() + } + + /// Get raw value of ErrorConfigRead + /// + /// - Start bit: 21 + /// - Signal size: 1 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Unsigned + #[inline(always)] + pub fn error_config_read_raw(&self) -> bool { + let signal = self.raw.view_bits::()[21..22].load_le::(); + + signal == 1 + } + + /// Set value of ErrorConfigRead + #[inline(always)] + pub fn set_error_config_read(&mut self, value: bool) -> Result<(), CanError> { + let value = value as u8; + self.raw.view_bits_mut::()[21..22].store_le(value); + Ok(()) + } + + /// ErrorWatchdogCausedLastReset + /// + /// - Min: 0 + /// - Max: 1 + /// - Unit: "On / Off" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn error_watchdog_caused_last_reset(&self) -> bool { + self.error_watchdog_caused_last_reset_raw() + } + + /// Get raw value of ErrorWatchdogCausedLastReset + /// + /// - Start bit: 20 + /// - Signal size: 1 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Unsigned + #[inline(always)] + pub fn error_watchdog_caused_last_reset_raw(&self) -> bool { + let signal = self.raw.view_bits::()[20..21].load_le::(); + + signal == 1 + } + + /// Set value of ErrorWatchdogCausedLastReset + #[inline(always)] + pub fn set_error_watchdog_caused_last_reset(&mut self, value: bool) -> Result<(), CanError> { + let value = value as u8; + self.raw.view_bits_mut::()[20..21].store_le(value); + Ok(()) + } + + /// ErrorBadMotorPositionHallSeq + /// + /// - Min: 0 + /// - Max: 1 + /// - Unit: "On / Off" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn error_bad_motor_position_hall_seq(&self) -> bool { + self.error_bad_motor_position_hall_seq_raw() + } + + /// Get raw value of ErrorBadMotorPositionHallSeq + /// + /// - Start bit: 19 + /// - Signal size: 1 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Unsigned + #[inline(always)] + pub fn error_bad_motor_position_hall_seq_raw(&self) -> bool { + let signal = self.raw.view_bits::()[19..20].load_le::(); + + signal == 1 + } + + /// Set value of ErrorBadMotorPositionHallSeq + #[inline(always)] + pub fn set_error_bad_motor_position_hall_seq(&mut self, value: bool) -> Result<(), CanError> { + let value = value as u8; + self.raw.view_bits_mut::()[19..20].store_le(value); + Ok(()) + } + + /// ErrorDcBusOverVoltage + /// + /// - Min: 0 + /// - Max: 1 + /// - Unit: "On / Off" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn error_dc_bus_over_voltage(&self) -> bool { + self.error_dc_bus_over_voltage_raw() + } + + /// Get raw value of ErrorDcBusOverVoltage + /// + /// - Start bit: 18 + /// - Signal size: 1 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Unsigned + #[inline(always)] + pub fn error_dc_bus_over_voltage_raw(&self) -> bool { + let signal = self.raw.view_bits::()[18..19].load_le::(); + + signal == 1 + } + + /// Set value of ErrorDcBusOverVoltage + #[inline(always)] + pub fn set_error_dc_bus_over_voltage(&mut self, value: bool) -> Result<(), CanError> { + let value = value as u8; + self.raw.view_bits_mut::()[18..19].store_le(value); + Ok(()) + } + + /// ErrorSoftwareOverCurrent + /// + /// - Min: 0 + /// - Max: 1 + /// - Unit: "On / Off" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn error_software_over_current(&self) -> bool { + self.error_software_over_current_raw() + } + + /// Get raw value of ErrorSoftwareOverCurrent + /// + /// - Start bit: 17 + /// - Signal size: 1 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Unsigned + #[inline(always)] + pub fn error_software_over_current_raw(&self) -> bool { + let signal = self.raw.view_bits::()[17..18].load_le::(); + + signal == 1 + } + + /// Set value of ErrorSoftwareOverCurrent + #[inline(always)] + pub fn set_error_software_over_current(&mut self, value: bool) -> Result<(), CanError> { + let value = value as u8; + self.raw.view_bits_mut::()[17..18].store_le(value); + Ok(()) + } + + /// ErrorHardwareOverCurrent + /// + /// - Min: 0 + /// - Max: 1 + /// - Unit: "On / Off" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn error_hardware_over_current(&self) -> bool { + self.error_hardware_over_current_raw() + } + + /// Get raw value of ErrorHardwareOverCurrent + /// + /// - Start bit: 16 + /// - Signal size: 1 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Unsigned + #[inline(always)] + pub fn error_hardware_over_current_raw(&self) -> bool { + let signal = self.raw.view_bits::()[16..17].load_le::(); + + signal == 1 + } + + /// Set value of ErrorHardwareOverCurrent + #[inline(always)] + pub fn set_error_hardware_over_current(&mut self, value: bool) -> Result<(), CanError> { + let value = value as u8; + self.raw.view_bits_mut::()[16..17].store_le(value); + Ok(()) + } + + /// ActiveMotor + /// + /// The index of the active motor currently being used. + /// + /// - Min: 0 + /// - Max: 0 + /// - Unit: "" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn active_motor(&self) -> u16 { + self.active_motor_raw() + } + + /// Get raw value of ActiveMotor + /// + /// - Start bit: 32 + /// - Signal size: 16 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Unsigned + #[inline(always)] + pub fn active_motor_raw(&self) -> u16 { + let signal = self.raw.view_bits::()[32..48].load_le::(); + + let factor = 1; + u16::from(signal).saturating_mul(factor).saturating_add(0) + } + + /// Set value of ActiveMotor + #[inline(always)] + pub fn set_active_motor(&mut self, value: u16) -> Result<(), CanError> { + let factor = 1; + let value = value.checked_sub(0).ok_or(CanError::ParameterOutOfRange { + message_id: Status::MESSAGE_ID, + })?; + let value = (value / factor) as u16; + + self.raw.view_bits_mut::()[32..48].store_le(value); + Ok(()) + } + + /// TxErrorCount + /// + /// The DSP CAN transmission error counter (CAN 2.0) + /// + /// - Min: 0 + /// - Max: 0 + /// - Unit: "" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn tx_error_count(&self) -> u8 { + self.tx_error_count_raw() + } + + /// Get raw value of TxErrorCount + /// + /// - Start bit: 48 + /// - Signal size: 8 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Unsigned + #[inline(always)] + pub fn tx_error_count_raw(&self) -> u8 { + let signal = self.raw.view_bits::()[48..56].load_le::(); + + let factor = 1; + u8::from(signal).saturating_mul(factor).saturating_add(0) + } + + /// Set value of TxErrorCount + #[inline(always)] + pub fn set_tx_error_count(&mut self, value: u8) -> Result<(), CanError> { + let factor = 1; + let value = value.checked_sub(0).ok_or(CanError::ParameterOutOfRange { + message_id: Status::MESSAGE_ID, + })?; + let value = (value / factor) as u8; + + self.raw.view_bits_mut::()[48..56].store_le(value); + Ok(()) + } + + /// RxErrorCount + /// + /// The DSP CAN receive error counter (CAN 2.0) + /// + /// - Min: 0 + /// - Max: 0 + /// - Unit: "" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn rx_error_count(&self) -> u8 { + self.rx_error_count_raw() + } + + /// Get raw value of RxErrorCount + /// + /// - Start bit: 56 + /// - Signal size: 8 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Unsigned + #[inline(always)] + pub fn rx_error_count_raw(&self) -> u8 { + let signal = self.raw.view_bits::()[56..64].load_le::(); + + let factor = 1; + u8::from(signal).saturating_mul(factor).saturating_add(0) + } + + /// Set value of RxErrorCount + #[inline(always)] + pub fn set_rx_error_count(&mut self, value: u8) -> Result<(), CanError> { + let factor = 1; + let value = value.checked_sub(0).ok_or(CanError::ParameterOutOfRange { + message_id: Status::MESSAGE_ID, + })?; + let value = (value / factor) as u8; + + self.raw.view_bits_mut::()[56..64].store_le(value); + Ok(()) + } +} + +impl core::convert::TryFrom<&[u8]> for Status { + 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 Status { + 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 Status { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + if f.alternate() { + f.debug_struct("Status") + .field("limit_reserved", &self.limit_reserved()) + .field("limit_ipm_or_motor_temp", &self.limit_ipm_or_motor_temp()) + .field("limit_bus_voltage_lower", &self.limit_bus_voltage_lower()) + .field("limit_bus_voltage_upper", &self.limit_bus_voltage_upper()) + .field("limit_bus_current", &self.limit_bus_current()) + .field("limit_velocity", &self.limit_velocity()) + .field("limit_motor_current", &self.limit_motor_current()) + .field("limit_output_voltage_pwm", &self.limit_output_voltage_pwm()) + .field("error_reserved", &self.error_reserved()) + .field("error_motor_over_speed", &self.error_motor_over_speed()) + .field("error_desaturation_fault", &self.error_desaturation_fault()) + .field( + "error15v_rail_under_voltage", + &self.error15v_rail_under_voltage(), + ) + .field("error_config_read", &self.error_config_read()) + .field( + "error_watchdog_caused_last_reset", + &self.error_watchdog_caused_last_reset(), + ) + .field( + "error_bad_motor_position_hall_seq", + &self.error_bad_motor_position_hall_seq(), + ) + .field( + "error_dc_bus_over_voltage", + &self.error_dc_bus_over_voltage(), + ) + .field( + "error_software_over_current", + &self.error_software_over_current(), + ) + .field( + "error_hardware_over_current", + &self.error_hardware_over_current(), + ) + .field("active_motor", &self.active_motor()) + .field("tx_error_count", &self.tx_error_count()) + .field("rx_error_count", &self.rx_error_count()) + .finish() + } else { + f.debug_tuple("Status").field(&self.raw).finish() + } + } +} + +impl defmt::Format for Status { + fn format(&self, f: defmt::Formatter) { + defmt::write!(f, + "Status {{ LimitReserved={:?} LimitIpmOrMotorTemp={:?} LimitBusVoltageLower={:?} LimitBusVoltageUpper={:?} LimitBusCurrent={:?} LimitVelocity={:?} LimitMotorCurrent={:?} LimitOutputVoltagePWM={:?} ErrorReserved={:?} ErrorMotorOverSpeed={:?} ErrorDesaturationFault={:?} Error15vRailUnderVoltage={:?} ErrorConfigRead={:?} ErrorWatchdogCausedLastReset={:?} ErrorBadMotorPositionHallSeq={:?} ErrorDcBusOverVoltage={:?} ErrorSoftwareOverCurrent={:?} ErrorHardwareOverCurrent={:?} ActiveMotor={:?} TxErrorCount={:?} RxErrorCount={:?} }}", + self.limit_reserved(), + self.limit_ipm_or_motor_temp(), + self.limit_bus_voltage_lower(), + self.limit_bus_voltage_upper(), + self.limit_bus_current(), + self.limit_velocity(), + self.limit_motor_current(), + self.limit_output_voltage_pwm(), + self.error_reserved(), + self.error_motor_over_speed(), + self.error_desaturation_fault(), + self.error15v_rail_under_voltage(), + self.error_config_read(), + self.error_watchdog_caused_last_reset(), + self.error_bad_motor_position_hall_seq(), + self.error_dc_bus_over_voltage(), + self.error_software_over_current(), + self.error_hardware_over_current(), + self.active_motor(), + self.tx_error_count(), + self.rx_error_count(), + ); + } +} + +#[cfg(feature = "arb")] +impl<'a> Arbitrary<'a> for Status { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + let limit_reserved = u.int_in_range(0..=511)?; + let limit_ipm_or_motor_temp = u.int_in_range(0..=1)? == 1; + let limit_bus_voltage_lower = u.int_in_range(0..=1)? == 1; + let limit_bus_voltage_upper = u.int_in_range(0..=1)? == 1; + let limit_bus_current = u.int_in_range(0..=1)? == 1; + let limit_velocity = u.int_in_range(0..=1)? == 1; + let limit_motor_current = u.int_in_range(0..=1)? == 1; + let limit_output_voltage_pwm = u.int_in_range(0..=1)? == 1; + let error_reserved = u.int_in_range(0..=0)?; + let error_motor_over_speed = u.int_in_range(0..=1)? == 1; + let error_desaturation_fault = u.int_in_range(0..=1)? == 1; + let error15v_rail_under_voltage = u.int_in_range(0..=1)? == 1; + let error_config_read = u.int_in_range(0..=1)? == 1; + let error_watchdog_caused_last_reset = u.int_in_range(0..=1)? == 1; + let error_bad_motor_position_hall_seq = u.int_in_range(0..=1)? == 1; + let error_dc_bus_over_voltage = u.int_in_range(0..=1)? == 1; + let error_software_over_current = u.int_in_range(0..=1)? == 1; + let error_hardware_over_current = u.int_in_range(0..=1)? == 1; + let active_motor = u.int_in_range(0..=0)?; + let tx_error_count = u.int_in_range(0..=0)?; + let rx_error_count = u.int_in_range(0..=0)?; + Status::new( + limit_reserved, + limit_ipm_or_motor_temp, + limit_bus_voltage_lower, + limit_bus_voltage_upper, + limit_bus_current, + limit_velocity, + limit_motor_current, + limit_output_voltage_pwm, + error_reserved, + error_motor_over_speed, + error_desaturation_fault, + error15v_rail_under_voltage, + error_config_read, + error_watchdog_caused_last_reset, + error_bad_motor_position_hall_seq, + error_dc_bus_over_voltage, + error_software_over_current, + error_hardware_over_current, + active_motor, + tx_error_count, + rx_error_count, + ) + .map_err(|_| arbitrary::Error::IncorrectFormat) + } +} + +/// BusMeasurement +/// +/// - Standard ID: 130 (0x82) +/// - Size: 8 bytes +/// - Transmitter: WaveSculptor22 +#[derive(Clone, Copy)] +pub struct BusMeasurement { + raw: [u8; 8], +} + +impl BusMeasurement { + pub const MESSAGE_ID: embedded_can::Id = + Id::Standard(unsafe { StandardId::new_unchecked(0x82) }); + + pub const BUS_VOLTAGE_MIN: i32 = 0_i32; + pub const BUS_VOLTAGE_MAX: i32 = 0_i32; + pub const BUS_CURRENT_MIN: i32 = 0_i32; + pub const BUS_CURRENT_MAX: i32 = 0_i32; + + /// Construct new BusMeasurement from values + pub fn new(bus_voltage: i32, bus_current: i32) -> Result { + let mut res = Self { raw: [0u8; 8] }; + res.set_bus_voltage(bus_voltage)?; + res.set_bus_current(bus_current)?; + Ok(res) + } + + /// Access message payload raw value + pub fn raw(&self) -> &[u8; 8] { + &self.raw + } + + /// BusVoltage + /// + /// DC bus voltage at the controller. + /// + /// - Min: 0 + /// - Max: 0 + /// - Unit: "V" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn bus_voltage(&self) -> i32 { + self.bus_voltage_raw() + } + + /// Get raw value of BusVoltage + /// + /// - Start bit: 0 + /// - Signal size: 32 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Signed + #[inline(always)] + pub fn bus_voltage_raw(&self) -> i32 { + let signal = self.raw.view_bits::()[0..32].load_le::(); + + let factor = 1; + let signal = signal as i32; + i32::from(signal).saturating_mul(factor).saturating_add(0) + } + + /// Set value of BusVoltage + #[inline(always)] + pub fn set_bus_voltage(&mut self, value: i32) -> Result<(), CanError> { + let factor = 1; + let value = value.checked_sub(0).ok_or(CanError::ParameterOutOfRange { + message_id: BusMeasurement::MESSAGE_ID, + })?; + let value = (value / factor) as i32; + + let value = u32::from_ne_bytes(value.to_ne_bytes()); + self.raw.view_bits_mut::()[0..32].store_le(value); + Ok(()) + } + + /// BusCurrent + /// + /// Current drawn from the DC bus by the controller. + /// + /// - Min: 0 + /// - Max: 0 + /// - Unit: "A" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn bus_current(&self) -> i32 { + self.bus_current_raw() + } + + /// Get raw value of BusCurrent + /// + /// - Start bit: 32 + /// - Signal size: 32 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Signed + #[inline(always)] + pub fn bus_current_raw(&self) -> i32 { + let signal = self.raw.view_bits::()[32..64].load_le::(); + + let factor = 1; + let signal = signal as i32; + i32::from(signal).saturating_mul(factor).saturating_add(0) + } + + /// Set value of BusCurrent + #[inline(always)] + pub fn set_bus_current(&mut self, value: i32) -> Result<(), CanError> { + let factor = 1; + let value = value.checked_sub(0).ok_or(CanError::ParameterOutOfRange { + message_id: BusMeasurement::MESSAGE_ID, + })?; + let value = (value / factor) as i32; + + 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 BusMeasurement { + 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 BusMeasurement { + 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 BusMeasurement { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + if f.alternate() { + f.debug_struct("BusMeasurement") + .field("bus_voltage", &self.bus_voltage()) + .field("bus_current", &self.bus_current()) + .finish() + } else { + f.debug_tuple("BusMeasurement").field(&self.raw).finish() + } + } +} + +impl defmt::Format for BusMeasurement { + fn format(&self, f: defmt::Formatter) { + defmt::write!( + f, + "BusMeasurement {{ BusVoltage={:?} BusCurrent={:?} }}", + self.bus_voltage(), + self.bus_current(), + ); + } +} + +#[cfg(feature = "arb")] +impl<'a> Arbitrary<'a> for BusMeasurement { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + let bus_voltage = u.int_in_range(0..=0)?; + let bus_current = u.int_in_range(0..=0)?; + BusMeasurement::new(bus_voltage, bus_current).map_err(|_| arbitrary::Error::IncorrectFormat) + } +} + +/// VelocityMeasurement +/// +/// - Standard ID: 131 (0x83) +/// - Size: 8 bytes +/// - Transmitter: WaveSculptor22 +#[derive(Clone, Copy)] +pub struct VelocityMeasurement { + raw: [u8; 8], +} + +impl VelocityMeasurement { + pub const MESSAGE_ID: embedded_can::Id = + Id::Standard(unsafe { StandardId::new_unchecked(0x83) }); + + pub const MOTOR_VELOCITY_MIN: i32 = 0_i32; + pub const MOTOR_VELOCITY_MAX: i32 = 0_i32; + pub const VEHICLE_VELOCITY_MIN: i32 = 0_i32; + pub const VEHICLE_VELOCITY_MAX: i32 = 0_i32; + + /// Construct new VelocityMeasurement from values + pub fn new(motor_velocity: i32, vehicle_velocity: i32) -> Result { + let mut res = Self { raw: [0u8; 8] }; + res.set_motor_velocity(motor_velocity)?; + res.set_vehicle_velocity(vehicle_velocity)?; + Ok(res) + } + + /// Access message payload raw value + pub fn raw(&self) -> &[u8; 8] { + &self.raw + } + + /// MotorVelocity + /// + /// Motor angular frequency in revolutions per minute. + /// + /// - Min: 0 + /// - Max: 0 + /// - Unit: "rpm" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn motor_velocity(&self) -> i32 { + self.motor_velocity_raw() + } + + /// Get raw value of MotorVelocity + /// + /// - Start bit: 0 + /// - Signal size: 32 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Signed + #[inline(always)] + pub fn motor_velocity_raw(&self) -> i32 { + let signal = self.raw.view_bits::()[0..32].load_le::(); + + let factor = 1; + let signal = signal as i32; + i32::from(signal).saturating_mul(factor).saturating_add(0) + } + + /// Set value of MotorVelocity + #[inline(always)] + pub fn set_motor_velocity(&mut self, value: i32) -> Result<(), CanError> { + let factor = 1; + let value = value.checked_sub(0).ok_or(CanError::ParameterOutOfRange { + message_id: VelocityMeasurement::MESSAGE_ID, + })?; + let value = (value / factor) as i32; + + let value = u32::from_ne_bytes(value.to_ne_bytes()); + self.raw.view_bits_mut::()[0..32].store_le(value); + Ok(()) + } + + /// VehicleVelocity + /// + /// Vehicle velocity in metres / second. + /// + /// - Min: 0 + /// - Max: 0 + /// - Unit: "m/s" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn vehicle_velocity(&self) -> i32 { + self.vehicle_velocity_raw() + } + + /// Get raw value of VehicleVelocity + /// + /// - Start bit: 32 + /// - Signal size: 32 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Signed + #[inline(always)] + pub fn vehicle_velocity_raw(&self) -> i32 { + let signal = self.raw.view_bits::()[32..64].load_le::(); + + let factor = 1; + let signal = signal as i32; + i32::from(signal).saturating_mul(factor).saturating_add(0) + } + + /// Set value of VehicleVelocity + #[inline(always)] + pub fn set_vehicle_velocity(&mut self, value: i32) -> Result<(), CanError> { + let factor = 1; + let value = value.checked_sub(0).ok_or(CanError::ParameterOutOfRange { + message_id: VelocityMeasurement::MESSAGE_ID, + })?; + let value = (value / factor) as i32; + + 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 VelocityMeasurement { + 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 VelocityMeasurement { + 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 VelocityMeasurement { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + if f.alternate() { + f.debug_struct("VelocityMeasurement") + .field("motor_velocity", &self.motor_velocity()) + .field("vehicle_velocity", &self.vehicle_velocity()) + .finish() + } else { + f.debug_tuple("VelocityMeasurement") + .field(&self.raw) + .finish() + } + } +} + +impl defmt::Format for VelocityMeasurement { + fn format(&self, f: defmt::Formatter) { + defmt::write!( + f, + "VelocityMeasurement {{ MotorVelocity={:?} VehicleVelocity={:?} }}", + self.motor_velocity(), + self.vehicle_velocity(), + ); + } +} + +#[cfg(feature = "arb")] +impl<'a> Arbitrary<'a> for VelocityMeasurement { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + let motor_velocity = u.int_in_range(0..=0)?; + let vehicle_velocity = u.int_in_range(0..=0)?; + VelocityMeasurement::new(motor_velocity, vehicle_velocity) + .map_err(|_| arbitrary::Error::IncorrectFormat) + } +} + +/// PhaseCurrentMeasurement +/// +/// - Standard ID: 132 (0x84) +/// - Size: 8 bytes +/// - Transmitter: WaveSculptor22 +#[derive(Clone, Copy)] +pub struct PhaseCurrentMeasurement { + raw: [u8; 8], +} + +impl PhaseCurrentMeasurement { + pub const MESSAGE_ID: embedded_can::Id = + Id::Standard(unsafe { StandardId::new_unchecked(0x84) }); + + pub const PHASE_CURRENT_B_MIN: i32 = 0_i32; + pub const PHASE_CURRENT_B_MAX: i32 = 0_i32; + pub const PHASE_CURRENT_C_MIN: i32 = 0_i32; + pub const PHASE_CURRENT_C_MAX: i32 = 0_i32; + + /// Construct new PhaseCurrentMeasurement from values + pub fn new(phase_current_b: i32, phase_current_c: i32) -> Result { + let mut res = Self { raw: [0u8; 8] }; + res.set_phase_current_b(phase_current_b)?; + res.set_phase_current_c(phase_current_c)?; + Ok(res) + } + + /// Access message payload raw value + pub fn raw(&self) -> &[u8; 8] { + &self.raw + } + + /// PhaseCurrentB + /// + /// RMS current in motor Phase B. + /// + /// - Min: 0 + /// - Max: 0 + /// - Unit: "A_rms" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn phase_current_b(&self) -> i32 { + self.phase_current_b_raw() + } + + /// Get raw value of PhaseCurrentB + /// + /// - Start bit: 0 + /// - Signal size: 32 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Signed + #[inline(always)] + pub fn phase_current_b_raw(&self) -> i32 { + let signal = self.raw.view_bits::()[0..32].load_le::(); + + let factor = 1; + let signal = signal as i32; + i32::from(signal).saturating_mul(factor).saturating_add(0) + } + + /// Set value of PhaseCurrentB + #[inline(always)] + pub fn set_phase_current_b(&mut self, value: i32) -> Result<(), CanError> { + let factor = 1; + let value = value.checked_sub(0).ok_or(CanError::ParameterOutOfRange { + message_id: PhaseCurrentMeasurement::MESSAGE_ID, + })?; + let value = (value / factor) as i32; + + let value = u32::from_ne_bytes(value.to_ne_bytes()); + self.raw.view_bits_mut::()[0..32].store_le(value); + Ok(()) + } + + /// PhaseCurrentC + /// + /// RMS current in motor Phase C. + /// + /// - Min: 0 + /// - Max: 0 + /// - Unit: "A_rms" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn phase_current_c(&self) -> i32 { + self.phase_current_c_raw() + } + + /// Get raw value of PhaseCurrentC + /// + /// - Start bit: 32 + /// - Signal size: 32 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Signed + #[inline(always)] + pub fn phase_current_c_raw(&self) -> i32 { + let signal = self.raw.view_bits::()[32..64].load_le::(); + + let factor = 1; + let signal = signal as i32; + i32::from(signal).saturating_mul(factor).saturating_add(0) + } + + /// Set value of PhaseCurrentC + #[inline(always)] + pub fn set_phase_current_c(&mut self, value: i32) -> Result<(), CanError> { + let factor = 1; + let value = value.checked_sub(0).ok_or(CanError::ParameterOutOfRange { + message_id: PhaseCurrentMeasurement::MESSAGE_ID, + })?; + let value = (value / factor) as i32; + + 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 PhaseCurrentMeasurement { + 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 PhaseCurrentMeasurement { + 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 PhaseCurrentMeasurement { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + if f.alternate() { + f.debug_struct("PhaseCurrentMeasurement") + .field("phase_current_b", &self.phase_current_b()) + .field("phase_current_c", &self.phase_current_c()) + .finish() + } else { + f.debug_tuple("PhaseCurrentMeasurement") + .field(&self.raw) + .finish() + } + } +} + +impl defmt::Format for PhaseCurrentMeasurement { + fn format(&self, f: defmt::Formatter) { + defmt::write!( + f, + "PhaseCurrentMeasurement {{ PhaseCurrentB={:?} PhaseCurrentC={:?} }}", + self.phase_current_b(), + self.phase_current_c(), + ); + } +} + +#[cfg(feature = "arb")] +impl<'a> Arbitrary<'a> for PhaseCurrentMeasurement { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + let phase_current_b = u.int_in_range(0..=0)?; + let phase_current_c = u.int_in_range(0..=0)?; + PhaseCurrentMeasurement::new(phase_current_b, phase_current_c) + .map_err(|_| arbitrary::Error::IncorrectFormat) + } +} + +/// MotorVoltageVectorMeasurement +/// +/// - Standard ID: 133 (0x85) +/// - Size: 8 bytes +/// - Transmitter: WaveSculptor22 +#[derive(Clone, Copy)] +pub struct MotorVoltageVectorMeasurement { + raw: [u8; 8], +} + +impl MotorVoltageVectorMeasurement { + pub const MESSAGE_ID: embedded_can::Id = + Id::Standard(unsafe { StandardId::new_unchecked(0x85) }); + + pub const VQ_MIN: i32 = 0_i32; + pub const VQ_MAX: i32 = 0_i32; + pub const VD_MIN: i32 = 0_i32; + pub const VD_MAX: i32 = 0_i32; + + /// Construct new MotorVoltageVectorMeasurement from values + pub fn new(vq: i32, vd: i32) -> Result { + let mut res = Self { raw: [0u8; 8] }; + res.set_vq(vq)?; + res.set_vd(vd)?; + Ok(res) + } + + /// Access message payload raw value + pub fn raw(&self) -> &[u8; 8] { + &self.raw + } + + /// Vq + /// + /// Imaginary component of the applied non-rotating voltage vector to the motor. + /// + /// - Min: 0 + /// - Max: 0 + /// - Unit: "V" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn vq(&self) -> i32 { + self.vq_raw() + } + + /// Get raw value of Vq + /// + /// - Start bit: 0 + /// - Signal size: 32 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Signed + #[inline(always)] + pub fn vq_raw(&self) -> i32 { + let signal = self.raw.view_bits::()[0..32].load_le::(); + + let factor = 1; + let signal = signal as i32; + i32::from(signal).saturating_mul(factor).saturating_add(0) + } + + /// Set value of Vq + #[inline(always)] + pub fn set_vq(&mut self, value: i32) -> Result<(), CanError> { + let factor = 1; + let value = value.checked_sub(0).ok_or(CanError::ParameterOutOfRange { + message_id: MotorVoltageVectorMeasurement::MESSAGE_ID, + })?; + let value = (value / factor) as i32; + + let value = u32::from_ne_bytes(value.to_ne_bytes()); + self.raw.view_bits_mut::()[0..32].store_le(value); + Ok(()) + } + + /// Vd + /// + /// Real component of the applied non-rotating voltage vector to the motor. + /// + /// - Min: 0 + /// - Max: 0 + /// - Unit: "V" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn vd(&self) -> i32 { + self.vd_raw() + } + + /// Get raw value of Vd + /// + /// - Start bit: 32 + /// - Signal size: 32 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Signed + #[inline(always)] + pub fn vd_raw(&self) -> i32 { + let signal = self.raw.view_bits::()[32..64].load_le::(); + + let factor = 1; + let signal = signal as i32; + i32::from(signal).saturating_mul(factor).saturating_add(0) + } + + /// Set value of Vd + #[inline(always)] + pub fn set_vd(&mut self, value: i32) -> Result<(), CanError> { + let factor = 1; + let value = value.checked_sub(0).ok_or(CanError::ParameterOutOfRange { + message_id: MotorVoltageVectorMeasurement::MESSAGE_ID, + })?; + let value = (value / factor) as i32; + + 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 MotorVoltageVectorMeasurement { + 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 MotorVoltageVectorMeasurement { + 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 MotorVoltageVectorMeasurement { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + if f.alternate() { + f.debug_struct("MotorVoltageVectorMeasurement") + .field("vq", &self.vq()) + .field("vd", &self.vd()) + .finish() + } else { + f.debug_tuple("MotorVoltageVectorMeasurement") + .field(&self.raw) + .finish() + } + } +} + +impl defmt::Format for MotorVoltageVectorMeasurement { + fn format(&self, f: defmt::Formatter) { + defmt::write!( + f, + "MotorVoltageVectorMeasurement {{ Vq={:?} Vd={:?} }}", + self.vq(), + self.vd(), + ); + } +} + +#[cfg(feature = "arb")] +impl<'a> Arbitrary<'a> for MotorVoltageVectorMeasurement { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + let vq = u.int_in_range(0..=0)?; + let vd = u.int_in_range(0..=0)?; + MotorVoltageVectorMeasurement::new(vq, vd).map_err(|_| arbitrary::Error::IncorrectFormat) + } +} + +/// MotorCurrentVectorMeasurement +/// +/// - Standard ID: 134 (0x86) +/// - Size: 8 bytes +/// - Transmitter: WaveSculptor22 +#[derive(Clone, Copy)] +pub struct MotorCurrentVectorMeasurement { + raw: [u8; 8], +} + +impl MotorCurrentVectorMeasurement { + pub const MESSAGE_ID: embedded_can::Id = + Id::Standard(unsafe { StandardId::new_unchecked(0x86) }); + + pub const IQ_MIN: i32 = 0_i32; + pub const IQ_MAX: i32 = 0_i32; + pub const ID_MIN: i32 = 0_i32; + pub const ID_MAX: i32 = 0_i32; + + /// Construct new MotorCurrentVectorMeasurement from values + pub fn new(iq: i32, id: i32) -> Result { + let mut res = Self { raw: [0u8; 8] }; + res.set_iq(iq)?; + res.set_id(id)?; + Ok(res) + } + + /// Access message payload raw value + pub fn raw(&self) -> &[u8; 8] { + &self.raw + } + + /// Iq + /// + /// Imaginary component of the applied non-rotating current vector to the motor. This current produces torque in the motor and should be in phase with the back-EMF of the motor + /// + /// - Min: 0 + /// - Max: 0 + /// - Unit: "A" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn iq(&self) -> i32 { + self.iq_raw() + } + + /// Get raw value of Iq + /// + /// - Start bit: 0 + /// - Signal size: 32 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Signed + #[inline(always)] + pub fn iq_raw(&self) -> i32 { + let signal = self.raw.view_bits::()[0..32].load_le::(); + + let factor = 1; + let signal = signal as i32; + i32::from(signal).saturating_mul(factor).saturating_add(0) + } + + /// Set value of Iq + #[inline(always)] + pub fn set_iq(&mut self, value: i32) -> Result<(), CanError> { + let factor = 1; + let value = value.checked_sub(0).ok_or(CanError::ParameterOutOfRange { + message_id: MotorCurrentVectorMeasurement::MESSAGE_ID, + })?; + let value = (value / factor) as i32; + + let value = u32::from_ne_bytes(value.to_ne_bytes()); + self.raw.view_bits_mut::()[0..32].store_le(value); + Ok(()) + } + + /// Id + /// + /// Real component of the applied non-rotating current vector to the motor. This vector represents the field current of the motor. + /// + /// - Min: 0 + /// - Max: 0 + /// - Unit: "A" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn id(&self) -> i32 { + self.id_raw() + } + + /// Get raw value of Id + /// + /// - Start bit: 32 + /// - Signal size: 32 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Signed + #[inline(always)] + pub fn id_raw(&self) -> i32 { + let signal = self.raw.view_bits::()[32..64].load_le::(); + + let factor = 1; + let signal = signal as i32; + i32::from(signal).saturating_mul(factor).saturating_add(0) + } + + /// Set value of Id + #[inline(always)] + pub fn set_id(&mut self, value: i32) -> Result<(), CanError> { + let factor = 1; + let value = value.checked_sub(0).ok_or(CanError::ParameterOutOfRange { + message_id: MotorCurrentVectorMeasurement::MESSAGE_ID, + })?; + let value = (value / factor) as i32; + + 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 MotorCurrentVectorMeasurement { + 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 MotorCurrentVectorMeasurement { + 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 MotorCurrentVectorMeasurement { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + if f.alternate() { + f.debug_struct("MotorCurrentVectorMeasurement") + .field("iq", &self.iq()) + .field("id", &self.id()) + .finish() + } else { + f.debug_tuple("MotorCurrentVectorMeasurement") + .field(&self.raw) + .finish() + } + } +} + +impl defmt::Format for MotorCurrentVectorMeasurement { + fn format(&self, f: defmt::Formatter) { + defmt::write!( + f, + "MotorCurrentVectorMeasurement {{ Iq={:?} Id={:?} }}", + self.iq(), + self.id(), + ); + } +} + +#[cfg(feature = "arb")] +impl<'a> Arbitrary<'a> for MotorCurrentVectorMeasurement { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + let iq = u.int_in_range(0..=0)?; + let id = u.int_in_range(0..=0)?; + MotorCurrentVectorMeasurement::new(iq, id).map_err(|_| arbitrary::Error::IncorrectFormat) + } +} + +/// BackEMFMeasurementPrediction +/// +/// - Standard ID: 135 (0x87) +/// - Size: 8 bytes +/// - Transmitter: WaveSculptor22 +#[derive(Clone, Copy)] +pub struct BackEmfMeasurementPrediction { + raw: [u8; 8], +} + +impl BackEmfMeasurementPrediction { + pub const MESSAGE_ID: embedded_can::Id = + Id::Standard(unsafe { StandardId::new_unchecked(0x87) }); + + pub const BEM_FQ_MIN: i32 = 0_i32; + pub const BEM_FQ_MAX: i32 = 0_i32; + pub const BEM_FD_MIN: i32 = 0_i32; + pub const BEM_FD_MAX: i32 = 0_i32; + + /// Construct new BackEMFMeasurementPrediction from values + pub fn new(bem_fq: i32, bem_fd: i32) -> Result { + let mut res = Self { raw: [0u8; 8] }; + res.set_bem_fq(bem_fq)?; + res.set_bem_fd(bem_fd)?; + Ok(res) + } + + /// Access message payload raw value + pub fn raw(&self) -> &[u8; 8] { + &self.raw + } + + /// BEMFq + /// + /// The peak of the phase to neutral motor voltage. + /// + /// - Min: 0 + /// - Max: 0 + /// - Unit: "V" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn bem_fq(&self) -> i32 { + self.bem_fq_raw() + } + + /// Get raw value of BEMFq + /// + /// - Start bit: 0 + /// - Signal size: 32 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Signed + #[inline(always)] + pub fn bem_fq_raw(&self) -> i32 { + let signal = self.raw.view_bits::()[0..32].load_le::(); + + let factor = 1; + let signal = signal as i32; + i32::from(signal).saturating_mul(factor).saturating_add(0) + } + + /// Set value of BEMFq + #[inline(always)] + pub fn set_bem_fq(&mut self, value: i32) -> Result<(), CanError> { + let factor = 1; + let value = value.checked_sub(0).ok_or(CanError::ParameterOutOfRange { + message_id: BackEmfMeasurementPrediction::MESSAGE_ID, + })?; + let value = (value / factor) as i32; + + let value = u32::from_ne_bytes(value.to_ne_bytes()); + self.raw.view_bits_mut::()[0..32].store_le(value); + Ok(()) + } + + /// BEMFd + /// + /// By definition this value is always 0V. + /// + /// - Min: 0 + /// - Max: 0 + /// - Unit: "V" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn bem_fd(&self) -> i32 { + self.bem_fd_raw() + } + + /// Get raw value of BEMFd + /// + /// - Start bit: 32 + /// - Signal size: 32 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Signed + #[inline(always)] + pub fn bem_fd_raw(&self) -> i32 { + let signal = self.raw.view_bits::()[32..64].load_le::(); + + let factor = 1; + let signal = signal as i32; + i32::from(signal).saturating_mul(factor).saturating_add(0) + } + + /// Set value of BEMFd + #[inline(always)] + pub fn set_bem_fd(&mut self, value: i32) -> Result<(), CanError> { + let factor = 1; + let value = value.checked_sub(0).ok_or(CanError::ParameterOutOfRange { + message_id: BackEmfMeasurementPrediction::MESSAGE_ID, + })?; + let value = (value / factor) as i32; + + 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 BackEmfMeasurementPrediction { + 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 BackEmfMeasurementPrediction { + 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 BackEmfMeasurementPrediction { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + if f.alternate() { + f.debug_struct("BackEmfMeasurementPrediction") + .field("bem_fq", &self.bem_fq()) + .field("bem_fd", &self.bem_fd()) + .finish() + } else { + f.debug_tuple("BackEmfMeasurementPrediction") + .field(&self.raw) + .finish() + } + } +} + +impl defmt::Format for BackEmfMeasurementPrediction { + fn format(&self, f: defmt::Formatter) { + defmt::write!( + f, + "BackEmfMeasurementPrediction {{ BEMFq={:?} BEMFd={:?} }}", + self.bem_fq(), + self.bem_fd(), + ); + } +} + +#[cfg(feature = "arb")] +impl<'a> Arbitrary<'a> for BackEmfMeasurementPrediction { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + let bem_fq = u.int_in_range(0..=0)?; + let bem_fd = u.int_in_range(0..=0)?; + BackEmfMeasurementPrediction::new(bem_fq, bem_fd) + .map_err(|_| arbitrary::Error::IncorrectFormat) + } +} + +/// VoltageRail15VMeasurement +/// +/// - Standard ID: 136 (0x88) +/// - Size: 8 bytes +/// - Transmitter: WaveSculptor22 +#[derive(Clone, Copy)] +pub struct VoltageRail15VMeasurement { + raw: [u8; 8], +} + +impl VoltageRail15VMeasurement { + pub const MESSAGE_ID: embedded_can::Id = + Id::Standard(unsafe { StandardId::new_unchecked(0x88) }); + + pub const SUPPLY15_V_MIN: i32 = 0_i32; + pub const SUPPLY15_V_MAX: i32 = 0_i32; + pub const RESERVED_SUPPLY15_V_MIN: i32 = 0_i32; + pub const RESERVED_SUPPLY15_V_MAX: i32 = 0_i32; + + /// Construct new VoltageRail15VMeasurement from values + pub fn new(supply15_v: i32, reserved_supply15_v: i32) -> Result { + let mut res = Self { raw: [0u8; 8] }; + res.set_supply15_v(supply15_v)?; + res.set_reserved_supply15_v(reserved_supply15_v)?; + Ok(res) + } + + /// Access message payload raw value + pub fn raw(&self) -> &[u8; 8] { + &self.raw + } + + /// Supply15V + /// + /// Actual voltage level of the 15V power rail. + /// + /// - Min: 0 + /// - Max: 0 + /// - Unit: "V" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn supply15_v(&self) -> i32 { + self.supply15_v_raw() + } + + /// Get raw value of Supply15V + /// + /// - Start bit: 32 + /// - Signal size: 32 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Signed + #[inline(always)] + pub fn supply15_v_raw(&self) -> i32 { + let signal = self.raw.view_bits::()[32..64].load_le::(); + + let factor = 1; + let signal = signal as i32; + i32::from(signal).saturating_mul(factor).saturating_add(0) + } + + /// Set value of Supply15V + #[inline(always)] + pub fn set_supply15_v(&mut self, value: i32) -> Result<(), CanError> { + let factor = 1; + let value = value.checked_sub(0).ok_or(CanError::ParameterOutOfRange { + message_id: VoltageRail15VMeasurement::MESSAGE_ID, + })?; + let value = (value / factor) as i32; + + let value = u32::from_ne_bytes(value.to_ne_bytes()); + self.raw.view_bits_mut::()[32..64].store_le(value); + Ok(()) + } + + /// ReservedSupply15V + /// + /// - Min: 0 + /// - Max: 0 + /// - Unit: "" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn reserved_supply15_v(&self) -> i32 { + self.reserved_supply15_v_raw() + } + + /// Get raw value of ReservedSupply15V + /// + /// - Start bit: 0 + /// - Signal size: 32 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Signed + #[inline(always)] + pub fn reserved_supply15_v_raw(&self) -> i32 { + let signal = self.raw.view_bits::()[0..32].load_le::(); + + let factor = 1; + let signal = signal as i32; + i32::from(signal).saturating_mul(factor).saturating_add(0) + } + + /// Set value of ReservedSupply15V + #[inline(always)] + pub fn set_reserved_supply15_v(&mut self, value: i32) -> Result<(), CanError> { + let factor = 1; + let value = value.checked_sub(0).ok_or(CanError::ParameterOutOfRange { + message_id: VoltageRail15VMeasurement::MESSAGE_ID, + })?; + let value = (value / factor) as i32; + + let value = u32::from_ne_bytes(value.to_ne_bytes()); + self.raw.view_bits_mut::()[0..32].store_le(value); + Ok(()) + } +} + +impl core::convert::TryFrom<&[u8]> for VoltageRail15VMeasurement { + 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 VoltageRail15VMeasurement { + 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 VoltageRail15VMeasurement { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + if f.alternate() { + f.debug_struct("VoltageRail15VMeasurement") + .field("supply15_v", &self.supply15_v()) + .field("reserved_supply15_v", &self.reserved_supply15_v()) + .finish() + } else { + f.debug_tuple("VoltageRail15VMeasurement") + .field(&self.raw) + .finish() + } + } +} + +impl defmt::Format for VoltageRail15VMeasurement { + fn format(&self, f: defmt::Formatter) { + defmt::write!( + f, + "VoltageRail15VMeasurement {{ Supply15V={:?} ReservedSupply15V={:?} }}", + self.supply15_v(), + self.reserved_supply15_v(), + ); + } +} + +#[cfg(feature = "arb")] +impl<'a> Arbitrary<'a> for VoltageRail15VMeasurement { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + let supply15_v = u.int_in_range(0..=0)?; + let reserved_supply15_v = u.int_in_range(0..=0)?; + VoltageRail15VMeasurement::new(supply15_v, reserved_supply15_v) + .map_err(|_| arbitrary::Error::IncorrectFormat) + } +} + +/// VoltageRail3V31V9Measurement +/// +/// - Standard ID: 137 (0x89) +/// - Size: 8 bytes +/// - Transmitter: WaveSculptor22 +#[derive(Clone, Copy)] +pub struct VoltageRail3V31v9Measurement { + raw: [u8; 8], +} + +impl VoltageRail3V31v9Measurement { + pub const MESSAGE_ID: embedded_can::Id = + Id::Standard(unsafe { StandardId::new_unchecked(0x89) }); + + pub const SUPPLY1_V9_MIN: i32 = 0_i32; + pub const SUPPLY1_V9_MAX: i32 = 0_i32; + pub const SUPPLY3_V3_MIN: i32 = 0_i32; + pub const SUPPLY3_V3_MAX: i32 = 0_i32; + + /// Construct new VoltageRail3V31V9Measurement from values + pub fn new(supply1_v9: i32, supply3_v3: i32) -> Result { + let mut res = Self { raw: [0u8; 8] }; + res.set_supply1_v9(supply1_v9)?; + res.set_supply3_v3(supply3_v3)?; + Ok(res) + } + + /// Access message payload raw value + pub fn raw(&self) -> &[u8; 8] { + &self.raw + } + + /// Supply1V9 + /// + /// Actual voltage level of the 1.9V DSP power rail. + /// + /// - Min: 0 + /// - Max: 0 + /// - Unit: "V" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn supply1_v9(&self) -> i32 { + self.supply1_v9_raw() + } + + /// Get raw value of Supply1V9 + /// + /// - Start bit: 0 + /// - Signal size: 32 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Signed + #[inline(always)] + pub fn supply1_v9_raw(&self) -> i32 { + let signal = self.raw.view_bits::()[0..32].load_le::(); + + let factor = 1; + let signal = signal as i32; + i32::from(signal).saturating_mul(factor).saturating_add(0) + } + + /// Set value of Supply1V9 + #[inline(always)] + pub fn set_supply1_v9(&mut self, value: i32) -> Result<(), CanError> { + let factor = 1; + let value = value.checked_sub(0).ok_or(CanError::ParameterOutOfRange { + message_id: VoltageRail3V31v9Measurement::MESSAGE_ID, + })?; + let value = (value / factor) as i32; + + let value = u32::from_ne_bytes(value.to_ne_bytes()); + self.raw.view_bits_mut::()[0..32].store_le(value); + Ok(()) + } + + /// Supply3V3 + /// + /// Actual voltage level of the 3.3V power rail. + /// + /// - Min: 0 + /// - Max: 0 + /// - Unit: "V" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn supply3_v3(&self) -> i32 { + self.supply3_v3_raw() + } + + /// Get raw value of Supply3V3 + /// + /// - Start bit: 32 + /// - Signal size: 32 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Signed + #[inline(always)] + pub fn supply3_v3_raw(&self) -> i32 { + let signal = self.raw.view_bits::()[32..64].load_le::(); + + let factor = 1; + let signal = signal as i32; + i32::from(signal).saturating_mul(factor).saturating_add(0) + } + + /// Set value of Supply3V3 + #[inline(always)] + pub fn set_supply3_v3(&mut self, value: i32) -> Result<(), CanError> { + let factor = 1; + let value = value.checked_sub(0).ok_or(CanError::ParameterOutOfRange { + message_id: VoltageRail3V31v9Measurement::MESSAGE_ID, + })?; + let value = (value / factor) as i32; + + 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 VoltageRail3V31v9Measurement { + 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 VoltageRail3V31v9Measurement { + 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 VoltageRail3V31v9Measurement { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + if f.alternate() { + f.debug_struct("VoltageRail3V31v9Measurement") + .field("supply1_v9", &self.supply1_v9()) + .field("supply3_v3", &self.supply3_v3()) + .finish() + } else { + f.debug_tuple("VoltageRail3V31v9Measurement") + .field(&self.raw) + .finish() + } + } +} + +impl defmt::Format for VoltageRail3V31v9Measurement { + fn format(&self, f: defmt::Formatter) { + defmt::write!( + f, + "VoltageRail3V31v9Measurement {{ Supply1V9={:?} Supply3V3={:?} }}", + self.supply1_v9(), + self.supply3_v3(), + ); + } +} + +#[cfg(feature = "arb")] +impl<'a> Arbitrary<'a> for VoltageRail3V31v9Measurement { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + let supply1_v9 = u.int_in_range(0..=0)?; + let supply3_v3 = u.int_in_range(0..=0)?; + VoltageRail3V31v9Measurement::new(supply1_v9, supply3_v3) + .map_err(|_| arbitrary::Error::IncorrectFormat) + } +} + +/// Reserved0A +/// +/// - Standard ID: 138 (0x8a) +/// - Size: 8 bytes +/// - Transmitter: WaveSculptor22 +#[derive(Clone, Copy)] +pub struct Reserved0A { + raw: [u8; 8], +} + +impl Reserved0A { + pub const MESSAGE_ID: embedded_can::Id = + Id::Standard(unsafe { StandardId::new_unchecked(0x8a) }); + + pub const RESERVED0_A0_MIN: i32 = 0_i32; + pub const RESERVED0_A0_MAX: i32 = 0_i32; + pub const RESERVED0_A1_MIN: i32 = 0_i32; + pub const RESERVED0_A1_MAX: i32 = 0_i32; + + /// Construct new Reserved0A from values + pub fn new(reserved0_a0: i32, reserved0_a1: i32) -> Result { + let mut res = Self { raw: [0u8; 8] }; + res.set_reserved0_a0(reserved0_a0)?; + res.set_reserved0_a1(reserved0_a1)?; + Ok(res) + } + + /// Access message payload raw value + pub fn raw(&self) -> &[u8; 8] { + &self.raw + } + + /// Reserved0A0 + /// + /// - Min: 0 + /// - Max: 0 + /// - Unit: "" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn reserved0_a0(&self) -> i32 { + self.reserved0_a0_raw() + } + + /// Get raw value of Reserved0A0 + /// + /// - Start bit: 0 + /// - Signal size: 32 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Signed + #[inline(always)] + pub fn reserved0_a0_raw(&self) -> i32 { + let signal = self.raw.view_bits::()[0..32].load_le::(); + + let factor = 1; + let signal = signal as i32; + i32::from(signal).saturating_mul(factor).saturating_add(0) + } + + /// Set value of Reserved0A0 + #[inline(always)] + pub fn set_reserved0_a0(&mut self, value: i32) -> Result<(), CanError> { + let factor = 1; + let value = value.checked_sub(0).ok_or(CanError::ParameterOutOfRange { + message_id: Reserved0A::MESSAGE_ID, + })?; + let value = (value / factor) as i32; + + let value = u32::from_ne_bytes(value.to_ne_bytes()); + self.raw.view_bits_mut::()[0..32].store_le(value); + Ok(()) + } + + /// Reserved0A1 + /// + /// - Min: 0 + /// - Max: 0 + /// - Unit: "" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn reserved0_a1(&self) -> i32 { + self.reserved0_a1_raw() + } + + /// Get raw value of Reserved0A1 + /// + /// - Start bit: 32 + /// - Signal size: 32 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Signed + #[inline(always)] + pub fn reserved0_a1_raw(&self) -> i32 { + let signal = self.raw.view_bits::()[32..64].load_le::(); + + let factor = 1; + let signal = signal as i32; + i32::from(signal).saturating_mul(factor).saturating_add(0) + } + + /// Set value of Reserved0A1 + #[inline(always)] + pub fn set_reserved0_a1(&mut self, value: i32) -> Result<(), CanError> { + let factor = 1; + let value = value.checked_sub(0).ok_or(CanError::ParameterOutOfRange { + message_id: Reserved0A::MESSAGE_ID, + })?; + let value = (value / factor) as i32; + + 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 Reserved0A { + 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 Reserved0A { + 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 Reserved0A { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + if f.alternate() { + f.debug_struct("Reserved0A") + .field("reserved0_a0", &self.reserved0_a0()) + .field("reserved0_a1", &self.reserved0_a1()) + .finish() + } else { + f.debug_tuple("Reserved0A").field(&self.raw).finish() + } + } +} + +impl defmt::Format for Reserved0A { + fn format(&self, f: defmt::Formatter) { + defmt::write!( + f, + "Reserved0A {{ Reserved0A0={:?} Reserved0A1={:?} }}", + self.reserved0_a0(), + self.reserved0_a1(), + ); + } +} + +#[cfg(feature = "arb")] +impl<'a> Arbitrary<'a> for Reserved0A { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + let reserved0_a0 = u.int_in_range(0..=0)?; + let reserved0_a1 = u.int_in_range(0..=0)?; + Reserved0A::new(reserved0_a0, reserved0_a1).map_err(|_| arbitrary::Error::IncorrectFormat) + } +} + +/// HeatsinkMotorTempMeasurement +/// +/// - Standard ID: 139 (0x8b) +/// - Size: 8 bytes +/// - Transmitter: WaveSculptor22 +#[derive(Clone, Copy)] +pub struct HeatsinkMotorTempMeasurement { + raw: [u8; 8], +} + +impl HeatsinkMotorTempMeasurement { + pub const MESSAGE_ID: embedded_can::Id = + Id::Standard(unsafe { StandardId::new_unchecked(0x8b) }); + + pub const MOTOR_TEMP_MIN: i32 = 0_i32; + pub const MOTOR_TEMP_MAX: i32 = 0_i32; + pub const HEATSINK_TEMP_MIN: i32 = 0_i32; + pub const HEATSINK_TEMP_MAX: i32 = 0_i32; + + /// Construct new HeatsinkMotorTempMeasurement from values + pub fn new(motor_temp: i32, heatsink_temp: i32) -> Result { + let mut res = Self { raw: [0u8; 8] }; + res.set_motor_temp(motor_temp)?; + res.set_heatsink_temp(heatsink_temp)?; + Ok(res) + } + + /// Access message payload raw value + pub fn raw(&self) -> &[u8; 8] { + &self.raw + } + + /// MotorTemp + /// + /// Internal temperature of the motor + /// + /// - Min: 0 + /// - Max: 0 + /// - Unit: "C" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn motor_temp(&self) -> i32 { + self.motor_temp_raw() + } + + /// Get raw value of MotorTemp + /// + /// - Start bit: 0 + /// - Signal size: 32 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Signed + #[inline(always)] + pub fn motor_temp_raw(&self) -> i32 { + let signal = self.raw.view_bits::()[0..32].load_le::(); + + let factor = 1; + let signal = signal as i32; + i32::from(signal).saturating_mul(factor).saturating_add(0) + } + + /// Set value of MotorTemp + #[inline(always)] + pub fn set_motor_temp(&mut self, value: i32) -> Result<(), CanError> { + let factor = 1; + let value = value.checked_sub(0).ok_or(CanError::ParameterOutOfRange { + message_id: HeatsinkMotorTempMeasurement::MESSAGE_ID, + })?; + let value = (value / factor) as i32; + + let value = u32::from_ne_bytes(value.to_ne_bytes()); + self.raw.view_bits_mut::()[0..32].store_le(value); + Ok(()) + } + + /// HeatsinkTemp + /// + /// Internal temperature of Heat-sink (case). + /// + /// - Min: 0 + /// - Max: 0 + /// - Unit: "C" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn heatsink_temp(&self) -> i32 { + self.heatsink_temp_raw() + } + + /// Get raw value of HeatsinkTemp + /// + /// - Start bit: 32 + /// - Signal size: 32 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Signed + #[inline(always)] + pub fn heatsink_temp_raw(&self) -> i32 { + let signal = self.raw.view_bits::()[32..64].load_le::(); + + let factor = 1; + let signal = signal as i32; + i32::from(signal).saturating_mul(factor).saturating_add(0) + } + + /// Set value of HeatsinkTemp + #[inline(always)] + pub fn set_heatsink_temp(&mut self, value: i32) -> Result<(), CanError> { + let factor = 1; + let value = value.checked_sub(0).ok_or(CanError::ParameterOutOfRange { + message_id: HeatsinkMotorTempMeasurement::MESSAGE_ID, + })?; + let value = (value / factor) as i32; + + 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 HeatsinkMotorTempMeasurement { + 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 HeatsinkMotorTempMeasurement { + 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 HeatsinkMotorTempMeasurement { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + if f.alternate() { + f.debug_struct("HeatsinkMotorTempMeasurement") + .field("motor_temp", &self.motor_temp()) + .field("heatsink_temp", &self.heatsink_temp()) + .finish() + } else { + f.debug_tuple("HeatsinkMotorTempMeasurement") + .field(&self.raw) + .finish() + } + } +} + +impl defmt::Format for HeatsinkMotorTempMeasurement { + fn format(&self, f: defmt::Formatter) { + defmt::write!( + f, + "HeatsinkMotorTempMeasurement {{ MotorTemp={:?} HeatsinkTemp={:?} }}", + self.motor_temp(), + self.heatsink_temp(), + ); + } +} + +#[cfg(feature = "arb")] +impl<'a> Arbitrary<'a> for HeatsinkMotorTempMeasurement { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + let motor_temp = u.int_in_range(0..=0)?; + let heatsink_temp = u.int_in_range(0..=0)?; + HeatsinkMotorTempMeasurement::new(motor_temp, heatsink_temp) + .map_err(|_| arbitrary::Error::IncorrectFormat) + } +} + +/// DspBoardTempMeasurement +/// +/// - Standard ID: 140 (0x8c) +/// - Size: 8 bytes +/// - Transmitter: WaveSculptor22 +#[derive(Clone, Copy)] +pub struct DspBoardTempMeasurement { + raw: [u8; 8], +} + +impl DspBoardTempMeasurement { + pub const MESSAGE_ID: embedded_can::Id = + Id::Standard(unsafe { StandardId::new_unchecked(0x8c) }); + + pub const DSP_BOARD_TEMP_MIN: i32 = 0_i32; + pub const DSP_BOARD_TEMP_MAX: i32 = 0_i32; + pub const RESERVED_DSP_BOARD_TEMP_MIN: i32 = 0_i32; + pub const RESERVED_DSP_BOARD_TEMP_MAX: i32 = 0_i32; + + /// Construct new DspBoardTempMeasurement from values + pub fn new(dsp_board_temp: i32, reserved_dsp_board_temp: i32) -> Result { + let mut res = Self { raw: [0u8; 8] }; + res.set_dsp_board_temp(dsp_board_temp)?; + res.set_reserved_dsp_board_temp(reserved_dsp_board_temp)?; + Ok(res) + } + + /// Access message payload raw value + pub fn raw(&self) -> &[u8; 8] { + &self.raw + } + + /// DspBoardTemp + /// + /// Temperature of the DSP board. + /// + /// - Min: 0 + /// - Max: 0 + /// - Unit: "C" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn dsp_board_temp(&self) -> i32 { + self.dsp_board_temp_raw() + } + + /// Get raw value of DspBoardTemp + /// + /// - Start bit: 0 + /// - Signal size: 32 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Signed + #[inline(always)] + pub fn dsp_board_temp_raw(&self) -> i32 { + let signal = self.raw.view_bits::()[0..32].load_le::(); + + let factor = 1; + let signal = signal as i32; + i32::from(signal).saturating_mul(factor).saturating_add(0) + } + + /// Set value of DspBoardTemp + #[inline(always)] + pub fn set_dsp_board_temp(&mut self, value: i32) -> Result<(), CanError> { + let factor = 1; + let value = value.checked_sub(0).ok_or(CanError::ParameterOutOfRange { + message_id: DspBoardTempMeasurement::MESSAGE_ID, + })?; + let value = (value / factor) as i32; + + let value = u32::from_ne_bytes(value.to_ne_bytes()); + self.raw.view_bits_mut::()[0..32].store_le(value); + Ok(()) + } + + /// ReservedDspBoardTemp + /// + /// - Min: 0 + /// - Max: 0 + /// - Unit: "" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn reserved_dsp_board_temp(&self) -> i32 { + self.reserved_dsp_board_temp_raw() + } + + /// Get raw value of ReservedDspBoardTemp + /// + /// - Start bit: 32 + /// - Signal size: 32 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Signed + #[inline(always)] + pub fn reserved_dsp_board_temp_raw(&self) -> i32 { + let signal = self.raw.view_bits::()[32..64].load_le::(); + + let factor = 1; + let signal = signal as i32; + i32::from(signal).saturating_mul(factor).saturating_add(0) + } + + /// Set value of ReservedDspBoardTemp + #[inline(always)] + pub fn set_reserved_dsp_board_temp(&mut self, value: i32) -> Result<(), CanError> { + let factor = 1; + let value = value.checked_sub(0).ok_or(CanError::ParameterOutOfRange { + message_id: DspBoardTempMeasurement::MESSAGE_ID, + })?; + let value = (value / factor) as i32; + + 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 DspBoardTempMeasurement { + 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 DspBoardTempMeasurement { + 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 DspBoardTempMeasurement { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + if f.alternate() { + f.debug_struct("DspBoardTempMeasurement") + .field("dsp_board_temp", &self.dsp_board_temp()) + .field("reserved_dsp_board_temp", &self.reserved_dsp_board_temp()) + .finish() + } else { + f.debug_tuple("DspBoardTempMeasurement") + .field(&self.raw) + .finish() + } + } +} + +impl defmt::Format for DspBoardTempMeasurement { + fn format(&self, f: defmt::Formatter) { + defmt::write!( + f, + "DspBoardTempMeasurement {{ DspBoardTemp={:?} ReservedDspBoardTemp={:?} }}", + self.dsp_board_temp(), + self.reserved_dsp_board_temp(), + ); + } +} + +#[cfg(feature = "arb")] +impl<'a> Arbitrary<'a> for DspBoardTempMeasurement { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + let dsp_board_temp = u.int_in_range(0..=0)?; + let reserved_dsp_board_temp = u.int_in_range(0..=0)?; + DspBoardTempMeasurement::new(dsp_board_temp, reserved_dsp_board_temp) + .map_err(|_| arbitrary::Error::IncorrectFormat) + } +} + +/// Reserved0D +/// +/// - Standard ID: 141 (0x8d) +/// - Size: 8 bytes +/// - Transmitter: WaveSculptor22 +#[derive(Clone, Copy)] +pub struct Reserved0D { + raw: [u8; 8], +} + +impl Reserved0D { + pub const MESSAGE_ID: embedded_can::Id = + Id::Standard(unsafe { StandardId::new_unchecked(0x8d) }); + + pub const RESERVED0_D0_MIN: i32 = 0_i32; + pub const RESERVED0_D0_MAX: i32 = 0_i32; + pub const RESERVED0_D1_MIN: i32 = 0_i32; + pub const RESERVED0_D1_MAX: i32 = 0_i32; + + /// Construct new Reserved0D from values + pub fn new(reserved0_d0: i32, reserved0_d1: i32) -> Result { + let mut res = Self { raw: [0u8; 8] }; + res.set_reserved0_d0(reserved0_d0)?; + res.set_reserved0_d1(reserved0_d1)?; + Ok(res) + } + + /// Access message payload raw value + pub fn raw(&self) -> &[u8; 8] { + &self.raw + } + + /// Reserved0D0 + /// + /// - Min: 0 + /// - Max: 0 + /// - Unit: "" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn reserved0_d0(&self) -> i32 { + self.reserved0_d0_raw() + } + + /// Get raw value of Reserved0D0 + /// + /// - Start bit: 0 + /// - Signal size: 32 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Signed + #[inline(always)] + pub fn reserved0_d0_raw(&self) -> i32 { + let signal = self.raw.view_bits::()[0..32].load_le::(); + + let factor = 1; + let signal = signal as i32; + i32::from(signal).saturating_mul(factor).saturating_add(0) + } + + /// Set value of Reserved0D0 + #[inline(always)] + pub fn set_reserved0_d0(&mut self, value: i32) -> Result<(), CanError> { + let factor = 1; + let value = value.checked_sub(0).ok_or(CanError::ParameterOutOfRange { + message_id: Reserved0D::MESSAGE_ID, + })?; + let value = (value / factor) as i32; + + let value = u32::from_ne_bytes(value.to_ne_bytes()); + self.raw.view_bits_mut::()[0..32].store_le(value); + Ok(()) + } + + /// Reserved0D1 + /// + /// - Min: 0 + /// - Max: 0 + /// - Unit: "" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn reserved0_d1(&self) -> i32 { + self.reserved0_d1_raw() + } + + /// Get raw value of Reserved0D1 + /// + /// - Start bit: 32 + /// - Signal size: 32 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Signed + #[inline(always)] + pub fn reserved0_d1_raw(&self) -> i32 { + let signal = self.raw.view_bits::()[32..64].load_le::(); + + let factor = 1; + let signal = signal as i32; + i32::from(signal).saturating_mul(factor).saturating_add(0) + } + + /// Set value of Reserved0D1 + #[inline(always)] + pub fn set_reserved0_d1(&mut self, value: i32) -> Result<(), CanError> { + let factor = 1; + let value = value.checked_sub(0).ok_or(CanError::ParameterOutOfRange { + message_id: Reserved0D::MESSAGE_ID, + })?; + let value = (value / factor) as i32; + + 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 Reserved0D { + 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 Reserved0D { + 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 Reserved0D { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + if f.alternate() { + f.debug_struct("Reserved0D") + .field("reserved0_d0", &self.reserved0_d0()) + .field("reserved0_d1", &self.reserved0_d1()) + .finish() + } else { + f.debug_tuple("Reserved0D").field(&self.raw).finish() + } + } +} + +impl defmt::Format for Reserved0D { + fn format(&self, f: defmt::Formatter) { + defmt::write!( + f, + "Reserved0D {{ Reserved0D0={:?} Reserved0D1={:?} }}", + self.reserved0_d0(), + self.reserved0_d1(), + ); + } +} + +#[cfg(feature = "arb")] +impl<'a> Arbitrary<'a> for Reserved0D { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + let reserved0_d0 = u.int_in_range(0..=0)?; + let reserved0_d1 = u.int_in_range(0..=0)?; + Reserved0D::new(reserved0_d0, reserved0_d1).map_err(|_| arbitrary::Error::IncorrectFormat) + } +} + +/// OdometerBusAhMeasurement +/// +/// - Standard ID: 142 (0x8e) +/// - Size: 8 bytes +/// - Transmitter: WaveSculptor22 +#[derive(Clone, Copy)] +pub struct OdometerBusAhMeasurement { + raw: [u8; 8], +} + +impl OdometerBusAhMeasurement { + pub const MESSAGE_ID: embedded_can::Id = + Id::Standard(unsafe { StandardId::new_unchecked(0x8e) }); + + pub const ODOMETER_MIN: i32 = 0_i32; + pub const ODOMETER_MAX: i32 = 0_i32; + pub const DC_BUS_AH_MIN: i32 = 0_i32; + pub const DC_BUS_AH_MAX: i32 = 0_i32; + + /// Construct new OdometerBusAhMeasurement from values + pub fn new(odometer: i32, dc_bus_ah: i32) -> Result { + let mut res = Self { raw: [0u8; 8] }; + res.set_odometer(odometer)?; + res.set_dc_bus_ah(dc_bus_ah)?; + Ok(res) + } + + /// Access message payload raw value + pub fn raw(&self) -> &[u8; 8] { + &self.raw + } + + /// Odometer + /// + /// Distance the vehicle has travelled since reset. + /// + /// - Min: 0 + /// - Max: 0 + /// - Unit: "m" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn odometer(&self) -> i32 { + self.odometer_raw() + } + + /// Get raw value of Odometer + /// + /// - Start bit: 0 + /// - Signal size: 32 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Signed + #[inline(always)] + pub fn odometer_raw(&self) -> i32 { + let signal = self.raw.view_bits::()[0..32].load_le::(); + + let factor = 1; + let signal = signal as i32; + i32::from(signal).saturating_mul(factor).saturating_add(0) + } + + /// Set value of Odometer + #[inline(always)] + pub fn set_odometer(&mut self, value: i32) -> Result<(), CanError> { + let factor = 1; + let value = value.checked_sub(0).ok_or(CanError::ParameterOutOfRange { + message_id: OdometerBusAhMeasurement::MESSAGE_ID, + })?; + let value = (value / factor) as i32; + + let value = u32::from_ne_bytes(value.to_ne_bytes()); + self.raw.view_bits_mut::()[0..32].store_le(value); + Ok(()) + } + + /// DCBusAh + /// + /// Charge flow into the controller DC bus from the time of reset. + /// + /// - Min: 0 + /// - Max: 0 + /// - Unit: "Ah" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn dc_bus_ah(&self) -> i32 { + self.dc_bus_ah_raw() + } + + /// Get raw value of DCBusAh + /// + /// - Start bit: 32 + /// - Signal size: 32 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Signed + #[inline(always)] + pub fn dc_bus_ah_raw(&self) -> i32 { + let signal = self.raw.view_bits::()[32..64].load_le::(); + + let factor = 1; + let signal = signal as i32; + i32::from(signal).saturating_mul(factor).saturating_add(0) + } + + /// Set value of DCBusAh + #[inline(always)] + pub fn set_dc_bus_ah(&mut self, value: i32) -> Result<(), CanError> { + let factor = 1; + let value = value.checked_sub(0).ok_or(CanError::ParameterOutOfRange { + message_id: OdometerBusAhMeasurement::MESSAGE_ID, + })?; + let value = (value / factor) as i32; + + 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 OdometerBusAhMeasurement { + 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 OdometerBusAhMeasurement { + 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 OdometerBusAhMeasurement { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + if f.alternate() { + f.debug_struct("OdometerBusAhMeasurement") + .field("odometer", &self.odometer()) + .field("dc_bus_ah", &self.dc_bus_ah()) + .finish() + } else { + f.debug_tuple("OdometerBusAhMeasurement") + .field(&self.raw) + .finish() + } + } +} + +impl defmt::Format for OdometerBusAhMeasurement { + fn format(&self, f: defmt::Formatter) { + defmt::write!( + f, + "OdometerBusAhMeasurement {{ Odometer={:?} DCBusAh={:?} }}", + self.odometer(), + self.dc_bus_ah(), + ); + } +} + +#[cfg(feature = "arb")] +impl<'a> Arbitrary<'a> for OdometerBusAhMeasurement { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + let odometer = u.int_in_range(0..=0)?; + let dc_bus_ah = u.int_in_range(0..=0)?; + OdometerBusAhMeasurement::new(odometer, dc_bus_ah) + .map_err(|_| arbitrary::Error::IncorrectFormat) + } +} + +/// SlipSpeedMeasurement +/// +/// - Standard ID: 151 (0x97) +/// - Size: 8 bytes +/// - Transmitter: WaveSculptor22 +#[derive(Clone, Copy)] +pub struct SlipSpeedMeasurement { + raw: [u8; 8], +} + +impl SlipSpeedMeasurement { + pub const MESSAGE_ID: embedded_can::Id = + Id::Standard(unsafe { StandardId::new_unchecked(0x97) }); + + pub const SLIP_SPEED_MIN: i32 = 0_i32; + pub const SLIP_SPEED_MAX: i32 = 0_i32; + pub const RESERVED_SLIP_SPEED_MIN: i32 = 0_i32; + pub const RESERVED_SLIP_SPEED_MAX: i32 = 0_i32; + + /// Construct new SlipSpeedMeasurement from values + pub fn new(slip_speed: i32, reserved_slip_speed: i32) -> Result { + let mut res = Self { raw: [0u8; 8] }; + res.set_slip_speed(slip_speed)?; + res.set_reserved_slip_speed(reserved_slip_speed)?; + Ok(res) + } + + /// Access message payload raw value + pub fn raw(&self) -> &[u8; 8] { + &self.raw + } + + /// SlipSpeed + /// + /// Slip speed when driving an induction motor. + /// + /// - Min: 0 + /// - Max: 0 + /// - Unit: "Hz" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn slip_speed(&self) -> i32 { + self.slip_speed_raw() + } + + /// Get raw value of SlipSpeed + /// + /// - Start bit: 0 + /// - Signal size: 32 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Signed + #[inline(always)] + pub fn slip_speed_raw(&self) -> i32 { + let signal = self.raw.view_bits::()[0..32].load_le::(); + + let factor = 1; + let signal = signal as i32; + i32::from(signal).saturating_mul(factor).saturating_add(0) + } + + /// Set value of SlipSpeed + #[inline(always)] + pub fn set_slip_speed(&mut self, value: i32) -> Result<(), CanError> { + let factor = 1; + let value = value.checked_sub(0).ok_or(CanError::ParameterOutOfRange { + message_id: SlipSpeedMeasurement::MESSAGE_ID, + })?; + let value = (value / factor) as i32; + + let value = u32::from_ne_bytes(value.to_ne_bytes()); + self.raw.view_bits_mut::()[0..32].store_le(value); + Ok(()) + } + + /// ReservedSlipSpeed + /// + /// - Min: 0 + /// - Max: 0 + /// - Unit: "" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn reserved_slip_speed(&self) -> i32 { + self.reserved_slip_speed_raw() + } + + /// Get raw value of ReservedSlipSpeed + /// + /// - Start bit: 32 + /// - Signal size: 32 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Signed + #[inline(always)] + pub fn reserved_slip_speed_raw(&self) -> i32 { + let signal = self.raw.view_bits::()[32..64].load_le::(); + + let factor = 1; + let signal = signal as i32; + i32::from(signal).saturating_mul(factor).saturating_add(0) + } + + /// Set value of ReservedSlipSpeed + #[inline(always)] + pub fn set_reserved_slip_speed(&mut self, value: i32) -> Result<(), CanError> { + let factor = 1; + let value = value.checked_sub(0).ok_or(CanError::ParameterOutOfRange { + message_id: SlipSpeedMeasurement::MESSAGE_ID, + })?; + let value = (value / factor) as i32; + + 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 SlipSpeedMeasurement { + 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 SlipSpeedMeasurement { + 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 SlipSpeedMeasurement { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + if f.alternate() { + f.debug_struct("SlipSpeedMeasurement") + .field("slip_speed", &self.slip_speed()) + .field("reserved_slip_speed", &self.reserved_slip_speed()) + .finish() + } else { + f.debug_tuple("SlipSpeedMeasurement") + .field(&self.raw) + .finish() + } + } +} + +impl defmt::Format for SlipSpeedMeasurement { + fn format(&self, f: defmt::Formatter) { + defmt::write!( + f, + "SlipSpeedMeasurement {{ SlipSpeed={:?} ReservedSlipSpeed={:?} }}", + self.slip_speed(), + self.reserved_slip_speed(), + ); + } +} + +#[cfg(feature = "arb")] +impl<'a> Arbitrary<'a> for SlipSpeedMeasurement { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + let slip_speed = u.int_in_range(0..=0)?; + let reserved_slip_speed = u.int_in_range(0..=0)?; + SlipSpeedMeasurement::new(slip_speed, reserved_slip_speed) + .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(embedded_can::Id), + /// Signal parameter is not within the range + /// defined in the dbc + ParameterOutOfRange { + /// dbc message id + message_id: embedded_can::Id, + }, + InvalidPayloadSize, + /// Multiplexor value not defined in the dbc + InvalidMultiplexor { + /// dbc message id + message_id: embedded_can::Id, + /// Multiplexor value not defined in the dbc + multiplexor: u16, + }, +} + +impl core::fmt::Display for CanError { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:?}", self) + } +} +#[cfg(feature = "std")] +impl std::error::Error for CanError {} +#[cfg(feature = "arb")] +trait UnstructuredFloatExt { + fn float_in_range(&mut self, range: core::ops::RangeInclusive) -> arbitrary::Result; +} + +#[cfg(feature = "arb")] +impl UnstructuredFloatExt for arbitrary::Unstructured<'_> { + fn float_in_range(&mut self, range: core::ops::RangeInclusive) -> arbitrary::Result { + let min = range.start(); + let max = range.end(); + let steps = u32::MAX; + let factor = (max - min) / (steps as f32); + let random_int: u32 = self.int_in_range(0..=steps)?; + let random = min + factor * (random_int as f32); + Ok(random) + } +} diff --git a/solar_rust/src/messages_mppt.rs b/solar_rust/src/messages_mppt.rs new file mode 100644 index 0000000..0fe0e86 --- /dev/null +++ b/solar_rust/src/messages_mppt.rs @@ -0,0 +1,2381 @@ +// Generated code! +#![allow(unused_comparisons, unreachable_patterns, unused_imports)] +#![allow(clippy::let_and_return, clippy::eq_op)] +#![allow(clippy::useless_conversion, clippy::unnecessary_cast)] +#![allow( + clippy::excessive_precision, + clippy::manual_range_contains, + clippy::absurd_extreme_comparisons, + clippy::too_many_arguments +)] +#![deny(clippy::arithmetic_side_effects)] + +//! Message definitions from file `"mppt.dbc"` +//! +//! - Version: `Version("")` + +#[cfg(feature = "arb")] +use arbitrary::{Arbitrary, Unstructured}; +use bitvec::prelude::*; +use core::ops::BitOr; +use embedded_can::{ExtendedId, Id, StandardId}; + +/// All messages +#[derive(Clone, Debug, defmt::Format)] +pub enum Messages { + /// PowerInput + PowerInput(PowerInput), + /// PowerOutput + PowerOutput(PowerOutput), + /// Temperature + Temperature(Temperature), + /// AuxillaryPowerSupply + AuxillaryPowerSupply(AuxillaryPowerSupply), + /// Limits + Limits(Limits), + /// Status + Status(Status), + /// PowerConnector + PowerConnector(PowerConnector), +} + +impl Messages { + /// Read message from CAN frame + #[inline(never)] + pub fn from_can_message(id: Id, payload: &[u8]) -> Result { + let res = match id { + PowerInput::MESSAGE_ID => Messages::PowerInput(PowerInput::try_from(payload)?), + PowerOutput::MESSAGE_ID => Messages::PowerOutput(PowerOutput::try_from(payload)?), + Temperature::MESSAGE_ID => Messages::Temperature(Temperature::try_from(payload)?), + AuxillaryPowerSupply::MESSAGE_ID => { + Messages::AuxillaryPowerSupply(AuxillaryPowerSupply::try_from(payload)?) + } + Limits::MESSAGE_ID => Messages::Limits(Limits::try_from(payload)?), + Status::MESSAGE_ID => Messages::Status(Status::try_from(payload)?), + PowerConnector::MESSAGE_ID => { + Messages::PowerConnector(PowerConnector::try_from(payload)?) + } + id => return Err(CanError::UnknownMessageId(id)), + }; + Ok(res) + } +} + +/// PowerInput +/// +/// - Standard ID: 1536 (0x600) +/// - Size: 8 bytes +/// - Transmitter: ElmarSolarMPPT +#[derive(Clone, Copy)] +pub struct PowerInput { + raw: [u8; 8], +} + +impl PowerInput { + pub const MESSAGE_ID: embedded_can::Id = + Id::Standard(unsafe { StandardId::new_unchecked(0x600) }); + + pub const INPUT_VOLTAGE_MIN: i32 = 0_i32; + pub const INPUT_VOLTAGE_MAX: i32 = 0_i32; + pub const INPUT_CURRENT_MIN: i32 = 0_i32; + pub const INPUT_CURRENT_MAX: i32 = 0_i32; + + /// Construct new PowerInput from values + pub fn new(input_voltage: i32, input_current: i32) -> Result { + let mut res = Self { raw: [0u8; 8] }; + res.set_input_voltage(input_voltage)?; + res.set_input_current(input_current)?; + Ok(res) + } + + /// Access message payload raw value + pub fn raw(&self) -> &[u8; 8] { + &self.raw + } + + /// InputVoltage + /// + /// Input Voltage on the MPPT + /// + /// - Min: 0 + /// - Max: 0 + /// - Unit: "V" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn input_voltage(&self) -> i32 { + self.input_voltage_raw() + } + + /// Get raw value of InputVoltage + /// + /// - Start bit: 0 + /// - Signal size: 32 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Signed + #[inline(always)] + pub fn input_voltage_raw(&self) -> i32 { + let signal = self.raw.view_bits::()[0..32].load_le::(); + + let factor = 1; + let signal = signal as i32; + i32::from(signal).saturating_mul(factor).saturating_add(0) + } + + /// Set value of InputVoltage + #[inline(always)] + pub fn set_input_voltage(&mut self, value: i32) -> Result<(), CanError> { + let factor = 1; + let value = value.checked_sub(0).ok_or(CanError::ParameterOutOfRange { + message_id: PowerInput::MESSAGE_ID, + })?; + let value = (value / factor) as i32; + + let value = u32::from_ne_bytes(value.to_ne_bytes()); + self.raw.view_bits_mut::()[0..32].store_le(value); + Ok(()) + } + + /// InputCurrent + /// + /// Input Current on the MPPT + /// + /// - Min: 0 + /// - Max: 0 + /// - Unit: "A" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn input_current(&self) -> i32 { + self.input_current_raw() + } + + /// Get raw value of InputCurrent + /// + /// - Start bit: 32 + /// - Signal size: 32 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Signed + #[inline(always)] + pub fn input_current_raw(&self) -> i32 { + let signal = self.raw.view_bits::()[32..64].load_le::(); + + let factor = 1; + let signal = signal as i32; + i32::from(signal).saturating_mul(factor).saturating_add(0) + } + + /// Set value of InputCurrent + #[inline(always)] + pub fn set_input_current(&mut self, value: i32) -> Result<(), CanError> { + let factor = 1; + let value = value.checked_sub(0).ok_or(CanError::ParameterOutOfRange { + message_id: PowerInput::MESSAGE_ID, + })?; + let value = (value / factor) as i32; + + 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 PowerInput { + 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 PowerInput { + 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 PowerInput { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + if f.alternate() { + f.debug_struct("PowerInput") + .field("input_voltage", &self.input_voltage()) + .field("input_current", &self.input_current()) + .finish() + } else { + f.debug_tuple("PowerInput").field(&self.raw).finish() + } + } +} + +impl defmt::Format for PowerInput { + fn format(&self, f: defmt::Formatter) { + defmt::write!( + f, + "PowerInput {{ InputVoltage={:?} InputCurrent={:?} }}", + self.input_voltage(), + self.input_current(), + ); + } +} + +#[cfg(feature = "arb")] +impl<'a> Arbitrary<'a> for PowerInput { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + let input_voltage = u.int_in_range(0..=0)?; + let input_current = u.int_in_range(0..=0)?; + PowerInput::new(input_voltage, input_current).map_err(|_| arbitrary::Error::IncorrectFormat) + } +} + +/// PowerOutput +/// +/// - Standard ID: 1537 (0x601) +/// - Size: 8 bytes +/// - Transmitter: ElmarSolarMPPT +#[derive(Clone, Copy)] +pub struct PowerOutput { + raw: [u8; 8], +} + +impl PowerOutput { + pub const MESSAGE_ID: embedded_can::Id = + Id::Standard(unsafe { StandardId::new_unchecked(0x601) }); + + pub const OUTPUT_VOLTAGE_MIN: i32 = 0_i32; + pub const OUTPUT_VOLTAGE_MAX: i32 = 0_i32; + pub const OUTPUT_CURRENT_MIN: i32 = 0_i32; + pub const OUTPUT_CURRENT_MAX: i32 = 0_i32; + + /// Construct new PowerOutput from values + pub fn new(output_voltage: i32, output_current: i32) -> Result { + let mut res = Self { raw: [0u8; 8] }; + res.set_output_voltage(output_voltage)?; + res.set_output_current(output_current)?; + Ok(res) + } + + /// Access message payload raw value + pub fn raw(&self) -> &[u8; 8] { + &self.raw + } + + /// OutputVoltage + /// + /// Output Voltage from the MPPT + /// + /// - Min: 0 + /// - Max: 0 + /// - Unit: "V" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn output_voltage(&self) -> i32 { + self.output_voltage_raw() + } + + /// Get raw value of OutputVoltage + /// + /// - Start bit: 0 + /// - Signal size: 32 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Signed + #[inline(always)] + pub fn output_voltage_raw(&self) -> i32 { + let signal = self.raw.view_bits::()[0..32].load_le::(); + + let factor = 1; + let signal = signal as i32; + i32::from(signal).saturating_mul(factor).saturating_add(0) + } + + /// Set value of OutputVoltage + #[inline(always)] + pub fn set_output_voltage(&mut self, value: i32) -> Result<(), CanError> { + let factor = 1; + let value = value.checked_sub(0).ok_or(CanError::ParameterOutOfRange { + message_id: PowerOutput::MESSAGE_ID, + })?; + let value = (value / factor) as i32; + + let value = u32::from_ne_bytes(value.to_ne_bytes()); + self.raw.view_bits_mut::()[0..32].store_le(value); + Ok(()) + } + + /// OutputCurrent + /// + /// Output Current from the MPPT + /// + /// - Min: 0 + /// - Max: 0 + /// - Unit: "A" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn output_current(&self) -> i32 { + self.output_current_raw() + } + + /// Get raw value of OutputCurrent + /// + /// - Start bit: 32 + /// - Signal size: 32 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Signed + #[inline(always)] + pub fn output_current_raw(&self) -> i32 { + let signal = self.raw.view_bits::()[32..64].load_le::(); + + let factor = 1; + let signal = signal as i32; + i32::from(signal).saturating_mul(factor).saturating_add(0) + } + + /// Set value of OutputCurrent + #[inline(always)] + pub fn set_output_current(&mut self, value: i32) -> Result<(), CanError> { + let factor = 1; + let value = value.checked_sub(0).ok_or(CanError::ParameterOutOfRange { + message_id: PowerOutput::MESSAGE_ID, + })?; + let value = (value / factor) as i32; + + 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 PowerOutput { + 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 PowerOutput { + 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 PowerOutput { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + if f.alternate() { + f.debug_struct("PowerOutput") + .field("output_voltage", &self.output_voltage()) + .field("output_current", &self.output_current()) + .finish() + } else { + f.debug_tuple("PowerOutput").field(&self.raw).finish() + } + } +} + +impl defmt::Format for PowerOutput { + fn format(&self, f: defmt::Formatter) { + defmt::write!( + f, + "PowerOutput {{ OutputVoltage={:?} OutputCurrent={:?} }}", + self.output_voltage(), + self.output_current(), + ); + } +} + +#[cfg(feature = "arb")] +impl<'a> Arbitrary<'a> for PowerOutput { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + let output_voltage = u.int_in_range(0..=0)?; + let output_current = u.int_in_range(0..=0)?; + PowerOutput::new(output_voltage, output_current) + .map_err(|_| arbitrary::Error::IncorrectFormat) + } +} + +/// Temperature +/// +/// - Standard ID: 1538 (0x602) +/// - Size: 8 bytes +/// - Transmitter: ElmarSolarMPPT +#[derive(Clone, Copy)] +pub struct Temperature { + raw: [u8; 8], +} + +impl Temperature { + pub const MESSAGE_ID: embedded_can::Id = + Id::Standard(unsafe { StandardId::new_unchecked(0x602) }); + + pub const MOSFET_TEMPERATURE_MIN: i32 = 0_i32; + pub const MOSFET_TEMPERATURE_MAX: i32 = 0_i32; + pub const CONTROLLER_TEMPERATURE_MIN: i32 = 0_i32; + pub const CONTROLLER_TEMPERATURE_MAX: i32 = 0_i32; + + /// Construct new Temperature from values + pub fn new(mosfet_temperature: i32, controller_temperature: i32) -> Result { + let mut res = Self { raw: [0u8; 8] }; + res.set_mosfet_temperature(mosfet_temperature)?; + res.set_controller_temperature(controller_temperature)?; + Ok(res) + } + + /// Access message payload raw value + pub fn raw(&self) -> &[u8; 8] { + &self.raw + } + + /// MosfetTemperature + /// + /// Temperature as measured at the Mosfet + /// + /// - Min: 0 + /// - Max: 0 + /// - Unit: "C" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn mosfet_temperature(&self) -> i32 { + self.mosfet_temperature_raw() + } + + /// Get raw value of MosfetTemperature + /// + /// - Start bit: 0 + /// - Signal size: 32 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Signed + #[inline(always)] + pub fn mosfet_temperature_raw(&self) -> i32 { + let signal = self.raw.view_bits::()[0..32].load_le::(); + + let factor = 1; + let signal = signal as i32; + i32::from(signal).saturating_mul(factor).saturating_add(0) + } + + /// Set value of MosfetTemperature + #[inline(always)] + pub fn set_mosfet_temperature(&mut self, value: i32) -> Result<(), CanError> { + let factor = 1; + let value = value.checked_sub(0).ok_or(CanError::ParameterOutOfRange { + message_id: Temperature::MESSAGE_ID, + })?; + let value = (value / factor) as i32; + + let value = u32::from_ne_bytes(value.to_ne_bytes()); + self.raw.view_bits_mut::()[0..32].store_le(value); + Ok(()) + } + + /// ControllerTemperature + /// + /// Temperature as measured at the controller + /// + /// - Min: 0 + /// - Max: 0 + /// - Unit: "C" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn controller_temperature(&self) -> i32 { + self.controller_temperature_raw() + } + + /// Get raw value of ControllerTemperature + /// + /// - Start bit: 32 + /// - Signal size: 32 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Signed + #[inline(always)] + pub fn controller_temperature_raw(&self) -> i32 { + let signal = self.raw.view_bits::()[32..64].load_le::(); + + let factor = 1; + let signal = signal as i32; + i32::from(signal).saturating_mul(factor).saturating_add(0) + } + + /// Set value of ControllerTemperature + #[inline(always)] + pub fn set_controller_temperature(&mut self, value: i32) -> Result<(), CanError> { + let factor = 1; + let value = value.checked_sub(0).ok_or(CanError::ParameterOutOfRange { + message_id: Temperature::MESSAGE_ID, + })?; + let value = (value / factor) as i32; + + 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 Temperature { + 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 Temperature { + 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 Temperature { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + if f.alternate() { + f.debug_struct("Temperature") + .field("mosfet_temperature", &self.mosfet_temperature()) + .field("controller_temperature", &self.controller_temperature()) + .finish() + } else { + f.debug_tuple("Temperature").field(&self.raw).finish() + } + } +} + +impl defmt::Format for Temperature { + fn format(&self, f: defmt::Formatter) { + defmt::write!( + f, + "Temperature {{ MosfetTemperature={:?} ControllerTemperature={:?} }}", + self.mosfet_temperature(), + self.controller_temperature(), + ); + } +} + +#[cfg(feature = "arb")] +impl<'a> Arbitrary<'a> for Temperature { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + let mosfet_temperature = u.int_in_range(0..=0)?; + let controller_temperature = u.int_in_range(0..=0)?; + Temperature::new(mosfet_temperature, controller_temperature) + .map_err(|_| arbitrary::Error::IncorrectFormat) + } +} + +/// AuxillaryPowerSupply +/// +/// - Standard ID: 1539 (0x603) +/// - Size: 8 bytes +/// - Transmitter: ElmarSolarMPPT +#[derive(Clone, Copy)] +pub struct AuxillaryPowerSupply { + raw: [u8; 8], +} + +impl AuxillaryPowerSupply { + pub const MESSAGE_ID: embedded_can::Id = + Id::Standard(unsafe { StandardId::new_unchecked(0x603) }); + + pub const TWELVE_VOLT_MIN: i32 = 0_i32; + pub const TWELVE_VOLT_MAX: i32 = 0_i32; + pub const THREE_VOLT_MIN: i32 = 0_i32; + pub const THREE_VOLT_MAX: i32 = 0_i32; + + /// Construct new AuxillaryPowerSupply from values + pub fn new(twelve_volt: i32, three_volt: i32) -> Result { + let mut res = Self { raw: [0u8; 8] }; + res.set_twelve_volt(twelve_volt)?; + res.set_three_volt(three_volt)?; + Ok(res) + } + + /// Access message payload raw value + pub fn raw(&self) -> &[u8; 8] { + &self.raw + } + + /// TwelveVolt + /// + /// Voltage as measured at the 12v power auxillary supply + /// + /// - Min: 0 + /// - Max: 0 + /// - Unit: "V" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn twelve_volt(&self) -> i32 { + self.twelve_volt_raw() + } + + /// Get raw value of TwelveVolt + /// + /// - Start bit: 0 + /// - Signal size: 32 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Signed + #[inline(always)] + pub fn twelve_volt_raw(&self) -> i32 { + let signal = self.raw.view_bits::()[0..32].load_le::(); + + let factor = 1; + let signal = signal as i32; + i32::from(signal).saturating_mul(factor).saturating_add(0) + } + + /// Set value of TwelveVolt + #[inline(always)] + pub fn set_twelve_volt(&mut self, value: i32) -> Result<(), CanError> { + let factor = 1; + let value = value.checked_sub(0).ok_or(CanError::ParameterOutOfRange { + message_id: AuxillaryPowerSupply::MESSAGE_ID, + })?; + let value = (value / factor) as i32; + + let value = u32::from_ne_bytes(value.to_ne_bytes()); + self.raw.view_bits_mut::()[0..32].store_le(value); + Ok(()) + } + + /// ThreeVolt + /// + /// Voltage as measured at the 3v power supply + /// + /// - Min: 0 + /// - Max: 0 + /// - Unit: "V" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn three_volt(&self) -> i32 { + self.three_volt_raw() + } + + /// Get raw value of ThreeVolt + /// + /// - Start bit: 32 + /// - Signal size: 32 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Signed + #[inline(always)] + pub fn three_volt_raw(&self) -> i32 { + let signal = self.raw.view_bits::()[32..64].load_le::(); + + let factor = 1; + let signal = signal as i32; + i32::from(signal).saturating_mul(factor).saturating_add(0) + } + + /// Set value of ThreeVolt + #[inline(always)] + pub fn set_three_volt(&mut self, value: i32) -> Result<(), CanError> { + let factor = 1; + let value = value.checked_sub(0).ok_or(CanError::ParameterOutOfRange { + message_id: AuxillaryPowerSupply::MESSAGE_ID, + })?; + let value = (value / factor) as i32; + + 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 AuxillaryPowerSupply { + 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 AuxillaryPowerSupply { + 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 AuxillaryPowerSupply { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + if f.alternate() { + f.debug_struct("AuxillaryPowerSupply") + .field("twelve_volt", &self.twelve_volt()) + .field("three_volt", &self.three_volt()) + .finish() + } else { + f.debug_tuple("AuxillaryPowerSupply") + .field(&self.raw) + .finish() + } + } +} + +impl defmt::Format for AuxillaryPowerSupply { + fn format(&self, f: defmt::Formatter) { + defmt::write!( + f, + "AuxillaryPowerSupply {{ TwelveVolt={:?} ThreeVolt={:?} }}", + self.twelve_volt(), + self.three_volt(), + ); + } +} + +#[cfg(feature = "arb")] +impl<'a> Arbitrary<'a> for AuxillaryPowerSupply { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + let twelve_volt = u.int_in_range(0..=0)?; + let three_volt = u.int_in_range(0..=0)?; + AuxillaryPowerSupply::new(twelve_volt, three_volt) + .map_err(|_| arbitrary::Error::IncorrectFormat) + } +} + +/// Limits +/// +/// - Standard ID: 1540 (0x604) +/// - Size: 8 bytes +/// - Transmitter: ElmarSolarMPPT +#[derive(Clone, Copy)] +pub struct Limits { + raw: [u8; 8], +} + +impl Limits { + pub const MESSAGE_ID: embedded_can::Id = + Id::Standard(unsafe { StandardId::new_unchecked(0x604) }); + + pub const MAX_OUTPUT_VOLTAGE_MIN: i32 = 0_i32; + pub const MAX_OUTPUT_VOLTAGE_MAX: i32 = 0_i32; + pub const MAX_INPUT_CURRENT_MIN: i32 = 0_i32; + pub const MAX_INPUT_CURRENT_MAX: i32 = 0_i32; + + /// Construct new Limits from values + pub fn new(max_output_voltage: i32, max_input_current: i32) -> Result { + let mut res = Self { raw: [0u8; 8] }; + res.set_max_output_voltage(max_output_voltage)?; + res.set_max_input_current(max_input_current)?; + Ok(res) + } + + /// Access message payload raw value + pub fn raw(&self) -> &[u8; 8] { + &self.raw + } + + /// MaxOutputVoltage + /// + /// Maximim Output voltage configured for the device + /// + /// - Min: 0 + /// - Max: 0 + /// - Unit: "V" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn max_output_voltage(&self) -> i32 { + self.max_output_voltage_raw() + } + + /// Get raw value of MaxOutputVoltage + /// + /// - Start bit: 0 + /// - Signal size: 32 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Signed + #[inline(always)] + pub fn max_output_voltage_raw(&self) -> i32 { + let signal = self.raw.view_bits::()[0..32].load_le::(); + + let factor = 1; + let signal = signal as i32; + i32::from(signal).saturating_mul(factor).saturating_add(0) + } + + /// Set value of MaxOutputVoltage + #[inline(always)] + pub fn set_max_output_voltage(&mut self, value: i32) -> Result<(), CanError> { + let factor = 1; + let value = value.checked_sub(0).ok_or(CanError::ParameterOutOfRange { + message_id: Limits::MESSAGE_ID, + })?; + let value = (value / factor) as i32; + + let value = u32::from_ne_bytes(value.to_ne_bytes()); + self.raw.view_bits_mut::()[0..32].store_le(value); + Ok(()) + } + + /// MaxInputCurrent + /// + /// Maximum Input current configured for the device + /// + /// - Min: 0 + /// - Max: 0 + /// - Unit: "A" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn max_input_current(&self) -> i32 { + self.max_input_current_raw() + } + + /// Get raw value of MaxInputCurrent + /// + /// - Start bit: 32 + /// - Signal size: 32 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Signed + #[inline(always)] + pub fn max_input_current_raw(&self) -> i32 { + let signal = self.raw.view_bits::()[32..64].load_le::(); + + let factor = 1; + let signal = signal as i32; + i32::from(signal).saturating_mul(factor).saturating_add(0) + } + + /// Set value of MaxInputCurrent + #[inline(always)] + pub fn set_max_input_current(&mut self, value: i32) -> Result<(), CanError> { + let factor = 1; + let value = value.checked_sub(0).ok_or(CanError::ParameterOutOfRange { + message_id: Limits::MESSAGE_ID, + })?; + let value = (value / factor) as i32; + + 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 Limits { + 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 Limits { + 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 Limits { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + if f.alternate() { + f.debug_struct("Limits") + .field("max_output_voltage", &self.max_output_voltage()) + .field("max_input_current", &self.max_input_current()) + .finish() + } else { + f.debug_tuple("Limits").field(&self.raw).finish() + } + } +} + +impl defmt::Format for Limits { + fn format(&self, f: defmt::Formatter) { + defmt::write!( + f, + "Limits {{ MaxOutputVoltage={:?} MaxInputCurrent={:?} }}", + self.max_output_voltage(), + self.max_input_current(), + ); + } +} + +#[cfg(feature = "arb")] +impl<'a> Arbitrary<'a> for Limits { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + let max_output_voltage = u.int_in_range(0..=0)?; + let max_input_current = u.int_in_range(0..=0)?; + Limits::new(max_output_voltage, max_input_current) + .map_err(|_| arbitrary::Error::IncorrectFormat) + } +} + +/// Status +/// +/// - Standard ID: 1541 (0x605) +/// - Size: 8 bytes +/// - Transmitter: ElmarSolarMPPT +#[derive(Clone, Copy)] +pub struct Status { + raw: [u8; 8], +} + +impl Status { + pub const MESSAGE_ID: embedded_can::Id = + Id::Standard(unsafe { StandardId::new_unchecked(0x605) }); + + pub const CAN_RX_ERROR_COUNTER_MIN: u8 = 0_u8; + pub const CAN_RX_ERROR_COUNTER_MAX: u8 = 0_u8; + pub const CAN_TX_ERROR_COUNTER_MIN: u8 = 0_u8; + pub const CAN_TX_ERROR_COUNTER_MAX: u8 = 0_u8; + pub const CAN_TX_OVERFLOW_COUNTER_MIN: u8 = 0_u8; + pub const CAN_TX_OVERFLOW_COUNTER_MAX: u8 = 0_u8; + pub const MODE_MIN: u8 = 0_u8; + pub const MODE_MAX: u8 = 1_u8; + pub const RESERVED_MIN: u8 = 0_u8; + pub const RESERVED_MAX: u8 = 0_u8; + pub const TEST_COUNTER_MIN: u8 = 0_u8; + pub const TEST_COUNTER_MAX: u8 = 0_u8; + + /// Construct new Status from values + pub fn new( + error_reserved: bool, + error_mosfet_overheat: bool, + error_low_arrow_power: bool, + error_hw_over_voltage: bool, + error_hw_over_current: bool, + error_battery_low: bool, + error_battery_full: bool, + error12v_undervoltage: bool, + limit_output_voltage_max: bool, + limit_mosfet_temperature: bool, + limit_local_mppt: bool, + limit_input_current_min: bool, + limit_input_current_max: bool, + limit_global_mppt: bool, + limit_duty_cycle_max: bool, + limit_dury_cycle_min: bool, + can_rx_error_counter: u8, + can_tx_error_counter: u8, + can_tx_overflow_counter: u8, + mode: u8, + reserved: u8, + test_counter: u8, + ) -> Result { + let mut res = Self { raw: [0u8; 8] }; + res.set_error_reserved(error_reserved)?; + res.set_error_mosfet_overheat(error_mosfet_overheat)?; + res.set_error_low_arrow_power(error_low_arrow_power)?; + res.set_error_hw_over_voltage(error_hw_over_voltage)?; + res.set_error_hw_over_current(error_hw_over_current)?; + res.set_error_battery_low(error_battery_low)?; + res.set_error_battery_full(error_battery_full)?; + res.set_error12v_undervoltage(error12v_undervoltage)?; + res.set_limit_output_voltage_max(limit_output_voltage_max)?; + res.set_limit_mosfet_temperature(limit_mosfet_temperature)?; + res.set_limit_local_mppt(limit_local_mppt)?; + res.set_limit_input_current_min(limit_input_current_min)?; + res.set_limit_input_current_max(limit_input_current_max)?; + res.set_limit_global_mppt(limit_global_mppt)?; + res.set_limit_duty_cycle_max(limit_duty_cycle_max)?; + res.set_limit_dury_cycle_min(limit_dury_cycle_min)?; + res.set_can_rx_error_counter(can_rx_error_counter)?; + res.set_can_tx_error_counter(can_tx_error_counter)?; + res.set_can_tx_overflow_counter(can_tx_overflow_counter)?; + res.set_mode(mode)?; + res.set_reserved(reserved)?; + res.set_test_counter(test_counter)?; + Ok(res) + } + + /// Access message payload raw value + pub fn raw(&self) -> &[u8; 8] { + &self.raw + } + + /// ErrorReserved + /// + /// - Min: 0 + /// - Max: 1 + /// - Unit: "On / Off" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn error_reserved(&self) -> bool { + self.error_reserved_raw() + } + + /// Get raw value of ErrorReserved + /// + /// - Start bit: 29 + /// - Signal size: 1 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Unsigned + #[inline(always)] + pub fn error_reserved_raw(&self) -> bool { + let signal = self.raw.view_bits::()[29..30].load_le::(); + + signal == 1 + } + + /// Set value of ErrorReserved + #[inline(always)] + pub fn set_error_reserved(&mut self, value: bool) -> Result<(), CanError> { + let value = value as u8; + self.raw.view_bits_mut::()[29..30].store_le(value); + Ok(()) + } + + /// ErrorMosfetOverheat + /// + /// - Min: 0 + /// - Max: 1 + /// - Unit: "On / Off" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn error_mosfet_overheat(&self) -> bool { + self.error_mosfet_overheat_raw() + } + + /// Get raw value of ErrorMosfetOverheat + /// + /// - Start bit: 25 + /// - Signal size: 1 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Unsigned + #[inline(always)] + pub fn error_mosfet_overheat_raw(&self) -> bool { + let signal = self.raw.view_bits::()[25..26].load_le::(); + + signal == 1 + } + + /// Set value of ErrorMosfetOverheat + #[inline(always)] + pub fn set_error_mosfet_overheat(&mut self, value: bool) -> Result<(), CanError> { + let value = value as u8; + self.raw.view_bits_mut::()[25..26].store_le(value); + Ok(()) + } + + /// ErrorLowArrowPower + /// + /// - Min: 0 + /// - Max: 1 + /// - Unit: "On / Off" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn error_low_arrow_power(&self) -> bool { + self.error_low_arrow_power_raw() + } + + /// Get raw value of ErrorLowArrowPower + /// + /// - Start bit: 24 + /// - Signal size: 1 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Unsigned + #[inline(always)] + pub fn error_low_arrow_power_raw(&self) -> bool { + let signal = self.raw.view_bits::()[24..25].load_le::(); + + signal == 1 + } + + /// Set value of ErrorLowArrowPower + #[inline(always)] + pub fn set_error_low_arrow_power(&mut self, value: bool) -> Result<(), CanError> { + let value = value as u8; + self.raw.view_bits_mut::()[24..25].store_le(value); + Ok(()) + } + + /// ErrorHwOverVoltage + /// + /// - Min: 0 + /// - Max: 1 + /// - Unit: "On / Off" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn error_hw_over_voltage(&self) -> bool { + self.error_hw_over_voltage_raw() + } + + /// Get raw value of ErrorHwOverVoltage + /// + /// - Start bit: 31 + /// - Signal size: 1 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Unsigned + #[inline(always)] + pub fn error_hw_over_voltage_raw(&self) -> bool { + let signal = self.raw.view_bits::()[31..32].load_le::(); + + signal == 1 + } + + /// Set value of ErrorHwOverVoltage + #[inline(always)] + pub fn set_error_hw_over_voltage(&mut self, value: bool) -> Result<(), CanError> { + let value = value as u8; + self.raw.view_bits_mut::()[31..32].store_le(value); + Ok(()) + } + + /// ErrorHwOverCurrent + /// + /// - Min: 0 + /// - Max: 1 + /// - Unit: "On / Off" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn error_hw_over_current(&self) -> bool { + self.error_hw_over_current_raw() + } + + /// Get raw value of ErrorHwOverCurrent + /// + /// - Start bit: 30 + /// - Signal size: 1 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Unsigned + #[inline(always)] + pub fn error_hw_over_current_raw(&self) -> bool { + let signal = self.raw.view_bits::()[30..31].load_le::(); + + signal == 1 + } + + /// Set value of ErrorHwOverCurrent + #[inline(always)] + pub fn set_error_hw_over_current(&mut self, value: bool) -> Result<(), CanError> { + let value = value as u8; + self.raw.view_bits_mut::()[30..31].store_le(value); + Ok(()) + } + + /// ErrorBatteryLow + /// + /// - Min: 0 + /// - Max: 1 + /// - Unit: "On / Off" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn error_battery_low(&self) -> bool { + self.error_battery_low_raw() + } + + /// Get raw value of ErrorBatteryLow + /// + /// - Start bit: 26 + /// - Signal size: 1 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Unsigned + #[inline(always)] + pub fn error_battery_low_raw(&self) -> bool { + let signal = self.raw.view_bits::()[26..27].load_le::(); + + signal == 1 + } + + /// Set value of ErrorBatteryLow + #[inline(always)] + pub fn set_error_battery_low(&mut self, value: bool) -> Result<(), CanError> { + let value = value as u8; + self.raw.view_bits_mut::()[26..27].store_le(value); + Ok(()) + } + + /// ErrorBatteryFull + /// + /// - Min: 0 + /// - Max: 1 + /// - Unit: "On / Off" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn error_battery_full(&self) -> bool { + self.error_battery_full_raw() + } + + /// Get raw value of ErrorBatteryFull + /// + /// - Start bit: 27 + /// - Signal size: 1 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Unsigned + #[inline(always)] + pub fn error_battery_full_raw(&self) -> bool { + let signal = self.raw.view_bits::()[27..28].load_le::(); + + signal == 1 + } + + /// Set value of ErrorBatteryFull + #[inline(always)] + pub fn set_error_battery_full(&mut self, value: bool) -> Result<(), CanError> { + let value = value as u8; + self.raw.view_bits_mut::()[27..28].store_le(value); + Ok(()) + } + + /// Error12vUndervoltage + /// + /// - Min: 0 + /// - Max: 1 + /// - Unit: "On / Off" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn error12v_undervoltage(&self) -> bool { + self.error12v_undervoltage_raw() + } + + /// Get raw value of Error12vUndervoltage + /// + /// - Start bit: 28 + /// - Signal size: 1 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Unsigned + #[inline(always)] + pub fn error12v_undervoltage_raw(&self) -> bool { + let signal = self.raw.view_bits::()[28..29].load_le::(); + + signal == 1 + } + + /// Set value of Error12vUndervoltage + #[inline(always)] + pub fn set_error12v_undervoltage(&mut self, value: bool) -> Result<(), CanError> { + let value = value as u8; + self.raw.view_bits_mut::()[28..29].store_le(value); + Ok(()) + } + + /// LimitOutputVoltageMax + /// + /// - Min: 0 + /// - Max: 1 + /// - Unit: "On / Off" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn limit_output_voltage_max(&self) -> bool { + self.limit_output_voltage_max_raw() + } + + /// Get raw value of LimitOutputVoltageMax + /// + /// - Start bit: 34 + /// - Signal size: 1 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Unsigned + #[inline(always)] + pub fn limit_output_voltage_max_raw(&self) -> bool { + let signal = self.raw.view_bits::()[34..35].load_le::(); + + signal == 1 + } + + /// Set value of LimitOutputVoltageMax + #[inline(always)] + pub fn set_limit_output_voltage_max(&mut self, value: bool) -> Result<(), CanError> { + let value = value as u8; + self.raw.view_bits_mut::()[34..35].store_le(value); + Ok(()) + } + + /// LimitMosfetTemperature + /// + /// - Min: 0 + /// - Max: 1 + /// - Unit: "On / Off" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn limit_mosfet_temperature(&self) -> bool { + self.limit_mosfet_temperature_raw() + } + + /// Get raw value of LimitMosfetTemperature + /// + /// - Start bit: 35 + /// - Signal size: 1 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Unsigned + #[inline(always)] + pub fn limit_mosfet_temperature_raw(&self) -> bool { + let signal = self.raw.view_bits::()[35..36].load_le::(); + + signal == 1 + } + + /// Set value of LimitMosfetTemperature + #[inline(always)] + pub fn set_limit_mosfet_temperature(&mut self, value: bool) -> Result<(), CanError> { + let value = value as u8; + self.raw.view_bits_mut::()[35..36].store_le(value); + Ok(()) + } + + /// LimitLocalMPPT + /// + /// - Min: 0 + /// - Max: 1 + /// - Unit: "On / Off" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn limit_local_mppt(&self) -> bool { + self.limit_local_mppt_raw() + } + + /// Get raw value of LimitLocalMPPT + /// + /// - Start bit: 38 + /// - Signal size: 1 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Unsigned + #[inline(always)] + pub fn limit_local_mppt_raw(&self) -> bool { + let signal = self.raw.view_bits::()[38..39].load_le::(); + + signal == 1 + } + + /// Set value of LimitLocalMPPT + #[inline(always)] + pub fn set_limit_local_mppt(&mut self, value: bool) -> Result<(), CanError> { + let value = value as u8; + self.raw.view_bits_mut::()[38..39].store_le(value); + Ok(()) + } + + /// LimitInputCurrentMin + /// + /// - Min: 0 + /// - Max: 1 + /// - Unit: "On / Off" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn limit_input_current_min(&self) -> bool { + self.limit_input_current_min_raw() + } + + /// Get raw value of LimitInputCurrentMin + /// + /// - Start bit: 32 + /// - Signal size: 1 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Unsigned + #[inline(always)] + pub fn limit_input_current_min_raw(&self) -> bool { + let signal = self.raw.view_bits::()[32..33].load_le::(); + + signal == 1 + } + + /// Set value of LimitInputCurrentMin + #[inline(always)] + pub fn set_limit_input_current_min(&mut self, value: bool) -> Result<(), CanError> { + let value = value as u8; + self.raw.view_bits_mut::()[32..33].store_le(value); + Ok(()) + } + + /// LimitInputCurrentMax + /// + /// - Min: 0 + /// - Max: 1 + /// - Unit: "On / Off" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn limit_input_current_max(&self) -> bool { + self.limit_input_current_max_raw() + } + + /// Get raw value of LimitInputCurrentMax + /// + /// - Start bit: 33 + /// - Signal size: 1 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Unsigned + #[inline(always)] + pub fn limit_input_current_max_raw(&self) -> bool { + let signal = self.raw.view_bits::()[33..34].load_le::(); + + signal == 1 + } + + /// Set value of LimitInputCurrentMax + #[inline(always)] + pub fn set_limit_input_current_max(&mut self, value: bool) -> Result<(), CanError> { + let value = value as u8; + self.raw.view_bits_mut::()[33..34].store_le(value); + Ok(()) + } + + /// LimitGlobalMPPT + /// + /// - Min: 0 + /// - Max: 1 + /// - Unit: "On / Off" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn limit_global_mppt(&self) -> bool { + self.limit_global_mppt_raw() + } + + /// Get raw value of LimitGlobalMPPT + /// + /// - Start bit: 39 + /// - Signal size: 1 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Unsigned + #[inline(always)] + pub fn limit_global_mppt_raw(&self) -> bool { + let signal = self.raw.view_bits::()[39..40].load_le::(); + + signal == 1 + } + + /// Set value of LimitGlobalMPPT + #[inline(always)] + pub fn set_limit_global_mppt(&mut self, value: bool) -> Result<(), CanError> { + let value = value as u8; + self.raw.view_bits_mut::()[39..40].store_le(value); + Ok(()) + } + + /// LimitDutyCycleMax + /// + /// - Min: 0 + /// - Max: 1 + /// - Unit: "On / Off" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn limit_duty_cycle_max(&self) -> bool { + self.limit_duty_cycle_max_raw() + } + + /// Get raw value of LimitDutyCycleMax + /// + /// - Start bit: 37 + /// - Signal size: 1 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Unsigned + #[inline(always)] + pub fn limit_duty_cycle_max_raw(&self) -> bool { + let signal = self.raw.view_bits::()[37..38].load_le::(); + + signal == 1 + } + + /// Set value of LimitDutyCycleMax + #[inline(always)] + pub fn set_limit_duty_cycle_max(&mut self, value: bool) -> Result<(), CanError> { + let value = value as u8; + self.raw.view_bits_mut::()[37..38].store_le(value); + Ok(()) + } + + /// LimitDuryCycleMin + /// + /// - Min: 0 + /// - Max: 1 + /// - Unit: "On / Off" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn limit_dury_cycle_min(&self) -> bool { + self.limit_dury_cycle_min_raw() + } + + /// Get raw value of LimitDuryCycleMin + /// + /// - Start bit: 36 + /// - Signal size: 1 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Unsigned + #[inline(always)] + pub fn limit_dury_cycle_min_raw(&self) -> bool { + let signal = self.raw.view_bits::()[36..37].load_le::(); + + signal == 1 + } + + /// Set value of LimitDuryCycleMin + #[inline(always)] + pub fn set_limit_dury_cycle_min(&mut self, value: bool) -> Result<(), CanError> { + let value = value as u8; + self.raw.view_bits_mut::()[36..37].store_le(value); + Ok(()) + } + + /// CanRXErrorCounter + /// + /// - Min: 0 + /// - Max: 0 + /// - Unit: "" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn can_rx_error_counter(&self) -> u8 { + self.can_rx_error_counter_raw() + } + + /// Get raw value of CanRXErrorCounter + /// + /// - Start bit: 0 + /// - Signal size: 8 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Unsigned + #[inline(always)] + pub fn can_rx_error_counter_raw(&self) -> u8 { + let signal = self.raw.view_bits::()[0..8].load_le::(); + + let factor = 1; + u8::from(signal).saturating_mul(factor).saturating_add(0) + } + + /// Set value of CanRXErrorCounter + #[inline(always)] + pub fn set_can_rx_error_counter(&mut self, value: u8) -> Result<(), CanError> { + let factor = 1; + let value = value.checked_sub(0).ok_or(CanError::ParameterOutOfRange { + message_id: Status::MESSAGE_ID, + })?; + let value = (value / factor) as u8; + + self.raw.view_bits_mut::()[0..8].store_le(value); + Ok(()) + } + + /// CanTXErrorCounter + /// + /// - Min: 0 + /// - Max: 0 + /// - Unit: "" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn can_tx_error_counter(&self) -> u8 { + self.can_tx_error_counter_raw() + } + + /// Get raw value of CanTXErrorCounter + /// + /// - Start bit: 8 + /// - Signal size: 8 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Unsigned + #[inline(always)] + pub fn can_tx_error_counter_raw(&self) -> u8 { + let signal = self.raw.view_bits::()[8..16].load_le::(); + + let factor = 1; + u8::from(signal).saturating_mul(factor).saturating_add(0) + } + + /// Set value of CanTXErrorCounter + #[inline(always)] + pub fn set_can_tx_error_counter(&mut self, value: u8) -> Result<(), CanError> { + let factor = 1; + let value = value.checked_sub(0).ok_or(CanError::ParameterOutOfRange { + message_id: Status::MESSAGE_ID, + })?; + let value = (value / factor) as u8; + + self.raw.view_bits_mut::()[8..16].store_le(value); + Ok(()) + } + + /// CanTXOverflowCounter + /// + /// - Min: 0 + /// - Max: 0 + /// - Unit: "" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn can_tx_overflow_counter(&self) -> u8 { + self.can_tx_overflow_counter_raw() + } + + /// Get raw value of CanTXOverflowCounter + /// + /// - Start bit: 16 + /// - Signal size: 8 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Unsigned + #[inline(always)] + pub fn can_tx_overflow_counter_raw(&self) -> u8 { + let signal = self.raw.view_bits::()[16..24].load_le::(); + + let factor = 1; + u8::from(signal).saturating_mul(factor).saturating_add(0) + } + + /// Set value of CanTXOverflowCounter + #[inline(always)] + pub fn set_can_tx_overflow_counter(&mut self, value: u8) -> Result<(), CanError> { + let factor = 1; + let value = value.checked_sub(0).ok_or(CanError::ParameterOutOfRange { + message_id: Status::MESSAGE_ID, + })?; + let value = (value / factor) as u8; + + self.raw.view_bits_mut::()[16..24].store_le(value); + Ok(()) + } + + /// Mode + /// + /// - Min: 0 + /// - Max: 1 + /// - Unit: "" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn mode(&self) -> u8 { + self.mode_raw() + } + + /// Get raw value of Mode + /// + /// - Start bit: 40 + /// - Signal size: 8 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Unsigned + #[inline(always)] + pub fn mode_raw(&self) -> u8 { + let signal = self.raw.view_bits::()[40..48].load_le::(); + + let factor = 1; + u8::from(signal).saturating_mul(factor).saturating_add(0) + } + + /// Set value of Mode + #[inline(always)] + pub fn set_mode(&mut self, value: u8) -> Result<(), CanError> { + let factor = 1; + let value = value.checked_sub(0).ok_or(CanError::ParameterOutOfRange { + message_id: Status::MESSAGE_ID, + })?; + let value = (value / factor) as u8; + + self.raw.view_bits_mut::()[40..48].store_le(value); + Ok(()) + } + + /// Reserved + /// + /// - Min: 0 + /// - Max: 0 + /// - Unit: "" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn reserved(&self) -> u8 { + self.reserved_raw() + } + + /// Get raw value of Reserved + /// + /// - Start bit: 48 + /// - Signal size: 8 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Unsigned + #[inline(always)] + pub fn reserved_raw(&self) -> u8 { + let signal = self.raw.view_bits::()[48..56].load_le::(); + + let factor = 1; + u8::from(signal).saturating_mul(factor).saturating_add(0) + } + + /// Set value of Reserved + #[inline(always)] + pub fn set_reserved(&mut self, value: u8) -> Result<(), CanError> { + let factor = 1; + let value = value.checked_sub(0).ok_or(CanError::ParameterOutOfRange { + message_id: Status::MESSAGE_ID, + })?; + let value = (value / factor) as u8; + + self.raw.view_bits_mut::()[48..56].store_le(value); + Ok(()) + } + + /// TestCounter + /// + /// - Min: 0 + /// - Max: 0 + /// - Unit: "" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn test_counter(&self) -> u8 { + self.test_counter_raw() + } + + /// Get raw value of TestCounter + /// + /// - Start bit: 56 + /// - Signal size: 8 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Unsigned + #[inline(always)] + pub fn test_counter_raw(&self) -> u8 { + let signal = self.raw.view_bits::()[56..64].load_le::(); + + let factor = 1; + u8::from(signal).saturating_mul(factor).saturating_add(0) + } + + /// Set value of TestCounter + #[inline(always)] + pub fn set_test_counter(&mut self, value: u8) -> Result<(), CanError> { + let factor = 1; + let value = value.checked_sub(0).ok_or(CanError::ParameterOutOfRange { + message_id: Status::MESSAGE_ID, + })?; + let value = (value / factor) as u8; + + self.raw.view_bits_mut::()[56..64].store_le(value); + Ok(()) + } +} + +impl core::convert::TryFrom<&[u8]> for Status { + 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 Status { + 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 Status { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + if f.alternate() { + f.debug_struct("Status") + .field("error_reserved", &self.error_reserved()) + .field("error_mosfet_overheat", &self.error_mosfet_overheat()) + .field("error_low_arrow_power", &self.error_low_arrow_power()) + .field("error_hw_over_voltage", &self.error_hw_over_voltage()) + .field("error_hw_over_current", &self.error_hw_over_current()) + .field("error_battery_low", &self.error_battery_low()) + .field("error_battery_full", &self.error_battery_full()) + .field("error12v_undervoltage", &self.error12v_undervoltage()) + .field("limit_output_voltage_max", &self.limit_output_voltage_max()) + .field("limit_mosfet_temperature", &self.limit_mosfet_temperature()) + .field("limit_local_mppt", &self.limit_local_mppt()) + .field("limit_input_current_min", &self.limit_input_current_min()) + .field("limit_input_current_max", &self.limit_input_current_max()) + .field("limit_global_mppt", &self.limit_global_mppt()) + .field("limit_duty_cycle_max", &self.limit_duty_cycle_max()) + .field("limit_dury_cycle_min", &self.limit_dury_cycle_min()) + .field("can_rx_error_counter", &self.can_rx_error_counter()) + .field("can_tx_error_counter", &self.can_tx_error_counter()) + .field("can_tx_overflow_counter", &self.can_tx_overflow_counter()) + .field("mode", &self.mode()) + .field("reserved", &self.reserved()) + .field("test_counter", &self.test_counter()) + .finish() + } else { + f.debug_tuple("Status").field(&self.raw).finish() + } + } +} + +impl defmt::Format for Status { + fn format(&self, f: defmt::Formatter) { + defmt::write!(f, + "Status {{ ErrorReserved={:?} ErrorMosfetOverheat={:?} ErrorLowArrowPower={:?} ErrorHwOverVoltage={:?} ErrorHwOverCurrent={:?} ErrorBatteryLow={:?} ErrorBatteryFull={:?} Error12vUndervoltage={:?} LimitOutputVoltageMax={:?} LimitMosfetTemperature={:?} LimitLocalMPPT={:?} LimitInputCurrentMin={:?} LimitInputCurrentMax={:?} LimitGlobalMPPT={:?} LimitDutyCycleMax={:?} LimitDuryCycleMin={:?} CanRXErrorCounter={:?} CanTXErrorCounter={:?} CanTXOverflowCounter={:?} Mode={:?} Reserved={:?} TestCounter={:?} }}", + self.error_reserved(), + self.error_mosfet_overheat(), + self.error_low_arrow_power(), + self.error_hw_over_voltage(), + self.error_hw_over_current(), + self.error_battery_low(), + self.error_battery_full(), + self.error12v_undervoltage(), + self.limit_output_voltage_max(), + self.limit_mosfet_temperature(), + self.limit_local_mppt(), + self.limit_input_current_min(), + self.limit_input_current_max(), + self.limit_global_mppt(), + self.limit_duty_cycle_max(), + self.limit_dury_cycle_min(), + self.can_rx_error_counter(), + self.can_tx_error_counter(), + self.can_tx_overflow_counter(), + self.mode(), + self.reserved(), + self.test_counter(), + ); + } +} + +#[cfg(feature = "arb")] +impl<'a> Arbitrary<'a> for Status { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + let error_reserved = u.int_in_range(0..=1)? == 1; + let error_mosfet_overheat = u.int_in_range(0..=1)? == 1; + let error_low_arrow_power = u.int_in_range(0..=1)? == 1; + let error_hw_over_voltage = u.int_in_range(0..=1)? == 1; + let error_hw_over_current = u.int_in_range(0..=1)? == 1; + let error_battery_low = u.int_in_range(0..=1)? == 1; + let error_battery_full = u.int_in_range(0..=1)? == 1; + let error12v_undervoltage = u.int_in_range(0..=1)? == 1; + let limit_output_voltage_max = u.int_in_range(0..=1)? == 1; + let limit_mosfet_temperature = u.int_in_range(0..=1)? == 1; + let limit_local_mppt = u.int_in_range(0..=1)? == 1; + let limit_input_current_min = u.int_in_range(0..=1)? == 1; + let limit_input_current_max = u.int_in_range(0..=1)? == 1; + let limit_global_mppt = u.int_in_range(0..=1)? == 1; + let limit_duty_cycle_max = u.int_in_range(0..=1)? == 1; + let limit_dury_cycle_min = u.int_in_range(0..=1)? == 1; + let can_rx_error_counter = u.int_in_range(0..=0)?; + let can_tx_error_counter = u.int_in_range(0..=0)?; + let can_tx_overflow_counter = u.int_in_range(0..=0)?; + let mode = u.int_in_range(0..=1)?; + let reserved = u.int_in_range(0..=0)?; + let test_counter = u.int_in_range(0..=0)?; + Status::new( + error_reserved, + error_mosfet_overheat, + error_low_arrow_power, + error_hw_over_voltage, + error_hw_over_current, + error_battery_low, + error_battery_full, + error12v_undervoltage, + limit_output_voltage_max, + limit_mosfet_temperature, + limit_local_mppt, + limit_input_current_min, + limit_input_current_max, + limit_global_mppt, + limit_duty_cycle_max, + limit_dury_cycle_min, + can_rx_error_counter, + can_tx_error_counter, + can_tx_overflow_counter, + mode, + reserved, + test_counter, + ) + .map_err(|_| arbitrary::Error::IncorrectFormat) + } +} + +/// PowerConnector +/// +/// - Standard ID: 1542 (0x606) +/// - Size: 8 bytes +/// - Transmitter: ElmarSolarMPPT +#[derive(Clone, Copy)] +pub struct PowerConnector { + raw: [u8; 8], +} + +impl PowerConnector { + pub const MESSAGE_ID: embedded_can::Id = + Id::Standard(unsafe { StandardId::new_unchecked(0x606) }); + + pub const OUTPUT_VOLTAGE_BATTERY_SIDE_MIN: i32 = 0_i32; + pub const OUTPUT_VOLTAGE_BATTERY_SIDE_MAX: i32 = 0_i32; + pub const POWER_CONNECTOR_TEMP_MIN: i32 = 0_i32; + pub const POWER_CONNECTOR_TEMP_MAX: i32 = 0_i32; + + /// Construct new PowerConnector from values + pub fn new( + output_voltage_battery_side: i32, + power_connector_temp: i32, + ) -> Result { + let mut res = Self { raw: [0u8; 8] }; + res.set_output_voltage_battery_side(output_voltage_battery_side)?; + res.set_power_connector_temp(power_connector_temp)?; + Ok(res) + } + + /// Access message payload raw value + pub fn raw(&self) -> &[u8; 8] { + &self.raw + } + + /// OutputVoltageBatterySide + /// + /// Output Voltage (Battery side of fuse) + /// + /// - Min: 0 + /// - Max: 0 + /// - Unit: "V" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn output_voltage_battery_side(&self) -> i32 { + self.output_voltage_battery_side_raw() + } + + /// Get raw value of OutputVoltageBatterySide + /// + /// - Start bit: 0 + /// - Signal size: 32 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Signed + #[inline(always)] + pub fn output_voltage_battery_side_raw(&self) -> i32 { + let signal = self.raw.view_bits::()[0..32].load_le::(); + + let factor = 1; + let signal = signal as i32; + i32::from(signal).saturating_mul(factor).saturating_add(0) + } + + /// Set value of OutputVoltageBatterySide + #[inline(always)] + pub fn set_output_voltage_battery_side(&mut self, value: i32) -> Result<(), CanError> { + let factor = 1; + let value = value.checked_sub(0).ok_or(CanError::ParameterOutOfRange { + message_id: PowerConnector::MESSAGE_ID, + })?; + let value = (value / factor) as i32; + + let value = u32::from_ne_bytes(value.to_ne_bytes()); + self.raw.view_bits_mut::()[0..32].store_le(value); + Ok(()) + } + + /// PowerConnectorTemp + /// + /// Power connector temperature + /// + /// - Min: 0 + /// - Max: 0 + /// - Unit: "C" + /// - Receivers: Vector__XXX + #[inline(always)] + pub fn power_connector_temp(&self) -> i32 { + self.power_connector_temp_raw() + } + + /// Get raw value of PowerConnectorTemp + /// + /// - Start bit: 32 + /// - Signal size: 32 bits + /// - Factor: 1 + /// - Offset: 0 + /// - Byte order: LittleEndian + /// - Value type: Signed + #[inline(always)] + pub fn power_connector_temp_raw(&self) -> i32 { + let signal = self.raw.view_bits::()[32..64].load_le::(); + + let factor = 1; + let signal = signal as i32; + i32::from(signal).saturating_mul(factor).saturating_add(0) + } + + /// Set value of PowerConnectorTemp + #[inline(always)] + pub fn set_power_connector_temp(&mut self, value: i32) -> Result<(), CanError> { + let factor = 1; + let value = value.checked_sub(0).ok_or(CanError::ParameterOutOfRange { + message_id: PowerConnector::MESSAGE_ID, + })?; + let value = (value / factor) as i32; + + 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 PowerConnector { + 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 PowerConnector { + 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 PowerConnector { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + if f.alternate() { + f.debug_struct("PowerConnector") + .field( + "output_voltage_battery_side", + &self.output_voltage_battery_side(), + ) + .field("power_connector_temp", &self.power_connector_temp()) + .finish() + } else { + f.debug_tuple("PowerConnector").field(&self.raw).finish() + } + } +} + +impl defmt::Format for PowerConnector { + fn format(&self, f: defmt::Formatter) { + defmt::write!( + f, + "PowerConnector {{ OutputVoltageBatterySide={:?} PowerConnectorTemp={:?} }}", + self.output_voltage_battery_side(), + self.power_connector_temp(), + ); + } +} + +#[cfg(feature = "arb")] +impl<'a> Arbitrary<'a> for PowerConnector { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + let output_voltage_battery_side = u.int_in_range(0..=0)?; + let power_connector_temp = u.int_in_range(0..=0)?; + PowerConnector::new(output_voltage_battery_side, power_connector_temp) + .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(embedded_can::Id), + /// Signal parameter is not within the range + /// defined in the dbc + ParameterOutOfRange { + /// dbc message id + message_id: embedded_can::Id, + }, + InvalidPayloadSize, + /// Multiplexor value not defined in the dbc + InvalidMultiplexor { + /// dbc message id + message_id: embedded_can::Id, + /// Multiplexor value not defined in the dbc + multiplexor: u16, + }, +} + +impl core::fmt::Display for CanError { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:?}", self) + } +} +#[cfg(feature = "std")] +impl std::error::Error for CanError {} +#[cfg(feature = "arb")] +trait UnstructuredFloatExt { + fn float_in_range(&mut self, range: core::ops::RangeInclusive) -> arbitrary::Result; +} + +#[cfg(feature = "arb")] +impl UnstructuredFloatExt for arbitrary::Unstructured<'_> { + fn float_in_range(&mut self, range: core::ops::RangeInclusive) -> arbitrary::Result { + let min = range.start(); + let max = range.end(); + let steps = u32::MAX; + let factor = (max - min) / (steps as f32); + let random_int: u32 = self.int_in_range(0..=steps)?; + let random = min + factor * (random_int as f32); + Ok(random) + } +}