autosar_data_abstraction/communication/controller/
flexray.rs

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