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 dlc = message.dlc() as usize;
224 if payload.len() < dlc {
225 return Err(Error::Decoding(Error::PAYLOAD_LENGTH_MISMATCH));
226 }
227
228 let mut decoded_signals: Vec<DecodedSignal<'_>, { MAX_SIGNALS_PER_MESSAGE }> = Vec::new();
230
231 let mut switch_values = SwitchValues::<'_>::new();
233
234 let signals = message.signals();
235
236 let message_has_extended_mux = !self.extended_multiplexing.is_empty()
240 && self.has_extended_multiplexing_for_message(id);
241
242 let has_any_value_descriptions = !self.value_descriptions.is_empty();
245
246 for signal in signals.iter() {
249 if signal.is_multiplexer_switch() {
250 let (raw_value, physical_value) = signal.decode_raw(payload)?;
252
253 if raw_value < 0 {
255 return Err(Error::Decoding(Error::MULTIPLEXER_SWITCH_NEGATIVE));
256 }
257
258 switch_values.push(signal.name(), raw_value as u64)?;
260
261 let description = if has_any_value_descriptions {
263 self.value_descriptions_for_signal(id, signal.name())
264 .and_then(|vd| vd.get(raw_value as u64))
265 } else {
266 None
267 };
268
269 decoded_signals
271 .push(DecodedSignal::new(
272 signal.name(),
273 physical_value,
274 raw_value,
275 signal.min(),
276 signal.max(),
277 signal.unit(),
278 description,
279 ))
280 .map_err(|_| Error::Decoding(Error::MESSAGE_TOO_MANY_SIGNALS))?;
281 }
282 }
283
284 for signal in signals.iter() {
286 if signal.is_multiplexer_switch() {
288 continue;
289 }
290
291 let should_decode = if let Some(mux_value) = signal.multiplexer_switch_value() {
293 if message_has_extended_mux {
295 self.check_extended_multiplexing(id, signal.name(), &switch_values)
297 .unwrap_or_else(|| {
298 switch_values.any_has_value(mux_value)
300 })
301 } else {
302 switch_values.any_has_value(mux_value)
304 }
305 } else {
306 true
308 };
309
310 if should_decode {
311 let (raw_value, physical_value) = signal.decode_raw(payload)?;
313
314 let description = if has_any_value_descriptions {
316 self.value_descriptions_for_signal(id, signal.name())
317 .and_then(|vd| vd.get(raw_value as u64))
318 } else {
319 None
320 };
321
322 decoded_signals
323 .push(DecodedSignal::new(
324 signal.name(),
325 physical_value,
326 raw_value,
327 signal.min(),
328 signal.max(),
329 signal.unit(),
330 description,
331 ))
332 .map_err(|_| Error::Decoding(Error::MESSAGE_TOO_MANY_SIGNALS))?;
333 }
334 }
335
336 Ok(decoded_signals)
337 }
338
339 #[inline]
343 fn check_extended_multiplexing(
344 &self,
345 message_id: u32,
346 signal_name: &str,
347 switch_values: &SwitchValues,
348 ) -> Option<bool> {
349 let indices = self.ext_mux_index.get(message_id, signal_name)?;
351 if indices.is_empty() {
352 return None;
353 }
354
355 let mut unique_switches: [Option<&str>; MAX_SWITCHES] = [None; MAX_SWITCHES];
360 let mut unique_count = 0;
361
362 for &idx in indices {
363 if let Some(entry) = self.extended_multiplexing.get(idx) {
364 let switch_name = entry.multiplexer_switch();
365 let found =
367 unique_switches.iter().take(unique_count).any(|&s| s == Some(switch_name));
368 if !found && unique_count < MAX_SWITCHES {
369 unique_switches[unique_count] = Some(switch_name);
370 unique_count += 1;
371 }
372 }
373 }
374
375 for switch_opt in unique_switches.iter().take(unique_count) {
377 let switch_name = match switch_opt {
378 Some(name) => *name,
379 None => continue,
380 };
381
382 let switch_val = match switch_values.get_by_name(switch_name) {
384 Some(v) => v,
385 None => return Some(false), };
387
388 let mut has_match = false;
390 for &idx in indices {
391 if let Some(entry) = self.extended_multiplexing.get(idx) {
392 if entry.multiplexer_switch() == switch_name {
393 for &(min, max) in entry.value_ranges() {
394 if switch_val >= min && switch_val <= max {
395 has_match = true;
396 break;
397 }
398 }
399 if has_match {
400 break;
401 }
402 }
403 }
404 }
405
406 if !has_match {
407 return Some(false); }
409 }
410
411 Some(true) }
413
414 #[inline]
417 fn has_extended_multiplexing_for_message(&self, message_id: u32) -> bool {
418 self.extended_multiplexing
419 .iter()
420 .any(|ext_mux| ext_mux.message_id() == message_id)
421 }
422
423 #[cfg(feature = "embedded-can")]
470 #[inline]
471 pub fn decode_frame<T: Frame>(
472 &self,
473 frame: T,
474 ) -> Result<Vec<DecodedSignal<'_>, { MAX_SIGNALS_PER_MESSAGE }>> {
475 let payload = frame.data();
476 match frame.id() {
477 Id::Standard(id) => self.decode(id.as_raw() as u32, payload, false),
478 Id::Extended(id) => self.decode(id.as_raw(), payload, true),
479 }
480 }
481}
482
483#[cfg(test)]
484mod tests {
485 use crate::Dbc;
486
487 #[test]
488 fn test_decode_basic() {
489 let dbc = Dbc::parse(
490 r#"VERSION "1.0"
491
492BU_: ECM
493
494BO_ 256 Engine : 8 ECM
495 SG_ RPM : 0|16@1+ (0.25,0) [0|8000] "rpm" *
496"#,
497 )
498 .unwrap();
499
500 let payload = [0x40, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
502 let decoded = dbc.decode(256, &payload, false).unwrap();
503 assert_eq!(decoded.len(), 1);
504 assert_eq!(decoded[0].name, "RPM");
505 assert_eq!(decoded[0].value, 2000.0);
506 assert_eq!(decoded[0].raw_value, 8000); assert_eq!(decoded[0].min, 0.0);
508 assert_eq!(decoded[0].max, 8000.0);
509 assert!(decoded[0].is_in_range());
510 assert_eq!(decoded[0].unit, Some("rpm"));
511 }
512
513 #[test]
514 fn test_decode_message_not_found() {
515 let dbc = Dbc::parse(
516 r#"VERSION "1.0"
517
518BU_: ECM
519
520BO_ 256 Engine : 8 ECM
521"#,
522 )
523 .unwrap();
524
525 let payload = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
526 let result = dbc.decode(512, &payload, false);
527 assert!(result.is_err());
528 }
529
530 #[test]
531 fn test_decode_message() {
532 let data = r#"VERSION "1.0"
533
534BU_: ECM
535
536BO_ 256 Engine : 8 ECM
537 SG_ RPM : 0|16@1+ (0.25,0) [0|8000] "rpm" *
538 SG_ Temp : 16|8@1- (1,-40) [-40|215] "°C" *
539"#;
540
541 let dbc = Dbc::parse(data).unwrap();
542
543 let payload = [0x40, 0x1F, 0x5A, 0x00, 0x00, 0x00, 0x00, 0x00];
546 let decoded = dbc.decode(256, &payload, false).unwrap();
547
548 assert_eq!(decoded.len(), 2);
549 assert_eq!(decoded[0].name, "RPM");
550 assert_eq!(decoded[0].value, 2000.0);
551 assert_eq!(decoded[0].unit, Some("rpm"));
552 assert_eq!(decoded[1].name, "Temp");
553 assert_eq!(decoded[1].value, 50.0);
554 assert_eq!(decoded[1].unit, Some("°C"));
555 }
556
557 #[test]
558 fn test_decode_payload_length_mismatch() {
559 use crate::Error;
560 let data = r#"VERSION "1.0"
561
562BU_: ECM
563
564BO_ 256 Engine : 8 ECM
565 SG_ RPM : 0|16@1+ (0.25,0) [0|8000] "rpm" *
566"#;
567
568 let dbc = Dbc::parse(data).unwrap();
569
570 let payload = [0x40, 0x1F, 0x00, 0x00];
572 let result = dbc.decode(256, &payload, false);
573 assert!(result.is_err());
574 match result.unwrap_err() {
575 Error::Decoding(msg) => {
576 assert!(msg.contains(Error::PAYLOAD_LENGTH_MISMATCH));
577 }
578 _ => panic!("Expected Error::Decoding"),
579 }
580 }
581
582 #[test]
583 fn test_decode_big_endian_signal() {
584 let data = r#"VERSION "1.0"
585
586BU_: ECM
587
588BO_ 256 Engine : 8 ECM
589 SG_ RPM : 0|16@0+ (1.0,0) [0|65535] "rpm" *
590"#;
591
592 let dbc = Dbc::parse(data).unwrap();
593
594 let payload = [0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
598 let decoded = dbc.decode(256, &payload, false).unwrap();
599
600 assert_eq!(decoded.len(), 1);
601 assert_eq!(decoded[0].name, "RPM");
602 assert!(decoded[0].value >= 0.0);
605 assert_eq!(decoded[0].unit, Some("rpm"));
606 }
607
608 #[test]
609 fn test_decode_multiplexed_signal() {
610 let dbc = Dbc::parse(
611 r#"VERSION "1.0"
612
613BU_: ECM
614
615BO_ 256 Engine : 8 ECM
616 SG_ MuxId M : 0|8@1+ (1,0) [0|255] ""
617 SG_ Signal0 m0 : 8|16@1+ (0.1,0) [0|6553.5] "unit" *
618 SG_ Signal1 m1 : 24|16@1+ (0.01,0) [0|655.35] "unit" *
619 SG_ NormalSignal : 40|8@1+ (1,0) [0|255] ""
620"#,
621 )
622 .unwrap();
623
624 let payload = [0x00, 0x64, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00];
626 let decoded = dbc.decode(256, &payload, false).unwrap();
629
630 let find_signal = |name: &str| decoded.iter().find(|s| s.name == name).map(|s| s.value);
632
633 assert!(find_signal("MuxId").is_some());
635 assert!(find_signal("Signal0").is_some());
637 assert!(find_signal("Signal1").is_none());
639 assert!(find_signal("NormalSignal").is_some());
641 }
642
643 #[test]
644 fn test_decode_multiplexed_signal_switch_one() {
645 let dbc = Dbc::parse(
646 r#"VERSION "1.0"
647
648BU_: ECM
649
650BO_ 256 Engine : 8 ECM
651 SG_ MuxId M : 0|8@1+ (1,0) [0|255] ""
652 SG_ Signal0 m0 : 8|16@1+ (0.1,0) [0|6553.5] "unit" *
653 SG_ Signal1 m1 : 24|16@1+ (0.01,0) [0|655.35] "unit" *
654"#,
655 )
656 .unwrap();
657
658 let payload = [0x01, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00];
660 let decoded = dbc.decode(256, &payload, false).unwrap();
663
664 let find_signal = |name: &str| decoded.iter().find(|s| s.name == name).map(|s| s.value);
666
667 assert_eq!(find_signal("MuxId"), Some(1.0));
669 assert!(find_signal("Signal0").is_none());
671 assert!(find_signal("Signal1").is_some());
673 }
674
675 #[test]
676 fn test_decode_mixed_byte_order() {
677 let dbc = Dbc::parse(
678 r#"VERSION "1.0"
679
680BU_: ECM
681
682BO_ 256 MixedByteOrder : 8 ECM
683 SG_ LittleEndianSignal : 0|16@1+ (1.0,0) [0|65535] ""
684 SG_ BigEndianSignal : 23|16@0+ (1.0,0) [0|65535] ""
685 SG_ AnotherLittleEndian : 32|8@1+ (1.0,0) [0|255] ""
686 SG_ AnotherBigEndian : 47|8@0+ (1.0,0) [0|255] ""
687"#,
688 )
689 .unwrap();
690
691 let payload = [
697 0x34, 0x12, 0x00, 0x01, 0xAB, 0xCD, 0x00, 0x00, ];
703 let decoded = dbc.decode(256, &payload, false).unwrap();
704
705 let find_signal = |name: &str| decoded.iter().find(|s| s.name == name).map(|s| s.value);
707
708 assert_eq!(find_signal("LittleEndianSignal"), Some(4660.0)); let big_endian_value = find_signal("BigEndianSignal").unwrap();
713 assert!((0.0..=65535.0).contains(&big_endian_value));
715
716 assert_eq!(find_signal("AnotherLittleEndian"), Some(171.0)); let big_endian_8bit = find_signal("AnotherBigEndian");
721 assert!(big_endian_8bit.is_some());
722 assert!(big_endian_8bit.unwrap() >= 0.0 && big_endian_8bit.unwrap() <= 255.0);
723
724 assert_eq!(decoded.len(), 4);
726
727 assert!(find_signal("LittleEndianSignal").is_some());
729 assert!(find_signal("BigEndianSignal").is_some());
730 }
731
732 #[test]
733 fn test_decode_extended_multiplexing_simple() {
734 let dbc = Dbc::parse(
735 r#"VERSION "1.0"
736
737BU_: ECM
738
739BO_ 500 ComplexMux : 8 ECM
740 SG_ Mux1 M : 0|8@1+ (1,0) [0|255] ""
741 SG_ Signal_A m0 : 16|16@1+ (0.1,0) [0|100] "unit" *
742
743SG_MUL_VAL_ 500 Signal_A Mux1 5-10 ;
744"#,
745 )
746 .unwrap();
747
748 let payload = [0x05, 0x00, 0xE8, 0x03, 0x00, 0x00, 0x00, 0x00];
752 let decoded = dbc.decode(500, &payload, false).unwrap();
753
754 let find_signal = |name: &str| decoded.iter().find(|s| s.name == name).map(|s| s.value);
755
756 assert_eq!(find_signal("Mux1"), Some(5.0));
757 assert_eq!(
759 dbc.extended_multiplexing_for_message(500).count(),
760 1,
761 "Extended multiplexing entries should be parsed"
762 );
763 assert!(
764 find_signal("Signal_A").is_some(),
765 "Signal_A should be decoded when Mux1=5 (within range 5-10)"
766 );
767 assert_eq!(find_signal("Signal_A").unwrap(), 100.0);
768
769 let payload2 = [0x0F, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00];
771 let decoded2 = dbc.decode(500, &payload2, false).unwrap();
772 let find_signal2 = |name: &str| decoded2.iter().find(|s| s.name == name).map(|s| s.value);
773
774 assert_eq!(find_signal2("Mux1"), Some(15.0));
775 assert!(find_signal2("Signal_A").is_none());
776 }
777
778 #[test]
779 fn test_decode_extended_multiplexing_multiple_ranges() {
780 let dbc = Dbc::parse(
781 r#"VERSION "1.0"
782
783BU_: ECM
784
785BO_ 501 MultiRangeMux : 8 ECM
786 SG_ Mux1 M : 0|8@1+ (1,0) [0|255] ""
787 SG_ Signal_B m0 : 16|16@1+ (1,0) [0|65535] "unit" *
788
789SG_MUL_VAL_ 501 Signal_B Mux1 0-5,10-15,20-25 ;
790"#,
791 )
792 .unwrap();
793
794 let payload1 = [0x03, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00];
797 let decoded1 = dbc.decode(501, &payload1, false).unwrap();
798 let find1 = |name: &str| decoded1.iter().find(|s| s.name == name).map(|s| s.value);
799 assert_eq!(find1("Mux1"), Some(3.0));
800 assert!(find1("Signal_B").is_some());
801
802 let payload2 = [0x0C, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00];
805 let decoded2 = dbc.decode(501, &payload2, false).unwrap();
806 let find2 = |name: &str| decoded2.iter().find(|s| s.name == name).map(|s| s.value);
807 assert_eq!(find2("Mux1"), Some(12.0));
808 assert!(find2("Signal_B").is_some());
809
810 let payload3 = [0x16, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00];
813 let decoded3 = dbc.decode(501, &payload3, false).unwrap();
814 let find3 = |name: &str| decoded3.iter().find(|s| s.name == name).map(|s| s.value);
815 assert_eq!(find3("Mux1"), Some(22.0));
816 assert!(find3("Signal_B").is_some());
817
818 let payload4 = [0x08, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00];
821 let decoded4 = dbc.decode(501, &payload4, false).unwrap();
822 let find4 = |name: &str| decoded4.iter().find(|s| s.name == name).map(|s| s.value);
823 assert_eq!(find4("Mux1"), Some(8.0));
824 assert!(find4("Signal_B").is_none());
825 }
826
827 #[test]
830 fn test_decode_extended_multiplexing_multiple_switches() {
831 let dbc = Dbc::parse(
832 r#"VERSION "1.0"
833
834BU_: ECM
835
836BO_ 502 MultiSwitchMux : 8 ECM
837 SG_ Mux1 M : 0|8@1+ (1,0) [0|255] ""
838 SG_ Mux2 M : 8|8@1+ (1,0) [0|255] ""
839 SG_ Signal_C m0 : 16|16@1+ (1,0) [0|65535] "unit" *
840
841SG_MUL_VAL_ 502 Signal_C Mux1 5-10 ;
842SG_MUL_VAL_ 502 Signal_C Mux2 20-25 ;
843"#,
844 )
845 .unwrap();
846
847 let payload1 = [0x07, 0x16, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00];
850 let decoded1 = dbc.decode(502, &payload1, false).unwrap();
851 let find1 = |name: &str| decoded1.iter().find(|s| s.name == name).map(|s| s.value);
852 assert_eq!(find1("Mux1"), Some(7.0));
853 assert_eq!(find1("Mux2"), Some(22.0));
854 assert!(find1("Signal_C").is_some());
855
856 let payload2 = [0x07, 0x1E, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00];
858 let decoded2 = dbc.decode(502, &payload2, false).unwrap();
859 let find2 = |name: &str| decoded2.iter().find(|s| s.name == name).map(|s| s.value);
860 assert_eq!(find2("Mux1"), Some(7.0));
861 assert_eq!(find2("Mux2"), Some(30.0));
862 assert!(find2("Signal_C").is_none());
863
864 let payload3 = [0x0F, 0x16, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00];
866 let decoded3 = dbc.decode(502, &payload3, false).unwrap();
867 let find3 = |name: &str| decoded3.iter().find(|s| s.name == name).map(|s| s.value);
868 assert_eq!(find3("Mux1"), Some(15.0));
869 assert_eq!(find3("Mux2"), Some(22.0));
870 assert!(find3("Signal_C").is_none());
871 }
872
873 #[test]
876 fn test_decode_extended_multiplexing_takes_precedence() {
877 let dbc = Dbc::parse(
878 r#"VERSION "1.0"
879
880BU_: ECM
881
882BO_ 503 PrecedenceTest : 8 ECM
883 SG_ Mux1 M : 0|8@1+ (1,0) [0|255] ""
884 SG_ Signal_D m0 : 16|16@1+ (1,0) [0|65535] "unit" *
885
886SG_MUL_VAL_ 503 Signal_D Mux1 10-15 ;
887"#,
888 )
889 .unwrap();
890
891 let payload1 = [0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00];
895 let decoded1 = dbc.decode(503, &payload1, false).unwrap();
896 let find1 = |name: &str| decoded1.iter().find(|s| s.name == name).map(|s| s.value);
897 assert_eq!(find1("Mux1"), Some(0.0));
898 assert!(find1("Signal_D").is_none());
899
900 let payload2 = [0x0C, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x00];
902 let decoded2 = dbc.decode(503, &payload2, false).unwrap();
903 let find2 = |name: &str| decoded2.iter().find(|s| s.name == name).map(|s| s.value);
904 assert_eq!(find2("Mux1"), Some(12.0));
905 assert!(find2("Signal_D").is_some());
906 }
907
908 #[test]
911 fn test_decode_extended_multiplexing_with_extended_mux_signal() {
912 let dbc = Dbc::parse(
914 r#"VERSION "1.0"
915
916BU_: ECM
917
918BO_ 504 ExtendedMuxSignal : 8 ECM
919 SG_ Mux1 M : 0|8@1+ (1,0) [0|255] ""
920 SG_ Mux2 m65M : 8|8@1+ (1,0) [0|255] ""
921 SG_ Signal_E m0 : 16|16@1+ (1,0) [0|65535] "unit" *
922
923SG_MUL_VAL_ 504 Signal_E Mux1 65-65 ;
924SG_MUL_VAL_ 504 Signal_E Mux2 10-15 ;
925"#,
926 )
927 .unwrap();
928
929 let payload = [0x41, 0x0C, 0x00, 0xA0, 0x00, 0x00, 0x00, 0x00];
932 let decoded = dbc.decode(504, &payload, false).unwrap();
934 let find = |name: &str| decoded.iter().find(|s| s.name == name).map(|s| s.value);
935
936 assert_eq!(find("Mux1"), Some(65.0));
937 assert_eq!(find("Mux2"), Some(12.0));
938 assert!(find("Signal_E").is_some());
939
940 let payload2 = [0x40, 0x0C, 0x00, 0xB0, 0x00, 0x00, 0x00, 0x00];
942 let decoded2 = dbc.decode(504, &payload2, false).unwrap();
943 let find2 = |name: &str| decoded2.iter().find(|s| s.name == name).map(|s| s.value);
944 assert_eq!(find2("Mux1"), Some(64.0));
945 assert_eq!(find2("Mux2"), Some(12.0));
946 assert!(find2("Signal_E").is_none());
947 }
948
949 #[test]
950 fn test_decode_negative_multiplexer_switch() {
951 use crate::Error;
952 let dbc = Dbc::parse(
955 r#"VERSION "1.0"
956
957BU_: ECM
958
959BO_ 256 MuxMessage : 8 ECM
960 SG_ MuxSwitch M : 0|8@1- (1,0) [-128|127] ""
961 SG_ SignalA m0 : 8|8@1+ (1,0) [0|255] ""
962"#,
963 )
964 .unwrap();
965
966 let payload = [0xFB, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
970 let result = dbc.decode(256, &payload, false);
971 assert!(result.is_err());
972 match result.unwrap_err() {
973 Error::Decoding(msg) => {
974 assert_eq!(msg, Error::MULTIPLEXER_SWITCH_NEGATIVE);
975 }
976 _ => panic!("Expected Error::Decoding with MULTIPLEXER_SWITCH_NEGATIVE"),
977 }
978 }
979
980 #[test]
981 fn test_decode_too_many_unique_switches() {
982 use crate::{Error, MAX_SIGNALS_PER_MESSAGE};
983 if MAX_SIGNALS_PER_MESSAGE < 17 {
986 return;
987 }
988
989 let dbc_str = r#"VERSION "1.0"
993
994BU_: ECM
995
996BO_ 600 TooManySwitches : 18 ECM
997 SG_ Mux1 M : 0|8@1+ (1,0) [0|255] ""
998 SG_ Mux2 M : 8|8@1+ (1,0) [0|255] ""
999 SG_ Mux3 M : 16|8@1+ (1,0) [0|255] ""
1000 SG_ Mux4 M : 24|8@1+ (1,0) [0|255] ""
1001 SG_ Mux5 M : 32|8@1+ (1,0) [0|255] ""
1002 SG_ Mux6 M : 40|8@1+ (1,0) [0|255] ""
1003 SG_ Mux7 M : 48|8@1+ (1,0) [0|255] ""
1004 SG_ Mux8 M : 56|8@1+ (1,0) [0|255] ""
1005 SG_ Mux9 M : 64|8@1+ (1,0) [0|255] ""
1006 SG_ Mux10 M : 72|8@1+ (1,0) [0|255] ""
1007 SG_ Mux11 M : 80|8@1+ (1,0) [0|255] ""
1008 SG_ Mux12 M : 88|8@1+ (1,0) [0|255] ""
1009 SG_ Mux13 M : 96|8@1+ (1,0) [0|255] ""
1010 SG_ Mux14 M : 104|8@1+ (1,0) [0|255] ""
1011 SG_ Mux15 M : 112|8@1+ (1,0) [0|255] ""
1012 SG_ Mux16 M : 120|8@1+ (1,0) [0|255] ""
1013 SG_ Mux17 M : 128|8@1+ (1,0) [0|255] ""
1014 SG_ Signal_X m0 : 136|8@1+ (1,0) [0|255] "unit" *
1015
1016SG_MUL_VAL_ 600 Signal_X Mux1 0-255 ;
1017SG_MUL_VAL_ 600 Signal_X Mux2 0-255 ;
1018SG_MUL_VAL_ 600 Signal_X Mux3 0-255 ;
1019SG_MUL_VAL_ 600 Signal_X Mux4 0-255 ;
1020SG_MUL_VAL_ 600 Signal_X Mux5 0-255 ;
1021SG_MUL_VAL_ 600 Signal_X Mux6 0-255 ;
1022SG_MUL_VAL_ 600 Signal_X Mux7 0-255 ;
1023SG_MUL_VAL_ 600 Signal_X Mux8 0-255 ;
1024SG_MUL_VAL_ 600 Signal_X Mux9 0-255 ;
1025SG_MUL_VAL_ 600 Signal_X Mux10 0-255 ;
1026SG_MUL_VAL_ 600 Signal_X Mux11 0-255 ;
1027SG_MUL_VAL_ 600 Signal_X Mux12 0-255 ;
1028SG_MUL_VAL_ 600 Signal_X Mux13 0-255 ;
1029SG_MUL_VAL_ 600 Signal_X Mux14 0-255 ;
1030SG_MUL_VAL_ 600 Signal_X Mux15 0-255 ;
1031SG_MUL_VAL_ 600 Signal_X Mux16 0-255 ;
1032SG_MUL_VAL_ 600 Signal_X Mux17 0-255 ;
1033"#;
1034
1035 let dbc = Dbc::parse(dbc_str).unwrap();
1036
1037 let payload = [0x00; 18];
1040 let result = dbc.decode(600, &payload, false);
1041 assert!(
1042 result.is_err(),
1043 "Decode should fail when there are more than 16 unique switches"
1044 );
1045 match result.unwrap_err() {
1046 Error::Decoding(msg) => {
1047 assert_eq!(
1048 msg,
1049 Error::MESSAGE_TOO_MANY_SIGNALS,
1050 "Expected MESSAGE_TOO_MANY_SIGNALS error, got: {}",
1051 msg
1052 );
1053 }
1054 e => panic!(
1055 "Expected Error::Decoding with MESSAGE_TOO_MANY_SIGNALS, got: {:?}",
1056 e
1057 ),
1058 }
1059 }
1060
1061 #[test]
1062 fn test_decode_extended_can_id() {
1063 let dbc = Dbc::parse(
1067 r#"VERSION "1.0"
1068
1069BU_: ECM
1070
1071BO_ 2147484672 ExtendedMsg : 8 ECM
1072 SG_ Speed : 0|16@1+ (0.1,0) [0|6553.5] "km/h" *
1073"#,
1074 )
1075 .unwrap();
1076 let payload = [0xE8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
1079 let decoded = dbc.decode(0x400, &payload, true).unwrap();
1083 assert_eq!(decoded.len(), 1);
1084 assert_eq!(decoded[0].name, "Speed");
1085 assert_eq!(decoded[0].value, 100.0);
1086 assert_eq!(decoded[0].unit, Some("km/h"));
1087 }
1088
1089 #[test]
1090 fn test_decode_extended_can_id_not_found_without_flag() {
1091 let dbc = Dbc::parse(
1094 r#"VERSION "1.0"
1095
1096BU_: ECM
1097
1098BO_ 2147484672 ExtendedMsg : 8 ECM
1099 SG_ Speed : 0|16@1+ (0.1,0) [0|6553.5] "km/h" *
1100"#,
1101 )
1102 .unwrap();
1103
1104 let payload = [0xE8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
1105
1106 let result = dbc.decode(0x400, &payload, false);
1108 assert!(result.is_err());
1109 }
1110
1111 #[test]
1112 fn test_decode_standard_vs_extended_same_base_id() {
1113 let dbc = Dbc::parse(
1115 r#"VERSION "1.0"
1116
1117BU_: ECM
1118
1119BO_ 256 StandardMsg : 8 ECM
1120 SG_ StdSignal : 0|8@1+ (1,0) [0|255] "" *
1121
1122BO_ 2147483904 ExtendedMsg : 8 ECM
1123 SG_ ExtSignal : 0|8@1+ (2,0) [0|510] "" *
1124"#,
1125 )
1126 .unwrap();
1127 let payload = [0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; let decoded_std = dbc.decode(256, &payload, false).unwrap();
1133 assert_eq!(decoded_std.len(), 1);
1134 assert_eq!(decoded_std[0].name, "StdSignal");
1135 assert_eq!(decoded_std[0].value, 100.0); let decoded_ext = dbc.decode(256, &payload, true).unwrap();
1139 assert_eq!(decoded_ext.len(), 1);
1140 assert_eq!(decoded_ext[0].name, "ExtSignal");
1141 assert_eq!(decoded_ext[0].value, 200.0); }
1143
1144 #[test]
1145 fn test_decode_with_value_descriptions() {
1146 let dbc = Dbc::parse(
1149 r#"VERSION "1.0"
1150
1151BU_: ECM
1152
1153BO_ 200 GearboxData : 4 ECM
1154 SG_ GearActual : 0|8@1+ (1,0) [0|5] "" *
1155
1156VAL_ 200 GearActual 0 "Park" 1 "Reverse" 2 "Neutral" 3 "Drive" 4 "Sport" 5 "Manual" ;
1157"#,
1158 )
1159 .unwrap();
1160
1161 let payload = [0x00, 0x00, 0x00, 0x00];
1163 let decoded = dbc.decode(200, &payload, false).unwrap();
1164 assert_eq!(decoded.len(), 1);
1165 assert_eq!(decoded[0].name, "GearActual");
1166 assert_eq!(decoded[0].value, 0.0);
1167 assert_eq!(decoded[0].description, Some("Park"));
1168
1169 let payload = [0x03, 0x00, 0x00, 0x00];
1171 let decoded = dbc.decode(200, &payload, false).unwrap();
1172 assert_eq!(decoded[0].value, 3.0);
1173 assert_eq!(decoded[0].description, Some("Drive"));
1174
1175 let payload = [0x05, 0x00, 0x00, 0x00];
1177 let decoded = dbc.decode(200, &payload, false).unwrap();
1178 assert_eq!(decoded[0].value, 5.0);
1179 assert_eq!(decoded[0].description, Some("Manual"));
1180 }
1181
1182 #[test]
1183 fn test_decode_without_value_descriptions() {
1184 let dbc = Dbc::parse(
1186 r#"VERSION "1.0"
1187
1188BU_: ECM
1189
1190BO_ 256 Engine : 8 ECM
1191 SG_ RPM : 0|16@1+ (0.25,0) [0|8000] "rpm" *
1192"#,
1193 )
1194 .unwrap();
1195
1196 let payload = [0x40, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
1197 let decoded = dbc.decode(256, &payload, false).unwrap();
1198 assert_eq!(decoded.len(), 1);
1199 assert_eq!(decoded[0].name, "RPM");
1200 assert_eq!(decoded[0].value, 2000.0);
1201 assert_eq!(decoded[0].unit, Some("rpm"));
1202 assert_eq!(decoded[0].description, None);
1203 }
1204
1205 #[test]
1206 fn test_decode_value_description_not_found() {
1207 let dbc = Dbc::parse(
1209 r#"VERSION "1.0"
1210
1211BU_: ECM
1212
1213BO_ 200 GearboxData : 4 ECM
1214 SG_ GearActual : 0|8@1+ (1,0) [0|255] "" *
1215
1216VAL_ 200 GearActual 0 "Park" 1 "Reverse" 2 "Neutral" ;
1217"#,
1218 )
1219 .unwrap();
1220
1221 let payload = [0x0A, 0x00, 0x00, 0x00];
1223 let decoded = dbc.decode(200, &payload, false).unwrap();
1224 assert_eq!(decoded.len(), 1);
1225 assert_eq!(decoded[0].value, 10.0);
1226 assert_eq!(decoded[0].description, None); }
1228
1229 #[test]
1230 fn test_decode_multiplexer_with_value_descriptions() {
1231 let dbc = Dbc::parse(
1234 r#"VERSION "1.0"
1235
1236BU_: ECM
1237
1238BO_ 300 MultiplexedSensors : 8 ECM
1239 SG_ SensorID M : 0|8@1+ (1,0) [0|3] "" *
1240 SG_ Temperature m0 : 8|16@1- (0.1,-40) [-40|125] "°C" *
1241 SG_ Pressure m1 : 8|16@1+ (0.01,0) [0|655.35] "kPa" *
1242
1243VAL_ 300 SensorID 0 "Temperature Sensor" 1 "Pressure Sensor" 2 "Humidity Sensor" 3 "Voltage Sensor" ;
1244"#,
1245 )
1246 .unwrap();
1247
1248 let payload = [0x00, 0xF4, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00];
1251 let decoded = dbc.decode(300, &payload, false).unwrap();
1252
1253 let sensor_id = decoded.iter().find(|s| s.name == "SensorID").unwrap();
1255 assert_eq!(sensor_id.value, 0.0);
1256 assert_eq!(sensor_id.description, Some("Temperature Sensor"));
1257
1258 let temp = decoded.iter().find(|s| s.name == "Temperature").unwrap();
1260 assert!(temp.description.is_none()); let payload = [0x01, 0x10, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00];
1264 let decoded = dbc.decode(300, &payload, false).unwrap();
1265
1266 let sensor_id = decoded.iter().find(|s| s.name == "SensorID").unwrap();
1267 assert_eq!(sensor_id.value, 1.0);
1268 assert_eq!(sensor_id.description, Some("Pressure Sensor"));
1269 }
1270
1271 #[cfg(feature = "embedded-can")]
1272 mod embedded_can_tests {
1273 use super::*;
1274 use embedded_can::{ExtendedId, Frame, Id, StandardId};
1275
1276 struct TestFrame {
1278 id: Id,
1279 data: [u8; 8],
1280 dlc: usize,
1281 }
1282
1283 impl TestFrame {
1284 fn new_standard(id: u16, data: &[u8]) -> Self {
1285 let mut frame_data = [0u8; 8];
1286 let dlc = data.len().min(8);
1287 frame_data[..dlc].copy_from_slice(&data[..dlc]);
1288 Self {
1289 id: Id::Standard(StandardId::new(id).unwrap()),
1290 data: frame_data,
1291 dlc,
1292 }
1293 }
1294
1295 fn new_extended(id: u32, data: &[u8]) -> Self {
1296 let mut frame_data = [0u8; 8];
1297 let dlc = data.len().min(8);
1298 frame_data[..dlc].copy_from_slice(&data[..dlc]);
1299 Self {
1300 id: Id::Extended(ExtendedId::new(id).unwrap()),
1301 data: frame_data,
1302 dlc,
1303 }
1304 }
1305 }
1306
1307 impl Frame for TestFrame {
1308 fn new(id: impl Into<Id>, data: &[u8]) -> Option<Self> {
1309 let mut frame_data = [0u8; 8];
1310 let dlc = data.len().min(8);
1311 frame_data[..dlc].copy_from_slice(&data[..dlc]);
1312 Some(Self {
1313 id: id.into(),
1314 data: frame_data,
1315 dlc,
1316 })
1317 }
1318
1319 fn new_remote(_id: impl Into<Id>, _dlc: usize) -> Option<Self> {
1320 None }
1322
1323 fn is_extended(&self) -> bool {
1324 matches!(self.id, Id::Extended(_))
1325 }
1326
1327 fn is_remote_frame(&self) -> bool {
1328 false
1329 }
1330
1331 fn id(&self) -> Id {
1332 self.id
1333 }
1334
1335 fn dlc(&self) -> usize {
1336 self.dlc
1337 }
1338
1339 fn data(&self) -> &[u8] {
1340 &self.data[..self.dlc]
1341 }
1342 }
1343
1344 #[test]
1345 fn test_decode_frame_standard() {
1346 let dbc = Dbc::parse(
1347 r#"VERSION "1.0"
1348
1349BU_: ECM
1350
1351BO_ 256 Engine : 8 ECM
1352 SG_ RPM : 0|16@1+ (0.25,0) [0|8000] "rpm" *
1353"#,
1354 )
1355 .unwrap();
1356
1357 let frame =
1359 TestFrame::new_standard(256, &[0x40, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
1360
1361 let decoded = dbc.decode_frame(frame).unwrap();
1362 assert_eq!(decoded.len(), 1);
1363 assert_eq!(decoded[0].name, "RPM");
1364 assert_eq!(decoded[0].value, 2000.0);
1365 assert_eq!(decoded[0].unit, Some("rpm"));
1366 }
1367
1368 #[test]
1369 fn test_decode_frame_extended() {
1370 let dbc = Dbc::parse(
1372 r#"VERSION "1.0"
1373
1374BU_: ECM
1375
1376BO_ 2147484672 ExtendedMsg : 8 ECM
1377 SG_ Speed : 0|16@1+ (0.1,0) [0|6553.5] "km/h" *
1378"#,
1379 )
1380 .unwrap();
1381 let frame =
1385 TestFrame::new_extended(0x400, &[0xE8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
1386
1387 let decoded = dbc.decode_frame(frame).unwrap();
1388 assert_eq!(decoded.len(), 1);
1389 assert_eq!(decoded[0].name, "Speed");
1390 assert_eq!(decoded[0].value, 100.0);
1391 assert_eq!(decoded[0].unit, Some("km/h"));
1392 }
1393
1394 #[test]
1395 fn test_decode_frame_standard_vs_extended() {
1396 let dbc = Dbc::parse(
1398 r#"VERSION "1.0"
1399
1400BU_: ECM
1401
1402BO_ 256 StandardMsg : 8 ECM
1403 SG_ StdSignal : 0|8@1+ (1,0) [0|255] "" *
1404
1405BO_ 2147483904 ExtendedMsg : 8 ECM
1406 SG_ ExtSignal : 0|8@1+ (2,0) [0|510] "" *
1407"#,
1408 )
1409 .unwrap();
1410 let payload = [0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; let std_frame = TestFrame::new_standard(256, &payload);
1416 let decoded_std = dbc.decode_frame(std_frame).unwrap();
1417 assert_eq!(decoded_std[0].name, "StdSignal");
1418 assert_eq!(decoded_std[0].value, 100.0);
1419
1420 let ext_frame = TestFrame::new_extended(256, &payload);
1422 let decoded_ext = dbc.decode_frame(ext_frame).unwrap();
1423 assert_eq!(decoded_ext[0].name, "ExtSignal");
1424 assert_eq!(decoded_ext[0].value, 200.0);
1425 }
1426
1427 #[test]
1428 fn test_decode_frame_message_not_found() {
1429 let dbc = Dbc::parse(
1430 r#"VERSION "1.0"
1431
1432BU_: ECM
1433
1434BO_ 256 Engine : 8 ECM
1435"#,
1436 )
1437 .unwrap();
1438
1439 let frame =
1441 TestFrame::new_standard(512, &[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
1442 let result = dbc.decode_frame(frame);
1443 assert!(result.is_err());
1444 }
1445 }
1446}