1use crate::{Error, Signal, error::messages};
2use alloc::{boxed::Box, format, string::String, string::ToString, vec::Vec};
3
4#[derive(Debug, Clone, PartialEq)]
23pub struct Message {
24 id: u32,
25 name: Box<str>,
26 dlc: u8,
27 sender: Box<str>,
28 signals: Vec<Signal>,
29}
30
31impl Message {
32 fn validate(
34 id: u32,
35 name: &str,
36 dlc: u8,
37 sender: &str,
38 signals: &[Signal],
39 ) -> Result<(), Error> {
40 if name.trim().is_empty() {
41 return Err(Error::Message(messages::MESSAGE_NAME_EMPTY.to_string()));
42 }
43
44 if sender.trim().is_empty() {
45 return Err(Error::Message(messages::MESSAGE_SENDER_EMPTY.to_string()));
46 }
47
48 if dlc == 0 {
50 return Err(Error::Message(messages::MESSAGE_DLC_TOO_SMALL.to_string()));
51 }
52 if dlc > 8 {
53 return Err(Error::Message(messages::MESSAGE_DLC_TOO_LARGE.to_string()));
54 }
55
56 const MAX_STANDARD_ID: u32 = 0x7FF; const MIN_EXTENDED_ID: u32 = 0x800; const MAX_EXTENDED_ID: u32 = 0x1FFFFFFF; if id > MAX_EXTENDED_ID {
66 return Err(Error::Message(messages::message_id_out_of_range(id)));
67 }
68
69 if id <= MAX_STANDARD_ID {
73 } else if (MIN_EXTENDED_ID..=MAX_EXTENDED_ID).contains(&id) {
75 }
77
78 let max_bits = dlc as u16 * 8;
80 for signal in signals {
81 let end_bit = signal.start_bit() as u16 + signal.length() as u16;
82 if end_bit > max_bits {
83 return Err(Error::Message(messages::signal_extends_beyond_message(
84 signal.name(),
85 signal.start_bit(),
86 signal.length(),
87 end_bit,
88 max_bits,
89 dlc,
90 )));
91 }
92 }
93
94 for (i, sig1) in signals.iter().enumerate() {
99 let sig1_start = sig1.start_bit() as u16;
100 let sig1_end = sig1_start + sig1.length() as u16;
101
102 for sig2 in signals.iter().skip(i + 1) {
103 let sig2_start = sig2.start_bit() as u16;
104 let sig2_end = sig2_start + sig2.length() as u16;
105
106 if sig1_start < sig2_end && sig2_start < sig1_end {
109 return Err(Error::Message(messages::signal_overlap(
110 sig1.name(),
111 sig2.name(),
112 name,
113 )));
114 }
115 }
116 }
117
118 Ok(())
119 }
120
121 pub(crate) fn new(
135 id: u32,
136 name: impl AsRef<str>,
137 dlc: u8,
138 sender: impl AsRef<str>,
139 signals: Vec<Signal>,
140 ) -> Result<Self, Error> {
141 let name_str = name.as_ref();
142 let sender_str = sender.as_ref();
143 Self::validate(id, name_str, dlc, sender_str, &signals)?;
144
145 Ok(Self {
146 id,
147 name: name_str.into(),
148 dlc,
149 sender: sender_str.into(),
150 signals,
151 })
152 }
153
154 pub fn builder() -> MessageBuilder {
177 MessageBuilder::new()
178 }
179
180 pub(super) fn parse(message: &str, signals: Vec<Signal>) -> Result<Self, Error> {
181 let parts: Vec<&str> = message.split_whitespace().collect();
182 if parts.len() != 6 {
183 return Err(Error::Message(messages::MESSAGE_INVALID_FORMAT.to_string()));
184 }
185
186 let id = parts[1]
187 .parse()
188 .map_err(|_| Error::Message(messages::MESSAGE_INVALID_ID.to_string()))?;
189 let name = parts[2];
190 let dlc = parts[4]
191 .parse()
192 .map_err(|_| Error::Message(messages::MESSAGE_INVALID_DLC.to_string()))?;
193 let sender = parts[5];
194
195 Self::validate(id, name, dlc, sender, &signals)?;
197
198 Ok(Self {
199 id,
200 name: name.into(),
201 dlc,
202 sender: sender.into(),
203 signals,
204 })
205 }
206
207 #[inline]
209 pub fn id(&self) -> u32 {
210 self.id
211 }
212
213 #[inline]
215 pub fn name(&self) -> &str {
216 &self.name
217 }
218
219 #[inline]
221 pub fn dlc(&self) -> u8 {
222 self.dlc
223 }
224
225 #[inline]
227 pub fn sender(&self) -> &str {
228 &self.sender
229 }
230
231 #[inline]
233 pub fn signals(&self) -> &[Signal] {
234 &self.signals
235 }
236
237 pub fn find_signal(&self, name: &str) -> Option<&Signal> {
239 self.signals.iter().find(|s| s.name() == name)
240 }
241
242 pub fn to_dbc_string(&self) -> String {
279 use alloc::format;
280 format!(
281 "BO_ {} {} : {} {}",
282 self.id(),
283 self.name(),
284 self.dlc(),
285 self.sender()
286 )
287 }
288
289 pub fn to_dbc_string_with_signals(&self) -> String {
326 let mut result = String::with_capacity(200 + (self.signals.len() * 100));
327 result.push_str(&self.to_dbc_string());
328 result.push('\n');
329
330 for signal in &self.signals {
331 result.push_str(&signal.to_dbc_string());
332 result.push('\n');
333 }
334
335 result
336 }
337}
338
339#[derive(Debug, Clone)]
381pub struct MessageBuilder {
382 id: Option<u32>,
383 name: Option<Box<str>>,
384 dlc: Option<u8>,
385 sender: Option<Box<str>>,
386 signals: Vec<Signal>,
387}
388
389impl MessageBuilder {
390 fn new() -> Self {
391 Self {
392 id: None,
393 name: None,
394 dlc: None,
395 sender: None,
396 signals: Vec::new(),
397 }
398 }
399
400 pub fn id(mut self, id: u32) -> Self {
402 self.id = Some(id);
403 self
404 }
405
406 pub fn name(mut self, name: impl AsRef<str>) -> Self {
408 self.name = Some(name.as_ref().into());
409 self
410 }
411
412 pub fn dlc(mut self, dlc: u8) -> Self {
414 self.dlc = Some(dlc);
415 self
416 }
417
418 pub fn sender(mut self, sender: impl AsRef<str>) -> Self {
420 self.sender = Some(sender.as_ref().into());
421 self
422 }
423
424 pub fn add_signal(mut self, signal: Signal) -> Self {
426 self.signals.push(signal);
427 self
428 }
429
430 pub fn add_signals(mut self, signals: impl IntoIterator<Item = Signal>) -> Self {
432 self.signals.extend(signals);
433 self
434 }
435
436 pub fn signals(mut self, signals: Vec<Signal>) -> Self {
438 self.signals = signals;
439 self
440 }
441
442 pub fn clear_signals(mut self) -> Self {
444 self.signals.clear();
445 self
446 }
447
448 pub fn validate(&self) -> Result<(), Error> {
459 let id = self
460 .id
461 .ok_or_else(|| Error::Message(messages::MESSAGE_ID_REQUIRED.to_string()))?;
462 let name = self
463 .name
464 .as_ref()
465 .ok_or_else(|| Error::Message(messages::MESSAGE_NAME_EMPTY.to_string()))?;
466 let dlc = self
467 .dlc
468 .ok_or_else(|| Error::Message(messages::MESSAGE_DLC_REQUIRED.to_string()))?;
469 let sender = self
470 .sender
471 .as_ref()
472 .ok_or_else(|| Error::Message(messages::MESSAGE_SENDER_EMPTY.to_string()))?;
473
474 Message::validate(id, name.as_ref(), dlc, sender.as_ref(), &self.signals)
475 }
476
477 pub fn build(self) -> Result<Message, Error> {
485 let id = self
486 .id
487 .ok_or_else(|| Error::Message(messages::MESSAGE_ID_REQUIRED.to_string()))?;
488 let name = self
489 .name
490 .ok_or_else(|| Error::Message(messages::MESSAGE_NAME_EMPTY.to_string()))?;
491 let dlc = self
492 .dlc
493 .ok_or_else(|| Error::Message(messages::MESSAGE_DLC_REQUIRED.to_string()))?;
494 let sender = self
495 .sender
496 .ok_or_else(|| Error::Message(messages::MESSAGE_SENDER_EMPTY.to_string()))?;
497
498 Message::new(id, name.as_ref(), dlc, sender.as_ref(), self.signals)
499 }
500}
501
502#[cfg(test)]
503mod tests {
504 use super::*;
505 use crate::error::lang;
506 use crate::{ByteOrder, Receivers};
507
508 #[test]
509 fn test_message_new_valid() {
510 let signal = Signal::new(
511 "RPM",
512 0,
513 16,
514 ByteOrder::BigEndian,
515 true,
516 0.25,
517 0.0,
518 0.0,
519 8000.0,
520 Some("rpm" as &str),
521 Receivers::Broadcast,
522 )
523 .unwrap();
524
525 let message = Message::new(256, "EngineData", 8, "ECM", vec![signal]).unwrap();
526 assert_eq!(message.id(), 256);
527 assert_eq!(message.name(), "EngineData");
528 assert_eq!(message.dlc(), 8);
529 assert_eq!(message.sender(), "ECM");
530 assert_eq!(message.signals().len(), 1);
531 }
532
533 #[test]
534 fn test_message_new_empty_name() {
535 let signal = Signal::new(
536 "RPM",
537 0,
538 16,
539 ByteOrder::BigEndian,
540 true,
541 1.0,
542 0.0,
543 0.0,
544 100.0,
545 None::<&str>,
546 Receivers::None,
547 )
548 .unwrap();
549
550 let result = Message::new(256, "", 8, "ECM", vec![signal]);
551 assert!(result.is_err());
552 match result.unwrap_err() {
553 Error::Message(msg) => assert!(msg.contains(lang::MESSAGE_NAME_EMPTY)),
554 _ => panic!("Expected Signal error"),
555 }
556 }
557
558 #[test]
559 fn test_message_new_empty_sender() {
560 let signal = Signal::new(
561 "RPM",
562 0,
563 16,
564 ByteOrder::BigEndian,
565 true,
566 1.0,
567 0.0,
568 0.0,
569 100.0,
570 None::<&str>,
571 Receivers::None,
572 )
573 .unwrap();
574
575 let result = Message::new(256, "EngineData", 8, "", vec![signal]);
576 assert!(result.is_err());
577 match result.unwrap_err() {
578 Error::Message(msg) => assert!(msg.contains(lang::MESSAGE_SENDER_EMPTY)),
579 _ => panic!("Expected Signal error"),
580 }
581 }
582
583 #[test]
584 fn test_message_new_zero_dlc() {
585 let signal = Signal::new(
586 "RPM",
587 0,
588 16,
589 ByteOrder::BigEndian,
590 true,
591 1.0,
592 0.0,
593 0.0,
594 100.0,
595 None::<&str>,
596 Receivers::None,
597 )
598 .unwrap();
599
600 let result = Message::new(256, "EngineData", 0, "ECM", vec![signal]);
601 assert!(result.is_err());
602 match result.unwrap_err() {
603 Error::Message(msg) => assert!(msg.contains(lang::MESSAGE_DLC_TOO_SMALL)),
604 _ => panic!("Expected Signal error"),
605 }
606 }
607
608 #[test]
609 fn test_message_new_dlc_too_large() {
610 let signal = Signal::new(
611 "RPM",
612 0,
613 16,
614 ByteOrder::BigEndian,
615 true,
616 1.0,
617 0.0,
618 0.0,
619 100.0,
620 None::<&str>,
621 Receivers::None,
622 )
623 .unwrap();
624
625 let result = Message::new(256, "EngineData", 9, "ECM", vec![signal]);
626 assert!(result.is_err());
627 match result.unwrap_err() {
628 Error::Message(msg) => assert!(msg.contains(lang::MESSAGE_DLC_TOO_LARGE)),
629 _ => panic!("Expected Signal error"),
630 }
631 }
632
633 #[test]
634 fn test_message_new_signal_overflow() {
635 let signal = Signal::new(
637 "RPM",
638 0,
639 65, ByteOrder::BigEndian,
641 true,
642 1.0,
643 0.0,
644 0.0,
645 100.0,
646 None::<&str>,
647 Receivers::None,
648 );
649 assert!(signal.is_err()); let signal = Signal::new(
653 "RPM",
654 0,
655 32, ByteOrder::BigEndian,
657 true,
658 1.0,
659 0.0,
660 0.0,
661 100.0,
662 None::<&str>,
663 Receivers::None,
664 )
665 .unwrap();
666
667 let result = Message::new(256, "EngineData", 2, "ECM", vec![signal]);
669 assert!(result.is_err());
670 match result.unwrap_err() {
671 Error::Message(msg) => {
672 let template_text =
675 lang::FORMAT_SIGNAL_EXTENDS_BEYOND_MESSAGE.split("{}").next().unwrap();
676 assert!(msg.contains(template_text.trim_end()));
677 }
678 _ => panic!("Expected Signal error"),
679 }
680 }
681
682 #[test]
683 fn test_message_new_multiple_signals() {
684 let signal1 = Signal::new(
685 "RPM",
686 0,
687 16,
688 ByteOrder::BigEndian,
689 true,
690 1.0,
691 0.0,
692 0.0,
693 100.0,
694 None::<&str>,
695 Receivers::None,
696 )
697 .unwrap();
698
699 let signal2 = Signal::new(
700 "Temperature",
701 16,
702 8,
703 ByteOrder::BigEndian,
704 true,
705 1.0,
706 0.0,
707 0.0,
708 100.0,
709 None::<&str>,
710 Receivers::None,
711 )
712 .unwrap();
713
714 let message = Message::new(256, "EngineData", 8, "ECM", vec![signal1, signal2]).unwrap();
715 assert_eq!(message.signals().len(), 2);
716 }
717
718 #[test]
719 fn test_message_parse_invalid_dlc() {
720 let line = "BO_ 256 EngineData : 9 ECM";
722 let signals = vec![];
723 let result = Message::parse(line, signals);
724 assert!(result.is_err());
725 match result.unwrap_err() {
726 Error::Message(msg) => assert!(msg.contains(lang::MESSAGE_DLC_TOO_LARGE)),
727 _ => panic!("Expected Signal error"),
728 }
729 }
730
731 #[test]
732 fn test_message_parse_zero_dlc() {
733 let line = "BO_ 256 EngineData : 0 ECM";
735 let signals = vec![];
736 let result = Message::parse(line, signals);
737 assert!(result.is_err());
738 match result.unwrap_err() {
739 Error::Message(msg) => assert!(msg.contains(lang::MESSAGE_DLC_TOO_SMALL)),
740 _ => panic!("Expected Signal error"),
741 }
742 }
743
744 #[test]
745 fn test_message_parse_signal_overflow() {
746 let signal = Signal::new(
748 "RPM",
749 0,
750 32, ByteOrder::BigEndian,
752 true,
753 1.0,
754 0.0,
755 0.0,
756 100.0,
757 None::<&str>,
758 Receivers::None,
759 )
760 .unwrap();
761
762 let line = "BO_ 256 EngineData : 2 ECM";
764 let result = Message::parse(line, vec![signal]);
765 assert!(result.is_err());
766 match result.unwrap_err() {
767 Error::Message(msg) => {
768 let template_text =
771 lang::FORMAT_SIGNAL_EXTENDS_BEYOND_MESSAGE.split("{}").next().unwrap();
772 assert!(msg.contains(template_text.trim_end()));
773 }
774 _ => panic!("Expected Signal error"),
775 }
776 }
777
778 #[test]
779 fn test_message_parse_invalid_format() {
780 let line = "BO_ 256 EngineData : 8";
782 let result = Message::parse(line, vec![]);
783 assert!(result.is_err());
784 match result.unwrap_err() {
785 Error::Message(msg) => assert!(msg.contains(lang::MESSAGE_INVALID_FORMAT)),
786 _ => panic!("Expected Signal error"),
787 }
788 }
789
790 #[test]
791 fn test_message_parse_invalid_id() {
792 let line = "BO_ abc EngineData : 8 ECM";
794 let result = Message::parse(line, vec![]);
795 assert!(result.is_err());
796 match result.unwrap_err() {
797 Error::Message(msg) => assert!(msg.contains(lang::MESSAGE_INVALID_ID)),
798 _ => panic!("Expected Signal error"),
799 }
800 }
801
802 #[test]
803 fn test_message_parse_invalid_dlc_string() {
804 let line = "BO_ 256 EngineData : abc ECM";
806 let result = Message::parse(line, vec![]);
807 assert!(result.is_err());
808 match result.unwrap_err() {
809 Error::Message(msg) => assert!(msg.contains(lang::MESSAGE_INVALID_DLC)),
810 _ => panic!("Expected Signal error"),
811 }
812 }
813
814 #[test]
815 fn test_message_to_dbc_string() {
816 let signal = Signal::new(
817 "RPM",
818 0,
819 16,
820 ByteOrder::BigEndian,
821 true,
822 0.25,
823 0.0,
824 0.0,
825 8000.0,
826 Some("rpm" as &str),
827 Receivers::Broadcast,
828 )
829 .unwrap();
830
831 let message = Message::new(256, "EngineData", 8, "ECM", vec![signal]).unwrap();
832 assert_eq!(message.to_dbc_string(), "BO_ 256 EngineData : 8 ECM");
833 }
834
835 #[test]
836 fn test_message_to_dbc_string_with_signals() {
837 let signal1 = Signal::new(
838 "RPM",
839 0,
840 16,
841 ByteOrder::BigEndian,
842 true,
843 0.25,
844 0.0,
845 0.0,
846 8000.0,
847 Some("rpm" as &str),
848 Receivers::Broadcast,
849 )
850 .unwrap();
851
852 let signal2 = Signal::new(
853 "Temperature",
854 16,
855 8,
856 ByteOrder::LittleEndian,
857 false,
858 1.0,
859 -40.0,
860 -40.0,
861 215.0,
862 Some("°C" as &str),
863 Receivers::None,
864 )
865 .unwrap();
866
867 let message = Message::new(256, "EngineData", 8, "ECM", vec![signal1, signal2]).unwrap();
868 let dbc_str = message.to_dbc_string_with_signals();
869
870 assert!(dbc_str.contains("BO_ 256 EngineData : 8 ECM"));
871 assert!(dbc_str.contains("SG_ RPM : 0|16@1+ (0.25,0) [0|8000] \"rpm\" *"));
872 assert!(dbc_str.contains("SG_ Temperature : 16|8@0- (1,-40) [-40|215] \"°C\""));
873 }
874
875 #[test]
876 fn test_message_id_out_of_range() {
877 let signal = Signal::new(
878 "RPM",
879 0,
880 16,
881 ByteOrder::BigEndian,
882 true,
883 1.0,
884 0.0,
885 0.0,
886 100.0,
887 None::<&str>,
888 Receivers::None,
889 )
890 .unwrap();
891
892 let result = Message::new(0x20000000, "Test", 8, "ECM", vec![signal.clone()]);
894 assert!(result.is_err());
895 match result.unwrap_err() {
896 Error::Message(msg) => {
897 let template_text =
899 lang::FORMAT_MESSAGE_ID_OUT_OF_RANGE.split("{}").next().unwrap();
900 assert!(msg.contains(template_text.trim_end()));
901 }
902 _ => panic!("Expected Signal error"),
903 }
904
905 let result = Message::new(0, "Test", 8, "ECM", vec![signal.clone()]);
907 assert!(result.is_ok());
908
909 let result = Message::new(0x7FF, "Test", 8, "ECM", vec![signal.clone()]);
911 assert!(result.is_ok());
912
913 let result = Message::new(0x800, "Test", 8, "ECM", vec![signal.clone()]);
915 assert!(result.is_ok());
916
917 let result = Message::new(0x1FFFFFFF, "Test", 8, "ECM", vec![signal]);
919 assert!(result.is_ok());
920 }
921
922 #[test]
923 fn test_signal_overlap() {
924 let signal1 = Signal::new(
926 "Signal1",
927 0,
928 16,
929 ByteOrder::BigEndian,
930 true,
931 1.0,
932 0.0,
933 0.0,
934 100.0,
935 None::<&str>,
936 Receivers::None,
937 )
938 .unwrap();
939
940 let signal2 = Signal::new(
941 "Signal2",
942 8,
943 16,
944 ByteOrder::BigEndian,
945 true,
946 1.0,
947 0.0,
948 0.0,
949 100.0,
950 None::<&str>,
951 Receivers::None,
952 )
953 .unwrap();
954
955 let result = Message::new(256, "TestMessage", 8, "ECM", vec![signal1, signal2]);
956 assert!(result.is_err());
957 match result.unwrap_err() {
958 Error::Message(msg) => {
959 let template_text = lang::FORMAT_SIGNAL_OVERLAP.split("{}").next().unwrap();
962 assert!(msg.contains(template_text.trim_end()));
963 assert!(msg.contains("Signal1"));
964 assert!(msg.contains("Signal2"));
965 assert!(msg.contains("TestMessage"));
966 }
967 _ => panic!("Expected Signal error"),
968 }
969 }
970
971 #[test]
972 fn test_signal_no_overlap() {
973 let signal1 = Signal::new(
975 "Signal1",
976 0,
977 16,
978 ByteOrder::BigEndian,
979 true,
980 1.0,
981 0.0,
982 0.0,
983 100.0,
984 None::<&str>,
985 Receivers::None,
986 )
987 .unwrap();
988
989 let signal2 = Signal::new(
990 "Signal2",
991 16,
992 16,
993 ByteOrder::BigEndian,
994 true,
995 1.0,
996 0.0,
997 0.0,
998 100.0,
999 None::<&str>,
1000 Receivers::None,
1001 )
1002 .unwrap();
1003
1004 let result = Message::new(256, "TestMessage", 8, "ECM", vec![signal1, signal2]);
1005 assert!(result.is_ok());
1006 }
1007
1008 #[test]
1009 fn test_signal_overlap_adjacent() {
1010 let signal1 = Signal::new(
1012 "Signal1",
1013 0,
1014 16,
1015 ByteOrder::BigEndian,
1016 true,
1017 1.0,
1018 0.0,
1019 0.0,
1020 100.0,
1021 None::<&str>,
1022 Receivers::None,
1023 )
1024 .unwrap();
1025
1026 let signal2 = Signal::new(
1027 "Signal2",
1028 16,
1029 8,
1030 ByteOrder::BigEndian,
1031 true,
1032 1.0,
1033 0.0,
1034 0.0,
1035 100.0,
1036 None::<&str>,
1037 Receivers::None,
1038 )
1039 .unwrap();
1040
1041 let result = Message::new(256, "TestMessage", 8, "ECM", vec![signal1, signal2]);
1042 assert!(result.is_ok());
1043 }
1044
1045 #[test]
1046 fn test_signal_overlap_identical_position() {
1047 let signal1 = Signal::new(
1049 "Signal1",
1050 0,
1051 8,
1052 ByteOrder::BigEndian,
1053 true,
1054 1.0,
1055 0.0,
1056 0.0,
1057 100.0,
1058 None::<&str>,
1059 Receivers::None,
1060 )
1061 .unwrap();
1062
1063 let signal2 = Signal::new(
1064 "Signal2",
1065 0,
1066 8,
1067 ByteOrder::BigEndian,
1068 true,
1069 1.0,
1070 0.0,
1071 0.0,
1072 100.0,
1073 None::<&str>,
1074 Receivers::None,
1075 )
1076 .unwrap();
1077
1078 let result = Message::new(256, "TestMessage", 8, "ECM", vec![signal1, signal2]);
1079 assert!(result.is_err());
1080 match result.unwrap_err() {
1081 Error::Message(msg) => {
1082 let template_text = lang::FORMAT_SIGNAL_OVERLAP.split("{}").next().unwrap();
1085 assert!(msg.contains(template_text.trim_end()));
1086 }
1087 _ => panic!("Expected Signal error"),
1088 }
1089 }
1090}