1use crate::{Dbc, Error, MAX_SIGNALS_PER_MESSAGE, Message, Result, compat::Vec};
2#[cfg(feature = "embedded-can")]
3use embedded_can::{Frame, Id};
4
5#[derive(Debug, Clone, PartialEq)]
9pub struct DecodedSignal<'a> {
10 pub name: &'a str,
12 pub value: f64,
14 pub raw_value: i64,
17 pub min: f64,
19 pub max: f64,
21 pub unit: Option<&'a str>,
23 pub description: Option<&'a str>,
26}
27
28impl<'a> DecodedSignal<'a> {
29 #[inline]
54 pub fn new(
55 name: &'a str,
56 value: f64,
57 raw_value: i64,
58 min: f64,
59 max: f64,
60 unit: Option<&'a str>,
61 description: Option<&'a str>,
62 ) -> Self {
63 Self {
64 name,
65 value,
66 raw_value,
67 min,
68 max,
69 unit,
70 description,
71 }
72 }
73
74 #[inline]
88 pub fn is_in_range(&self) -> bool {
89 self.value >= self.min && self.value <= self.max
90 }
91}
92
93const MAX_SWITCHES: usize = 8;
96
97struct SwitchValues<'a> {
100 names: [Option<&'a str>; MAX_SWITCHES],
102 values: [u64; MAX_SWITCHES],
104 count: usize,
106}
107
108impl<'a> SwitchValues<'a> {
109 #[inline]
110 const fn new() -> Self {
111 Self {
112 names: [None; MAX_SWITCHES],
113 values: [0; MAX_SWITCHES],
114 count: 0,
115 }
116 }
117
118 #[inline]
120 fn push(&mut self, name: &'a str, value: u64) -> Result<()> {
121 if self.count >= MAX_SWITCHES {
122 return Err(Error::Decoding(Error::MESSAGE_TOO_MANY_SIGNALS));
123 }
124 let idx = self.count;
125 self.names[idx] = Some(name);
126 self.values[idx] = value;
127 self.count += 1;
128 Ok(())
129 }
130
131 #[inline]
133 fn get_by_name(&self, name: &str) -> Option<u64> {
134 for i in 0..self.count {
135 if self.names[i] == Some(name) {
136 return Some(self.values[i]);
137 }
138 }
139 None
140 }
141
142 #[inline]
144 fn any_has_value(&self, target: u64) -> bool {
145 for i in 0..self.count {
146 if self.values[i] == target && self.names[i].is_some() {
147 return true;
148 }
149 }
150 false
151 }
152}
153
154impl Dbc {
156 #[inline]
203 pub fn decode(
204 &self,
205 id: u32,
206 payload: &[u8],
207 is_extended: bool,
208 ) -> Result<Vec<DecodedSignal<'_>, { MAX_SIGNALS_PER_MESSAGE }>> {
209 let id = if is_extended {
211 id | Message::EXTENDED_ID_FLAG
212 } else {
213 id
214 };
215
216 let message = self
218 .messages()
219 .find_by_id(id)
220 .ok_or(Error::Decoding(Error::MESSAGE_NOT_FOUND))?;
221
222 let min_bytes = message.min_bytes_required() as usize;
226 if payload.len() < min_bytes {
227 return Err(Error::Decoding(Error::PAYLOAD_LENGTH_MISMATCH));
228 }
229
230 let mut decoded_signals: Vec<DecodedSignal<'_>, { MAX_SIGNALS_PER_MESSAGE }> = Vec::new();
232
233 let mut switch_values = SwitchValues::<'_>::new();
235
236 let signals = message.signals();
237
238 let message_has_extended_mux = !self.extended_multiplexing.is_empty()
242 && self.has_extended_multiplexing_for_message(id);
243
244 let has_any_value_descriptions = !self.value_descriptions.is_empty();
247
248 for signal in signals.iter() {
251 if signal.is_multiplexer_switch() {
252 let (raw_value, physical_value) = signal.decode_raw(payload)?;
254
255 if raw_value < 0 {
257 return Err(Error::Decoding(Error::MULTIPLEXER_SWITCH_NEGATIVE));
258 }
259
260 switch_values.push(signal.name(), raw_value as u64)?;
262
263 let description = if has_any_value_descriptions {
265 self.value_descriptions_for_signal(id, signal.name())
266 .and_then(|vd| vd.get(raw_value as u64))
267 } else {
268 None
269 };
270
271 decoded_signals
273 .push(DecodedSignal::new(
274 signal.name(),
275 physical_value,
276 raw_value,
277 signal.min(),
278 signal.max(),
279 signal.unit(),
280 description,
281 ))
282 .map_err(|_| Error::Decoding(Error::MESSAGE_TOO_MANY_SIGNALS))?;
283 }
284 }
285
286 for signal in signals.iter() {
288 if signal.is_multiplexer_switch() {
290 continue;
291 }
292
293 let should_decode = if let Some(mux_value) = signal.multiplexer_switch_value() {
295 if message_has_extended_mux {
297 self.check_extended_multiplexing(id, signal.name(), &switch_values)
299 .unwrap_or_else(|| {
300 switch_values.any_has_value(mux_value)
302 })
303 } else {
304 switch_values.any_has_value(mux_value)
306 }
307 } else {
308 true
310 };
311
312 if should_decode {
313 let (raw_value, physical_value) = signal.decode_raw(payload)?;
315
316 let description = if has_any_value_descriptions {
318 self.value_descriptions_for_signal(id, signal.name())
319 .and_then(|vd| vd.get(raw_value as u64))
320 } else {
321 None
322 };
323
324 decoded_signals
325 .push(DecodedSignal::new(
326 signal.name(),
327 physical_value,
328 raw_value,
329 signal.min(),
330 signal.max(),
331 signal.unit(),
332 description,
333 ))
334 .map_err(|_| Error::Decoding(Error::MESSAGE_TOO_MANY_SIGNALS))?;
335 }
336 }
337
338 Ok(decoded_signals)
339 }
340
341 #[inline]
345 fn check_extended_multiplexing(
346 &self,
347 message_id: u32,
348 signal_name: &str,
349 switch_values: &SwitchValues,
350 ) -> Option<bool> {
351 let indices = self.ext_mux_index.get(message_id, signal_name)?;
353 if indices.is_empty() {
354 return None;
355 }
356
357 let mut unique_switches: [Option<&str>; MAX_SWITCHES] = [None; MAX_SWITCHES];
362 let mut unique_count = 0;
363
364 for &idx in indices {
365 if let Some(entry) = self.extended_multiplexing.get(idx) {
366 let switch_name = entry.multiplexer_switch();
367 let found =
369 unique_switches.iter().take(unique_count).any(|&s| s == Some(switch_name));
370 if !found && unique_count < MAX_SWITCHES {
371 unique_switches[unique_count] = Some(switch_name);
372 unique_count += 1;
373 }
374 }
375 }
376
377 for switch_opt in unique_switches.iter().take(unique_count) {
379 let switch_name = match switch_opt {
380 Some(name) => *name,
381 None => continue,
382 };
383
384 let switch_val = match switch_values.get_by_name(switch_name) {
386 Some(v) => v,
387 None => return Some(false), };
389
390 let mut has_match = false;
392 for &idx in indices {
393 if let Some(entry) = self.extended_multiplexing.get(idx) {
394 if entry.multiplexer_switch() == switch_name {
395 for &(min, max) in entry.value_ranges() {
396 if switch_val >= min && switch_val <= max {
397 has_match = true;
398 break;
399 }
400 }
401 if has_match {
402 break;
403 }
404 }
405 }
406 }
407
408 if !has_match {
409 return Some(false); }
411 }
412
413 Some(true) }
415
416 #[inline]
419 fn has_extended_multiplexing_for_message(&self, message_id: u32) -> bool {
420 self.extended_multiplexing
421 .iter()
422 .any(|ext_mux| ext_mux.message_id() == message_id)
423 }
424
425 #[cfg(feature = "embedded-can")]
472 #[inline]
473 pub fn decode_frame<T: Frame>(
474 &self,
475 frame: T,
476 ) -> Result<Vec<DecodedSignal<'_>, { MAX_SIGNALS_PER_MESSAGE }>> {
477 let payload = frame.data();
478 match frame.id() {
479 Id::Standard(id) => self.decode(id.as_raw() as u32, payload, false),
480 Id::Extended(id) => self.decode(id.as_raw(), payload, true),
481 }
482 }
483}
484
485#[cfg(test)]
486mod tests {
487 use crate::Dbc;
488
489 #[test]
490 fn test_decode_basic() {
491 let dbc = Dbc::parse(
492 r#"VERSION "1.0"
493
494BU_: ECM
495
496BO_ 256 Engine : 8 ECM
497 SG_ RPM : 0|16@1+ (0.25,0) [0|8000] "rpm" *
498"#,
499 )
500 .unwrap();
501
502 let payload = [0x40, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
504 let decoded = dbc.decode(256, &payload, false).unwrap();
505 assert_eq!(decoded.len(), 1);
506 assert_eq!(decoded[0].name, "RPM");
507 assert_eq!(decoded[0].value, 2000.0);
508 assert_eq!(decoded[0].raw_value, 8000); assert_eq!(decoded[0].min, 0.0);
510 assert_eq!(decoded[0].max, 8000.0);
511 assert!(decoded[0].is_in_range());
512 assert_eq!(decoded[0].unit, Some("rpm"));
513 }
514
515 #[test]
516 fn test_decode_message_not_found() {
517 let dbc = Dbc::parse(
518 r#"VERSION "1.0"
519
520BU_: ECM
521
522BO_ 256 Engine : 8 ECM
523"#,
524 )
525 .unwrap();
526
527 let payload = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
528 let result = dbc.decode(512, &payload, false);
529 assert!(result.is_err());
530 }
531
532 #[test]
533 fn test_decode_message() {
534 let data = r#"VERSION "1.0"
535
536BU_: ECM
537
538BO_ 256 Engine : 8 ECM
539 SG_ RPM : 0|16@1+ (0.25,0) [0|8000] "rpm" *
540 SG_ Temp : 16|8@1- (1,-40) [-40|215] "°C" *
541"#;
542
543 let dbc = Dbc::parse(data).unwrap();
544
545 let payload = [0x40, 0x1F, 0x5A, 0x00, 0x00, 0x00, 0x00, 0x00];
548 let decoded = dbc.decode(256, &payload, false).unwrap();
549
550 assert_eq!(decoded.len(), 2);
551 assert_eq!(decoded[0].name, "RPM");
552 assert_eq!(decoded[0].value, 2000.0);
553 assert_eq!(decoded[0].unit, Some("rpm"));
554 assert_eq!(decoded[1].name, "Temp");
555 assert_eq!(decoded[1].value, 50.0);
556 assert_eq!(decoded[1].unit, Some("°C"));
557 }
558
559 #[test]
560 fn test_decode_payload_length_mismatch() {
561 use crate::Error;
562 let data = r#"VERSION "1.0"
563
564BU_: ECM
565
566BO_ 256 Engine : 8 ECM
567 SG_ RPM : 0|16@1+ (0.25,0) [0|8000] "rpm" *
568"#;
569
570 let dbc = Dbc::parse(data).unwrap();
571
572 let payload = [0x40];
575 let result = dbc.decode(256, &payload, false);
576 assert!(result.is_err());
577 match result.unwrap_err() {
578 Error::Decoding(msg) => {
579 assert!(msg.contains(Error::PAYLOAD_LENGTH_MISMATCH));
580 }
581 _ => panic!("Expected Error::Decoding"),
582 }
583
584 let payload = [0x40, 0x1F];
586 let result = dbc.decode(256, &payload, false);
587 assert!(result.is_ok());
588
589 let payload = [0x40, 0x1F, 0x00, 0x00];
591 let result = dbc.decode(256, &payload, false);
592 assert!(result.is_ok());
593 }
594
595 #[test]
596 fn test_decode_dlc_larger_than_signal_coverage() {
597 let data = r#"VERSION "1.0"
600
601BU_: ECM
602
603BO_ 1024 NewMessage : 8 ECM
604 SG_ Temp : 0|8@1+ (1,0) [0|255] "" ECM
605 SG_ Pressure : 8|8@1+ (1,0) [0|255] "" ECM
606 SG_ Heel : 16|4@1+ (1,0) [0|15] "" ECM
607 SG_ Rest : 20|4@1+ (1,0) [0|15] "" ECM
608"#;
609
610 let dbc = Dbc::parse(data).unwrap();
611 let message = dbc.messages().find("NewMessage").unwrap();
612
613 assert_eq!(message.dlc(), 8);
615 assert_eq!(message.min_bytes_required(), 3);
616
617 let payload = [0xAB, 0xCD, 0xEF, 0x00, 0x00, 0x00];
620 let decoded = dbc.decode(1024, &payload, false).unwrap();
621
622 assert_eq!(decoded.len(), 4);
623
624 assert_eq!(
626 decoded.iter().find(|s| s.name == "Temp").unwrap().raw_value,
627 0xAB
628 );
629 assert_eq!(
630 decoded.iter().find(|s| s.name == "Pressure").unwrap().raw_value,
631 0xCD
632 );
633 assert_eq!(
634 decoded.iter().find(|s| s.name == "Heel").unwrap().raw_value,
635 0xF
636 );
637 assert_eq!(
638 decoded.iter().find(|s| s.name == "Rest").unwrap().raw_value,
639 0xE
640 );
641 }
642
643 #[test]
644 fn test_decode_big_endian_signal() {
645 let data = r#"VERSION "1.0"
646
647BU_: ECM
648
649BO_ 256 Engine : 8 ECM
650 SG_ RPM : 0|16@0+ (1.0,0) [0|65535] "rpm" *
651"#;
652
653 let dbc = Dbc::parse(data).unwrap();
654
655 let payload = [0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
659 let decoded = dbc.decode(256, &payload, false).unwrap();
660
661 assert_eq!(decoded.len(), 1);
662 assert_eq!(decoded[0].name, "RPM");
663 assert!(decoded[0].value >= 0.0);
666 assert_eq!(decoded[0].unit, Some("rpm"));
667 }
668
669 #[test]
670 fn test_decode_multiplexed_signal() {
671 let dbc = Dbc::parse(
672 r#"VERSION "1.0"
673
674BU_: ECM
675
676BO_ 256 Engine : 8 ECM
677 SG_ MuxId M : 0|8@1+ (1,0) [0|255] ""
678 SG_ Signal0 m0 : 8|16@1+ (0.1,0) [0|6553.5] "unit" *
679 SG_ Signal1 m1 : 24|16@1+ (0.01,0) [0|655.35] "unit" *
680 SG_ NormalSignal : 40|8@1+ (1,0) [0|255] ""
681"#,
682 )
683 .unwrap();
684
685 let payload = [0x00, 0x64, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00];
687 let decoded = dbc.decode(256, &payload, false).unwrap();
690
691 let find_signal = |name: &str| decoded.iter().find(|s| s.name == name).map(|s| s.value);
693
694 assert!(find_signal("MuxId").is_some());
696 assert!(find_signal("Signal0").is_some());
698 assert!(find_signal("Signal1").is_none());
700 assert!(find_signal("NormalSignal").is_some());
702 }
703
704 #[test]
705 fn test_decode_multiplexed_signal_switch_one() {
706 let dbc = Dbc::parse(
707 r#"VERSION "1.0"
708
709BU_: ECM
710
711BO_ 256 Engine : 8 ECM
712 SG_ MuxId M : 0|8@1+ (1,0) [0|255] ""
713 SG_ Signal0 m0 : 8|16@1+ (0.1,0) [0|6553.5] "unit" *
714 SG_ Signal1 m1 : 24|16@1+ (0.01,0) [0|655.35] "unit" *
715"#,
716 )
717 .unwrap();
718
719 let payload = [0x01, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00];
721 let decoded = dbc.decode(256, &payload, false).unwrap();
724
725 let find_signal = |name: &str| decoded.iter().find(|s| s.name == name).map(|s| s.value);
727
728 assert_eq!(find_signal("MuxId"), Some(1.0));
730 assert!(find_signal("Signal0").is_none());
732 assert!(find_signal("Signal1").is_some());
734 }
735
736 #[test]
737 fn test_decode_mixed_byte_order() {
738 let dbc = Dbc::parse(
739 r#"VERSION "1.0"
740
741BU_: ECM
742
743BO_ 256 MixedByteOrder : 8 ECM
744 SG_ LittleEndianSignal : 0|16@1+ (1.0,0) [0|65535] ""
745 SG_ BigEndianSignal : 23|16@0+ (1.0,0) [0|65535] ""
746 SG_ AnotherLittleEndian : 32|8@1+ (1.0,0) [0|255] ""
747 SG_ AnotherBigEndian : 47|8@0+ (1.0,0) [0|255] ""
748"#,
749 )
750 .unwrap();
751
752 let payload = [
758 0x34, 0x12, 0x00, 0x01, 0xAB, 0xCD, 0x00, 0x00, ];
764 let decoded = dbc.decode(256, &payload, false).unwrap();
765
766 let find_signal = |name: &str| decoded.iter().find(|s| s.name == name).map(|s| s.value);
768
769 assert_eq!(find_signal("LittleEndianSignal"), Some(4660.0)); let big_endian_value = find_signal("BigEndianSignal").unwrap();
774 assert!((0.0..=65535.0).contains(&big_endian_value));
776
777 assert_eq!(find_signal("AnotherLittleEndian"), Some(171.0)); let big_endian_8bit = find_signal("AnotherBigEndian");
782 assert!(big_endian_8bit.is_some());
783 assert!(big_endian_8bit.unwrap() >= 0.0 && big_endian_8bit.unwrap() <= 255.0);
784
785 assert_eq!(decoded.len(), 4);
787
788 assert!(find_signal("LittleEndianSignal").is_some());
790 assert!(find_signal("BigEndianSignal").is_some());
791 }
792
793 #[test]
794 fn test_decode_extended_multiplexing_simple() {
795 let dbc = Dbc::parse(
796 r#"VERSION "1.0"
797
798BU_: ECM
799
800BO_ 500 ComplexMux : 8 ECM
801 SG_ Mux1 M : 0|8@1+ (1,0) [0|255] ""
802 SG_ Signal_A m0 : 16|16@1+ (0.1,0) [0|100] "unit" *
803
804SG_MUL_VAL_ 500 Signal_A Mux1 5-10 ;
805"#,
806 )
807 .unwrap();
808
809 let payload = [0x05, 0x00, 0xE8, 0x03, 0x00, 0x00, 0x00, 0x00];
813 let decoded = dbc.decode(500, &payload, false).unwrap();
814
815 let find_signal = |name: &str| decoded.iter().find(|s| s.name == name).map(|s| s.value);
816
817 assert_eq!(find_signal("Mux1"), Some(5.0));
818 assert_eq!(
820 dbc.extended_multiplexing_for_message(500).count(),
821 1,
822 "Extended multiplexing entries should be parsed"
823 );
824 assert!(
825 find_signal("Signal_A").is_some(),
826 "Signal_A should be decoded when Mux1=5 (within range 5-10)"
827 );
828 assert_eq!(find_signal("Signal_A").unwrap(), 100.0);
829
830 let payload2 = [0x0F, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00];
832 let decoded2 = dbc.decode(500, &payload2, false).unwrap();
833 let find_signal2 = |name: &str| decoded2.iter().find(|s| s.name == name).map(|s| s.value);
834
835 assert_eq!(find_signal2("Mux1"), Some(15.0));
836 assert!(find_signal2("Signal_A").is_none());
837 }
838
839 #[test]
840 fn test_decode_extended_multiplexing_multiple_ranges() {
841 let dbc = Dbc::parse(
842 r#"VERSION "1.0"
843
844BU_: ECM
845
846BO_ 501 MultiRangeMux : 8 ECM
847 SG_ Mux1 M : 0|8@1+ (1,0) [0|255] ""
848 SG_ Signal_B m0 : 16|16@1+ (1,0) [0|65535] "unit" *
849
850SG_MUL_VAL_ 501 Signal_B Mux1 0-5,10-15,20-25 ;
851"#,
852 )
853 .unwrap();
854
855 let payload1 = [0x03, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00];
858 let decoded1 = dbc.decode(501, &payload1, false).unwrap();
859 let find1 = |name: &str| decoded1.iter().find(|s| s.name == name).map(|s| s.value);
860 assert_eq!(find1("Mux1"), Some(3.0));
861 assert!(find1("Signal_B").is_some());
862
863 let payload2 = [0x0C, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00];
866 let decoded2 = dbc.decode(501, &payload2, false).unwrap();
867 let find2 = |name: &str| decoded2.iter().find(|s| s.name == name).map(|s| s.value);
868 assert_eq!(find2("Mux1"), Some(12.0));
869 assert!(find2("Signal_B").is_some());
870
871 let payload3 = [0x16, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00];
874 let decoded3 = dbc.decode(501, &payload3, false).unwrap();
875 let find3 = |name: &str| decoded3.iter().find(|s| s.name == name).map(|s| s.value);
876 assert_eq!(find3("Mux1"), Some(22.0));
877 assert!(find3("Signal_B").is_some());
878
879 let payload4 = [0x08, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00];
882 let decoded4 = dbc.decode(501, &payload4, false).unwrap();
883 let find4 = |name: &str| decoded4.iter().find(|s| s.name == name).map(|s| s.value);
884 assert_eq!(find4("Mux1"), Some(8.0));
885 assert!(find4("Signal_B").is_none());
886 }
887
888 #[test]
891 fn test_decode_extended_multiplexing_multiple_switches() {
892 let dbc = Dbc::parse(
893 r#"VERSION "1.0"
894
895BU_: ECM
896
897BO_ 502 MultiSwitchMux : 8 ECM
898 SG_ Mux1 M : 0|8@1+ (1,0) [0|255] ""
899 SG_ Mux2 M : 8|8@1+ (1,0) [0|255] ""
900 SG_ Signal_C m0 : 16|16@1+ (1,0) [0|65535] "unit" *
901
902SG_MUL_VAL_ 502 Signal_C Mux1 5-10 ;
903SG_MUL_VAL_ 502 Signal_C Mux2 20-25 ;
904"#,
905 )
906 .unwrap();
907
908 let payload1 = [0x07, 0x16, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00];
911 let decoded1 = dbc.decode(502, &payload1, false).unwrap();
912 let find1 = |name: &str| decoded1.iter().find(|s| s.name == name).map(|s| s.value);
913 assert_eq!(find1("Mux1"), Some(7.0));
914 assert_eq!(find1("Mux2"), Some(22.0));
915 assert!(find1("Signal_C").is_some());
916
917 let payload2 = [0x07, 0x1E, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00];
919 let decoded2 = dbc.decode(502, &payload2, false).unwrap();
920 let find2 = |name: &str| decoded2.iter().find(|s| s.name == name).map(|s| s.value);
921 assert_eq!(find2("Mux1"), Some(7.0));
922 assert_eq!(find2("Mux2"), Some(30.0));
923 assert!(find2("Signal_C").is_none());
924
925 let payload3 = [0x0F, 0x16, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00];
927 let decoded3 = dbc.decode(502, &payload3, false).unwrap();
928 let find3 = |name: &str| decoded3.iter().find(|s| s.name == name).map(|s| s.value);
929 assert_eq!(find3("Mux1"), Some(15.0));
930 assert_eq!(find3("Mux2"), Some(22.0));
931 assert!(find3("Signal_C").is_none());
932 }
933
934 #[test]
937 fn test_decode_extended_multiplexing_takes_precedence() {
938 let dbc = Dbc::parse(
939 r#"VERSION "1.0"
940
941BU_: ECM
942
943BO_ 503 PrecedenceTest : 8 ECM
944 SG_ Mux1 M : 0|8@1+ (1,0) [0|255] ""
945 SG_ Signal_D m0 : 16|16@1+ (1,0) [0|65535] "unit" *
946
947SG_MUL_VAL_ 503 Signal_D Mux1 10-15 ;
948"#,
949 )
950 .unwrap();
951
952 let payload1 = [0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00];
956 let decoded1 = dbc.decode(503, &payload1, false).unwrap();
957 let find1 = |name: &str| decoded1.iter().find(|s| s.name == name).map(|s| s.value);
958 assert_eq!(find1("Mux1"), Some(0.0));
959 assert!(find1("Signal_D").is_none());
960
961 let payload2 = [0x0C, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x00];
963 let decoded2 = dbc.decode(503, &payload2, false).unwrap();
964 let find2 = |name: &str| decoded2.iter().find(|s| s.name == name).map(|s| s.value);
965 assert_eq!(find2("Mux1"), Some(12.0));
966 assert!(find2("Signal_D").is_some());
967 }
968
969 #[test]
972 fn test_decode_extended_multiplexing_with_extended_mux_signal() {
973 let dbc = Dbc::parse(
975 r#"VERSION "1.0"
976
977BU_: ECM
978
979BO_ 504 ExtendedMuxSignal : 8 ECM
980 SG_ Mux1 M : 0|8@1+ (1,0) [0|255] ""
981 SG_ Mux2 m65M : 8|8@1+ (1,0) [0|255] ""
982 SG_ Signal_E m0 : 16|16@1+ (1,0) [0|65535] "unit" *
983
984SG_MUL_VAL_ 504 Signal_E Mux1 65-65 ;
985SG_MUL_VAL_ 504 Signal_E Mux2 10-15 ;
986"#,
987 )
988 .unwrap();
989
990 let payload = [0x41, 0x0C, 0x00, 0xA0, 0x00, 0x00, 0x00, 0x00];
993 let decoded = dbc.decode(504, &payload, false).unwrap();
995 let find = |name: &str| decoded.iter().find(|s| s.name == name).map(|s| s.value);
996
997 assert_eq!(find("Mux1"), Some(65.0));
998 assert_eq!(find("Mux2"), Some(12.0));
999 assert!(find("Signal_E").is_some());
1000
1001 let payload2 = [0x40, 0x0C, 0x00, 0xB0, 0x00, 0x00, 0x00, 0x00];
1003 let decoded2 = dbc.decode(504, &payload2, false).unwrap();
1004 let find2 = |name: &str| decoded2.iter().find(|s| s.name == name).map(|s| s.value);
1005 assert_eq!(find2("Mux1"), Some(64.0));
1006 assert_eq!(find2("Mux2"), Some(12.0));
1007 assert!(find2("Signal_E").is_none());
1008 }
1009
1010 #[test]
1011 fn test_decode_negative_multiplexer_switch() {
1012 use crate::Error;
1013 let dbc = Dbc::parse(
1016 r#"VERSION "1.0"
1017
1018BU_: ECM
1019
1020BO_ 256 MuxMessage : 8 ECM
1021 SG_ MuxSwitch M : 0|8@1- (1,0) [-128|127] ""
1022 SG_ SignalA m0 : 8|8@1+ (1,0) [0|255] ""
1023"#,
1024 )
1025 .unwrap();
1026
1027 let payload = [0xFB, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
1031 let result = dbc.decode(256, &payload, false);
1032 assert!(result.is_err());
1033 match result.unwrap_err() {
1034 Error::Decoding(msg) => {
1035 assert_eq!(msg, Error::MULTIPLEXER_SWITCH_NEGATIVE);
1036 }
1037 _ => panic!("Expected Error::Decoding with MULTIPLEXER_SWITCH_NEGATIVE"),
1038 }
1039 }
1040
1041 #[test]
1042 fn test_decode_too_many_unique_switches() {
1043 use crate::{Error, MAX_SIGNALS_PER_MESSAGE};
1044 if MAX_SIGNALS_PER_MESSAGE < 17 {
1047 return;
1048 }
1049
1050 let dbc_str = r#"VERSION "1.0"
1054
1055BU_: ECM
1056
1057BO_ 600 TooManySwitches : 18 ECM
1058 SG_ Mux1 M : 0|8@1+ (1,0) [0|255] ""
1059 SG_ Mux2 M : 8|8@1+ (1,0) [0|255] ""
1060 SG_ Mux3 M : 16|8@1+ (1,0) [0|255] ""
1061 SG_ Mux4 M : 24|8@1+ (1,0) [0|255] ""
1062 SG_ Mux5 M : 32|8@1+ (1,0) [0|255] ""
1063 SG_ Mux6 M : 40|8@1+ (1,0) [0|255] ""
1064 SG_ Mux7 M : 48|8@1+ (1,0) [0|255] ""
1065 SG_ Mux8 M : 56|8@1+ (1,0) [0|255] ""
1066 SG_ Mux9 M : 64|8@1+ (1,0) [0|255] ""
1067 SG_ Mux10 M : 72|8@1+ (1,0) [0|255] ""
1068 SG_ Mux11 M : 80|8@1+ (1,0) [0|255] ""
1069 SG_ Mux12 M : 88|8@1+ (1,0) [0|255] ""
1070 SG_ Mux13 M : 96|8@1+ (1,0) [0|255] ""
1071 SG_ Mux14 M : 104|8@1+ (1,0) [0|255] ""
1072 SG_ Mux15 M : 112|8@1+ (1,0) [0|255] ""
1073 SG_ Mux16 M : 120|8@1+ (1,0) [0|255] ""
1074 SG_ Mux17 M : 128|8@1+ (1,0) [0|255] ""
1075 SG_ Signal_X m0 : 136|8@1+ (1,0) [0|255] "unit" *
1076
1077SG_MUL_VAL_ 600 Signal_X Mux1 0-255 ;
1078SG_MUL_VAL_ 600 Signal_X Mux2 0-255 ;
1079SG_MUL_VAL_ 600 Signal_X Mux3 0-255 ;
1080SG_MUL_VAL_ 600 Signal_X Mux4 0-255 ;
1081SG_MUL_VAL_ 600 Signal_X Mux5 0-255 ;
1082SG_MUL_VAL_ 600 Signal_X Mux6 0-255 ;
1083SG_MUL_VAL_ 600 Signal_X Mux7 0-255 ;
1084SG_MUL_VAL_ 600 Signal_X Mux8 0-255 ;
1085SG_MUL_VAL_ 600 Signal_X Mux9 0-255 ;
1086SG_MUL_VAL_ 600 Signal_X Mux10 0-255 ;
1087SG_MUL_VAL_ 600 Signal_X Mux11 0-255 ;
1088SG_MUL_VAL_ 600 Signal_X Mux12 0-255 ;
1089SG_MUL_VAL_ 600 Signal_X Mux13 0-255 ;
1090SG_MUL_VAL_ 600 Signal_X Mux14 0-255 ;
1091SG_MUL_VAL_ 600 Signal_X Mux15 0-255 ;
1092SG_MUL_VAL_ 600 Signal_X Mux16 0-255 ;
1093SG_MUL_VAL_ 600 Signal_X Mux17 0-255 ;
1094"#;
1095
1096 let dbc = Dbc::parse(dbc_str).unwrap();
1097
1098 let payload = [0x00; 18];
1101 let result = dbc.decode(600, &payload, false);
1102 assert!(
1103 result.is_err(),
1104 "Decode should fail when there are more than 16 unique switches"
1105 );
1106 match result.unwrap_err() {
1107 Error::Decoding(msg) => {
1108 assert_eq!(
1109 msg,
1110 Error::MESSAGE_TOO_MANY_SIGNALS,
1111 "Expected MESSAGE_TOO_MANY_SIGNALS error, got: {}",
1112 msg
1113 );
1114 }
1115 e => panic!(
1116 "Expected Error::Decoding with MESSAGE_TOO_MANY_SIGNALS, got: {:?}",
1117 e
1118 ),
1119 }
1120 }
1121
1122 #[test]
1123 fn test_decode_extended_can_id() {
1124 let dbc = Dbc::parse(
1128 r#"VERSION "1.0"
1129
1130BU_: ECM
1131
1132BO_ 2147484672 ExtendedMsg : 8 ECM
1133 SG_ Speed : 0|16@1+ (0.1,0) [0|6553.5] "km/h" *
1134"#,
1135 )
1136 .unwrap();
1137 let payload = [0xE8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
1140 let decoded = dbc.decode(0x400, &payload, true).unwrap();
1144 assert_eq!(decoded.len(), 1);
1145 assert_eq!(decoded[0].name, "Speed");
1146 assert_eq!(decoded[0].value, 100.0);
1147 assert_eq!(decoded[0].unit, Some("km/h"));
1148 }
1149
1150 #[test]
1151 fn test_decode_extended_can_id_not_found_without_flag() {
1152 let dbc = Dbc::parse(
1155 r#"VERSION "1.0"
1156
1157BU_: ECM
1158
1159BO_ 2147484672 ExtendedMsg : 8 ECM
1160 SG_ Speed : 0|16@1+ (0.1,0) [0|6553.5] "km/h" *
1161"#,
1162 )
1163 .unwrap();
1164
1165 let payload = [0xE8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
1166
1167 let result = dbc.decode(0x400, &payload, false);
1169 assert!(result.is_err());
1170 }
1171
1172 #[test]
1173 fn test_decode_standard_vs_extended_same_base_id() {
1174 let dbc = Dbc::parse(
1176 r#"VERSION "1.0"
1177
1178BU_: ECM
1179
1180BO_ 256 StandardMsg : 8 ECM
1181 SG_ StdSignal : 0|8@1+ (1,0) [0|255] "" *
1182
1183BO_ 2147483904 ExtendedMsg : 8 ECM
1184 SG_ ExtSignal : 0|8@1+ (2,0) [0|510] "" *
1185"#,
1186 )
1187 .unwrap();
1188 let payload = [0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; let decoded_std = dbc.decode(256, &payload, false).unwrap();
1194 assert_eq!(decoded_std.len(), 1);
1195 assert_eq!(decoded_std[0].name, "StdSignal");
1196 assert_eq!(decoded_std[0].value, 100.0); let decoded_ext = dbc.decode(256, &payload, true).unwrap();
1200 assert_eq!(decoded_ext.len(), 1);
1201 assert_eq!(decoded_ext[0].name, "ExtSignal");
1202 assert_eq!(decoded_ext[0].value, 200.0); }
1204
1205 #[test]
1206 fn test_decode_with_value_descriptions() {
1207 let dbc = Dbc::parse(
1210 r#"VERSION "1.0"
1211
1212BU_: ECM
1213
1214BO_ 200 GearboxData : 4 ECM
1215 SG_ GearActual : 0|8@1+ (1,0) [0|5] "" *
1216
1217VAL_ 200 GearActual 0 "Park" 1 "Reverse" 2 "Neutral" 3 "Drive" 4 "Sport" 5 "Manual" ;
1218"#,
1219 )
1220 .unwrap();
1221
1222 let payload = [0x00, 0x00, 0x00, 0x00];
1224 let decoded = dbc.decode(200, &payload, false).unwrap();
1225 assert_eq!(decoded.len(), 1);
1226 assert_eq!(decoded[0].name, "GearActual");
1227 assert_eq!(decoded[0].value, 0.0);
1228 assert_eq!(decoded[0].description, Some("Park"));
1229
1230 let payload = [0x03, 0x00, 0x00, 0x00];
1232 let decoded = dbc.decode(200, &payload, false).unwrap();
1233 assert_eq!(decoded[0].value, 3.0);
1234 assert_eq!(decoded[0].description, Some("Drive"));
1235
1236 let payload = [0x05, 0x00, 0x00, 0x00];
1238 let decoded = dbc.decode(200, &payload, false).unwrap();
1239 assert_eq!(decoded[0].value, 5.0);
1240 assert_eq!(decoded[0].description, Some("Manual"));
1241 }
1242
1243 #[test]
1244 fn test_decode_without_value_descriptions() {
1245 let dbc = Dbc::parse(
1247 r#"VERSION "1.0"
1248
1249BU_: ECM
1250
1251BO_ 256 Engine : 8 ECM
1252 SG_ RPM : 0|16@1+ (0.25,0) [0|8000] "rpm" *
1253"#,
1254 )
1255 .unwrap();
1256
1257 let payload = [0x40, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
1258 let decoded = dbc.decode(256, &payload, false).unwrap();
1259 assert_eq!(decoded.len(), 1);
1260 assert_eq!(decoded[0].name, "RPM");
1261 assert_eq!(decoded[0].value, 2000.0);
1262 assert_eq!(decoded[0].unit, Some("rpm"));
1263 assert_eq!(decoded[0].description, None);
1264 }
1265
1266 #[test]
1267 fn test_decode_value_description_not_found() {
1268 let dbc = Dbc::parse(
1270 r#"VERSION "1.0"
1271
1272BU_: ECM
1273
1274BO_ 200 GearboxData : 4 ECM
1275 SG_ GearActual : 0|8@1+ (1,0) [0|255] "" *
1276
1277VAL_ 200 GearActual 0 "Park" 1 "Reverse" 2 "Neutral" ;
1278"#,
1279 )
1280 .unwrap();
1281
1282 let payload = [0x0A, 0x00, 0x00, 0x00];
1284 let decoded = dbc.decode(200, &payload, false).unwrap();
1285 assert_eq!(decoded.len(), 1);
1286 assert_eq!(decoded[0].value, 10.0);
1287 assert_eq!(decoded[0].description, None); }
1289
1290 #[test]
1291 fn test_decode_multiplexer_with_value_descriptions() {
1292 let dbc = Dbc::parse(
1295 r#"VERSION "1.0"
1296
1297BU_: ECM
1298
1299BO_ 300 MultiplexedSensors : 8 ECM
1300 SG_ SensorID M : 0|8@1+ (1,0) [0|3] "" *
1301 SG_ Temperature m0 : 8|16@1- (0.1,-40) [-40|125] "°C" *
1302 SG_ Pressure m1 : 8|16@1+ (0.01,0) [0|655.35] "kPa" *
1303
1304VAL_ 300 SensorID 0 "Temperature Sensor" 1 "Pressure Sensor" 2 "Humidity Sensor" 3 "Voltage Sensor" ;
1305"#,
1306 )
1307 .unwrap();
1308
1309 let payload = [0x00, 0xF4, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00];
1312 let decoded = dbc.decode(300, &payload, false).unwrap();
1313
1314 let sensor_id = decoded.iter().find(|s| s.name == "SensorID").unwrap();
1316 assert_eq!(sensor_id.value, 0.0);
1317 assert_eq!(sensor_id.description, Some("Temperature Sensor"));
1318
1319 let temp = decoded.iter().find(|s| s.name == "Temperature").unwrap();
1321 assert!(temp.description.is_none()); let payload = [0x01, 0x10, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00];
1325 let decoded = dbc.decode(300, &payload, false).unwrap();
1326
1327 let sensor_id = decoded.iter().find(|s| s.name == "SensorID").unwrap();
1328 assert_eq!(sensor_id.value, 1.0);
1329 assert_eq!(sensor_id.description, Some("Pressure Sensor"));
1330 }
1331
1332 #[cfg(feature = "embedded-can")]
1333 mod embedded_can_tests {
1334 use super::*;
1335 use embedded_can::{ExtendedId, Frame, Id, StandardId};
1336
1337 struct TestFrame {
1339 id: Id,
1340 data: [u8; 8],
1341 dlc: usize,
1342 }
1343
1344 impl TestFrame {
1345 fn new_standard(id: u16, data: &[u8]) -> Self {
1346 let mut frame_data = [0u8; 8];
1347 let dlc = data.len().min(8);
1348 frame_data[..dlc].copy_from_slice(&data[..dlc]);
1349 Self {
1350 id: Id::Standard(StandardId::new(id).unwrap()),
1351 data: frame_data,
1352 dlc,
1353 }
1354 }
1355
1356 fn new_extended(id: u32, data: &[u8]) -> Self {
1357 let mut frame_data = [0u8; 8];
1358 let dlc = data.len().min(8);
1359 frame_data[..dlc].copy_from_slice(&data[..dlc]);
1360 Self {
1361 id: Id::Extended(ExtendedId::new(id).unwrap()),
1362 data: frame_data,
1363 dlc,
1364 }
1365 }
1366 }
1367
1368 impl Frame for TestFrame {
1369 fn new(id: impl Into<Id>, data: &[u8]) -> Option<Self> {
1370 let mut frame_data = [0u8; 8];
1371 let dlc = data.len().min(8);
1372 frame_data[..dlc].copy_from_slice(&data[..dlc]);
1373 Some(Self {
1374 id: id.into(),
1375 data: frame_data,
1376 dlc,
1377 })
1378 }
1379
1380 fn new_remote(_id: impl Into<Id>, _dlc: usize) -> Option<Self> {
1381 None }
1383
1384 fn is_extended(&self) -> bool {
1385 matches!(self.id, Id::Extended(_))
1386 }
1387
1388 fn is_remote_frame(&self) -> bool {
1389 false
1390 }
1391
1392 fn id(&self) -> Id {
1393 self.id
1394 }
1395
1396 fn dlc(&self) -> usize {
1397 self.dlc
1398 }
1399
1400 fn data(&self) -> &[u8] {
1401 &self.data[..self.dlc]
1402 }
1403 }
1404
1405 #[test]
1406 fn test_decode_frame_standard() {
1407 let dbc = Dbc::parse(
1408 r#"VERSION "1.0"
1409
1410BU_: ECM
1411
1412BO_ 256 Engine : 8 ECM
1413 SG_ RPM : 0|16@1+ (0.25,0) [0|8000] "rpm" *
1414"#,
1415 )
1416 .unwrap();
1417
1418 let frame =
1420 TestFrame::new_standard(256, &[0x40, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
1421
1422 let decoded = dbc.decode_frame(frame).unwrap();
1423 assert_eq!(decoded.len(), 1);
1424 assert_eq!(decoded[0].name, "RPM");
1425 assert_eq!(decoded[0].value, 2000.0);
1426 assert_eq!(decoded[0].unit, Some("rpm"));
1427 }
1428
1429 #[test]
1430 fn test_decode_frame_extended() {
1431 let dbc = Dbc::parse(
1433 r#"VERSION "1.0"
1434
1435BU_: ECM
1436
1437BO_ 2147484672 ExtendedMsg : 8 ECM
1438 SG_ Speed : 0|16@1+ (0.1,0) [0|6553.5] "km/h" *
1439"#,
1440 )
1441 .unwrap();
1442 let frame =
1446 TestFrame::new_extended(0x400, &[0xE8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
1447
1448 let decoded = dbc.decode_frame(frame).unwrap();
1449 assert_eq!(decoded.len(), 1);
1450 assert_eq!(decoded[0].name, "Speed");
1451 assert_eq!(decoded[0].value, 100.0);
1452 assert_eq!(decoded[0].unit, Some("km/h"));
1453 }
1454
1455 #[test]
1456 fn test_decode_frame_standard_vs_extended() {
1457 let dbc = Dbc::parse(
1459 r#"VERSION "1.0"
1460
1461BU_: ECM
1462
1463BO_ 256 StandardMsg : 8 ECM
1464 SG_ StdSignal : 0|8@1+ (1,0) [0|255] "" *
1465
1466BO_ 2147483904 ExtendedMsg : 8 ECM
1467 SG_ ExtSignal : 0|8@1+ (2,0) [0|510] "" *
1468"#,
1469 )
1470 .unwrap();
1471 let payload = [0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; let std_frame = TestFrame::new_standard(256, &payload);
1477 let decoded_std = dbc.decode_frame(std_frame).unwrap();
1478 assert_eq!(decoded_std[0].name, "StdSignal");
1479 assert_eq!(decoded_std[0].value, 100.0);
1480
1481 let ext_frame = TestFrame::new_extended(256, &payload);
1483 let decoded_ext = dbc.decode_frame(ext_frame).unwrap();
1484 assert_eq!(decoded_ext[0].name, "ExtSignal");
1485 assert_eq!(decoded_ext[0].value, 200.0);
1486 }
1487
1488 #[test]
1489 fn test_decode_frame_message_not_found() {
1490 let dbc = Dbc::parse(
1491 r#"VERSION "1.0"
1492
1493BU_: ECM
1494
1495BO_ 256 Engine : 8 ECM
1496"#,
1497 )
1498 .unwrap();
1499
1500 let frame =
1502 TestFrame::new_standard(512, &[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
1503 let result = dbc.decode_frame(frame);
1504 assert!(result.is_err());
1505 }
1506 }
1507}