autosar_data_abstraction/communication/cluster/
ethernet.rs

1use crate::communication::{AbstractCluster, EthernetPhysicalChannel, EthernetVlanInfo};
2use crate::{
3    AbstractionElement, ArPackage, AutosarAbstractionError, IdentifiableAbstractionElement, abstraction_element,
4};
5use autosar_data::{Element, ElementName};
6
7/// An `EthernetCluster` contains all configuration items associated with an ethernet network.
8/// The cluster connects multiple ECUs.
9#[derive(Debug, Clone, PartialEq, Eq, Hash)]
10pub struct EthernetCluster(Element);
11abstraction_element!(EthernetCluster, EthernetCluster);
12impl IdentifiableAbstractionElement for EthernetCluster {}
13
14impl EthernetCluster {
15    // create a new EthernetCluster - for internal use. User code should call System::create_ethernet_cluster
16    pub(crate) fn new(cluster_name: &str, package: &ArPackage) -> Result<Self, AutosarAbstractionError> {
17        let elem_pkg_elements = package.element().get_or_create_sub_element(ElementName::Elements)?;
18        let elem_cluster = elem_pkg_elements.create_named_sub_element(ElementName::EthernetCluster, cluster_name)?;
19        if let Ok(cluster_content) = elem_cluster
20            .create_sub_element(ElementName::EthernetClusterVariants)
21            .and_then(|ecv| ecv.create_sub_element(ElementName::EthernetClusterConditional))
22        {
23            let _ = cluster_content.create_sub_element(ElementName::PhysicalChannels);
24        }
25
26        Ok(EthernetCluster(elem_cluster))
27    }
28
29    /// Create a new physical channel for the cluster
30    ///
31    /// The supplied VLAN info must be unique - there cannot be two VLANs with the same vlan identifier.
32    /// One channel may be created without VLAN information; it carries untagged traffic.
33    ///
34    /// # Example
35    ///
36    /// ```
37    /// # use autosar_data::*;
38    /// # use autosar_data_abstraction::*;
39    /// # use autosar_data_abstraction::communication::*;
40    /// # fn main() -> Result<(), AutosarAbstractionError> {
41    /// # let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
42    /// # let package = model.get_or_create_package("/pkg1")?;
43    /// # let system = package.create_system("System", SystemCategory::SystemExtract)?;
44    /// let cluster = system.create_ethernet_cluster("Cluster", &package)?;
45    /// let vlan_info = EthernetVlanInfo {
46    ///     vlan_name: "VLAN_1".to_string(),
47    ///     vlan_id: 1,
48    /// };
49    /// let channel = cluster.create_physical_channel("Channel", Some(&vlan_info))?;
50    /// # Ok(())}
51    /// ```
52    ///
53    /// # Errors
54    ///
55    /// - [`AutosarAbstractionError::ItemAlreadyExists`] There is already a physical channel for this VLAN
56    /// - [`AutosarAbstractionError::ModelError`] An error occurred in the Autosar model while trying to create the ECU-INSTANCE
57    pub fn create_physical_channel(
58        &self,
59        channel_name: &str,
60        vlan_info: Option<&EthernetVlanInfo>,
61    ) -> Result<EthernetPhysicalChannel, AutosarAbstractionError> {
62        let phys_channels = self
63            .0
64            .get_or_create_sub_element(ElementName::EthernetClusterVariants)?
65            .get_or_create_sub_element(ElementName::EthernetClusterConditional)?
66            .get_or_create_sub_element(ElementName::PhysicalChannels)?;
67
68        EthernetPhysicalChannel::new(channel_name, &phys_channels, vlan_info)
69    }
70
71    /// returns an iterator over all [`EthernetPhysicalChannel`]s in the cluster
72    ///
73    /// # Example
74    ///
75    /// ```
76    /// # use autosar_data::*;
77    /// # use autosar_data_abstraction::*;
78    /// # fn main() -> Result<(), AutosarAbstractionError> {
79    /// # let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
80    /// # let package = model.get_or_create_package("/pkg1")?;
81    /// # let system = package.create_system("System", SystemCategory::SystemExtract)?;
82    /// # let cluster = system.create_ethernet_cluster("Cluster", &package)?;
83    /// cluster.create_physical_channel("Channel", None)?;
84    /// for channel in cluster.physical_channels() {
85    ///     // ...
86    /// }
87    /// # Ok(())}
88    /// ```
89    pub fn physical_channels(&self) -> impl Iterator<Item = EthernetPhysicalChannel> + Send + use<> {
90        self.element()
91            .get_sub_element(ElementName::EthernetClusterVariants)
92            .and_then(|ecv| ecv.get_sub_element(ElementName::EthernetClusterConditional))
93            .and_then(|ecc| ecc.get_sub_element(ElementName::PhysicalChannels))
94            .into_iter()
95            .flat_map(|phys_channel| phys_channel.sub_elements())
96            .filter_map(|elem| EthernetPhysicalChannel::try_from(elem).ok())
97    }
98}
99
100impl AbstractCluster for EthernetCluster {}
101
102//##################################################################
103
104#[cfg(test)]
105mod test {
106    use crate::{
107        AutosarModelAbstraction, SystemCategory,
108        communication::{AbstractCluster, EthernetVlanInfo},
109    };
110    use autosar_data::AutosarVersion;
111
112    #[test]
113    fn cluster() {
114        let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
115        let pkg = model.get_or_create_package("/test").unwrap();
116        let system = pkg.create_system("System", SystemCategory::SystemDescription).unwrap();
117
118        let pkg2 = model.get_or_create_package("/ethernet").unwrap();
119        // create the ethernet cluster EthCluster
120        let result = system.create_ethernet_cluster("EthCluster", &pkg2);
121        assert!(result.is_ok());
122        let cluster = result.unwrap();
123        // creating the same cluster again is not possible
124        let result = system.create_ethernet_cluster("EthCluster", &pkg2);
125        assert!(result.is_err());
126
127        // system link
128        let linked_system = cluster.system().unwrap();
129        assert_eq!(linked_system, system);
130
131        // create an untagged channel
132        let result = cluster.create_physical_channel("Channel1", None);
133        assert!(result.is_ok());
134        // can't create a second untagged channel
135        let result = cluster.create_physical_channel("Channel2", None);
136        assert!(result.is_err());
137
138        // create a channel for VLAN 1
139        let vlan_info = EthernetVlanInfo {
140            vlan_name: "VLAN_1".to_string(),
141            vlan_id: 1,
142        };
143        let result = cluster.create_physical_channel("Channel3", Some(&vlan_info));
144        assert!(result.is_ok());
145
146        // can't create a second channel called Channel3
147        let vlan_info = EthernetVlanInfo {
148            vlan_name: "VLAN_2".to_string(),
149            vlan_id: 2,
150        };
151        let result = cluster.create_physical_channel("Channel3", Some(&vlan_info));
152        assert!(result.is_err());
153
154        // create a channel for VLAN 2
155        let vlan_info = EthernetVlanInfo {
156            vlan_name: "VLAN_2".to_string(),
157            vlan_id: 2,
158        };
159        let result = cluster.create_physical_channel("Channel4", Some(&vlan_info));
160        assert!(result.is_ok());
161
162        // can't create a second channel for VLAN 2
163        let vlan_info = EthernetVlanInfo {
164            vlan_name: "VLAN_2".to_string(),
165            vlan_id: 2,
166        };
167        let result = cluster.create_physical_channel("Channel5", Some(&vlan_info));
168        assert!(result.is_err());
169
170        let count = cluster.physical_channels().count();
171        assert_eq!(count, 3);
172    }
173}