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#[derive(Clone, Debug, PartialEq)]
11#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
12pub struct Message {
13 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 fn try_from(value: Pair<'_, Rule>) -> Result<Self, Self::Error> {
28 let mut pairs = validated_inner(value, Rule::message)?;
29
30 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 use crate::NumericValue;
61
62 #[test]
63 fn message_definition_test() {
64 let def = r#"
65BO_ 1 MCA_A1: 6 MFA
66 SG_ ABC_1 : 9|2@1+ (1,0) [0|0] "x" XYZ_OUS
67 SG_ BasL2 : 3|2@0- (1,0) [0|0] "x" DFA_FUS
68"#;
69
70 let exp = Message {
71 id: MessageId::Standard(1),
72 name: "MCA_A1".to_string(),
73 size: 6,
74 transmitter: Transmitter::NodeName("MFA".to_string()),
75 signals: vec![
76 Signal {
77 name: "ABC_1".to_string(),
78 start_bit: 9,
79 size: 2,
80 byte_order: ByteOrder::LittleEndian,
81 value_type: ValueType::Unsigned,
82 factor: 1.0,
83 offset: 0.0,
84 min: NumericValue::Uint(0),
85 max: NumericValue::Uint(0),
86 unit: "x".to_string(),
87 multiplexer_indicator: MultiplexIndicator::Plain,
88 receivers: vec!["XYZ_OUS".to_string()],
89 },
90 Signal {
91 name: "BasL2".to_string(),
92 start_bit: 3,
93 size: 2,
94 byte_order: ByteOrder::BigEndian,
95 value_type: ValueType::Signed,
96 factor: 1.0,
97 offset: 0.0,
98 min: NumericValue::Uint(0),
99 max: NumericValue::Uint(0),
100 unit: "x".to_string(),
101 multiplexer_indicator: MultiplexIndicator::Plain,
102 receivers: vec!["DFA_FUS".to_string()],
103 },
104 ],
105 };
106 let val = test_into::<Message>(def.trim_start(), Rule::message);
107 assert_eq!(val, exp);
108 }
109
110 #[test]
111 fn min_max_numeric_test() {
112 let def = r#"BO_ 1 MCA_A1: 6 MFA
113 SG_ uint : 9|2@1+ (1,0) [0|18446744073709551615] "x" XYZ_OUS
114 SG_ int : 3|2@0- (1,0) [-9223372036854775808|9223372036854775807] "x" DFA_FUS
115"#;
116
117 let exp = Message {
118 id: MessageId::Standard(1),
119 name: "MCA_A1".to_string(),
120 size: 6,
121 transmitter: Transmitter::NodeName("MFA".to_string()),
122 signals: vec![
123 Signal {
124 name: "uint".to_string(),
125 start_bit: 9,
126 size: 2,
127 byte_order: ByteOrder::LittleEndian,
128 value_type: ValueType::Unsigned,
129 factor: 1.0,
130 offset: 0.0,
131 min: NumericValue::Uint(0),
132 max: NumericValue::Uint(18_446_744_073_709_551_615),
133 unit: "x".to_string(),
134 multiplexer_indicator: MultiplexIndicator::Plain,
135 receivers: vec!["XYZ_OUS".to_string()],
136 },
137 Signal {
138 name: "int".to_string(),
139 start_bit: 3,
140 size: 2,
141 byte_order: ByteOrder::BigEndian,
142 value_type: ValueType::Signed,
143 factor: 1.0,
144 offset: 0.0,
145 min: NumericValue::Int(-9_223_372_036_854_775_808),
146 max: NumericValue::Uint(9_223_372_036_854_775_807),
147 unit: "x".to_string(),
148 multiplexer_indicator: MultiplexIndicator::Plain,
149 receivers: vec!["DFA_FUS".to_string()],
150 },
151 ],
152 };
153 let val = test_into::<Message>(def.trim_start(), Rule::message);
154 assert_eq!(val, exp);
155 }
156}