Skip to main content

dbc_codegen2/ir/
ir_builder.rs

1use can_dbc::Dbc as ParsedDbc;
2use can_dbc::Message as ParsedMessage;
3use can_dbc::Signal as ParsedSignal;
4use can_dbc::SignalExtendedValueTypeList as ParsedExtendedValueType;
5use crate::ir::{map_into, SignalValueEnum, ExtendedValueType, Signal, Message, SignalIdx, SignalLayout, SignalLayoutIdx, MessageLayout, MessageLayoutIdx};
6use can_dbc::ValueDescription as ParsedValueDescription;
7
8use std::collections::HashMap;
9
10use crate::DbcFile;
11
12type SignalKey = (can_dbc::MessageId, String);
13
14pub struct IRBuilder {
15    file: DbcFile,
16    can_dbc_messages: Vec<ParsedMessage>,
17
18    value_enum_map: HashMap<SignalKey, SignalValueEnum>,
19    extended_type_map: HashMap<SignalKey, ExtendedValueType>,
20
21    signal_layout_map: HashMap<SignalLayout, SignalLayoutIdx>,
22    message_layout_map: HashMap<MessageLayout, MessageLayoutIdx>,
23}
24
25impl IRBuilder {
26
27    pub fn to_ir(value: ParsedDbc) -> DbcFile {
28        let mut builder = Self::new(value);
29        builder.build();
30        builder.file
31    }
32
33    fn new(value: ParsedDbc) -> Self {
34        let value_enum_map = Self::value_enum_map(value.value_descriptions);
35        let extended_type_map = Self::extended_type_map(value.signal_extended_value_type_list);
36
37        let mut file = DbcFile::default();
38        file.nodes = map_into(value.nodes);
39
40        Self {
41            file,
42            can_dbc_messages: value.messages,
43
44            value_enum_map,
45            extended_type_map,
46
47            signal_layout_map: HashMap::new(),
48            message_layout_map: HashMap::new(),
49        }
50    }
51
52    fn build(&mut self) {
53        for msg in std::mem::take(&mut self.can_dbc_messages) {
54            if msg.name == "VECTOR__INDEPENDENT_SIG_MSG" {
55                continue;
56            }
57
58            self.build_message(msg);
59        }
60    }
61
62    fn build_message(&mut self, msg: ParsedMessage) {
63        let ParsedMessage { id, name, size, transmitter, signals, .. } = msg;
64
65        let mut signal_idxs = Vec::new();
66        let mut signal_layout_idxs = Vec::new();
67
68        for sig in signals {
69            let (sig_idx, layout_idx) = self.build_signal(id, sig);
70
71            signal_idxs.push(sig_idx);
72            signal_layout_idxs.push(layout_idx);
73        }
74
75        let layout_idx = self.build_message_layout(signal_layout_idxs);
76
77        let message = Message::from_parsed(
78            id,
79            name,
80            size,
81            transmitter,
82            signal_idxs,
83            layout_idx,
84        );
85
86        self.file.messages.push(message);
87    }
88
89    fn build_message_layout(
90        &mut self,
91        signal_layout_idxs: Vec<SignalLayoutIdx>,
92    ) -> MessageLayoutIdx {
93        let layout = MessageLayout {
94            signal_layouts: signal_layout_idxs,
95        };
96
97        if let Some(idx) = self.message_layout_map.get(&layout) {
98            return *idx;
99        }
100
101        let idx = MessageLayoutIdx(self.file.message_layouts.len());
102
103        self.file.message_layouts.push(layout.clone());
104        self.message_layout_map.insert(layout, idx);
105
106        idx
107    }
108
109    fn build_signal(
110        &mut self,
111        message_id: can_dbc::MessageId,
112        parsed_sig: ParsedSignal,
113    ) -> (SignalIdx, SignalLayoutIdx) {
114
115        let key = (message_id, parsed_sig.name.clone());
116
117        let layout_idx = self.build_signal_layout(&parsed_sig);
118
119        let mut signal = Signal::from(parsed_sig);
120        signal.layout = layout_idx;
121
122        if let Some(enum_val) = self.value_enum_map.remove(&key) {
123            signal.signal_value_enum = Some(enum_val);
124        }
125
126        if let Some(ext) = self.extended_type_map.remove(&key) {
127            signal.extended_type = ext;
128        }
129
130        let idx = SignalIdx(self.file.signals.len());
131        self.file.signals.push(signal);
132
133        (idx, layout_idx)
134    }
135
136    fn build_signal_layout(&mut self, sig: &ParsedSignal) -> SignalLayoutIdx {
137        let layout = SignalLayout::from(sig);
138
139        if let Some(idx) = self.signal_layout_map.get(&layout) {
140            return *idx;
141        }
142
143        let idx = SignalLayoutIdx(self.file.signal_layouts.len());
144
145        self.file.signal_layouts.push(layout);
146        self.signal_layout_map.insert(layout, idx);
147
148        idx
149    }
150
151    fn value_enum_map(value_descriptions: Vec<ParsedValueDescription>) -> HashMap<SignalKey, SignalValueEnum> {
152        let mut value_enum_map: HashMap<SignalKey, SignalValueEnum> = HashMap::new();
153
154        for value_enum in value_descriptions {
155            if let ParsedValueDescription::Signal {
156                message_id,
157                name,
158                value_descriptions,
159            } = value_enum
160            {
161                let sve = SignalValueEnum::from_parsed( value_descriptions);
162                value_enum_map.insert((message_id, name), sve);
163            }
164        }
165
166        value_enum_map
167    }
168
169    fn extended_type_map(extended_types: Vec<ParsedExtendedValueType>) -> HashMap<SignalKey, ExtendedValueType> {
170        let mut extended_type_map: HashMap<SignalKey, ExtendedValueType> = HashMap::new();
171
172        for ext in extended_types {
173            let ir_ext_type = ExtendedValueType::from(ext.signal_extended_value_type);
174
175            let ParsedExtendedValueType { message_id, signal_name, ..} = ext;
176            extended_type_map.insert((message_id, signal_name),ir_ext_type);
177        }
178
179        extended_type_map
180    }
181}