autosar_data_abstraction/communication/network_management/
mod.rs

1use crate::communication::{
2    AbstractCluster, AbstractCommunicationController, CanCluster, EthernetCluster, FlexrayCluster, NmPdu,
3};
4use crate::{
5    AbstractionElement, ArPackage, AutosarAbstractionError, EcuInstance, IdentifiableAbstractionElement,
6    abstraction_element,
7};
8use autosar_data::{Element, ElementName};
9
10mod can_nm;
11mod flexray_nm;
12mod udp_nm;
13
14pub use can_nm::*;
15pub use flexray_nm::*;
16pub use udp_nm::*;
17
18//##################################################################
19
20/// The `NmConfig` is the root element for the network management configuration.
21///
22/// Only one config may exist per `System`, and this configuration may contain multiple `NmClusters` for different bus types.
23///
24/// Use [`System::create_nm_config`](crate::System::create_nm_config) to create a new `NmConfig` in a `System`.
25#[derive(Debug, Clone, PartialEq, Eq, Hash)]
26pub struct NmConfig(Element);
27abstraction_element!(NmConfig, NmConfig);
28impl IdentifiableAbstractionElement for NmConfig {}
29
30impl NmConfig {
31    /// create a new `NmConfig` in the given `ArPackage`
32    pub(crate) fn new(name: &str, package: &ArPackage) -> Result<Self, AutosarAbstractionError> {
33        let elements = package.element().get_or_create_sub_element(ElementName::Elements)?;
34        let nm_config = Self(elements.create_named_sub_element(ElementName::NmConfig, name)?);
35        nm_config
36            .element()
37            .create_sub_element(ElementName::Category)?
38            .set_character_data("NM_CONFIG")?;
39        Ok(nm_config)
40    }
41
42    /// create a new `CanNmCluster`
43    pub fn create_can_nm_cluster(
44        &self,
45        name: &str,
46        settings: &CanNmClusterSettings,
47        can_cluster: &CanCluster,
48    ) -> Result<CanNmCluster, AutosarAbstractionError> {
49        let nmclusters = self.element().get_or_create_sub_element(ElementName::NmClusters)?;
50        CanNmCluster::new(name, &nmclusters, settings, can_cluster)
51    }
52
53    /// create a new `FlexrayNmCluster`
54    pub fn create_flexray_nm_cluster(
55        &self,
56        name: &str,
57        settings: &FlexrayNmClusterSettings,
58        flexray_cluster: &FlexrayCluster,
59    ) -> Result<FlexrayNmCluster, AutosarAbstractionError> {
60        let nmclusters = self.element().get_or_create_sub_element(ElementName::NmClusters)?;
61        FlexrayNmCluster::new(name, &nmclusters, settings, flexray_cluster)
62    }
63
64    /// create a new `UdpNmCluster`
65    pub fn create_udp_nm_cluster(
66        &self,
67        name: &str,
68        settings: &UdpNmClusterSettings,
69        ethernet_cluster: &EthernetCluster,
70    ) -> Result<UdpNmCluster, AutosarAbstractionError> {
71        let nmclusters = self.element().get_or_create_sub_element(ElementName::NmClusters)?;
72        UdpNmCluster::new(name, &nmclusters, settings, ethernet_cluster)
73    }
74
75    /// get all `NmClusters`
76    pub fn nm_clusters(&self) -> impl Iterator<Item = NmCluster> + Send + use<> {
77        self.element()
78            .get_sub_element(ElementName::NmClusters)
79            .into_iter()
80            .flat_map(|clusters| clusters.sub_elements())
81            .filter_map(|elem| elem.try_into().ok())
82    }
83
84    /// create a new `CanNmClusterCoupling`
85    pub fn create_can_nm_cluster_coupling(
86        &self,
87        nm_busload_reduction_enabled: bool,
88        nm_immediate_restart_enabled: bool,
89    ) -> Result<CanNmClusterCoupling, AutosarAbstractionError> {
90        let nmcluster_couplings = self
91            .element()
92            .get_or_create_sub_element(ElementName::NmClusterCouplings)?;
93        CanNmClusterCoupling::new(
94            &nmcluster_couplings,
95            nm_busload_reduction_enabled,
96            nm_immediate_restart_enabled,
97        )
98    }
99
100    /// create a new `FlexrayNmClusterCoupling`
101    pub fn create_flexray_nm_cluster_coupling(
102        &self,
103        nm_schedule_variant: FlexrayNmScheduleVariant,
104    ) -> Result<FlexrayNmClusterCoupling, AutosarAbstractionError> {
105        let nmcluster_couplings = self
106            .element()
107            .get_or_create_sub_element(ElementName::NmClusterCouplings)?;
108        FlexrayNmClusterCoupling::new(&nmcluster_couplings, nm_schedule_variant)
109    }
110
111    /// create a new `UdpNmClusterCoupling`
112    pub fn create_udp_nm_cluster_coupling(&self) -> Result<UdpNmClusterCoupling, AutosarAbstractionError> {
113        let nmcluster_couplings = self
114            .element()
115            .get_or_create_sub_element(ElementName::NmClusterCouplings)?;
116        UdpNmClusterCoupling::new(&nmcluster_couplings)
117    }
118
119    /// iterate over all `NmClusterCouplings`
120    pub fn nm_cluster_couplings(&self) -> impl Iterator<Item = NmClusterCoupling> + Send + use<> {
121        self.element()
122            .get_sub_element(ElementName::NmClusterCouplings)
123            .into_iter()
124            .flat_map(|couplings| couplings.sub_elements())
125            .filter_map(|elem| elem.try_into().ok())
126    }
127
128    /// create a new `NmEcu`
129    pub fn create_nm_ecu(&self, name: &str, ecu_instance: &EcuInstance) -> Result<NmEcu, AutosarAbstractionError> {
130        let nm_ecus = self.element().get_or_create_sub_element(ElementName::NmIfEcus)?;
131        NmEcu::new(name, &nm_ecus, ecu_instance)
132    }
133
134    /// iterate over all `NmEcus`
135    pub fn nm_ecus(&self) -> impl Iterator<Item = NmEcu> + Send + use<> {
136        self.element()
137            .get_sub_element(ElementName::NmIfEcus)
138            .into_iter()
139            .flat_map(|ecus| ecus.sub_elements())
140            .filter_map(|elem| elem.try_into().ok())
141    }
142}
143
144//##################################################################
145
146/// An NM cluster is a set of NM nodes coordinated by the NM algorithm.
147/// The `AbstractNmCluster` is a common interface for all bus specific NM clusters and provides common functionality.
148pub trait AbstractNmCluster: AbstractionElement {
149    /// type of the communication cluster on which this NM cluster is based
150    type CommunicationClusterType: AbstractCluster;
151    /// type of the NM node in this cluster, e.g. `CanNmNode` for a `CanNmCluster`
152    type NmNodeType: AbstractNmNode;
153
154    /// set the referenced `CommunicationCluster`
155    fn set_communication_cluster(
156        &self,
157        cluster: &Self::CommunicationClusterType,
158    ) -> Result<(), AutosarAbstractionError> {
159        self.element()
160            .get_or_create_sub_element(ElementName::CommunicationClusterRef)?
161            .set_reference_target(cluster.element())?;
162        Ok(())
163    }
164
165    /// get the referenced `CommunicationCluster`
166    fn communication_cluster(&self) -> Option<Self::CommunicationClusterType> {
167        self.element()
168            .get_sub_element(ElementName::CommunicationClusterRef)
169            .and_then(|ccref| ccref.get_reference_target().ok())
170            .and_then(|elem| elem.try_into().ok())
171    }
172
173    // Note: can't add NmNodes in the trait, because different types of NmNodes need different parameters
174
175    /// iterate over all `NmNodes` in this cluster
176    fn nm_nodes(&self) -> impl Iterator<Item = Self::NmNodeType> + Send + use<Self> {
177        self.element()
178            .get_sub_element(ElementName::NmNodes)
179            .into_iter()
180            .flat_map(|nodes| nodes.sub_elements())
181            .filter_map(|elem| elem.try_into().ok())
182    }
183
184    /// set or remove the nmChannelSleepMaster flag
185    fn set_channel_sleep_master(&self, value: Option<bool>) -> Result<(), AutosarAbstractionError> {
186        if let Some(value) = value {
187            self.element()
188                .get_or_create_sub_element(ElementName::NmChannelSleepMaster)?
189                .set_character_data(value)?;
190        } else {
191            let _ = self
192                .element()
193                .remove_sub_element_kind(ElementName::NmChannelSleepMaster);
194        }
195        Ok(())
196    }
197
198    /// get the nmChannelSleepMaster flag
199    fn channel_sleep_master(&self) -> Option<bool> {
200        self.element()
201            .get_sub_element(ElementName::NmChannelSleepMaster)
202            .and_then(|elem| elem.character_data())
203            .and_then(|cdata| cdata.parse_bool())
204    }
205
206    /// set the nmNodeDetectionEnabled flag
207    fn set_node_detection_enabled(&self, value: Option<bool>) -> Result<(), AutosarAbstractionError> {
208        if let Some(value) = value {
209            self.element()
210                .get_or_create_sub_element(ElementName::NmNodeDetectionEnabled)?
211                .set_character_data(value)?;
212        } else {
213            let _ = self
214                .element()
215                .remove_sub_element_kind(ElementName::NmNodeDetectionEnabled);
216        }
217        Ok(())
218    }
219
220    /// get the nmNodeDetectionEnabled flag
221    fn node_detection_enabled(&self) -> Option<bool> {
222        self.element()
223            .get_sub_element(ElementName::NmNodeDetectionEnabled)
224            .and_then(|elem| elem.character_data())
225            .and_then(|cdata| cdata.parse_bool())
226    }
227
228    /// set the nmNodeIdEnabled flag
229    fn set_node_id_enabled(&self, value: Option<bool>) -> Result<(), AutosarAbstractionError> {
230        if let Some(value) = value {
231            self.element()
232                .get_or_create_sub_element(ElementName::NmNodeIdEnabled)?
233                .set_character_data(value)?;
234        } else {
235            let _ = self.element().remove_sub_element_kind(ElementName::NmNodeIdEnabled);
236        }
237        Ok(())
238    }
239
240    /// get the nmNodeIdEnabled flag
241    fn node_id_enabled(&self) -> Option<bool> {
242        self.element()
243            .get_sub_element(ElementName::NmNodeIdEnabled)
244            .and_then(|elem| elem.character_data())
245            .and_then(|cdata| cdata.parse_bool())
246    }
247
248    /// set the nmPncParticipation flag
249    fn set_pnc_participation(&self, value: Option<bool>) -> Result<(), AutosarAbstractionError> {
250        if let Some(value) = value {
251            self.element()
252                .get_or_create_sub_element(ElementName::NmPncParticipation)?
253                .set_character_data(value)?;
254        } else {
255            let _ = self.element().remove_sub_element_kind(ElementName::NmPncParticipation);
256        }
257        Ok(())
258    }
259
260    /// get the nmPncParticipation flag
261    fn pnc_participation(&self) -> Option<bool> {
262        self.element()
263            .get_sub_element(ElementName::NmPncParticipation)
264            .and_then(|elem| elem.character_data())
265            .and_then(|cdata| cdata.parse_bool())
266    }
267
268    /// set the nmRepeatMsgIndEnabled flag
269    fn set_repeat_msg_ind_enabled(&self, value: Option<bool>) -> Result<(), AutosarAbstractionError> {
270        if let Some(value) = value {
271            self.element()
272                .get_or_create_sub_element(ElementName::NmRepeatMsgIndEnabled)?
273                .set_character_data(value)?;
274        } else {
275            let _ = self
276                .element()
277                .remove_sub_element_kind(ElementName::NmRepeatMsgIndEnabled);
278        }
279        Ok(())
280    }
281
282    /// get the nmRepeatMsgIndEnabled flag
283    fn repeat_msg_ind_enabled(&self) -> Option<bool> {
284        self.element()
285            .get_sub_element(ElementName::NmRepeatMsgIndEnabled)
286            .and_then(|elem| elem.character_data())
287            .and_then(|cdata| cdata.parse_bool())
288    }
289
290    /// set the nmSynchronizingNetwork flag
291    fn set_synchronizing_network(&self, value: Option<bool>) -> Result<(), AutosarAbstractionError> {
292        if let Some(value) = value {
293            self.element()
294                .get_or_create_sub_element(ElementName::NmSynchronizingNetwork)?
295                .set_character_data(value)?;
296        } else {
297            let _ = self
298                .element()
299                .remove_sub_element_kind(ElementName::NmSynchronizingNetwork);
300        }
301        Ok(())
302    }
303
304    /// get the nmSynchronizingNetwork flag
305    fn synchronizing_network(&self) -> Option<bool> {
306        self.element()
307            .get_sub_element(ElementName::NmSynchronizingNetwork)
308            .and_then(|elem| elem.character_data())
309            .and_then(|cdata| cdata.parse_bool())
310    }
311
312    /// set the pncClusterVectorLength
313    fn set_pnc_cluster_vector_length(&self, value: Option<u8>) -> Result<(), AutosarAbstractionError> {
314        if let Some(value) = value {
315            self.element()
316                .get_or_create_sub_element(ElementName::PncClusterVectorLength)?
317                .set_character_data(u64::from(value))?;
318        } else {
319            let _ = self
320                .element()
321                .remove_sub_element_kind(ElementName::PncClusterVectorLength);
322        }
323        Ok(())
324    }
325
326    /// get the pncClusterVectorLength
327    fn pnc_cluster_vector_length(&self) -> Option<u8> {
328        self.element()
329            .get_sub_element(ElementName::PncClusterVectorLength)
330            .and_then(|elem| elem.character_data())
331            .and_then(|cdata| cdata.parse_integer())
332    }
333}
334
335//##################################################################
336
337/// The `NmCluster` encapsulates the bus specific NM clusters.
338#[derive(Debug, Clone, PartialEq, Eq, Hash)]
339pub enum NmCluster {
340    /// the NM cluster is a `CanNmCluster`
341    CanNm(CanNmCluster),
342    /// the NM cluster is a `FlexrayNmCluster`
343    FlexrayNm(FlexrayNmCluster),
344    /// the NM cluster is a `UdpNmCluster`
345    UdpNm(UdpNmCluster),
346}
347
348impl TryFrom<Element> for NmCluster {
349    type Error = AutosarAbstractionError;
350
351    fn try_from(element: Element) -> Result<Self, Self::Error> {
352        match element.element_name() {
353            ElementName::CanNmCluster => CanNmCluster::try_from(element).map(NmCluster::CanNm),
354            ElementName::FlexrayNmCluster => FlexrayNmCluster::try_from(element).map(NmCluster::FlexrayNm),
355            ElementName::UdpNmCluster => UdpNmCluster::try_from(element).map(NmCluster::UdpNm),
356            _ => Err(AutosarAbstractionError::ConversionError {
357                element,
358                dest: "NmCluster".to_string(),
359            }),
360        }
361    }
362}
363
364impl AbstractionElement for NmCluster {
365    fn element(&self) -> &Element {
366        match self {
367            NmCluster::CanNm(cluster) => cluster.element(),
368            NmCluster::FlexrayNm(cluster) => cluster.element(),
369            NmCluster::UdpNm(cluster) => cluster.element(),
370        }
371    }
372}
373
374impl IdentifiableAbstractionElement for NmCluster {}
375
376//##################################################################
377
378/// The `NmClusterCoupling` is used to couple two `NmClusters` together.
379///
380/// `AbstractNmClusterCoupling` is a common interface for all bus specific
381/// NM cluster couplings and provides common functionality.
382pub trait AbstractNmClusterCoupling: AbstractionElement {
383    /// type of the coupled `NmCluster`s
384    type NmClusterType: AbstractNmCluster;
385
386    /// add a reference to a coupled `NmCluster`
387    fn add_coupled_cluster(&self, cluster: &Self::NmClusterType) -> Result<(), AutosarAbstractionError> {
388        self.element()
389            .get_or_create_sub_element(ElementName::CoupledClusterRefs)?
390            .create_sub_element(ElementName::CoupledClusterRef)?
391            .set_reference_target(cluster.element())?;
392        Ok(())
393    }
394
395    /// iterate over all coupled `NmClusters`
396    fn coupled_clusters(&self) -> impl Iterator<Item = Self::NmClusterType> + Send + use<Self> {
397        self.element()
398            .get_sub_element(ElementName::CoupledClusterRefs)
399            .into_iter()
400            .flat_map(|clusters| clusters.sub_elements())
401            .filter_map(|refelem| {
402                refelem
403                    .get_reference_target()
404                    .ok()
405                    .and_then(|elem| elem.try_into().ok())
406            })
407    }
408}
409
410//##################################################################
411
412/// Wrapper for the different types of `NmClusterCoupling`; this type is returned by the iterator over `NmClusterCouplings`.
413#[derive(Debug, Clone, PartialEq, Eq, Hash)]
414pub enum NmClusterCoupling {
415    /// the coupling is a `CanNmClusterCoupling`
416    CanNmClusterCoupling(CanNmClusterCoupling),
417    /// the coupling is a `FlexrayNmClusterCoupling`
418    FlexrayNmClusterCoupling(FlexrayNmClusterCoupling),
419    /// the coupling is a `UdpNmClusterCoupling`
420    UdpNmClusterCoupling(UdpNmClusterCoupling),
421}
422
423impl TryFrom<Element> for NmClusterCoupling {
424    type Error = AutosarAbstractionError;
425
426    fn try_from(element: Element) -> Result<Self, Self::Error> {
427        match element.element_name() {
428            ElementName::CanNmClusterCoupling => {
429                CanNmClusterCoupling::try_from(element).map(NmClusterCoupling::CanNmClusterCoupling)
430            }
431            ElementName::FlexrayNmClusterCoupling => {
432                FlexrayNmClusterCoupling::try_from(element).map(NmClusterCoupling::FlexrayNmClusterCoupling)
433            }
434            ElementName::UdpNmClusterCoupling => {
435                UdpNmClusterCoupling::try_from(element).map(NmClusterCoupling::UdpNmClusterCoupling)
436            }
437            _ => Err(AutosarAbstractionError::ConversionError {
438                element,
439                dest: "NmClusterCoupling".to_string(),
440            }),
441        }
442    }
443}
444
445impl AbstractionElement for NmClusterCoupling {
446    fn element(&self) -> &Element {
447        match self {
448            NmClusterCoupling::CanNmClusterCoupling(coupling) => coupling.element(),
449            NmClusterCoupling::FlexrayNmClusterCoupling(coupling) => coupling.element(),
450            NmClusterCoupling::UdpNmClusterCoupling(coupling) => coupling.element(),
451        }
452    }
453}
454
455impl IdentifiableAbstractionElement for NmClusterCoupling {}
456
457//##################################################################
458
459/// The `NmEcu` represents an `EcuInstance` wich participates in network management.
460#[derive(Debug, Clone, PartialEq, Eq, Hash)]
461pub struct NmEcu(Element);
462abstraction_element!(NmEcu, NmEcu);
463impl IdentifiableAbstractionElement for NmEcu {}
464
465impl NmEcu {
466    pub(crate) fn new(
467        name: &str,
468        parent: &Element,
469        ecu_instance: &EcuInstance,
470    ) -> Result<Self, AutosarAbstractionError> {
471        let nm_ecu_elem = parent.create_named_sub_element(ElementName::NmEcu, name)?;
472        let nm_ecu = Self(nm_ecu_elem);
473        nm_ecu.set_ecu_instance(ecu_instance)?;
474
475        Ok(nm_ecu)
476    }
477
478    /// set the referenced `EcuInstance`
479    pub fn set_ecu_instance(&self, ecu_instance: &EcuInstance) -> Result<(), AutosarAbstractionError> {
480        self.element()
481            .get_or_create_sub_element(ElementName::EcuInstanceRef)?
482            .set_reference_target(ecu_instance.element())?;
483        Ok(())
484    }
485
486    /// get the referenced `EcuInstance`
487    #[must_use]
488    pub fn ecu_instance(&self) -> Option<EcuInstance> {
489        self.element()
490            .get_sub_element(ElementName::EcuInstanceRef)
491            .and_then(|eiref| eiref.get_reference_target().ok())
492            .and_then(|elem| elem.try_into().ok())
493    }
494
495    /// set the nmBusSynchronizationEnabled flag
496    ///
497    /// This flag is optional; if it is set to `Some()` the value is created, if it is set to None the value is removed.
498    pub fn set_nm_bus_synchronization_enabled(&self, value: Option<bool>) -> Result<(), AutosarAbstractionError> {
499        if let Some(value) = value {
500            self.element()
501                .get_or_create_sub_element(ElementName::NmBusSynchronizationEnabled)?
502                .set_character_data(value)?;
503        } else {
504            let _ = self
505                .element()
506                .remove_sub_element_kind(ElementName::NmBusSynchronizationEnabled);
507        }
508        Ok(())
509    }
510
511    /// get the nmBusSynchronizationEnabled flag
512    #[must_use]
513    pub fn nm_bus_synchronization_enabled(&self) -> Option<bool> {
514        self.element()
515            .get_sub_element(ElementName::NmBusSynchronizationEnabled)
516            .and_then(|elem| elem.character_data())
517            .and_then(|cdata| cdata.parse_bool())
518    }
519
520    /// set the nmComControlEnabled flag
521    ///
522    /// This flag is optional; if it is set to `Some()` the value is created, if it is set to None the value is removed.
523    pub fn set_nm_com_control_enabled(&self, value: Option<bool>) -> Result<(), AutosarAbstractionError> {
524        if let Some(value) = value {
525            self.element()
526                .get_or_create_sub_element(ElementName::NmComControlEnabled)?
527                .set_character_data(value)?;
528        } else {
529            let _ = self.element().remove_sub_element_kind(ElementName::NmComControlEnabled);
530        }
531        Ok(())
532    }
533
534    /// get the nmComControlEnabled flag
535    #[must_use]
536    pub fn nm_com_control_enabled(&self) -> Option<bool> {
537        self.element()
538            .get_sub_element(ElementName::NmComControlEnabled)
539            .and_then(|elem| elem.character_data())
540            .and_then(|cdata| cdata.parse_bool())
541    }
542
543    /// set or remove the nmCycletimeMainFunction value
544    ///
545    /// This value is optional; if it is set to Some(x) the value is created, if it is set to None the value is removed.
546    pub fn set_cycle_time_main_function(&self, value: Option<f64>) -> Result<(), AutosarAbstractionError> {
547        if let Some(value) = value {
548            self.element()
549                .get_or_create_sub_element(ElementName::NmCycletimeMainFunction)?
550                .set_character_data(value)?;
551        } else {
552            let _ = self
553                .element()
554                .remove_sub_element_kind(ElementName::NmCycletimeMainFunction);
555        }
556        Ok(())
557    }
558
559    /// get the nmCycletimeMainFunction value
560    #[must_use]
561    pub fn cycle_time_main_function(&self) -> Option<f64> {
562        self.element()
563            .get_sub_element(ElementName::NmCycletimeMainFunction)
564            .and_then(|elem| elem.character_data())
565            .and_then(|cdata| cdata.parse_float())
566    }
567}
568
569//##################################################################
570
571/// `AbstractNmNode` is a common interface for all bus specific NM nodes and provides common functionality.
572///
573/// The `NmNode` represents a node in the network management.
574/// Each `NmNode` is connected to a `CommunicationController` and an `NmEcu`.
575pub trait AbstractNmNode: AbstractionElement {
576    /// type of the communication controller connected to this node
577    type CommunicationControllerType: AbstractCommunicationController;
578
579    /// set the referenced `CommunicationController`
580    fn set_communication_controller(
581        &self,
582        controller: &Self::CommunicationControllerType,
583    ) -> Result<(), AutosarAbstractionError> {
584        self.element()
585            .get_or_create_sub_element(ElementName::ControllerRef)?
586            .set_reference_target(controller.element())?;
587        Ok(())
588    }
589
590    /// get the referenced `CommunicationController`
591    fn communication_controller(&self) -> Option<Self::CommunicationControllerType> {
592        self.element()
593            .get_sub_element(ElementName::ControllerRef)
594            .and_then(|ccref| ccref.get_reference_target().ok())
595            .and_then(|elem| elem.try_into().ok())
596    }
597
598    /// set the referenced `NmEcu`
599    fn set_nm_ecu(&self, ecu: &NmEcu) -> Result<(), AutosarAbstractionError> {
600        self.element()
601            .get_or_create_sub_element(ElementName::NmIfEcuRef)?
602            .set_reference_target(ecu.element())?;
603        Ok(())
604    }
605
606    /// get the referenced `NmEcu`
607    fn nm_ecu(&self) -> Option<NmEcu> {
608        self.element()
609            .get_sub_element(ElementName::NmIfEcuRef)
610            .and_then(|eiref| eiref.get_reference_target().ok())
611            .and_then(|elem| elem.try_into().ok())
612    }
613
614    /// set the nmNodeId
615    /// This value is optional; if it is set to Some(x) the value is created, if it is set to None the value is removed.
616    fn set_node_id(&self, value: Option<u32>) -> Result<(), AutosarAbstractionError> {
617        if let Some(value) = value {
618            self.element()
619                .get_or_create_sub_element(ElementName::NmNodeId)?
620                .set_character_data(u64::from(value))?;
621        } else {
622            let _ = self.element().remove_sub_element_kind(ElementName::NmNodeId);
623        }
624        Ok(())
625    }
626
627    /// get the nmNodeId
628    fn node_id(&self) -> Option<u32> {
629        self.element()
630            .get_sub_element(ElementName::NmNodeId)
631            .and_then(|elem| elem.character_data())
632            .and_then(|cdata| cdata.parse_integer())
633    }
634
635    /// set ot remove the nmPassiveModeEnabled flag
636    ///
637    /// This flag is optional; if it is set to Some(x) the value is created, if it is set to None the value is removed.
638    fn set_passive_mode(&self, value: Option<bool>) -> Result<(), AutosarAbstractionError> {
639        if let Some(value) = value {
640            self.element()
641                .get_or_create_sub_element(ElementName::NmPassiveModeEnabled)?
642                .set_character_data(value)?;
643        } else {
644            let _ = self
645                .element()
646                .remove_sub_element_kind(ElementName::NmPassiveModeEnabled);
647        }
648        Ok(())
649    }
650
651    /// get the nmPassiveModeEnabled flag
652    fn passive_mode(&self) -> Option<bool> {
653        self.element()
654            .get_sub_element(ElementName::NmPassiveModeEnabled)
655            .and_then(|elem| elem.character_data())
656            .and_then(|cdata| cdata.parse_bool())
657    }
658
659    /// add an Rx `NmPdu`
660    ///
661    /// Every `NmNode` must have at least one Rx `NmPdu`
662    fn add_rx_nm_pdu(&self, nm_pdu: &NmPdu) -> Result<(), AutosarAbstractionError> {
663        let rx_pdus = self.element().get_or_create_sub_element(ElementName::RxNmPduRefs)?;
664        rx_pdus
665            .create_sub_element(ElementName::RxNmPduRef)?
666            .set_reference_target(nm_pdu.element())?;
667        Ok(())
668    }
669
670    /// iterate over all RX `NmPdus`
671    fn rx_nm_pdus(&self) -> impl Iterator<Item = NmPdu> + Send + use<Self> {
672        self.element()
673            .get_sub_element(ElementName::RxNmPduRefs)
674            .into_iter()
675            .flat_map(|rx_pdus| rx_pdus.sub_elements())
676            .filter_map(|refelem| {
677                refelem
678                    .get_reference_target()
679                    .ok()
680                    .and_then(|elem| elem.try_into().ok())
681            })
682    }
683
684    /// add a Tx `NmPdu`
685    ///
686    /// Active `NmNodes` must have at least one Tx `NmPdu`, while passive `NmNodes` may have none.
687    fn add_tx_nm_pdu(&self, nm_pdu: &NmPdu) -> Result<(), AutosarAbstractionError> {
688        let tx_pdus = self.element().get_or_create_sub_element(ElementName::TxNmPduRefs)?;
689        tx_pdus
690            .create_sub_element(ElementName::TxNmPduRef)?
691            .set_reference_target(nm_pdu.element())?;
692        Ok(())
693    }
694
695    /// iterate over all TX `NmPdus`
696    fn tx_nm_pdus(&self) -> impl Iterator<Item = NmPdu> + Send + use<Self> {
697        self.element()
698            .get_sub_element(ElementName::TxNmPduRefs)
699            .into_iter()
700            .flat_map(|tx_pdus| tx_pdus.sub_elements())
701            .filter_map(|refelem| {
702                refelem
703                    .get_reference_target()
704                    .ok()
705                    .and_then(|elem| elem.try_into().ok())
706            })
707    }
708}
709
710//##################################################################
711
712#[cfg(test)]
713mod test {
714    use crate::communication::*;
715    use crate::*;
716    use autosar_data::AutosarVersion;
717
718    #[test]
719    fn test_can_nm() {
720        let model = AutosarModelAbstraction::create("test", AutosarVersion::LATEST);
721        let package = model.get_or_create_package("/package").unwrap();
722        let system = package.create_system("System", SystemCategory::SystemExtract).unwrap();
723
724        let can_cluster = system.create_can_cluster("can_cluster", &package, None).unwrap();
725        let can_physical_channel = can_cluster.create_physical_channel("can_channel").unwrap();
726        let ecu1 = system.create_ecu_instance("ecu1", &package).unwrap();
727        let ecu2 = system.create_ecu_instance("ecu2", &package).unwrap();
728
729        let ecu1_communication_controller = ecu1.create_can_communication_controller("can_controller_1").unwrap();
730        let ecu2_communication_controller = ecu2.create_can_communication_controller("can_controller_2").unwrap();
731
732        let _connector1 = ecu1_communication_controller
733            .connect_physical_channel("Ecu1_connection", &can_physical_channel)
734            .unwrap();
735        let _connector2 = ecu2_communication_controller
736            .connect_physical_channel("Ecu2_connection", &can_physical_channel)
737            .unwrap();
738
739        let nm_pdu1 = system.create_nm_pdu("NmPdu1", &package, 8).unwrap();
740        let nm_pdu2 = system.create_nm_pdu("NmPdu2", &package, 8).unwrap();
741
742        //========= NM Config ==========
743
744        let nm_config = system.create_nm_config("NmConfig", &package).unwrap();
745
746        // ------ CAN NM cluster ------
747        let can_nm_cluster_settings = CanNmClusterSettings {
748            nm_busload_reduction_active: false,
749            nm_immediate_nm_transmissions: 22,
750            nm_message_timeout_time: 4.5,
751            nm_msg_cycle_time: 1.0,
752            nm_network_timeout: 9.0,
753            nm_remote_sleep_indication_time: 2.0,
754            nm_repeat_message_time: 2.0,
755            nm_wait_bus_sleep_time: 2.0,
756        };
757        let can_nm_cluster = nm_config
758            .create_can_nm_cluster("can_nm_cluster", &can_nm_cluster_settings, &can_cluster)
759            .unwrap();
760        assert_eq!(nm_config.nm_clusters().count(), 1);
761        let generic_cluster = nm_config.nm_clusters().next().unwrap();
762        assert_eq!(generic_cluster.element(), can_nm_cluster.element());
763        assert_eq!(can_nm_cluster.communication_cluster(), Some(can_cluster));
764        // verify settings
765        assert_eq!(can_nm_cluster.nm_busload_reduction_active(), Some(false));
766        assert_eq!(can_nm_cluster.nm_immediate_nm_transmissions(), Some(22));
767        assert_eq!(can_nm_cluster.nm_message_timeout_time(), Some(4.5));
768        assert_eq!(can_nm_cluster.nm_msg_cycle_time(), Some(1.0));
769        assert_eq!(can_nm_cluster.nm_network_timeout(), Some(9.0));
770        assert_eq!(can_nm_cluster.nm_remote_sleep_indication_time(), Some(2.0));
771        assert_eq!(can_nm_cluster.nm_repeat_message_time(), Some(2.0));
772        assert_eq!(can_nm_cluster.nm_wait_bus_sleep_time(), Some(2.0));
773        // test additional CanNmCluster properties
774        can_nm_cluster.set_channel_sleep_master(Some(true)).unwrap();
775        assert_eq!(can_nm_cluster.channel_sleep_master(), Some(true));
776        can_nm_cluster.set_node_detection_enabled(Some(false)).unwrap();
777        assert_eq!(can_nm_cluster.node_detection_enabled(), Some(false));
778        can_nm_cluster.set_node_id_enabled(Some(true)).unwrap();
779        assert_eq!(can_nm_cluster.node_id_enabled(), Some(true));
780        can_nm_cluster.set_pnc_participation(Some(true)).unwrap();
781        assert_eq!(can_nm_cluster.pnc_participation(), Some(true));
782        can_nm_cluster.set_repeat_msg_ind_enabled(Some(true)).unwrap();
783        assert_eq!(can_nm_cluster.repeat_msg_ind_enabled(), Some(true));
784        can_nm_cluster.set_synchronizing_network(Some(true)).unwrap();
785        assert_eq!(can_nm_cluster.synchronizing_network(), Some(true));
786        can_nm_cluster.set_pnc_cluster_vector_length(Some(3)).unwrap();
787        assert_eq!(can_nm_cluster.pnc_cluster_vector_length(), Some(3));
788        // remove optional values
789        can_nm_cluster.set_channel_sleep_master(None).unwrap();
790        assert_eq!(can_nm_cluster.channel_sleep_master(), None);
791        can_nm_cluster.set_node_detection_enabled(None).unwrap();
792        assert_eq!(can_nm_cluster.node_detection_enabled(), None);
793        can_nm_cluster.set_node_id_enabled(None).unwrap();
794        assert_eq!(can_nm_cluster.node_id_enabled(), None);
795        can_nm_cluster.set_pnc_participation(None).unwrap();
796        assert_eq!(can_nm_cluster.pnc_participation(), None);
797        can_nm_cluster.set_repeat_msg_ind_enabled(None).unwrap();
798        assert_eq!(can_nm_cluster.repeat_msg_ind_enabled(), None);
799        can_nm_cluster.set_synchronizing_network(None).unwrap();
800        assert_eq!(can_nm_cluster.synchronizing_network(), None);
801        can_nm_cluster.set_pnc_cluster_vector_length(None).unwrap();
802        assert_eq!(can_nm_cluster.pnc_cluster_vector_length(), None);
803
804        // ------ CAN NM ecu ------
805        let nm_ecu1 = nm_config.create_nm_ecu("nm_ecu1", &ecu1).unwrap();
806        let nm_ecu2 = nm_config.create_nm_ecu("nm_ecu2", &ecu2).unwrap();
807        assert_eq!(nm_config.nm_ecus().count(), 2);
808        assert_eq!(nm_ecu1.ecu_instance(), Some(ecu1));
809        assert_eq!(nm_ecu2.ecu_instance(), Some(ecu2));
810        nm_ecu1.set_nm_bus_synchronization_enabled(Some(true)).unwrap();
811        assert_eq!(nm_ecu1.nm_bus_synchronization_enabled(), Some(true));
812        nm_ecu1.set_nm_com_control_enabled(Some(true)).unwrap();
813        assert_eq!(nm_ecu1.nm_com_control_enabled(), Some(true));
814        nm_ecu1.set_cycle_time_main_function(Some(0.1)).unwrap();
815        assert_eq!(nm_ecu1.cycle_time_main_function(), Some(0.1));
816        // remove optional values
817        nm_ecu1.set_nm_bus_synchronization_enabled(None).unwrap();
818        assert_eq!(nm_ecu1.nm_bus_synchronization_enabled(), None);
819        nm_ecu1.set_nm_com_control_enabled(None).unwrap();
820        assert_eq!(nm_ecu1.nm_com_control_enabled(), None);
821        nm_ecu1.set_cycle_time_main_function(None).unwrap();
822        assert_eq!(nm_ecu1.cycle_time_main_function(), None);
823
824        // ------ CAN NM node ------
825        let nm_node1 = can_nm_cluster
826            .create_can_nm_node("can_nm_node1", &ecu1_communication_controller, &nm_ecu1)
827            .unwrap();
828        assert_eq!(nm_node1.communication_controller(), Some(ecu1_communication_controller));
829        assert_eq!(nm_node1.nm_ecu(), Some(nm_ecu1));
830        nm_node1.set_node_id(Some(1)).unwrap();
831        assert_eq!(nm_node1.node_id(), Some(1));
832        nm_node1.set_passive_mode(Some(false)).unwrap();
833        assert_eq!(nm_node1.passive_mode(), Some(false));
834
835        let nm_node2 = can_nm_cluster
836            .create_can_nm_node("can_nm_node2", &ecu2_communication_controller, &nm_ecu2)
837            .unwrap();
838        assert_eq!(can_nm_cluster.nm_nodes().count(), 2);
839        assert_eq!(nm_node2.communication_controller(), Some(ecu2_communication_controller));
840
841        nm_node1.add_rx_nm_pdu(&nm_pdu1).unwrap();
842        nm_node1.add_tx_nm_pdu(&nm_pdu2).unwrap();
843        assert_eq!(nm_node1.rx_nm_pdus().count(), 1);
844        assert_eq!(nm_node1.tx_nm_pdus().count(), 1);
845        nm_node2.add_rx_nm_pdu(&nm_pdu2).unwrap();
846        nm_node2.add_tx_nm_pdu(&nm_pdu1).unwrap();
847        assert_eq!(nm_node2.rx_nm_pdus().count(), 1);
848        assert_eq!(nm_node2.tx_nm_pdus().count(), 1);
849
850        assert_eq!(can_nm_cluster.nm_nodes().next().unwrap(), nm_node1);
851
852        // remove optional values
853        nm_node1.set_node_id(None).unwrap();
854        assert_eq!(nm_node1.node_id(), None);
855        nm_node1.set_passive_mode(None).unwrap();
856        assert_eq!(nm_node1.passive_mode(), None);
857
858        // ------ CAN NM Cluster Coupling ------
859        let cluster_coupling = nm_config.create_can_nm_cluster_coupling(true, true).unwrap();
860        assert_eq!(nm_config.nm_cluster_couplings().count(), 1);
861        assert_eq!(
862            nm_config.nm_cluster_couplings().next().unwrap().element(),
863            cluster_coupling.element()
864        );
865        assert_eq!(cluster_coupling.nm_busload_reduction_enabled(), Some(true));
866        assert_eq!(cluster_coupling.nm_immediate_restart_enabled(), Some(true));
867        cluster_coupling.add_coupled_cluster(&can_nm_cluster).unwrap();
868        assert_eq!(cluster_coupling.coupled_clusters().count(), 1);
869
870        // conversions
871        let can_nm_cluster2 = CanNmCluster::try_from(can_nm_cluster.element().clone()).unwrap();
872        assert_eq!(can_nm_cluster2, can_nm_cluster);
873        let nm_cluster2 = NmCluster::try_from(can_nm_cluster.element().clone()).unwrap();
874        assert_eq!(nm_cluster2, NmCluster::CanNm(can_nm_cluster));
875        let result = NmCluster::try_from(model.root_element());
876        assert!(result.is_err());
877        let cluster_coupling2 = CanNmClusterCoupling::try_from(cluster_coupling.element().clone()).unwrap();
878        assert_eq!(cluster_coupling2, cluster_coupling);
879        let coupling2 = NmClusterCoupling::try_from(cluster_coupling.element().clone()).unwrap();
880        assert_eq!(coupling2, NmClusterCoupling::CanNmClusterCoupling(cluster_coupling));
881        let result = NmClusterCoupling::try_from(model.root_element());
882        assert!(result.is_err());
883    }
884
885    #[test]
886    fn test_flexray_nm() {
887        let model = AutosarModelAbstraction::create("test", AutosarVersion::LATEST);
888        let package = model.get_or_create_package("/package").unwrap();
889        let system = package.create_system("System", SystemCategory::SystemExtract).unwrap();
890
891        let flexray_cluster = system
892            .create_flexray_cluster("flexray_cluster", &package, &FlexrayClusterSettings::default())
893            .unwrap();
894        let flexray_physical_channel = flexray_cluster
895            .create_physical_channel("flexray_channel", FlexrayChannelName::A)
896            .unwrap();
897        let ecu1 = system.create_ecu_instance("ecu1", &package).unwrap();
898        let ecu2 = system.create_ecu_instance("ecu2", &package).unwrap();
899
900        let ecu1_communication_controller = ecu1
901            .create_flexray_communication_controller("flexray_controller_1")
902            .unwrap();
903        let ecu2_communication_controller = ecu2
904            .create_flexray_communication_controller("flexray_controller_2")
905            .unwrap();
906
907        let _connector1 = ecu1_communication_controller
908            .connect_physical_channel("Ecu1_connection", &flexray_physical_channel)
909            .unwrap();
910        let _connector2 = ecu2_communication_controller
911            .connect_physical_channel("Ecu2_connection", &flexray_physical_channel)
912            .unwrap();
913
914        let nm_pdu1 = system.create_nm_pdu("NmPdu1", &package, 8).unwrap();
915        let nm_pdu2 = system.create_nm_pdu("NmPdu2", &package, 8).unwrap();
916
917        //========= NM Config ==========
918
919        let nm_config = system.create_nm_config("NmConfig", &package).unwrap();
920
921        // ------ Flexray NM cluster ------
922        let flexray_nm_cluster_settings = FlexrayNmClusterSettings {
923            nm_data_cycle: 1,
924            nm_remote_sleep_indication_time: 2.0,
925            nm_repeat_message_time: 3.0,
926            nm_repetition_cycle: 4,
927            nm_voting_cycle: 5,
928        };
929        let flexray_nm_cluster = nm_config
930            .create_flexray_nm_cluster("flexray_nm_cluster", &flexray_nm_cluster_settings, &flexray_cluster)
931            .unwrap();
932        assert_eq!(nm_config.nm_clusters().count(), 1);
933        let generic_cluster = nm_config.nm_clusters().next().unwrap();
934        assert_eq!(generic_cluster.element(), flexray_nm_cluster.element());
935        assert_eq!(flexray_nm_cluster.communication_cluster(), Some(flexray_cluster));
936        // verify settings
937        assert_eq!(flexray_nm_cluster.nm_data_cycle(), Some(1));
938        assert_eq!(flexray_nm_cluster.nm_remote_sleep_indication_time(), Some(2.0));
939        assert_eq!(flexray_nm_cluster.nm_repeat_message_time(), Some(3.0));
940        assert_eq!(flexray_nm_cluster.nm_repetition_cycle(), Some(4));
941        assert_eq!(flexray_nm_cluster.nm_voting_cycle(), Some(5));
942        // test additional FlexrayNmCluster properties
943        flexray_nm_cluster.set_channel_sleep_master(Some(true)).unwrap();
944        assert_eq!(flexray_nm_cluster.channel_sleep_master(), Some(true));
945        flexray_nm_cluster.set_node_detection_enabled(Some(false)).unwrap();
946        assert_eq!(flexray_nm_cluster.node_detection_enabled(), Some(false));
947        flexray_nm_cluster.set_node_id_enabled(Some(true)).unwrap();
948        assert_eq!(flexray_nm_cluster.node_id_enabled(), Some(true));
949        flexray_nm_cluster.set_pnc_participation(Some(true)).unwrap();
950        assert_eq!(flexray_nm_cluster.pnc_participation(), Some(true));
951        flexray_nm_cluster.set_repeat_msg_ind_enabled(Some(true)).unwrap();
952        assert_eq!(flexray_nm_cluster.repeat_msg_ind_enabled(), Some(true));
953        flexray_nm_cluster.set_synchronizing_network(Some(true)).unwrap();
954        assert_eq!(flexray_nm_cluster.synchronizing_network(), Some(true));
955        flexray_nm_cluster.set_pnc_cluster_vector_length(Some(3)).unwrap();
956        assert_eq!(flexray_nm_cluster.pnc_cluster_vector_length(), Some(3));
957        // remove optional values
958        flexray_nm_cluster.set_channel_sleep_master(None).unwrap();
959        assert_eq!(flexray_nm_cluster.channel_sleep_master(), None);
960        flexray_nm_cluster.set_node_detection_enabled(None).unwrap();
961        assert_eq!(flexray_nm_cluster.node_detection_enabled(), None);
962        flexray_nm_cluster.set_node_id_enabled(None).unwrap();
963        assert_eq!(flexray_nm_cluster.node_id_enabled(), None);
964        flexray_nm_cluster.set_pnc_participation(None).unwrap();
965        assert_eq!(flexray_nm_cluster.pnc_participation(), None);
966        flexray_nm_cluster.set_repeat_msg_ind_enabled(None).unwrap();
967        assert_eq!(flexray_nm_cluster.repeat_msg_ind_enabled(), None);
968        flexray_nm_cluster.set_synchronizing_network(None).unwrap();
969        assert_eq!(flexray_nm_cluster.synchronizing_network(), None);
970        flexray_nm_cluster.set_pnc_cluster_vector_length(None).unwrap();
971        assert_eq!(flexray_nm_cluster.pnc_cluster_vector_length(), None);
972
973        // ------ Flexray NM ecu ------
974        let nm_ecu1 = nm_config.create_nm_ecu("nm_ecu1", &ecu1).unwrap();
975        let nm_ecu2 = nm_config.create_nm_ecu("nm_ecu2", &ecu2).unwrap();
976        assert_eq!(nm_config.nm_ecus().count(), 2);
977        assert_eq!(nm_ecu1.ecu_instance(), Some(ecu1));
978        assert_eq!(nm_ecu2.ecu_instance(), Some(ecu2));
979        nm_ecu1.set_nm_bus_synchronization_enabled(Some(true)).unwrap();
980        assert_eq!(nm_ecu1.nm_bus_synchronization_enabled(), Some(true));
981        nm_ecu1.set_nm_com_control_enabled(Some(true)).unwrap();
982        assert_eq!(nm_ecu1.nm_com_control_enabled(), Some(true));
983        nm_ecu1.set_cycle_time_main_function(Some(0.1)).unwrap();
984        assert_eq!(nm_ecu1.cycle_time_main_function(), Some(0.1));
985
986        // ------ Flexray NM node ------
987        let nm_node1 = flexray_nm_cluster
988            .create_flexray_nm_node("flexray_nm_node1", &ecu1_communication_controller, &nm_ecu1)
989            .unwrap();
990        assert_eq!(nm_node1.communication_controller(), Some(ecu1_communication_controller));
991        assert_eq!(nm_node1.nm_ecu(), Some(nm_ecu1));
992        nm_node1.set_node_id(Some(1)).unwrap();
993        assert_eq!(nm_node1.node_id(), Some(1));
994        nm_node1.set_passive_mode(Some(false)).unwrap();
995        assert_eq!(nm_node1.passive_mode(), Some(false));
996
997        let nm_node2 = flexray_nm_cluster
998            .create_flexray_nm_node("flexray_nm_node2", &ecu2_communication_controller, &nm_ecu2)
999            .unwrap();
1000        assert_eq!(flexray_nm_cluster.nm_nodes().count(), 2);
1001        assert_eq!(nm_node2.communication_controller(), Some(ecu2_communication_controller));
1002
1003        nm_node1.add_rx_nm_pdu(&nm_pdu1).unwrap();
1004        nm_node1.add_tx_nm_pdu(&nm_pdu2).unwrap();
1005        assert_eq!(nm_node1.rx_nm_pdus().count(), 1);
1006        assert_eq!(nm_node1.tx_nm_pdus().count(), 1);
1007        nm_node2.add_rx_nm_pdu(&nm_pdu2).unwrap();
1008        nm_node2.add_tx_nm_pdu(&nm_pdu1).unwrap();
1009        assert_eq!(nm_node2.rx_nm_pdus().count(), 1);
1010        assert_eq!(nm_node2.tx_nm_pdus().count(), 1);
1011
1012        assert_eq!(flexray_nm_cluster.nm_nodes().next().unwrap(), nm_node1);
1013
1014        // remove optional values
1015        nm_node1.set_node_id(None).unwrap();
1016        assert_eq!(nm_node1.node_id(), None);
1017        nm_node1.set_passive_mode(None).unwrap();
1018        assert_eq!(nm_node1.passive_mode(), None);
1019
1020        // ------ Flexray NM Cluster Coupling ------
1021        let cluster_coupling = nm_config
1022            .create_flexray_nm_cluster_coupling(FlexrayNmScheduleVariant::ScheduleVariant6)
1023            .unwrap();
1024        assert_eq!(nm_config.nm_cluster_couplings().count(), 1);
1025        assert_eq!(
1026            cluster_coupling.nm_schedule_variant(),
1027            Some(FlexrayNmScheduleVariant::ScheduleVariant6)
1028        );
1029        cluster_coupling.add_coupled_cluster(&flexray_nm_cluster).unwrap();
1030        assert_eq!(cluster_coupling.coupled_clusters().count(), 1);
1031
1032        // ------ Flexray Schedule Variant ------
1033        assert_eq!(
1034            EnumItem::from(FlexrayNmScheduleVariant::ScheduleVariant1),
1035            EnumItem::ScheduleVariant1
1036        );
1037        assert_eq!(
1038            EnumItem::from(FlexrayNmScheduleVariant::ScheduleVariant2),
1039            EnumItem::ScheduleVariant2
1040        );
1041        assert_eq!(
1042            EnumItem::from(FlexrayNmScheduleVariant::ScheduleVariant3),
1043            EnumItem::ScheduleVariant3
1044        );
1045        assert_eq!(
1046            EnumItem::from(FlexrayNmScheduleVariant::ScheduleVariant4),
1047            EnumItem::ScheduleVariant4
1048        );
1049        assert_eq!(
1050            EnumItem::from(FlexrayNmScheduleVariant::ScheduleVariant5),
1051            EnumItem::ScheduleVariant5
1052        );
1053        assert_eq!(
1054            EnumItem::from(FlexrayNmScheduleVariant::ScheduleVariant6),
1055            EnumItem::ScheduleVariant6
1056        );
1057        assert_eq!(
1058            EnumItem::from(FlexrayNmScheduleVariant::ScheduleVariant7),
1059            EnumItem::ScheduleVariant7
1060        );
1061
1062        assert_eq!(
1063            FlexrayNmScheduleVariant::try_from(EnumItem::ScheduleVariant1).unwrap(),
1064            FlexrayNmScheduleVariant::ScheduleVariant1
1065        );
1066        assert_eq!(
1067            FlexrayNmScheduleVariant::try_from(EnumItem::ScheduleVariant2).unwrap(),
1068            FlexrayNmScheduleVariant::ScheduleVariant2
1069        );
1070        assert_eq!(
1071            FlexrayNmScheduleVariant::try_from(EnumItem::ScheduleVariant3).unwrap(),
1072            FlexrayNmScheduleVariant::ScheduleVariant3
1073        );
1074        assert_eq!(
1075            FlexrayNmScheduleVariant::try_from(EnumItem::ScheduleVariant4).unwrap(),
1076            FlexrayNmScheduleVariant::ScheduleVariant4
1077        );
1078        assert_eq!(
1079            FlexrayNmScheduleVariant::try_from(EnumItem::ScheduleVariant5).unwrap(),
1080            FlexrayNmScheduleVariant::ScheduleVariant5
1081        );
1082        assert_eq!(
1083            FlexrayNmScheduleVariant::try_from(EnumItem::ScheduleVariant6).unwrap(),
1084            FlexrayNmScheduleVariant::ScheduleVariant6
1085        );
1086        assert_eq!(
1087            FlexrayNmScheduleVariant::try_from(EnumItem::ScheduleVariant7).unwrap(),
1088            FlexrayNmScheduleVariant::ScheduleVariant7
1089        );
1090        assert!(FlexrayNmScheduleVariant::try_from(EnumItem::Aa).is_err());
1091
1092        // Cluster Coupling conversions
1093        let cluster_coupling2 = nm_config.nm_cluster_couplings().next().unwrap();
1094        assert_eq!(cluster_coupling.element(), cluster_coupling2.element());
1095    }
1096
1097    #[test]
1098    fn test_udp_nm() {
1099        let model = AutosarModelAbstraction::create("test", AutosarVersion::LATEST);
1100        let package = model.get_or_create_package("/package").unwrap();
1101        let system = package.create_system("System", SystemCategory::SystemExtract).unwrap();
1102
1103        let ethernet_cluster = system.create_ethernet_cluster("ethernet_cluster", &package).unwrap();
1104        let ethernet_physical_channel = ethernet_cluster
1105            .create_physical_channel("ethernet_channel", None)
1106            .unwrap();
1107        let ecu1 = system.create_ecu_instance("ecu1", &package).unwrap();
1108        let ecu2 = system.create_ecu_instance("ecu2", &package).unwrap();
1109
1110        let ecu1_communication_controller = ecu1
1111            .create_ethernet_communication_controller("udp_controller_1", None)
1112            .unwrap();
1113        let ecu2_communication_controller = ecu2
1114            .create_ethernet_communication_controller("udp_controller_2", None)
1115            .unwrap();
1116
1117        let _connector1 = ecu1_communication_controller
1118            .connect_physical_channel("Ecu1_connection", &ethernet_physical_channel)
1119            .unwrap();
1120        let _connector2 = ecu2_communication_controller
1121            .connect_physical_channel("Ecu2_connection", &ethernet_physical_channel)
1122            .unwrap();
1123
1124        let nm_pdu1 = system.create_nm_pdu("NmPdu1", &package, 8).unwrap();
1125        let nm_pdu2 = system.create_nm_pdu("NmPdu2", &package, 8).unwrap();
1126
1127        //========= NM Config ==========
1128
1129        let nm_config = system.create_nm_config("NmConfig", &package).unwrap();
1130
1131        // ------ UDP NM cluster ------
1132        let udp_nm_cluster_settings = UdpNmClusterSettings {
1133            nm_msg_cycle_time: 1.0,
1134            nm_msg_timeout_time: 2.0,
1135            nm_network_timeout: 3.0,
1136            nm_remote_sleep_indication_time: 4.0,
1137            nm_repeat_message_time: 5.0,
1138            nm_wait_bus_sleep_time: 6.0,
1139        };
1140        let udp_nm_cluster = nm_config
1141            .create_udp_nm_cluster("udp_nm_cluster", &udp_nm_cluster_settings, &ethernet_cluster)
1142            .unwrap();
1143        assert_eq!(nm_config.nm_clusters().count(), 1);
1144        let generic_cluster = nm_config.nm_clusters().next().unwrap();
1145        assert_eq!(generic_cluster.element(), udp_nm_cluster.element());
1146        assert_eq!(udp_nm_cluster.communication_cluster(), Some(ethernet_cluster));
1147        // verify settings
1148        assert_eq!(udp_nm_cluster.nm_msg_cycle_time(), Some(1.0));
1149        assert_eq!(udp_nm_cluster.nm_message_timeout_time(), Some(2.0));
1150        assert_eq!(udp_nm_cluster.nm_network_timeout(), Some(3.0));
1151        assert_eq!(udp_nm_cluster.nm_remote_sleep_indication_time(), Some(4.0));
1152        assert_eq!(udp_nm_cluster.nm_repeat_message_time(), Some(5.0));
1153        assert_eq!(udp_nm_cluster.nm_wait_bus_sleep_time(), Some(6.0));
1154        // test additional UdpNmCluster properties
1155        udp_nm_cluster.set_channel_sleep_master(Some(true)).unwrap();
1156        assert_eq!(udp_nm_cluster.channel_sleep_master(), Some(true));
1157        udp_nm_cluster.set_node_detection_enabled(Some(false)).unwrap();
1158        assert_eq!(udp_nm_cluster.node_detection_enabled(), Some(false));
1159        udp_nm_cluster.set_nm_cbv_position(Some(33)).unwrap();
1160        assert_eq!(udp_nm_cluster.nm_cbv_position(), Some(33));
1161        udp_nm_cluster.set_nm_immediate_nm_transmissions(Some(11)).unwrap();
1162        assert_eq!(udp_nm_cluster.nm_immediate_nm_transmissions(), Some(11));
1163        udp_nm_cluster.set_vlan(Some(&ethernet_physical_channel)).unwrap();
1164        assert_eq!(udp_nm_cluster.vlan(), Some(ethernet_physical_channel));
1165        udp_nm_cluster.set_nm_nid_position(Some(3)).unwrap();
1166        assert_eq!(udp_nm_cluster.nm_nid_position(), Some(3));
1167        udp_nm_cluster.set_node_id_enabled(Some(true)).unwrap();
1168        assert_eq!(udp_nm_cluster.node_id_enabled(), Some(true));
1169        udp_nm_cluster.set_pnc_participation(Some(true)).unwrap();
1170        assert_eq!(udp_nm_cluster.pnc_participation(), Some(true));
1171        udp_nm_cluster.set_repeat_msg_ind_enabled(Some(true)).unwrap();
1172        assert_eq!(udp_nm_cluster.repeat_msg_ind_enabled(), Some(true));
1173        udp_nm_cluster.set_synchronizing_network(Some(true)).unwrap();
1174        assert_eq!(udp_nm_cluster.synchronizing_network(), Some(true));
1175        udp_nm_cluster.set_pnc_cluster_vector_length(Some(3)).unwrap();
1176        assert_eq!(udp_nm_cluster.pnc_cluster_vector_length(), Some(3));
1177        // remove optional values
1178        udp_nm_cluster.set_channel_sleep_master(None).unwrap();
1179        assert_eq!(udp_nm_cluster.channel_sleep_master(), None);
1180        udp_nm_cluster.set_node_detection_enabled(None).unwrap();
1181        assert_eq!(udp_nm_cluster.node_detection_enabled(), None);
1182        udp_nm_cluster.set_nm_cbv_position(None).unwrap();
1183        assert_eq!(udp_nm_cluster.nm_cbv_position(), None);
1184        udp_nm_cluster.set_nm_immediate_nm_transmissions(None).unwrap();
1185        assert_eq!(udp_nm_cluster.nm_immediate_nm_transmissions(), None);
1186        udp_nm_cluster.set_vlan(None).unwrap();
1187        assert_eq!(udp_nm_cluster.vlan(), None);
1188        udp_nm_cluster.set_nm_nid_position(None).unwrap();
1189        assert_eq!(udp_nm_cluster.nm_nid_position(), None);
1190        udp_nm_cluster.set_node_id_enabled(None).unwrap();
1191        assert_eq!(udp_nm_cluster.node_id_enabled(), None);
1192        udp_nm_cluster.set_pnc_participation(None).unwrap();
1193        assert_eq!(udp_nm_cluster.pnc_participation(), None);
1194        udp_nm_cluster.set_repeat_msg_ind_enabled(None).unwrap();
1195        assert_eq!(udp_nm_cluster.repeat_msg_ind_enabled(), None);
1196        udp_nm_cluster.set_synchronizing_network(None).unwrap();
1197        assert_eq!(udp_nm_cluster.synchronizing_network(), None);
1198        udp_nm_cluster.set_pnc_cluster_vector_length(None).unwrap();
1199        assert_eq!(udp_nm_cluster.pnc_cluster_vector_length(), None);
1200
1201        // ------ UDP NM ecu ------
1202        let nm_ecu1 = nm_config.create_nm_ecu("nm_ecu1", &ecu1).unwrap();
1203        let nm_ecu2 = nm_config.create_nm_ecu("nm_ecu2", &ecu2).unwrap();
1204        assert_eq!(nm_config.nm_ecus().count(), 2);
1205        assert_eq!(nm_ecu1.ecu_instance(), Some(ecu1));
1206        assert_eq!(nm_ecu2.ecu_instance(), Some(ecu2));
1207        nm_ecu1.set_nm_bus_synchronization_enabled(Some(true)).unwrap();
1208        assert_eq!(nm_ecu1.nm_bus_synchronization_enabled(), Some(true));
1209        nm_ecu1.set_nm_com_control_enabled(Some(true)).unwrap();
1210        assert_eq!(nm_ecu1.nm_com_control_enabled(), Some(true));
1211        nm_ecu1.set_cycle_time_main_function(Some(0.1)).unwrap();
1212        assert_eq!(nm_ecu1.cycle_time_main_function(), Some(0.1));
1213
1214        // ------ UDP NM node ------
1215        let nm_node1 = udp_nm_cluster
1216            .create_udp_nm_node("udp_nm_node1", &ecu1_communication_controller, &nm_ecu1, 0.1)
1217            .unwrap();
1218        assert_eq!(nm_node1.communication_controller(), Some(ecu1_communication_controller));
1219        assert_eq!(nm_node1.nm_ecu(), Some(nm_ecu1));
1220        assert_eq!(nm_node1.nm_msg_cycle_offset(), Some(0.1));
1221        nm_node1.set_node_id(Some(1)).unwrap();
1222        assert_eq!(nm_node1.node_id(), Some(1));
1223        nm_node1.set_passive_mode(Some(false)).unwrap();
1224        assert_eq!(nm_node1.passive_mode(), Some(false));
1225        nm_node1.set_all_nm_messages_keep_awake(Some(true)).unwrap();
1226        assert_eq!(nm_node1.all_nm_messages_keep_awake(), Some(true));
1227
1228        let nm_node2 = udp_nm_cluster
1229            .create_udp_nm_node("udp_nm_node2", &ecu2_communication_controller, &nm_ecu2, 0.1)
1230            .unwrap();
1231        assert_eq!(udp_nm_cluster.nm_nodes().count(), 2);
1232        assert_eq!(nm_node2.communication_controller(), Some(ecu2_communication_controller));
1233
1234        nm_node1.add_rx_nm_pdu(&nm_pdu1).unwrap();
1235        nm_node1.add_tx_nm_pdu(&nm_pdu2).unwrap();
1236        assert_eq!(nm_node1.rx_nm_pdus().count(), 1);
1237        assert_eq!(nm_node1.tx_nm_pdus().count(), 1);
1238        nm_node2.add_rx_nm_pdu(&nm_pdu2).unwrap();
1239        nm_node2.add_tx_nm_pdu(&nm_pdu1).unwrap();
1240        assert_eq!(nm_node2.rx_nm_pdus().count(), 1);
1241        assert_eq!(nm_node2.tx_nm_pdus().count(), 1);
1242
1243        assert_eq!(udp_nm_cluster.nm_nodes().next().unwrap(), nm_node1);
1244
1245        // remove optional values
1246        nm_node1.set_node_id(None).unwrap();
1247        assert_eq!(nm_node1.node_id(), None);
1248        nm_node1.set_passive_mode(None).unwrap();
1249        assert_eq!(nm_node1.passive_mode(), None);
1250        nm_node1.set_all_nm_messages_keep_awake(None).unwrap();
1251        assert_eq!(nm_node1.all_nm_messages_keep_awake(), None);
1252
1253        // ------ UDP NM Cluster Coupling ------
1254
1255        let cluster_coupling = nm_config.create_udp_nm_cluster_coupling().unwrap();
1256        assert_eq!(nm_config.nm_cluster_couplings().count(), 1);
1257        cluster_coupling.add_coupled_cluster(&udp_nm_cluster).unwrap();
1258        assert_eq!(cluster_coupling.coupled_clusters().count(), 1);
1259        cluster_coupling.set_nm_immediate_restart_enabled(Some(true)).unwrap();
1260        assert_eq!(cluster_coupling.nm_immediate_restart_enabled(), Some(true));
1261        // remove optional values
1262        cluster_coupling.set_nm_immediate_restart_enabled(None).unwrap();
1263        assert_eq!(cluster_coupling.nm_immediate_restart_enabled(), None);
1264
1265        // Cluster Coupling conversions
1266        let cluster_coupling2 = nm_config.nm_cluster_couplings().next().unwrap();
1267        assert_eq!(cluster_coupling.element(), cluster_coupling2.element());
1268    }
1269}