autosar_data_abstraction/system/
mod.rs

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