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 unit: Option<&'a str>,
16 pub description: Option<&'a str>,
19}
20
21impl<'a> DecodedSignal<'a> {
22 #[inline]
42 pub fn new(
43 name: &'a str,
44 value: f64,
45 unit: Option<&'a str>,
46 description: Option<&'a str>,
47 ) -> Self {
48 Self {
49 name,
50 value,
51 unit,
52 description,
53 }
54 }
55}
56
57const MAX_SWITCHES: usize = 8;
60
61struct SwitchValues<'a> {
64 names: [Option<&'a str>; MAX_SWITCHES],
66 values: [u64; MAX_SWITCHES],
68 count: usize,
70}
71
72impl<'a> SwitchValues<'a> {
73 #[inline]
74 const fn new() -> Self {
75 Self {
76 names: [None; MAX_SWITCHES],
77 values: [0; MAX_SWITCHES],
78 count: 0,
79 }
80 }
81
82 #[inline]
84 fn push(&mut self, name: &'a str, value: u64) -> Result<()> {
85 if self.count >= MAX_SWITCHES {
86 return Err(Error::Decoding(Error::MESSAGE_TOO_MANY_SIGNALS));
87 }
88 let idx = self.count;
89 self.names[idx] = Some(name);
90 self.values[idx] = value;
91 self.count += 1;
92 Ok(())
93 }
94
95 #[inline]
97 fn get_by_name(&self, name: &str) -> Option<u64> {
98 for i in 0..self.count {
99 if self.names[i] == Some(name) {
100 return Some(self.values[i]);
101 }
102 }
103 None
104 }
105
106 #[inline]
108 fn any_has_value(&self, target: u64) -> bool {
109 for i in 0..self.count {
110 if self.values[i] == target && self.names[i].is_some() {
111 return true;
112 }
113 }
114 false
115 }
116}
117
118impl Dbc {
120 #[inline]
167 pub fn decode(
168 &self,
169 id: u32,
170 payload: &[u8],
171 is_extended: bool,
172 ) -> Result<Vec<DecodedSignal<'_>, { MAX_SIGNALS_PER_MESSAGE }>> {
173 let id = if is_extended {
175 id | Message::EXTENDED_ID_FLAG
176 } else {
177 id
178 };
179
180 let message = self
182 .messages()
183 .find_by_id(id)
184 .ok_or(Error::Decoding(Error::MESSAGE_NOT_FOUND))?;
185
186 let dlc = message.dlc() as usize;
188 if payload.len() < dlc {
189 return Err(Error::Decoding(Error::PAYLOAD_LENGTH_MISMATCH));
190 }
191
192 let mut decoded_signals: Vec<DecodedSignal<'_>, { MAX_SIGNALS_PER_MESSAGE }> = Vec::new();
194
195 let mut switch_values = SwitchValues::<'_>::new();
197
198 let signals = message.signals();
199
200 let message_has_extended_mux = !self.extended_multiplexing.is_empty()
204 && self.has_extended_multiplexing_for_message(id);
205
206 let has_any_value_descriptions = !self.value_descriptions.is_empty();
209
210 for signal in signals.iter() {
213 if signal.is_multiplexer_switch() {
214 let (raw_value, physical_value) = signal.decode_raw(payload)?;
216
217 if raw_value < 0 {
219 return Err(Error::Decoding(Error::MULTIPLEXER_SWITCH_NEGATIVE));
220 }
221
222 switch_values.push(signal.name(), raw_value as u64)?;
224
225 let description = if has_any_value_descriptions {
227 self.value_descriptions_for_signal(id, signal.name())
228 .and_then(|vd| vd.get(raw_value as u64))
229 } else {
230 None
231 };
232
233 decoded_signals
235 .push(DecodedSignal::new(
236 signal.name(),
237 physical_value,
238 signal.unit(),
239 description,
240 ))
241 .map_err(|_| Error::Decoding(Error::MESSAGE_TOO_MANY_SIGNALS))?;
242 }
243 }
244
245 for signal in signals.iter() {
247 if signal.is_multiplexer_switch() {
249 continue;
250 }
251
252 let should_decode = if let Some(mux_value) = signal.multiplexer_switch_value() {
254 if message_has_extended_mux {
256 self.check_extended_multiplexing(id, signal.name(), &switch_values)
258 .unwrap_or_else(|| {
259 switch_values.any_has_value(mux_value)
261 })
262 } else {
263 switch_values.any_has_value(mux_value)
265 }
266 } else {
267 true
269 };
270
271 if should_decode {
272 let (raw_value, physical_value) = signal.decode_raw(payload)?;
274
275 let description = if has_any_value_descriptions {
277 self.value_descriptions_for_signal(id, signal.name())
278 .and_then(|vd| vd.get(raw_value as u64))
279 } else {
280 None
281 };
282
283 decoded_signals
284 .push(DecodedSignal::new(
285 signal.name(),
286 physical_value,
287 signal.unit(),
288 description,
289 ))
290 .map_err(|_| Error::Decoding(Error::MESSAGE_TOO_MANY_SIGNALS))?;
291 }
292 }
293
294 Ok(decoded_signals)
295 }
296
297 #[inline]
301 fn check_extended_multiplexing(
302 &self,
303 message_id: u32,
304 signal_name: &str,
305 switch_values: &SwitchValues,
306 ) -> Option<bool> {
307 let indices = self.ext_mux_index.get(message_id, signal_name)?;
309 if indices.is_empty() {
310 return None;
311 }
312
313 let mut unique_switches: [Option<&str>; MAX_SWITCHES] = [None; MAX_SWITCHES];
318 let mut unique_count = 0;
319
320 for &idx in indices {
321 if let Some(entry) = self.extended_multiplexing.get(idx) {
322 let switch_name = entry.multiplexer_switch();
323 let found =
325 unique_switches.iter().take(unique_count).any(|&s| s == Some(switch_name));
326 if !found && unique_count < MAX_SWITCHES {
327 unique_switches[unique_count] = Some(switch_name);
328 unique_count += 1;
329 }
330 }
331 }
332
333 for switch_opt in unique_switches.iter().take(unique_count) {
335 let switch_name = match switch_opt {
336 Some(name) => *name,
337 None => continue,
338 };
339
340 let switch_val = match switch_values.get_by_name(switch_name) {
342 Some(v) => v,
343 None => return Some(false), };
345
346 let mut has_match = false;
348 for &idx in indices {
349 if let Some(entry) = self.extended_multiplexing.get(idx) {
350 if entry.multiplexer_switch() == switch_name {
351 for &(min, max) in entry.value_ranges() {
352 if switch_val >= min && switch_val <= max {
353 has_match = true;
354 break;
355 }
356 }
357 if has_match {
358 break;
359 }
360 }
361 }
362 }
363
364 if !has_match {
365 return Some(false); }
367 }
368
369 Some(true) }
371
372 #[inline]
375 fn has_extended_multiplexing_for_message(&self, message_id: u32) -> bool {
376 self.extended_multiplexing
377 .iter()
378 .any(|ext_mux| ext_mux.message_id() == message_id)
379 }
380
381 #[cfg(feature = "embedded-can")]
428 #[inline]
429 pub fn decode_frame<T: Frame>(
430 &self,
431 frame: T,
432 ) -> Result<Vec<DecodedSignal<'_>, { MAX_SIGNALS_PER_MESSAGE }>> {
433 let payload = frame.data();
434 match frame.id() {
435 Id::Standard(id) => self.decode(id.as_raw() as u32, payload, false),
436 Id::Extended(id) => self.decode(id.as_raw(), payload, true),
437 }
438 }
439}
440
441#[cfg(test)]
442mod tests {
443 use crate::Dbc;
444
445 #[test]
446 fn test_decode_basic() {
447 let dbc = Dbc::parse(
448 r#"VERSION "1.0"
449
450BU_: ECM
451
452BO_ 256 Engine : 8 ECM
453 SG_ RPM : 0|16@1+ (0.25,0) [0|8000] "rpm" *
454"#,
455 )
456 .unwrap();
457
458 let payload = [0x40, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
460 let decoded = dbc.decode(256, &payload, false).unwrap();
461 assert_eq!(decoded.len(), 1);
462 assert_eq!(decoded[0].name, "RPM");
463 assert_eq!(decoded[0].value, 2000.0);
464 assert_eq!(decoded[0].unit, Some("rpm"));
465 }
466
467 #[test]
468 fn test_decode_message_not_found() {
469 let dbc = Dbc::parse(
470 r#"VERSION "1.0"
471
472BU_: ECM
473
474BO_ 256 Engine : 8 ECM
475"#,
476 )
477 .unwrap();
478
479 let payload = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
480 let result = dbc.decode(512, &payload, false);
481 assert!(result.is_err());
482 }
483
484 #[test]
485 fn test_decode_message() {
486 let data = r#"VERSION "1.0"
487
488BU_: ECM
489
490BO_ 256 Engine : 8 ECM
491 SG_ RPM : 0|16@1+ (0.25,0) [0|8000] "rpm" *
492 SG_ Temp : 16|8@1- (1,-40) [-40|215] "°C" *
493"#;
494
495 let dbc = Dbc::parse(data).unwrap();
496
497 let payload = [0x40, 0x1F, 0x5A, 0x00, 0x00, 0x00, 0x00, 0x00];
500 let decoded = dbc.decode(256, &payload, false).unwrap();
501
502 assert_eq!(decoded.len(), 2);
503 assert_eq!(decoded[0].name, "RPM");
504 assert_eq!(decoded[0].value, 2000.0);
505 assert_eq!(decoded[0].unit, Some("rpm"));
506 assert_eq!(decoded[1].name, "Temp");
507 assert_eq!(decoded[1].value, 50.0);
508 assert_eq!(decoded[1].unit, Some("°C"));
509 }
510
511 #[test]
512 fn test_decode_payload_length_mismatch() {
513 use crate::Error;
514 let data = r#"VERSION "1.0"
515
516BU_: ECM
517
518BO_ 256 Engine : 8 ECM
519 SG_ RPM : 0|16@1+ (0.25,0) [0|8000] "rpm" *
520"#;
521
522 let dbc = Dbc::parse(data).unwrap();
523
524 let payload = [0x40, 0x1F, 0x00, 0x00];
526 let result = dbc.decode(256, &payload, false);
527 assert!(result.is_err());
528 match result.unwrap_err() {
529 Error::Decoding(msg) => {
530 assert!(msg.contains(Error::PAYLOAD_LENGTH_MISMATCH));
531 }
532 _ => panic!("Expected Error::Decoding"),
533 }
534 }
535
536 #[test]
537 fn test_decode_big_endian_signal() {
538 let data = r#"VERSION "1.0"
539
540BU_: ECM
541
542BO_ 256 Engine : 8 ECM
543 SG_ RPM : 0|16@0+ (1.0,0) [0|65535] "rpm" *
544"#;
545
546 let dbc = Dbc::parse(data).unwrap();
547
548 let payload = [0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
552 let decoded = dbc.decode(256, &payload, false).unwrap();
553
554 assert_eq!(decoded.len(), 1);
555 assert_eq!(decoded[0].name, "RPM");
556 assert!(decoded[0].value >= 0.0);
559 assert_eq!(decoded[0].unit, Some("rpm"));
560 }
561
562 #[test]
563 fn test_decode_multiplexed_signal() {
564 let dbc = Dbc::parse(
565 r#"VERSION "1.0"
566
567BU_: ECM
568
569BO_ 256 Engine : 8 ECM
570 SG_ MuxId M : 0|8@1+ (1,0) [0|255] ""
571 SG_ Signal0 m0 : 8|16@1+ (0.1,0) [0|6553.5] "unit" *
572 SG_ Signal1 m1 : 24|16@1+ (0.01,0) [0|655.35] "unit" *
573 SG_ NormalSignal : 40|8@1+ (1,0) [0|255] ""
574"#,
575 )
576 .unwrap();
577
578 let payload = [0x00, 0x64, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00];
580 let decoded = dbc.decode(256, &payload, false).unwrap();
583
584 let find_signal = |name: &str| decoded.iter().find(|s| s.name == name).map(|s| s.value);
586
587 assert!(find_signal("MuxId").is_some());
589 assert!(find_signal("Signal0").is_some());
591 assert!(find_signal("Signal1").is_none());
593 assert!(find_signal("NormalSignal").is_some());
595 }
596
597 #[test]
598 fn test_decode_multiplexed_signal_switch_one() {
599 let dbc = Dbc::parse(
600 r#"VERSION "1.0"
601
602BU_: ECM
603
604BO_ 256 Engine : 8 ECM
605 SG_ MuxId M : 0|8@1+ (1,0) [0|255] ""
606 SG_ Signal0 m0 : 8|16@1+ (0.1,0) [0|6553.5] "unit" *
607 SG_ Signal1 m1 : 24|16@1+ (0.01,0) [0|655.35] "unit" *
608"#,
609 )
610 .unwrap();
611
612 let payload = [0x01, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00];
614 let decoded = dbc.decode(256, &payload, false).unwrap();
617
618 let find_signal = |name: &str| decoded.iter().find(|s| s.name == name).map(|s| s.value);
620
621 assert_eq!(find_signal("MuxId"), Some(1.0));
623 assert!(find_signal("Signal0").is_none());
625 assert!(find_signal("Signal1").is_some());
627 }
628
629 #[test]
630 fn test_decode_mixed_byte_order() {
631 let dbc = Dbc::parse(
632 r#"VERSION "1.0"
633
634BU_: ECM
635
636BO_ 256 MixedByteOrder : 8 ECM
637 SG_ LittleEndianSignal : 0|16@1+ (1.0,0) [0|65535] ""
638 SG_ BigEndianSignal : 16|16@0+ (1.0,0) [0|65535] ""
639 SG_ AnotherLittleEndian : 32|8@1+ (1.0,0) [0|255] ""
640 SG_ AnotherBigEndian : 40|8@0+ (1.0,0) [0|255] ""
641"#,
642 )
643 .unwrap();
644
645 let payload = [
651 0x34, 0x12, 0x00, 0x01, 0xAB, 0xCD, 0x00, 0x00, ];
657 let decoded = dbc.decode(256, &payload, false).unwrap();
658
659 let find_signal = |name: &str| decoded.iter().find(|s| s.name == name).map(|s| s.value);
661
662 assert_eq!(find_signal("LittleEndianSignal"), Some(4660.0)); let big_endian_value = find_signal("BigEndianSignal").unwrap();
667 assert!((0.0..=65535.0).contains(&big_endian_value));
669
670 assert_eq!(find_signal("AnotherLittleEndian"), Some(171.0)); let big_endian_8bit = find_signal("AnotherBigEndian");
675 assert!(big_endian_8bit.is_some());
676 assert!(big_endian_8bit.unwrap() >= 0.0 && big_endian_8bit.unwrap() <= 255.0);
677
678 assert_eq!(decoded.len(), 4);
680
681 assert!(find_signal("LittleEndianSignal").is_some());
683 assert!(find_signal("BigEndianSignal").is_some());
684 }
685
686 #[test]
687 fn test_decode_extended_multiplexing_simple() {
688 let dbc = Dbc::parse(
689 r#"VERSION "1.0"
690
691BU_: ECM
692
693BO_ 500 ComplexMux : 8 ECM
694 SG_ Mux1 M : 0|8@1+ (1,0) [0|255] ""
695 SG_ Signal_A m0 : 16|16@1+ (0.1,0) [0|100] "unit" *
696
697SG_MUL_VAL_ 500 Signal_A Mux1 5-10 ;
698"#,
699 )
700 .unwrap();
701
702 let payload = [0x05, 0x00, 0xE8, 0x03, 0x00, 0x00, 0x00, 0x00];
706 let decoded = dbc.decode(500, &payload, false).unwrap();
707
708 let find_signal = |name: &str| decoded.iter().find(|s| s.name == name).map(|s| s.value);
709
710 assert_eq!(find_signal("Mux1"), Some(5.0));
711 assert_eq!(
713 dbc.extended_multiplexing_for_message(500).count(),
714 1,
715 "Extended multiplexing entries should be parsed"
716 );
717 assert!(
718 find_signal("Signal_A").is_some(),
719 "Signal_A should be decoded when Mux1=5 (within range 5-10)"
720 );
721 assert_eq!(find_signal("Signal_A").unwrap(), 100.0);
722
723 let payload2 = [0x0F, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00];
725 let decoded2 = dbc.decode(500, &payload2, false).unwrap();
726 let find_signal2 = |name: &str| decoded2.iter().find(|s| s.name == name).map(|s| s.value);
727
728 assert_eq!(find_signal2("Mux1"), Some(15.0));
729 assert!(find_signal2("Signal_A").is_none());
730 }
731
732 #[test]
733 fn test_decode_extended_multiplexing_multiple_ranges() {
734 let dbc = Dbc::parse(
735 r#"VERSION "1.0"
736
737BU_: ECM
738
739BO_ 501 MultiRangeMux : 8 ECM
740 SG_ Mux1 M : 0|8@1+ (1,0) [0|255] ""
741 SG_ Signal_B m0 : 16|16@1+ (1,0) [0|65535] "unit" *
742
743SG_MUL_VAL_ 501 Signal_B Mux1 0-5,10-15,20-25 ;
744"#,
745 )
746 .unwrap();
747
748 let payload1 = [0x03, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00];
751 let decoded1 = dbc.decode(501, &payload1, false).unwrap();
752 let find1 = |name: &str| decoded1.iter().find(|s| s.name == name).map(|s| s.value);
753 assert_eq!(find1("Mux1"), Some(3.0));
754 assert!(find1("Signal_B").is_some());
755
756 let payload2 = [0x0C, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00];
759 let decoded2 = dbc.decode(501, &payload2, false).unwrap();
760 let find2 = |name: &str| decoded2.iter().find(|s| s.name == name).map(|s| s.value);
761 assert_eq!(find2("Mux1"), Some(12.0));
762 assert!(find2("Signal_B").is_some());
763
764 let payload3 = [0x16, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00];
767 let decoded3 = dbc.decode(501, &payload3, false).unwrap();
768 let find3 = |name: &str| decoded3.iter().find(|s| s.name == name).map(|s| s.value);
769 assert_eq!(find3("Mux1"), Some(22.0));
770 assert!(find3("Signal_B").is_some());
771
772 let payload4 = [0x08, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00];
775 let decoded4 = dbc.decode(501, &payload4, false).unwrap();
776 let find4 = |name: &str| decoded4.iter().find(|s| s.name == name).map(|s| s.value);
777 assert_eq!(find4("Mux1"), Some(8.0));
778 assert!(find4("Signal_B").is_none());
779 }
780
781 #[test]
784 fn test_decode_extended_multiplexing_multiple_switches() {
785 let dbc = Dbc::parse(
786 r#"VERSION "1.0"
787
788BU_: ECM
789
790BO_ 502 MultiSwitchMux : 8 ECM
791 SG_ Mux1 M : 0|8@1+ (1,0) [0|255] ""
792 SG_ Mux2 M : 8|8@1+ (1,0) [0|255] ""
793 SG_ Signal_C m0 : 16|16@1+ (1,0) [0|65535] "unit" *
794
795SG_MUL_VAL_ 502 Signal_C Mux1 5-10 ;
796SG_MUL_VAL_ 502 Signal_C Mux2 20-25 ;
797"#,
798 )
799 .unwrap();
800
801 let payload1 = [0x07, 0x16, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00];
804 let decoded1 = dbc.decode(502, &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(7.0));
807 assert_eq!(find1("Mux2"), Some(22.0));
808 assert!(find1("Signal_C").is_some());
809
810 let payload2 = [0x07, 0x1E, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00];
812 let decoded2 = dbc.decode(502, &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(7.0));
815 assert_eq!(find2("Mux2"), Some(30.0));
816 assert!(find2("Signal_C").is_none());
817
818 let payload3 = [0x0F, 0x16, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00];
820 let decoded3 = dbc.decode(502, &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(15.0));
823 assert_eq!(find3("Mux2"), Some(22.0));
824 assert!(find3("Signal_C").is_none());
825 }
826
827 #[test]
830 fn test_decode_extended_multiplexing_takes_precedence() {
831 let dbc = Dbc::parse(
832 r#"VERSION "1.0"
833
834BU_: ECM
835
836BO_ 503 PrecedenceTest : 8 ECM
837 SG_ Mux1 M : 0|8@1+ (1,0) [0|255] ""
838 SG_ Signal_D m0 : 16|16@1+ (1,0) [0|65535] "unit" *
839
840SG_MUL_VAL_ 503 Signal_D Mux1 10-15 ;
841"#,
842 )
843 .unwrap();
844
845 let payload1 = [0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00];
849 let decoded1 = dbc.decode(503, &payload1, false).unwrap();
850 let find1 = |name: &str| decoded1.iter().find(|s| s.name == name).map(|s| s.value);
851 assert_eq!(find1("Mux1"), Some(0.0));
852 assert!(find1("Signal_D").is_none());
853
854 let payload2 = [0x0C, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x00];
856 let decoded2 = dbc.decode(503, &payload2, false).unwrap();
857 let find2 = |name: &str| decoded2.iter().find(|s| s.name == name).map(|s| s.value);
858 assert_eq!(find2("Mux1"), Some(12.0));
859 assert!(find2("Signal_D").is_some());
860 }
861
862 #[test]
865 fn test_decode_extended_multiplexing_with_extended_mux_signal() {
866 let dbc = Dbc::parse(
868 r#"VERSION "1.0"
869
870BU_: ECM
871
872BO_ 504 ExtendedMuxSignal : 8 ECM
873 SG_ Mux1 M : 0|8@1+ (1,0) [0|255] ""
874 SG_ Mux2 m65M : 8|8@1+ (1,0) [0|255] ""
875 SG_ Signal_E m0 : 16|16@1+ (1,0) [0|65535] "unit" *
876
877SG_MUL_VAL_ 504 Signal_E Mux1 65-65 ;
878SG_MUL_VAL_ 504 Signal_E Mux2 10-15 ;
879"#,
880 )
881 .unwrap();
882
883 let payload = [0x41, 0x0C, 0x00, 0xA0, 0x00, 0x00, 0x00, 0x00];
886 let decoded = dbc.decode(504, &payload, false).unwrap();
888 let find = |name: &str| decoded.iter().find(|s| s.name == name).map(|s| s.value);
889
890 assert_eq!(find("Mux1"), Some(65.0));
891 assert_eq!(find("Mux2"), Some(12.0));
892 assert!(find("Signal_E").is_some());
893
894 let payload2 = [0x40, 0x0C, 0x00, 0xB0, 0x00, 0x00, 0x00, 0x00];
896 let decoded2 = dbc.decode(504, &payload2, false).unwrap();
897 let find2 = |name: &str| decoded2.iter().find(|s| s.name == name).map(|s| s.value);
898 assert_eq!(find2("Mux1"), Some(64.0));
899 assert_eq!(find2("Mux2"), Some(12.0));
900 assert!(find2("Signal_E").is_none());
901 }
902
903 #[test]
904 fn test_decode_negative_multiplexer_switch() {
905 use crate::Error;
906 let dbc = Dbc::parse(
909 r#"VERSION "1.0"
910
911BU_: ECM
912
913BO_ 256 MuxMessage : 8 ECM
914 SG_ MuxSwitch M : 0|8@1- (1,0) [-128|127] ""
915 SG_ SignalA m0 : 8|8@1+ (1,0) [0|255] ""
916"#,
917 )
918 .unwrap();
919
920 let payload = [0xFB, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
924 let result = dbc.decode(256, &payload, false);
925 assert!(result.is_err());
926 match result.unwrap_err() {
927 Error::Decoding(msg) => {
928 assert_eq!(msg, Error::MULTIPLEXER_SWITCH_NEGATIVE);
929 }
930 _ => panic!("Expected Error::Decoding with MULTIPLEXER_SWITCH_NEGATIVE"),
931 }
932 }
933
934 #[test]
935 fn test_decode_too_many_unique_switches() {
936 use crate::{Error, MAX_SIGNALS_PER_MESSAGE};
937 if MAX_SIGNALS_PER_MESSAGE < 17 {
940 return;
941 }
942
943 let dbc_str = r#"VERSION "1.0"
947
948BU_: ECM
949
950BO_ 600 TooManySwitches : 18 ECM
951 SG_ Mux1 M : 0|8@1+ (1,0) [0|255] ""
952 SG_ Mux2 M : 8|8@1+ (1,0) [0|255] ""
953 SG_ Mux3 M : 16|8@1+ (1,0) [0|255] ""
954 SG_ Mux4 M : 24|8@1+ (1,0) [0|255] ""
955 SG_ Mux5 M : 32|8@1+ (1,0) [0|255] ""
956 SG_ Mux6 M : 40|8@1+ (1,0) [0|255] ""
957 SG_ Mux7 M : 48|8@1+ (1,0) [0|255] ""
958 SG_ Mux8 M : 56|8@1+ (1,0) [0|255] ""
959 SG_ Mux9 M : 64|8@1+ (1,0) [0|255] ""
960 SG_ Mux10 M : 72|8@1+ (1,0) [0|255] ""
961 SG_ Mux11 M : 80|8@1+ (1,0) [0|255] ""
962 SG_ Mux12 M : 88|8@1+ (1,0) [0|255] ""
963 SG_ Mux13 M : 96|8@1+ (1,0) [0|255] ""
964 SG_ Mux14 M : 104|8@1+ (1,0) [0|255] ""
965 SG_ Mux15 M : 112|8@1+ (1,0) [0|255] ""
966 SG_ Mux16 M : 120|8@1+ (1,0) [0|255] ""
967 SG_ Mux17 M : 128|8@1+ (1,0) [0|255] ""
968 SG_ Signal_X m0 : 136|8@1+ (1,0) [0|255] "unit" *
969
970SG_MUL_VAL_ 600 Signal_X Mux1 0-255 ;
971SG_MUL_VAL_ 600 Signal_X Mux2 0-255 ;
972SG_MUL_VAL_ 600 Signal_X Mux3 0-255 ;
973SG_MUL_VAL_ 600 Signal_X Mux4 0-255 ;
974SG_MUL_VAL_ 600 Signal_X Mux5 0-255 ;
975SG_MUL_VAL_ 600 Signal_X Mux6 0-255 ;
976SG_MUL_VAL_ 600 Signal_X Mux7 0-255 ;
977SG_MUL_VAL_ 600 Signal_X Mux8 0-255 ;
978SG_MUL_VAL_ 600 Signal_X Mux9 0-255 ;
979SG_MUL_VAL_ 600 Signal_X Mux10 0-255 ;
980SG_MUL_VAL_ 600 Signal_X Mux11 0-255 ;
981SG_MUL_VAL_ 600 Signal_X Mux12 0-255 ;
982SG_MUL_VAL_ 600 Signal_X Mux13 0-255 ;
983SG_MUL_VAL_ 600 Signal_X Mux14 0-255 ;
984SG_MUL_VAL_ 600 Signal_X Mux15 0-255 ;
985SG_MUL_VAL_ 600 Signal_X Mux16 0-255 ;
986SG_MUL_VAL_ 600 Signal_X Mux17 0-255 ;
987"#;
988
989 let dbc = Dbc::parse(dbc_str).unwrap();
990
991 let payload = [0x00; 18];
994 let result = dbc.decode(600, &payload, false);
995 assert!(
996 result.is_err(),
997 "Decode should fail when there are more than 16 unique switches"
998 );
999 match result.unwrap_err() {
1000 Error::Decoding(msg) => {
1001 assert_eq!(
1002 msg,
1003 Error::MESSAGE_TOO_MANY_SIGNALS,
1004 "Expected MESSAGE_TOO_MANY_SIGNALS error, got: {}",
1005 msg
1006 );
1007 }
1008 e => panic!(
1009 "Expected Error::Decoding with MESSAGE_TOO_MANY_SIGNALS, got: {:?}",
1010 e
1011 ),
1012 }
1013 }
1014
1015 #[test]
1016 fn test_decode_extended_can_id() {
1017 let dbc = Dbc::parse(
1021 r#"VERSION "1.0"
1022
1023BU_: ECM
1024
1025BO_ 2147484672 ExtendedMsg : 8 ECM
1026 SG_ Speed : 0|16@1+ (0.1,0) [0|6553.5] "km/h" *
1027"#,
1028 )
1029 .unwrap();
1030 let payload = [0xE8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
1033 let decoded = dbc.decode(0x400, &payload, true).unwrap();
1037 assert_eq!(decoded.len(), 1);
1038 assert_eq!(decoded[0].name, "Speed");
1039 assert_eq!(decoded[0].value, 100.0);
1040 assert_eq!(decoded[0].unit, Some("km/h"));
1041 }
1042
1043 #[test]
1044 fn test_decode_extended_can_id_not_found_without_flag() {
1045 let dbc = Dbc::parse(
1048 r#"VERSION "1.0"
1049
1050BU_: ECM
1051
1052BO_ 2147484672 ExtendedMsg : 8 ECM
1053 SG_ Speed : 0|16@1+ (0.1,0) [0|6553.5] "km/h" *
1054"#,
1055 )
1056 .unwrap();
1057
1058 let payload = [0xE8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
1059
1060 let result = dbc.decode(0x400, &payload, false);
1062 assert!(result.is_err());
1063 }
1064
1065 #[test]
1066 fn test_decode_standard_vs_extended_same_base_id() {
1067 let dbc = Dbc::parse(
1069 r#"VERSION "1.0"
1070
1071BU_: ECM
1072
1073BO_ 256 StandardMsg : 8 ECM
1074 SG_ StdSignal : 0|8@1+ (1,0) [0|255] "" *
1075
1076BO_ 2147483904 ExtendedMsg : 8 ECM
1077 SG_ ExtSignal : 0|8@1+ (2,0) [0|510] "" *
1078"#,
1079 )
1080 .unwrap();
1081 let payload = [0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; let decoded_std = dbc.decode(256, &payload, false).unwrap();
1087 assert_eq!(decoded_std.len(), 1);
1088 assert_eq!(decoded_std[0].name, "StdSignal");
1089 assert_eq!(decoded_std[0].value, 100.0); let decoded_ext = dbc.decode(256, &payload, true).unwrap();
1093 assert_eq!(decoded_ext.len(), 1);
1094 assert_eq!(decoded_ext[0].name, "ExtSignal");
1095 assert_eq!(decoded_ext[0].value, 200.0); }
1097
1098 #[test]
1099 fn test_decode_with_value_descriptions() {
1100 let dbc = Dbc::parse(
1103 r#"VERSION "1.0"
1104
1105BU_: ECM
1106
1107BO_ 200 GearboxData : 4 ECM
1108 SG_ GearActual : 0|8@1+ (1,0) [0|5] "" *
1109
1110VAL_ 200 GearActual 0 "Park" 1 "Reverse" 2 "Neutral" 3 "Drive" 4 "Sport" 5 "Manual" ;
1111"#,
1112 )
1113 .unwrap();
1114
1115 let payload = [0x00, 0x00, 0x00, 0x00];
1117 let decoded = dbc.decode(200, &payload, false).unwrap();
1118 assert_eq!(decoded.len(), 1);
1119 assert_eq!(decoded[0].name, "GearActual");
1120 assert_eq!(decoded[0].value, 0.0);
1121 assert_eq!(decoded[0].description, Some("Park"));
1122
1123 let payload = [0x03, 0x00, 0x00, 0x00];
1125 let decoded = dbc.decode(200, &payload, false).unwrap();
1126 assert_eq!(decoded[0].value, 3.0);
1127 assert_eq!(decoded[0].description, Some("Drive"));
1128
1129 let payload = [0x05, 0x00, 0x00, 0x00];
1131 let decoded = dbc.decode(200, &payload, false).unwrap();
1132 assert_eq!(decoded[0].value, 5.0);
1133 assert_eq!(decoded[0].description, Some("Manual"));
1134 }
1135
1136 #[test]
1137 fn test_decode_without_value_descriptions() {
1138 let dbc = Dbc::parse(
1140 r#"VERSION "1.0"
1141
1142BU_: ECM
1143
1144BO_ 256 Engine : 8 ECM
1145 SG_ RPM : 0|16@1+ (0.25,0) [0|8000] "rpm" *
1146"#,
1147 )
1148 .unwrap();
1149
1150 let payload = [0x40, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
1151 let decoded = dbc.decode(256, &payload, false).unwrap();
1152 assert_eq!(decoded.len(), 1);
1153 assert_eq!(decoded[0].name, "RPM");
1154 assert_eq!(decoded[0].value, 2000.0);
1155 assert_eq!(decoded[0].unit, Some("rpm"));
1156 assert_eq!(decoded[0].description, None);
1157 }
1158
1159 #[test]
1160 fn test_decode_value_description_not_found() {
1161 let dbc = Dbc::parse(
1163 r#"VERSION "1.0"
1164
1165BU_: ECM
1166
1167BO_ 200 GearboxData : 4 ECM
1168 SG_ GearActual : 0|8@1+ (1,0) [0|255] "" *
1169
1170VAL_ 200 GearActual 0 "Park" 1 "Reverse" 2 "Neutral" ;
1171"#,
1172 )
1173 .unwrap();
1174
1175 let payload = [0x0A, 0x00, 0x00, 0x00];
1177 let decoded = dbc.decode(200, &payload, false).unwrap();
1178 assert_eq!(decoded.len(), 1);
1179 assert_eq!(decoded[0].value, 10.0);
1180 assert_eq!(decoded[0].description, None); }
1182
1183 #[test]
1184 fn test_decode_multiplexer_with_value_descriptions() {
1185 let dbc = Dbc::parse(
1188 r#"VERSION "1.0"
1189
1190BU_: ECM
1191
1192BO_ 300 MultiplexedSensors : 8 ECM
1193 SG_ SensorID M : 0|8@1+ (1,0) [0|3] "" *
1194 SG_ Temperature m0 : 8|16@1- (0.1,-40) [-40|125] "°C" *
1195 SG_ Pressure m1 : 8|16@1+ (0.01,0) [0|655.35] "kPa" *
1196
1197VAL_ 300 SensorID 0 "Temperature Sensor" 1 "Pressure Sensor" 2 "Humidity Sensor" 3 "Voltage Sensor" ;
1198"#,
1199 )
1200 .unwrap();
1201
1202 let payload = [0x00, 0xF4, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00];
1205 let decoded = dbc.decode(300, &payload, false).unwrap();
1206
1207 let sensor_id = decoded.iter().find(|s| s.name == "SensorID").unwrap();
1209 assert_eq!(sensor_id.value, 0.0);
1210 assert_eq!(sensor_id.description, Some("Temperature Sensor"));
1211
1212 let temp = decoded.iter().find(|s| s.name == "Temperature").unwrap();
1214 assert!(temp.description.is_none()); let payload = [0x01, 0x10, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00];
1218 let decoded = dbc.decode(300, &payload, false).unwrap();
1219
1220 let sensor_id = decoded.iter().find(|s| s.name == "SensorID").unwrap();
1221 assert_eq!(sensor_id.value, 1.0);
1222 assert_eq!(sensor_id.description, Some("Pressure Sensor"));
1223 }
1224
1225 #[cfg(feature = "embedded-can")]
1226 mod embedded_can_tests {
1227 use super::*;
1228 use embedded_can::{ExtendedId, Frame, Id, StandardId};
1229
1230 struct TestFrame {
1232 id: Id,
1233 data: [u8; 8],
1234 dlc: usize,
1235 }
1236
1237 impl TestFrame {
1238 fn new_standard(id: u16, data: &[u8]) -> Self {
1239 let mut frame_data = [0u8; 8];
1240 let dlc = data.len().min(8);
1241 frame_data[..dlc].copy_from_slice(&data[..dlc]);
1242 Self {
1243 id: Id::Standard(StandardId::new(id).unwrap()),
1244 data: frame_data,
1245 dlc,
1246 }
1247 }
1248
1249 fn new_extended(id: u32, data: &[u8]) -> Self {
1250 let mut frame_data = [0u8; 8];
1251 let dlc = data.len().min(8);
1252 frame_data[..dlc].copy_from_slice(&data[..dlc]);
1253 Self {
1254 id: Id::Extended(ExtendedId::new(id).unwrap()),
1255 data: frame_data,
1256 dlc,
1257 }
1258 }
1259 }
1260
1261 impl Frame for TestFrame {
1262 fn new(id: impl Into<Id>, data: &[u8]) -> Option<Self> {
1263 let mut frame_data = [0u8; 8];
1264 let dlc = data.len().min(8);
1265 frame_data[..dlc].copy_from_slice(&data[..dlc]);
1266 Some(Self {
1267 id: id.into(),
1268 data: frame_data,
1269 dlc,
1270 })
1271 }
1272
1273 fn new_remote(_id: impl Into<Id>, _dlc: usize) -> Option<Self> {
1274 None }
1276
1277 fn is_extended(&self) -> bool {
1278 matches!(self.id, Id::Extended(_))
1279 }
1280
1281 fn is_remote_frame(&self) -> bool {
1282 false
1283 }
1284
1285 fn id(&self) -> Id {
1286 self.id
1287 }
1288
1289 fn dlc(&self) -> usize {
1290 self.dlc
1291 }
1292
1293 fn data(&self) -> &[u8] {
1294 &self.data[..self.dlc]
1295 }
1296 }
1297
1298 #[test]
1299 fn test_decode_frame_standard() {
1300 let dbc = Dbc::parse(
1301 r#"VERSION "1.0"
1302
1303BU_: ECM
1304
1305BO_ 256 Engine : 8 ECM
1306 SG_ RPM : 0|16@1+ (0.25,0) [0|8000] "rpm" *
1307"#,
1308 )
1309 .unwrap();
1310
1311 let frame =
1313 TestFrame::new_standard(256, &[0x40, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
1314
1315 let decoded = dbc.decode_frame(frame).unwrap();
1316 assert_eq!(decoded.len(), 1);
1317 assert_eq!(decoded[0].name, "RPM");
1318 assert_eq!(decoded[0].value, 2000.0);
1319 assert_eq!(decoded[0].unit, Some("rpm"));
1320 }
1321
1322 #[test]
1323 fn test_decode_frame_extended() {
1324 let dbc = Dbc::parse(
1326 r#"VERSION "1.0"
1327
1328BU_: ECM
1329
1330BO_ 2147484672 ExtendedMsg : 8 ECM
1331 SG_ Speed : 0|16@1+ (0.1,0) [0|6553.5] "km/h" *
1332"#,
1333 )
1334 .unwrap();
1335 let frame =
1339 TestFrame::new_extended(0x400, &[0xE8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
1340
1341 let decoded = dbc.decode_frame(frame).unwrap();
1342 assert_eq!(decoded.len(), 1);
1343 assert_eq!(decoded[0].name, "Speed");
1344 assert_eq!(decoded[0].value, 100.0);
1345 assert_eq!(decoded[0].unit, Some("km/h"));
1346 }
1347
1348 #[test]
1349 fn test_decode_frame_standard_vs_extended() {
1350 let dbc = Dbc::parse(
1352 r#"VERSION "1.0"
1353
1354BU_: ECM
1355
1356BO_ 256 StandardMsg : 8 ECM
1357 SG_ StdSignal : 0|8@1+ (1,0) [0|255] "" *
1358
1359BO_ 2147483904 ExtendedMsg : 8 ECM
1360 SG_ ExtSignal : 0|8@1+ (2,0) [0|510] "" *
1361"#,
1362 )
1363 .unwrap();
1364 let payload = [0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; let std_frame = TestFrame::new_standard(256, &payload);
1370 let decoded_std = dbc.decode_frame(std_frame).unwrap();
1371 assert_eq!(decoded_std[0].name, "StdSignal");
1372 assert_eq!(decoded_std[0].value, 100.0);
1373
1374 let ext_frame = TestFrame::new_extended(256, &payload);
1376 let decoded_ext = dbc.decode_frame(ext_frame).unwrap();
1377 assert_eq!(decoded_ext[0].name, "ExtSignal");
1378 assert_eq!(decoded_ext[0].value, 200.0);
1379 }
1380
1381 #[test]
1382 fn test_decode_frame_message_not_found() {
1383 let dbc = Dbc::parse(
1384 r#"VERSION "1.0"
1385
1386BU_: ECM
1387
1388BO_ 256 Engine : 8 ECM
1389"#,
1390 )
1391 .unwrap();
1392
1393 let frame =
1395 TestFrame::new_standard(512, &[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
1396 let result = dbc.decode_frame(frame);
1397 assert!(result.is_err());
1398 }
1399 }
1400}