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