autosar_data_abstraction/communication/physical_channel/
flexray.rs

1use crate::{
2    AbstractionElement, AutosarAbstractionError, IdentifiableAbstractionElement, abstraction_element,
3    communication::{
4        AbstractPhysicalChannel, FlexrayCluster, FlexrayCommunicationConnector, FlexrayCommunicationCycle,
5        FlexrayFrame, FlexrayFrameTriggering, PhysicalChannel,
6    },
7};
8use autosar_data::{Element, ElementName, EnumItem};
9
10/// the `FlexrayPhysicalChannel` represents either channel A or B of Flexray cluster
11#[derive(Debug, Clone, PartialEq, Eq, Hash)]
12pub struct FlexrayPhysicalChannel(Element);
13abstraction_element!(FlexrayPhysicalChannel, FlexrayPhysicalChannel);
14impl IdentifiableAbstractionElement for FlexrayPhysicalChannel {}
15
16impl FlexrayPhysicalChannel {
17    /// get the channel name of a `FlexrayPhysicalChannel`
18    #[must_use]
19    pub fn channel_name(&self) -> Option<FlexrayChannelName> {
20        let cn = self
21            .0
22            .get_sub_element(ElementName::ChannelName)?
23            .character_data()?
24            .enum_value()?;
25        match cn {
26            EnumItem::ChannelA => Some(FlexrayChannelName::A),
27            EnumItem::ChannelB => Some(FlexrayChannelName::B),
28            _ => None,
29        }
30    }
31
32    /// remove this `FlexrayPhysicalChannel` from the model
33    pub fn remove(self, deep: bool) -> Result<(), AutosarAbstractionError> {
34        // remove all frame triggerings of this physical channel
35        for ft in self.frame_triggerings() {
36            ft.remove(deep)?;
37        }
38
39        // remove all pdu triggerings of this physical channel
40        for pt in self.pdu_triggerings() {
41            pt.remove(deep)?;
42        }
43
44        // remove all signal triggerings of this physical channel
45        for st in self.signal_triggerings() {
46            st.remove(deep)?;
47        }
48
49        // remove all connectors using this physical channel
50        for connector in self.connectors() {
51            connector.remove(deep)?;
52        }
53
54        AbstractionElement::remove(self, deep)
55    }
56
57    /// get the cluster containing this physical channel
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 cluster = system.create_flexray_cluster("Cluster", &package, &FlexrayClusterSettings::default())?;
70    /// let channel = cluster.create_physical_channel("Channel", FlexrayChannelName::A)?;
71    /// let cluster_2 = channel.cluster()?;
72    /// assert_eq!(cluster, cluster_2);
73    /// # Ok(())}
74    /// ```
75    ///
76    /// # Errors
77    ///
78    /// - [`AutosarAbstractionError::ModelError`] An error occurred in the Autosar model
79    pub fn cluster(&self) -> Result<FlexrayCluster, AutosarAbstractionError> {
80        let cluster_elem = self.0.named_parent()?.unwrap();
81        FlexrayCluster::try_from(cluster_elem)
82    }
83
84    /// add a trigger for a flexray frame in this physical channel
85    ///
86    /// # Example
87    ///
88    /// ```
89    /// # use autosar_data::*;
90    /// # use autosar_data_abstraction::*;
91    /// # use autosar_data_abstraction::communication::*;
92    /// # fn main() -> Result<(), AutosarAbstractionError> {
93    /// # let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
94    /// # let package = model.get_or_create_package("/pkg1")?;
95    /// # let frame_package = model.get_or_create_package("/Frames")?;
96    /// # let system = package.create_system("System", SystemCategory::SystemExtract)?;
97    /// # let cluster = system.create_flexray_cluster("Cluster", &package, &FlexrayClusterSettings::default())?;
98    /// let channel = cluster.create_physical_channel("Channel", FlexrayChannelName::A)?;
99    /// let frame = system.create_flexray_frame("Frame", &frame_package, 64)?;
100    /// let timing = FlexrayCommunicationCycle::Repetition {base_cycle: 1, cycle_repetition: CycleRepetition::C1};
101    /// channel.trigger_frame(&frame, 1, &timing)?;
102    /// # Ok(())}
103    /// ```
104    pub fn trigger_frame(
105        &self,
106        frame: &FlexrayFrame,
107        slot_id: u16,
108        timing: &FlexrayCommunicationCycle,
109    ) -> Result<FlexrayFrameTriggering, AutosarAbstractionError> {
110        FlexrayFrameTriggering::new(self, frame, slot_id, timing)
111    }
112
113    /// iterate over all frame triggerings of this physical channel
114    ///
115    /// # Example
116    ///
117    /// ```
118    /// # use autosar_data::*;
119    /// # use autosar_data_abstraction::{*, communication::*};
120    /// # fn main() -> Result<(), AutosarAbstractionError> {
121    /// # let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
122    /// # let package = model.get_or_create_package("/pkg1")?;
123    /// # let system = package.create_system("System", SystemCategory::SystemExtract)?;
124    /// # let cluster = system.create_flexray_cluster("Cluster", &package, &FlexrayClusterSettings::default())?;
125    /// # let channel = cluster.create_physical_channel("Channel", FlexrayChannelName::A)?;
126    /// # let frame = system.create_flexray_frame("Frame", &package, 64)?;
127    /// # let timing = FlexrayCommunicationCycle::Repetition {base_cycle: 1, cycle_repetition: CycleRepetition::C1};
128    /// channel.trigger_frame(&frame, 1, &timing)?;
129    /// for ft in channel.frame_triggerings() {
130    ///     println!("Frame triggering: {:?}", ft);
131    /// }
132    /// # assert_eq!(channel.frame_triggerings().count(), 1);
133    /// # Ok(())}
134    pub fn frame_triggerings(&self) -> impl Iterator<Item = FlexrayFrameTriggering> + Send + use<> {
135        self.0
136            .get_sub_element(ElementName::FrameTriggerings)
137            .into_iter()
138            .flat_map(|elem| elem.sub_elements())
139            .filter_map(|elem| FlexrayFrameTriggering::try_from(elem).ok())
140    }
141}
142
143impl From<FlexrayPhysicalChannel> for PhysicalChannel {
144    fn from(channel: FlexrayPhysicalChannel) -> Self {
145        PhysicalChannel::Flexray(channel)
146    }
147}
148
149impl AbstractPhysicalChannel for FlexrayPhysicalChannel {
150    type CommunicationConnectorType = FlexrayCommunicationConnector;
151}
152
153//##################################################################
154
155/// A flexray cluster may contain the channels A and/or B.
156///
157/// This enum is an abstraction over the \<CHANNEL-NAME\> element.
158#[derive(Debug, Clone, Copy, PartialEq, Eq)]
159pub enum FlexrayChannelName {
160    /// Channel A
161    A,
162    /// Channel B
163    B,
164}
165
166//##################################################################
167
168#[cfg(test)]
169mod test {
170    use crate::{
171        AbstractionElement, AutosarModelAbstraction, ByteOrder, SystemCategory,
172        communication::{AbstractFrame, FlexrayChannelName, FlexrayClusterSettings},
173    };
174    use autosar_data::{AutosarVersion, ElementName};
175
176    #[test]
177    fn channel() {
178        let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
179        let pkg = model.get_or_create_package("/test").unwrap();
180        let system = pkg.create_system("System", SystemCategory::SystemDescription).unwrap();
181        let settings = FlexrayClusterSettings::default();
182        let cluster = system.create_flexray_cluster("FlxCluster", &pkg, &settings).unwrap();
183
184        let channel = cluster
185            .create_physical_channel("channel_name", FlexrayChannelName::A)
186            .unwrap();
187        let c2 = channel.cluster().unwrap();
188        assert_eq!(cluster, c2);
189
190        let wrapped_channel: super::PhysicalChannel = channel.clone().into();
191        assert_eq!(wrapped_channel, super::PhysicalChannel::Flexray(channel.clone()));
192
193        // damage the channel info by removing the channel name
194        let elem_channelname = channel.element().get_sub_element(ElementName::ChannelName).unwrap();
195        elem_channelname.remove_character_data().unwrap();
196        assert!(channel.channel_name().is_none());
197
198        // now there is no longer a channel A
199        let channel2 = cluster.create_physical_channel("channel_name2", FlexrayChannelName::A);
200        assert!(channel2.is_ok());
201    }
202
203    #[test]
204    fn remove_channel() {
205        let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
206        let pkg = model.get_or_create_package("/test").unwrap();
207        let system = pkg.create_system("System", SystemCategory::SystemDescription).unwrap();
208        let settings = FlexrayClusterSettings::default();
209        let cluster = system.create_flexray_cluster("FlxCluster", &pkg, &settings).unwrap();
210
211        let channel = cluster
212            .create_physical_channel("channel_name", FlexrayChannelName::A)
213            .unwrap();
214
215        let frame = system.create_flexray_frame("FlexrayFrame", &pkg, 8).unwrap();
216        let timing = crate::communication::FlexrayCommunicationCycle::Repetition {
217            base_cycle: 1,
218            cycle_repetition: crate::communication::CycleRepetition::C1,
219        };
220        let _ = channel.trigger_frame(&frame, 1, &timing).unwrap();
221        let isignal_ipdu = system.create_isignal_ipdu("ISignalIPdu", &pkg, 8).unwrap();
222        let _ = frame
223            .map_pdu(&isignal_ipdu, 0, ByteOrder::MostSignificantByteLast, None)
224            .unwrap();
225
226        channel.remove(true).unwrap();
227
228        assert!(cluster.physical_channels().channel_a.is_none());
229        assert!(cluster.physical_channels().channel_b.is_none());
230
231        // the PDU was removed, because it was unused and deep removal was requested
232        assert!(isignal_ipdu.element().parent().is_err());
233    }
234}