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, is_used_system_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    /// remove this `FlexrayFrame` from the model
32    pub fn remove(self, deep: bool) -> Result<(), AutosarAbstractionError> {
33        for pdu_mapping in self.mapped_pdus() {
34            pdu_mapping.remove(deep)?;
35        }
36
37        // get all frame triggerings using this frame
38        let frame_triggerings = self.frame_triggerings();
39
40        // remove the element itself
41        AbstractionElement::remove(self, deep)?;
42
43        // remove the frame triggerings
44        for ft in frame_triggerings {
45            ft.remove(deep)?;
46        }
47
48        Ok(())
49    }
50}
51
52impl AbstractFrame for FlexrayFrame {
53    type FrameTriggeringType = FlexrayFrameTriggering;
54
55    /// Iterator over all [`FlexrayFrameTriggering`]s using this frame
56    fn frame_triggerings(&self) -> Vec<FlexrayFrameTriggering> {
57        let model_result = self.element().model();
58        let path_result = self.element().path();
59        if let (Ok(model), Ok(path)) = (model_result, path_result) {
60            model
61                .get_references_to(&path)
62                .iter()
63                .filter_map(|e| {
64                    e.upgrade()
65                        .and_then(|ref_elem| ref_elem.named_parent().ok().flatten())
66                        .and_then(|elem| FlexrayFrameTriggering::try_from(elem).ok())
67                })
68                .collect()
69        } else {
70            vec![]
71        }
72    }
73
74    /// map a PDU to the frame
75    fn map_pdu<T: AbstractPdu>(
76        &self,
77        gen_pdu: &T,
78        start_position: u32,
79        byte_order: ByteOrder,
80        update_bit: Option<u32>,
81    ) -> Result<PduToFrameMapping, AutosarAbstractionError> {
82        Frame::Flexray(self.clone()).map_pdu(gen_pdu, start_position, byte_order, update_bit)
83    }
84}
85
86//##################################################################
87
88/// The frame triggering connects a frame to a physical channel
89#[derive(Debug, Clone, PartialEq, Eq, Hash)]
90pub struct FlexrayFrameTriggering(Element);
91abstraction_element!(FlexrayFrameTriggering, FlexrayFrameTriggering);
92impl IdentifiableAbstractionElement for FlexrayFrameTriggering {}
93
94impl FlexrayFrameTriggering {
95    pub(crate) fn new(
96        channel: &FlexrayPhysicalChannel,
97        frame: &FlexrayFrame,
98        slot_id: u16,
99        timing: &FlexrayCommunicationCycle,
100    ) -> Result<Self, AutosarAbstractionError> {
101        let model = channel.element().model()?;
102        let base_path = channel.element().path()?;
103        let frame_name = frame
104            .name()
105            .ok_or(AutosarAbstractionError::InvalidParameter("invalid frame".to_string()))?;
106        let ft_name = format!("FT_{frame_name}");
107        let ft_name = make_unique_name(&model, &base_path, &ft_name);
108
109        let frame_triggerings = channel
110            .element()
111            .get_or_create_sub_element(ElementName::FrameTriggerings)?;
112        let fr_triggering =
113            frame_triggerings.create_named_sub_element(ElementName::FlexrayFrameTriggering, &ft_name)?;
114
115        fr_triggering
116            .create_sub_element(ElementName::FrameRef)?
117            .set_reference_target(frame.element())?;
118
119        let ft = Self(fr_triggering);
120        ft.set_slot(slot_id)?;
121        ft.set_timing(timing)?;
122
123        for pdu_mapping in frame.mapped_pdus() {
124            if let Some(pdu) = pdu_mapping.pdu() {
125                ft.add_pdu_triggering(&pdu)?;
126            }
127        }
128
129        Ok(ft)
130    }
131
132    /// remove this `FlexrayFrameTriggering` from the model
133    pub fn remove(self, deep: bool) -> Result<(), AutosarAbstractionError> {
134        let opt_frame = self.frame();
135
136        // remove all pdu triggerings of this frame triggering
137        for pt in self.pdu_triggerings() {
138            pt.remove(deep)?;
139        }
140        for frame_port in self.frame_ports() {
141            frame_port.remove(deep)?;
142        }
143
144        AbstractionElement::remove(self, deep)?;
145
146        // if deep, check if the frame became unused because of this frame triggering removal
147        // if so remove it too
148        if deep && let Some(frame) = opt_frame {
149            // check if any frame became unused because of this frame triggering removal
150            // if so remove it too
151            if !is_used_system_element(frame.element()) {
152                frame.remove(deep)?;
153            }
154        }
155
156        Ok(())
157    }
158
159    /// set the slot id for the flexray frame triggering
160    pub fn set_slot(&self, slot_id: u16) -> Result<(), AutosarAbstractionError> {
161        self.element()
162            .get_or_create_sub_element(ElementName::AbsolutelyScheduledTimings)?
163            .get_or_create_sub_element(ElementName::FlexrayAbsolutelyScheduledTiming)?
164            .get_or_create_sub_element(ElementName::SlotId)?
165            .set_character_data(slot_id.to_string())?;
166        Ok(())
167    }
168
169    /// get the slot id of the flexray frame triggering
170    ///
171    /// In a well-formed file this always returns Some(value); None should only be seen if the file is incomplete.
172    #[must_use]
173    pub fn slot(&self) -> Option<u16> {
174        self.element()
175            .get_sub_element(ElementName::AbsolutelyScheduledTimings)?
176            .get_sub_element(ElementName::FlexrayAbsolutelyScheduledTiming)?
177            .get_sub_element(ElementName::SlotId)?
178            .character_data()?
179            .parse_integer()
180    }
181
182    /// set the timing of the flexray frame
183    pub fn set_timing(&self, timing: &FlexrayCommunicationCycle) -> Result<(), AutosarAbstractionError> {
184        let timings_elem = self
185            .element()
186            .get_or_create_sub_element(ElementName::AbsolutelyScheduledTimings)?
187            .get_or_create_sub_element(ElementName::FlexrayAbsolutelyScheduledTiming)?
188            .get_or_create_sub_element(ElementName::CommunicationCycle)?;
189        match timing {
190            FlexrayCommunicationCycle::Counter { cycle_counter } => {
191                let _ = timings_elem.remove_sub_element_kind(ElementName::CycleRepetition);
192                timings_elem
193                    .get_or_create_sub_element(ElementName::CycleCounter)?
194                    .get_or_create_sub_element(ElementName::CycleCounter)?
195                    .set_character_data(cycle_counter.to_string())?;
196            }
197            FlexrayCommunicationCycle::Repetition {
198                base_cycle,
199                cycle_repetition,
200            } => {
201                let _ = timings_elem.remove_sub_element_kind(ElementName::CycleCounter);
202                let repetition = timings_elem.get_or_create_sub_element(ElementName::CycleRepetition)?;
203                repetition
204                    .get_or_create_sub_element(ElementName::BaseCycle)?
205                    .set_character_data(base_cycle.to_string())?;
206                repetition
207                    .get_or_create_sub_element(ElementName::CycleRepetition)?
208                    .set_character_data::<EnumItem>((*cycle_repetition).into())?;
209            }
210        }
211        Ok(())
212    }
213
214    /// get the timing of the flexray frame
215    ///
216    /// In a well-formed file this should always return Some(...)
217    #[must_use]
218    pub fn timing(&self) -> Option<FlexrayCommunicationCycle> {
219        let timings = self
220            .element()
221            .get_sub_element(ElementName::AbsolutelyScheduledTimings)?
222            .get_sub_element(ElementName::FlexrayAbsolutelyScheduledTiming)?
223            .get_sub_element(ElementName::CommunicationCycle)?;
224
225        if let Some(counter_based) = timings.get_sub_element(ElementName::CycleCounter) {
226            let cycle_counter = counter_based
227                .get_sub_element(ElementName::CycleCounter)?
228                .character_data()?
229                .parse_integer()?;
230            Some(FlexrayCommunicationCycle::Counter { cycle_counter })
231        } else if let Some(repetition) = timings.get_sub_element(ElementName::CycleRepetition) {
232            let base_cycle = repetition
233                .get_sub_element(ElementName::BaseCycle)?
234                .character_data()?
235                .parse_integer()?;
236            let cycle_repetition = repetition
237                .get_sub_element(ElementName::CycleRepetition)?
238                .character_data()?
239                .enum_value()?
240                .try_into()
241                .ok()?;
242
243            Some(FlexrayCommunicationCycle::Repetition {
244                base_cycle,
245                cycle_repetition,
246            })
247        } else {
248            None
249        }
250    }
251
252    pub(crate) fn add_pdu_triggering(&self, pdu: &Pdu) -> Result<PduTriggering, AutosarAbstractionError> {
253        FrameTriggering::Flexray(self.clone()).add_pdu_triggering(pdu)
254    }
255
256    /// get the physical channel that contains this frame triggering
257    pub fn physical_channel(&self) -> Result<FlexrayPhysicalChannel, AutosarAbstractionError> {
258        let channel_elem = self.element().named_parent()?.unwrap();
259        FlexrayPhysicalChannel::try_from(channel_elem)
260    }
261
262    /// connect this frame triggering to an ECU
263    ///
264    /// The frame triggering may be connected to any number of ECUs.
265    pub fn connect_to_ecu(
266        &self,
267        ecu: &EcuInstance,
268        direction: CommunicationDirection,
269    ) -> Result<FramePort, AutosarAbstractionError> {
270        FrameTriggering::Flexray(self.clone()).connect_to_ecu(ecu, direction)
271    }
272}
273
274impl AbstractFrameTriggering for FlexrayFrameTriggering {
275    type FrameType = FlexrayFrame;
276}
277
278impl From<FlexrayFrameTriggering> for FrameTriggering {
279    fn from(fft: FlexrayFrameTriggering) -> Self {
280        FrameTriggering::Flexray(fft)
281    }
282}
283
284//##################################################################
285
286/// The timing settings of a Flexray frame
287#[derive(Debug, Clone, Copy, PartialEq, Eq)]
288pub enum FlexrayCommunicationCycle {
289    /// The frame is sent every `cycle_counter` cycles
290    Counter {
291        /// the cycle counter
292        cycle_counter: u8,
293    },
294    /// The frame is sent every `base_cycle` cycles and repeated every `cycle_repetition` cycles
295    Repetition {
296        /// the base cycle - typically 64
297        base_cycle: u8,
298        /// the cycle repetition
299        cycle_repetition: CycleRepetition,
300    },
301}
302
303/// The cycle repetition of a Flexray frame, from the Flexray standard
304#[derive(Debug, Clone, Copy, PartialEq, Eq)]
305pub enum CycleRepetition {
306    /// 1 - sent every cycle
307    C1,
308    /// 2 - sent every second cycle
309    C2,
310    /// 4 - sent every fourth cycle
311    C4,
312    /// 5 - sent every fifth cycle (Flexray 3.0 only)
313    C5,
314    /// 8 - sent every eighth cycle
315    C8,
316    /// 10 - sent every tenth cycle (Flexray 3.0 only)
317    C10,
318    /// 16 - sent every sixteenth cycle
319    C16,
320    /// 20 - sent every twentieth cycle (Flexray 3.0 only)
321    C20,
322    /// 32 - sent every thirty-second cycle
323    C32,
324    /// 40 - sent every fortieth cycle (Flexray 3.0 only)
325    C40,
326    /// 50 - sent every fiftieth cycle (Flexray 3.0 only)
327    C50,
328    /// 64 - sent every sixty-fourth cycle
329    C64,
330}
331
332impl TryFrom<EnumItem> for CycleRepetition {
333    type Error = AutosarAbstractionError;
334
335    fn try_from(value: EnumItem) -> Result<Self, Self::Error> {
336        match value {
337            EnumItem::CycleRepetition1 => Ok(Self::C1),
338            EnumItem::CycleRepetition2 => Ok(Self::C2),
339            EnumItem::CycleRepetition4 => Ok(Self::C4),
340            EnumItem::CycleRepetition5 => Ok(Self::C5),
341            EnumItem::CycleRepetition8 => Ok(Self::C8),
342            EnumItem::CycleRepetition10 => Ok(Self::C10),
343            EnumItem::CycleRepetition16 => Ok(Self::C16),
344            EnumItem::CycleRepetition20 => Ok(Self::C20),
345            EnumItem::CycleRepetition32 => Ok(Self::C32),
346            EnumItem::CycleRepetition40 => Ok(Self::C40),
347            EnumItem::CycleRepetition50 => Ok(Self::C50),
348            EnumItem::CycleRepetition64 => Ok(Self::C64),
349
350            _ => Err(AutosarAbstractionError::ValueConversionError {
351                value: value.to_string(),
352                dest: "CycleRepetitionType".to_string(),
353            }),
354        }
355    }
356}
357
358impl From<CycleRepetition> for EnumItem {
359    fn from(value: CycleRepetition) -> Self {
360        match value {
361            CycleRepetition::C1 => EnumItem::CycleRepetition1,
362            CycleRepetition::C2 => EnumItem::CycleRepetition2,
363            CycleRepetition::C4 => EnumItem::CycleRepetition4,
364            CycleRepetition::C5 => EnumItem::CycleRepetition5,
365            CycleRepetition::C8 => EnumItem::CycleRepetition8,
366            CycleRepetition::C10 => EnumItem::CycleRepetition10,
367            CycleRepetition::C16 => EnumItem::CycleRepetition16,
368            CycleRepetition::C20 => EnumItem::CycleRepetition20,
369            CycleRepetition::C32 => EnumItem::CycleRepetition32,
370            CycleRepetition::C40 => EnumItem::CycleRepetition40,
371            CycleRepetition::C50 => EnumItem::CycleRepetition50,
372            CycleRepetition::C64 => EnumItem::CycleRepetition64,
373        }
374    }
375}
376
377//##################################################################
378
379#[cfg(test)]
380mod test {
381    use super::*;
382    use crate::{
383        AutosarModelAbstraction, ByteOrder, SystemCategory,
384        communication::{AbstractPhysicalChannel, FlexrayChannelName, FlexrayClusterSettings},
385    };
386    use autosar_data::AutosarVersion;
387
388    #[test]
389    fn fr_frame() {
390        let model = AutosarModelAbstraction::create("test", AutosarVersion::LATEST);
391        let package = model.get_or_create_package("/package").unwrap();
392        let system = package.create_system("System", SystemCategory::EcuExtract).unwrap();
393        let flexray_cluster = system
394            .create_flexray_cluster("Cluster", &package, &FlexrayClusterSettings::default())
395            .unwrap();
396        let channel = flexray_cluster
397            .create_physical_channel("Channel", FlexrayChannelName::A)
398            .unwrap();
399
400        let ecu_instance = system.create_ecu_instance("ECU", &package).unwrap();
401        let can_controller = ecu_instance
402            .create_flexray_communication_controller("Controller")
403            .unwrap();
404        can_controller.connect_physical_channel("connection", &channel).unwrap();
405
406        let pdu1 = system.create_isignal_ipdu("pdu1", &package, 8).unwrap();
407        let pdu2 = system.create_isignal_ipdu("pdu2", &package, 8).unwrap();
408
409        // create two frames
410        let frame1 = system.create_flexray_frame("frame1", &package, 64).unwrap();
411        let frame2 = system.create_flexray_frame("frame2", &package, 64).unwrap();
412
413        assert_eq!(frame1.length().unwrap(), 64);
414        frame1.set_length(60).unwrap();
415        assert_eq!(frame1.length().unwrap(), 60);
416
417        // map a PDU to frame1 before it has been connected to the channel
418        let mapping = frame1
419            .map_pdu(&pdu1, 7, ByteOrder::MostSignificantByteFirst, Some(8))
420            .unwrap();
421        assert!(frame1.mapped_pdus().count() == 1);
422        assert_eq!(frame1.mapped_pdus().next().unwrap(), mapping);
423
424        // trigger both frames
425        let frame_triggering1 = channel
426            .trigger_frame(
427                &frame1,
428                1,
429                &FlexrayCommunicationCycle::Repetition {
430                    base_cycle: 1,
431                    cycle_repetition: CycleRepetition::C1,
432                },
433            )
434            .unwrap();
435        assert_eq!(frame1.frame_triggerings().len(), 1);
436        let frame_triggering2 = channel
437            .trigger_frame(&frame2, 2, &FlexrayCommunicationCycle::Counter { cycle_counter: 2 })
438            .unwrap();
439        assert_eq!(frame2.frame_triggerings().len(), 1);
440        assert_eq!(channel.frame_triggerings().count(), 2);
441
442        // a pdu triggering for the mapped pdu should be created when the frame is connected to the channel
443        assert_eq!(frame_triggering1.pdu_triggerings().count(), 1);
444
445        // map another PDU to the frame after it has been connected to the channel
446        let _ = frame1
447            .map_pdu(&pdu2, 71, ByteOrder::MostSignificantByteFirst, None)
448            .unwrap();
449        assert!(frame1.mapped_pdus().count() == 2);
450
451        // mapping the PDU to the connected frame should create a PDU triggering
452        assert_eq!(frame_triggering1.pdu_triggerings().count(), 2);
453
454        // connect the frame triggering to an ECU
455        let frame_port = frame_triggering1
456            .connect_to_ecu(&ecu_instance, CommunicationDirection::Out)
457            .unwrap();
458        assert_eq!(frame_port.ecu().unwrap(), ecu_instance);
459        assert_eq!(
460            frame_port.communication_direction().unwrap(),
461            CommunicationDirection::Out
462        );
463        frame_port.set_name("port").unwrap();
464        assert_eq!(frame_port.name().unwrap(), "port");
465
466        assert_eq!(frame_triggering1.frame().unwrap(), frame1);
467        assert_eq!(frame_triggering1.slot().unwrap(), 1);
468        assert_eq!(
469            frame_triggering1.timing().unwrap(),
470            FlexrayCommunicationCycle::Repetition {
471                base_cycle: 1,
472                cycle_repetition: CycleRepetition::C1
473            }
474        );
475        assert_eq!(frame_triggering1.physical_channel().unwrap(), channel);
476        assert_eq!(frame_triggering2.frame().unwrap(), frame2);
477        assert_eq!(frame_triggering2.slot().unwrap(), 2);
478        assert_eq!(
479            frame_triggering2.timing().unwrap(),
480            FlexrayCommunicationCycle::Counter { cycle_counter: 2 }
481        );
482        assert_eq!(frame_triggering2.physical_channel().unwrap(), channel);
483
484        assert_eq!(mapping.pdu().unwrap(), pdu1.into());
485        assert_eq!(mapping.byte_order().unwrap(), ByteOrder::MostSignificantByteFirst);
486        assert_eq!(mapping.start_position().unwrap(), 7);
487        assert_eq!(mapping.update_bit(), Some(8));
488    }
489
490    #[test]
491    fn cycle_repetition() {
492        assert_eq!(EnumItem::CycleRepetition1, CycleRepetition::C1.into());
493        assert_eq!(EnumItem::CycleRepetition2, CycleRepetition::C2.into());
494        assert_eq!(EnumItem::CycleRepetition4, CycleRepetition::C4.into());
495        assert_eq!(EnumItem::CycleRepetition5, CycleRepetition::C5.into());
496        assert_eq!(EnumItem::CycleRepetition8, CycleRepetition::C8.into());
497        assert_eq!(EnumItem::CycleRepetition10, CycleRepetition::C10.into());
498        assert_eq!(EnumItem::CycleRepetition16, CycleRepetition::C16.into());
499        assert_eq!(EnumItem::CycleRepetition20, CycleRepetition::C20.into());
500        assert_eq!(EnumItem::CycleRepetition32, CycleRepetition::C32.into());
501        assert_eq!(EnumItem::CycleRepetition40, CycleRepetition::C40.into());
502        assert_eq!(EnumItem::CycleRepetition50, CycleRepetition::C50.into());
503        assert_eq!(EnumItem::CycleRepetition64, CycleRepetition::C64.into());
504
505        assert_eq!(CycleRepetition::C1, EnumItem::CycleRepetition1.try_into().unwrap());
506        assert_eq!(CycleRepetition::C2, EnumItem::CycleRepetition2.try_into().unwrap());
507        assert_eq!(CycleRepetition::C4, EnumItem::CycleRepetition4.try_into().unwrap());
508        assert_eq!(CycleRepetition::C5, EnumItem::CycleRepetition5.try_into().unwrap());
509        assert_eq!(CycleRepetition::C8, EnumItem::CycleRepetition8.try_into().unwrap());
510        assert_eq!(CycleRepetition::C10, EnumItem::CycleRepetition10.try_into().unwrap());
511        assert_eq!(CycleRepetition::C16, EnumItem::CycleRepetition16.try_into().unwrap());
512        assert_eq!(CycleRepetition::C20, EnumItem::CycleRepetition20.try_into().unwrap());
513        assert_eq!(CycleRepetition::C32, EnumItem::CycleRepetition32.try_into().unwrap());
514        assert_eq!(CycleRepetition::C40, EnumItem::CycleRepetition40.try_into().unwrap());
515        assert_eq!(CycleRepetition::C50, EnumItem::CycleRepetition50.try_into().unwrap());
516        assert_eq!(CycleRepetition::C64, EnumItem::CycleRepetition64.try_into().unwrap());
517
518        let result: Result<CycleRepetition, _> = EnumItem::Aa.try_into();
519        assert!(result.is_err());
520    }
521
522    #[test]
523    fn remove_frame_triggering() {
524        let model = AutosarModelAbstraction::create("test", AutosarVersion::LATEST);
525        let package = model.get_or_create_package("/package").unwrap();
526        let system = package.create_system("System", SystemCategory::EcuExtract).unwrap();
527        let flexray_cluster = system
528            .create_flexray_cluster("Cluster", &package, &FlexrayClusterSettings::default())
529            .unwrap();
530        let channel = flexray_cluster
531            .create_physical_channel("Channel", FlexrayChannelName::A)
532            .unwrap();
533
534        let frame = system.create_flexray_frame("frame", &package, 8).unwrap();
535        let pdu = system.create_isignal_ipdu("pdu", &package, 8).unwrap();
536
537        let frame_triggering = channel
538            .trigger_frame(&frame, 0x123, &FlexrayCommunicationCycle::Counter { cycle_counter: 1 })
539            .unwrap();
540
541        let _mapping = frame
542            .map_pdu(&pdu, 0, ByteOrder::MostSignificantByteLast, None)
543            .unwrap();
544
545        assert_eq!(frame.mapped_pdus().count(), 1);
546        assert_eq!(frame.frame_triggerings().len(), 1);
547        assert_eq!(channel.frame_triggerings().count(), 1);
548
549        // remove the frame triggering
550        frame_triggering.remove(false).unwrap();
551        // the frame remains because we did a shallow removal
552        assert_eq!(system.frames().count(), 1);
553
554        // re-create the frame triggering
555        let frame_triggering = channel
556            .trigger_frame(&frame, 0x123, &FlexrayCommunicationCycle::Counter { cycle_counter: 1 })
557            .unwrap();
558        // remove the frame triggering with deep=true
559        frame_triggering.remove(true).unwrap();
560
561        // the frame triggering should be removed
562        assert_eq!(channel.frame_triggerings().count(), 0);
563        // the frame should be removed because it became unused
564        assert_eq!(system.frames().count(), 0);
565        // the mapping should be removed because the frame was removed
566        assert_eq!(frame.mapped_pdus().count(), 0);
567        // the pdu was also removed, because it became unused and we did a deep removal
568        assert_eq!(system.pdus().count(), 0);
569
570        assert_eq!(channel.frame_triggerings().count(), 0);
571        assert_eq!(channel.pdu_triggerings().count(), 0);
572    }
573
574    #[test]
575    fn remove_frame() {
576        let model = AutosarModelAbstraction::create("test", AutosarVersion::LATEST);
577        let package = model.get_or_create_package("/package").unwrap();
578        let system = package.create_system("System", SystemCategory::EcuExtract).unwrap();
579        let flexray_cluster = system
580            .create_flexray_cluster("Cluster", &package, &FlexrayClusterSettings::default())
581            .unwrap();
582        let channel = flexray_cluster
583            .create_physical_channel("Channel", FlexrayChannelName::A)
584            .unwrap();
585        let frame = system.create_flexray_frame("frame", &package, 8).unwrap();
586        let pdu = system.create_isignal_ipdu("pdu", &package, 8).unwrap();
587        let frame_triggering = channel
588            .trigger_frame(&frame, 0x123, &FlexrayCommunicationCycle::Counter { cycle_counter: 1 })
589            .unwrap();
590        let mapping = frame
591            .map_pdu(&pdu, 0, ByteOrder::MostSignificantByteLast, None)
592            .unwrap();
593        assert_eq!(frame.mapped_pdus().count(), 1);
594        assert_eq!(frame.frame_triggerings().len(), 1);
595        assert_eq!(channel.frame_triggerings().count(), 1);
596        // remove the frame with deep=false
597        frame.remove(false).unwrap();
598        // the frame should be removed
599        assert_eq!(system.frames().count(), 0);
600        // the mapping should be removed
601        assert!(mapping.element().path().is_err());
602        // the pdu should still exist
603        assert_eq!(system.pdus().count(), 1);
604        // the frame triggering should be removed
605        assert!(frame_triggering.element().path().is_err());
606        assert_eq!(channel.frame_triggerings().count(), 0);
607        assert_eq!(channel.pdu_triggerings().count(), 0);
608    }
609}