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    /// return an iterator over the [`FlexrayPhysicalChannel`]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 flexray_controller = ecu_instance.create_flexray_communication_controller("FRCtrl")?;
39    /// # let cluster = system.create_flexray_cluster("Cluster", &package, &FlexrayClusterSettings::default())?;
40    /// # let physical_channel = cluster.create_physical_channel("Channel", FlexrayChannelName::A)?;
41    /// flexray_controller.connect_physical_channel("connection", &physical_channel)?;
42    /// for channel in flexray_controller.connected_channels() {
43    ///     // ...
44    /// }
45    /// # Ok(())}
46    /// ```
47    ///
48    /// # Errors
49    ///
50    /// - [`AutosarAbstractionError::ModelError`] An error occurred in the Autosar model
51    pub fn connected_channels(&self) -> impl Iterator<Item = FlexrayPhysicalChannel> + Send + 'static {
52        if let Ok(ecu) = self.ecu_instance().map(|ecuinstance| ecuinstance.element().clone()) {
53            FlexrayCtrlChannelsIterator::new(self, &ecu)
54        } else {
55            FlexrayCtrlChannelsIterator {
56                connector_iter: None,
57                comm_controller: self.0.clone(),
58                model: None,
59            }
60        }
61    }
62
63    /// Connect this [`FlexrayCommunicationController`] inside an [`EcuInstance`] to a [`FlexrayPhysicalChannel`] in the [`crate::System`]
64    ///
65    /// Creates a `FlexrayCommunicationConnector` in the [`EcuInstance`] that contains this [`FlexrayCommunicationController`].
66    ///
67    /// This function establishes the relationships:
68    ///  - [`FlexrayPhysicalChannel`] -> `FlexrayCommunicationConnector`
69    ///  - `FlexrayCommunicationConnector` -> [`FlexrayCommunicationController`]
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 flexray_controller = ecu_instance.create_flexray_communication_controller("FlxCtrl")?;
83    /// # let cluster = system.create_flexray_cluster("Cluster", &package, &FlexrayClusterSettings::default())?;
84    /// # let physical_channel = cluster.create_physical_channel("Channel", FlexrayChannelName::A)?;
85    /// flexray_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        flx_channel: &FlexrayPhysicalChannel,
96    ) -> Result<FlexrayCommunicationConnector, AutosarAbstractionError> {
97        let ecu = self.0.named_parent()?.unwrap();
98
99        for existing_channel in self.connected_channels() {
100            if existing_channel == *flx_channel {
101                return Err(AutosarAbstractionError::ItemAlreadyExists);
102            }
103        }
104
105        // create a new connector
106        let connectors = ecu.get_or_create_sub_element(ElementName::Connectors)?;
107        let connector = FlexrayCommunicationConnector::new(connection_name, &connectors, self)?;
108
109        let channel_connctor_refs = flx_channel
110            .element()
111            .get_or_create_sub_element(ElementName::CommConnectors)?;
112        channel_connctor_refs
113            .create_sub_element(ElementName::CommunicationConnectorRefConditional)
114            .and_then(|ccrc| ccrc.create_sub_element(ElementName::CommunicationConnectorRef))
115            .and_then(|ccr| ccr.set_reference_target(connector.element()))?;
116
117        Ok(connector)
118    }
119}
120
121impl AbstractCommunicationController for FlexrayCommunicationController {}
122
123//##################################################################
124
125/// A connector between a [`FlexrayCommunicationController`] in an ECU and a [`FlexrayPhysicalChannel`]
126#[derive(Debug, Clone, PartialEq, Eq, Hash)]
127pub struct FlexrayCommunicationConnector(Element);
128abstraction_element!(FlexrayCommunicationConnector, FlexrayCommunicationConnector);
129impl IdentifiableAbstractionElement for FlexrayCommunicationConnector {}
130
131impl FlexrayCommunicationConnector {
132    pub(crate) fn new(
133        name: &str,
134        parent: &Element,
135        controller: &FlexrayCommunicationController,
136    ) -> Result<Self, AutosarAbstractionError> {
137        let connector = parent.create_named_sub_element(ElementName::FlexrayCommunicationConnector, name)?;
138        connector
139            .create_sub_element(ElementName::CommControllerRef)
140            .and_then(|refelem| refelem.set_reference_target(controller.element()))?;
141
142        Ok(Self(connector))
143    }
144}
145
146impl AbstractCommunicationConnector for FlexrayCommunicationConnector {
147    type CommunicationControllerType = FlexrayCommunicationController;
148
149    fn controller(&self) -> Result<Self::CommunicationControllerType, AutosarAbstractionError> {
150        let controller = self
151            .element()
152            .get_sub_element(ElementName::CommControllerRef)
153            .ok_or_else(|| {
154                AutosarAbstractionError::ModelError(AutosarDataError::ElementNotFound {
155                    target: ElementName::CommControllerRef,
156                    parent: self.element().element_name(),
157                })
158            })?
159            .get_reference_target()?;
160        FlexrayCommunicationController::try_from(controller)
161    }
162}
163
164//##################################################################
165
166#[doc(hidden)]
167pub struct FlexrayCtrlChannelsIterator {
168    connector_iter: Option<ElementsIterator>,
169    comm_controller: Element,
170    model: Option<AutosarModel>,
171}
172
173impl FlexrayCtrlChannelsIterator {
174    fn new(controller: &FlexrayCommunicationController, ecu: &Element) -> Self {
175        let iter = ecu.get_sub_element(ElementName::Connectors).map(|c| c.sub_elements());
176        let comm_controller = controller.element().clone();
177        let model = comm_controller.model().ok();
178        Self {
179            connector_iter: iter,
180            comm_controller,
181            model,
182        }
183    }
184}
185
186impl Iterator for FlexrayCtrlChannelsIterator {
187    type Item = FlexrayPhysicalChannel;
188
189    fn next(&mut self) -> Option<Self::Item> {
190        let model = self.model.as_ref()?;
191        let connector_iter = self.connector_iter.as_mut()?;
192        for connector in connector_iter.by_ref() {
193            if connector.element_name() == ElementName::FlexrayCommunicationConnector {
194                if let Some(commcontroller_of_connector) = connector
195                    .get_sub_element(ElementName::CommControllerRef)
196                    .and_then(|ccr| ccr.get_reference_target().ok())
197                {
198                    if commcontroller_of_connector == self.comm_controller {
199                        for ref_origin in model
200                            .get_references_to(&connector.path().ok()?)
201                            .iter()
202                            .filter_map(WeakElement::upgrade)
203                            .filter_map(|elem| elem.named_parent().ok().flatten())
204                        {
205                            // This assumes that each connector will only ever be referenced by at most one
206                            // PhysicalChannel, which is true for well-formed files.
207                            if ref_origin.element_name() == ElementName::FlexrayPhysicalChannel {
208                                return FlexrayPhysicalChannel::try_from(ref_origin).ok();
209                            }
210                        }
211                    }
212                }
213            }
214        }
215        None
216    }
217}
218
219//##################################################################
220
221#[cfg(test)]
222mod test {
223    use crate::{
224        AutosarModelAbstraction, SystemCategory,
225        communication::{FlexrayChannelName, FlexrayClusterSettings},
226    };
227
228    use super::*;
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_flexray_communication_controller("Controller");
240        let controller = result.unwrap();
241
242        // create some physical channels
243        let settings = FlexrayClusterSettings::default();
244        let cluster = system.create_flexray_cluster("FlxCluster", &pkg, &settings).unwrap();
245        let channel1 = cluster.create_physical_channel("C1", FlexrayChannelName::A).unwrap();
246
247        // connect the controller to channel1
248        let connector = controller
249            .connect_physical_channel("connection_name1", &channel1)
250            .unwrap();
251        assert_eq!(connector.controller().unwrap(), controller);
252        // can't connect to the same channel again
253        let result = controller.connect_physical_channel("connection_name2", &channel1);
254        assert!(result.is_err());
255
256        let count = controller.connected_channels().count();
257        assert_eq!(count, 1);
258
259        // remove the controller and try to list its connected channels again
260        let ctrl_parent = controller.0.parent().unwrap().unwrap();
261        ctrl_parent.remove_sub_element(controller.0.clone()).unwrap();
262        let count = controller.connected_channels().count();
263        assert_eq!(count, 0);
264    }
265
266    #[test]
267    fn connector() {
268        let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
269        let pkg = model.get_or_create_package("/test").unwrap();
270        let system = pkg.create_system("System", SystemCategory::SystemDescription).unwrap();
271        let ecu = system.create_ecu_instance("ECU", &pkg).unwrap();
272
273        // create a controller
274        let controller = ecu.create_flexray_communication_controller("Controller").unwrap();
275        assert_eq!(controller.ecu_instance().unwrap(), ecu);
276
277        // create some physical channels
278        let settings = FlexrayClusterSettings::default();
279        let cluster = system.create_flexray_cluster("FlxCluster", &pkg, &settings).unwrap();
280        let channel1 = cluster.create_physical_channel("C1", FlexrayChannelName::A).unwrap();
281
282        // connect the controller to channel1
283        let connector = controller
284            .connect_physical_channel("connection_name1", &channel1)
285            .unwrap();
286        assert_eq!(connector.controller().unwrap(), controller);
287        assert_eq!(connector.ecu_instance().unwrap(), ecu);
288
289        // remove the connector and try to get the controller again
290        let conn_parent = connector.0.parent().unwrap().unwrap();
291        conn_parent.remove_sub_element(connector.0.clone()).unwrap();
292        let result = connector.controller();
293        assert!(result.is_err());
294    }
295}