1use crate::{
2 ByteOrder, Parser, Receivers,
3 error::{ParseError, ParseResult},
4};
5
6#[derive(Debug, Clone, PartialEq)]
7pub struct Signal<'a> {
8 name: &'a str,
9 start_bit: u16,
10 length: u16,
11 byte_order: ByteOrder,
12 unsigned: bool,
13 factor: f64,
14 offset: f64,
15 min: f64,
16 max: f64,
17 unit: Option<&'a str>,
18 receivers: Receivers<'a>,
19}
20
21impl<'a> Signal<'a> {
22 pub(crate) fn validate(name: &str, length: u16, min: f64, max: f64) -> ParseResult<()> {
23 if name.trim().is_empty() {
24 return Err(ParseError::Signal(crate::error::lang::SIGNAL_NAME_EMPTY));
25 }
26
27 if length == 0 {
33 return Err(ParseError::Signal(
34 crate::error::lang::SIGNAL_LENGTH_TOO_SMALL,
35 ));
36 }
37 if length > 512 {
38 return Err(ParseError::Signal(
39 crate::error::lang::SIGNAL_LENGTH_TOO_LARGE,
40 ));
41 }
42
43 if min > max {
51 return Err(ParseError::Signal(crate::error::lang::INVALID_RANGE));
52 }
53
54 Ok(())
55 }
56
57 #[cfg(any(feature = "alloc", feature = "kernel"))]
58 #[allow(clippy::too_many_arguments)] pub(crate) fn new(
60 name: &'a str,
61 start_bit: u16,
62 length: u16,
63 byte_order: ByteOrder,
64 unsigned: bool,
65 factor: f64,
66 offset: f64,
67 min: f64,
68 max: f64,
69 unit: Option<&'a str>,
70 receivers: Receivers<'a>,
71 ) -> Self {
72 Self {
74 name,
75 start_bit,
76 length,
77 byte_order,
78 unsigned,
79 factor,
80 offset,
81 min,
82 max,
83 unit,
84 receivers,
85 }
86 }
87
88 fn parse_position<'b>(parser: &mut Parser<'b>) -> ParseResult<(u16, u16, ByteOrder, bool)> {
89 let start_bit = match parser.parse_u32() {
91 Ok(v) => v as u16,
92 Err(_) => {
93 return Err(ParseError::Signal(
94 crate::error::lang::SIGNAL_PARSE_INVALID_START_BIT,
95 ));
96 }
97 };
98
99 if start_bit > 511 {
101 return Err(ParseError::Signal(
102 crate::error::lang::SIGNAL_PARSE_INVALID_START_BIT,
103 ));
104 }
105
106 parser.expect(b"|").map_err(|_| ParseError::Expected("Expected pipe"))?;
108
109 let length = parser
111 .parse_u32()
112 .map_err(|_| ParseError::Signal(crate::error::lang::SIGNAL_PARSE_INVALID_LENGTH))?
113 as u16;
114
115 parser.expect(b"@").map_err(|_| ParseError::Expected("Expected @"))?;
117
118 let bo_byte = if parser.expect(b"0").is_ok() {
121 b'0'
122 } else if parser.expect(b"1").is_ok() {
123 b'1'
124 } else {
125 return Err(ParseError::Expected("Expected byte order"));
126 };
127
128 let byte_order = match bo_byte {
129 b'0' => ByteOrder::BigEndian, b'1' => ByteOrder::LittleEndian, _ => return Err(ParseError::InvalidChar(bo_byte as char)),
132 };
133
134 let sign_byte = if parser.expect(b"+").is_ok() {
136 b'+'
137 } else if parser.expect(b"-").is_ok() {
138 b'-'
139 } else {
140 return Err(ParseError::Expected("Expected sign (+ or -)"));
141 };
142
143 let unsigned = match sign_byte {
144 b'+' => true,
145 b'-' => false,
146 _ => return Err(ParseError::InvalidChar(sign_byte as char)),
147 };
148
149 Ok((start_bit, length, byte_order, unsigned))
150 }
151
152 fn parse_factor_offset<'b>(parser: &mut Parser<'b>) -> ParseResult<(f64, f64)> {
153 parser
155 .expect(b"(")
156 .map_err(|_| ParseError::Expected("Expected opening parenthesis"))?;
157
158 parser.skip_newlines_and_spaces();
160
161 let pos_before = parser.pos();
165 let factor = match parser.parse_f64() {
166 Ok(val) => val,
167 Err(_) => {
168 if parser.pos() == pos_before {
170 0.0 } else {
172 return Err(ParseError::Signal(
174 crate::error::lang::SIGNAL_PARSE_INVALID_FACTOR,
175 ));
176 }
177 }
178 };
179
180 parser.expect(b",").map_err(|_| ParseError::Expected("Expected comma"))?;
182
183 parser.skip_newlines_and_spaces();
185
186 let pos_before = parser.pos();
188 let offset = match parser.parse_f64() {
189 Ok(val) => val,
190 Err(_) => {
191 if parser.pos() == pos_before {
193 0.0 } else {
195 return Err(ParseError::Signal(
196 crate::error::lang::SIGNAL_PARSE_INVALID_OFFSET,
197 ));
198 }
199 }
200 };
201
202 parser.skip_newlines_and_spaces();
204
205 parser
207 .expect(b")")
208 .map_err(|_| ParseError::Expected("Expected closing parenthesis"))?;
209
210 Ok((factor, offset))
211 }
212
213 fn parse_range<'b>(parser: &mut Parser<'b>) -> ParseResult<(f64, f64)> {
214 parser
216 .expect(b"[")
217 .map_err(|_| ParseError::Expected("Expected opening bracket"))?;
218
219 parser.skip_newlines_and_spaces();
221
222 let pos_before = parser.pos();
224 let min = match parser.parse_f64() {
225 Ok(val) => val,
226 Err(_) => {
227 if parser.pos() == pos_before {
229 0.0 } else {
231 return Err(ParseError::Signal(
232 crate::error::lang::SIGNAL_PARSE_INVALID_MIN,
233 ));
234 }
235 }
236 };
237
238 parser.expect(b"|").map_err(|_| ParseError::Expected("Expected pipe"))?;
240
241 parser.skip_newlines_and_spaces();
243
244 let pos_before = parser.pos();
246 let max = match parser.parse_f64() {
247 Ok(val) => val,
248 Err(_) => {
249 if parser.pos() == pos_before {
251 0.0 } else {
253 return Err(ParseError::Signal(
254 crate::error::lang::SIGNAL_PARSE_INVALID_MAX,
255 ));
256 }
257 }
258 };
259
260 parser.skip_newlines_and_spaces();
262
263 parser
265 .expect(b"]")
266 .map_err(|_| ParseError::Expected("Expected closing bracket"))?;
267
268 Ok((min, max))
269 }
270
271 fn parse_unit<'b: 'a>(parser: &mut Parser<'b>) -> ParseResult<Option<&'a str>> {
272 const MAX_UNIT_LENGTH: u16 = 256;
273
274 parser
276 .expect(b"\"")
277 .map_err(|_| ParseError::Expected("Expected opening quote"))?;
278
279 let unit_bytes = parser.take_until_quote(false, MAX_UNIT_LENGTH).map_err(|e| match e {
281 ParseError::MaxStrLength(_) => {
282 ParseError::Signal(crate::error::lang::SIGNAL_PARSE_UNIT_TOO_LONG)
283 }
284 _ => ParseError::Expected("Expected closing quote"),
285 })?;
286
287 let unit_str = core::str::from_utf8(unit_bytes)
289 .map_err(|_| ParseError::Expected("Invalid UTF-8 in unit"))?;
290
291 let unit = if unit_str.is_empty() {
292 None
293 } else {
294 Some(unit_str)
295 };
296
297 Ok(unit)
298 }
299
300 pub(crate) fn parse<'b: 'a>(parser: &mut Parser<'b>) -> ParseResult<Self> {
301 parser
303 .expect(crate::SG_.as_bytes())
304 .map_err(|_| ParseError::Expected("Expected SG_ keyword"))?;
305
306 parser.skip_newlines_and_spaces();
308
309 let name = parser
311 .parse_identifier()
312 .map_err(|_| ParseError::Signal(crate::error::lang::SIGNAL_NAME_EMPTY))?;
313
314 parser.skip_newlines_and_spaces();
318
319 if parser.expect(b"m").is_ok() || parser.expect(b"M").is_ok() {
322 loop {
324 let _pos_before = parser.pos();
325 if parser.expect(b"0").is_ok()
327 || parser.expect(b"1").is_ok()
328 || parser.expect(b"2").is_ok()
329 || parser.expect(b"3").is_ok()
330 || parser.expect(b"4").is_ok()
331 || parser.expect(b"5").is_ok()
332 || parser.expect(b"6").is_ok()
333 || parser.expect(b"7").is_ok()
334 || parser.expect(b"8").is_ok()
335 || parser.expect(b"9").is_ok()
336 {
337 } else {
339 break;
341 }
342 }
343 parser.skip_newlines_and_spaces();
345 }
346
347 parser.expect(b":").map_err(|_| ParseError::Expected("Expected colon"))?;
349
350 parser.skip_newlines_and_spaces();
352
353 let (start_bit, length, byte_order, unsigned) = Self::parse_position(parser)?;
355
356 parser.skip_newlines_and_spaces();
358
359 let (factor, offset) = Self::parse_factor_offset(parser)?;
361
362 parser.skip_newlines_and_spaces();
364
365 let (min, max) = Self::parse_range(parser)?;
367
368 parser.skip_newlines_and_spaces();
370
371 let unit = Self::parse_unit(parser)?;
373
374 let _ = parser.skip_whitespace().ok(); let receivers = Receivers::parse(parser)?;
380
381 Self::validate(name, length, min, max)?;
383 Ok(Self {
386 name,
387 start_bit,
388 length,
389 byte_order,
390 unsigned,
391 factor,
392 offset,
393 min,
394 max,
395 unit,
396 receivers,
397 })
398 }
399
400 #[inline]
401 #[must_use = "return value should be checked"]
402 pub fn name(&self) -> &str {
403 self.name
404 }
405
406 #[inline]
407 #[must_use]
408 pub fn start_bit(&self) -> u16 {
409 self.start_bit
410 }
411
412 #[inline]
413 #[must_use]
414 pub fn length(&self) -> u16 {
415 self.length
416 }
417
418 #[inline]
419 #[must_use]
420 pub fn byte_order(&self) -> ByteOrder {
421 self.byte_order
422 }
423
424 #[inline]
425 #[must_use]
426 pub fn is_unsigned(&self) -> bool {
427 self.unsigned
428 }
429
430 #[inline]
431 #[must_use]
432 pub fn factor(&self) -> f64 {
433 self.factor
434 }
435
436 #[inline]
437 #[must_use]
438 pub fn offset(&self) -> f64 {
439 self.offset
440 }
441
442 #[inline]
443 #[must_use]
444 pub fn min(&self) -> f64 {
445 self.min
446 }
447
448 #[inline]
449 #[must_use]
450 pub fn max(&self) -> f64 {
451 self.max
452 }
453
454 #[inline]
455 #[must_use]
456 pub fn unit(&self) -> Option<&'a str> {
457 self.unit
458 }
459
460 #[inline]
461 #[must_use]
462 pub fn receivers(&self) -> &Receivers<'a> {
463 &self.receivers
464 }
465
466 #[cfg(feature = "alloc")]
467 #[must_use]
468 pub fn to_dbc_string(&self) -> alloc::string::String {
469 use alloc::{
470 format,
471 string::{String, ToString},
472 };
473 let mut result = String::with_capacity(100); result.push_str(" SG_ ");
476 result.push_str(self.name());
477 result.push_str(" : ");
478 result.push_str(&self.start_bit().to_string());
479 result.push('|');
480 result.push_str(&self.length().to_string());
481 result.push('@');
482
483 match self.byte_order() {
486 ByteOrder::BigEndian => result.push('0'), ByteOrder::LittleEndian => result.push('1'), }
489
490 if self.is_unsigned() {
492 result.push('+');
493 } else {
494 result.push('-');
495 }
496
497 result.push_str(" (");
499 result.push_str(&format!("{}", self.factor()));
500 result.push(',');
501 result.push_str(&format!("{}", self.offset()));
502 result.push(')');
503
504 result.push_str(" [");
506 result.push_str(&format!("{}", self.min()));
507 result.push('|');
508 result.push_str(&format!("{}", self.max()));
509 result.push(']');
510
511 result.push(' ');
513 if let Some(unit) = self.unit() {
514 result.push('"');
515 result.push_str(unit);
516 result.push('"');
517 } else {
518 result.push_str("\"\"");
519 }
520
521 match self.receivers() {
523 Receivers::Broadcast => {
524 result.push(' ');
525 result.push('*');
526 }
527 Receivers::Nodes(_, count) => {
528 if *count > 0 {
529 result.push(' ');
530 for (i, node) in self.receivers().iter().enumerate() {
531 if i > 0 {
532 result.push(' ');
533 }
534 result.push_str(node);
535 }
536 }
537 }
538 Receivers::None => {
539 }
541 }
542
543 result
544 }
545}
546
547impl<'a> Eq for Signal<'a> {}
549
550impl<'a> core::hash::Hash for Signal<'a> {
552 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
553 self.name.hash(state);
554 self.start_bit.hash(state);
555 self.length.hash(state);
556 self.byte_order.hash(state);
557 self.unsigned.hash(state);
558 self.factor.to_bits().hash(state);
560 self.offset.to_bits().hash(state);
561 self.min.to_bits().hash(state);
562 self.max.to_bits().hash(state);
563 self.unit.hash(state);
564 self.receivers.hash(state);
565 }
566}
567
568#[cfg(feature = "alloc")]
569impl<'a> core::fmt::Display for Signal<'a> {
570 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
571 write!(f, "{}", self.to_dbc_string())
572 }
573}
574
575#[cfg(test)]
576mod tests {
577 #![allow(clippy::float_cmp)]
578 use super::*;
579 use crate::{
580 Parser,
581 error::{ParseError, lang},
582 };
583
584 #[test]
588 fn test_parse_valid_signal() {
589 let line = r#"SG_ RPM : 0|16@0+ (0.25,0) [0|8000] "rpm" TCM"#;
590 let mut parser = Parser::new(line.as_bytes()).unwrap();
591 let sig = Signal::parse(&mut parser).unwrap();
592 assert_eq!(sig.name(), "RPM");
593 assert_eq!(sig.start_bit(), 0);
594 assert_eq!(sig.length(), 16);
595 assert_eq!(sig.byte_order(), ByteOrder::BigEndian); assert!(sig.is_unsigned());
597 assert_eq!(sig.factor(), 0.25);
598 assert_eq!(sig.offset(), 0.);
599 assert_eq!(sig.min(), 0.);
600 assert_eq!(sig.max(), 8000.);
601 assert_eq!(sig.unit(), Some("rpm"));
602 let mut receivers_iter = sig.receivers().iter();
604 assert_eq!(receivers_iter.next(), Some("TCM"));
605 assert_eq!(receivers_iter.next(), None);
606 }
607
608 #[test]
609 fn test_parse_signal_with_empty_unit_and_broadcast() {
610 let line = r#"SG_ ABSActive : 16|1@0+ (1,0) [0|1] "" *"#;
611 let mut parser = Parser::new(line.as_bytes()).unwrap();
612 let sig = Signal::parse(&mut parser).unwrap();
613 assert_eq!(sig.name(), "ABSActive");
614 assert_eq!(sig.start_bit(), 16);
615 assert_eq!(sig.length(), 1);
616 assert_eq!(sig.byte_order(), ByteOrder::BigEndian); assert!(sig.is_unsigned());
618 assert_eq!(sig.factor(), 1.);
619 assert_eq!(sig.offset(), 0.);
620 assert_eq!(sig.min(), 0.);
621 assert_eq!(sig.max(), 1.);
622 assert_eq!(sig.unit(), None);
623 assert_eq!(sig.receivers(), &Receivers::Broadcast);
624 }
625
626 #[test]
627 fn test_parse_signal_with_negative_offset_and_min() {
628 let line = r#"SG_ Temperature : 16|8@0- (1,-40) [-40|215] "°C" TCM BCM"#;
629 let mut parser = Parser::new(line.as_bytes()).unwrap();
630 let sig = Signal::parse(&mut parser).unwrap();
631 assert_eq!(sig.name(), "Temperature");
632 assert_eq!(sig.start_bit(), 16);
633 assert_eq!(sig.length(), 8);
634 assert_eq!(sig.byte_order(), ByteOrder::BigEndian); assert!(!sig.is_unsigned());
636 assert_eq!(sig.factor(), 1.);
637 assert_eq!(sig.offset(), -40.);
638 assert_eq!(sig.min(), -40.);
639 assert_eq!(sig.max(), 215.);
640 assert_eq!(sig.unit(), Some("°C"));
641 let mut receivers_iter = sig.receivers().iter();
643 assert_eq!(receivers_iter.next(), Some("TCM"));
644 assert_eq!(receivers_iter.next(), Some("BCM"));
645 assert_eq!(receivers_iter.next(), None);
646 }
647
648 #[test]
649 fn test_parse_signal_with_percent_unit() {
650 let line = r#"SG_ ThrottlePosition : 24|8@0+ (0.392157,0) [0|100] "%" *"#;
651 let mut parser = Parser::new(line.as_bytes()).unwrap();
652 let sig = Signal::parse(&mut parser).unwrap();
653 assert_eq!(sig.name(), "ThrottlePosition");
654 assert_eq!(sig.start_bit(), 24);
655 assert_eq!(sig.length(), 8);
656 assert_eq!(sig.byte_order(), ByteOrder::BigEndian); assert!(sig.is_unsigned());
658 assert_eq!(sig.factor(), 0.392_157);
659 assert_eq!(sig.offset(), 0.);
660 assert_eq!(sig.min(), 0.);
661 assert_eq!(sig.max(), 100.);
662 assert_eq!(sig.unit(), Some("%"));
663 assert_eq!(sig.receivers(), &Receivers::Broadcast);
664 }
665
666 #[test]
667 fn test_parse_signal_missing_factors_and_limits() {
668 let line = r#"SG_ Simple : 10|4@0+ ( , ) [ | ] "" *"#;
670 let mut parser = Parser::new(line.as_bytes()).unwrap();
671 let sig = Signal::parse(&mut parser).unwrap();
672 assert_eq!(sig.name(), "Simple");
673 assert_eq!(sig.start_bit(), 10);
674 assert_eq!(sig.length(), 4);
675 assert_eq!(sig.byte_order(), ByteOrder::BigEndian); assert!(sig.is_unsigned());
677 assert_eq!(sig.factor(), 0.);
678 assert_eq!(sig.offset(), 0.);
679 assert_eq!(sig.min(), 0.);
680 assert_eq!(sig.max(), 0.);
681 assert_eq!(sig.unit(), None);
682 assert_eq!(sig.receivers(), &Receivers::Broadcast);
683 }
684
685 #[test]
686 fn test_parse_signal_missing_start_bit() {
687 let line = r#"SG_ RPM : |16@0+ (0.25,0) [0|8000] "rpm" TCM"#;
688 let mut parser = Parser::new(line.as_bytes()).unwrap();
689 let err = Signal::parse(&mut parser).unwrap_err();
690 match err {
691 ParseError::Signal(msg) => {
692 assert!(
694 msg.contains(lang::SIGNAL_PARSE_INVALID_START_BIT)
695 || msg.contains("Signal 'RPM'")
696 );
697 }
698 _ => panic!("Expected ParseError::Signal"),
699 }
700 }
701
702 #[test]
703 fn test_parse_signal_invalid_range() {
704 let line = r#"SG_ Test : 0|8@0+ (1,0) [100|50] "unit" *"#;
706 let mut parser = Parser::new(line.as_bytes()).unwrap();
707 let err = Signal::parse(&mut parser).unwrap_err();
708 match err {
709 ParseError::Signal(msg) => {
710 assert!(msg.contains(lang::INVALID_RANGE));
711 }
712 e => panic!("Expected ParseError::Signal, got: {:?}", e),
713 }
714 }
715
716 #[test]
717 fn test_parse_signal_overflow() {
718 let line = r#"SG_ Test : 60|10@0+ (1,0) [0|100] "unit" *"#;
722 let mut parser = Parser::new(line.as_bytes()).unwrap();
723 let signal = Signal::parse(&mut parser).unwrap();
724 assert_eq!(signal.start_bit(), 60);
725 assert_eq!(signal.length(), 10);
726 }
728
729 #[test]
730 fn test_parse_signal_length_too_large() {
731 let line = r#"SG_ Test : 0|513@0+ (1,0) [0|100] "unit" *"#;
733 let mut parser = Parser::new(line.as_bytes()).unwrap();
734 let err = Signal::parse(&mut parser).unwrap_err();
735 match err {
736 ParseError::Signal(msg) => {
737 assert!(
739 msg.contains(lang::SIGNAL_LENGTH_TOO_LARGE)
740 || msg.contains("Signal 'Test'")
741 || msg.contains("513")
742 );
743 }
744 e => panic!("Expected ParseError::Signal, got: {:?}", e),
745 }
746 }
747
748 #[test]
749 fn test_parse_signal_zero_length() {
750 let line = r#"SG_ Test : 0|0@0+ (1,0) [0|100] "unit" *"#;
752 let mut parser = Parser::new(line.as_bytes()).unwrap();
753 let err = Signal::parse(&mut parser).unwrap_err();
754 match err {
755 ParseError::Signal(msg) => {
756 assert!(
758 msg.contains(lang::SIGNAL_LENGTH_TOO_SMALL)
759 || msg.contains("Signal 'Test'")
760 || msg.contains("0 bits")
761 );
762 }
763 e => panic!("Expected ParseError::Signal, got: {:?}", e),
764 }
765 }
766
767 #[test]
768 fn test_parse_signal_missing_length() {
769 let line = r#"SG_ RPM : 0|@0+ (0.25,0) [0|8000] "rpm" TCM"#;
770 let mut parser = Parser::new(line.as_bytes()).unwrap();
771 let err = Signal::parse(&mut parser).unwrap_err();
772 match err {
773 ParseError::Signal(msg) => assert!(msg.contains(lang::SIGNAL_PARSE_INVALID_LENGTH)),
774 e => panic!("Expected ParseError::Signal, got: {:?}", e),
775 }
776 }
777
778 #[cfg(any(feature = "alloc", feature = "kernel"))]
780 mod tests_with_alloc {
781 #[cfg(feature = "alloc")]
782 use super::*;
783
784 #[test]
785 #[cfg(feature = "alloc")] fn test_signal_to_dbc_string_round_trip() {
787 use alloc::vec;
788 let test_cases = vec![
790 (
791 r#"SG_ RPM : 0|16@0+ (0.25,0) [0|8000] "rpm" *"#,
792 " SG_ RPM : 0|16@0+ (0.25,0) [0|8000] \"rpm\" *",
793 ),
794 (
795 r#"SG_ Temperature : 16|8@1- (1,-40) [-40|215] "°C" TCM BCM"#,
796 " SG_ Temperature : 16|8@1- (1,-40) [-40|215] \"°C\" TCM BCM",
797 ),
798 (
799 r#"SG_ Flag : 24|1@0+ (1,0) [0|1] "" *"#,
800 " SG_ Flag : 24|1@0+ (1,0) [0|1] \"\" *",
801 ),
802 ];
803
804 for (input_line, expected_output) in test_cases {
805 let mut parser = Parser::new(input_line.as_bytes()).unwrap();
807 let signal = Signal::parse(&mut parser).unwrap();
808
809 let dbc_string = signal.to_dbc_string();
811 assert_eq!(dbc_string, expected_output);
812
813 let mut parser2 = Parser::new(dbc_string.as_bytes()).unwrap();
815 parser2.skip_newlines_and_spaces();
817 let signal2 = Signal::parse(&mut parser2).unwrap();
818
819 assert_eq!(signal.name(), signal2.name());
821 assert_eq!(signal.start_bit(), signal2.start_bit());
822 assert_eq!(signal.length(), signal2.length());
823 assert_eq!(signal.byte_order(), signal2.byte_order());
824 assert_eq!(signal.is_unsigned(), signal2.is_unsigned());
825 assert_eq!(signal.factor(), signal2.factor());
826 assert_eq!(signal.offset(), signal2.offset());
827 assert_eq!(signal.min(), signal2.min());
828 assert_eq!(signal.max(), signal2.max());
829 assert_eq!(signal.unit(), signal2.unit());
830 }
831 }
832 }
833
834 }