autosar_data_abstraction/communication/controller/
can.rs

1use crate::{
2    AbstractionElement, AutosarAbstractionError, EcuInstance, IdentifiableAbstractionElement, abstraction_element,
3    communication::{AbstractCommunicationConnector, AbstractCommunicationController, CanPhysicalChannel},
4};
5use autosar_data::{AutosarDataError, AutosarModel, Element, ElementName, ElementsIterator, WeakElement};
6
7/// An `EcuInstance` needs a `CanCommunicationController` in order to connect to a CAN cluster.
8#[derive(Debug, Clone, PartialEq, Eq, Hash)]
9pub struct CanCommunicationController(Element);
10abstraction_element!(CanCommunicationController, CanCommunicationController);
11impl IdentifiableAbstractionElement for CanCommunicationController {}
12
13impl CanCommunicationController {
14    // create a new CanCommunicationController - called by EcuInstance::create_can_communication_controller
15    pub(crate) fn new(name: &str, ecu: &EcuInstance) -> Result<Self, AutosarAbstractionError> {
16        let commcontrollers = ecu.element().get_or_create_sub_element(ElementName::CommControllers)?;
17        let ctrl = commcontrollers.create_named_sub_element(ElementName::CanCommunicationController, name)?;
18        let _canccc = ctrl
19            .create_sub_element(ElementName::CanCommunicationControllerVariants)?
20            .create_sub_element(ElementName::CanCommunicationControllerConditional)?;
21
22        Ok(Self(ctrl))
23    }
24
25    /// return an iterator over the [`CanPhysicalChannel`]s connected to this controller
26    ///
27    /// # Example
28    ///
29    /// ```
30    /// # use autosar_data::*;
31    /// # use autosar_data_abstraction::*;
32    /// # use autosar_data_abstraction::communication::*;
33    /// # fn main() -> Result<(), AutosarAbstractionError> {
34    /// # let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
35    /// # let package = model.get_or_create_package("/pkg1")?;
36    /// # let system = package.create_system("System", SystemCategory::SystemExtract)?;
37    /// # let ecu_instance = system.create_ecu_instance("ecu_name", &package)?;
38    /// let can_controller = ecu_instance.create_can_communication_controller("CanCtrl")?;
39    /// # let cluster = system.create_can_cluster("Cluster", &package, None)?;
40    /// # let physical_channel = cluster.create_physical_channel("Channel")?;
41    /// can_controller.connect_physical_channel("connection", &physical_channel)?;
42    /// for channel in can_controller.connected_channels() {
43    ///     // ...
44    /// }
45    /// # Ok(())}
46    /// ```
47    ///
48    /// # Errors
49    ///
50    /// - [`AutosarAbstractionError::ModelError`] An error occurred in the Autosar model while trying to get the ECU-INSTANCE
51    pub fn connected_channels(&self) -> impl Iterator<Item = CanPhysicalChannel> + Send + use<> {
52        if let Ok(ecu) = self.ecu_instance().map(|ecuinstance| ecuinstance.element().clone()) {
53            CanCtrlChannelsIterator::new(self, &ecu)
54        } else {
55            CanCtrlChannelsIterator {
56                connector_iter: None,
57                comm_controller: self.0.clone(),
58                model: None,
59            }
60        }
61    }
62
63    /// Connect this [`CanCommunicationController`] inside an [`EcuInstance`] to a [`CanPhysicalChannel`] in the [`crate::System`]
64    ///
65    /// Creates a [`CanCommunicationConnector`] in the [`EcuInstance`] that contains this [`CanCommunicationController`].
66    ///
67    /// This function establishes the relationships:
68    ///  - [`CanPhysicalChannel`] -> [`CanCommunicationConnector`]
69    ///  - [`CanCommunicationConnector`] -> [`CanCommunicationController`]
70    ///
71    /// # Example
72    ///
73    /// ```
74    /// # use autosar_data::*;
75    /// # use autosar_data_abstraction::*;
76    /// # use autosar_data_abstraction::communication::*;
77    /// # fn main() -> Result<(), AutosarAbstractionError> {
78    /// # let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
79    /// # let package = model.get_or_create_package("/pkg1")?;
80    /// # let system = package.create_system("System", SystemCategory::SystemExtract)?;
81    /// # let ecu_instance = system.create_ecu_instance("ecu_name", &package)?;
82    /// let can_controller = ecu_instance.create_can_communication_controller("CanCtrl")?;
83    /// # let cluster = system.create_can_cluster("Cluster", &package, None)?;
84    /// # let physical_channel = cluster.create_physical_channel("Channel")?;
85    /// can_controller.connect_physical_channel("connection", &physical_channel)?;
86    /// # Ok(())}
87    /// ```
88    ///
89    /// # Errors
90    ///
91    /// - [`AutosarAbstractionError::ModelError`] An error occurred in the Autosar model while trying to create the ECU-INSTANCE
92    pub fn connect_physical_channel(
93        &self,
94        connection_name: &str,
95        can_channel: &CanPhysicalChannel,
96    ) -> Result<CanCommunicationConnector, AutosarAbstractionError> {
97        let ecu = self.0.named_parent()?.unwrap();
98        // check that there is no existing connector for this CanCommunicationController
99        if let Some(connectors) = ecu.get_sub_element(ElementName::Connectors) {
100            for connector in connectors.sub_elements() {
101                // Does the existing connector reference this CanCommunicationController?
102                // A CanCommunicationController can only connect to a single CAN cluster, so a second
103                // connector cannot be created.
104                if let Some(ccref) = connector.get_sub_element(ElementName::CommControllerRef)
105                    && let Ok(commcontroller_of_connector) = ccref.get_reference_target()
106                    && commcontroller_of_connector == self.0
107                {
108                    return Err(AutosarAbstractionError::ItemAlreadyExists);
109                }
110            }
111        }
112        // create a new connector
113        let connectors = ecu.get_or_create_sub_element(ElementName::Connectors)?;
114        let connector = CanCommunicationConnector::new(connection_name, &connectors, self)?;
115
116        let channel_connctor_refs = can_channel
117            .element()
118            .get_or_create_sub_element(ElementName::CommConnectors)?;
119        channel_connctor_refs
120            .create_sub_element(ElementName::CommunicationConnectorRefConditional)
121            .and_then(|ccrc| ccrc.create_sub_element(ElementName::CommunicationConnectorRef))
122            .and_then(|ccr| ccr.set_reference_target(connector.element()))?;
123
124        Ok(connector)
125    }
126}
127
128impl AbstractCommunicationController for CanCommunicationController {}
129
130//##################################################################
131
132/// A connector between a [`CanCommunicationController`] in an ECU and a [`CanPhysicalChannel`]
133#[derive(Debug, Clone, PartialEq, Eq, Hash)]
134pub struct CanCommunicationConnector(Element);
135abstraction_element!(CanCommunicationConnector, CanCommunicationConnector);
136impl IdentifiableAbstractionElement for CanCommunicationConnector {}
137
138impl CanCommunicationConnector {
139    pub(crate) fn new(
140        name: &str,
141        parent: &Element,
142        controller: &CanCommunicationController,
143    ) -> Result<Self, AutosarAbstractionError> {
144        let connector = parent.create_named_sub_element(ElementName::CanCommunicationConnector, name)?;
145        connector
146            .create_sub_element(ElementName::CommControllerRef)?
147            .set_reference_target(controller.element())?;
148        Ok(Self(connector))
149    }
150}
151
152impl AbstractCommunicationConnector for CanCommunicationConnector {
153    type CommunicationControllerType = CanCommunicationController;
154
155    fn controller(&self) -> Result<Self::CommunicationControllerType, AutosarAbstractionError> {
156        let controller = self
157            .element()
158            .get_sub_element(ElementName::CommControllerRef)
159            .ok_or_else(|| {
160                AutosarAbstractionError::ModelError(AutosarDataError::ElementNotFound {
161                    target: ElementName::CommControllerRef,
162                    parent: self.element().element_name(),
163                })
164            })?
165            .get_reference_target()?;
166        CanCommunicationController::try_from(controller)
167    }
168}
169
170//##################################################################
171
172#[doc(hidden)]
173pub struct CanCtrlChannelsIterator {
174    connector_iter: Option<ElementsIterator>,
175    comm_controller: Element,
176    model: Option<AutosarModel>,
177}
178
179impl CanCtrlChannelsIterator {
180    fn new(controller: &CanCommunicationController, ecu: &Element) -> Self {
181        let iter = ecu.get_sub_element(ElementName::Connectors).map(|c| c.sub_elements());
182        let comm_controller = controller.element().clone();
183        let model = comm_controller.model().ok();
184        Self {
185            connector_iter: iter,
186            comm_controller,
187            model,
188        }
189    }
190}
191
192impl Iterator for CanCtrlChannelsIterator {
193    type Item = CanPhysicalChannel;
194
195    fn next(&mut self) -> Option<Self::Item> {
196        let model = self.model.as_ref()?;
197        let connector_iter = self.connector_iter.as_mut()?;
198        for connector in connector_iter.by_ref() {
199            if connector.element_name() == ElementName::CanCommunicationConnector
200                && let Some(commcontroller_of_connector) = connector
201                    .get_sub_element(ElementName::CommControllerRef)
202                    .and_then(|ccr| ccr.get_reference_target().ok())
203                && commcontroller_of_connector == self.comm_controller
204            {
205                for ref_origin in model
206                    .get_references_to(&connector.path().ok()?)
207                    .iter()
208                    .filter_map(WeakElement::upgrade)
209                    .filter_map(|elem| elem.named_parent().ok().flatten())
210                {
211                    // This assumes that each connector will only ever be referenced by at most one
212                    // PhysicalChannel, which is true for well-formed files.
213                    if ref_origin.element_name() == ElementName::CanPhysicalChannel {
214                        return CanPhysicalChannel::try_from(ref_origin).ok();
215                    }
216                }
217            }
218        }
219        None
220    }
221}
222
223//##################################################################
224
225#[cfg(test)]
226mod test {
227    use super::*;
228    use crate::{AutosarModelAbstraction, SystemCategory};
229    use autosar_data::AutosarVersion;
230
231    #[test]
232    fn controller() {
233        let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
234        let pkg = model.get_or_create_package("/test").unwrap();
235        let system = pkg.create_system("System", SystemCategory::SystemDescription).unwrap();
236        let ecu = system.create_ecu_instance("ECU", &pkg).unwrap();
237
238        // create a controller
239        let result = ecu.create_can_communication_controller("Controller");
240        let controller = result.unwrap();
241
242        // create some physical channels
243        let cluster = system.create_can_cluster("CanCluster", &pkg, None).unwrap();
244        let channel1 = cluster.create_physical_channel("C1").unwrap();
245
246        // connect the controller to channel1
247        let connector = controller
248            .connect_physical_channel("connection_name1", &channel1)
249            .unwrap();
250        assert_eq!(connector.controller().unwrap(), controller);
251        // can't connect to the same channel again
252        let result = controller.connect_physical_channel("connection_name2", &channel1);
253        assert!(result.is_err());
254
255        let count = controller.connected_channels().count();
256        assert_eq!(count, 1);
257
258        // remove the controller and try to list its connected channels again
259        let ctrl_parent = controller.0.parent().unwrap().unwrap();
260        ctrl_parent.remove_sub_element(controller.0.clone()).unwrap();
261        let count = controller.connected_channels().count();
262        assert_eq!(count, 0);
263    }
264
265    #[test]
266    fn connector() {
267        let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
268        let pkg = model.get_or_create_package("/test").unwrap();
269        let system = pkg.create_system("System", SystemCategory::SystemDescription).unwrap();
270        let ecu = system.create_ecu_instance("ECU", &pkg).unwrap();
271
272        // create a controller
273        let controller = ecu.create_can_communication_controller("Controller").unwrap();
274        assert_eq!(controller.ecu_instance().unwrap(), ecu);
275
276        // create some physical channels
277        let cluster = system.create_can_cluster("CanCluster", &pkg, None).unwrap();
278        let channel1 = cluster.create_physical_channel("C1").unwrap();
279
280        // connect the controller to channel1
281        let connector = controller
282            .connect_physical_channel("connection_name1", &channel1)
283            .unwrap();
284        assert_eq!(connector.controller().unwrap(), controller);
285        assert_eq!(connector.ecu_instance().unwrap(), ecu);
286
287        // remove the CommControllerRef from the connector and try to get the controller
288        connector
289            .element()
290            .remove_sub_element_kind(ElementName::CommControllerRef)
291            .unwrap();
292        let result = connector.controller();
293        assert!(result.is_err());
294    }
295}