1mod switch_values;
2pub(crate) use switch_values::SwitchValues;
3
4use crate::{Dbc, Error, MAX_SIGNALS_PER_MESSAGE, Message, Result, compat::Vec};
5#[cfg(feature = "embedded-can")]
6use embedded_can::{Frame, Id};
7
8#[derive(Debug, Clone, PartialEq)]
12pub struct DecodedSignal<'a> {
13 pub name: &'a str,
15 pub value: f64,
17 pub raw_value: i64,
20 pub min: f64,
22 pub max: f64,
24 pub unit: Option<&'a str>,
26 pub description: Option<&'a str>,
29}
30
31impl<'a> DecodedSignal<'a> {
32 #[inline]
57 pub fn new(
58 name: &'a str,
59 value: f64,
60 raw_value: i64,
61 min: f64,
62 max: f64,
63 unit: Option<&'a str>,
64 description: Option<&'a str>,
65 ) -> Self {
66 Self {
67 name,
68 value,
69 raw_value,
70 min,
71 max,
72 unit,
73 description,
74 }
75 }
76
77 #[inline]
91 pub fn is_in_range(&self) -> bool {
92 self.value >= self.min && self.value <= self.max
93 }
94}
95
96const MAX_SWITCHES: usize = 8;
99
100impl Dbc {
102 #[inline]
149 pub fn decode(
150 &self,
151 id: u32,
152 payload: &[u8],
153 is_extended: bool,
154 ) -> Result<Vec<DecodedSignal<'_>, { MAX_SIGNALS_PER_MESSAGE }>> {
155 let id = if is_extended {
157 id | Message::EXTENDED_ID_FLAG
158 } else {
159 id
160 };
161
162 let message = self
164 .messages()
165 .find_by_id(id)
166 .ok_or(Error::Decoding(Error::MESSAGE_NOT_FOUND))?;
167
168 let min_bytes = message.min_bytes_required() as usize;
172 if payload.len() < min_bytes {
173 return Err(Error::Decoding(Error::PAYLOAD_LENGTH_MISMATCH));
174 }
175
176 let mut decoded_signals: Vec<DecodedSignal<'_>, { MAX_SIGNALS_PER_MESSAGE }> = Vec::new();
178
179 let mut switch_values = SwitchValues::<'_>::new();
181
182 let signals = message.signals();
183
184 let message_has_extended_mux = !self.extended_multiplexing.is_empty()
188 && self.has_extended_multiplexing_for_message(id);
189
190 let has_any_value_descriptions = !self.value_descriptions.is_empty();
193
194 for signal in signals.iter() {
197 if signal.is_multiplexer_switch() {
198 let (raw_value, physical_value) = signal.decode_raw(payload)?;
200
201 if raw_value < 0 {
203 return Err(Error::Decoding(Error::MULTIPLEXER_SWITCH_NEGATIVE));
204 }
205
206 switch_values.push(signal.name(), raw_value as u64)?;
208
209 let description = if has_any_value_descriptions {
211 self.value_descriptions_for_signal(id, signal.name())
212 .and_then(|vd| vd.get(raw_value as u64))
213 } else {
214 None
215 };
216
217 decoded_signals
219 .push(DecodedSignal::new(
220 signal.name(),
221 physical_value,
222 raw_value,
223 signal.min(),
224 signal.max(),
225 signal.unit(),
226 description,
227 ))
228 .map_err(|_| Error::Decoding(Error::MESSAGE_TOO_MANY_SIGNALS))?;
229 }
230 }
231
232 for signal in signals.iter() {
234 if signal.is_multiplexer_switch() {
236 continue;
237 }
238
239 let should_decode = if let Some(mux_value) = signal.multiplexer_switch_value() {
241 if message_has_extended_mux {
243 self.check_extended_multiplexing(id, signal.name(), &switch_values)
245 .unwrap_or_else(|| {
246 switch_values.any_has_value(mux_value)
248 })
249 } else {
250 switch_values.any_has_value(mux_value)
252 }
253 } else {
254 true
256 };
257
258 if should_decode {
259 let (raw_value, physical_value) = signal.decode_raw(payload)?;
261
262 let description = if has_any_value_descriptions {
264 self.value_descriptions_for_signal(id, signal.name())
265 .and_then(|vd| vd.get(raw_value as u64))
266 } else {
267 None
268 };
269
270 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 Ok(decoded_signals)
285 }
286
287 #[inline]
291 fn check_extended_multiplexing(
292 &self,
293 message_id: u32,
294 signal_name: &str,
295 switch_values: &SwitchValues,
296 ) -> Option<bool> {
297 let indices = self.ext_mux_index.get(message_id, signal_name)?;
299 if indices.is_empty() {
300 return None;
301 }
302
303 let mut unique_switches: [Option<&str>; MAX_SWITCHES] = [None; MAX_SWITCHES];
308 let mut unique_count = 0;
309
310 for &idx in indices {
311 if let Some(entry) = self.extended_multiplexing.get(idx) {
312 let switch_name = entry.multiplexer_switch();
313 let found =
315 unique_switches.iter().take(unique_count).any(|&s| s == Some(switch_name));
316 if !found && unique_count < MAX_SWITCHES {
317 unique_switches[unique_count] = Some(switch_name);
318 unique_count += 1;
319 }
320 }
321 }
322
323 for switch_opt in unique_switches.iter().take(unique_count) {
325 let switch_name = match switch_opt {
326 Some(name) => *name,
327 None => continue,
328 };
329
330 let switch_val = match switch_values.get_by_name(switch_name) {
332 Some(v) => v,
333 None => return Some(false), };
335
336 let mut has_match = false;
338 for &idx in indices {
339 if let Some(entry) = self.extended_multiplexing.get(idx) {
340 if entry.multiplexer_switch() == switch_name {
341 for &(min, max) in entry.value_ranges() {
342 if switch_val >= min && switch_val <= max {
343 has_match = true;
344 break;
345 }
346 }
347 if has_match {
348 break;
349 }
350 }
351 }
352 }
353
354 if !has_match {
355 return Some(false); }
357 }
358
359 Some(true) }
361
362 #[inline]
365 fn has_extended_multiplexing_for_message(&self, message_id: u32) -> bool {
366 self.extended_multiplexing
367 .iter()
368 .any(|ext_mux| ext_mux.message_id() == message_id)
369 }
370
371 #[cfg(feature = "embedded-can")]
418 #[inline]
419 pub fn decode_frame<T: Frame>(
420 &self,
421 frame: T,
422 ) -> Result<Vec<DecodedSignal<'_>, { MAX_SIGNALS_PER_MESSAGE }>> {
423 let payload = frame.data();
424 match frame.id() {
425 Id::Standard(id) => self.decode(id.as_raw() as u32, payload, false),
426 Id::Extended(id) => self.decode(id.as_raw(), payload, true),
427 }
428 }
429}
430
431#[cfg(test)]
432mod tests {
433 use crate::Dbc;
434
435 #[test]
436 fn test_decode_basic() {
437 let dbc = Dbc::parse(
438 r#"VERSION "1.0"
439
440BU_: ECM
441
442BO_ 256 Engine : 8 ECM
443 SG_ RPM : 0|16@1+ (0.25,0) [0|8000] "rpm" *
444"#,
445 )
446 .unwrap();
447
448 let payload = [0x40, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
450 let decoded = dbc.decode(256, &payload, false).unwrap();
451 assert_eq!(decoded.len(), 1);
452 assert_eq!(decoded[0].name, "RPM");
453 assert_eq!(decoded[0].value, 2000.0);
454 assert_eq!(decoded[0].raw_value, 8000); assert_eq!(decoded[0].min, 0.0);
456 assert_eq!(decoded[0].max, 8000.0);
457 assert!(decoded[0].is_in_range());
458 assert_eq!(decoded[0].unit, Some("rpm"));
459 }
460
461 #[test]
462 fn test_decode_message_not_found() {
463 let dbc = Dbc::parse(
464 r#"VERSION "1.0"
465
466BU_: ECM
467
468BO_ 256 Engine : 8 ECM
469"#,
470 )
471 .unwrap();
472
473 let payload = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
474 let result = dbc.decode(512, &payload, false);
475 assert!(result.is_err());
476 }
477
478 #[test]
479 fn test_decode_message() {
480 let data = r#"VERSION "1.0"
481
482BU_: ECM
483
484BO_ 256 Engine : 8 ECM
485 SG_ RPM : 0|16@1+ (0.25,0) [0|8000] "rpm" *
486 SG_ Temp : 16|8@1- (1,-40) [-40|215] "°C" *
487"#;
488
489 let dbc = Dbc::parse(data).unwrap();
490
491 let payload = [0x40, 0x1F, 0x5A, 0x00, 0x00, 0x00, 0x00, 0x00];
494 let decoded = dbc.decode(256, &payload, false).unwrap();
495
496 assert_eq!(decoded.len(), 2);
497 assert_eq!(decoded[0].name, "RPM");
498 assert_eq!(decoded[0].value, 2000.0);
499 assert_eq!(decoded[0].unit, Some("rpm"));
500 assert_eq!(decoded[1].name, "Temp");
501 assert_eq!(decoded[1].value, 50.0);
502 assert_eq!(decoded[1].unit, Some("°C"));
503 }
504
505 #[test]
506 fn test_decode_payload_length_mismatch() {
507 use crate::Error;
508 let data = r#"VERSION "1.0"
509
510BU_: ECM
511
512BO_ 256 Engine : 8 ECM
513 SG_ RPM : 0|16@1+ (0.25,0) [0|8000] "rpm" *
514"#;
515
516 let dbc = Dbc::parse(data).unwrap();
517
518 let payload = [0x40];
521 let result = dbc.decode(256, &payload, false);
522 assert!(result.is_err());
523 match result.unwrap_err() {
524 Error::Decoding(msg) => {
525 assert!(msg.contains(Error::PAYLOAD_LENGTH_MISMATCH));
526 }
527 _ => panic!("Expected Error::Decoding"),
528 }
529
530 let payload = [0x40, 0x1F];
532 let result = dbc.decode(256, &payload, false);
533 assert!(result.is_ok());
534
535 let payload = [0x40, 0x1F, 0x00, 0x00];
537 let result = dbc.decode(256, &payload, false);
538 assert!(result.is_ok());
539 }
540
541 #[test]
542 fn test_decode_dlc_larger_than_signal_coverage() {
543 let data = r#"VERSION "1.0"
546
547BU_: ECM
548
549BO_ 1024 NewMessage : 8 ECM
550 SG_ Temp : 0|8@1+ (1,0) [0|255] "" ECM
551 SG_ Pressure : 8|8@1+ (1,0) [0|255] "" ECM
552 SG_ Heel : 16|4@1+ (1,0) [0|15] "" ECM
553 SG_ Rest : 20|4@1+ (1,0) [0|15] "" ECM
554"#;
555
556 let dbc = Dbc::parse(data).unwrap();
557 let message = dbc.messages().find("NewMessage").unwrap();
558
559 assert_eq!(message.dlc(), 8);
561 assert_eq!(message.min_bytes_required(), 3);
562
563 let payload = [0xAB, 0xCD, 0xEF, 0x00, 0x00, 0x00];
566 let decoded = dbc.decode(1024, &payload, false).unwrap();
567
568 assert_eq!(decoded.len(), 4);
569
570 assert_eq!(
572 decoded.iter().find(|s| s.name == "Temp").unwrap().raw_value,
573 0xAB
574 );
575 assert_eq!(
576 decoded.iter().find(|s| s.name == "Pressure").unwrap().raw_value,
577 0xCD
578 );
579 assert_eq!(
580 decoded.iter().find(|s| s.name == "Heel").unwrap().raw_value,
581 0xF
582 );
583 assert_eq!(
584 decoded.iter().find(|s| s.name == "Rest").unwrap().raw_value,
585 0xE
586 );
587 }
588
589 #[test]
590 fn test_decode_big_endian_signal() {
591 let data = r#"VERSION "1.0"
592
593BU_: ECM
594
595BO_ 256 Engine : 8 ECM
596 SG_ RPM : 0|16@0+ (1.0,0) [0|65535] "rpm" *
597"#;
598
599 let dbc = Dbc::parse(data).unwrap();
600
601 let payload = [0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
605 let decoded = dbc.decode(256, &payload, false).unwrap();
606
607 assert_eq!(decoded.len(), 1);
608 assert_eq!(decoded[0].name, "RPM");
609 assert!(decoded[0].value >= 0.0);
612 assert_eq!(decoded[0].unit, Some("rpm"));
613 }
614
615 #[test]
616 fn test_decode_multiplexed_signal() {
617 let dbc = Dbc::parse(
618 r#"VERSION "1.0"
619
620BU_: ECM
621
622BO_ 256 Engine : 8 ECM
623 SG_ MuxId M : 0|8@1+ (1,0) [0|255] ""
624 SG_ Signal0 m0 : 8|16@1+ (0.1,0) [0|6553.5] "unit" *
625 SG_ Signal1 m1 : 24|16@1+ (0.01,0) [0|655.35] "unit" *
626 SG_ NormalSignal : 40|8@1+ (1,0) [0|255] ""
627"#,
628 )
629 .unwrap();
630
631 let payload = [0x00, 0x64, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00];
633 let decoded = dbc.decode(256, &payload, false).unwrap();
636
637 let find_signal = |name: &str| decoded.iter().find(|s| s.name == name).map(|s| s.value);
639
640 assert!(find_signal("MuxId").is_some());
642 assert!(find_signal("Signal0").is_some());
644 assert!(find_signal("Signal1").is_none());
646 assert!(find_signal("NormalSignal").is_some());
648 }
649
650 #[test]
651 fn test_decode_multiplexed_signal_switch_one() {
652 let dbc = Dbc::parse(
653 r#"VERSION "1.0"
654
655BU_: ECM
656
657BO_ 256 Engine : 8 ECM
658 SG_ MuxId M : 0|8@1+ (1,0) [0|255] ""
659 SG_ Signal0 m0 : 8|16@1+ (0.1,0) [0|6553.5] "unit" *
660 SG_ Signal1 m1 : 24|16@1+ (0.01,0) [0|655.35] "unit" *
661"#,
662 )
663 .unwrap();
664
665 let payload = [0x01, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00];
667 let decoded = dbc.decode(256, &payload, false).unwrap();
670
671 let find_signal = |name: &str| decoded.iter().find(|s| s.name == name).map(|s| s.value);
673
674 assert_eq!(find_signal("MuxId"), Some(1.0));
676 assert!(find_signal("Signal0").is_none());
678 assert!(find_signal("Signal1").is_some());
680 }
681
682 #[test]
683 fn test_decode_mixed_byte_order() {
684 let dbc = Dbc::parse(
685 r#"VERSION "1.0"
686
687BU_: ECM
688
689BO_ 256 MixedByteOrder : 8 ECM
690 SG_ LittleEndianSignal : 0|16@1+ (1.0,0) [0|65535] ""
691 SG_ BigEndianSignal : 23|16@0+ (1.0,0) [0|65535] ""
692 SG_ AnotherLittleEndian : 32|8@1+ (1.0,0) [0|255] ""
693 SG_ AnotherBigEndian : 47|8@0+ (1.0,0) [0|255] ""
694"#,
695 )
696 .unwrap();
697
698 let payload = [
704 0x34, 0x12, 0x00, 0x01, 0xAB, 0xCD, 0x00, 0x00, ];
710 let decoded = dbc.decode(256, &payload, false).unwrap();
711
712 let find_signal = |name: &str| decoded.iter().find(|s| s.name == name).map(|s| s.value);
714
715 assert_eq!(find_signal("LittleEndianSignal"), Some(4660.0)); let big_endian_value = find_signal("BigEndianSignal").unwrap();
720 assert!((0.0..=65535.0).contains(&big_endian_value));
722
723 assert_eq!(find_signal("AnotherLittleEndian"), Some(171.0)); let big_endian_8bit = find_signal("AnotherBigEndian");
728 assert!(big_endian_8bit.is_some());
729 assert!(big_endian_8bit.unwrap() >= 0.0 && big_endian_8bit.unwrap() <= 255.0);
730
731 assert_eq!(decoded.len(), 4);
733
734 assert!(find_signal("LittleEndianSignal").is_some());
736 assert!(find_signal("BigEndianSignal").is_some());
737 }
738
739 #[test]
740 fn test_decode_extended_multiplexing_simple() {
741 let dbc = Dbc::parse(
742 r#"VERSION "1.0"
743
744BU_: ECM
745
746BO_ 500 ComplexMux : 8 ECM
747 SG_ Mux1 M : 0|8@1+ (1,0) [0|255] ""
748 SG_ Signal_A m0 : 16|16@1+ (0.1,0) [0|100] "unit" *
749
750SG_MUL_VAL_ 500 Signal_A Mux1 5-10 ;
751"#,
752 )
753 .unwrap();
754
755 let payload = [0x05, 0x00, 0xE8, 0x03, 0x00, 0x00, 0x00, 0x00];
759 let decoded = dbc.decode(500, &payload, false).unwrap();
760
761 let find_signal = |name: &str| decoded.iter().find(|s| s.name == name).map(|s| s.value);
762
763 assert_eq!(find_signal("Mux1"), Some(5.0));
764 assert_eq!(
766 dbc.extended_multiplexing_for_message(500).count(),
767 1,
768 "Extended multiplexing entries should be parsed"
769 );
770 assert!(
771 find_signal("Signal_A").is_some(),
772 "Signal_A should be decoded when Mux1=5 (within range 5-10)"
773 );
774 assert_eq!(find_signal("Signal_A").unwrap(), 100.0);
775
776 let payload2 = [0x0F, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00];
778 let decoded2 = dbc.decode(500, &payload2, false).unwrap();
779 let find_signal2 = |name: &str| decoded2.iter().find(|s| s.name == name).map(|s| s.value);
780
781 assert_eq!(find_signal2("Mux1"), Some(15.0));
782 assert!(find_signal2("Signal_A").is_none());
783 }
784
785 #[test]
786 fn test_decode_extended_multiplexing_multiple_ranges() {
787 let dbc = Dbc::parse(
788 r#"VERSION "1.0"
789
790BU_: ECM
791
792BO_ 501 MultiRangeMux : 8 ECM
793 SG_ Mux1 M : 0|8@1+ (1,0) [0|255] ""
794 SG_ Signal_B m0 : 16|16@1+ (1,0) [0|65535] "unit" *
795
796SG_MUL_VAL_ 501 Signal_B Mux1 0-5,10-15,20-25 ;
797"#,
798 )
799 .unwrap();
800
801 let payload1 = [0x03, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00];
804 let decoded1 = dbc.decode(501, &payload1, false).unwrap();
805 let find1 = |name: &str| decoded1.iter().find(|s| s.name == name).map(|s| s.value);
806 assert_eq!(find1("Mux1"), Some(3.0));
807 assert!(find1("Signal_B").is_some());
808
809 let payload2 = [0x0C, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00];
812 let decoded2 = dbc.decode(501, &payload2, false).unwrap();
813 let find2 = |name: &str| decoded2.iter().find(|s| s.name == name).map(|s| s.value);
814 assert_eq!(find2("Mux1"), Some(12.0));
815 assert!(find2("Signal_B").is_some());
816
817 let payload3 = [0x16, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00];
820 let decoded3 = dbc.decode(501, &payload3, false).unwrap();
821 let find3 = |name: &str| decoded3.iter().find(|s| s.name == name).map(|s| s.value);
822 assert_eq!(find3("Mux1"), Some(22.0));
823 assert!(find3("Signal_B").is_some());
824
825 let payload4 = [0x08, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00];
828 let decoded4 = dbc.decode(501, &payload4, false).unwrap();
829 let find4 = |name: &str| decoded4.iter().find(|s| s.name == name).map(|s| s.value);
830 assert_eq!(find4("Mux1"), Some(8.0));
831 assert!(find4("Signal_B").is_none());
832 }
833
834 #[test]
837 fn test_decode_extended_multiplexing_multiple_switches() {
838 let dbc = Dbc::parse(
839 r#"VERSION "1.0"
840
841BU_: ECM
842
843BO_ 502 MultiSwitchMux : 8 ECM
844 SG_ Mux1 M : 0|8@1+ (1,0) [0|255] ""
845 SG_ Mux2 M : 8|8@1+ (1,0) [0|255] ""
846 SG_ Signal_C m0 : 16|16@1+ (1,0) [0|65535] "unit" *
847
848SG_MUL_VAL_ 502 Signal_C Mux1 5-10 ;
849SG_MUL_VAL_ 502 Signal_C Mux2 20-25 ;
850"#,
851 )
852 .unwrap();
853
854 let payload1 = [0x07, 0x16, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00];
857 let decoded1 = dbc.decode(502, &payload1, false).unwrap();
858 let find1 = |name: &str| decoded1.iter().find(|s| s.name == name).map(|s| s.value);
859 assert_eq!(find1("Mux1"), Some(7.0));
860 assert_eq!(find1("Mux2"), Some(22.0));
861 assert!(find1("Signal_C").is_some());
862
863 let payload2 = [0x07, 0x1E, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00];
865 let decoded2 = dbc.decode(502, &payload2, false).unwrap();
866 let find2 = |name: &str| decoded2.iter().find(|s| s.name == name).map(|s| s.value);
867 assert_eq!(find2("Mux1"), Some(7.0));
868 assert_eq!(find2("Mux2"), Some(30.0));
869 assert!(find2("Signal_C").is_none());
870
871 let payload3 = [0x0F, 0x16, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00];
873 let decoded3 = dbc.decode(502, &payload3, false).unwrap();
874 let find3 = |name: &str| decoded3.iter().find(|s| s.name == name).map(|s| s.value);
875 assert_eq!(find3("Mux1"), Some(15.0));
876 assert_eq!(find3("Mux2"), Some(22.0));
877 assert!(find3("Signal_C").is_none());
878 }
879
880 #[test]
883 fn test_decode_extended_multiplexing_takes_precedence() {
884 let dbc = Dbc::parse(
885 r#"VERSION "1.0"
886
887BU_: ECM
888
889BO_ 503 PrecedenceTest : 8 ECM
890 SG_ Mux1 M : 0|8@1+ (1,0) [0|255] ""
891 SG_ Signal_D m0 : 16|16@1+ (1,0) [0|65535] "unit" *
892
893SG_MUL_VAL_ 503 Signal_D Mux1 10-15 ;
894"#,
895 )
896 .unwrap();
897
898 let payload1 = [0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00];
902 let decoded1 = dbc.decode(503, &payload1, false).unwrap();
903 let find1 = |name: &str| decoded1.iter().find(|s| s.name == name).map(|s| s.value);
904 assert_eq!(find1("Mux1"), Some(0.0));
905 assert!(find1("Signal_D").is_none());
906
907 let payload2 = [0x0C, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x00];
909 let decoded2 = dbc.decode(503, &payload2, false).unwrap();
910 let find2 = |name: &str| decoded2.iter().find(|s| s.name == name).map(|s| s.value);
911 assert_eq!(find2("Mux1"), Some(12.0));
912 assert!(find2("Signal_D").is_some());
913 }
914
915 #[test]
918 fn test_decode_extended_multiplexing_with_extended_mux_signal() {
919 let dbc = Dbc::parse(
921 r#"VERSION "1.0"
922
923BU_: ECM
924
925BO_ 504 ExtendedMuxSignal : 8 ECM
926 SG_ Mux1 M : 0|8@1+ (1,0) [0|255] ""
927 SG_ Mux2 m65M : 8|8@1+ (1,0) [0|255] ""
928 SG_ Signal_E m0 : 16|16@1+ (1,0) [0|65535] "unit" *
929
930SG_MUL_VAL_ 504 Signal_E Mux1 65-65 ;
931SG_MUL_VAL_ 504 Signal_E Mux2 10-15 ;
932"#,
933 )
934 .unwrap();
935
936 let payload = [0x41, 0x0C, 0x00, 0xA0, 0x00, 0x00, 0x00, 0x00];
939 let decoded = dbc.decode(504, &payload, false).unwrap();
941 let find = |name: &str| decoded.iter().find(|s| s.name == name).map(|s| s.value);
942
943 assert_eq!(find("Mux1"), Some(65.0));
944 assert_eq!(find("Mux2"), Some(12.0));
945 assert!(find("Signal_E").is_some());
946
947 let payload2 = [0x40, 0x0C, 0x00, 0xB0, 0x00, 0x00, 0x00, 0x00];
949 let decoded2 = dbc.decode(504, &payload2, false).unwrap();
950 let find2 = |name: &str| decoded2.iter().find(|s| s.name == name).map(|s| s.value);
951 assert_eq!(find2("Mux1"), Some(64.0));
952 assert_eq!(find2("Mux2"), Some(12.0));
953 assert!(find2("Signal_E").is_none());
954 }
955
956 #[test]
957 fn test_decode_negative_multiplexer_switch() {
958 use crate::Error;
959 let dbc = Dbc::parse(
962 r#"VERSION "1.0"
963
964BU_: ECM
965
966BO_ 256 MuxMessage : 8 ECM
967 SG_ MuxSwitch M : 0|8@1- (1,0) [-128|127] ""
968 SG_ SignalA m0 : 8|8@1+ (1,0) [0|255] ""
969"#,
970 )
971 .unwrap();
972
973 let payload = [0xFB, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
977 let result = dbc.decode(256, &payload, false);
978 assert!(result.is_err());
979 match result.unwrap_err() {
980 Error::Decoding(msg) => {
981 assert_eq!(msg, Error::MULTIPLEXER_SWITCH_NEGATIVE);
982 }
983 _ => panic!("Expected Error::Decoding with MULTIPLEXER_SWITCH_NEGATIVE"),
984 }
985 }
986
987 #[test]
988 fn test_decode_too_many_unique_switches() {
989 use crate::{Error, MAX_SIGNALS_PER_MESSAGE};
990 if MAX_SIGNALS_PER_MESSAGE < 17 {
993 return;
994 }
995
996 let dbc_str = r#"VERSION "1.0"
1000
1001BU_: ECM
1002
1003BO_ 600 TooManySwitches : 18 ECM
1004 SG_ Mux1 M : 0|8@1+ (1,0) [0|255] ""
1005 SG_ Mux2 M : 8|8@1+ (1,0) [0|255] ""
1006 SG_ Mux3 M : 16|8@1+ (1,0) [0|255] ""
1007 SG_ Mux4 M : 24|8@1+ (1,0) [0|255] ""
1008 SG_ Mux5 M : 32|8@1+ (1,0) [0|255] ""
1009 SG_ Mux6 M : 40|8@1+ (1,0) [0|255] ""
1010 SG_ Mux7 M : 48|8@1+ (1,0) [0|255] ""
1011 SG_ Mux8 M : 56|8@1+ (1,0) [0|255] ""
1012 SG_ Mux9 M : 64|8@1+ (1,0) [0|255] ""
1013 SG_ Mux10 M : 72|8@1+ (1,0) [0|255] ""
1014 SG_ Mux11 M : 80|8@1+ (1,0) [0|255] ""
1015 SG_ Mux12 M : 88|8@1+ (1,0) [0|255] ""
1016 SG_ Mux13 M : 96|8@1+ (1,0) [0|255] ""
1017 SG_ Mux14 M : 104|8@1+ (1,0) [0|255] ""
1018 SG_ Mux15 M : 112|8@1+ (1,0) [0|255] ""
1019 SG_ Mux16 M : 120|8@1+ (1,0) [0|255] ""
1020 SG_ Mux17 M : 128|8@1+ (1,0) [0|255] ""
1021 SG_ Signal_X m0 : 136|8@1+ (1,0) [0|255] "unit" *
1022
1023SG_MUL_VAL_ 600 Signal_X Mux1 0-255 ;
1024SG_MUL_VAL_ 600 Signal_X Mux2 0-255 ;
1025SG_MUL_VAL_ 600 Signal_X Mux3 0-255 ;
1026SG_MUL_VAL_ 600 Signal_X Mux4 0-255 ;
1027SG_MUL_VAL_ 600 Signal_X Mux5 0-255 ;
1028SG_MUL_VAL_ 600 Signal_X Mux6 0-255 ;
1029SG_MUL_VAL_ 600 Signal_X Mux7 0-255 ;
1030SG_MUL_VAL_ 600 Signal_X Mux8 0-255 ;
1031SG_MUL_VAL_ 600 Signal_X Mux9 0-255 ;
1032SG_MUL_VAL_ 600 Signal_X Mux10 0-255 ;
1033SG_MUL_VAL_ 600 Signal_X Mux11 0-255 ;
1034SG_MUL_VAL_ 600 Signal_X Mux12 0-255 ;
1035SG_MUL_VAL_ 600 Signal_X Mux13 0-255 ;
1036SG_MUL_VAL_ 600 Signal_X Mux14 0-255 ;
1037SG_MUL_VAL_ 600 Signal_X Mux15 0-255 ;
1038SG_MUL_VAL_ 600 Signal_X Mux16 0-255 ;
1039SG_MUL_VAL_ 600 Signal_X Mux17 0-255 ;
1040"#;
1041
1042 let dbc = Dbc::parse(dbc_str).unwrap();
1043
1044 let payload = [0x00; 18];
1047 let result = dbc.decode(600, &payload, false);
1048 assert!(
1049 result.is_err(),
1050 "Decode should fail when there are more than 16 unique switches"
1051 );
1052 match result.unwrap_err() {
1053 Error::Decoding(msg) => {
1054 assert_eq!(
1055 msg,
1056 Error::MESSAGE_TOO_MANY_SIGNALS,
1057 "Expected MESSAGE_TOO_MANY_SIGNALS error, got: {}",
1058 msg
1059 );
1060 }
1061 e => panic!(
1062 "Expected Error::Decoding with MESSAGE_TOO_MANY_SIGNALS, got: {:?}",
1063 e
1064 ),
1065 }
1066 }
1067
1068 #[test]
1069 fn test_decode_extended_can_id() {
1070 let dbc = Dbc::parse(
1074 r#"VERSION "1.0"
1075
1076BU_: ECM
1077
1078BO_ 2147484672 ExtendedMsg : 8 ECM
1079 SG_ Speed : 0|16@1+ (0.1,0) [0|6553.5] "km/h" *
1080"#,
1081 )
1082 .unwrap();
1083 let payload = [0xE8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
1086 let decoded = dbc.decode(0x400, &payload, true).unwrap();
1090 assert_eq!(decoded.len(), 1);
1091 assert_eq!(decoded[0].name, "Speed");
1092 assert_eq!(decoded[0].value, 100.0);
1093 assert_eq!(decoded[0].unit, Some("km/h"));
1094 }
1095
1096 #[test]
1097 fn test_decode_extended_can_id_not_found_without_flag() {
1098 let dbc = Dbc::parse(
1101 r#"VERSION "1.0"
1102
1103BU_: ECM
1104
1105BO_ 2147484672 ExtendedMsg : 8 ECM
1106 SG_ Speed : 0|16@1+ (0.1,0) [0|6553.5] "km/h" *
1107"#,
1108 )
1109 .unwrap();
1110
1111 let payload = [0xE8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
1112
1113 let result = dbc.decode(0x400, &payload, false);
1115 assert!(result.is_err());
1116 }
1117
1118 #[test]
1119 fn test_decode_standard_vs_extended_same_base_id() {
1120 let dbc = Dbc::parse(
1122 r#"VERSION "1.0"
1123
1124BU_: ECM
1125
1126BO_ 256 StandardMsg : 8 ECM
1127 SG_ StdSignal : 0|8@1+ (1,0) [0|255] "" *
1128
1129BO_ 2147483904 ExtendedMsg : 8 ECM
1130 SG_ ExtSignal : 0|8@1+ (2,0) [0|510] "" *
1131"#,
1132 )
1133 .unwrap();
1134 let payload = [0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; let decoded_std = dbc.decode(256, &payload, false).unwrap();
1140 assert_eq!(decoded_std.len(), 1);
1141 assert_eq!(decoded_std[0].name, "StdSignal");
1142 assert_eq!(decoded_std[0].value, 100.0); let decoded_ext = dbc.decode(256, &payload, true).unwrap();
1146 assert_eq!(decoded_ext.len(), 1);
1147 assert_eq!(decoded_ext[0].name, "ExtSignal");
1148 assert_eq!(decoded_ext[0].value, 200.0); }
1150
1151 #[test]
1152 fn test_decode_with_value_descriptions() {
1153 let dbc = Dbc::parse(
1156 r#"VERSION "1.0"
1157
1158BU_: ECM
1159
1160BO_ 200 GearboxData : 4 ECM
1161 SG_ GearActual : 0|8@1+ (1,0) [0|5] "" *
1162
1163VAL_ 200 GearActual 0 "Park" 1 "Reverse" 2 "Neutral" 3 "Drive" 4 "Sport" 5 "Manual" ;
1164"#,
1165 )
1166 .unwrap();
1167
1168 let payload = [0x00, 0x00, 0x00, 0x00];
1170 let decoded = dbc.decode(200, &payload, false).unwrap();
1171 assert_eq!(decoded.len(), 1);
1172 assert_eq!(decoded[0].name, "GearActual");
1173 assert_eq!(decoded[0].value, 0.0);
1174 assert_eq!(decoded[0].description, Some("Park"));
1175
1176 let payload = [0x03, 0x00, 0x00, 0x00];
1178 let decoded = dbc.decode(200, &payload, false).unwrap();
1179 assert_eq!(decoded[0].value, 3.0);
1180 assert_eq!(decoded[0].description, Some("Drive"));
1181
1182 let payload = [0x05, 0x00, 0x00, 0x00];
1184 let decoded = dbc.decode(200, &payload, false).unwrap();
1185 assert_eq!(decoded[0].value, 5.0);
1186 assert_eq!(decoded[0].description, Some("Manual"));
1187 }
1188
1189 #[test]
1190 fn test_decode_without_value_descriptions() {
1191 let dbc = Dbc::parse(
1193 r#"VERSION "1.0"
1194
1195BU_: ECM
1196
1197BO_ 256 Engine : 8 ECM
1198 SG_ RPM : 0|16@1+ (0.25,0) [0|8000] "rpm" *
1199"#,
1200 )
1201 .unwrap();
1202
1203 let payload = [0x40, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
1204 let decoded = dbc.decode(256, &payload, false).unwrap();
1205 assert_eq!(decoded.len(), 1);
1206 assert_eq!(decoded[0].name, "RPM");
1207 assert_eq!(decoded[0].value, 2000.0);
1208 assert_eq!(decoded[0].unit, Some("rpm"));
1209 assert_eq!(decoded[0].description, None);
1210 }
1211
1212 #[test]
1213 fn test_decode_value_description_not_found() {
1214 let dbc = Dbc::parse(
1216 r#"VERSION "1.0"
1217
1218BU_: ECM
1219
1220BO_ 200 GearboxData : 4 ECM
1221 SG_ GearActual : 0|8@1+ (1,0) [0|255] "" *
1222
1223VAL_ 200 GearActual 0 "Park" 1 "Reverse" 2 "Neutral" ;
1224"#,
1225 )
1226 .unwrap();
1227
1228 let payload = [0x0A, 0x00, 0x00, 0x00];
1230 let decoded = dbc.decode(200, &payload, false).unwrap();
1231 assert_eq!(decoded.len(), 1);
1232 assert_eq!(decoded[0].value, 10.0);
1233 assert_eq!(decoded[0].description, None); }
1235
1236 #[test]
1237 fn test_decode_multiplexer_with_value_descriptions() {
1238 let dbc = Dbc::parse(
1241 r#"VERSION "1.0"
1242
1243BU_: ECM
1244
1245BO_ 300 MultiplexedSensors : 8 ECM
1246 SG_ SensorID M : 0|8@1+ (1,0) [0|3] "" *
1247 SG_ Temperature m0 : 8|16@1- (0.1,-40) [-40|125] "°C" *
1248 SG_ Pressure m1 : 8|16@1+ (0.01,0) [0|655.35] "kPa" *
1249
1250VAL_ 300 SensorID 0 "Temperature Sensor" 1 "Pressure Sensor" 2 "Humidity Sensor" 3 "Voltage Sensor" ;
1251"#,
1252 )
1253 .unwrap();
1254
1255 let payload = [0x00, 0xF4, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00];
1258 let decoded = dbc.decode(300, &payload, false).unwrap();
1259
1260 let sensor_id = decoded.iter().find(|s| s.name == "SensorID").unwrap();
1262 assert_eq!(sensor_id.value, 0.0);
1263 assert_eq!(sensor_id.description, Some("Temperature Sensor"));
1264
1265 let temp = decoded.iter().find(|s| s.name == "Temperature").unwrap();
1267 assert!(temp.description.is_none()); let payload = [0x01, 0x10, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00];
1271 let decoded = dbc.decode(300, &payload, false).unwrap();
1272
1273 let sensor_id = decoded.iter().find(|s| s.name == "SensorID").unwrap();
1274 assert_eq!(sensor_id.value, 1.0);
1275 assert_eq!(sensor_id.description, Some("Pressure Sensor"));
1276 }
1277
1278 #[cfg(feature = "embedded-can")]
1279 mod embedded_can_tests {
1280 use super::*;
1281 use embedded_can::{ExtendedId, Frame, Id, StandardId};
1282
1283 struct TestFrame {
1285 id: Id,
1286 data: [u8; 8],
1287 dlc: usize,
1288 }
1289
1290 impl TestFrame {
1291 fn new_standard(id: u16, data: &[u8]) -> Self {
1292 let mut frame_data = [0u8; 8];
1293 let dlc = data.len().min(8);
1294 frame_data[..dlc].copy_from_slice(&data[..dlc]);
1295 Self {
1296 id: Id::Standard(StandardId::new(id).unwrap()),
1297 data: frame_data,
1298 dlc,
1299 }
1300 }
1301
1302 fn new_extended(id: u32, data: &[u8]) -> Self {
1303 let mut frame_data = [0u8; 8];
1304 let dlc = data.len().min(8);
1305 frame_data[..dlc].copy_from_slice(&data[..dlc]);
1306 Self {
1307 id: Id::Extended(ExtendedId::new(id).unwrap()),
1308 data: frame_data,
1309 dlc,
1310 }
1311 }
1312 }
1313
1314 impl Frame for TestFrame {
1315 fn new(id: impl Into<Id>, data: &[u8]) -> Option<Self> {
1316 let mut frame_data = [0u8; 8];
1317 let dlc = data.len().min(8);
1318 frame_data[..dlc].copy_from_slice(&data[..dlc]);
1319 Some(Self {
1320 id: id.into(),
1321 data: frame_data,
1322 dlc,
1323 })
1324 }
1325
1326 fn new_remote(_id: impl Into<Id>, _dlc: usize) -> Option<Self> {
1327 None }
1329
1330 fn is_extended(&self) -> bool {
1331 matches!(self.id, Id::Extended(_))
1332 }
1333
1334 fn is_remote_frame(&self) -> bool {
1335 false
1336 }
1337
1338 fn id(&self) -> Id {
1339 self.id
1340 }
1341
1342 fn dlc(&self) -> usize {
1343 self.dlc
1344 }
1345
1346 fn data(&self) -> &[u8] {
1347 &self.data[..self.dlc]
1348 }
1349 }
1350
1351 #[test]
1352 fn test_decode_frame_standard() {
1353 let dbc = Dbc::parse(
1354 r#"VERSION "1.0"
1355
1356BU_: ECM
1357
1358BO_ 256 Engine : 8 ECM
1359 SG_ RPM : 0|16@1+ (0.25,0) [0|8000] "rpm" *
1360"#,
1361 )
1362 .unwrap();
1363
1364 let frame =
1366 TestFrame::new_standard(256, &[0x40, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
1367
1368 let decoded = dbc.decode_frame(frame).unwrap();
1369 assert_eq!(decoded.len(), 1);
1370 assert_eq!(decoded[0].name, "RPM");
1371 assert_eq!(decoded[0].value, 2000.0);
1372 assert_eq!(decoded[0].unit, Some("rpm"));
1373 }
1374
1375 #[test]
1376 fn test_decode_frame_extended() {
1377 let dbc = Dbc::parse(
1379 r#"VERSION "1.0"
1380
1381BU_: ECM
1382
1383BO_ 2147484672 ExtendedMsg : 8 ECM
1384 SG_ Speed : 0|16@1+ (0.1,0) [0|6553.5] "km/h" *
1385"#,
1386 )
1387 .unwrap();
1388 let frame =
1392 TestFrame::new_extended(0x400, &[0xE8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
1393
1394 let decoded = dbc.decode_frame(frame).unwrap();
1395 assert_eq!(decoded.len(), 1);
1396 assert_eq!(decoded[0].name, "Speed");
1397 assert_eq!(decoded[0].value, 100.0);
1398 assert_eq!(decoded[0].unit, Some("km/h"));
1399 }
1400
1401 #[test]
1402 fn test_decode_frame_standard_vs_extended() {
1403 let dbc = Dbc::parse(
1405 r#"VERSION "1.0"
1406
1407BU_: ECM
1408
1409BO_ 256 StandardMsg : 8 ECM
1410 SG_ StdSignal : 0|8@1+ (1,0) [0|255] "" *
1411
1412BO_ 2147483904 ExtendedMsg : 8 ECM
1413 SG_ ExtSignal : 0|8@1+ (2,0) [0|510] "" *
1414"#,
1415 )
1416 .unwrap();
1417 let payload = [0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; let std_frame = TestFrame::new_standard(256, &payload);
1423 let decoded_std = dbc.decode_frame(std_frame).unwrap();
1424 assert_eq!(decoded_std[0].name, "StdSignal");
1425 assert_eq!(decoded_std[0].value, 100.0);
1426
1427 let ext_frame = TestFrame::new_extended(256, &payload);
1429 let decoded_ext = dbc.decode_frame(ext_frame).unwrap();
1430 assert_eq!(decoded_ext[0].name, "ExtSignal");
1431 assert_eq!(decoded_ext[0].value, 200.0);
1432 }
1433
1434 #[test]
1435 fn test_decode_frame_message_not_found() {
1436 let dbc = Dbc::parse(
1437 r#"VERSION "1.0"
1438
1439BU_: ECM
1440
1441BO_ 256 Engine : 8 ECM
1442"#,
1443 )
1444 .unwrap();
1445
1446 let frame =
1448 TestFrame::new_standard(512, &[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
1449 let result = dbc.decode_frame(frame);
1450 assert!(result.is_err());
1451 }
1452 }
1453}