autosar_data_abstraction/communication/frame/
flexray.rs

1use crate::communication::{
2    AbstractFrame, AbstractFrameTriggering, AbstractPdu, CommunicationDirection, FlexrayPhysicalChannel, Frame,
3    FramePort, FrameTriggering, Pdu, PduToFrameMapping, PduTriggering,
4};
5use crate::{
6    AbstractionElement, ArPackage, AutosarAbstractionError, ByteOrder, EcuInstance, IdentifiableAbstractionElement,
7    abstraction_element, make_unique_name,
8};
9use autosar_data::{Element, ElementName, EnumItem};
10
11//##################################################################
12
13/// a Flexray frame
14#[derive(Debug, Clone, PartialEq, Eq, Hash)]
15pub struct FlexrayFrame(Element);
16abstraction_element!(FlexrayFrame, FlexrayFrame);
17impl IdentifiableAbstractionElement for FlexrayFrame {}
18
19impl FlexrayFrame {
20    pub(crate) fn new(name: &str, package: &ArPackage, byte_length: u64) -> Result<Self, AutosarAbstractionError> {
21        let pkg_elements = package.element().get_or_create_sub_element(ElementName::Elements)?;
22        let fr_frame = pkg_elements.create_named_sub_element(ElementName::FlexrayFrame, name)?;
23
24        fr_frame
25            .create_sub_element(ElementName::FrameLength)?
26            .set_character_data(byte_length.to_string())?;
27
28        Ok(Self(fr_frame))
29    }
30}
31
32impl AbstractFrame for FlexrayFrame {
33    type FrameTriggeringType = FlexrayFrameTriggering;
34
35    /// Iterator over all [`FlexrayFrameTriggering`]s using this frame
36    fn frame_triggerings(&self) -> Vec<FlexrayFrameTriggering> {
37        let model_result = self.element().model();
38        let path_result = self.element().path();
39        if let (Ok(model), Ok(path)) = (model_result, path_result) {
40            model
41                .get_references_to(&path)
42                .iter()
43                .filter_map(|e| {
44                    e.upgrade()
45                        .and_then(|ref_elem| ref_elem.named_parent().ok().flatten())
46                        .and_then(|elem| FlexrayFrameTriggering::try_from(elem).ok())
47                })
48                .collect()
49        } else {
50            vec![]
51        }
52    }
53
54    /// map a PDU to the frame
55    fn map_pdu<T: AbstractPdu>(
56        &self,
57        gen_pdu: &T,
58        start_position: u32,
59        byte_order: ByteOrder,
60        update_bit: Option<u32>,
61    ) -> Result<PduToFrameMapping, AutosarAbstractionError> {
62        Frame::Flexray(self.clone()).map_pdu(gen_pdu, start_position, byte_order, update_bit)
63    }
64}
65
66//##################################################################
67
68/// The frame triggering connects a frame to a physical channel
69#[derive(Debug, Clone, PartialEq, Eq, Hash)]
70pub struct FlexrayFrameTriggering(Element);
71abstraction_element!(FlexrayFrameTriggering, FlexrayFrameTriggering);
72impl IdentifiableAbstractionElement for FlexrayFrameTriggering {}
73
74impl FlexrayFrameTriggering {
75    pub(crate) fn new(
76        channel: &FlexrayPhysicalChannel,
77        frame: &FlexrayFrame,
78        slot_id: u16,
79        timing: &FlexrayCommunicationCycle,
80    ) -> Result<Self, AutosarAbstractionError> {
81        let model = channel.element().model()?;
82        let base_path = channel.element().path()?;
83        let frame_name = frame
84            .name()
85            .ok_or(AutosarAbstractionError::InvalidParameter("invalid frame".to_string()))?;
86        let ft_name = format!("FT_{frame_name}");
87        let ft_name = make_unique_name(&model, &base_path, &ft_name);
88
89        let frame_triggerings = channel
90            .element()
91            .get_or_create_sub_element(ElementName::FrameTriggerings)?;
92        let fr_triggering =
93            frame_triggerings.create_named_sub_element(ElementName::FlexrayFrameTriggering, &ft_name)?;
94
95        fr_triggering
96            .create_sub_element(ElementName::FrameRef)?
97            .set_reference_target(frame.element())?;
98
99        let ft = Self(fr_triggering);
100        ft.set_slot(slot_id)?;
101        ft.set_timing(timing)?;
102
103        for pdu_mapping in frame.mapped_pdus() {
104            if let Some(pdu) = pdu_mapping.pdu() {
105                ft.add_pdu_triggering(&pdu)?;
106            }
107        }
108
109        Ok(ft)
110    }
111
112    /// set the slot id for the flexray frame triggering
113    pub fn set_slot(&self, slot_id: u16) -> Result<(), AutosarAbstractionError> {
114        self.element()
115            .get_or_create_sub_element(ElementName::AbsolutelyScheduledTimings)?
116            .get_or_create_sub_element(ElementName::FlexrayAbsolutelyScheduledTiming)?
117            .get_or_create_sub_element(ElementName::SlotId)?
118            .set_character_data(slot_id.to_string())?;
119        Ok(())
120    }
121
122    /// get the slot id of the flexray frame triggering
123    ///
124    /// In a well-formed file this always returns Some(value); None should only be seen if the file is incomplete.
125    #[must_use]
126    pub fn slot(&self) -> Option<u16> {
127        self.element()
128            .get_sub_element(ElementName::AbsolutelyScheduledTimings)?
129            .get_sub_element(ElementName::FlexrayAbsolutelyScheduledTiming)?
130            .get_sub_element(ElementName::SlotId)?
131            .character_data()?
132            .parse_integer()
133    }
134
135    /// set the timing of the flexray frame
136    pub fn set_timing(&self, timing: &FlexrayCommunicationCycle) -> Result<(), AutosarAbstractionError> {
137        let timings_elem = self
138            .element()
139            .get_or_create_sub_element(ElementName::AbsolutelyScheduledTimings)?
140            .get_or_create_sub_element(ElementName::FlexrayAbsolutelyScheduledTiming)?
141            .get_or_create_sub_element(ElementName::CommunicationCycle)?;
142        match timing {
143            FlexrayCommunicationCycle::Counter { cycle_counter } => {
144                let _ = timings_elem.remove_sub_element_kind(ElementName::CycleRepetition);
145                timings_elem
146                    .get_or_create_sub_element(ElementName::CycleCounter)?
147                    .get_or_create_sub_element(ElementName::CycleCounter)?
148                    .set_character_data(cycle_counter.to_string())?;
149            }
150            FlexrayCommunicationCycle::Repetition {
151                base_cycle,
152                cycle_repetition,
153            } => {
154                let _ = timings_elem.remove_sub_element_kind(ElementName::CycleCounter);
155                let repetition = timings_elem.get_or_create_sub_element(ElementName::CycleRepetition)?;
156                repetition
157                    .get_or_create_sub_element(ElementName::BaseCycle)?
158                    .set_character_data(base_cycle.to_string())?;
159                repetition
160                    .get_or_create_sub_element(ElementName::CycleRepetition)?
161                    .set_character_data::<EnumItem>((*cycle_repetition).into())?;
162            }
163        }
164        Ok(())
165    }
166
167    /// get the timing of the flexray frame
168    ///
169    /// In a well-formed file this should always return Some(...)
170    #[must_use]
171    pub fn timing(&self) -> Option<FlexrayCommunicationCycle> {
172        let timings = self
173            .element()
174            .get_sub_element(ElementName::AbsolutelyScheduledTimings)?
175            .get_sub_element(ElementName::FlexrayAbsolutelyScheduledTiming)?
176            .get_sub_element(ElementName::CommunicationCycle)?;
177
178        if let Some(counter_based) = timings.get_sub_element(ElementName::CycleCounter) {
179            let cycle_counter = counter_based
180                .get_sub_element(ElementName::CycleCounter)?
181                .character_data()?
182                .parse_integer()?;
183            Some(FlexrayCommunicationCycle::Counter { cycle_counter })
184        } else if let Some(repetition) = timings.get_sub_element(ElementName::CycleRepetition) {
185            let base_cycle = repetition
186                .get_sub_element(ElementName::BaseCycle)?
187                .character_data()?
188                .parse_integer()?;
189            let cycle_repetition = repetition
190                .get_sub_element(ElementName::CycleRepetition)?
191                .character_data()?
192                .enum_value()?
193                .try_into()
194                .ok()?;
195
196            Some(FlexrayCommunicationCycle::Repetition {
197                base_cycle,
198                cycle_repetition,
199            })
200        } else {
201            None
202        }
203    }
204
205    pub(crate) fn add_pdu_triggering(&self, pdu: &Pdu) -> Result<PduTriggering, AutosarAbstractionError> {
206        FrameTriggering::Flexray(self.clone()).add_pdu_triggering(pdu)
207    }
208
209    /// get the physical channel that contains this frame triggering
210    pub fn physical_channel(&self) -> Result<FlexrayPhysicalChannel, AutosarAbstractionError> {
211        let channel_elem = self.element().named_parent()?.unwrap();
212        FlexrayPhysicalChannel::try_from(channel_elem)
213    }
214
215    /// connect this frame triggering to an ECU
216    ///
217    /// The frame triggering may be connected to any number of ECUs.
218    pub fn connect_to_ecu(
219        &self,
220        ecu: &EcuInstance,
221        direction: CommunicationDirection,
222    ) -> Result<FramePort, AutosarAbstractionError> {
223        FrameTriggering::Flexray(self.clone()).connect_to_ecu(ecu, direction)
224    }
225}
226
227impl AbstractFrameTriggering for FlexrayFrameTriggering {
228    type FrameType = FlexrayFrame;
229}
230
231impl From<FlexrayFrameTriggering> for FrameTriggering {
232    fn from(fft: FlexrayFrameTriggering) -> Self {
233        FrameTriggering::Flexray(fft)
234    }
235}
236
237//##################################################################
238
239/// The timing settings of a Flexray frame
240#[derive(Debug, Clone, Copy, PartialEq, Eq)]
241pub enum FlexrayCommunicationCycle {
242    /// The frame is sent every `cycle_counter` cycles
243    Counter {
244        /// the cycle counter
245        cycle_counter: u8,
246    },
247    /// The frame is sent every `base_cycle` cycles and repeated every `cycle_repetition` cycles
248    Repetition {
249        /// the base cycle - typically 64
250        base_cycle: u8,
251        /// the cycle repetition
252        cycle_repetition: CycleRepetition,
253    },
254}
255
256/// The cycle repetition of a Flexray frame, from the Flexray standard
257#[derive(Debug, Clone, Copy, PartialEq, Eq)]
258pub enum CycleRepetition {
259    /// 1 - sent every cycle
260    C1,
261    /// 2 - sent every second cycle
262    C2,
263    /// 4 - sent every fourth cycle
264    C4,
265    /// 5 - sent every fifth cycle (Flexray 3.0 only)
266    C5,
267    /// 8 - sent every eighth cycle
268    C8,
269    /// 10 - sent every tenth cycle (Flexray 3.0 only)
270    C10,
271    /// 16 - sent every sixteenth cycle
272    C16,
273    /// 20 - sent every twentieth cycle (Flexray 3.0 only)
274    C20,
275    /// 32 - sent every thirty-second cycle
276    C32,
277    /// 40 - sent every fortieth cycle (Flexray 3.0 only)
278    C40,
279    /// 50 - sent every fiftieth cycle (Flexray 3.0 only)
280    C50,
281    /// 64 - sent every sixty-fourth cycle
282    C64,
283}
284
285impl TryFrom<EnumItem> for CycleRepetition {
286    type Error = AutosarAbstractionError;
287
288    fn try_from(value: EnumItem) -> Result<Self, Self::Error> {
289        match value {
290            EnumItem::CycleRepetition1 => Ok(Self::C1),
291            EnumItem::CycleRepetition2 => Ok(Self::C2),
292            EnumItem::CycleRepetition4 => Ok(Self::C4),
293            EnumItem::CycleRepetition5 => Ok(Self::C5),
294            EnumItem::CycleRepetition8 => Ok(Self::C8),
295            EnumItem::CycleRepetition10 => Ok(Self::C10),
296            EnumItem::CycleRepetition16 => Ok(Self::C16),
297            EnumItem::CycleRepetition20 => Ok(Self::C20),
298            EnumItem::CycleRepetition32 => Ok(Self::C32),
299            EnumItem::CycleRepetition40 => Ok(Self::C40),
300            EnumItem::CycleRepetition50 => Ok(Self::C50),
301            EnumItem::CycleRepetition64 => Ok(Self::C64),
302
303            _ => Err(AutosarAbstractionError::ValueConversionError {
304                value: value.to_string(),
305                dest: "CycleRepetitionType".to_string(),
306            }),
307        }
308    }
309}
310
311impl From<CycleRepetition> for EnumItem {
312    fn from(value: CycleRepetition) -> Self {
313        match value {
314            CycleRepetition::C1 => EnumItem::CycleRepetition1,
315            CycleRepetition::C2 => EnumItem::CycleRepetition2,
316            CycleRepetition::C4 => EnumItem::CycleRepetition4,
317            CycleRepetition::C5 => EnumItem::CycleRepetition5,
318            CycleRepetition::C8 => EnumItem::CycleRepetition8,
319            CycleRepetition::C10 => EnumItem::CycleRepetition10,
320            CycleRepetition::C16 => EnumItem::CycleRepetition16,
321            CycleRepetition::C20 => EnumItem::CycleRepetition20,
322            CycleRepetition::C32 => EnumItem::CycleRepetition32,
323            CycleRepetition::C40 => EnumItem::CycleRepetition40,
324            CycleRepetition::C50 => EnumItem::CycleRepetition50,
325            CycleRepetition::C64 => EnumItem::CycleRepetition64,
326        }
327    }
328}
329
330//##################################################################
331
332#[cfg(test)]
333mod test {
334    use super::*;
335    use crate::{
336        AutosarModelAbstraction, ByteOrder, SystemCategory,
337        communication::{FlexrayChannelName, FlexrayClusterSettings},
338    };
339    use autosar_data::AutosarVersion;
340
341    #[test]
342    fn fr_frame() {
343        let model = AutosarModelAbstraction::create("test", AutosarVersion::LATEST);
344        let package = model.get_or_create_package("/package").unwrap();
345        let system = package.create_system("System", SystemCategory::EcuExtract).unwrap();
346        let flexray_cluster = system
347            .create_flexray_cluster("Cluster", &package, &FlexrayClusterSettings::default())
348            .unwrap();
349        let channel = flexray_cluster
350            .create_physical_channel("Channel", FlexrayChannelName::A)
351            .unwrap();
352
353        let ecu_instance = system.create_ecu_instance("ECU", &package).unwrap();
354        let can_controller = ecu_instance
355            .create_flexray_communication_controller("Controller")
356            .unwrap();
357        can_controller.connect_physical_channel("connection", &channel).unwrap();
358
359        let pdu1 = system.create_isignal_ipdu("pdu1", &package, 8).unwrap();
360        let pdu2 = system.create_isignal_ipdu("pdu2", &package, 8).unwrap();
361
362        // create two frames
363        let frame1 = system.create_flexray_frame("frame1", &package, 64).unwrap();
364        let frame2 = system.create_flexray_frame("frame2", &package, 64).unwrap();
365
366        assert_eq!(frame1.length().unwrap(), 64);
367        frame1.set_length(60).unwrap();
368        assert_eq!(frame1.length().unwrap(), 60);
369
370        // map a PDU to frame1 before it has been connected to the channel
371        let mapping = frame1
372            .map_pdu(&pdu1, 7, ByteOrder::MostSignificantByteFirst, Some(8))
373            .unwrap();
374        assert!(frame1.mapped_pdus().count() == 1);
375        assert_eq!(frame1.mapped_pdus().next().unwrap(), mapping);
376
377        // trigger both frames
378        let frame_triggering1 = channel
379            .trigger_frame(
380                &frame1,
381                1,
382                &FlexrayCommunicationCycle::Repetition {
383                    base_cycle: 1,
384                    cycle_repetition: CycleRepetition::C1,
385                },
386            )
387            .unwrap();
388        assert_eq!(frame1.frame_triggerings().len(), 1);
389        let frame_triggering2 = channel
390            .trigger_frame(&frame2, 2, &FlexrayCommunicationCycle::Counter { cycle_counter: 2 })
391            .unwrap();
392        assert_eq!(frame2.frame_triggerings().len(), 1);
393        assert_eq!(channel.frame_triggerings().count(), 2);
394
395        // a pdu triggering for the mapped pdu should be created when the frame is connected to the channel
396        assert_eq!(frame_triggering1.pdu_triggerings().count(), 1);
397
398        // map another PDU to the frame after it has been connected to the channel
399        let _ = frame1
400            .map_pdu(&pdu2, 71, ByteOrder::MostSignificantByteFirst, None)
401            .unwrap();
402        assert!(frame1.mapped_pdus().count() == 2);
403
404        // mapping the PDU to the connected frame should create a PDU triggering
405        assert_eq!(frame_triggering1.pdu_triggerings().count(), 2);
406
407        // connect the frame triggering to an ECU
408        let frame_port = frame_triggering1
409            .connect_to_ecu(&ecu_instance, CommunicationDirection::Out)
410            .unwrap();
411        assert_eq!(frame_port.ecu().unwrap(), ecu_instance);
412        assert_eq!(
413            frame_port.communication_direction().unwrap(),
414            CommunicationDirection::Out
415        );
416        frame_port.set_name("port").unwrap();
417        assert_eq!(frame_port.name().unwrap(), "port");
418
419        assert_eq!(frame_triggering1.frame().unwrap(), frame1);
420        assert_eq!(frame_triggering1.slot().unwrap(), 1);
421        assert_eq!(
422            frame_triggering1.timing().unwrap(),
423            FlexrayCommunicationCycle::Repetition {
424                base_cycle: 1,
425                cycle_repetition: CycleRepetition::C1
426            }
427        );
428        assert_eq!(frame_triggering1.physical_channel().unwrap(), channel);
429        assert_eq!(frame_triggering2.frame().unwrap(), frame2);
430        assert_eq!(frame_triggering2.slot().unwrap(), 2);
431        assert_eq!(
432            frame_triggering2.timing().unwrap(),
433            FlexrayCommunicationCycle::Counter { cycle_counter: 2 }
434        );
435        assert_eq!(frame_triggering2.physical_channel().unwrap(), channel);
436
437        assert_eq!(mapping.pdu().unwrap(), pdu1.into());
438        assert_eq!(mapping.byte_order().unwrap(), ByteOrder::MostSignificantByteFirst);
439        assert_eq!(mapping.start_position().unwrap(), 7);
440        assert_eq!(mapping.update_bit(), Some(8));
441    }
442
443    #[test]
444    fn cycle_repetition() {
445        assert_eq!(EnumItem::CycleRepetition1, CycleRepetition::C1.into());
446        assert_eq!(EnumItem::CycleRepetition2, CycleRepetition::C2.into());
447        assert_eq!(EnumItem::CycleRepetition4, CycleRepetition::C4.into());
448        assert_eq!(EnumItem::CycleRepetition5, CycleRepetition::C5.into());
449        assert_eq!(EnumItem::CycleRepetition8, CycleRepetition::C8.into());
450        assert_eq!(EnumItem::CycleRepetition10, CycleRepetition::C10.into());
451        assert_eq!(EnumItem::CycleRepetition16, CycleRepetition::C16.into());
452        assert_eq!(EnumItem::CycleRepetition20, CycleRepetition::C20.into());
453        assert_eq!(EnumItem::CycleRepetition32, CycleRepetition::C32.into());
454        assert_eq!(EnumItem::CycleRepetition40, CycleRepetition::C40.into());
455        assert_eq!(EnumItem::CycleRepetition50, CycleRepetition::C50.into());
456        assert_eq!(EnumItem::CycleRepetition64, CycleRepetition::C64.into());
457
458        assert_eq!(CycleRepetition::C1, EnumItem::CycleRepetition1.try_into().unwrap());
459        assert_eq!(CycleRepetition::C2, EnumItem::CycleRepetition2.try_into().unwrap());
460        assert_eq!(CycleRepetition::C4, EnumItem::CycleRepetition4.try_into().unwrap());
461        assert_eq!(CycleRepetition::C5, EnumItem::CycleRepetition5.try_into().unwrap());
462        assert_eq!(CycleRepetition::C8, EnumItem::CycleRepetition8.try_into().unwrap());
463        assert_eq!(CycleRepetition::C10, EnumItem::CycleRepetition10.try_into().unwrap());
464        assert_eq!(CycleRepetition::C16, EnumItem::CycleRepetition16.try_into().unwrap());
465        assert_eq!(CycleRepetition::C20, EnumItem::CycleRepetition20.try_into().unwrap());
466        assert_eq!(CycleRepetition::C32, EnumItem::CycleRepetition32.try_into().unwrap());
467        assert_eq!(CycleRepetition::C40, EnumItem::CycleRepetition40.try_into().unwrap());
468        assert_eq!(CycleRepetition::C50, EnumItem::CycleRepetition50.try_into().unwrap());
469        assert_eq!(CycleRepetition::C64, EnumItem::CycleRepetition64.try_into().unwrap());
470
471        let result: Result<CycleRepetition, _> = EnumItem::Aa.try_into();
472        assert!(result.is_err());
473    }
474}