1use crate::{Error, error::messages};
2use alloc::{
3 boxed::Box,
4 string::{String, ToString},
5 vec::Vec,
6};
7
8#[derive(Debug, Clone, PartialEq)]
35pub struct Signal {
36 name: Box<str>,
37 start_bit: u8,
38 length: u8,
39 byte_order: ByteOrder,
40 unsigned: bool,
41 factor: f64,
42 offset: f64,
43 min: f64,
44 max: f64,
45 unit: Option<Box<str>>,
46 receivers: Receivers,
47}
48
49#[derive(Debug, Clone, Copy, PartialEq, Eq)]
53pub enum ByteOrder {
54 LittleEndian = 0,
56 BigEndian = 1,
58}
59
60#[derive(Debug, Clone, PartialEq)]
64pub enum Receivers {
65 Broadcast,
67 Nodes(Vec<Box<str>>),
69 None,
71}
72
73impl Signal {
74 fn validate(name: &str, start_bit: u8, length: u8, min: f64, max: f64) -> Result<(), Error> {
76 if name.trim().is_empty() {
77 return Err(Error::Signal(messages::SIGNAL_NAME_EMPTY.to_string()));
78 }
79
80 if length == 0 {
82 return Err(Error::Signal(messages::SIGNAL_LENGTH_TOO_SMALL.to_string()));
83 }
84 if length > 64 {
85 return Err(Error::Signal(messages::SIGNAL_LENGTH_TOO_LARGE.to_string()));
86 }
87
88 let end_bit = start_bit as u16 + length as u16;
90 if end_bit > 64 {
91 return Err(Error::Signal(messages::signal_extends_beyond_can(
92 start_bit, length, end_bit,
93 )));
94 }
95
96 if min > max {
98 return Err(Error::Signal(messages::invalid_range(min, max)));
99 }
100
101 Ok(())
102 }
103
104 #[allow(clippy::too_many_arguments)] pub(crate) fn new(
117 name: impl AsRef<str>,
118 start_bit: u8,
119 length: u8,
120 byte_order: ByteOrder,
121 unsigned: bool,
122 factor: f64,
123 offset: f64,
124 min: f64,
125 max: f64,
126 unit: Option<impl AsRef<str>>,
127 receivers: Receivers,
128 ) -> Result<Self, Error> {
129 let name_str = name.as_ref();
130 Self::validate(name_str, start_bit, length, min, max)?;
131
132 Ok(Self {
133 name: name_str.into(),
134 start_bit,
135 length,
136 byte_order,
137 unsigned,
138 factor,
139 offset,
140 min,
141 max,
142 unit: unit.map(|u| u.as_ref().into()),
143 receivers,
144 })
145 }
146
147 pub fn builder() -> SignalBuilder {
170 SignalBuilder::new()
171 }
172
173 pub(super) fn parse(line: &str) -> Result<Self, Error> {
174 let line = line.trim_start();
178 let line = line
179 .strip_prefix("SG_")
180 .or_else(|| line.strip_prefix("SG_"))
181 .ok_or_else(|| Error::Signal(messages::SIGNAL_PARSE_EXPECTED_SG.to_string()))?;
182 let line = line.trim();
183
184 let (name, rest) = match line.split_once(':') {
186 Some((n, r)) => (n.trim(), r.trim()),
187 None => {
188 return Err(Error::Signal(
189 messages::SIGNAL_PARSE_MISSING_COLON.to_string(),
190 ));
191 }
192 };
193
194 let mut rest = rest;
197 let mut tokens = rest.splitn(2, ' ');
198 let pos = tokens
199 .next()
200 .ok_or_else(|| Error::Signal(messages::SIGNAL_PARSE_MISSING_POSITION.to_string()))?
201 .trim();
202 rest = tokens
203 .next()
204 .ok_or_else(|| Error::Signal(messages::SIGNAL_PARSE_MISSING_REST.to_string()))?
205 .trim();
206
207 let (bitlen, bosign) = pos
209 .split_once('@')
210 .ok_or_else(|| Error::Signal(messages::SIGNAL_PARSE_EXPECTED_AT.to_string()))?;
211 let (startbit, length) = bitlen
212 .split_once('|')
213 .ok_or_else(|| Error::Signal(messages::SIGNAL_PARSE_EXPECTED_PIPE.to_string()))?;
214
215 let start_bit: u8 = startbit
216 .trim()
217 .parse()
218 .map_err(|_| Error::Signal(messages::SIGNAL_PARSE_INVALID_START_BIT.to_string()))?;
219 let length: u8 = length
220 .trim()
221 .parse()
222 .map_err(|_| Error::Signal(messages::SIGNAL_PARSE_INVALID_LENGTH.to_string()))?;
223
224 let bosign = bosign.trim();
226 let (byte_order, unsigned) = {
227 let mut chars = bosign.chars();
228 let bo = chars.next().ok_or_else(|| {
229 Error::Signal(messages::SIGNAL_PARSE_MISSING_BYTE_ORDER.to_string())
230 })?;
231 let sign = chars
232 .next()
233 .ok_or_else(|| Error::Signal(messages::SIGNAL_PARSE_MISSING_SIGN.to_string()))?;
234 let byte_order = match bo {
235 '0' => ByteOrder::LittleEndian,
236 '1' => ByteOrder::BigEndian,
237 _ => return Err(Error::Signal(messages::unknown_byte_order(bo))),
238 };
239 let unsigned = match sign {
240 '+' => true,
241 '-' => false,
242 _ => return Err(Error::Signal(messages::unknown_sign(sign))),
243 };
244 (byte_order, unsigned)
245 };
246
247 let rest = rest.trim_start();
249 let (f_and_rest, rest) = match rest.trim_start().split_once(')') {
250 Some((f, r)) => (f, r),
251 None => {
252 return Err(Error::Signal(
253 messages::SIGNAL_PARSE_MISSING_CLOSING_PAREN.to_string(),
254 ));
255 }
256 };
257 let f_and_rest = f_and_rest.trim_start();
258 let f_and_rest = f_and_rest.strip_prefix('(').ok_or_else(|| {
259 Error::Signal(messages::SIGNAL_PARSE_MISSING_OPENING_PAREN.to_string())
260 })?;
261 let (factor_str, offset_str) = f_and_rest
262 .split_once(',')
263 .ok_or_else(|| Error::Signal(messages::SIGNAL_PARSE_MISSING_COMMA.to_string()))?;
264 let (factor_str, offset_str) = (factor_str.trim(), offset_str.trim());
265 let factor: f64 = if factor_str.is_empty() {
266 0.
267 } else {
268 factor_str
269 .parse()
270 .map_err(|_| Error::Signal(messages::SIGNAL_PARSE_INVALID_FACTOR.to_string()))?
271 };
272 let offset: f64 = if offset_str.is_empty() {
273 0.
274 } else {
275 offset_str
276 .parse()
277 .map_err(|_| Error::Signal(messages::SIGNAL_PARSE_INVALID_OFFSET.to_string()))?
278 };
279 let rest = rest.trim_start();
280
281 let (minmax, rest) = match rest.split_once(']') {
283 Some((m, r)) => (m, r),
284 None => {
285 return Err(Error::Signal(
286 messages::SIGNAL_PARSE_MISSING_CLOSING_BRACKET.to_string(),
287 ));
288 }
289 };
290 let minmax = minmax.trim_start().strip_prefix('[').ok_or_else(|| {
291 Error::Signal(messages::SIGNAL_PARSE_MISSING_OPENING_BRACKET.to_string())
292 })?;
293 let (min_str, max_str) = minmax.split_once('|').ok_or_else(|| {
294 Error::Signal(messages::SIGNAL_PARSE_MISSING_PIPE_IN_RANGE.to_string())
295 })?;
296 let (min_str, max_str) = (min_str.trim(), max_str.trim());
297 let min: f64 = if min_str.is_empty() {
298 0.
299 } else {
300 min_str
301 .parse()
302 .map_err(|_| Error::Signal(messages::SIGNAL_PARSE_INVALID_MIN.to_string()))?
303 };
304 let max: f64 = if max_str.is_empty() {
305 0.
306 } else {
307 max_str
308 .parse()
309 .map_err(|_| Error::Signal(messages::SIGNAL_PARSE_INVALID_MAX.to_string()))?
310 };
311 let mut rest = rest.trim_start();
312
313 if !rest.starts_with('"') {
315 return Err(Error::Signal(
316 messages::SIGNAL_PARSE_EXPECTED_UNIT_QUOTE.to_string(),
317 ));
318 }
319 rest = &rest[1..];
320 let mut unit_str = String::with_capacity(10);
322 for c in rest.chars() {
323 if c == '"' {
324 break;
325 }
326 unit_str.push(c);
327 }
328 rest = rest[unit_str.len()..].trim_start();
330 if rest.starts_with('"') {
331 rest = &rest[1..];
332 }
333 let unit = if unit_str.is_empty() {
334 None
335 } else {
336 Some(unit_str.into_boxed_str())
337 };
338 let rest = rest.trim_start();
339
340 let receivers = if rest.is_empty() {
342 Receivers::None
343 } else if rest == "*" {
344 Receivers::Broadcast
345 } else {
346 let nodes: Vec<Box<str>> = rest.split_whitespace().map(|s| s.into()).collect();
348 if nodes.is_empty() {
349 Receivers::None
350 } else {
351 Receivers::Nodes(nodes)
352 }
353 };
354
355 Self::validate(name, start_bit, length, min, max)?;
357
358 Ok(Signal {
359 name: name.into(),
360 start_bit,
361 length,
362 byte_order,
363 unsigned,
364 factor,
365 offset,
366 min,
367 max,
368 unit,
369 receivers,
370 })
371 }
372
373 #[inline]
375 pub fn name(&self) -> &str {
376 &self.name
377 }
378
379 #[inline]
381 pub fn start_bit(&self) -> u8 {
382 self.start_bit
383 }
384
385 #[inline]
387 pub fn length(&self) -> u8 {
388 self.length
389 }
390
391 #[inline]
393 pub fn byte_order(&self) -> ByteOrder {
394 self.byte_order
395 }
396
397 #[inline]
399 pub fn is_unsigned(&self) -> bool {
400 self.unsigned
401 }
402
403 #[inline]
405 pub fn factor(&self) -> f64 {
406 self.factor
407 }
408
409 #[inline]
411 pub fn offset(&self) -> f64 {
412 self.offset
413 }
414
415 #[inline]
417 pub fn min(&self) -> f64 {
418 self.min
419 }
420
421 #[inline]
423 pub fn max(&self) -> f64 {
424 self.max
425 }
426
427 #[inline]
429 pub fn unit(&self) -> Option<&str> {
430 self.unit.as_ref().map(|s| s.as_ref())
431 }
432
433 #[inline]
435 pub fn receivers(&self) -> &Receivers {
436 &self.receivers
437 }
438
439 pub fn to_dbc_string(&self) -> String {
466 use alloc::format;
467
468 let mut result = String::with_capacity(100); result.push_str(" SG_ ");
471 result.push_str(self.name());
472 result.push_str(" : ");
473 result.push_str(&self.start_bit().to_string());
474 result.push('|');
475 result.push_str(&self.length().to_string());
476 result.push('@');
477
478 match self.byte_order() {
480 ByteOrder::LittleEndian => result.push('0'),
481 ByteOrder::BigEndian => result.push('1'),
482 }
483
484 if self.is_unsigned() {
486 result.push('+');
487 } else {
488 result.push('-');
489 }
490
491 result.push_str(" (");
493 result.push_str(&format!("{}", self.factor()));
494 result.push(',');
495 result.push_str(&format!("{}", self.offset()));
496 result.push(')');
497
498 result.push_str(" [");
500 result.push_str(&format!("{}", self.min()));
501 result.push('|');
502 result.push_str(&format!("{}", self.max()));
503 result.push(']');
504
505 result.push(' ');
507 if let Some(unit) = self.unit() {
508 result.push('"');
509 result.push_str(unit);
510 result.push('"');
511 } else {
512 result.push_str("\"\"");
513 }
514
515 match self.receivers() {
517 Receivers::Broadcast => {
518 result.push(' ');
519 result.push('*');
520 }
521 Receivers::Nodes(nodes) => {
522 if !nodes.is_empty() {
523 result.push(' ');
524 for (i, node) in nodes.iter().enumerate() {
525 if i > 0 {
526 result.push(' ');
527 }
528 result.push_str(node.as_ref());
529 }
530 }
531 }
532 Receivers::None => {
533 }
535 }
536
537 result
538 }
539}
540
541#[derive(Debug, Clone)]
575pub struct SignalBuilder {
576 name: Option<Box<str>>,
577 start_bit: Option<u8>,
578 length: Option<u8>,
579 byte_order: ByteOrder,
580 unsigned: bool,
581 factor: f64,
582 offset: f64,
583 min: f64,
584 max: f64,
585 unit: Option<Box<str>>,
586 receivers: Receivers,
587}
588
589impl SignalBuilder {
590 fn new() -> Self {
591 Self {
592 name: None,
593 start_bit: None,
594 length: None,
595 byte_order: ByteOrder::BigEndian,
596 unsigned: true,
597 factor: 1.0,
598 offset: 0.0,
599 min: 0.0,
600 max: 0.0,
601 unit: None,
602 receivers: Receivers::None,
603 }
604 }
605
606 pub fn name(mut self, name: impl AsRef<str>) -> Self {
608 self.name = Some(name.as_ref().into());
609 self
610 }
611
612 pub fn start_bit(mut self, start_bit: u8) -> Self {
614 self.start_bit = Some(start_bit);
615 self
616 }
617
618 pub fn length(mut self, length: u8) -> Self {
620 self.length = Some(length);
621 self
622 }
623
624 pub fn byte_order(mut self, byte_order: ByteOrder) -> Self {
626 self.byte_order = byte_order;
627 self
628 }
629
630 pub fn unsigned(mut self, unsigned: bool) -> Self {
632 self.unsigned = unsigned;
633 self
634 }
635
636 pub fn factor(mut self, factor: f64) -> Self {
638 self.factor = factor;
639 self
640 }
641
642 pub fn offset(mut self, offset: f64) -> Self {
644 self.offset = offset;
645 self
646 }
647
648 pub fn min(mut self, min: f64) -> Self {
650 self.min = min;
651 self
652 }
653
654 pub fn max(mut self, max: f64) -> Self {
656 self.max = max;
657 self
658 }
659
660 pub fn unit(mut self, unit: impl AsRef<str>) -> Self {
662 self.unit = Some(unit.as_ref().into());
663 self
664 }
665
666 pub fn no_unit(mut self) -> Self {
668 self.unit = None;
669 self
670 }
671
672 pub fn receivers(mut self, receivers: Receivers) -> Self {
674 self.receivers = receivers;
675 self
676 }
677
678 pub fn validate(&self) -> Result<(), Error> {
689 let name = self
690 .name
691 .as_ref()
692 .ok_or_else(|| Error::Signal(messages::SIGNAL_NAME_EMPTY.to_string()))?;
693 let start_bit = self
694 .start_bit
695 .ok_or_else(|| Error::Signal(messages::SIGNAL_START_BIT_REQUIRED.to_string()))?;
696 let length = self
697 .length
698 .ok_or_else(|| Error::Signal(messages::SIGNAL_LENGTH_REQUIRED.to_string()))?;
699
700 Signal::validate(name.as_ref(), start_bit, length, self.min, self.max)
701 }
702
703 pub fn build(self) -> Result<Signal, Error> {
711 let name = self
712 .name
713 .ok_or_else(|| Error::Signal(messages::SIGNAL_NAME_EMPTY.to_string()))?;
714 let start_bit = self
715 .start_bit
716 .ok_or_else(|| Error::Signal(messages::SIGNAL_START_BIT_REQUIRED.to_string()))?;
717 let length = self
718 .length
719 .ok_or_else(|| Error::Signal(messages::SIGNAL_LENGTH_REQUIRED.to_string()))?;
720
721 Signal::new(
722 name.as_ref(),
723 start_bit,
724 length,
725 self.byte_order,
726 self.unsigned,
727 self.factor,
728 self.offset,
729 self.min,
730 self.max,
731 self.unit.as_ref().map(|s| s.as_ref()),
732 self.receivers,
733 )
734 }
735}
736
737#[cfg(test)]
738mod tests {
739 use super::*;
740 use crate::Error;
741 use crate::error::lang;
742 extern crate std;
743
744 #[test]
745 fn test_signal_new_valid() {
746 let signal = Signal::new(
747 "RPM",
748 0,
749 16,
750 ByteOrder::BigEndian,
751 true,
752 0.25,
753 0.0,
754 0.0,
755 8000.0,
756 Some("rpm" as &str),
757 Receivers::Broadcast,
758 )
759 .unwrap();
760 assert_eq!(signal.name(), "RPM");
761 assert_eq!(signal.start_bit(), 0);
762 assert_eq!(signal.length(), 16);
763 assert_eq!(signal.byte_order(), ByteOrder::BigEndian);
764 assert!(signal.is_unsigned());
765 assert_eq!(signal.factor(), 0.25);
766 assert_eq!(signal.offset(), 0.0);
767 assert_eq!(signal.min(), 0.0);
768 assert_eq!(signal.max(), 8000.0);
769 assert_eq!(signal.unit(), Some("rpm"));
770 assert_eq!(signal.receivers(), &Receivers::Broadcast);
771 }
772
773 #[test]
774 fn test_signal_new_empty_name() {
775 let result = Signal::new(
776 "",
777 0,
778 16,
779 ByteOrder::BigEndian,
780 true,
781 1.0,
782 0.0,
783 0.0,
784 100.0,
785 None::<&str>,
786 Receivers::None,
787 );
788 assert!(result.is_err());
789 match result.unwrap_err() {
790 Error::Signal(msg) => assert!(msg.contains(lang::SIGNAL_NAME_EMPTY)),
791 _ => panic!("Expected Signal error"),
792 }
793 }
794
795 #[test]
796 fn test_signal_new_zero_length() {
797 let result = Signal::new(
798 "Test",
799 0,
800 0,
801 ByteOrder::BigEndian,
802 true,
803 1.0,
804 0.0,
805 0.0,
806 100.0,
807 None::<&str>,
808 Receivers::None,
809 );
810 assert!(result.is_err());
811 match result.unwrap_err() {
812 Error::Signal(msg) => assert!(msg.contains(lang::SIGNAL_LENGTH_TOO_SMALL)),
813 _ => panic!("Expected Signal error"),
814 }
815 }
816
817 #[test]
818 fn test_signal_new_length_too_large() {
819 let result = Signal::new(
820 "Test",
821 0,
822 65,
823 ByteOrder::BigEndian,
824 true,
825 1.0,
826 0.0,
827 0.0,
828 100.0,
829 None::<&str>,
830 Receivers::None,
831 );
832 assert!(result.is_err());
833 match result.unwrap_err() {
834 Error::Signal(msg) => assert!(msg.contains(lang::SIGNAL_LENGTH_TOO_LARGE)),
835 _ => panic!("Expected Signal error"),
836 }
837 }
838
839 #[test]
840 fn test_signal_new_overflow() {
841 let result = Signal::new(
842 "Test",
843 60,
844 10,
845 ByteOrder::BigEndian,
846 true,
847 1.0,
848 0.0,
849 0.0,
850 100.0,
851 None::<&str>,
852 Receivers::None,
853 );
854 assert!(result.is_err());
855 match result.unwrap_err() {
856 Error::Signal(msg) => {
857 let template_text =
859 lang::FORMAT_SIGNAL_EXTENDS_BEYOND_CAN.split("{}").next().unwrap();
860 assert!(msg.contains(template_text.trim_end()));
861 }
862 _ => panic!("Expected Signal error"),
863 }
864 }
865
866 #[test]
867 fn test_signal_new_invalid_range() {
868 let result = Signal::new(
869 "Test",
870 0,
871 8,
872 ByteOrder::BigEndian,
873 true,
874 1.0,
875 0.0,
876 100.0,
877 50.0,
878 None::<&str>,
879 Receivers::None,
880 );
881 assert!(result.is_err());
882 match result.unwrap_err() {
883 Error::Signal(msg) => {
884 let template_text = lang::FORMAT_INVALID_RANGE.split("{}").next().unwrap();
886 assert!(msg.contains(template_text.trim_end_matches(':').trim_end()));
887 }
888 _ => panic!("Expected Signal error"),
889 }
890 }
891
892 #[test]
893 fn test_signal_new_max_boundary() {
894 let signal = Signal::new(
896 "FullMessage",
897 0,
898 64,
899 ByteOrder::BigEndian,
900 true,
901 1.0,
902 0.0,
903 0.0,
904 100.0,
905 None::<&str>,
906 Receivers::None,
907 )
908 .unwrap();
909 assert_eq!(signal.length(), 64);
910 }
911
912 #[test]
913 fn test_signal_new_with_receivers() {
914 let nodes = vec!["ECM".into(), "TCM".into()];
915 let unit: Option<&str> = Some("°C");
916 let signal = Signal::new(
917 "TestSignal",
918 8,
919 16,
920 ByteOrder::LittleEndian,
921 false,
922 0.1,
923 -40.0,
924 -40.0,
925 215.0,
926 unit,
927 Receivers::Nodes(nodes),
928 )
929 .unwrap();
930 assert_eq!(signal.name(), "TestSignal");
931 assert!(!signal.is_unsigned());
932 assert_eq!(signal.unit(), Some("°C"));
933 match signal.receivers() {
934 Receivers::Nodes(n) => assert_eq!(n.len(), 2),
935 _ => panic!("Expected Nodes variant"),
936 }
937 }
938
939 #[test]
940 fn test_parse_valid_signal() {
941 let line = r#" SG_ RPM : 0|16@0+ (0.25,0) [0|8000] "rpm" TCM"#;
942 let sig = Signal::parse(line).unwrap();
943 assert_eq!(sig.name(), "RPM");
944 assert_eq!(sig.start_bit(), 0);
945 assert_eq!(sig.length(), 16);
946 assert_eq!(sig.byte_order(), ByteOrder::LittleEndian);
947 assert!(sig.is_unsigned());
948 assert_eq!(sig.factor(), 0.25);
949 assert_eq!(sig.offset(), 0.);
950 assert_eq!(sig.min(), 0.);
951 assert_eq!(sig.max(), 8000.);
952 assert_eq!(sig.unit(), Some("rpm"));
953 assert_eq!(sig.receivers(), &Receivers::Nodes(vec!["TCM".into()]));
954 }
955
956 #[test]
957 fn test_parse_signal_with_empty_unit_and_broadcast() {
958 let line = r#" SG_ ABSActive : 16|1@0+ (1,0) [0|1] "" *"#;
959 let sig = Signal::parse(line).unwrap();
960 assert_eq!(sig.name(), "ABSActive");
961 assert_eq!(sig.start_bit(), 16);
962 assert_eq!(sig.length(), 1);
963 assert_eq!(sig.byte_order(), ByteOrder::LittleEndian);
964 assert!(sig.is_unsigned());
965 assert_eq!(sig.factor(), 1.);
966 assert_eq!(sig.offset(), 0.);
967 assert_eq!(sig.min(), 0.);
968 assert_eq!(sig.max(), 1.);
969 assert_eq!(sig.unit(), None);
970 assert_eq!(sig.receivers(), &Receivers::Broadcast);
971 }
972
973 #[test]
974 fn test_parse_signal_with_negative_offset_and_min() {
975 let line = r#" SG_ Temperature : 16|8@0- (1,-40) [-40|215] "°C" TCM BCM"#;
976 let sig = Signal::parse(line).unwrap();
977 assert_eq!(sig.name(), "Temperature");
978 assert_eq!(sig.start_bit(), 16);
979 assert_eq!(sig.length(), 8);
980 assert_eq!(sig.byte_order(), ByteOrder::LittleEndian);
981 assert!(!sig.is_unsigned());
982 assert_eq!(sig.factor(), 1.);
983 assert_eq!(sig.offset(), -40.);
984 assert_eq!(sig.min(), -40.);
985 assert_eq!(sig.max(), 215.);
986 assert_eq!(sig.unit(), Some("°C"));
987 assert_eq!(
988 sig.receivers(),
989 &Receivers::Nodes(vec!["TCM".into(), "BCM".into()])
990 );
991 }
992
993 #[test]
994 fn test_parse_signal_with_percent_unit() {
995 let line = r#" SG_ ThrottlePosition : 24|8@0+ (0.392157,0) [0|100] "%" *"#;
996 let sig = Signal::parse(line).unwrap();
997 assert_eq!(sig.name(), "ThrottlePosition");
998 assert_eq!(sig.start_bit(), 24);
999 assert_eq!(sig.length(), 8);
1000 assert_eq!(sig.byte_order(), ByteOrder::LittleEndian);
1001 assert!(sig.is_unsigned());
1002 assert_eq!(sig.factor(), 0.392157);
1003 assert_eq!(sig.offset(), 0.);
1004 assert_eq!(sig.min(), 0.);
1005 assert_eq!(sig.max(), 100.);
1006 assert_eq!(sig.unit(), Some("%"));
1007 assert_eq!(sig.receivers(), &Receivers::Broadcast);
1008 }
1009
1010 #[test]
1011 fn test_parse_signal_missing_factors_and_limits() {
1012 let line = r#" SG_ Simple : 10|4@0+ ( , ) [ | ] "" *"#;
1014 let sig = Signal::parse(line).unwrap();
1015 assert_eq!(sig.name(), "Simple");
1016 assert_eq!(sig.start_bit(), 10);
1017 assert_eq!(sig.length(), 4);
1018 assert_eq!(sig.byte_order(), ByteOrder::LittleEndian);
1019 assert!(sig.is_unsigned());
1020 assert_eq!(sig.factor(), 0.);
1021 assert_eq!(sig.offset(), 0.);
1022 assert_eq!(sig.min(), 0.);
1023 assert_eq!(sig.max(), 0.);
1024 assert_eq!(sig.unit(), None);
1025 assert_eq!(sig.receivers(), &Receivers::Broadcast);
1026 }
1027
1028 #[test]
1029 fn test_parse_signal_missing_start_bit() {
1030 let line = r#" SG_ RPM : |16@0+ (0.25,0) [0|8000] "rpm" TCM"#;
1031 let err = Signal::parse(line).unwrap_err();
1032 match err {
1033 Error::Signal(msg) => assert!(msg.contains(lang::SIGNAL_PARSE_INVALID_START_BIT)),
1034 _ => panic!("Expected Signal error"),
1035 }
1036 }
1037
1038 #[test]
1039 fn test_parse_signal_invalid_range() {
1040 let line = r#" SG_ Test : 0|8@0+ (1,0) [100|50] "unit" *"#;
1042 let err = Signal::parse(line).unwrap_err();
1043 match err {
1044 Error::Signal(msg) => {
1045 let template_text = lang::FORMAT_INVALID_RANGE.split("{}").next().unwrap();
1047 assert!(msg.contains(template_text.trim_end_matches(':').trim_end()));
1048 }
1049 _ => panic!("Expected Signal error"),
1050 }
1051 }
1052
1053 #[test]
1054 fn test_parse_signal_overflow() {
1055 let line = r#" SG_ Test : 60|10@0+ (1,0) [0|100] "unit" *"#;
1057 let err = Signal::parse(line).unwrap_err();
1058 match err {
1059 Error::Signal(msg) => {
1060 let template_text =
1062 lang::FORMAT_SIGNAL_EXTENDS_BEYOND_CAN.split("{}").next().unwrap();
1063 assert!(msg.contains(template_text.trim_end()));
1064 }
1065 _ => panic!("Expected Signal error"),
1066 }
1067 }
1068
1069 #[test]
1070 fn test_parse_signal_length_too_large() {
1071 let line = r#" SG_ Test : 0|65@0+ (1,0) [0|100] "unit" *"#;
1073 let err = Signal::parse(line).unwrap_err();
1074 match err {
1075 Error::Signal(msg) => assert!(msg.contains(lang::SIGNAL_LENGTH_TOO_LARGE)),
1076 _ => panic!("Expected Signal error"),
1077 }
1078 }
1079
1080 #[test]
1081 fn test_parse_signal_zero_length() {
1082 let line = r#" SG_ Test : 0|0@0+ (1,0) [0|100] "unit" *"#;
1084 let err = Signal::parse(line).unwrap_err();
1085 match err {
1086 Error::Signal(msg) => assert!(msg.contains(lang::SIGNAL_LENGTH_TOO_SMALL)),
1087 _ => panic!("Expected Signal error"),
1088 }
1089 }
1090
1091 #[test]
1092 fn test_parse_signal_missing_length() {
1093 let line = r#" SG_ RPM : 0|@0+ (0.25,0) [0|8000] "rpm" TCM"#;
1094 let err = Signal::parse(line).unwrap_err();
1095 match err {
1096 Error::Signal(msg) => assert!(msg.contains(lang::SIGNAL_PARSE_INVALID_LENGTH)),
1097 _ => panic!("Expected Signal error"),
1098 }
1099 }
1100
1101 #[test]
1102 fn test_signal_to_dbc_string() {
1103 let signal1 = Signal::new(
1105 "RPM",
1106 0,
1107 16,
1108 ByteOrder::BigEndian,
1109 true,
1110 0.25,
1111 0.0,
1112 0.0,
1113 8000.0,
1114 Some("rpm" as &str),
1115 Receivers::Broadcast,
1116 )
1117 .unwrap();
1118 assert_eq!(
1119 signal1.to_dbc_string(),
1120 " SG_ RPM : 0|16@1+ (0.25,0) [0|8000] \"rpm\" *"
1121 );
1122
1123 let signal2 = Signal::new(
1125 "Temperature",
1126 16,
1127 8,
1128 ByteOrder::LittleEndian,
1129 false,
1130 1.0,
1131 -40.0,
1132 -40.0,
1133 215.0,
1134 Some("°C" as &str),
1135 Receivers::Nodes(vec!["TCM".into(), "BCM".into()]),
1136 )
1137 .unwrap();
1138 assert_eq!(
1139 signal2.to_dbc_string(),
1140 " SG_ Temperature : 16|8@0- (1,-40) [-40|215] \"°C\" TCM BCM"
1141 );
1142
1143 let signal3 = Signal::new(
1145 "Flag",
1146 24,
1147 1,
1148 ByteOrder::BigEndian,
1149 true,
1150 1.0,
1151 0.0,
1152 0.0,
1153 1.0,
1154 None::<&str>,
1155 Receivers::None,
1156 )
1157 .unwrap();
1158 assert_eq!(
1159 signal3.to_dbc_string(),
1160 " SG_ Flag : 24|1@1+ (1,0) [0|1] \"\""
1161 );
1162 }
1163}