autosar_data_abstraction/system/
mod.rs

1use crate::communication::{
2    CanCluster, CanFrame, CanTpConfig, Cluster, ContainerIPdu, ContainerIPduHeaderType, DcmIPdu, DoIpTpConfig,
3    EthernetCluster, EventGroupControlType, FlexrayArTpConfig, FlexrayCluster, FlexrayClusterSettings, FlexrayFrame,
4    FlexrayTpConfig, Frame, GeneralPurposeIPdu, GeneralPurposeIPduCategory, GeneralPurposePdu,
5    GeneralPurposePduCategory, ISignal, ISignalGroup, ISignalIPdu, MultiplexedIPdu, NPdu, NmConfig, NmPdu, Pdu,
6    RxAcceptContainedIPdu, SecureCommunicationProps, SecuredIPdu, ServiceInstanceCollectionSet, SoAdRoutingGroup,
7    SocketConnectionIpduIdentifierSet, SomeipTpConfig, SystemSignal, SystemSignalGroup,
8};
9use crate::datatype::SwBaseType;
10use crate::software_component::{CompositionSwComponentType, RootSwCompositionPrototype};
11use crate::{
12    AbstractionElement, ArPackage, AutosarAbstractionError, EcuInstance, IdentifiableAbstractionElement,
13    abstraction_element,
14};
15use autosar_data::{AutosarModel, Element, ElementName, WeakElement};
16use std::iter::FusedIterator;
17
18mod mapping;
19
20pub use mapping::*;
21
22/// The System is the top level of a system template
23///
24/// It defines how ECUs communicate with each other over various networks.
25/// It also contains the mapping of software components to ECUs.
26#[derive(Debug, Clone, PartialEq, Eq, Hash)]
27pub struct System(Element);
28abstraction_element!(System, System);
29impl IdentifiableAbstractionElement for System {}
30
31impl System {
32    // find an existing \<SYSTEM\> in the model, if it exists
33    #[must_use]
34    pub(crate) fn find(model: &AutosarModel) -> Option<Self> {
35        let elem = model
36            .identifiable_elements()
37            .filter_map(|(_, weak)| weak.upgrade())
38            .find(|elem| elem.element_name() == ElementName::System)?;
39        Some(Self(elem))
40    }
41
42    /// Create a new SYSTEM in the given AR-PACKAGE
43    ///
44    /// Note that an Autosar model should ony contain one SYSTEM. This is not checked here.
45    ///
46    /// Use [`ArPackage::create_system`] to create a new system.
47    ///
48    /// # Example
49    ///
50    /// ```
51    /// # use autosar_data::*;
52    /// # use autosar_data_abstraction::*;
53    /// # fn main() -> Result<(), AutosarAbstractionError> {
54    /// # let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
55    /// let package = model.get_or_create_package("/my/pkg")?;
56    /// let system = package.create_system("System", SystemCategory::SystemExtract)?;
57    /// assert!(model.get_element_by_path("/my/pkg/System").is_some());
58    /// # Ok(())}
59    /// ```
60    ///
61    /// # Errors
62    ///
63    /// - [`AutosarAbstractionError::ModelError`] An error occurred in the Autosar model while trying to create the SYSTEM element
64    pub(crate) fn new(
65        name: &str,
66        package: &ArPackage,
67        category: SystemCategory,
68    ) -> Result<Self, AutosarAbstractionError> {
69        let pkg_elem_elements = package.element().get_or_create_sub_element(ElementName::Elements)?;
70
71        let system_elem = pkg_elem_elements.create_named_sub_element(ElementName::System, name)?;
72        let system = System(system_elem);
73        system.set_category(category)?;
74
75        Ok(system)
76    }
77
78    /// set the category of the system
79    pub fn set_category(&self, category: SystemCategory) -> Result<(), AutosarAbstractionError> {
80        self.0
81            .get_or_create_sub_element(ElementName::Category)?
82            .set_character_data(category.to_string())?;
83        Ok(())
84    }
85
86    /// get the category of the system
87    #[must_use]
88    pub fn category(&self) -> Option<SystemCategory> {
89        self.0
90            .get_sub_element(ElementName::Category)?
91            .character_data()?
92            .string_value()?
93            .parse()
94            .ok()
95    }
96
97    /// set the pncVectorLength of the system
98    pub fn set_pnc_vector_length(&self, length: Option<u32>) -> Result<(), AutosarAbstractionError> {
99        if let Some(length) = length {
100            self.0
101                .get_or_create_sub_element(ElementName::PncVectorLength)?
102                .set_character_data(length as u64)?;
103        } else {
104            let _ = self.0.remove_sub_element_kind(ElementName::PncVectorLength);
105        }
106        Ok(())
107    }
108
109    /// get the pncVectorLength of the system
110    #[must_use]
111    pub fn pnc_vector_length(&self) -> Option<u32> {
112        self.0
113            .get_sub_element(ElementName::PncVectorLength)?
114            .character_data()?
115            .parse_integer()
116    }
117
118    /// set the pncVectorOffset of the system
119    pub fn set_pnc_vector_offset(&self, offset: Option<u32>) -> Result<(), AutosarAbstractionError> {
120        if let Some(offset) = offset {
121            self.0
122                .get_or_create_sub_element(ElementName::PncVectorOffset)?
123                .set_character_data(offset as u64)?;
124        } else {
125            let _ = self.0.remove_sub_element_kind(ElementName::PncVectorOffset);
126        }
127        Ok(())
128    }
129
130    /// get the pncVectorOffset of the system
131    #[must_use]
132    pub fn pnc_vector_offset(&self) -> Option<u32> {
133        self.0
134            .get_sub_element(ElementName::PncVectorOffset)?
135            .character_data()?
136            .parse_integer()
137    }
138
139    /// create an `EcuInstance` that is connected to this System
140    ///
141    /// # Example
142    ///
143    /// ```
144    /// # use autosar_data::*;
145    /// # use autosar_data_abstraction::*;
146    /// # fn main() -> Result<(), AutosarAbstractionError> {
147    /// # let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
148    /// # let package1 = model.get_or_create_package("/pkg1")?;
149    /// let system = package1.create_system("System", SystemCategory::SystemExtract)?;
150    /// # let package2 = model.get_or_create_package("/pkg2")?;
151    /// let ecu_instance = system.create_ecu_instance("ecu_name", &package2)?;
152    /// # Ok(())}
153    /// ```
154    ///
155    /// # Errors
156    ///
157    /// - [`AutosarAbstractionError::ModelError`] An error occurred in the Autosar model while trying to create the ECU-INSTANCE
158    pub fn create_ecu_instance(&self, name: &str, package: &ArPackage) -> Result<EcuInstance, AutosarAbstractionError> {
159        let ecu_instance = EcuInstance::new(name, package)?;
160        self.create_fibex_element_ref_unchecked(ecu_instance.element())?;
161
162        Ok(ecu_instance)
163    }
164
165    /// get an iterator over all ECU-INSTANCEs in this SYSTEM
166    ///
167    /// # Example
168    ///
169    /// ```
170    /// # use autosar_data::*;
171    /// # use autosar_data_abstraction::*;
172    /// # fn main() -> Result<(), AutosarAbstractionError> {
173    /// # let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
174    /// # let package = model.get_or_create_package("/pkg1")?;
175    /// let system = package.create_system("System", SystemCategory::SystemExtract)?;
176    /// system.create_ecu_instance("ecu_name1", &package)?;
177    /// system.create_ecu_instance("ecu_name2", &package)?;
178    /// for ecu in system.ecu_instances() {
179    ///     // do something
180    /// }
181    /// assert_eq!(system.ecu_instances().count(), 2);
182    /// # Ok(())}
183    /// ```
184    pub fn ecu_instances(&self) -> impl Iterator<Item = EcuInstance> + Send + 'static {
185        EcuInstanceIterator::new(self)
186    }
187
188    /// create a new CAN-CLUSTER
189    ///
190    /// The cluster must have a channel to be valid, but this channel is not created automatically.
191    /// Call [`CanCluster::create_physical_channel`] to create it.
192    ///
193    /// # Example
194    ///
195    /// ```
196    /// # use autosar_data::*;
197    /// # use autosar_data_abstraction::*;
198    /// # use autosar_data_abstraction::communication::*;
199    /// # fn main() -> Result<(), AutosarAbstractionError> {
200    /// # let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
201    /// # let package = model.get_or_create_package("/pkg1")?;
202    /// let system = package.create_system("System", SystemCategory::SystemExtract)?;
203    /// let cluster = system.create_can_cluster("can_cluster", &package, None)?;
204    /// cluster.create_physical_channel("can_channel");
205    /// # Ok(())}
206    /// ```
207    ///
208    /// # Errors
209    ///
210    /// - [`AutosarAbstractionError::ModelError`] An error occurred in the Autosar model while trying to create the can cluster
211    pub fn create_can_cluster(
212        &self,
213        cluster_name: &str,
214        package: &ArPackage,
215        can_baudrate: Option<u32>,
216    ) -> Result<CanCluster, AutosarAbstractionError> {
217        let cluster = CanCluster::new(cluster_name, package, can_baudrate)?;
218        self.create_fibex_element_ref_unchecked(cluster.element())?;
219
220        Ok(cluster)
221    }
222
223    /// create a new ETHERNET-CLUSTER and connect it to the SYSTEM
224    ///
225    /// The cluster must have at least one channel to be valid.
226    /// Call [`EthernetCluster::create_physical_channel`] to create it.
227    ///
228    /// # Example
229    ///
230    /// ```
231    /// # use autosar_data::*;
232    /// # use autosar_data_abstraction::*;
233    /// # use autosar_data_abstraction::communication::*;
234    /// # fn main() -> Result<(), AutosarAbstractionError> {
235    /// # let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
236    /// # let package = model.get_or_create_package("/pkg1")?;
237    /// let system = package.create_system("System", SystemCategory::SystemExtract)?;
238    /// let cluster = system.create_ethernet_cluster("ethernet_cluster", &package)?;
239    /// let vlan_info = EthernetVlanInfo { vlan_name: "VLAN_1".to_string(), vlan_id: 1};
240    /// cluster.create_physical_channel("ethernet_channel", Some(&vlan_info));
241    /// # Ok(())}
242    /// ```
243    ///
244    /// # Errors
245    ///
246    /// - [`AutosarAbstractionError::ModelError`] An error occurred in the Autosar model while trying to create the ethernet cluster
247    pub fn create_ethernet_cluster(
248        &self,
249        cluster_name: &str,
250        package: &ArPackage,
251    ) -> Result<EthernetCluster, AutosarAbstractionError> {
252        let cluster = EthernetCluster::new(cluster_name, package)?;
253        self.create_fibex_element_ref_unchecked(cluster.element())?;
254
255        Ok(cluster)
256    }
257
258    /// create a new FLEXRAY-CLUSTER and connect it to the SYSTEM
259    ///
260    /// A `FlexrayClusterSettings` structure containing the timings and parameters for the Flexray cluster must be provided.
261    ///
262    /// The cluster must have at least one channel to be valid.
263    /// Call [`FlexrayCluster::create_physical_channel`] to create it.
264    ///
265    /// # Example
266    ///
267    /// ```
268    /// # use autosar_data::*;
269    /// # use autosar_data_abstraction::*;
270    /// # use autosar_data_abstraction::communication::*;
271    /// # fn main() -> Result<(), AutosarAbstractionError> {
272    /// # let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
273    /// # let package = model.get_or_create_package("/pkg1")?;
274    /// let system = package.create_system("System", SystemCategory::SystemExtract)?;
275    /// let cluster = system.create_flexray_cluster("flexray_cluster", &package, &FlexrayClusterSettings::default())?;
276    /// cluster.create_physical_channel("flexray_channel", FlexrayChannelName::A);
277    /// # Ok(())}
278    /// ```
279    ///
280    /// # Errors
281    ///
282    /// - [`AutosarAbstractionError::ModelError`] An error occurred in the Autosar model while trying to create the flexray cluster
283    pub fn create_flexray_cluster(
284        &self,
285        cluster_name: &str,
286        package: &ArPackage,
287        settings: &FlexrayClusterSettings,
288    ) -> Result<FlexrayCluster, AutosarAbstractionError> {
289        let cluster = FlexrayCluster::new(cluster_name, package, settings)?;
290        self.create_fibex_element_ref_unchecked(cluster.element())?;
291
292        Ok(cluster)
293    }
294
295    /// Create an iterator over all clusters connected to the SYSTEM
296    ///
297    /// # Example
298    ///
299    /// ```
300    /// # use autosar_data::*;
301    /// # use autosar_data_abstraction::*;
302    /// # use autosar_data_abstraction::communication::*;
303    /// # fn main() -> Result<(), AutosarAbstractionError> {
304    /// # let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
305    /// # let package = model.get_or_create_package("/pkg1")?;
306    /// let system = package.create_system("System", SystemCategory::SystemExtract)?;
307    /// system.create_can_cluster("can_cluster", &package, None)?;
308    /// system.create_flexray_cluster("flexray_cluster", &package, &FlexrayClusterSettings::default())?;
309    /// for cluster in system.clusters() {
310    ///     // do something
311    /// }
312    /// assert_eq!(system.clusters().count(), 2);
313    /// # Ok(())}
314    /// ```
315    pub fn clusters(&self) -> impl Iterator<Item = Cluster> + Send + 'static {
316        self.0
317            .get_sub_element(ElementName::FibexElements)
318            .into_iter()
319            .flat_map(|fibexelems| fibexelems.sub_elements())
320            .filter_map(|ferc| {
321                ferc.get_sub_element(ElementName::FibexElementRef)
322                    .and_then(|fer| fer.get_reference_target().ok())
323                    .and_then(|elem| Cluster::try_from(elem).ok())
324            })
325    }
326
327    /// create a new [`CanFrame`]
328    ///
329    /// This new frame needs to be linked to a `CanPhysicalChannel`
330    pub fn create_can_frame(
331        &self,
332        name: &str,
333        package: &ArPackage,
334        byte_length: u64,
335    ) -> Result<CanFrame, AutosarAbstractionError> {
336        let can_frame = CanFrame::new(name, package, byte_length)?;
337        self.create_fibex_element_ref_unchecked(can_frame.element())?;
338
339        Ok(can_frame)
340    }
341
342    /// create a new [`FlexrayFrame`]
343    ///
344    /// This new frame needs to be linked to a `FlexrayPhysicalChannel`
345    pub fn create_flexray_frame(
346        &self,
347        name: &str,
348        package: &ArPackage,
349        byte_length: u64,
350    ) -> Result<FlexrayFrame, AutosarAbstractionError> {
351        let flexray_frame = FlexrayFrame::new(name, package, byte_length)?;
352        self.create_fibex_element_ref_unchecked(flexray_frame.element())?;
353
354        Ok(flexray_frame)
355    }
356
357    /// iterate over all Frames in the System
358    ///
359    /// This iterator returns all CAN and Flexray frames that are connected to the System using a `FibexElementRef`.
360    pub fn frames(&self) -> impl Iterator<Item = Frame> + Send + 'static {
361        self.0
362            .get_sub_element(ElementName::FibexElements)
363            .into_iter()
364            .flat_map(|fibexelems| fibexelems.sub_elements())
365            .filter_map(|ferc| {
366                ferc.get_sub_element(ElementName::FibexElementRef)
367                    .and_then(|fer| fer.get_reference_target().ok())
368                    .and_then(|elem| Frame::try_from(elem).ok())
369            })
370    }
371
372    /// create a new isignal in the [`System`]
373    ///
374    /// # Example
375    ///
376    /// ```
377    /// # use autosar_data::*;
378    /// # use autosar_data_abstraction::*;
379    /// # use autosar_data_abstraction::communication::*;
380    /// # fn main() -> Result<(), AutosarAbstractionError> {
381    /// # let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
382    /// # let package = model.get_or_create_package("/pkg1")?;
383    /// # let system = package.create_system("System", SystemCategory::SystemExtract)?;
384    /// let sig_package = model.get_or_create_package("/ISignals")?;
385    /// let sys_package = model.get_or_create_package("/SystemSignals")?;
386    /// let system_signal = sys_package.create_system_signal("signal1")?;
387    /// system.create_isignal("signal1", &sig_package, 32, &system_signal, None)?;
388    /// # Ok(())}
389    /// ```
390    ///
391    /// # Errors
392    ///
393    /// - [`AutosarAbstractionError::InvalidParameter`] `sig_package` and `sys_package` may not be identical
394    /// - [`AutosarAbstractionError::ModelError`] An error occurred in the Autosar model while trying to create elements
395    pub fn create_isignal(
396        &self,
397        name: &str,
398        package: &ArPackage,
399        bit_length: u64,
400        syssignal: &SystemSignal,
401        datatype: Option<&SwBaseType>,
402    ) -> Result<ISignal, AutosarAbstractionError> {
403        let i_signal = ISignal::new(name, package, bit_length, syssignal, datatype)?;
404
405        self.create_fibex_element_ref_unchecked(i_signal.element())?;
406
407        Ok(i_signal)
408    }
409
410    /// iterate over all `ISignals` in the System
411    ///
412    /// This iterator returns all `ISignals` that are connected to the System using a `FibexElementRef`.
413    pub fn isignals(&self) -> impl Iterator<Item = ISignal> + Send + 'static {
414        self.0
415            .get_sub_element(ElementName::FibexElements)
416            .into_iter()
417            .flat_map(|fibexelems| fibexelems.sub_elements())
418            .filter_map(|ferc| {
419                ferc.get_sub_element(ElementName::FibexElementRef)
420                    .and_then(|fer| fer.get_reference_target().ok())
421                    .and_then(|elem| ISignal::try_from(elem).ok())
422            })
423    }
424
425    /// create a new signal group in the [`System`]
426    ///
427    /// `I-SIGNAL-GROUP` and `SYSTEM-SIGNAL-GROUP` are created using the same name; therefore they must be placed in
428    /// different packages: `sig_package` and `sys_package` may not be identical.
429    ///
430    /// # Example
431    ///
432    /// ```
433    /// # use autosar_data::*;
434    /// # use autosar_data_abstraction::*;
435    /// # use autosar_data_abstraction::communication::*;
436    /// # fn main() -> Result<(), AutosarAbstractionError> {
437    /// # let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
438    /// # let package = model.get_or_create_package("/pkg1")?;
439    /// # let system = package.create_system("System", SystemCategory::SystemExtract)?;
440    /// let sig_package = model.get_or_create_package("/ISignals")?;
441    /// let sys_package = model.get_or_create_package("/SystemSignals")?;
442    /// let system_signal_group = sys_package.create_system_signal_group("signalgroup")?;
443    /// system.create_isignal_group("signal_group", &sig_package, &system_signal_group)?;
444    /// # Ok(())}
445    /// ```
446    ///
447    /// # Errors
448    ///
449    /// - [`AutosarAbstractionError::InvalidParameter`] `sig_package` and `sys_package` may not be identical
450    /// - [`AutosarAbstractionError::ModelError`] An error occurred in the Autosar model while trying to create elements
451    pub fn create_isignal_group(
452        &self,
453        name: &str,
454        package: &ArPackage,
455        system_signal_group: &SystemSignalGroup,
456    ) -> Result<ISignalGroup, AutosarAbstractionError> {
457        let i_signal_group = ISignalGroup::new(name, package, system_signal_group)?;
458
459        self.create_fibex_element_ref_unchecked(i_signal_group.element())?;
460
461        Ok(i_signal_group)
462    }
463
464    /// iterate over all `ISignalGroups` in the System
465    ///
466    /// This iterator returns all `ISignalGroups` that are connected to the System using a `FibexElementRef`.
467    pub fn isignal_groups(&self) -> impl Iterator<Item = ISignalGroup> + Send + 'static {
468        self.0
469            .get_sub_element(ElementName::FibexElements)
470            .into_iter()
471            .flat_map(|fibexelems| fibexelems.sub_elements())
472            .filter_map(|ferc| {
473                ferc.get_sub_element(ElementName::FibexElementRef)
474                    .and_then(|fer| fer.get_reference_target().ok())
475                    .and_then(|elem| ISignalGroup::try_from(elem).ok())
476            })
477    }
478
479    /// create an [`ISignalIPdu`] in the [`System`]
480    ///
481    /// # Example
482    ///
483    /// ```
484    /// # use autosar_data::*;
485    /// # use autosar_data_abstraction::*;
486    /// # use autosar_data_abstraction::communication::*;
487    /// # fn main() -> Result<(), AutosarAbstractionError> {
488    /// # let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
489    /// # let package = model.get_or_create_package("/pkg1")?;
490    /// # let system = package.create_system("System", SystemCategory::SystemExtract)?;
491    /// let package = model.get_or_create_package("/Pdus")?;
492    /// system.create_isignal_ipdu("pdu", &package, 42)?;
493    /// # Ok(())}
494    /// ```
495    ///
496    /// # Errors
497    ///
498    /// - [`AutosarAbstractionError::ModelError`] An error occurred in the Autosar model while trying to create elements
499    pub fn create_isignal_ipdu(
500        &self,
501        name: &str,
502        package: &ArPackage,
503        length: u32,
504    ) -> Result<ISignalIPdu, AutosarAbstractionError> {
505        let pdu = ISignalIPdu::new(name, package, length)?;
506        self.create_fibex_element_ref_unchecked(pdu.element())?;
507
508        Ok(pdu)
509    }
510
511    /// create an [`NmPdu`] in the [`System`]
512    ///
513    /// # Example
514    ///
515    /// ```
516    /// # use autosar_data::*;
517    /// # use autosar_data_abstraction::*;
518    /// # use autosar_data_abstraction::communication::*;
519    /// # fn main() -> Result<(), AutosarAbstractionError> {
520    /// # let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
521    /// # let package = model.get_or_create_package("/pkg1")?;
522    /// # let system = package.create_system("System", SystemCategory::SystemExtract)?;
523    /// let package = model.get_or_create_package("/Pdus")?;
524    /// system.create_nm_pdu("pdu", &package, 42)?;
525    /// # Ok(())}
526    /// ```
527    ///
528    /// # Errors
529    ///
530    /// - [`AutosarAbstractionError::ModelError`] An error occurred in the Autosar model while trying to create elements
531    pub fn create_nm_pdu(
532        &self,
533        name: &str,
534        package: &ArPackage,
535        length: u32,
536    ) -> Result<NmPdu, AutosarAbstractionError> {
537        let pdu = NmPdu::new(name, package, length)?;
538        self.create_fibex_element_ref_unchecked(pdu.element())?;
539
540        Ok(pdu)
541    }
542
543    /// create an [`NPdu`] in the [`System`]
544    ///
545    /// # Example
546    ///
547    /// ```
548    /// # use autosar_data::*;
549    /// # use autosar_data_abstraction::*;
550    /// # use autosar_data_abstraction::communication::*;
551    /// # fn main() -> Result<(), AutosarAbstractionError> {
552    /// # let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
553    /// # let package = model.get_or_create_package("/pkg1")?;
554    /// # let system = package.create_system("System", SystemCategory::SystemExtract)?;
555    /// let package = model.get_or_create_package("/Pdus")?;
556    /// system.create_n_pdu("pdu", &package, 42)?;
557    /// # Ok(())}
558    /// ```
559    ///
560    /// # Errors
561    ///
562    /// - [`AutosarAbstractionError::ModelError`] An error occurred in the Autosar model while trying to create elements
563    pub fn create_n_pdu(&self, name: &str, package: &ArPackage, length: u32) -> Result<NPdu, AutosarAbstractionError> {
564        let pdu = NPdu::new(name, package, length)?;
565        self.create_fibex_element_ref_unchecked(pdu.element())?;
566
567        Ok(pdu)
568    }
569
570    /// create a [`DcmIPdu`] in the [`System`]
571    ///
572    /// # Example
573    ///
574    /// ```
575    /// # use autosar_data::*;
576    /// # use autosar_data_abstraction::*;
577    /// # use autosar_data_abstraction::communication::*;
578    /// # fn main() -> Result<(), AutosarAbstractionError> {
579    /// # let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
580    /// # let package = model.get_or_create_package("/pkg1")?;
581    /// # let system = package.create_system("System", SystemCategory::SystemExtract)?;
582    /// let package = model.get_or_create_package("/Pdus")?;
583    /// system.create_dcm_ipdu("pdu", &package, 42)?;
584    /// # Ok(())}
585    /// ```
586    ///
587    /// # Errors
588    ///
589    /// - [`AutosarAbstractionError::ModelError`] An error occurred in the Autosar model while trying to create elements
590    pub fn create_dcm_ipdu(
591        &self,
592        name: &str,
593        package: &ArPackage,
594        length: u32,
595    ) -> Result<DcmIPdu, AutosarAbstractionError> {
596        let pdu = DcmIPdu::new(name, package, length)?;
597        self.create_fibex_element_ref_unchecked(pdu.element())?;
598
599        Ok(pdu)
600    }
601
602    /// create a [`GeneralPurposePdu`] in the [`System`]
603    ///
604    /// # Example
605    ///
606    /// ```
607    /// # use autosar_data::*;
608    /// # use autosar_data_abstraction::*;
609    /// # use autosar_data_abstraction::communication::*;
610    /// # fn main() -> Result<(), AutosarAbstractionError> {
611    /// # let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
612    /// # let package = model.get_or_create_package("/pkg1")?;
613    /// # let system = package.create_system("System", SystemCategory::SystemExtract)?;
614    /// let package = model.get_or_create_package("/Pdus")?;
615    /// system.create_general_purpose_pdu("pdu", &package, 42, GeneralPurposePduCategory::GlobalTime)?;
616    /// # Ok(())}
617    /// ```
618    ///
619    /// # Errors
620    ///
621    /// - [`AutosarAbstractionError::ModelError`] An error occurred in the Autosar model while trying to create elements
622    pub fn create_general_purpose_pdu(
623        &self,
624        name: &str,
625        package: &ArPackage,
626        length: u32,
627        category: GeneralPurposePduCategory,
628    ) -> Result<GeneralPurposePdu, AutosarAbstractionError> {
629        let pdu = GeneralPurposePdu::new(name, package, length, category)?;
630        self.create_fibex_element_ref_unchecked(pdu.element())?;
631
632        Ok(pdu)
633    }
634
635    /// create a [`GeneralPurposeIPdu`] in the [`System`]
636    ///
637    /// # Example
638    ///
639    /// ```
640    /// # use autosar_data::*;
641    /// # use autosar_data_abstraction::*;
642    /// # use autosar_data_abstraction::communication::*;
643    /// # fn main() -> Result<(), AutosarAbstractionError> {
644    /// # let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
645    /// # let package = model.get_or_create_package("/pkg1")?;
646    /// # let system = package.create_system("System", SystemCategory::SystemExtract)?;
647    /// let package = model.get_or_create_package("/Pdus")?;
648    /// system.create_general_purpose_ipdu("pdu", &package, 42, GeneralPurposeIPduCategory::Xcp)?;
649    /// # Ok(())}
650    /// ```
651    ///
652    /// # Errors
653    ///
654    /// - [`AutosarAbstractionError::ModelError`] An error occurred in the Autosar model while trying to create elements
655    pub fn create_general_purpose_ipdu(
656        &self,
657        name: &str,
658        package: &ArPackage,
659        length: u32,
660        category: GeneralPurposeIPduCategory,
661    ) -> Result<GeneralPurposeIPdu, AutosarAbstractionError> {
662        let pdu = GeneralPurposeIPdu::new(name, package, length, category)?;
663        self.create_fibex_element_ref_unchecked(pdu.element())?;
664
665        Ok(pdu)
666    }
667
668    /// create a [`ContainerIPdu`] in the [`System`]
669    ///
670    /// # Example
671    ///
672    /// ```
673    /// # use autosar_data::*;
674    /// # use autosar_data_abstraction::*;
675    /// # use autosar_data_abstraction::communication::*;
676    /// # fn main() -> Result<(), AutosarAbstractionError> {
677    /// # let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
678    /// # let package = model.get_or_create_package("/pkg1")?;
679    /// # let system = package.create_system("System", SystemCategory::SystemExtract)?;
680    /// let package = model.get_or_create_package("/Pdus")?;
681    /// system.create_container_ipdu("pdu", &package, 42, ContainerIPduHeaderType::ShortHeader, RxAcceptContainedIPdu::AcceptAll)?;
682    /// # Ok(())}
683    /// ```
684    ///
685    /// # Errors
686    ///
687    /// - [`AutosarAbstractionError::ModelError`] An error occurred in the Autosar model while trying to create elements
688    pub fn create_container_ipdu(
689        &self,
690        name: &str,
691        package: &ArPackage,
692        length: u32,
693        header_type: ContainerIPduHeaderType,
694        rx_accept: RxAcceptContainedIPdu,
695    ) -> Result<ContainerIPdu, AutosarAbstractionError> {
696        let pdu = ContainerIPdu::new(name, package, length, header_type, rx_accept)?;
697        self.create_fibex_element_ref_unchecked(pdu.element())?;
698
699        Ok(pdu)
700    }
701
702    /// create a [`SecuredIPdu`] in the [`System`]
703    ///
704    /// # Example
705    ///
706    /// ```
707    /// # use autosar_data::*;
708    /// # use autosar_data_abstraction::*;
709    /// # use autosar_data_abstraction::communication::*;
710    /// # fn main() -> Result<(), AutosarAbstractionError> {
711    /// # let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
712    /// # let package = model.get_or_create_package("/pkg1")?;
713    /// # let system = package.create_system("System", SystemCategory::SystemExtract)?;
714    /// let package = model.get_or_create_package("/Pdus")?;
715    /// let secure_communication_props = SecureCommunicationProps::default();
716    /// system.create_secured_ipdu("pdu", &package, 42, &secure_communication_props)?;
717    /// # Ok(())}
718    /// ```
719    ///
720    /// # Errors
721    ///
722    /// - [`AutosarAbstractionError::ModelError`] An error occurred in the Autosar model while trying to create elements
723    pub fn create_secured_ipdu(
724        &self,
725        name: &str,
726        package: &ArPackage,
727        length: u32,
728        secure_props: &SecureCommunicationProps,
729    ) -> Result<SecuredIPdu, AutosarAbstractionError> {
730        let pdu = SecuredIPdu::new(name, package, length, secure_props)?;
731        self.create_fibex_element_ref_unchecked(pdu.element())?;
732
733        Ok(pdu)
734    }
735
736    /// create a [`MultiplexedIPdu`] in the [`System`]
737    ///
738    /// # Example
739    ///
740    /// ```
741    /// # use autosar_data::*;
742    /// # use autosar_data_abstraction::*;
743    /// # use autosar_data_abstraction::communication::*;
744    /// # fn main() -> Result<(), AutosarAbstractionError> {
745    /// # let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
746    /// # let package = model.get_or_create_package("/pkg1")?;
747    /// # let system = package.create_system("System", SystemCategory::SystemExtract)?;
748    /// let package = model.get_or_create_package("/Pdus")?;
749    /// system.create_multiplexed_ipdu("pdu", &package, 42)?;
750    /// # Ok(())}
751    /// ```
752    ///
753    /// # Errors
754    ///
755    /// - [`AutosarAbstractionError::ModelError`] An error occurred in the Autosar model while trying to create elements
756    pub fn create_multiplexed_ipdu(
757        &self,
758        name: &str,
759        package: &ArPackage,
760        length: u32,
761    ) -> Result<MultiplexedIPdu, AutosarAbstractionError> {
762        let pdu = MultiplexedIPdu::new(name, package, length)?;
763        self.create_fibex_element_ref_unchecked(pdu.element())?;
764
765        Ok(pdu)
766    }
767
768    /// iterate over all PDUs in the System
769    ///
770    /// This iterator returns all PDUs that are connected to the System using a `FibexElementRef`.
771    pub fn pdus(&self) -> impl Iterator<Item = Pdu> + Send + 'static {
772        self.0
773            .get_sub_element(ElementName::FibexElements)
774            .into_iter()
775            .flat_map(|fibexelems| fibexelems.sub_elements())
776            .filter_map(|ferc| {
777                ferc.get_sub_element(ElementName::FibexElementRef)
778                    .and_then(|fer| fer.get_reference_target().ok())
779                    .and_then(|elem| Pdu::try_from(elem).ok())
780            })
781    }
782
783    /// Create a `SocketConnectionIpduIdentifierSet` in the SYSTEM
784    ///
785    /// `SocketConnectionIpduIdentifierSet` are part of the new ethernet modeling that was introduced in Autosar 4.5.0 (`AUTOSAR_00048`).
786    ///
787    /// # Example
788    ///
789    /// ```
790    /// # use autosar_data::*;
791    /// # use autosar_data_abstraction::*;
792    /// # use autosar_data_abstraction::communication::*;
793    /// # fn main() -> Result<(), AutosarAbstractionError> {
794    /// # let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
795    /// # let package = model.get_or_create_package("/pkg1")?;
796    /// let system = package.create_system("System", SystemCategory::SystemExtract)?;
797    /// let set = system.create_socket_connection_ipdu_identifier_set("set", &package)?;
798    /// # Ok(())}
799    /// ```
800    pub fn create_socket_connection_ipdu_identifier_set(
801        &self,
802        name: &str,
803        package: &ArPackage,
804    ) -> Result<SocketConnectionIpduIdentifierSet, AutosarAbstractionError> {
805        let set = SocketConnectionIpduIdentifierSet::new(name, package)?;
806        self.create_fibex_element_ref_unchecked(set.element())?;
807
808        Ok(set)
809    }
810
811    /// Create a `SoAdRoutingGroup` in the SYSTEM
812    ///
813    /// `SoAdRoutingGroup` are part of the old ethernet modeling that was used prior to Autosar 4.5.0 (`AUTOSAR_00048`).
814    /// The elements are still present (but obsolete) in newer versions of the standard.
815    /// Old and new elements may not be mixed in the same model.
816    pub fn create_so_ad_routing_group(
817        &self,
818        name: &str,
819        package: &ArPackage,
820        control_type: Option<EventGroupControlType>,
821    ) -> Result<SoAdRoutingGroup, AutosarAbstractionError> {
822        let group = SoAdRoutingGroup::new(name, package, control_type)?;
823        self.create_fibex_element_ref_unchecked(group.element())?;
824
825        Ok(group)
826    }
827
828    /// Create a `ServiceInstanceCollectionSet` in the SYSTEM
829    ///
830    /// `ServiceInstanceCollectionSet`s are part of the new ethernet modeling that was introduced in Autosar 4.5.0 (`AUTOSAR_00048`).
831    pub fn create_service_instance_collection_set(
832        &self,
833        name: &str,
834        package: &ArPackage,
835    ) -> Result<ServiceInstanceCollectionSet, AutosarAbstractionError> {
836        let set = ServiceInstanceCollectionSet::new(name, package)?;
837        self.create_fibex_element_ref_unchecked(set.element())?;
838
839        Ok(set)
840    }
841
842    /// Create a `SomeipTpConfig` in the SYSTEM
843    ///
844    /// `SomeipTpConfig`s contain the configuration how to segment or reassemble large `SomeipTp` PDUs.
845    pub fn create_someip_tp_config<T: Into<Cluster> + Clone>(
846        &self,
847        name: &str,
848        package: &ArPackage,
849        cluster: &T,
850    ) -> Result<SomeipTpConfig, AutosarAbstractionError> {
851        let config = SomeipTpConfig::new(name, package, &cluster.clone().into())?;
852        self.create_fibex_element_ref_unchecked(config.element())?;
853
854        Ok(config)
855    }
856
857    /// Create a `CanTpConfig` in the SYSTEM
858    ///
859    /// `CanTpConfig`s contain the configuration how to segment or reassemble diagnostic messages on a CAN bus.
860    pub fn create_can_tp_config(
861        &self,
862        name: &str,
863        package: &ArPackage,
864        can_cluster: &CanCluster,
865    ) -> Result<CanTpConfig, AutosarAbstractionError> {
866        let config = CanTpConfig::new(name, package, can_cluster)?;
867        self.create_fibex_element_ref_unchecked(config.element())?;
868
869        Ok(config)
870    }
871
872    /// Create a `DoIpTpConfig` in the SYSTEM
873    ///
874    /// `DoIpTpConfig`s contain the configuration how to transmit diagnostic messages over IP networks.
875    pub fn create_doip_tp_config(
876        &self,
877        name: &str,
878        package: &ArPackage,
879        eth_cluster: &EthernetCluster,
880    ) -> Result<DoIpTpConfig, AutosarAbstractionError> {
881        let config = DoIpTpConfig::new(name, package, eth_cluster)?;
882        self.create_fibex_element_ref_unchecked(config.element())?;
883
884        Ok(config)
885    }
886
887    /// Create a `FlexRayTpConfig` in the SYSTEM
888    ///
889    /// `FlexRayTpConfig`s describe how to segment or reassemble diagnostic messages on a `FlexRay` bus.
890    /// This configuration type is used for Flexray ISO TP communication.
891    pub fn create_flexray_tp_config(
892        &self,
893        name: &str,
894        package: &ArPackage,
895        flexray_cluster: &FlexrayCluster,
896    ) -> Result<FlexrayTpConfig, AutosarAbstractionError> {
897        let config = FlexrayTpConfig::new(name, package, flexray_cluster)?;
898        self.create_fibex_element_ref_unchecked(config.element())?;
899
900        Ok(config)
901    }
902
903    /// Create a `FlexrayArTpConfig` in the SYSTEM
904    ///
905    /// `FlexrayArTpConfig`s describe how to segment or reassemble diagnostic messages on a `FlexRay` bus.
906    /// This configuration type is used for Flexray AUTOSAR TP communication.
907    pub fn create_flexray_ar_tp_config(
908        &self,
909        name: &str,
910        package: &ArPackage,
911        flexray_cluster: &FlexrayCluster,
912    ) -> Result<FlexrayArTpConfig, AutosarAbstractionError> {
913        let config = FlexrayArTpConfig::new(name, package, flexray_cluster)?;
914        self.create_fibex_element_ref_unchecked(config.element())?;
915
916        Ok(config)
917    }
918
919    /// Create a new `NmConfig` in the SYSTEM
920    ///
921    /// `NmConfig`s contain the configuration for network management.
922    /// The System may contain zero or one `NmConfig`s.
923    pub fn create_nm_config(&self, name: &str, package: &ArPackage) -> Result<NmConfig, AutosarAbstractionError> {
924        let config = NmConfig::new(name, package)?;
925        self.create_fibex_element_ref_unchecked(config.element())?;
926
927        Ok(config)
928    }
929
930    /// Get the `NmConfig` of the SYSTEM, if any
931    ///
932    /// The System may contain zero or one `NmConfig`s.
933    #[must_use]
934    pub fn nm_config(&self) -> Option<NmConfig> {
935        self.0
936            .get_sub_element(ElementName::FibexElements)
937            .into_iter()
938            .flat_map(|fibexelems| fibexelems.sub_elements())
939            .find_map(|ferc| {
940                ferc.get_sub_element(ElementName::FibexElementRef)
941                    .and_then(|fer| fer.get_reference_target().ok())
942                    .and_then(|elem| NmConfig::try_from(elem).ok())
943            })
944    }
945
946    /// connect an element to the SYSTEM by creating a FIBEX-ELEMENT-REF
947    ///
948    /// If there is already a FIBEX-ELEMENT-REF, this function does nothing, successfully.
949    ///
950    /// # Example
951    ///
952    /// ```
953    /// # use autosar_data::*;
954    /// # use autosar_data_abstraction::*;
955    /// # use autosar_data_abstraction::communication::*;
956    /// # fn main() -> Result<(), AutosarAbstractionError> {
957    /// # let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
958    /// # let package = model.get_or_create_package("/pkg1")?;
959    /// let system = package.create_system("System", SystemCategory::SystemExtract)?;
960    /// # let pkg_elements = package.element().get_sub_element(ElementName::Elements).unwrap();
961    /// let can_cluster = pkg_elements.create_named_sub_element(ElementName::CanCluster, "Cluster")?;
962    /// system.create_fibex_element_ref(&can_cluster)?;
963    /// # Ok(())}
964    /// ```
965    ///
966    /// # Errors
967    ///
968    /// - [`AutosarAbstractionError::ModelError`] An error occurred in the Autosar model
969    pub fn create_fibex_element_ref(&self, elem: &Element) -> Result<(), AutosarAbstractionError> {
970        let model = elem.model()?;
971        let refs = model.get_references_to(&elem.path()?);
972        for reference in refs.iter().filter_map(WeakElement::upgrade) {
973            if reference.element_name() == ElementName::FibexElementRef {
974                // a FIBEX-ELEMENT-REF for this elem already exists.
975                return Ok(());
976            }
977        }
978        self.create_fibex_element_ref_unchecked(elem)
979    }
980
981    fn create_fibex_element_ref_unchecked(&self, elem: &Element) -> Result<(), AutosarAbstractionError> {
982        let fibex_elements = self.0.get_or_create_sub_element(ElementName::FibexElements)?;
983        let fibex_element_ref = fibex_elements
984            .create_sub_element(ElementName::FibexElementRefConditional)?
985            .create_sub_element(ElementName::FibexElementRef)?;
986        fibex_element_ref.set_reference_target(elem)?;
987        Ok(())
988    }
989
990    /// set the root software composition of the system
991    ///
992    /// When the root software composition is set, a root sw composition prototype is created for it.
993    /// This function will remove any existing root sw composition prototype
994    pub fn set_root_sw_composition(
995        &self,
996        name: &str,
997        composition_type: &CompositionSwComponentType,
998    ) -> Result<RootSwCompositionPrototype, AutosarAbstractionError> {
999        let root_compositions = self
1000            .0
1001            .get_or_create_sub_element(ElementName::RootSoftwareCompositions)?;
1002
1003        if let Some(existing_composition) = root_compositions.get_sub_element(ElementName::RootSwCompositionPrototype) {
1004            root_compositions.remove_sub_element(existing_composition)?;
1005        }
1006        RootSwCompositionPrototype::new(name, &root_compositions, composition_type)
1007    }
1008
1009    /// get the root software composition of the system
1010    #[must_use]
1011    pub fn root_sw_composition(&self) -> Option<RootSwCompositionPrototype> {
1012        let root_compositions = self.element().get_sub_element(ElementName::RootSoftwareCompositions)?;
1013        let root_composition = root_compositions.get_sub_element(ElementName::RootSwCompositionPrototype)?;
1014        RootSwCompositionPrototype::try_from(root_composition).ok()
1015    }
1016
1017    /// get or create a mapping for this system
1018    ///
1019    /// There does not seem to be any benefit to having multiple mappings for a single system, so this function
1020    /// will return the first mapping if it exists. Otherwise a new mapping will be created with the provided name.
1021    pub fn get_or_create_mapping(&self, name: &str) -> Result<SystemMapping, AutosarAbstractionError> {
1022        if let Some(mapping) = self.0.get_sub_element(ElementName::Mappings) {
1023            if let Some(mapping) = mapping.get_sub_element(ElementName::SystemMapping) {
1024                return SystemMapping::try_from(mapping);
1025            }
1026        }
1027        SystemMapping::new(name, self)
1028    }
1029}
1030
1031//#########################################################
1032
1033/// The category of a System
1034#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1035pub enum SystemCategory {
1036    /// The `System` is used to describe system constraints
1037    SystemConstraints,
1038    /// The `System` is used to describe the system configuration of a complete AUTOSAR system
1039    SystemDescription,
1040    /// The `System` is used to describe a subsystem specific view on the complete system description
1041    SystemExtract,
1042    /// The `System` is used to describe the ECU specific view on the complete system description
1043    EcuExtract,
1044    /// The `System` is used to describe a functional (solution-independent/abstract) system design
1045    AbstractSystemDescription,
1046    /// The `System` is used to describe the closed view on one ECU
1047    EcuSystemDescription,
1048    /// The `System` describes the content of one `CpSoftwareCluster`
1049    SwClusterSystemDescription,
1050    /// `System` which describes the rapid prototyping algorithm in the format of AUTOSAR Software Components
1051    RptSystem,
1052}
1053
1054impl std::fmt::Display for SystemCategory {
1055    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1056        match self {
1057            SystemCategory::SystemConstraints => f.write_str("SYSTEM_CONSTRAINTS"),
1058            SystemCategory::SystemDescription => f.write_str("SYSTEM_DESCRIPTION"),
1059            SystemCategory::SystemExtract => f.write_str("SYSTEM_EXTRACT"),
1060            SystemCategory::EcuExtract => f.write_str("ECU_EXTRACT"),
1061            SystemCategory::AbstractSystemDescription => f.write_str("ABSTRACT_SYSTEM_DESCRIPTION"),
1062            SystemCategory::EcuSystemDescription => f.write_str("ECU_SYSTEM_DESCRIPTION"),
1063            SystemCategory::SwClusterSystemDescription => f.write_str("SW_CLUSTER_SYSTEM_DESCRIPTION"),
1064            SystemCategory::RptSystem => f.write_str("RPT_SYSTEM"),
1065        }
1066    }
1067}
1068
1069impl std::str::FromStr for SystemCategory {
1070    type Err = AutosarAbstractionError;
1071
1072    fn from_str(s: &str) -> Result<Self, Self::Err> {
1073        match s {
1074            "SYSTEM_CONSTRAINTS" => Ok(SystemCategory::SystemConstraints),
1075            "SYSTEM_DESCRIPTION" => Ok(SystemCategory::SystemDescription),
1076            "SYSTEM_EXTRACT" => Ok(SystemCategory::SystemExtract),
1077            "ECU_EXTRACT" => Ok(SystemCategory::EcuExtract),
1078            "ABSTRACT_SYSTEM_DESCRIPTION" => Ok(SystemCategory::AbstractSystemDescription),
1079            "ECU_SYSTEM_DESCRIPTION" => Ok(SystemCategory::EcuSystemDescription),
1080            "SW_CLUSTER_SYSTEM_DESCRIPTION" => Ok(SystemCategory::SwClusterSystemDescription),
1081            "RPT_SYSTEM" => Ok(SystemCategory::RptSystem),
1082            _ => Err(AutosarAbstractionError::InvalidParameter(s.to_string())),
1083        }
1084    }
1085}
1086
1087//#########################################################
1088
1089/// An iterator over all `EcuInstances` in a System
1090pub struct EcuInstanceIterator {
1091    fibex_elements: Option<Element>,
1092    position: usize,
1093}
1094
1095impl EcuInstanceIterator {
1096    pub(crate) fn new(system: &System) -> Self {
1097        let fibex_elements = system.0.get_sub_element(ElementName::FibexElements);
1098
1099        EcuInstanceIterator {
1100            fibex_elements,
1101            position: 0,
1102        }
1103    }
1104}
1105
1106impl Iterator for EcuInstanceIterator {
1107    type Item = EcuInstance;
1108
1109    fn next(&mut self) -> Option<Self::Item> {
1110        let fibelem = self.fibex_elements.as_ref()?;
1111
1112        while let Some(fibrefcond) = fibelem.get_sub_element_at(self.position) {
1113            self.position += 1;
1114            if let Some(ecuinstance) = fibrefcond
1115                .get_sub_element(ElementName::FibexElementRef)
1116                .and_then(|r| r.get_reference_target().ok())
1117                .and_then(|target| EcuInstance::try_from(target).ok())
1118            {
1119                return Some(ecuinstance);
1120            }
1121        }
1122        self.fibex_elements = None;
1123        None
1124    }
1125}
1126
1127impl FusedIterator for EcuInstanceIterator {}
1128
1129//#########################################################
1130
1131#[cfg(test)]
1132mod test {
1133    use crate::{
1134        AbstractionElement, AutosarModelAbstraction, IdentifiableAbstractionElement, System,
1135        communication::{
1136            ContainerIPduHeaderType, FlexrayClusterSettings, GeneralPurposeIPduCategory, GeneralPurposePduCategory,
1137            RxAcceptContainedIPdu, SecureCommunicationProps,
1138        },
1139        software_component::CompositionSwComponentType,
1140        system::SystemCategory,
1141    };
1142    use autosar_data::{AutosarVersion, ElementName};
1143
1144    #[test]
1145    fn system() {
1146        let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
1147
1148        // try to find a system in the empty model
1149        let result = model.find_system();
1150        assert!(result.is_none());
1151
1152        // create a System
1153        let package = model.get_or_create_package("/SYSTEM").unwrap();
1154        let system = package.create_system("System", SystemCategory::SystemExtract).unwrap();
1155
1156        // find the newly created system
1157        let system_2 = model.find_system().unwrap();
1158        assert_eq!(system, system_2);
1159
1160        // name
1161        assert_eq!(system.name().unwrap(), "System");
1162        system.set_name("NewName").unwrap();
1163        assert_eq!(system.name().unwrap(), "NewName");
1164
1165        // category
1166        assert_eq!(system.category().unwrap(), SystemCategory::SystemExtract);
1167        system.set_category(SystemCategory::EcuExtract).unwrap();
1168        assert_eq!(system.category().unwrap(), SystemCategory::EcuExtract);
1169
1170        // pnc vector length
1171        assert!(system.pnc_vector_length().is_none());
1172        system.set_pnc_vector_length(Some(42)).unwrap();
1173        assert_eq!(system.pnc_vector_length().unwrap(), 42);
1174        system.set_pnc_vector_length(None).unwrap();
1175        assert!(system.pnc_vector_length().is_none());
1176
1177        // pnc vector offset
1178        assert!(system.pnc_vector_offset().is_none());
1179        system.set_pnc_vector_offset(Some(42)).unwrap();
1180        assert_eq!(system.pnc_vector_offset().unwrap(), 42);
1181        system.set_pnc_vector_offset(None).unwrap();
1182        assert!(system.pnc_vector_offset().is_none());
1183    }
1184
1185    #[test]
1186    fn system_category() {
1187        let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
1188        let package = model.get_or_create_package("/SYSTEM").unwrap();
1189        System::new("System", &package, SystemCategory::AbstractSystemDescription).unwrap();
1190
1191        let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
1192        let package = model.get_or_create_package("/SYSTEM").unwrap();
1193        System::new("System", &package, SystemCategory::EcuExtract).unwrap();
1194
1195        let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
1196        let package = model.get_or_create_package("/SYSTEM").unwrap();
1197        System::new("System", &package, SystemCategory::EcuSystemDescription).unwrap();
1198
1199        let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
1200        let package = model.get_or_create_package("/SYSTEM").unwrap();
1201        System::new("System", &package, SystemCategory::RptSystem).unwrap();
1202
1203        let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
1204        let package = model.get_or_create_package("/SYSTEM").unwrap();
1205        System::new("System", &package, SystemCategory::SwClusterSystemDescription).unwrap();
1206
1207        let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
1208        let package = model.get_or_create_package("/SYSTEM").unwrap();
1209        System::new("System", &package, SystemCategory::SystemConstraints).unwrap();
1210
1211        let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
1212        let package = model.get_or_create_package("/SYSTEM").unwrap();
1213        System::new("System", &package, SystemCategory::SystemDescription).unwrap();
1214
1215        let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
1216        let package = model.get_or_create_package("/SYSTEM").unwrap();
1217        System::new("System", &package, SystemCategory::SystemExtract).unwrap();
1218    }
1219
1220    #[test]
1221    fn fibex_ref() {
1222        let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
1223        let package = model.get_or_create_package("/SYSTEM").unwrap();
1224        let system = package
1225            .create_system("System", SystemCategory::SystemDescription)
1226            .unwrap();
1227
1228        let el_elements = package
1229            .element()
1230            .get_or_create_sub_element(ElementName::Elements)
1231            .unwrap();
1232        let el_ecuinst = el_elements
1233            .create_named_sub_element(ElementName::EcuInstance, "Ecu")
1234            .unwrap();
1235
1236        let el_fibex_elements = system
1237            .element()
1238            .get_or_create_sub_element(ElementName::FibexElements)
1239            .unwrap();
1240        assert_eq!(el_fibex_elements.sub_elements().count(), 0);
1241
1242        // create one reference
1243        system.create_fibex_element_ref(&el_ecuinst).unwrap();
1244        assert_eq!(el_fibex_elements.sub_elements().count(), 1);
1245        // find the existing reference and do nothing
1246        system.create_fibex_element_ref(&el_ecuinst).unwrap();
1247        assert_eq!(el_fibex_elements.sub_elements().count(), 1);
1248    }
1249
1250    #[test]
1251    fn ecu_instance_iterator() {
1252        let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
1253        let package_1 = model.get_or_create_package("/SYSTEM").unwrap();
1254        let system = package_1
1255            .create_system("System", SystemCategory::SystemExtract)
1256            .unwrap();
1257        let package_2 = model.get_or_create_package("/ECU").unwrap();
1258        system.create_ecu_instance("Ecu_1", &package_2).unwrap();
1259        system.create_ecu_instance("Ecu_2", &package_2).unwrap();
1260        system.create_ecu_instance("Ecu_3", &package_2).unwrap();
1261
1262        let mut iter = system.ecu_instances();
1263        let item = iter.next().unwrap();
1264        assert_eq!(item.name().unwrap(), "Ecu_1");
1265        assert_eq!(model.get_element_by_path("/ECU/Ecu_1").unwrap(), *item.element());
1266        let item = iter.next().unwrap();
1267        assert_eq!(item.name().unwrap(), "Ecu_2");
1268        assert_eq!(model.get_element_by_path("/ECU/Ecu_2").unwrap(), *item.element());
1269        let item = iter.next().unwrap();
1270        assert_eq!(item.name().unwrap(), "Ecu_3");
1271        assert_eq!(model.get_element_by_path("/ECU/Ecu_3").unwrap(), *item.element());
1272
1273        assert!(iter.next().is_none());
1274        // after returning none the iterator continues to return none
1275        assert!(iter.next().is_none());
1276    }
1277
1278    #[test]
1279    fn cluster_iterator() {
1280        let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
1281        let package_1 = model.get_or_create_package("/SYSTEM").unwrap();
1282        let system = package_1
1283            .create_system("System", SystemCategory::SystemExtract)
1284            .unwrap();
1285        let package_2 = model.get_or_create_package("/Clusters").unwrap();
1286
1287        system.create_can_cluster("CanCluster", &package_2, None).unwrap();
1288
1289        let settings = FlexrayClusterSettings::new();
1290        system
1291            .create_flexray_cluster("FlexrayCluster", &package_2, &settings)
1292            .unwrap();
1293
1294        system.create_ethernet_cluster("EthernetCluster", &package_2).unwrap();
1295
1296        // the ecu-instance is a fourth item in the FIBEX-ELEMENTS of the system, which should not be picked up by the iterator
1297        let package_3 = model.get_or_create_package("/ECU").unwrap();
1298        system.create_ecu_instance("Ecu_1", &package_3).unwrap();
1299
1300        assert_eq!(system.clusters().count(), 3);
1301    }
1302
1303    #[test]
1304    fn frames_iterator() {
1305        let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
1306        let package_1 = model.get_or_create_package("/SYSTEM").unwrap();
1307        let system = package_1
1308            .create_system("System", SystemCategory::SystemExtract)
1309            .unwrap();
1310        let package_2 = model.get_or_create_package("/Frames").unwrap();
1311
1312        system.create_can_frame("CanFrame", &package_2, 8).unwrap();
1313        system.create_flexray_frame("FlexrayFrame", &package_2, 8).unwrap();
1314
1315        // the ecu-instance is a third item in the FIBEX-ELEMENTS of the system, which should not be picked up by the iterator
1316        let package_3 = model.get_or_create_package("/ECU").unwrap();
1317        system.create_ecu_instance("Ecu_1", &package_3).unwrap();
1318
1319        assert_eq!(system.frames().count(), 2);
1320    }
1321
1322    #[test]
1323    fn signals_iterator() {
1324        let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
1325        let package_1 = model.get_or_create_package("/SYSTEM").unwrap();
1326        let system = package_1
1327            .create_system("System", SystemCategory::SystemExtract)
1328            .unwrap();
1329        let package_2 = model.get_or_create_package("/Signals").unwrap();
1330
1331        let syssig1 = package_2.create_system_signal("syssig1").unwrap();
1332        system.create_isignal("Sig1", &package_2, 8, &syssig1, None).unwrap();
1333        let syssig2 = package_2.create_system_signal("syssig2").unwrap();
1334        system.create_isignal("Sig2", &package_2, 8, &syssig2, None).unwrap();
1335
1336        // the ecu-instance is a third item in the FIBEX-ELEMENTS of the system, which should not be picked up by the iterator
1337        let package_3 = model.get_or_create_package("/ECU").unwrap();
1338        system.create_ecu_instance("Ecu_1", &package_3).unwrap();
1339
1340        assert_eq!(system.isignals().count(), 2);
1341    }
1342
1343    #[test]
1344    fn isignal_groups_iterator() {
1345        let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
1346        let package_1 = model.get_or_create_package("/SYSTEM").unwrap();
1347        let system = package_1
1348            .create_system("System", SystemCategory::SystemExtract)
1349            .unwrap();
1350        let package_2 = model.get_or_create_package("/SignalGroups").unwrap();
1351
1352        let sysgroup1 = package_2.create_system_signal_group("sysgroup1").unwrap();
1353        system
1354            .create_isignal_group("siggroup1", &package_2, &sysgroup1)
1355            .unwrap();
1356        let sysgroup2 = package_2.create_system_signal_group("sysgroup2").unwrap();
1357        system
1358            .create_isignal_group("siggroup2", &package_2, &sysgroup2)
1359            .unwrap();
1360
1361        // the ecu-instance is a third item in the FIBEX-ELEMENTS of the system, which should not be picked up by the iterator
1362        let package_3 = model.get_or_create_package("/ECU").unwrap();
1363        system.create_ecu_instance("Ecu_1", &package_3).unwrap();
1364
1365        assert_eq!(system.isignal_groups().count(), 2);
1366    }
1367
1368    #[test]
1369    fn pdus_iterator() {
1370        let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
1371        let package_1 = model.get_or_create_package("/SYSTEM").unwrap();
1372        let system = package_1
1373            .create_system("System", SystemCategory::SystemExtract)
1374            .unwrap();
1375        let package_2 = model.get_or_create_package("/Pdus").unwrap();
1376
1377        system.create_dcm_ipdu("DcmIpdu", &package_2, 8).unwrap();
1378        system
1379            .create_general_purpose_pdu("GeneralPurposePdu", &package_2, 8, GeneralPurposePduCategory::DoIp)
1380            .unwrap();
1381        system
1382            .create_general_purpose_ipdu("GeneralPurposeIpdu", &package_2, 8, GeneralPurposeIPduCategory::Xcp)
1383            .unwrap();
1384        system
1385            .create_container_ipdu(
1386                "ContainerIpdu",
1387                &package_2,
1388                8,
1389                ContainerIPduHeaderType::NoHeader,
1390                RxAcceptContainedIPdu::AcceptAll,
1391            )
1392            .unwrap();
1393        system
1394            .create_secured_ipdu("SecuredIpdu", &package_2, 8, &SecureCommunicationProps::default())
1395            .unwrap();
1396        system
1397            .create_multiplexed_ipdu("MultiplexedIpdu", &package_2, 8)
1398            .unwrap();
1399
1400        // the EcuInstance is a seventh item in the FIBEX-ELEMENTS of the system, which should not be picked up by the iterator
1401        let package_3 = model.get_or_create_package("/ECU").unwrap();
1402        system.create_ecu_instance("Ecu_1", &package_3).unwrap();
1403
1404        assert_eq!(system.pdus().count(), 6);
1405    }
1406
1407    #[test]
1408    fn nm_config() {
1409        let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
1410        let sys_package = model.get_or_create_package("/SYSTEM").unwrap();
1411        let system = sys_package
1412            .create_system("System", SystemCategory::SystemExtract)
1413            .unwrap();
1414
1415        assert!(system.nm_config().is_none());
1416
1417        let nm_package = model.get_or_create_package("/Nm").unwrap();
1418        let nm_config = system.create_nm_config("NmConfig", &nm_package).unwrap();
1419
1420        assert!(system.nm_config().is_some());
1421        assert_eq!(system.nm_config().unwrap(), nm_config);
1422    }
1423
1424    #[test]
1425    fn sw_mapping() {
1426        let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
1427        let package_1 = model.get_or_create_package("/SYSTEM").unwrap();
1428        let system = package_1
1429            .create_system("System", SystemCategory::SystemExtract)
1430            .unwrap();
1431        let package_2 = model.get_or_create_package("/SWC").unwrap();
1432        let package_3 = model.get_or_create_package("/ECU").unwrap();
1433
1434        let root_composition = CompositionSwComponentType::new("RootComposition", &package_2).unwrap();
1435        let context_composition = CompositionSwComponentType::new("ContextComposition", &package_2).unwrap();
1436        let ecu_composition = CompositionSwComponentType::new("EcuComposition", &package_2).unwrap();
1437        let _root_proto = system
1438            .set_root_sw_composition("RootComposition", &root_composition)
1439            .unwrap();
1440        assert_eq!(system.root_sw_composition().unwrap(), _root_proto);
1441
1442        let context_proto = root_composition
1443            .create_component("ContextComposition", &context_composition.clone())
1444            .unwrap();
1445        let ecu_proto = context_composition
1446            .create_component("EcuComposition", &ecu_composition)
1447            .unwrap();
1448        let ecu = system.create_ecu_instance("Ecu", &package_3).unwrap();
1449
1450        let mapping = system.get_or_create_mapping("Mapping").unwrap();
1451        mapping.map_swc_to_ecu("SwcToEcu1", &context_proto, &ecu).unwrap();
1452        let swc_to_ecu = mapping.map_swc_to_ecu("SwcToEcu2", &ecu_proto, &ecu).unwrap();
1453
1454        assert_eq!(swc_to_ecu.target_component().unwrap(), ecu_proto);
1455        assert_eq!(swc_to_ecu.ecu_instance().unwrap(), ecu);
1456
1457        // println!("{}", _file.serialize().unwrap());
1458    }
1459}