can_dbc/ast/
signal.rs

1use can_dbc_pest::{Pair, Rule};
2
3use crate::ast::{ByteOrder, MultiplexIndicator, ValueType};
4use crate::parser::{
5    collect_strings, next, next_optional_rule, next_rule, next_string, parse_min_max_float,
6    parse_next_float, parse_next_inner_str, parse_next_uint, validated_inner,
7};
8use crate::DbcError;
9
10/// One or multiple signals are the payload of a CAN frame.
11/// To determine the actual value of a signal the following fn applies:
12/// `let value = |can_signal_value| can_signal_value * factor + offset;`
13#[derive(Clone, Debug, PartialEq)]
14#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
15pub struct Signal {
16    pub name: String,
17    pub multiplexer_indicator: MultiplexIndicator,
18    pub start_bit: u64,
19    pub size: u64,
20    pub byte_order: ByteOrder,
21    pub value_type: ValueType,
22    pub factor: f64,
23    pub offset: f64,
24    pub min: f64,
25    pub max: f64,
26    pub unit: String,
27    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Vec::is_empty"))]
28    pub receivers: Vec<String>,
29}
30
31/// Parse signal: `SG_ signal_name : start_bit|signal_size@byte_order+/- (factor,offset) [min|max] "unit" receiver`
32impl TryFrom<Pair<'_, Rule>> for Signal {
33    type Error = DbcError;
34
35    fn try_from(value: Pair<'_, Rule>) -> Result<Self, Self::Error> {
36        let mut pairs = validated_inner(value, Rule::signal)?;
37
38        next_rule(&mut pairs, Rule::signal_nl_ident)?; // skip
39        let name = next_string(&mut pairs, Rule::signal_name)?;
40        let multiplexer_indicator =
41            if let Some(v) = next_optional_rule(&mut pairs, Rule::multiplexer_indicator) {
42                v.as_str().try_into()?
43            } else {
44                MultiplexIndicator::Plain
45            };
46        let start_bit = parse_next_uint(&mut pairs, Rule::start_bit)?;
47        let size = parse_next_uint(&mut pairs, Rule::signal_size)?;
48        let byte_order = next(&mut pairs)?.try_into()?;
49        let value_type = next(&mut pairs)?.try_into()?;
50        let factor = parse_next_float(&mut pairs, Rule::factor)?;
51        let offset = parse_next_float(&mut pairs, Rule::offset)?;
52        let (min, max) = parse_min_max_float(next_rule(&mut pairs, Rule::min_max)?)?;
53        let unit = parse_next_inner_str(&mut pairs, Rule::unit)?;
54        let receivers = collect_strings(&mut pairs, Rule::node_name)?;
55
56        Ok(Self {
57            name,
58            multiplexer_indicator,
59            start_bit,
60            size,
61            byte_order,
62            value_type,
63            factor,
64            offset,
65            min,
66            max,
67            unit,
68            receivers,
69        })
70    }
71}
72
73#[cfg(test)]
74mod tests {
75    use super::*;
76    use crate::test_helpers::*;
77
78    #[test]
79    fn signal_test() {
80        let def = r#"
81 SG_ NAME : 3|2@1- (1,0) [0|0] "x" UFA
82"#;
83
84        let exp = Signal {
85            name: "NAME".to_string(),
86            start_bit: 3,
87            size: 2,
88            byte_order: ByteOrder::LittleEndian,
89            value_type: ValueType::Signed,
90            factor: 1.0,
91            offset: 0.0,
92            min: 0.0,
93            max: 0.0,
94            unit: "x".to_string(),
95            multiplexer_indicator: MultiplexIndicator::Plain,
96            receivers: vec!["UFA".to_string()],
97        };
98        let val = test_into::<Signal>(def, Rule::signal);
99        assert_eq!(val, exp);
100    }
101
102    #[test]
103    fn signal_definition_test() {
104        // multiple newlines with optional spaces/comments before each signal line
105        let def = "\r\n \r\n SG_ BasL2 : 3|2@0- (1,0) [0|0] \"x\" DFA_FUS\r\n";
106
107        let exp = Signal {
108            name: "BasL2".to_string(),
109            start_bit: 3,
110            size: 2,
111            byte_order: ByteOrder::BigEndian,
112            value_type: ValueType::Signed,
113            factor: 1.0,
114            offset: 0.0,
115            min: 0.0,
116            max: 0.0,
117            unit: "x".to_string(),
118            multiplexer_indicator: MultiplexIndicator::Plain,
119            receivers: vec!["DFA_FUS".to_string()],
120        };
121        let val = test_into::<Signal>(def, Rule::signal);
122        assert_eq!(val, exp);
123    }
124}