autosar_data_abstraction/communication/controller/
lin.rs

1use crate::{
2    AbstractionElement, AutosarAbstractionError, EcuInstance, IdentifiableAbstractionElement, abstraction_element,
3    communication::{AbstractCommunicationConnector, AbstractCommunicationController, LinPhysicalChannel},
4};
5use autosar_data::{AutosarDataError, AutosarModel, Element, ElementName, ElementsIterator, WeakElement};
6
7//##################################################################
8
9/// Common behaviour for LIN communication controllers
10pub trait AbstractLinCommunicationController:
11    AbstractCommunicationController + Into<LinCommunicationController>
12{
13    /// return an iterator over the [`LinPhysicalChannel`]s connected to this controller
14    ///
15    /// # Example
16    ///
17    /// ```
18    /// # use autosar_data::*;
19    /// # use autosar_data_abstraction::*;
20    /// # use autosar_data_abstraction::communication::*;
21    /// # fn main() -> Result<(), AutosarAbstractionError> {
22    /// # let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
23    /// # let package = model.get_or_create_package("/pkg1")?;
24    /// # let system = package.create_system("System", SystemCategory::SystemExtract)?;
25    /// # let ecu_instance = system.create_ecu_instance("ecu_name", &package)?;
26    /// let lin_master = ecu_instance.create_lin_master_communication_controller("LinMaster")?;
27    /// # let cluster = system.create_lin_cluster("Cluster", &package)?;
28    /// # let physical_channel = cluster.create_physical_channel("Channel")?;
29    /// lin_master.connect_physical_channel("connection", &physical_channel)?;
30    /// for channel in lin_master.connected_channels() {
31    ///     // ...
32    /// }
33    /// # Ok(())}
34    /// ```
35    ///
36    /// # Errors
37    ///
38    /// - [`AutosarAbstractionError::ModelError`] An error occurred in the Autosar model while trying to get the ECU-INSTANCE
39    fn connected_channels(&self) -> impl Iterator<Item = LinPhysicalChannel> + Send + use<Self> {
40        if let Ok(ecu) = self.ecu_instance().map(|ecuinstance| ecuinstance.element().clone()) {
41            LinCtrlChannelsIterator::new(&self.clone().into(), &ecu)
42        } else {
43            LinCtrlChannelsIterator {
44                connector_iter: None,
45                comm_controller: self.element().clone(),
46                model: None,
47            }
48        }
49    }
50
51    /// Connect this [`CanCommunicationController`] inside an [`EcuInstance`] to a [`CanPhysicalChannel`] in the [`crate::System`]
52    ///
53    /// Creates a [`CanCommunicationConnector`] in the [`EcuInstance`] that contains this [`CanCommunicationController`].
54    ///
55    /// This function establishes the relationships:
56    ///  - [`CanPhysicalChannel`] -> [`CanCommunicationConnector`]
57    ///  - [`CanCommunicationConnector`] -> [`CanCommunicationController`]
58    ///
59    /// # Example
60    ///
61    /// ```
62    /// # use autosar_data::*;
63    /// # use autosar_data_abstraction::*;
64    /// # use autosar_data_abstraction::communication::*;
65    /// # fn main() -> Result<(), AutosarAbstractionError> {
66    /// # let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
67    /// # let package = model.get_or_create_package("/pkg1")?;
68    /// # let system = package.create_system("System", SystemCategory::SystemExtract)?;
69    /// # let ecu_instance = system.create_ecu_instance("ecu_name", &package)?;
70    /// let lin_slave = ecu_instance.create_lin_slave_communication_controller("LinSlave")?;
71    /// # let cluster = system.create_lin_cluster("Cluster", &package)?;
72    /// # let physical_channel = cluster.create_physical_channel("Channel")?;
73    /// lin_slave.connect_physical_channel("connection", &physical_channel)?;
74    /// # Ok(())}
75    /// ```
76    ///
77    /// # Errors
78    ///
79    /// - [`AutosarAbstractionError::ModelError`] An error occurred in the Autosar model while trying to create the ECU-INSTANCE
80    fn connect_physical_channel(
81        &self,
82        connection_name: &str,
83        lin_channel: &LinPhysicalChannel,
84    ) -> Result<LinCommunicationConnector, AutosarAbstractionError> {
85        let ecu = self.element().named_parent()?.unwrap();
86        // check that there is no existing connector for this LinCommunicationController
87        if let Some(connectors) = ecu.get_sub_element(ElementName::Connectors) {
88            for connector in connectors.sub_elements() {
89                // Does the existing connector reference this LinCommunicationController?
90                // A LinCommunicationController can only connect to a single LIN cluster, so a second
91                // connector cannot be created.
92                if let Some(ccref) = connector.get_sub_element(ElementName::CommControllerRef)
93                    && let Ok(commcontroller_of_connector) = ccref.get_reference_target()
94                    && &commcontroller_of_connector == self.element()
95                {
96                    return Err(AutosarAbstractionError::ItemAlreadyExists);
97                }
98            }
99        }
100        // create a new connector
101        let connectors = ecu.get_or_create_sub_element(ElementName::Connectors)?;
102        let connector = LinCommunicationConnector::new(connection_name, &connectors, &self.clone().into())?;
103
104        let channel_connector_refs = lin_channel
105            .element()
106            .get_or_create_sub_element(ElementName::CommConnectors)?;
107        channel_connector_refs
108            .create_sub_element(ElementName::CommunicationConnectorRefConditional)
109            .and_then(|ccrc| ccrc.create_sub_element(ElementName::CommunicationConnectorRef))
110            .and_then(|ccr| ccr.set_reference_target(connector.element()))?;
111
112        Ok(connector)
113    }
114}
115
116//##################################################################
117
118/// An `EcuInstance` needs a `LinMaster` or `LinSlave` in order to connect to a LIN cluster.
119#[derive(Debug, Clone, PartialEq, Eq, Hash)]
120pub struct LinMaster(Element);
121abstraction_element!(LinMaster, LinMaster);
122impl IdentifiableAbstractionElement for LinMaster {}
123
124impl LinMaster {
125    // create a new LinMaster - called by EcuInstance::create_lin_master_communication_controller
126    pub(crate) fn new(name: &str, ecu: &EcuInstance) -> Result<Self, AutosarAbstractionError> {
127        let commcontrollers = ecu.element().get_or_create_sub_element(ElementName::CommControllers)?;
128        let ctrl = commcontrollers.create_named_sub_element(ElementName::LinMaster, name)?;
129        let _lincc = ctrl
130            .create_sub_element(ElementName::LinMasterVariants)?
131            .create_sub_element(ElementName::LinMasterConditional)?;
132
133        Ok(Self(ctrl))
134    }
135
136    /// remove this `LinMaster` from the model
137    pub fn remove(self, deep: bool) -> Result<(), AutosarAbstractionError> {
138        // remove all the connectors using this controller
139        let ecu_instance = self.ecu_instance()?;
140        for connector in ecu_instance
141            .element()
142            .get_sub_element(ElementName::Connectors)
143            .iter()
144            .flat_map(|connectors| connectors.sub_elements())
145            .filter_map(|conn| LinCommunicationConnector::try_from(conn).ok())
146        {
147            if let Ok(controller_of_connector) = connector.controller()
148                && controller_of_connector.element() == self.element()
149            {
150                connector.remove(deep)?;
151            }
152        }
153
154        AbstractionElement::remove(self, deep)
155    }
156}
157
158impl AbstractCommunicationController for LinMaster {}
159impl AbstractLinCommunicationController for LinMaster {}
160
161//##################################################################
162
163/// An `EcuInstance` needs a `LinMaster` or `LinSlave` in order to connect to a LIN cluster.
164#[derive(Debug, Clone, PartialEq, Eq, Hash)]
165pub struct LinSlave(Element);
166abstraction_element!(LinSlave, LinSlave);
167impl IdentifiableAbstractionElement for LinSlave {}
168
169impl LinSlave {
170    // create a new LinSlave - called by EcuInstance::create_lin_slave_communication_controller
171    pub(crate) fn new(name: &str, ecu: &EcuInstance) -> Result<Self, AutosarAbstractionError> {
172        let commcontrollers = ecu.element().get_or_create_sub_element(ElementName::CommControllers)?;
173        let ctrl = commcontrollers.create_named_sub_element(ElementName::LinSlave, name)?;
174        let _linsc = ctrl
175            .create_sub_element(ElementName::LinSlaveVariants)?
176            .create_sub_element(ElementName::LinSlaveConditional)?;
177
178        Ok(Self(ctrl))
179    }
180
181    /// remove this `LinSlave` from the model
182    pub fn remove(self, deep: bool) -> Result<(), AutosarAbstractionError> {
183        // remove all the connectors using this controller
184        let ecu_instance = self.ecu_instance()?;
185        for connector in ecu_instance
186            .element()
187            .get_sub_element(ElementName::Connectors)
188            .iter()
189            .flat_map(|connectors| connectors.sub_elements())
190            .filter_map(|conn| LinCommunicationConnector::try_from(conn).ok())
191        {
192            if let Ok(controller_of_connector) = connector.controller()
193                && controller_of_connector.element() == self.element()
194            {
195                connector.remove(deep)?;
196            }
197        }
198
199        AbstractionElement::remove(self, deep)
200    }
201}
202
203impl AbstractCommunicationController for LinSlave {}
204impl AbstractLinCommunicationController for LinSlave {}
205
206//##################################################################
207
208/// A connector between a [`LinMaster`] or [`LinSlave`] in an ECU and a [`LinPhysicalChannel`]
209#[derive(Debug, Clone, PartialEq, Eq, Hash)]
210pub struct LinCommunicationConnector(Element);
211abstraction_element!(LinCommunicationConnector, LinCommunicationConnector);
212impl IdentifiableAbstractionElement for LinCommunicationConnector {}
213
214impl LinCommunicationConnector {
215    pub(crate) fn new(
216        name: &str,
217        parent: &Element,
218        controller: &LinCommunicationController,
219    ) -> Result<Self, AutosarAbstractionError> {
220        let connector = parent.create_named_sub_element(ElementName::LinCommunicationConnector, name)?;
221        connector
222            .create_sub_element(ElementName::CommControllerRef)?
223            .set_reference_target(controller.element())?;
224        Ok(Self(connector))
225    }
226}
227
228impl AbstractCommunicationConnector for LinCommunicationConnector {
229    type CommunicationControllerType = LinCommunicationController;
230
231    fn controller(&self) -> Result<Self::CommunicationControllerType, AutosarAbstractionError> {
232        let controller = self
233            .element()
234            .get_sub_element(ElementName::CommControllerRef)
235            .ok_or_else(|| {
236                AutosarAbstractionError::ModelError(AutosarDataError::ElementNotFound {
237                    target: ElementName::CommControllerRef,
238                    parent: self.element().element_name(),
239                })
240            })?
241            .get_reference_target()?;
242        LinCommunicationController::try_from(controller)
243    }
244}
245
246//##################################################################
247
248/// A LIN communication controller is either a [`LinMaster`] or a [`LinSlave`].
249#[derive(Debug, Clone, PartialEq, Eq, Hash)]
250pub enum LinCommunicationController {
251    /// A LIN Master communication controller
252    Master(LinMaster),
253    /// A LIN Slave communication controller
254    Slave(LinSlave),
255}
256impl AbstractionElement for LinCommunicationController {
257    fn element(&self) -> &autosar_data::Element {
258        match self {
259            LinCommunicationController::Master(master) => master.element(),
260            LinCommunicationController::Slave(slave) => slave.element(),
261        }
262    }
263}
264impl AbstractCommunicationController for LinCommunicationController {}
265
266impl TryFrom<Element> for LinCommunicationController {
267    type Error = AutosarAbstractionError;
268
269    fn try_from(element: Element) -> Result<Self, Self::Error> {
270        match element.element_name() {
271            ElementName::LinMaster => Ok(Self::Master(LinMaster::try_from(element)?)),
272            ElementName::LinSlave => Ok(Self::Slave(LinSlave::try_from(element)?)),
273            _ => Err(AutosarAbstractionError::ConversionError {
274                element,
275                dest: "LinCommunicationController".to_string(),
276            }),
277        }
278    }
279}
280
281impl From<LinMaster> for LinCommunicationController {
282    fn from(value: LinMaster) -> Self {
283        LinCommunicationController::Master(value)
284    }
285}
286
287impl From<LinSlave> for LinCommunicationController {
288    fn from(value: LinSlave) -> Self {
289        LinCommunicationController::Slave(value)
290    }
291}
292
293//##################################################################
294
295#[doc(hidden)]
296pub struct LinCtrlChannelsIterator {
297    connector_iter: Option<ElementsIterator>,
298    comm_controller: Element,
299    model: Option<AutosarModel>,
300}
301
302impl LinCtrlChannelsIterator {
303    fn new(controller: &LinCommunicationController, ecu: &Element) -> Self {
304        let iter = ecu.get_sub_element(ElementName::Connectors).map(|c| c.sub_elements());
305        let comm_controller = controller.element().clone();
306        let model = comm_controller.model().ok();
307        Self {
308            connector_iter: iter,
309            comm_controller,
310            model,
311        }
312    }
313}
314
315impl Iterator for LinCtrlChannelsIterator {
316    type Item = LinPhysicalChannel;
317
318    fn next(&mut self) -> Option<Self::Item> {
319        let model = self.model.as_ref()?;
320        let connector_iter = self.connector_iter.as_mut()?;
321        for connector in connector_iter.by_ref() {
322            if connector.element_name() == ElementName::LinCommunicationConnector
323                && let Some(commcontroller_of_connector) = connector
324                    .get_sub_element(ElementName::CommControllerRef)
325                    .and_then(|ccr| ccr.get_reference_target().ok())
326                && commcontroller_of_connector == self.comm_controller
327            {
328                for ref_origin in model
329                    .get_references_to(&connector.path().ok()?)
330                    .iter()
331                    .filter_map(WeakElement::upgrade)
332                    .filter_map(|elem| elem.named_parent().ok().flatten())
333                {
334                    // This assumes that each connector will only ever be referenced by at most one
335                    // PhysicalChannel, which is true for well-formed files.
336                    if ref_origin.element_name() == ElementName::LinPhysicalChannel {
337                        return LinPhysicalChannel::try_from(ref_origin).ok();
338                    }
339                }
340            }
341        }
342        None
343    }
344}
345
346//##################################################################
347
348#[cfg(test)]
349mod test {
350    use autosar_data::AutosarVersion;
351
352    use crate::{AutosarModelAbstraction, SystemCategory};
353
354    use super::*;
355
356    #[test]
357    fn controller() {
358        let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
359        let pkg = model.get_or_create_package("/test").unwrap();
360        let system = pkg.create_system("System", SystemCategory::SystemDescription).unwrap();
361        let ecu = system.create_ecu_instance("ECU", &pkg).unwrap();
362
363        // create a LIN master and a LIN slave communication controller
364        let result = ecu.create_lin_master_communication_controller("LinMaster");
365        let lin_master = result.unwrap();
366        let result = ecu.create_lin_slave_communication_controller("LinSlave");
367        let lin_slave = result.unwrap();
368
369        // create some physical channels
370        let cluster = system.create_lin_cluster("LinCluster", &pkg).unwrap();
371        let channel = cluster.create_physical_channel("C1").unwrap();
372
373        // connect the controllers to the channel
374        let connector_m = lin_master
375            .connect_physical_channel("master_connection", &channel)
376            .unwrap();
377        assert_eq!(connector_m.controller().unwrap(), lin_master.clone().into());
378        let connector_s = lin_slave
379            .connect_physical_channel("slave_connection", &channel)
380            .unwrap();
381        assert_eq!(connector_s.controller().unwrap(), lin_slave.clone().into());
382        // can't connect to the same channel again
383        let result = lin_master.connect_physical_channel("connection_name2", &channel);
384        assert!(result.is_err());
385
386        let count = lin_master.connected_channels().count();
387        assert_eq!(count, 1);
388
389        // remove the controller and try to list its connected channels again
390        let ctrl_parent = lin_master.0.parent().unwrap().unwrap();
391        ctrl_parent.remove_sub_element(lin_master.0.clone()).unwrap();
392        let count = lin_master.connected_channels().count();
393        assert_eq!(count, 0);
394    }
395
396    #[test]
397    fn connector() {
398        let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
399        let pkg = model.get_or_create_package("/test").unwrap();
400        let system = pkg.create_system("System", SystemCategory::SystemDescription).unwrap();
401        let ecu = system.create_ecu_instance("ECU", &pkg).unwrap();
402
403        // create a controller
404        let lin_master = ecu.create_lin_master_communication_controller("Controller").unwrap();
405        assert_eq!(lin_master.ecu_instance().unwrap(), ecu);
406
407        // create some physical channels
408        let cluster = system.create_lin_cluster("LinCluster", &pkg).unwrap();
409        let channel = cluster.create_physical_channel("C1").unwrap();
410
411        // connect the controller to channel1
412        let connector = lin_master
413            .connect_physical_channel("connection_name1", &channel)
414            .unwrap();
415        assert_eq!(connector.controller().unwrap(), lin_master.clone().into());
416        assert_eq!(connector.ecu_instance().unwrap(), ecu);
417
418        // remove the CommControllerRef from the connector and try to get the controller
419        connector
420            .element()
421            .remove_sub_element_kind(ElementName::CommControllerRef)
422            .unwrap();
423        let result = connector.controller();
424        assert!(result.is_err());
425    }
426
427    #[test]
428    fn remove_controller() {
429        let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
430        let pkg = model.get_or_create_package("/test").unwrap();
431        let system = pkg.create_system("System", SystemCategory::SystemDescription).unwrap();
432        let ecu = system.create_ecu_instance("ECU", &pkg).unwrap();
433        // create a controller
434        let lin_master = ecu.create_lin_master_communication_controller("Controller").unwrap();
435        // create a lin cluster with a physical channel
436        let cluster = system.create_lin_cluster("LinCluster", &pkg).unwrap();
437        let channel = cluster.create_physical_channel("C1").unwrap();
438        // connect the controller to the channel
439        let connector = lin_master
440            .connect_physical_channel("connection_name1", &channel)
441            .unwrap();
442
443        // remove the controller, which should also remove the connector
444        lin_master.remove(true).unwrap();
445
446        assert_eq!(ecu.communication_controllers().count(), 0);
447        assert!(connector.element().path().is_err());
448    }
449}