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 && (root_composition_type == comp_type || root_composition_type.is_parent_of(&comp_type))
76 {
77 context_composition_prototypes.push(comp_proto.clone());
78 current_composition = comp_type;
79 break;
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<SenderReceiverToSignalMapping, 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<SenderReceiverToSignalMapping, AutosarAbstractionError> {
135 let Some(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
169 SenderReceiverToSignalMapping::new(
170 &data_mappings,
171 signal,
172 data_element,
173 port_prototype,
174 context_components,
175 root_composition_prototype,
176 )
177 }
178}
179
180#[derive(Debug, Clone, PartialEq, Eq, Hash)]
184pub struct SwcToEcuMapping(Element);
185abstraction_element!(SwcToEcuMapping, SwcToEcuMapping);
186impl IdentifiableAbstractionElement for SwcToEcuMapping {}
187
188impl SwcToEcuMapping {
189 pub(crate) fn new(
190 name: &str,
191 component_prototype: &SwComponentPrototype,
192 context_composition_prototypes: &[ComponentPrototype],
193 root_composition_prototype: &RootSwCompositionPrototype,
194 ecu: &EcuInstance,
195 mapping: &SystemMapping,
196 ) -> Result<Self, AutosarAbstractionError> {
197 let sw_mappings_elem = mapping.element().get_or_create_sub_element(ElementName::SwMappings)?;
198 let swc_to_ecu_mapping = sw_mappings_elem.create_named_sub_element(ElementName::SwcToEcuMapping, name)?;
199
200 let iref = swc_to_ecu_mapping
201 .create_sub_element(ElementName::ComponentIrefs)?
202 .create_sub_element(ElementName::ComponentIref)?;
203
204 iref.create_sub_element(ElementName::ContextCompositionRef)?
206 .set_reference_target(root_composition_prototype.element())?;
207 for context_comp in context_composition_prototypes {
208 iref.create_sub_element(ElementName::ContextComponentRef)?
209 .set_reference_target(context_comp.element())?;
210 }
211 iref.create_sub_element(ElementName::TargetComponentRef)?
213 .set_reference_target(component_prototype.element())?;
214
215 swc_to_ecu_mapping
216 .create_sub_element(ElementName::EcuInstanceRef)?
217 .set_reference_target(ecu.element())?;
218
219 Ok(Self(swc_to_ecu_mapping))
220 }
221
222 #[must_use]
224 pub fn target_component(&self) -> Option<SwComponentPrototype> {
225 self.element()
226 .get_sub_element(ElementName::ComponentIrefs)
227 .and_then(|irefs| irefs.get_sub_element(ElementName::ComponentIref))
228 .and_then(|iref| iref.get_sub_element(ElementName::TargetComponentRef))
229 .and_then(|target| target.get_reference_target().ok())
230 .and_then(|target| SwComponentPrototype::try_from(target).ok())
231 }
232
233 #[must_use]
235 pub fn ecu_instance(&self) -> Option<EcuInstance> {
236 self.element()
237 .get_sub_element(ElementName::EcuInstanceRef)
238 .and_then(|r| r.get_reference_target().ok())
239 .and_then(|target| EcuInstance::try_from(target).ok())
240 }
241}
242
243#[derive(Debug, Clone, PartialEq, Eq, Hash)]
247pub struct SenderReceiverToSignalMapping(Element);
248abstraction_element!(SenderReceiverToSignalMapping, SenderReceiverToSignalMapping);
249
250impl SenderReceiverToSignalMapping {
251 pub(crate) fn new(
252 parent: &Element,
253 signal: &SystemSignal,
254 data_element: &VariableDataPrototype,
255 port_prototype: &PortPrototype,
256 context_components: &[&SwComponentPrototype],
257 root_composition_prototype: Option<&RootSwCompositionPrototype>,
258 ) -> Result<Self, AutosarAbstractionError> {
259 let sr_mapping = parent.create_sub_element(ElementName::SenderReceiverToSignalMapping)?;
260 let iref = sr_mapping.create_sub_element(ElementName::DataElementIref)?;
261 iref.create_sub_element(ElementName::ContextPortRef)?
262 .set_reference_target(port_prototype.element())?;
263 iref.create_sub_element(ElementName::TargetDataPrototypeRef)?
264 .set_reference_target(data_element.element())?;
265
266 for comp_proto in context_components {
268 iref.create_sub_element(ElementName::ContextComponentRef)?
269 .set_reference_target(comp_proto.element())?;
270 }
271
272 if let Some(root_composition_prototype) = root_composition_prototype {
273 iref.create_sub_element(ElementName::ContextCompositionRef)?
274 .set_reference_target(root_composition_prototype.element())?;
275 }
276
277 sr_mapping
278 .create_sub_element(ElementName::SystemSignalRef)?
279 .set_reference_target(signal.element())?;
280
281 Ok(Self(sr_mapping))
282 }
283
284 #[must_use]
286 pub fn system_signal(&self) -> Option<SystemSignal> {
287 let element = self
288 .element()
289 .get_sub_element(ElementName::SystemSignalRef)
290 .and_then(|r| r.get_reference_target().ok())?;
291 SystemSignal::try_from(element).ok()
292 }
293
294 #[must_use]
296 pub fn data_element(&self) -> Option<VariableDataPrototype> {
297 let element = self
298 .element()
299 .get_sub_element(ElementName::DataElementIref)
300 .and_then(|iref| iref.get_sub_element(ElementName::TargetDataPrototypeRef))
301 .and_then(|r| r.get_reference_target().ok())?;
302 VariableDataPrototype::try_from(element).ok()
303 }
304}
305
306#[cfg(test)]
309mod test {
310 use super::*;
311 use crate::{
312 AutosarModelAbstraction, SystemCategory,
313 datatype::{ApplicationPrimitiveCategory, ApplicationPrimitiveDataType},
314 };
315
316 #[test]
317 fn mappings() {
318 let model = AutosarModelAbstraction::create("filename", autosar_data::AutosarVersion::LATEST);
319 let package = model.get_or_create_package("/package").unwrap();
320 let system = package
321 .create_system("test_system", SystemCategory::EcuExtract)
322 .unwrap();
323 let mapping = system.get_or_create_mapping("test_mapping").unwrap();
324
325 let ecu = system.create_ecu_instance("test_ecu", &package).unwrap();
326 let root_composition_type = package.create_composition_sw_component_type("test_swc").unwrap();
327 let _root_composition = system
328 .set_root_sw_composition("test_root_composition", &root_composition_type)
329 .unwrap();
330
331 let ecu_composition_type = package
332 .create_composition_sw_component_type("Ecu_A_Composition")
333 .unwrap();
334 let ecu_composition_prototype = root_composition_type
335 .create_component("Ecu_A_Composition_Prototype", &ecu_composition_type)
336 .unwrap();
337
338 let swc_to_ecu = mapping
340 .map_swc_to_ecu("test_swc_to_ecu", &ecu_composition_prototype, &ecu)
341 .unwrap();
342
343 assert_eq!(swc_to_ecu.target_component().unwrap(), ecu_composition_prototype);
344 assert_eq!(swc_to_ecu.ecu_instance().unwrap(), ecu);
345
346 let sys_signal = package.create_system_signal("test_signal").unwrap();
348
349 let sender_receiver_interface = package
350 .create_sender_receiver_interface("SenderReceiverInterface")
351 .unwrap();
352 let data_type = ApplicationPrimitiveDataType::new(
353 "Primitive",
354 &package,
355 ApplicationPrimitiveCategory::Value,
356 None,
357 None,
358 None,
359 )
360 .unwrap();
361 let data_element = sender_receiver_interface
362 .create_data_element("element", &data_type)
363 .unwrap();
364 let sr_port = ecu_composition_type
365 .create_r_port("test_port", &sender_receiver_interface)
366 .unwrap();
367
368 mapping
369 .map_sender_receiver_to_signal(&sys_signal, &data_element, &sr_port, &[], None)
370 .unwrap();
371 }
372}