1use crate::{
2 BitTiming, Dbc, Error, ExtendedMultiplexing, MAX_EXTENDED_MULTIPLEXING, MAX_MESSAGES,
3 MAX_NODES, MAX_SIGNALS_PER_MESSAGE, Message, Nodes, Parser, Result, Signal, ValueDescriptions,
4 Version,
5 compat::{Comment, Name, ValueDescEntries, Vec},
6 dbc::{Messages, Validate, ValueDescriptionsMap},
7};
8
9impl Dbc {
10 pub fn parse(data: &str) -> Result<Self> {
29 let mut parser = Parser::new(data.as_bytes())?;
30
31 let mut messages_buffer: Vec<Message, { MAX_MESSAGES }> = Vec::new();
32
33 let mut message_count_actual = 0;
34
35 use crate::{
37 BA_, BA_DEF_, BA_DEF_DEF_, BO_, BO_TX_BU_, BS_, BU_, CM_, EV_, NS_, SG_, SG_MUL_VAL_,
38 SIG_GROUP_, SIG_VALTYPE_, VAL_, VAL_TABLE_, VERSION,
39 };
40
41 let mut version: Option<Version> = None;
42 let mut bit_timing: Option<BitTiming> = None;
43 let mut nodes: Option<Nodes> = None;
44
45 type ValueDescBufferEntry = (Option<u32>, Name, ValueDescEntries);
47 type ValueDescBuffer = Vec<ValueDescBufferEntry, { MAX_MESSAGES }>;
48 type ExtMuxBuffer = Vec<ExtendedMultiplexing, { MAX_EXTENDED_MULTIPLEXING }>;
49
50 type MessageCommentBuffer = Vec<(u32, Comment), { MAX_MESSAGES }>;
53 type SignalCommentBuffer = Vec<(u32, Name, Comment), { MAX_MESSAGES * 4 }>;
55
56 let mut value_descriptions_buffer: ValueDescBuffer = ValueDescBuffer::new();
57 let mut extended_multiplexing_buffer: ExtMuxBuffer = ExtMuxBuffer::new();
58
59 let mut db_comment: Option<Comment> = None;
61 type NodeCommentBuffer = Vec<(Name, Comment), { MAX_NODES }>;
63 let mut node_comments_buffer: NodeCommentBuffer = NodeCommentBuffer::new();
64 let mut message_comments_buffer: MessageCommentBuffer = MessageCommentBuffer::new();
65 let mut signal_comments_buffer: SignalCommentBuffer = SignalCommentBuffer::new();
66
67 loop {
68 parser.skip_newlines_and_spaces();
70 if parser.starts_with(b"//") {
71 parser.skip_to_end_of_line();
72 continue;
73 }
74
75 let keyword_result = parser.peek_next_keyword();
76 let keyword = match keyword_result {
77 Ok(kw) => kw,
78 Err(Error::UnexpectedEof { .. }) => break,
79 Err(Error::Expected { .. }) => {
80 if parser.starts_with(b"//") {
81 parser.skip_to_end_of_line();
82 continue;
83 }
84 return Err(keyword_result.unwrap_err());
85 }
86 Err(e) => return Err(e),
87 };
88
89 let pos_at_keyword = parser.pos();
91
92 match keyword {
93 NS_ => {
94 let line = parser.line();
96 parser
97 .expect(crate::NS_.as_bytes())
98 .map_err(|_| Error::expected_at("Failed to consume NS_ keyword", line))?;
99 parser.skip_newlines_and_spaces();
100 let _ = parser.expect(b":").ok();
101 loop {
102 parser.skip_newlines_and_spaces();
103 if parser.is_empty() {
104 break;
105 }
106 if parser.starts_with(b" ") || parser.starts_with(b"\t") {
107 parser.skip_to_end_of_line();
108 continue;
109 }
110 if parser.starts_with(b"//") {
111 parser.skip_to_end_of_line();
112 continue;
113 }
114 if parser.starts_with(BS_.as_bytes())
115 || parser.starts_with(BU_.as_bytes())
116 || parser.starts_with(BO_.as_bytes())
117 || parser.starts_with(SG_.as_bytes())
118 || parser.starts_with(VERSION.as_bytes())
119 {
120 break;
121 }
122 parser.skip_to_end_of_line();
123 }
124 continue;
125 }
126 BS_ => {
127 let parsed = BitTiming::parse(&mut parser)?;
129 if !parsed.is_empty() {
131 bit_timing = Some(parsed);
132 }
133 parser.skip_to_end_of_line();
134 continue;
135 }
136 VAL_TABLE_ | BA_DEF_ | BA_DEF_DEF_ | BA_ | SIG_GROUP_ | SIG_VALTYPE_ | EV_
137 | BO_TX_BU_ => {
138 let _ = parser.expect(keyword.as_bytes()).ok();
154 parser.skip_to_end_of_line();
155 continue;
156 }
157 CM_ => {
158 let _ = parser.expect(crate::CM_.as_bytes()).ok();
165 parser.skip_newlines_and_spaces();
166
167 if parser.starts_with(b"\"") {
169 if parser.expect(b"\"").is_ok() {
171 if let Ok(comment_bytes) = parser.take_until_quote(false, 1024) {
172 if let Ok(comment_str) = core::str::from_utf8(comment_bytes) {
173 if let Ok(comment) = Comment::try_from(comment_str) {
174 db_comment = Some(comment);
175 }
176 }
177 }
178 }
179 parser.skip_to_end_of_line();
180 } else if parser.starts_with(BU_.as_bytes()) {
181 let _ = parser.expect(BU_.as_bytes()).ok();
183 parser.skip_newlines_and_spaces();
184 if let Ok(node_name_bytes) = parser.parse_identifier() {
185 if let Ok(node_name) = Name::try_from(node_name_bytes) {
186 parser.skip_newlines_and_spaces();
187 if parser.expect(b"\"").is_ok() {
188 if let Ok(comment_bytes) = parser.take_until_quote(false, 1024)
189 {
190 if let Ok(comment_str) = core::str::from_utf8(comment_bytes)
191 {
192 if let Ok(comment) = Comment::try_from(comment_str) {
193 let _ =
194 node_comments_buffer.push((node_name, comment));
195 }
196 }
197 }
198 }
199 }
200 }
201 parser.skip_to_end_of_line();
202 } else if parser.starts_with(BO_.as_bytes()) {
203 let _ = parser.expect(BO_.as_bytes()).ok();
205 parser.skip_newlines_and_spaces();
206 if let Ok(message_id) = parser.parse_u32() {
207 parser.skip_newlines_and_spaces();
208 if parser.expect(b"\"").is_ok() {
209 if let Ok(comment_bytes) = parser.take_until_quote(false, 1024) {
210 if let Ok(comment_str) = core::str::from_utf8(comment_bytes) {
211 if let Ok(comment) = Comment::try_from(comment_str) {
212 let _ =
213 message_comments_buffer.push((message_id, comment));
214 }
215 }
216 }
217 }
218 }
219 parser.skip_to_end_of_line();
220 } else if parser.starts_with(SG_.as_bytes()) {
221 let _ = parser.expect(SG_.as_bytes()).ok();
223 parser.skip_newlines_and_spaces();
224 if let Ok(message_id) = parser.parse_u32() {
225 parser.skip_newlines_and_spaces();
226 if let Ok(signal_name_bytes) = parser.parse_identifier() {
227 if let Ok(signal_name) = Name::try_from(signal_name_bytes) {
228 parser.skip_newlines_and_spaces();
229 if parser.expect(b"\"").is_ok() {
230 if let Ok(comment_bytes) =
231 parser.take_until_quote(false, 1024)
232 {
233 if let Ok(comment_str) =
234 core::str::from_utf8(comment_bytes)
235 {
236 if let Ok(comment) = Comment::try_from(comment_str)
237 {
238 let _ = signal_comments_buffer.push((
239 message_id,
240 signal_name,
241 comment,
242 ));
243 }
244 }
245 }
246 }
247 }
248 }
249 }
250 parser.skip_to_end_of_line();
251 } else {
252 parser.skip_to_end_of_line();
254 }
255 continue;
256 }
257 SG_MUL_VAL_ => {
258 let line = parser.line();
260 parser.expect(SG_MUL_VAL_.as_bytes()).map_err(|_| {
261 Error::expected_at("Failed to consume SG_MUL_VAL_ keyword", line)
262 })?;
263
264 if let Some(ext_mux) = ExtendedMultiplexing::parse(&mut parser) {
266 if extended_multiplexing_buffer.push(ext_mux).is_err() {
267 return Err(Error::Validation(Error::EXTENDED_MULTIPLEXING_TOO_MANY));
269 }
270 } else {
271 parser.skip_to_end_of_line();
273 }
274 continue;
275 }
276 VAL_ => {
277 let _ = parser.expect(crate::VAL_.as_bytes()).ok();
279 parser.skip_newlines_and_spaces();
283 let message_id = match parser.parse_i64() {
284 Ok(id) => {
285 if id == -1 {
287 None
288 } else if id >= 0 && id <= u32::MAX as i64 {
289 Some(id as u32)
290 } else {
291 parser.skip_to_end_of_line();
292 continue;
293 }
294 }
295 Err(_) => {
296 parser.skip_to_end_of_line();
297 continue;
298 }
299 };
300 parser.skip_newlines_and_spaces();
301 let signal_name = match parser.parse_identifier() {
302 Ok(name) => match Name::try_from(name) {
303 Ok(s) => s,
304 Err(_) => {
305 parser.skip_to_end_of_line();
306 continue;
307 }
308 },
309 Err(_) => {
310 parser.skip_to_end_of_line();
311 continue;
312 }
313 };
314 let mut entries: ValueDescEntries = ValueDescEntries::new();
316 loop {
317 parser.skip_newlines_and_spaces();
318 if parser.starts_with(b";") {
320 parser.expect(b";").ok();
321 break;
322 }
323 let value = match parser.parse_i64() {
327 Ok(v) => {
328 if v == -1 { 0xFFFF_FFFFu64 } else { v as u64 }
330 }
331 Err(_) => {
332 parser.skip_to_end_of_line();
333 break;
334 }
335 };
336 parser.skip_newlines_and_spaces();
337 if parser.expect(b"\"").is_err() {
339 parser.skip_to_end_of_line();
340 break;
341 }
342 let description_bytes = match parser.take_until_quote(false, 1024) {
343 Ok(bytes) => bytes,
344 Err(_) => {
345 parser.skip_to_end_of_line();
346 break;
347 }
348 };
349 let description = match core::str::from_utf8(description_bytes)
350 .ok()
351 .and_then(|s| Name::try_from(s).ok())
352 {
353 Some(desc) => desc,
354 None => {
355 parser.skip_to_end_of_line();
356 break;
357 }
358 };
359 let _ = entries.push((value, description));
360 }
361 if !entries.is_empty() {
362 let _ = value_descriptions_buffer.push((message_id, signal_name, entries));
363 }
364 continue;
365 }
366 VERSION => {
367 version = Some(Version::parse(&mut parser)?);
369 continue;
370 }
371 BU_ => {
372 parser.skip_to_end_of_line();
374 let bu_input = &data.as_bytes()[pos_at_keyword..parser.pos()];
375 let mut bu_parser = Parser::new(bu_input)?;
376 nodes = Some(Nodes::parse(&mut bu_parser)?);
377 continue;
378 }
379 BO_ => {
380 if message_count_actual >= MAX_MESSAGES {
382 return Err(parser.err_nodes(Error::NODES_TOO_MANY));
383 }
384
385 let message_start_pos = pos_at_keyword;
387
388 let header_line_end = {
391 let mut temp_parser = Parser::new(&data.as_bytes()[pos_at_keyword..])?;
393 temp_parser.expect(crate::BO_.as_bytes()).ok();
395 temp_parser.skip_whitespace().ok();
396 temp_parser.parse_u32().ok(); temp_parser.skip_whitespace().ok();
398 temp_parser.parse_identifier().ok(); temp_parser.skip_whitespace().ok();
400 temp_parser.expect(b":").ok(); temp_parser.skip_whitespace().ok();
402 temp_parser.parse_u8().ok(); temp_parser.skip_whitespace().ok();
404 temp_parser.parse_identifier().ok(); pos_at_keyword + temp_parser.pos()
406 };
407
408 parser.skip_to_end_of_line(); let mut signals_array: Vec<Signal, { MAX_SIGNALS_PER_MESSAGE }> = Vec::new();
412
413 loop {
415 parser.skip_newlines_and_spaces();
416
417 let keyword_result = parser.peek_next_keyword();
420 let keyword = match keyword_result {
421 Ok(kw) => kw,
422 Err(Error::UnexpectedEof { .. }) => break,
423 Err(_) => break, };
425
426 if keyword != SG_ {
428 break; }
430
431 if signals_array.len() >= MAX_SIGNALS_PER_MESSAGE {
433 return Err(parser.err_message(Error::MESSAGE_TOO_MANY_SIGNALS));
434 }
435
436 match Signal::parse(&mut parser) {
438 Ok(signal) => {
439 signals_array.push(signal).map_err(|_| {
440 parser.err_receivers(Error::SIGNAL_RECEIVERS_TOO_MANY)
441 })?;
442 if parser.at_newline() {
445 parser.skip_to_end_of_line();
446 }
447 }
448 Err(_) => {
449 parser.skip_to_end_of_line();
451 break;
452 }
453 }
454 }
455
456 let message_input = &data.as_bytes()[message_start_pos..header_line_end];
460 let mut message_parser = Parser::new(message_input)?;
461
462 let message = Message::parse(&mut message_parser, signals_array.as_slice())?;
464
465 messages_buffer
466 .push(message)
467 .map_err(|_| parser.err_message(Error::NODES_TOO_MANY))?;
468 message_count_actual += 1;
469 continue;
470 }
471 SG_ => {
472 parser.skip_to_end_of_line();
474 continue;
475 }
476 _ => {
477 parser.skip_to_end_of_line();
478 continue;
479 }
480 }
481 }
482
483 let mut nodes = nodes.unwrap_or_default();
485
486 for (node_name, comment) in node_comments_buffer.iter() {
488 nodes.set_node_comment(node_name.as_str(), comment.clone());
489 }
490
491 let version = version.or_else(|| {
493 static EMPTY_VERSION: &[u8] = b"VERSION \"\"";
494 let mut parser = Parser::new(EMPTY_VERSION).ok()?;
495 Version::parse(&mut parser).ok()
496 });
497
498 let value_descriptions_map = {
500 let mut map: crate::compat::BTreeMap<
501 (Option<u32>, Name),
502 ValueDescriptions,
503 { MAX_MESSAGES },
504 > = crate::compat::BTreeMap::new();
505 for (message_id, signal_name, entries) in value_descriptions_buffer.iter() {
506 let key = (*message_id, signal_name.clone());
507 let value_descriptions = ValueDescriptions::new(entries.clone());
508 let _ = map.insert(key, value_descriptions);
509 }
510 ValueDescriptionsMap::new(map)
511 };
512
513 for (message_id, comment) in message_comments_buffer.iter() {
516 for msg in messages_buffer.iter_mut() {
517 if msg.id() == *message_id || msg.id_with_flag() == *message_id {
518 msg.set_comment(comment.clone());
519 break;
520 }
521 }
522 }
523
524 for (message_id, signal_name, comment) in signal_comments_buffer.iter() {
526 for msg in messages_buffer.iter_mut() {
527 if msg.id() == *message_id || msg.id_with_flag() == *message_id {
528 if let Some(signal) = msg.signals_mut().find_mut(signal_name.as_str()) {
529 signal.set_comment(comment.clone());
530 }
531 break;
532 }
533 }
534 }
535
536 let messages_slice: &[Message] = messages_buffer.as_slice();
538 let extended_multiplexing_slice: &[ExtendedMultiplexing] =
539 extended_multiplexing_buffer.as_slice();
540
541 Validate::validate(
543 &nodes,
544 messages_slice,
545 Some(&value_descriptions_map),
546 Some(extended_multiplexing_slice),
547 )
548 .map_err(|e| {
549 crate::error::map_val_error(e, Error::message, || {
550 Error::message(Error::MESSAGE_ERROR_PREFIX)
551 })
552 })?;
553
554 let messages = Messages::new(messages_slice)?;
556
557 Ok(Dbc::new(
558 version,
559 bit_timing,
560 nodes,
561 messages,
562 value_descriptions_map,
563 extended_multiplexing_buffer,
564 db_comment,
565 ))
566 }
567
568 pub fn parse_bytes(data: &[u8]) -> Result<Self> {
581 let content =
582 core::str::from_utf8(data).map_err(|_e| Error::expected(Error::INVALID_UTF8))?;
583 Dbc::parse(content)
584 }
585}
586
587#[cfg(test)]
588mod tests {
589 use crate::Dbc;
590
591 #[test]
592 fn test_parse_basic() {
593 let dbc_content = r#"VERSION "1.0"
594
595BU_: ECM
596
597BO_ 256 Engine : 8 ECM
598 SG_ RPM : 0|16@1+ (0.25,0) [0|8000] "rpm"
599"#;
600 let dbc = Dbc::parse(dbc_content).unwrap();
601 assert_eq!(dbc.version().map(|v| v.as_str()), Some("1.0"));
602 assert!(dbc.nodes().contains("ECM"));
603 assert_eq!(dbc.messages().len(), 1);
604 }
605
606 #[test]
607 fn test_parse_bytes() {
608 let dbc_bytes = b"VERSION \"1.0\"\n\nBU_: ECM\n\nBO_ 256 Engine : 8 ECM";
609 let dbc = Dbc::parse_bytes(dbc_bytes).unwrap();
610 assert_eq!(dbc.version().map(|v| v.as_str()), Some("1.0"));
611 assert!(dbc.nodes().contains("ECM"));
612 assert_eq!(dbc.messages().len(), 1);
613 }
614
615 #[test]
616 fn test_parse_empty_nodes() {
617 let dbc_content = r#"VERSION "1.0"
618
619BU_:
620
621BO_ 256 Engine : 8 ECM
622"#;
623 let dbc = Dbc::parse(dbc_content).unwrap();
624 assert!(dbc.nodes().is_empty());
625 }
626
627 #[test]
628 fn test_parse_no_version() {
629 let dbc_content = r#"BU_: ECM
630
631BO_ 256 Engine : 8 ECM
632"#;
633 let dbc = Dbc::parse(dbc_content).unwrap();
634 assert!(dbc.version().is_some());
636 }
637
638 #[test]
639 fn parses_real_dbc() {
640 let data = r#"VERSION "1.0"
641
642BU_: ECM TCM
643
644BO_ 256 Engine : 8 ECM
645 SG_ RPM : 0|16@1+ (0.25,0) [0|8000] "rpm"
646 SG_ Temp : 16|8@1- (1,-40) [-40|215] "°C"
647
648BO_ 512 Brake : 4 TCM
649 SG_ Pressure : 0|16@1+ (0.1,0) [0|1000] "bar""#;
650
651 let dbc = Dbc::parse(data).unwrap();
652 assert_eq!(dbc.messages().len(), 2);
653 let mut messages_iter = dbc.messages().iter();
654 let msg0 = messages_iter.next().unwrap();
655 assert_eq!(msg0.signals().len(), 2);
656 let mut signals_iter = msg0.signals().iter();
657 assert_eq!(signals_iter.next().unwrap().name(), "RPM");
658 assert_eq!(signals_iter.next().unwrap().name(), "Temp");
659 let msg1 = messages_iter.next().unwrap();
660 assert_eq!(msg1.signals().len(), 1);
661 assert_eq!(msg1.signals().iter().next().unwrap().name(), "Pressure");
662 }
663
664 #[test]
665 fn test_parse_duplicate_message_id() {
666 use crate::Error;
667 let data = r#"VERSION "1.0"
669
670BU_: ECM
671
672BO_ 256 EngineData1 : 8 ECM
673 SG_ RPM : 0|16@0+ (0.25,0) [0|8000] "rpm"
674
675BO_ 256 EngineData2 : 8 ECM
676 SG_ Temp : 16|8@0- (1,-40) [-40|215] "°C"
677"#;
678
679 let result = Dbc::parse(data);
680 assert!(result.is_err());
681 match result.unwrap_err() {
682 Error::Message { msg, .. } => {
683 assert!(msg.contains(Error::DUPLICATE_MESSAGE_ID));
684 }
685 _ => panic!("Expected Error::Message"),
686 }
687 }
688
689 #[test]
690 fn test_parse_sender_not_in_nodes() {
691 use crate::Error;
692 let data = r#"VERSION "1.0"
694
695BU_: ECM
696
697BO_ 256 EngineData : 8 TCM
698 SG_ RPM : 0|16@0+ (0.25,0) [0|8000] "rpm"
699"#;
700
701 let result = Dbc::parse(data);
702 assert!(result.is_err());
703 match result.unwrap_err() {
704 Error::Message { msg, .. } => {
705 assert!(msg.contains(Error::SENDER_NOT_IN_NODES));
706 }
707 _ => panic!("Expected Error::Message"),
708 }
709 }
710
711 #[test]
712 fn test_parse_empty_file() {
713 use crate::Error;
714 let result = Dbc::parse("");
716 assert!(result.is_err());
717 match result.unwrap_err() {
718 Error::UnexpectedEof { .. } => {
719 }
721 _ => panic!("Expected Error::UnexpectedEof"),
722 }
723 }
724
725 #[test]
726 fn test_parse_bytes_invalid_utf8() {
727 use crate::Error;
728 let invalid_bytes = &[0xFF, 0xFE, 0xFD];
730 let result = Dbc::parse_bytes(invalid_bytes);
731 assert!(result.is_err());
732 match result.unwrap_err() {
733 Error::Expected { msg, .. } => {
734 assert_eq!(msg, Error::INVALID_UTF8);
735 }
736 _ => panic!("Expected Error::Expected with INVALID_UTF8"),
737 }
738 }
739
740 #[test]
741 fn test_parse_without_version_with_comment() {
742 let data = r#"// This is a comment
744BU_: ECM
745
746BO_ 256 Engine : 8 ECM
747 SG_ RPM : 0|16@1+ (0.25,0) [0|8000] "rpm"
748"#;
749 let dbc = Dbc::parse(data).unwrap();
750 assert_eq!(dbc.version().map(|v| v.as_str()), Some(""));
751 }
752
753 #[test]
754 fn test_parse_with_strict_boundary_check() {
755 let data = r#"VERSION "1.0"
757
758BU_: ECM
759
760BO_ 256 Test : 8 ECM
761 SG_ CHECKSUM : 63|8@1+ (1,0) [0|255] ""
762"#;
763
764 let result = Dbc::parse(data);
766 assert!(result.is_err());
767 }
768
769 #[cfg(feature = "std")]
770 #[test]
771 fn test_parse_val_value_descriptions() {
772 let data = r#"VERSION ""
773
774NS_ :
775
776BS_:
777
778BU_: Node1 Node2
779
780BO_ 100 Message1 : 8 Node1
781 SG_ Signal : 32|8@1- (1,0) [-1|4] "Gear" Node2
782
783VAL_ 100 Signal -1 "Reverse" 0 "Neutral" 1 "First" 2 "Second" 3 "Third" 4 "Fourth" ;
784"#;
785
786 let dbc = match Dbc::parse(data) {
787 Ok(dbc) => dbc,
788 Err(e) => panic!("Failed to parse DBC: {:?}", e),
789 };
790
791 assert_eq!(dbc.messages().len(), 1);
793 let message = dbc.messages().iter().find(|m| m.id() == 100).unwrap();
794 assert_eq!(message.name(), "Message1");
795 assert_eq!(message.sender(), "Node1");
796
797 let value_descriptions = dbc
799 .value_descriptions_for_signal(100, "Signal")
800 .expect("Value descriptions should exist");
801 assert_eq!(value_descriptions.get(0xFFFFFFFF), Some("Reverse")); assert_eq!(value_descriptions.get(0), Some("Neutral"));
803 assert_eq!(value_descriptions.get(1), Some("First"));
804 assert_eq!(value_descriptions.get(2), Some("Second"));
805 assert_eq!(value_descriptions.get(3), Some("Third"));
806 assert_eq!(value_descriptions.get(4), Some("Fourth"));
807 }
808
809 #[cfg(feature = "std")]
810 #[test]
811 fn test_parse_val_global_value_descriptions() {
812 let data = r#"VERSION "1.0"
814
815NS_ :
816
817 VAL_
818
819BS_:
820
821BU_: ECU DASH
822
823BO_ 256 EngineData: 8 ECU
824 SG_ EngineRPM : 0|16@1+ (0.125,0) [0|8000] "rpm" Vector__XXX
825 SG_ DI_gear : 24|3@1+ (1,0) [0|7] "" Vector__XXX
826
827BO_ 512 DashboardDisplay: 8 DASH
828 SG_ DI_gear : 0|3@1+ (1,0) [0|7] "" Vector__XXX
829 SG_ SpeedDisplay : 8|16@1+ (0.01,0) [0|300] "km/h" Vector__XXX
830
831VAL_ -1 DI_gear 0 "INVALID" 1 "P" 2 "R" 3 "N" 4 "D" 5 "S" 6 "L" 7 "SNA" ;
832"#;
833
834 let dbc = match Dbc::parse(data) {
835 Ok(dbc) => dbc,
836 Err(e) => panic!("Failed to parse DBC: {:?}", e),
837 };
838
839 assert_eq!(dbc.messages().len(), 2);
841
842 let engine_msg = dbc.messages().iter().find(|m| m.id() == 256).unwrap();
844 assert_eq!(engine_msg.name(), "EngineData");
845 assert_eq!(engine_msg.sender(), "ECU");
846 let di_gear_signal1 = engine_msg.signals().find("DI_gear").unwrap();
847 assert_eq!(di_gear_signal1.name(), "DI_gear");
848 assert_eq!(di_gear_signal1.start_bit(), 24);
849
850 let dash_msg = dbc.messages().iter().find(|m| m.id() == 512).unwrap();
852 assert_eq!(dash_msg.name(), "DashboardDisplay");
853 assert_eq!(dash_msg.sender(), "DASH");
854 let di_gear_signal2 = dash_msg.signals().find("DI_gear").unwrap();
855 assert_eq!(di_gear_signal2.name(), "DI_gear");
856 assert_eq!(di_gear_signal2.start_bit(), 0);
857
858 let value_descriptions1 = dbc
860 .value_descriptions_for_signal(256, "DI_gear")
861 .expect("Global value descriptions should exist for DI_gear in message 256");
862
863 assert_eq!(value_descriptions1.get(0), Some("INVALID"));
864 assert_eq!(value_descriptions1.get(1), Some("P"));
865 assert_eq!(value_descriptions1.get(2), Some("R"));
866 assert_eq!(value_descriptions1.get(3), Some("N"));
867 assert_eq!(value_descriptions1.get(4), Some("D"));
868 assert_eq!(value_descriptions1.get(5), Some("S"));
869 assert_eq!(value_descriptions1.get(6), Some("L"));
870 assert_eq!(value_descriptions1.get(7), Some("SNA"));
871
872 let value_descriptions2 = dbc
874 .value_descriptions_for_signal(512, "DI_gear")
875 .expect("Global value descriptions should exist for DI_gear in message 512");
876
877 assert_eq!(value_descriptions2.get(0), Some("INVALID"));
879 assert_eq!(value_descriptions2.get(1), Some("P"));
880 assert_eq!(value_descriptions2.get(2), Some("R"));
881 assert_eq!(value_descriptions2.get(3), Some("N"));
882 assert_eq!(value_descriptions2.get(4), Some("D"));
883 assert_eq!(value_descriptions2.get(5), Some("S"));
884 assert_eq!(value_descriptions2.get(6), Some("L"));
885 assert_eq!(value_descriptions2.get(7), Some("SNA"));
886
887 assert_eq!(value_descriptions1.len(), value_descriptions2.len());
890 assert_eq!(value_descriptions1.len(), 8);
891
892 assert_eq!(dbc.value_descriptions_for_signal(256, "EngineRPM"), None);
894 assert_eq!(dbc.value_descriptions_for_signal(512, "SpeedDisplay"), None);
895 }
896
897 #[test]
906 fn test_spec_section_8_3_dlc_zero_is_valid() {
907 let data = r#"VERSION "1.0"
909
910BU_: ECM
911
912BO_ 256 ControlMessage : 0 ECM
913"#;
914 let dbc = Dbc::parse(data).unwrap();
915 assert_eq!(dbc.messages().len(), 1);
916 let msg = dbc.messages().iter().next().unwrap();
917 assert_eq!(msg.dlc(), 0);
918 }
919
920 #[test]
924 fn test_spec_section_8_1_extended_can_id_format() {
925 let data = r#"VERSION "1.0"
928
929BU_: ECM
930
931BO_ 2147484820 ExtendedMessage : 8 ECM
932"#;
933 let dbc = Dbc::parse(data).unwrap();
934 assert_eq!(dbc.messages().len(), 1);
935 let msg = dbc.messages().iter().next().unwrap();
936 assert_eq!(msg.id(), 0x494); assert!(msg.is_extended()); }
940
941 #[test]
943 fn test_spec_section_8_1_max_extended_id() {
944 let data = r#"VERSION "1.0"
946
947BU_: ECM
948
949BO_ 2684354559 MaxExtendedId : 8 ECM
950"#;
951 let dbc = Dbc::parse(data).unwrap();
952 assert_eq!(dbc.messages().len(), 1);
953 let msg = dbc.messages().iter().next().unwrap();
954 assert_eq!(msg.id(), 0x1FFFFFFF);
956 assert!(msg.is_extended());
957 }
958
959 #[test]
962 fn test_spec_section_8_4_vector_xxx_transmitter() {
963 let data = r#"VERSION "1.0"
964
965BU_: Gateway
966
967BO_ 256 UnknownSender : 8 Vector__XXX
968 SG_ Signal1 : 0|8@1+ (1,0) [0|255] "" Gateway
969"#;
970 let dbc = Dbc::parse(data).unwrap();
971 assert_eq!(dbc.messages().len(), 1);
972 let msg = dbc.messages().iter().next().unwrap();
973 assert_eq!(msg.sender(), "Vector__XXX");
974 }
975
976 #[test]
979 fn test_spec_section_9_5_receivers_comma_separated() {
980 use crate::{Parser, Signal};
984
985 let signal = Signal::parse(
987 &mut Parser::new(b"SG_ RPM : 0|16@1+ (0.25,0) [0|8000] \"rpm\" Gateway,Dashboard")
988 .unwrap(),
989 )
990 .unwrap();
991 assert_eq!(signal.receivers().len(), 2);
992 let mut receivers = signal.receivers().iter();
993 assert_eq!(receivers.next(), Some("Gateway"));
994 assert_eq!(receivers.next(), Some("Dashboard"));
995 }
996
997 #[test]
1000 fn test_spec_section_9_4_multiplexer_indicators() {
1001 let data = r#"VERSION "1.0"
1002
1003BU_: ECM Gateway
1004
1005BO_ 400 MultiplexedMsg : 8 ECM
1006 SG_ MuxSwitch M : 0|8@1+ (1,0) [0|255] "" Gateway
1007 SG_ Signal_0 m0 : 8|16@1+ (0.1,0) [0|1000] "kPa" Gateway
1008 SG_ Signal_1 m1 : 8|16@1+ (0.01,0) [0|100] "degC" Gateway
1009"#;
1010 let dbc = Dbc::parse(data).unwrap();
1011 let msg = dbc.messages().iter().next().unwrap();
1012
1013 let mux_switch = msg.signals().find("MuxSwitch").unwrap();
1015 let signal_0 = msg.signals().find("Signal_0").unwrap();
1016 let signal_1 = msg.signals().find("Signal_1").unwrap();
1017
1018 assert!(mux_switch.is_multiplexer_switch());
1020 assert_eq!(mux_switch.multiplexer_switch_value(), None);
1021
1022 assert!(!signal_0.is_multiplexer_switch());
1024 assert_eq!(signal_0.multiplexer_switch_value(), Some(0));
1025
1026 assert!(!signal_1.is_multiplexer_switch());
1027 assert_eq!(signal_1.multiplexer_switch_value(), Some(1));
1028 }
1029
1030 #[test]
1031 fn test_error_includes_line_number() {
1032 let data = r#"VERSION "1.0"
1034
1035BU_: ECM
1036
1037BO_ invalid EngineData : 8 ECM
1038"#;
1039
1040 let result = Dbc::parse(data);
1041 assert!(result.is_err());
1042 let err = result.unwrap_err();
1043 assert!(err.line().is_some(), "Error should include line number");
1045 }
1046
1047 #[test]
1053 fn test_parse_cm_database_comment() {
1054 let data = r#"VERSION "1.0"
1055
1056BU_: ECM
1057
1058BO_ 256 Engine : 8 ECM
1059
1060CM_ "This is the database comment";
1061"#;
1062 let dbc = Dbc::parse(data).unwrap();
1063 assert_eq!(dbc.comment(), Some("This is the database comment"));
1064 }
1065
1066 #[test]
1068 fn test_parse_cm_node_comment() {
1069 let data = r#"VERSION "1.0"
1070
1071BU_: ECM
1072
1073BO_ 256 Engine : 8 ECM
1074
1075CM_ BU_ ECM "Engine Control Module";
1076"#;
1077 let dbc = Dbc::parse(data).unwrap();
1078 assert_eq!(dbc.node_comment("ECM"), Some("Engine Control Module"));
1079 }
1080
1081 #[test]
1083 fn test_parse_cm_message_comment() {
1084 let data = r#"VERSION "1.0"
1085
1086BU_: ECM
1087
1088BO_ 256 Engine : 8 ECM
1089
1090CM_ BO_ 256 "Engine status message";
1091"#;
1092 let dbc = Dbc::parse(data).unwrap();
1093 let msg = dbc.messages().iter().next().unwrap();
1094 assert_eq!(msg.comment(), Some("Engine status message"));
1095 }
1096
1097 #[test]
1099 fn test_parse_cm_signal_comment() {
1100 let data = r#"VERSION "1.0"
1101
1102BU_: ECM
1103
1104BO_ 256 Engine : 8 ECM
1105 SG_ RPM : 0|16@1+ (0.25,0) [0|8000] "rpm"
1106
1107CM_ SG_ 256 RPM "Engine rotations per minute";
1108"#;
1109 let dbc = Dbc::parse(data).unwrap();
1110 let msg = dbc.messages().iter().next().unwrap();
1111 let signal = msg.signals().find("RPM").unwrap();
1112 assert_eq!(signal.comment(), Some("Engine rotations per minute"));
1113 }
1114
1115 #[test]
1117 fn test_parse_cm_multiple_comments() {
1118 let data = r#"VERSION "1.0"
1119
1120BU_: ECM TCM
1121
1122BO_ 256 Engine : 8 ECM
1123 SG_ RPM : 0|16@1+ (0.25,0) [0|8000] "rpm"
1124
1125BO_ 512 Trans : 8 TCM
1126 SG_ Gear : 0|8@1+ (1,0) [0|6] ""
1127
1128CM_ "Vehicle CAN database";
1129CM_ BU_ ECM "Engine Control Module";
1130CM_ BU_ TCM "Transmission Control Module";
1131CM_ BO_ 256 "Engine status message";
1132CM_ BO_ 512 "Transmission status";
1133CM_ SG_ 256 RPM "Engine rotations per minute";
1134CM_ SG_ 512 Gear "Current gear position";
1135"#;
1136 let dbc = Dbc::parse(data).unwrap();
1137
1138 assert_eq!(dbc.comment(), Some("Vehicle CAN database"));
1140
1141 assert_eq!(dbc.node_comment("ECM"), Some("Engine Control Module"));
1143 assert_eq!(dbc.node_comment("TCM"), Some("Transmission Control Module"));
1144
1145 let engine = dbc.messages().iter().find(|m| m.id() == 256).unwrap();
1147 let trans = dbc.messages().iter().find(|m| m.id() == 512).unwrap();
1148 assert_eq!(engine.comment(), Some("Engine status message"));
1149 assert_eq!(trans.comment(), Some("Transmission status"));
1150
1151 let rpm = engine.signals().find("RPM").unwrap();
1153 let gear = trans.signals().find("Gear").unwrap();
1154 assert_eq!(rpm.comment(), Some("Engine rotations per minute"));
1155 assert_eq!(gear.comment(), Some("Current gear position"));
1156 }
1157
1158 #[test]
1160 fn test_parse_cm_before_entity() {
1161 let data = r#"VERSION "1.0"
1162
1163BU_: ECM
1164
1165CM_ BO_ 256 "Engine status message";
1166CM_ SG_ 256 RPM "Engine RPM";
1167
1168BO_ 256 Engine : 8 ECM
1169 SG_ RPM : 0|16@1+ (0.25,0) [0|8000] "rpm"
1170"#;
1171 let dbc = Dbc::parse(data).unwrap();
1172 let msg = dbc.messages().iter().next().unwrap();
1173 assert_eq!(msg.comment(), Some("Engine status message"));
1174 let signal = msg.signals().find("RPM").unwrap();
1175 assert_eq!(signal.comment(), Some("Engine RPM"));
1176 }
1177
1178 #[test]
1180 fn test_parse_cm_last_wins() {
1181 let data = r#"VERSION "1.0"
1182
1183BU_: ECM
1184
1185BO_ 256 Engine : 8 ECM
1186 SG_ RPM : 0|16@1+ (0.25,0) [0|8000] "rpm"
1187
1188CM_ BO_ 256 "First message comment";
1189CM_ BO_ 256 "Second message comment";
1190CM_ SG_ 256 RPM "First signal comment";
1191CM_ SG_ 256 RPM "Second signal comment";
1192CM_ BU_ ECM "First node comment";
1193CM_ BU_ ECM "Second node comment";
1194"#;
1195 let dbc = Dbc::parse(data).unwrap();
1196
1197 let msg = dbc.messages().iter().next().unwrap();
1199 assert_eq!(msg.comment(), Some("Second message comment"));
1200 let signal = msg.signals().find("RPM").unwrap();
1201 assert_eq!(signal.comment(), Some("Second signal comment"));
1202 assert_eq!(dbc.node_comment("ECM"), Some("Second node comment"));
1203 }
1204
1205 #[test]
1207 #[cfg(feature = "std")]
1208 fn test_parse_cm_round_trip() {
1209 let data = r#"VERSION "1.0"
1210
1211BU_: ECM TCM
1212
1213BO_ 256 Engine : 8 ECM
1214 SG_ RPM : 0|16@1+ (0.25,0) [0|8000] "rpm"
1215
1216CM_ "Database comment";
1217CM_ BU_ ECM "Engine Control Module";
1218CM_ BO_ 256 "Engine status message";
1219CM_ SG_ 256 RPM "Engine rotations per minute";
1220"#;
1221 let dbc = Dbc::parse(data).unwrap();
1222
1223 let serialized = dbc.to_dbc_string();
1225 let dbc2 = Dbc::parse(&serialized).unwrap();
1226
1227 assert_eq!(dbc2.comment(), Some("Database comment"));
1229 assert_eq!(dbc2.node_comment("ECM"), Some("Engine Control Module"));
1230 let msg = dbc2.messages().iter().next().unwrap();
1231 assert_eq!(msg.comment(), Some("Engine status message"));
1232 let signal = msg.signals().find("RPM").unwrap();
1233 assert_eq!(signal.comment(), Some("Engine rotations per minute"));
1234 }
1235
1236 #[test]
1238 #[cfg(feature = "std")]
1239 fn test_serialize_cm_comments() {
1240 let data = r#"VERSION "1.0"
1241
1242BU_: ECM
1243
1244BO_ 256 Engine : 8 ECM
1245 SG_ RPM : 0|16@1+ (0.25,0) [0|8000] "rpm"
1246
1247CM_ "Database comment";
1248CM_ BU_ ECM "Engine Control Module";
1249CM_ BO_ 256 "Engine status";
1250CM_ SG_ 256 RPM "RPM signal";
1251"#;
1252 let dbc = Dbc::parse(data).unwrap();
1253 let serialized = dbc.to_dbc_string();
1254
1255 assert!(serialized.contains("CM_ \"Database comment\";"));
1257 assert!(serialized.contains("CM_ BU_ ECM \"Engine Control Module\";"));
1258 assert!(serialized.contains("CM_ BO_ 256 \"Engine status\";"));
1259 assert!(serialized.contains("CM_ SG_ 256 RPM \"RPM signal\";"));
1260 }
1261}