autosar_data_abstraction/communication/cluster/
ethernet.rs

1use crate::communication::{
2    AbstractCluster, DoIpTpConfig, EthernetPhysicalChannel, EthernetVlanInfo, SomeipTpConfig, UdpNmCluster,
3};
4use crate::{
5    AbstractionElement, ArPackage, AutosarAbstractionError, IdentifiableAbstractionElement, abstraction_element,
6    get_reference_parents,
7};
8use autosar_data::{Element, ElementName};
9
10/// An `EthernetCluster` contains all configuration items associated with an ethernet network.
11/// The cluster connects multiple ECUs.
12#[derive(Debug, Clone, PartialEq, Eq, Hash)]
13pub struct EthernetCluster(Element);
14abstraction_element!(EthernetCluster, EthernetCluster);
15impl IdentifiableAbstractionElement for EthernetCluster {}
16
17impl EthernetCluster {
18    // create a new EthernetCluster - for internal use. User code should call System::create_ethernet_cluster
19    pub(crate) fn new(cluster_name: &str, package: &ArPackage) -> Result<Self, AutosarAbstractionError> {
20        let elem_pkg_elements = package.element().get_or_create_sub_element(ElementName::Elements)?;
21        let elem_cluster = elem_pkg_elements.create_named_sub_element(ElementName::EthernetCluster, cluster_name)?;
22        if let Ok(cluster_content) = elem_cluster
23            .create_sub_element(ElementName::EthernetClusterVariants)
24            .and_then(|ecv| ecv.create_sub_element(ElementName::EthernetClusterConditional))
25        {
26            let _ = cluster_content.create_sub_element(ElementName::PhysicalChannels);
27        }
28
29        Ok(EthernetCluster(elem_cluster))
30    }
31
32    /// remove this `EthernetCluster` from the model
33    pub fn remove(self, deep: bool) -> Result<(), AutosarAbstractionError> {
34        // remove all the physical channels
35        for channel in self.physical_channels() {
36            channel.remove(deep)?;
37        }
38        let ref_parents = get_reference_parents(self.element())?;
39
40        // delegate to the trait implementation to clean up all other references to the element and the element itself
41        AbstractionElement::remove(self, deep)?;
42
43        // check if any DoipTpConfig, or UdpNmCluster or SomeIpTpConfig uses this EthernetCluster
44        // The cluster reference is mandatory these elements, so we remove them together with the cluster
45        for (named_parent, _parent) in ref_parents {
46            match named_parent.element_name() {
47                ElementName::DoIpTpConfig => {
48                    if let Ok(doip_tp_config) = DoIpTpConfig::try_from(named_parent) {
49                        doip_tp_config.remove(deep)?;
50                    }
51                }
52                ElementName::UdpNmCluster => {
53                    if let Ok(udp_nm_cluster) = UdpNmCluster::try_from(named_parent) {
54                        udp_nm_cluster.remove(deep)?;
55                    }
56                }
57                ElementName::SomeipTpConfig => {
58                    if let Ok(someip_tp_config) = SomeipTpConfig::try_from(named_parent) {
59                        someip_tp_config.remove(deep)?;
60                    }
61                }
62                _ => {}
63            }
64        }
65
66        Ok(())
67    }
68
69    /// Create a new physical channel for the cluster
70    ///
71    /// The supplied VLAN info must be unique - there cannot be two VLANs with the same vlan identifier.
72    /// One channel may be created without VLAN information; it carries untagged traffic.
73    ///
74    /// # Example
75    ///
76    /// ```
77    /// # use autosar_data::*;
78    /// # use autosar_data_abstraction::*;
79    /// # use autosar_data_abstraction::communication::*;
80    /// # fn main() -> Result<(), AutosarAbstractionError> {
81    /// # let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
82    /// # let package = model.get_or_create_package("/pkg1")?;
83    /// # let system = package.create_system("System", SystemCategory::SystemExtract)?;
84    /// let cluster = system.create_ethernet_cluster("Cluster", &package)?;
85    /// let vlan_info = EthernetVlanInfo {
86    ///     vlan_name: "VLAN_1".to_string(),
87    ///     vlan_id: 1,
88    /// };
89    /// let channel = cluster.create_physical_channel("Channel", Some(&vlan_info))?;
90    /// # Ok(())}
91    /// ```
92    ///
93    /// # Errors
94    ///
95    /// - [`AutosarAbstractionError::ItemAlreadyExists`] There is already a physical channel for this VLAN
96    /// - [`AutosarAbstractionError::ModelError`] An error occurred in the Autosar model while trying to create the ECU-INSTANCE
97    pub fn create_physical_channel(
98        &self,
99        channel_name: &str,
100        vlan_info: Option<&EthernetVlanInfo>,
101    ) -> Result<EthernetPhysicalChannel, AutosarAbstractionError> {
102        let phys_channels = self
103            .0
104            .get_or_create_sub_element(ElementName::EthernetClusterVariants)?
105            .get_or_create_sub_element(ElementName::EthernetClusterConditional)?
106            .get_or_create_sub_element(ElementName::PhysicalChannels)?;
107
108        EthernetPhysicalChannel::new(channel_name, &phys_channels, vlan_info)
109    }
110
111    /// returns an iterator over all [`EthernetPhysicalChannel`]s in the cluster
112    ///
113    /// # Example
114    ///
115    /// ```
116    /// # use autosar_data::*;
117    /// # use autosar_data_abstraction::*;
118    /// # fn main() -> Result<(), AutosarAbstractionError> {
119    /// # let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
120    /// # let package = model.get_or_create_package("/pkg1")?;
121    /// # let system = package.create_system("System", SystemCategory::SystemExtract)?;
122    /// # let cluster = system.create_ethernet_cluster("Cluster", &package)?;
123    /// cluster.create_physical_channel("Channel", None)?;
124    /// for channel in cluster.physical_channels() {
125    ///     // ...
126    /// }
127    /// # Ok(())}
128    /// ```
129    pub fn physical_channels(&self) -> impl Iterator<Item = EthernetPhysicalChannel> + Send + use<> {
130        self.element()
131            .get_sub_element(ElementName::EthernetClusterVariants)
132            .and_then(|ecv| ecv.get_sub_element(ElementName::EthernetClusterConditional))
133            .and_then(|ecc| ecc.get_sub_element(ElementName::PhysicalChannels))
134            .into_iter()
135            .flat_map(|phys_channel| phys_channel.sub_elements())
136            .filter_map(|elem| EthernetPhysicalChannel::try_from(elem).ok())
137    }
138}
139
140impl AbstractCluster for EthernetCluster {}
141
142//##################################################################
143
144#[cfg(test)]
145mod test {
146    use crate::{
147        AbstractionElement, AutosarModelAbstraction, SystemCategory,
148        communication::{AbstractCluster, EthernetVlanInfo, UdpNmClusterSettings},
149    };
150    use autosar_data::AutosarVersion;
151
152    #[test]
153    fn cluster() {
154        let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
155        let pkg = model.get_or_create_package("/test").unwrap();
156        let system = pkg.create_system("System", SystemCategory::SystemDescription).unwrap();
157
158        let pkg2 = model.get_or_create_package("/ethernet").unwrap();
159        // create the ethernet cluster EthCluster
160        let result = system.create_ethernet_cluster("EthCluster", &pkg2);
161        assert!(result.is_ok());
162        let cluster = result.unwrap();
163        // creating the same cluster again is not possible
164        let result = system.create_ethernet_cluster("EthCluster", &pkg2);
165        assert!(result.is_err());
166
167        // system link
168        let linked_system = cluster.system().unwrap();
169        assert_eq!(linked_system, system);
170
171        // create an untagged channel
172        let result = cluster.create_physical_channel("Channel1", None);
173        assert!(result.is_ok());
174        // can't create a second untagged channel
175        let result = cluster.create_physical_channel("Channel2", None);
176        assert!(result.is_err());
177
178        // create a channel for VLAN 1
179        let vlan_info = EthernetVlanInfo {
180            vlan_name: "VLAN_1".to_string(),
181            vlan_id: 1,
182        };
183        let result = cluster.create_physical_channel("Channel3", Some(&vlan_info));
184        assert!(result.is_ok());
185
186        // can't create a second channel called Channel3
187        let vlan_info = EthernetVlanInfo {
188            vlan_name: "VLAN_2".to_string(),
189            vlan_id: 2,
190        };
191        let result = cluster.create_physical_channel("Channel3", Some(&vlan_info));
192        assert!(result.is_err());
193
194        // create a channel for VLAN 2
195        let vlan_info = EthernetVlanInfo {
196            vlan_name: "VLAN_2".to_string(),
197            vlan_id: 2,
198        };
199        let result = cluster.create_physical_channel("Channel4", Some(&vlan_info));
200        assert!(result.is_ok());
201
202        // can't create a second channel for VLAN 2
203        let vlan_info = EthernetVlanInfo {
204            vlan_name: "VLAN_2".to_string(),
205            vlan_id: 2,
206        };
207        let result = cluster.create_physical_channel("Channel5", Some(&vlan_info));
208        assert!(result.is_err());
209
210        let count = cluster.physical_channels().count();
211        assert_eq!(count, 3);
212    }
213
214    #[test]
215    fn remove_cluster() {
216        let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
217        let pkg = model.get_or_create_package("/test").unwrap();
218        let system = pkg.create_system("System", SystemCategory::SystemDescription).unwrap();
219        let pkg2 = model.get_or_create_package("/ethernet").unwrap();
220        let cluster = system.create_ethernet_cluster("EthCluster", &pkg2).unwrap();
221        let channel = cluster.create_physical_channel("Channel1", None).unwrap();
222
223        let doip_tp_config = system.create_doip_tp_config("DoIpTpConfig", &pkg2, &cluster).unwrap();
224        let nm_config = system.create_nm_config("NmConfig", &pkg2).unwrap();
225        let settings = UdpNmClusterSettings {
226            nm_msg_cycle_time: 5.0,
227            nm_msg_timeout_time: 5.0,
228            nm_network_timeout: 5.0,
229            nm_remote_sleep_indication_time: 5.0,
230            nm_repeat_message_time: 5.0,
231            nm_wait_bus_sleep_time: 5.0,
232        };
233        let udp_nm_cluster = nm_config
234            .create_udp_nm_cluster("UdpNmCluster", &settings, &cluster)
235            .unwrap();
236
237        let someip_tp_config = system
238            .create_someip_tp_config("SomeipTpConfig", &pkg2, &cluster)
239            .unwrap();
240        // remove the cluster
241        let result = cluster.remove(true);
242        assert!(result.is_ok());
243        // check that the channel, DoIpTpConfig, UdpNmCluster and SomeIpTpConfig are also removed
244        assert!(channel.element().path().is_err());
245        assert!(doip_tp_config.element().path().is_err());
246        assert!(udp_nm_cluster.element().path().is_err());
247        assert!(someip_tp_config.element().path().is_err());
248    }
249}