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