Skip to main content

can_dbc/ast/
dbc.rs

1use std::str;
2
3use can_dbc_pest::{DbcParser, Parser as _, Rule};
4
5use crate::ast::{
6    AttributeDefault, AttributeDefinition, AttributeValueForObject, Baudrate, Comment,
7    EnvironmentVariable, EnvironmentVariableData, ExtendedMultiplex, Message, MessageId,
8    MessageTransmitter, MultiplexIndicator, Node, Signal, SignalExtendedValueType,
9    SignalExtendedValueTypeList, SignalGroups, SignalType, SignalTypeRef, Symbol, ValDescription,
10    ValueDescription, ValueTable, Version,
11};
12use crate::parser::{collect_all, DbcError, DbcResult};
13use crate::{AttributeValue, AttributeValueForObjectType, AttributeValueForRelation};
14
15#[derive(Clone, Debug, PartialEq)]
16#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
17pub struct Dbc {
18    /// Version generated by DB editor
19    pub version: Version,
20    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Vec::is_empty"))]
21    pub new_symbols: Vec<Symbol>,
22    /// Baud rate of network
23    pub bit_timing: Option<Vec<Baudrate>>,
24    /// CAN network nodes
25    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Vec::is_empty"))]
26    pub nodes: Vec<Node>,
27    /// Global value table
28    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Vec::is_empty"))]
29    pub value_tables: Vec<ValueTable>,
30    /// CAN message (frame) details including signal details
31    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Vec::is_empty"))]
32    pub messages: Vec<Message>,
33    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Vec::is_empty"))]
34    pub message_transmitters: Vec<MessageTransmitter>,
35    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Vec::is_empty"))]
36    pub environment_variables: Vec<EnvironmentVariable>,
37    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Vec::is_empty"))]
38    pub environment_variable_data: Vec<EnvironmentVariableData>,
39    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Vec::is_empty"))]
40    pub signal_types: Vec<SignalType>,
41    /// Object comments
42    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Vec::is_empty"))]
43    pub comments: Vec<Comment>,
44    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Vec::is_empty"))]
45    pub attribute_definitions: Vec<AttributeDefinition>,
46    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Vec::is_empty"))]
47    pub relation_attribute_definitions: Vec<AttributeDefinition>,
48    // undefined
49    // sigtype_attr_list: SigtypeAttrList,
50    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Vec::is_empty"))]
51    pub attribute_defaults: Vec<AttributeDefault>,
52    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Vec::is_empty"))]
53    pub relation_attribute_defaults: Vec<AttributeDefault>,
54    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Vec::is_empty"))]
55    pub relation_attribute_values: Vec<AttributeValueForRelation>,
56    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Vec::is_empty"))]
57    pub attribute_values_database: Vec<AttributeValueForDatabase>,
58    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Vec::is_empty"))]
59    pub attribute_values_node: Vec<AttributeValueForNode>,
60    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Vec::is_empty"))]
61    pub attribute_values_message: Vec<AttributeValueForMessage>,
62    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Vec::is_empty"))]
63    pub attribute_values_signal: Vec<AttributeValueForSignal>,
64    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Vec::is_empty"))]
65    pub attribute_values_env: Vec<AttributeValueForEnvVariable>,
66    /// Encoding for signal raw values
67    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Vec::is_empty"))]
68    pub value_descriptions: Vec<ValueDescription>,
69    // obsolete + undefined
70    // category_definitions: Vec<CategoryDefinition>,
71    // obsolete + undefined
72    //categories: Vec<Category>,
73    // obsolete + undefined
74    //filter: Vec<Filter>,
75    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Vec::is_empty"))]
76    pub signal_type_refs: Vec<SignalTypeRef>,
77    /// Signal groups define a group of signals within a message
78    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Vec::is_empty"))]
79    pub signal_groups: Vec<SignalGroups>,
80    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Vec::is_empty"))]
81    pub signal_extended_value_type_list: Vec<SignalExtendedValueTypeList>,
82    /// Extended multiplex attributes
83    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Vec::is_empty"))]
84    pub extended_multiplex: Vec<ExtendedMultiplex>,
85}
86
87#[derive(Clone, Debug, PartialEq)]
88#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
89pub struct AttributeValueForDatabase {
90    pub name: String,
91    pub value: AttributeValue,
92}
93
94#[derive(Clone, Debug, PartialEq)]
95#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
96pub struct AttributeValueForNode {
97    pub name: String,
98    pub node_name: String,
99    pub value: AttributeValue,
100}
101
102#[derive(Clone, Debug, PartialEq)]
103#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
104pub struct AttributeValueForMessage {
105    pub name: String,
106    pub message_id: MessageId,
107    pub value: AttributeValue,
108}
109
110#[derive(Clone, Debug, PartialEq)]
111#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
112pub struct AttributeValueForSignal {
113    pub name: String,
114    pub message_id: MessageId,
115    pub signal_name: String,
116    pub value: AttributeValue,
117}
118
119#[derive(Clone, Debug, PartialEq)]
120#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
121pub struct AttributeValueForEnvVariable {
122    pub name: String,
123    pub variable_name: String,
124    pub value: AttributeValue,
125}
126
127impl Dbc {
128    #[must_use]
129    pub fn signal_by_name(&self, message_id: MessageId, signal_name: &str) -> Option<&Signal> {
130        let message = self
131            .messages
132            .iter()
133            .find(|message| message.id == message_id);
134
135        if let Some(message) = message {
136            return message
137                .signals
138                .iter()
139                .find(|signal| signal.name == *signal_name);
140        }
141        None
142    }
143
144    /// Lookup a message comment
145    #[must_use]
146    pub fn message_comment(&self, message_id: MessageId) -> Option<&str> {
147        self.comments.iter().find_map(|x| match x {
148            Comment::Message {
149                id: ref x_message_id,
150                ref comment,
151            } => {
152                if *x_message_id == message_id {
153                    Some(comment.as_str())
154                } else {
155                    None
156                }
157            }
158            _ => None,
159        })
160    }
161
162    /// Lookup a signal comment
163    #[must_use]
164    pub fn signal_comment(&self, message_id: MessageId, signal_name: &str) -> Option<&str> {
165        self.comments.iter().find_map(|x| match x {
166            Comment::Signal {
167                message_id: ref x_message_id,
168                name: ref x_signal_name,
169                comment,
170            } => {
171                if *x_message_id == message_id && x_signal_name == signal_name {
172                    Some(comment.as_str())
173                } else {
174                    None
175                }
176            }
177            _ => None,
178        })
179    }
180
181    /// Lookup value descriptions for signal
182    #[must_use]
183    pub fn value_descriptions_for_signal(
184        &self,
185        message_id: MessageId,
186        signal_name: &str,
187    ) -> Option<&[ValDescription]> {
188        self.value_descriptions.iter().find_map(|x| match x {
189            ValueDescription::Signal {
190                message_id: ref x_message_id,
191                name: ref x_signal_name,
192                ref value_descriptions,
193            } => {
194                if *x_message_id == message_id && x_signal_name == signal_name {
195                    Some(value_descriptions.as_slice())
196                } else {
197                    None
198                }
199            }
200            ValueDescription::EnvironmentVariable { .. } => None,
201        })
202    }
203
204    /// Lookup the extended value for a given signal
205    #[must_use]
206    pub fn extended_value_type_for_signal(
207        &self,
208        message_id: MessageId,
209        signal_name: &str,
210    ) -> Option<&SignalExtendedValueType> {
211        self.signal_extended_value_type_list.iter().find_map(|x| {
212            let SignalExtendedValueTypeList {
213                message_id: ref x_message_id,
214                signal_name: ref x_signal_name,
215                ref signal_extended_value_type,
216            } = x;
217            if *x_message_id == message_id && x_signal_name == signal_name {
218                Some(signal_extended_value_type)
219            } else {
220                None
221            }
222        })
223    }
224
225    /// Lookup the message multiplexer switch signal for a given message
226    /// This does not work for extended multiplexed messages, if multiple multiplexors are defined for a message an Error is returned.
227    pub fn message_multiplexor_switch(&self, message_id: MessageId) -> DbcResult<Option<&Signal>> {
228        let message = self
229            .messages
230            .iter()
231            .find(|message| message.id == message_id);
232
233        if let Some(message) = message {
234            if self
235                .extended_multiplex
236                .iter()
237                .any(|ext_mp| ext_mp.message_id == message_id)
238            {
239                Err(DbcError::MultipleMultiplexors)
240            } else {
241                Ok(message
242                    .signals
243                    .iter()
244                    .find(|signal| signal.multiplexer_indicator == MultiplexIndicator::Multiplexor))
245            }
246        } else {
247            Ok(None)
248        }
249    }
250
251    /// Lookup an assigned message-level (`BO_`) attribute value.
252    #[must_use]
253    pub fn message_attribute(&self, message_id: MessageId, name: &str) -> Option<&AttributeValue> {
254        self.attribute_values_message
255            .iter()
256            .find(|a| a.message_id == message_id && a.name == name)
257            .map(|a| &a.value)
258    }
259
260    /// Lookup an assigned signal-level (`SG_`) attribute value.
261    #[must_use]
262    pub fn signal_attribute(
263        &self,
264        message_id: MessageId,
265        signal_name: &str,
266        name: &str,
267    ) -> Option<&AttributeValue> {
268        self.attribute_values_signal
269            .iter()
270            .find(|a| a.message_id == message_id && a.signal_name == signal_name && a.name == name)
271            .map(|a| &a.value)
272    }
273
274    /// Lookup an attribute's default value (`BA_DEF_DEF_`).
275    #[must_use]
276    pub fn attribute_default(&self, name: &str) -> Option<&AttributeValue> {
277        self.attribute_defaults
278            .iter()
279            .find(|d| d.name == name)
280            .map(|d| &d.value)
281    }
282
283    /// Lookup a message-level attribute value.
284    /// Falls back to the default `BA_DEF_DEF_` if a value is not defined.
285    #[must_use]
286    pub fn resolved_message_attribute(
287        &self,
288        message_id: MessageId,
289        name: &str,
290    ) -> Option<&AttributeValue> {
291        self.message_attribute(message_id, name)
292            .or_else(|| self.attribute_default(name))
293    }
294
295    /// Lookup a signal-level attribute value.
296    /// Falls back to the default `BA_DEF_DEF_` if a value is not defined.
297    #[must_use]
298    pub fn resolved_signal_attribute(
299        &self,
300        message_id: MessageId,
301        signal_name: &str,
302        name: &str,
303    ) -> Option<&AttributeValue> {
304        self.signal_attribute(message_id, signal_name, name)
305            .or_else(|| self.attribute_default(name))
306    }
307}
308
309impl<'a> TryFrom<&'a str> for Dbc {
310    type Error = DbcError;
311
312    fn try_from(dbc_in: &'a str) -> Result<Self, Self::Error> {
313        dbc(dbc_in)
314    }
315}
316
317#[expect(clippy::too_many_lines)] // FIXME: refactor
318pub(crate) fn dbc(buffer: &str) -> DbcResult<Dbc> {
319    let mut version = Version::default();
320    let mut new_symbols = vec![];
321    let mut bit_timing = None;
322    let mut nodes = vec![];
323    let mut value_tables = vec![];
324    let mut messages: Vec<Message> = vec![];
325    let mut message_transmitters = vec![];
326    let mut environment_variables = vec![];
327    let mut environment_variable_data = vec![];
328    let mut comments = vec![];
329    let mut attribute_definitions = vec![];
330    let mut relation_attribute_definitions = vec![];
331    let mut attribute_defaults = vec![];
332    let mut relation_attribute_defaults = vec![];
333    let mut attribute_values_database = vec![];
334    let mut attribute_values_node = vec![];
335    let mut attribute_values_message = vec![];
336    let mut attribute_values_signal = vec![];
337    let mut attribute_values_env = vec![];
338    let mut relation_attribute_values = vec![];
339    let mut value_descriptions = vec![];
340    let mut signal_groups = vec![];
341    let mut signal_extended_value_type_list = vec![];
342    let mut extended_multiplex = vec![];
343
344    for pair in DbcParser::parse(Rule::file, buffer)? {
345        if !matches!(pair.as_rule(), Rule::file) {
346            return Err(DbcError::ExpectedRule(Rule::file, pair.as_rule()));
347        }
348        for pairs in pair.into_inner() {
349            match pairs.as_rule() {
350                Rule::version => version = pairs.try_into()?,
351                Rule::new_symbols => {
352                    let symbols: Vec<Symbol> = collect_all::<Symbol>(&mut pairs.into_inner())?;
353                    new_symbols.extend(symbols);
354                }
355                Rule::bit_timing => {
356                    let _inner_pairs = pairs.into_inner();
357                    // For now, just return empty vec since bit-timing parsing is not implemented
358                    bit_timing = Some(vec![]);
359                }
360                Rule::nodes => nodes = collect_all::<Node>(&mut pairs.into_inner())?,
361                Rule::message => messages.push(pairs.try_into()?),
362                Rule::comment => comments.push(pairs.try_into()?),
363                Rule::attr_def => attribute_definitions.push(pairs.try_into()?),
364                Rule::ba_def_rel => relation_attribute_definitions.push(pairs.try_into()?),
365                Rule::ba_rel => relation_attribute_values.push(pairs.try_into()?),
366                Rule::attr_value => {
367                    let attr_value: AttributeValueForObject = pairs.try_into()?;
368                    match attr_value.value {
369                        AttributeValueForObjectType::Raw(attribute_value) => {
370                            attribute_values_database.push(AttributeValueForDatabase {
371                                name: attr_value.name,
372                                value: attribute_value,
373                            });
374                        }
375                        AttributeValueForObjectType::NetworkNode(node_name, attribute_value) => {
376                            attribute_values_node.push(AttributeValueForNode {
377                                name: attr_value.name,
378                                node_name,
379                                value: attribute_value,
380                            });
381                        }
382                        AttributeValueForObjectType::MessageDefinition(
383                            message_id,
384                            attribute_value,
385                        ) => {
386                            if let Some(value) = attribute_value {
387                                attribute_values_message.push(AttributeValueForMessage {
388                                    name: attr_value.name,
389                                    message_id,
390                                    value,
391                                });
392                            }
393                        }
394                        AttributeValueForObjectType::Signal(
395                            message_id,
396                            signal_name,
397                            attribute_value,
398                        ) => {
399                            attribute_values_signal.push(AttributeValueForSignal {
400                                name: attr_value.name,
401                                message_id,
402                                signal_name,
403                                value: attribute_value,
404                            });
405                        }
406                        AttributeValueForObjectType::EnvVariable(
407                            variable_name,
408                            attribute_value,
409                        ) => {
410                            attribute_values_env.push(AttributeValueForEnvVariable {
411                                name: attr_value.name,
412                                variable_name,
413                                value: attribute_value,
414                            });
415                        }
416                    }
417                }
418                Rule::value_table => value_tables.push(pairs.try_into()?),
419                Rule::value_table_def => value_descriptions.push(pairs.try_into()?),
420                Rule::signal_group => signal_groups.push(pairs.try_into()?),
421                Rule::signal_value_type => {
422                    signal_extended_value_type_list.push(pairs.try_into()?);
423                }
424                Rule::message_transmitter => message_transmitters.push(pairs.try_into()?),
425                Rule::ba_def_def => attribute_defaults.push(pairs.try_into()?),
426                Rule::ba_def_def_rel => relation_attribute_defaults.push(pairs.try_into()?),
427                Rule::sg_mul_val => extended_multiplex.push(pairs.try_into()?),
428                Rule::environment_variable => {
429                    environment_variables.push(pairs.try_into()?);
430                }
431                Rule::env_var_data => environment_variable_data.push(pairs.try_into()?),
432                Rule::EOI => {
433                    // ignore
434                }
435                other => Err(DbcError::UnknownRule(other))?,
436            }
437        }
438    }
439
440    Ok(Dbc {
441        version,
442        new_symbols,
443        bit_timing,
444        nodes,
445        value_tables,
446        messages,
447        message_transmitters,
448        environment_variables,
449        environment_variable_data,
450        signal_types: vec![], // TODO
451        comments,
452        attribute_definitions,
453        relation_attribute_definitions,
454        attribute_defaults,
455        relation_attribute_defaults,
456        relation_attribute_values,
457        attribute_values_database,
458        attribute_values_node,
459        attribute_values_message,
460        attribute_values_signal,
461        attribute_values_env,
462        value_descriptions,
463        signal_type_refs: vec![], // TODO
464        signal_groups,
465        signal_extended_value_type_list,
466        extended_multiplex,
467    })
468}