can_dbc/ast/
message.rs

1use can_dbc_pest::{Pair, Rule};
2
3use crate::ast::{MessageId, Signal, Transmitter};
4use crate::parser::{
5    collect_expected, next_rule, next_string, parse_next_uint, single_inner, validated_inner,
6};
7use crate::DbcError;
8
9/// CAN message (frame) details including signal details
10#[derive(Clone, Debug, PartialEq)]
11#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
12pub struct Message {
13    /// CAN id in header of CAN frame.
14    /// Must be unique in DBC file.
15    pub id: MessageId,
16    pub name: String,
17    pub size: u64,
18    pub transmitter: Transmitter,
19    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Vec::is_empty"))]
20    pub signals: Vec<Signal>,
21}
22
23impl TryFrom<Pair<'_, Rule>> for Message {
24    type Error = DbcError;
25
26    /// Parse message: `BO_ message_id message_name: message_size transmitter`
27    fn try_from(value: Pair<'_, Rule>) -> Result<Self, Self::Error> {
28        let mut pairs = validated_inner(value, Rule::message)?;
29
30        // Parse msg_var (contains msg_literal ~ message_id)
31        let msg_var_pair = next_rule(&mut pairs, Rule::msg_var)?;
32        let id = single_inner(msg_var_pair, Rule::message_id)?.try_into()?;
33        let name = next_string(&mut pairs, Rule::message_name)?;
34        let size = parse_next_uint(&mut pairs, Rule::message_size)?;
35
36        let transmitter = next_string(&mut pairs, Rule::transmitter)?;
37        let transmitter = if matches!(transmitter.as_str(), "Vector__XXX" | "VectorXXX" | "") {
38            Transmitter::VectorXXX
39        } else {
40            Transmitter::NodeName(transmitter)
41        };
42
43        let signals = collect_expected(&mut pairs, Rule::signal)?;
44
45        Ok(Self {
46            id,
47            name,
48            size,
49            transmitter,
50            signals,
51        })
52    }
53}
54
55#[cfg(test)]
56mod tests {
57    use super::*;
58    use crate::ast::{ByteOrder, MultiplexIndicator, ValueType};
59    use crate::test_helpers::*;
60
61    #[test]
62    fn message_definition_test() {
63        let def = r#"
64BO_ 1 MCA_A1: 6 MFA
65 SG_ ABC_1 : 9|2@1+ (1,0) [0|0] "x" XYZ_OUS
66 SG_ BasL2 : 3|2@0- (1,0) [0|0] "x" DFA_FUS
67"#;
68
69        let exp = Message {
70            id: MessageId::Standard(1),
71            name: "MCA_A1".to_string(),
72            size: 6,
73            transmitter: Transmitter::NodeName("MFA".to_string()),
74            signals: vec![
75                Signal {
76                    name: "ABC_1".to_string(),
77                    start_bit: 9,
78                    size: 2,
79                    byte_order: ByteOrder::LittleEndian,
80                    value_type: ValueType::Unsigned,
81                    factor: 1.0,
82                    offset: 0.0,
83                    min: 0.0,
84                    max: 0.0,
85                    unit: "x".to_string(),
86                    multiplexer_indicator: MultiplexIndicator::Plain,
87                    receivers: vec!["XYZ_OUS".to_string()],
88                },
89                Signal {
90                    name: "BasL2".to_string(),
91                    start_bit: 3,
92                    size: 2,
93                    byte_order: ByteOrder::BigEndian,
94                    value_type: ValueType::Signed,
95                    factor: 1.0,
96                    offset: 0.0,
97                    min: 0.0,
98                    max: 0.0,
99                    unit: "x".to_string(),
100                    multiplexer_indicator: MultiplexIndicator::Plain,
101                    receivers: vec!["DFA_FUS".to_string()],
102                },
103            ],
104        };
105        let val = test_into::<Message>(def.trim_start(), Rule::message);
106        assert_eq!(val, exp);
107    }
108}