autosar_data_abstraction/system/
mapping.rs1use crate::{
2 AbstractionElement, AutosarAbstractionError, EcuInstance, Element, IdentifiableAbstractionElement, System,
3 abstraction_element, communication, software_component,
4};
5use autosar_data::ElementName;
6use communication::SystemSignal;
7use software_component::{
8 AbstractSwComponentType, ComponentPrototype, PortInterface, PortPrototype, RootSwCompositionPrototype,
9 SwComponentPrototype, VariableDataPrototype,
10};
11
12#[derive(Debug, Clone, PartialEq, Eq, Hash)]
18pub struct SystemMapping(Element);
19abstraction_element!(SystemMapping, SystemMapping);
20impl IdentifiableAbstractionElement for SystemMapping {}
21
22impl SystemMapping {
23 pub(crate) fn new(name: &str, system: &System) -> Result<Self, AutosarAbstractionError> {
24 let element = system
25 .element()
26 .get_or_create_sub_element(ElementName::Mappings)?
27 .create_named_sub_element(ElementName::SystemMapping, name)?;
28
29 Ok(Self(element))
30 }
31
32 pub fn system(&self) -> Result<System, AutosarAbstractionError> {
34 let sys_elem = self.element().named_parent()?.unwrap();
35 System::try_from(sys_elem)
36 }
37
38 pub fn map_swc_to_ecu(
40 &self,
41 name: &str,
42 component_prototype: &SwComponentPrototype,
43 ecu: &EcuInstance,
44 ) -> Result<SwcToEcuMapping, AutosarAbstractionError> {
45 let root_composition_prototype =
46 self.system()?
47 .root_sw_composition()
48 .ok_or(AutosarAbstractionError::InvalidParameter(
49 "The root compositon must be set before mapping any swc".to_string(),
50 ))?;
51 let root_composition_type =
52 root_composition_prototype
53 .composition()
54 .ok_or(AutosarAbstractionError::InvalidParameter(
55 "Incomplete root composition prototype".to_string(),
56 ))?;
57
58 let mut context_composition_prototypes = vec![];
59 let mut current_composition = component_prototype.parent_composition()?;
60
61 if root_composition_type != current_composition && !root_composition_type.is_parent_of(¤t_composition) {
63 return Err(AutosarAbstractionError::InvalidParameter(
64 "The composition is not a child of the root composition".to_string(),
65 ));
66 }
67
68 while current_composition != root_composition_type {
70 for comp_proto in current_composition.instances() {
72 if let Ok(Some(comp_type)) = comp_proto.parent_composition() {
75 if root_composition_type == comp_type || root_composition_type.is_parent_of(&comp_type) {
76 context_composition_prototypes.push(comp_proto.clone());
77 current_composition = comp_type;
78 break;
79 }
80 }
81 }
82 }
83
84 context_composition_prototypes.reverse();
86
87 SwcToEcuMapping::new(
88 name,
89 component_prototype,
90 &context_composition_prototypes,
91 &root_composition_prototype,
92 ecu,
93 self,
94 )
95 }
96
97 pub fn map_sender_receiver_to_signal<T: Into<PortPrototype> + Clone>(
111 &self,
112 signal: &SystemSignal,
113 data_element: &VariableDataPrototype,
114 port_prototype: &T,
115 context_components: &[&SwComponentPrototype],
116 root_composition_prototype: Option<&RootSwCompositionPrototype>,
117 ) -> Result<(), AutosarAbstractionError> {
118 self.map_sender_receiver_to_signal_internal(
119 signal,
120 data_element,
121 &port_prototype.clone().into(),
122 context_components,
123 root_composition_prototype,
124 )
125 }
126
127 fn map_sender_receiver_to_signal_internal(
128 &self,
129 signal: &SystemSignal,
130 data_element: &VariableDataPrototype,
131 port_prototype: &PortPrototype,
132 context_components: &[&SwComponentPrototype],
133 root_composition_prototype: Option<&RootSwCompositionPrototype>,
134 ) -> Result<(), AutosarAbstractionError> {
135 let PortInterface::SenderReceiverInterface(interface) = port_prototype.port_interface()? else {
138 return Err(AutosarAbstractionError::InvalidParameter(
139 "The port prototype must be a sender/receiver port".to_string(),
140 ));
141 };
142
143 if data_element.interface()? != interface {
145 return Err(AutosarAbstractionError::InvalidParameter(
146 "The data element must be part of the sender/receiver interface".to_string(),
147 ));
148 }
149
150 if let Some(swc_prototype) = context_components.last() {
152 let swc_type = port_prototype.component_type()?;
153 let swc_prototype_type =
154 swc_prototype
155 .component_type()
156 .ok_or(AutosarAbstractionError::InvalidParameter(
157 "invalid SWC prototype: component type ref is missing".to_string(),
158 ))?;
159 if swc_type != swc_prototype_type {
160 return Err(AutosarAbstractionError::InvalidParameter(
161 "The port must be part of the component prototype".to_string(),
162 ));
163 }
164 }
165
166 let data_mappings = self.element().get_or_create_sub_element(ElementName::DataMappings)?;
168 let sr_mapping = data_mappings.create_sub_element(ElementName::SenderReceiverToSignalMapping)?;
169
170 let iref = sr_mapping.create_sub_element(ElementName::DataElementIref)?;
171 iref.create_sub_element(ElementName::ContextPortRef)?
172 .set_reference_target(port_prototype.element())?;
173 iref.create_sub_element(ElementName::TargetDataPrototypeRef)?
174 .set_reference_target(data_element.element())?;
175
176 for comp_proto in context_components {
178 iref.create_sub_element(ElementName::ContextComponentRef)?
179 .set_reference_target(comp_proto.element())?;
180 }
181
182 if let Some(root_composition_prototype) = root_composition_prototype {
183 iref.create_sub_element(ElementName::ContextCompositionRef)?
184 .set_reference_target(root_composition_prototype.element())?;
185 }
186
187 sr_mapping
188 .create_sub_element(ElementName::SystemSignalRef)?
189 .set_reference_target(signal.element())?;
190
191 Ok(())
192 }
193}
194
195#[derive(Debug, Clone, PartialEq, Eq, Hash)]
199pub struct SwcToEcuMapping(Element);
200abstraction_element!(SwcToEcuMapping, SwcToEcuMapping);
201impl IdentifiableAbstractionElement for SwcToEcuMapping {}
202
203impl SwcToEcuMapping {
204 pub(crate) fn new(
205 name: &str,
206 component_prototype: &SwComponentPrototype,
207 context_composition_prototypes: &[ComponentPrototype],
208 root_composition_prototype: &RootSwCompositionPrototype,
209 ecu: &EcuInstance,
210 mapping: &SystemMapping,
211 ) -> Result<Self, AutosarAbstractionError> {
212 let sw_mappings_elem = mapping.element().get_or_create_sub_element(ElementName::SwMappings)?;
213 let swc_to_ecu_mapping = sw_mappings_elem.create_named_sub_element(ElementName::SwcToEcuMapping, name)?;
214
215 let iref = swc_to_ecu_mapping
216 .create_sub_element(ElementName::ComponentIrefs)?
217 .create_sub_element(ElementName::ComponentIref)?;
218
219 iref.create_sub_element(ElementName::ContextCompositionRef)?
221 .set_reference_target(root_composition_prototype.element())?;
222 for context_comp in context_composition_prototypes {
223 iref.create_sub_element(ElementName::ContextComponentRef)?
224 .set_reference_target(context_comp.element())?;
225 }
226 iref.create_sub_element(ElementName::TargetComponentRef)?
228 .set_reference_target(component_prototype.element())?;
229
230 swc_to_ecu_mapping
231 .create_sub_element(ElementName::EcuInstanceRef)?
232 .set_reference_target(ecu.element())?;
233
234 Ok(Self(swc_to_ecu_mapping))
235 }
236
237 #[must_use]
239 pub fn target_component(&self) -> Option<SwComponentPrototype> {
240 self.element()
241 .get_sub_element(ElementName::ComponentIrefs)
242 .and_then(|irefs| irefs.get_sub_element(ElementName::ComponentIref))
243 .and_then(|iref| iref.get_sub_element(ElementName::TargetComponentRef))
244 .and_then(|target| target.get_reference_target().ok())
245 .and_then(|target| SwComponentPrototype::try_from(target).ok())
246 }
247
248 #[must_use]
250 pub fn ecu_instance(&self) -> Option<EcuInstance> {
251 self.element()
252 .get_sub_element(ElementName::EcuInstanceRef)
253 .and_then(|r| r.get_reference_target().ok())
254 .and_then(|target| EcuInstance::try_from(target).ok())
255 }
256}
257
258#[cfg(test)]
261mod test {
262 use super::*;
263 use crate::{
264 AutosarModelAbstraction, SystemCategory,
265 datatype::{ApplicationPrimitiveCategory, ApplicationPrimitiveDataType},
266 };
267
268 #[test]
269 fn mappings() {
270 let model = AutosarModelAbstraction::create("filename", autosar_data::AutosarVersion::LATEST);
271 let package = model.get_or_create_package("/package").unwrap();
272 let system = package
273 .create_system("test_system", SystemCategory::EcuExtract)
274 .unwrap();
275 let mapping = system.get_or_create_mapping("test_mapping").unwrap();
276
277 let ecu = system.create_ecu_instance("test_ecu", &package).unwrap();
278 let root_composition_type = package.create_composition_sw_component_type("test_swc").unwrap();
279 let _root_composition = system
280 .set_root_sw_composition("test_root_composition", &root_composition_type)
281 .unwrap();
282
283 let ecu_composition_type = package
284 .create_composition_sw_component_type("Ecu_A_Composition")
285 .unwrap();
286 let ecu_composition_prototype = root_composition_type
287 .create_component("Ecu_A_Composition_Prototype", &ecu_composition_type)
288 .unwrap();
289
290 let swc_to_ecu = mapping
292 .map_swc_to_ecu("test_swc_to_ecu", &ecu_composition_prototype, &ecu)
293 .unwrap();
294
295 assert_eq!(swc_to_ecu.target_component().unwrap(), ecu_composition_prototype);
296 assert_eq!(swc_to_ecu.ecu_instance().unwrap(), ecu);
297
298 let sys_signal = package.create_system_signal("test_signal").unwrap();
300
301 let sender_receiver_interface = package
302 .create_sender_receiver_interface("SenderReceiverInterface")
303 .unwrap();
304 let data_type = ApplicationPrimitiveDataType::new(
305 "Primitive",
306 &package,
307 ApplicationPrimitiveCategory::Value,
308 None,
309 None,
310 None,
311 )
312 .unwrap();
313 let data_element = sender_receiver_interface
314 .create_data_element("element", &data_type)
315 .unwrap();
316 let sr_port = ecu_composition_type
317 .create_r_port("test_port", &sender_receiver_interface)
318 .unwrap();
319
320 mapping
321 .map_sender_receiver_to_signal(&sys_signal, &data_element, &sr_port, &[], None)
322 .unwrap();
323 }
324}