autosar_data_abstraction/communication/cluster/
lin.rs

1use crate::communication::{AbstractCluster, LinPhysicalChannel};
2use crate::{
3    AbstractionElement, ArPackage, AutosarAbstractionError, IdentifiableAbstractionElement, abstraction_element,
4};
5use autosar_data::{Element, ElementName};
6
7//##################################################################
8
9/// A `LinCluster` contains all configuration items associated with a LIN network.
10/// The cluster connects multiple ECUs.
11#[derive(Debug, Clone, PartialEq, Eq, Hash)]
12pub struct LinCluster(Element);
13abstraction_element!(LinCluster, LinCluster);
14impl IdentifiableAbstractionElement for LinCluster {}
15
16impl LinCluster {
17    // create a new LinCluster - for internal use. User code should call System::create_lin_cluster
18    pub(crate) fn new(cluster_name: &str, package: &ArPackage) -> Result<Self, AutosarAbstractionError> {
19        let elem_pkg_elements = package.element().get_or_create_sub_element(ElementName::Elements)?;
20        let elem_cluster = elem_pkg_elements.create_named_sub_element(ElementName::LinCluster, cluster_name)?;
21        if let Ok(cluster_content) = elem_cluster
22            .create_sub_element(ElementName::LinClusterVariants)
23            .and_then(|ccv| ccv.create_sub_element(ElementName::LinClusterConditional))
24        {
25            let _ = cluster_content
26                .create_sub_element(ElementName::ProtocolName)
27                .and_then(|pn| pn.set_character_data("CAN"));
28
29            let _ = cluster_content.create_sub_element(ElementName::PhysicalChannels);
30        }
31
32        let lin_cluster = LinCluster(elem_cluster);
33
34        Ok(lin_cluster)
35    }
36
37    /// Create a new physical channel for the cluster
38    ///
39    /// A LIN cluster must contain exactly one physical channel; trying to add a second one triggers an error.
40    ///
41    /// # Example
42    ///
43    /// ```
44    /// # use autosar_data::*;
45    /// # use autosar_data_abstraction::*;
46    /// # use autosar_data_abstraction::communication::*;
47    /// # fn main() -> Result<(), AutosarAbstractionError> {
48    /// # let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00051);
49    /// # let package = model.get_or_create_package("/pkg1")?;
50    /// # let system = package.create_system("System", SystemCategory::SystemExtract)?;
51    /// let cluster = system.create_lin_cluster("Cluster", &package)?;
52    /// let channel = cluster.create_physical_channel("Channel")?;
53    /// # Ok(())}
54    /// ```
55    ///
56    /// # Errors
57    ///
58    /// - [`AutosarAbstractionError::ItemAlreadyExists`] There is already a physical channel in this LIN cluster
59    /// - [`AutosarAbstractionError::ModelError`] An error occurred in the Autosar model while trying to create the ECU-INSTANCE
60    pub fn create_physical_channel(&self, channel_name: &str) -> Result<LinPhysicalChannel, AutosarAbstractionError> {
61        let phys_channels = self
62            .0
63            .get_or_create_sub_element(ElementName::LinClusterVariants)?
64            .get_or_create_sub_element(ElementName::LinClusterConditional)?
65            .get_or_create_sub_element(ElementName::PhysicalChannels)?;
66
67        if phys_channels.sub_elements().count() != 0 {
68            return Err(AutosarAbstractionError::ItemAlreadyExists);
69        }
70
71        let channel = phys_channels.create_named_sub_element(ElementName::LinPhysicalChannel, channel_name)?;
72
73        LinPhysicalChannel::try_from(channel)
74    }
75
76    /// return the `LinPhysicalChannel` of the Cluster, if it has been created
77    ///
78    /// # Example
79    ///
80    /// ```
81    /// # use autosar_data::*;
82    /// # use autosar_data_abstraction::*;
83    /// # use autosar_data_abstraction::communication::*;
84    /// # fn main() -> Result<(), AutosarAbstractionError> {
85    /// # let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
86    /// # let package = model.get_or_create_package("/pkg1")?;
87    /// # let system = package.create_system("System", SystemCategory::SystemExtract)?;
88    /// # let cluster = system.create_can_cluster("Cluster", &package, None)?;
89    /// # let can_channel = cluster.create_physical_channel("Channel")?;
90    /// if let Some(channel) = cluster.physical_channel() {
91    /// #   assert_eq!(channel, can_channel);
92    /// }
93    /// # Ok(())}
94    /// ```
95    #[must_use]
96    pub fn physical_channel(&self) -> Option<LinPhysicalChannel> {
97        let channel = self
98            .0
99            .get_sub_element(ElementName::LinClusterVariants)?
100            .get_sub_element(ElementName::LinClusterConditional)?
101            .get_sub_element(ElementName::PhysicalChannels)?
102            .get_sub_element(ElementName::LinPhysicalChannel)?;
103        LinPhysicalChannel::try_from(channel).ok()
104    }
105}
106
107impl AbstractCluster for LinCluster {}
108
109//##################################################################
110
111#[cfg(test)]
112mod test {
113    use crate::{AutosarModelAbstraction, SystemCategory, communication::AbstractCluster};
114    use autosar_data::AutosarVersion;
115
116    #[test]
117    fn cluster() {
118        let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00051);
119        let pkg = model.get_or_create_package("/test").unwrap();
120        let system = pkg.create_system("System", SystemCategory::SystemDescription).unwrap();
121
122        let pkg2 = model.get_or_create_package("/lin").unwrap();
123        // create the LIN cluster LinCluster
124        let result = system.create_lin_cluster("LinCluster", &pkg2);
125        assert!(result.is_ok());
126        let cluster = result.unwrap();
127        // creating the same cluster again is not possible
128        let result = system.create_lin_cluster("LinCluster", &pkg2);
129        assert!(result.is_err());
130
131        // system link
132        let linked_system = cluster.system().unwrap();
133        assert_eq!(linked_system, system);
134
135        // create a channel
136        let result = cluster.create_physical_channel("Channel1");
137        assert!(result.is_ok());
138        // can't create a second channel
139        let result = cluster.create_physical_channel("Channel2");
140        assert!(result.is_err());
141
142        let pc = cluster.physical_channel();
143        assert!(pc.is_some());
144    }
145}