autosar_data_abstraction/communication/frame/
lin.rs

1use crate::communication::{
2    AbstractFrame, AbstractFrameTriggering, AbstractPdu, CommunicationDirection, Frame, FramePort, FrameTriggering,
3    LinPhysicalChannel, 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};
10
11//##################################################################
12
13/// A frame on a LIN bus
14#[derive(Debug, Clone, PartialEq, Eq, Hash)]
15pub struct LinEventTriggeredFrame(Element);
16abstraction_element!(LinEventTriggeredFrame, LinEventTriggeredFrame);
17impl IdentifiableAbstractionElement for LinEventTriggeredFrame {}
18
19impl LinEventTriggeredFrame {
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 lin_frame = pkg_elements.create_named_sub_element(ElementName::LinEventTriggeredFrame, name)?;
23
24        lin_frame
25            .create_sub_element(ElementName::FrameLength)?
26            .set_character_data(byte_length.to_string())?;
27
28        Ok(Self(lin_frame))
29    }
30
31    /// remove this `CanFrame` 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 LinEventTriggeredFrame {
53    type FrameTriggeringType = LinFrameTriggering;
54
55    /// List all [`LinFrameTriggering`]s using this frame
56    fn frame_triggerings(&self) -> Vec<LinFrameTriggering> {
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| LinFrameTriggering::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::Lin(LinFrame::EventTriggered(self.clone())).map_pdu(gen_pdu, start_position, byte_order, update_bit)
83    }
84}
85
86//##################################################################
87
88/// A frame on a LIN bus
89#[derive(Debug, Clone, PartialEq, Eq, Hash)]
90pub struct LinSporadicFrame(Element);
91abstraction_element!(LinSporadicFrame, LinSporadicFrame);
92impl IdentifiableAbstractionElement for LinSporadicFrame {}
93
94impl LinSporadicFrame {
95    pub(crate) fn new(name: &str, package: &ArPackage, byte_length: u64) -> Result<Self, AutosarAbstractionError> {
96        let pkg_elements = package.element().get_or_create_sub_element(ElementName::Elements)?;
97        let lin_frame = pkg_elements.create_named_sub_element(ElementName::LinSporadicFrame, name)?;
98
99        lin_frame
100            .create_sub_element(ElementName::FrameLength)?
101            .set_character_data(byte_length.to_string())?;
102
103        Ok(Self(lin_frame))
104    }
105
106    /// remove this `CanFrame` from the model
107    pub fn remove(self, deep: bool) -> Result<(), AutosarAbstractionError> {
108        for pdu_mapping in self.mapped_pdus() {
109            pdu_mapping.remove(deep)?;
110        }
111
112        // get all frame triggerings using this frame
113        let frame_triggerings = self.frame_triggerings();
114
115        // remove the element itself
116        AbstractionElement::remove(self, deep)?;
117
118        // remove the frame triggerings
119        for ft in frame_triggerings {
120            ft.remove(deep)?;
121        }
122
123        Ok(())
124    }
125}
126
127impl AbstractFrame for LinSporadicFrame {
128    type FrameTriggeringType = LinFrameTriggering;
129
130    /// List all [`LinFrameTriggering`]s using this frame
131    fn frame_triggerings(&self) -> Vec<LinFrameTriggering> {
132        let model_result = self.element().model();
133        let path_result = self.element().path();
134        if let (Ok(model), Ok(path)) = (model_result, path_result) {
135            model
136                .get_references_to(&path)
137                .iter()
138                .filter_map(|e| {
139                    e.upgrade()
140                        .and_then(|ref_elem| ref_elem.named_parent().ok().flatten())
141                        .and_then(|elem| LinFrameTriggering::try_from(elem).ok())
142                })
143                .collect()
144        } else {
145            vec![]
146        }
147    }
148
149    /// map a PDU to the frame
150    fn map_pdu<T: AbstractPdu>(
151        &self,
152        gen_pdu: &T,
153        start_position: u32,
154        byte_order: ByteOrder,
155        update_bit: Option<u32>,
156    ) -> Result<PduToFrameMapping, AutosarAbstractionError> {
157        Frame::Lin(LinFrame::Sporadic(self.clone())).map_pdu(gen_pdu, start_position, byte_order, update_bit)
158    }
159}
160
161//##################################################################
162
163/// A frame on a LIN bus
164#[derive(Debug, Clone, PartialEq, Eq, Hash)]
165pub struct LinUnconditionalFrame(Element);
166abstraction_element!(LinUnconditionalFrame, LinUnconditionalFrame);
167impl IdentifiableAbstractionElement for LinUnconditionalFrame {}
168
169impl LinUnconditionalFrame {
170    pub(crate) fn new(name: &str, package: &ArPackage, byte_length: u64) -> Result<Self, AutosarAbstractionError> {
171        let pkg_elements = package.element().get_or_create_sub_element(ElementName::Elements)?;
172        let lin_frame = pkg_elements.create_named_sub_element(ElementName::LinUnconditionalFrame, name)?;
173
174        lin_frame
175            .create_sub_element(ElementName::FrameLength)?
176            .set_character_data(byte_length.to_string())?;
177
178        Ok(Self(lin_frame))
179    }
180
181    /// remove this `CanFrame` from the model
182    pub fn remove(self, deep: bool) -> Result<(), AutosarAbstractionError> {
183        for pdu_mapping in self.mapped_pdus() {
184            pdu_mapping.remove(deep)?;
185        }
186
187        // get all frame triggerings using this frame
188        let frame_triggerings = self.frame_triggerings();
189
190        // remove the element itself
191        AbstractionElement::remove(self, deep)?;
192
193        // remove the frame triggerings
194        for ft in frame_triggerings {
195            ft.remove(deep)?;
196        }
197
198        Ok(())
199    }
200}
201
202impl AbstractFrame for LinUnconditionalFrame {
203    type FrameTriggeringType = LinFrameTriggering;
204
205    /// List all [`LinFrameTriggering`]s using this frame
206    fn frame_triggerings(&self) -> Vec<LinFrameTriggering> {
207        let model_result = self.element().model();
208        let path_result = self.element().path();
209        if let (Ok(model), Ok(path)) = (model_result, path_result) {
210            model
211                .get_references_to(&path)
212                .iter()
213                .filter_map(|e| {
214                    e.upgrade()
215                        .and_then(|ref_elem| ref_elem.named_parent().ok().flatten())
216                        .and_then(|elem| LinFrameTriggering::try_from(elem).ok())
217                })
218                .collect()
219        } else {
220            vec![]
221        }
222    }
223
224    /// map a PDU to the frame
225    fn map_pdu<T: AbstractPdu>(
226        &self,
227        gen_pdu: &T,
228        start_position: u32,
229        byte_order: ByteOrder,
230        update_bit: Option<u32>,
231    ) -> Result<PduToFrameMapping, AutosarAbstractionError> {
232        Frame::Lin(LinFrame::Unconditional(self.clone())).map_pdu(gen_pdu, start_position, byte_order, update_bit)
233    }
234}
235
236//##################################################################
237
238/// A frame on a LIN bus
239#[derive(Debug, Clone, PartialEq, Eq, Hash)]
240pub enum LinFrame {
241    /// An event triggered LIN frame
242    EventTriggered(LinEventTriggeredFrame),
243    /// A sporadic LIN frame
244    Sporadic(LinSporadicFrame),
245    /// An unconditional LIN frame
246    Unconditional(LinUnconditionalFrame),
247}
248
249impl AbstractionElement for LinFrame {
250    fn element(&self) -> &autosar_data::Element {
251        match self {
252            LinFrame::EventTriggered(ftf) => ftf.element(),
253            LinFrame::Sporadic(fs) => fs.element(),
254            LinFrame::Unconditional(fu) => fu.element(),
255        }
256    }
257}
258impl IdentifiableAbstractionElement for LinFrame {}
259
260impl TryFrom<Element> for LinFrame {
261    type Error = AutosarAbstractionError;
262
263    fn try_from(element: Element) -> Result<Self, Self::Error> {
264        match element.element_name() {
265            ElementName::LinEventTriggeredFrame => {
266                Ok(LinFrame::EventTriggered(LinEventTriggeredFrame::try_from(element)?))
267            }
268            ElementName::LinSporadicFrame => Ok(LinFrame::Sporadic(LinSporadicFrame::try_from(element)?)),
269            ElementName::LinUnconditionalFrame => {
270                Ok(LinFrame::Unconditional(LinUnconditionalFrame::try_from(element)?))
271            }
272            _ => Err(AutosarAbstractionError::ConversionError {
273                element,
274                dest: "LinFrame".to_string(),
275            }),
276        }
277    }
278}
279
280impl From<LinEventTriggeredFrame> for LinFrame {
281    fn from(frame: LinEventTriggeredFrame) -> Self {
282        LinFrame::EventTriggered(frame)
283    }
284}
285
286impl From<LinSporadicFrame> for LinFrame {
287    fn from(frame: LinSporadicFrame) -> Self {
288        LinFrame::Sporadic(frame)
289    }
290}
291
292impl From<LinUnconditionalFrame> for LinFrame {
293    fn from(frame: LinUnconditionalFrame) -> Self {
294        LinFrame::Unconditional(frame)
295    }
296}
297
298impl AbstractFrame for LinFrame {
299    type FrameTriggeringType = LinFrameTriggering;
300
301    /// List all [`LinFrameTriggering`]s using this frame
302    fn frame_triggerings(&self) -> Vec<LinFrameTriggering> {
303        match self {
304            LinFrame::EventTriggered(ftf) => ftf.frame_triggerings(),
305            LinFrame::Sporadic(fs) => fs.frame_triggerings(),
306            LinFrame::Unconditional(fu) => fu.frame_triggerings(),
307        }
308    }
309
310    /// map a PDU to the frame
311    fn map_pdu<T: AbstractPdu>(
312        &self,
313        gen_pdu: &T,
314        start_position: u32,
315        byte_order: ByteOrder,
316        update_bit: Option<u32>,
317    ) -> Result<PduToFrameMapping, AutosarAbstractionError> {
318        match self {
319            LinFrame::EventTriggered(ftf) => ftf.map_pdu(gen_pdu, start_position, byte_order, update_bit),
320            LinFrame::Sporadic(fs) => fs.map_pdu(gen_pdu, start_position, byte_order, update_bit),
321            LinFrame::Unconditional(fu) => fu.map_pdu(gen_pdu, start_position, byte_order, update_bit),
322        }
323    }
324}
325
326impl LinFrame {
327    /// remove this `LinFrame` from the model
328    pub fn remove(self, deep: bool) -> Result<(), AutosarAbstractionError> {
329        match self {
330            LinFrame::EventTriggered(ftf) => ftf.remove(deep),
331            LinFrame::Sporadic(fs) => fs.remove(deep),
332            LinFrame::Unconditional(fu) => fu.remove(deep),
333        }
334    }
335}
336
337//##################################################################
338
339/// The frame triggering connects a frame to a physical channel
340#[derive(Debug, Clone, PartialEq, Eq, Hash)]
341pub struct LinFrameTriggering(Element);
342abstraction_element!(LinFrameTriggering, LinFrameTriggering);
343impl IdentifiableAbstractionElement for LinFrameTriggering {}
344
345impl LinFrameTriggering {
346    pub(crate) fn new(
347        channel: &LinPhysicalChannel,
348        frame: &LinFrame,
349        identifier: u32,
350    ) -> Result<Self, AutosarAbstractionError> {
351        let model = channel.element().model()?;
352        let base_path = channel.element().path()?;
353        let frame_name = frame
354            .name()
355            .ok_or(AutosarAbstractionError::InvalidParameter("invalid frame".to_string()))?;
356        let ft_name = format!("FT_{frame_name}");
357        let ft_name = make_unique_name(&model, &base_path, &ft_name);
358
359        let frame_triggerings = channel
360            .element()
361            .get_or_create_sub_element(ElementName::FrameTriggerings)?;
362        let lin_triggering = frame_triggerings.create_named_sub_element(ElementName::LinFrameTriggering, &ft_name)?;
363
364        lin_triggering
365            .create_sub_element(ElementName::FrameRef)?
366            .set_reference_target(frame.element())?;
367
368        let ft = Self(lin_triggering);
369        ft.set_identifier(identifier)?;
370
371        for pdu_mapping in frame.mapped_pdus() {
372            if let Some(pdu) = pdu_mapping.pdu() {
373                ft.add_pdu_triggering(&pdu)?;
374            }
375        }
376
377        Ok(ft)
378    }
379
380    /// remove this `CanFrameTriggering` from the model
381    pub fn remove(self, deep: bool) -> Result<(), AutosarAbstractionError> {
382        let opt_frame = self.frame();
383
384        // remove all pdu triggerings of this frame triggering
385        for pt in self.pdu_triggerings() {
386            pt.remove(deep)?;
387        }
388        for frame_port in self.frame_ports() {
389            frame_port.remove(deep)?;
390        }
391
392        AbstractionElement::remove(self, deep)?;
393
394        // if deep, check if the frame became unused because of this frame triggering removal
395        // if so remove it too
396        if deep && let Some(frame) = opt_frame {
397            // check if any frame became unused because of this frame triggering removal
398            // if so remove it too
399            if !is_used_system_element(frame.element()) {
400                frame.remove(deep)?;
401            }
402        }
403
404        Ok(())
405    }
406
407    /// set the can id associated with this frame
408    pub fn set_identifier(&self, identifier: u32) -> Result<(), AutosarAbstractionError> {
409        self.element()
410            .get_or_create_sub_element(ElementName::Identifier)?
411            .set_character_data(identifier.to_string())?;
412
413        Ok(())
414    }
415
416    /// get the can id associated with this frame triggering
417    #[must_use]
418    pub fn identifier(&self) -> Option<u32> {
419        self.element()
420            .get_sub_element(ElementName::Identifier)?
421            .character_data()?
422            .parse_integer()
423    }
424
425    pub(crate) fn add_pdu_triggering(&self, pdu: &Pdu) -> Result<PduTriggering, AutosarAbstractionError> {
426        FrameTriggering::Lin(self.clone()).add_pdu_triggering(pdu)
427    }
428
429    /// get the physical channel that contains this frame triggering
430    pub fn physical_channel(&self) -> Result<LinPhysicalChannel, AutosarAbstractionError> {
431        let channel_elem = self.element().named_parent()?.unwrap();
432        LinPhysicalChannel::try_from(channel_elem)
433    }
434
435    /// connect this frame triggering to an ECU
436    ///
437    /// The direction parameter specifies if the communication is incoming or outgoing
438    pub fn connect_to_ecu(
439        &self,
440        ecu: &EcuInstance,
441        direction: CommunicationDirection,
442    ) -> Result<FramePort, AutosarAbstractionError> {
443        FrameTriggering::Lin(self.clone()).connect_to_ecu(ecu, direction)
444    }
445}
446
447impl AbstractFrameTriggering for LinFrameTriggering {
448    type FrameType = LinFrame;
449}
450
451impl From<LinFrameTriggering> for FrameTriggering {
452    fn from(cft: LinFrameTriggering) -> Self {
453        FrameTriggering::Lin(cft)
454    }
455}
456
457//##################################################################
458
459#[cfg(test)]
460mod test {
461    use super::*;
462    use crate::{AutosarModelAbstraction, SystemCategory, communication::AbstractPhysicalChannel};
463    use autosar_data::AutosarVersion;
464
465    #[test]
466    fn create_frames() {
467        let model = AutosarModelAbstraction::create("test", AutosarVersion::LATEST);
468        let package = model.get_or_create_package("/package").unwrap();
469
470        let event_triggered_frame = LinEventTriggeredFrame::new("EventTriggeredFrame", &package, 8).unwrap();
471        assert_eq!(
472            event_triggered_frame.element().element_name(),
473            ElementName::LinEventTriggeredFrame
474        );
475
476        let sporadic_frame = LinSporadicFrame::new("SporadicFrame", &package, 8).unwrap();
477        assert_eq!(sporadic_frame.element().element_name(), ElementName::LinSporadicFrame);
478
479        let unconditional_frame = LinUnconditionalFrame::new("UnconditionalFrame", &package, 8).unwrap();
480        assert_eq!(
481            unconditional_frame.element().element_name(),
482            ElementName::LinUnconditionalFrame
483        );
484    }
485
486    #[test]
487    fn remove_frame_triggering() {
488        let model = AutosarModelAbstraction::create("test", AutosarVersion::LATEST);
489        let package = model.get_or_create_package("/package").unwrap();
490        let system = package.create_system("System", SystemCategory::EcuExtract).unwrap();
491        let lin_cluster = system.create_lin_cluster("Cluster", &package).unwrap();
492        let channel = lin_cluster.create_physical_channel("Channel").unwrap();
493
494        let frame = system.create_lin_unconditional_frame("frame", &package, 8).unwrap();
495        let pdu = system.create_isignal_ipdu("pdu", &package, 8).unwrap();
496
497        let frame_triggering = channel.trigger_frame(&frame, 1).unwrap();
498
499        let _mapping = frame
500            .map_pdu(&pdu, 0, ByteOrder::MostSignificantByteLast, None)
501            .unwrap();
502
503        assert_eq!(frame.mapped_pdus().count(), 1);
504        assert_eq!(frame.frame_triggerings().len(), 1);
505        assert_eq!(channel.frame_triggerings().count(), 1);
506
507        // remove the frame triggering
508        frame_triggering.remove(false).unwrap();
509        // the frame remains because we did a shallow removal
510        assert_eq!(system.frames().count(), 1);
511
512        // re-create the frame triggering
513        let frame_triggering = channel.trigger_frame(&frame, 2).unwrap();
514        // remove the frame triggering with deep=true
515        frame_triggering.remove(true).unwrap();
516
517        // the frame triggering should be removed
518        assert_eq!(channel.frame_triggerings().count(), 0);
519        // the frame should be removed because it became unused
520        assert_eq!(system.frames().count(), 0);
521        // the mapping should be removed because the frame was removed
522        assert_eq!(frame.mapped_pdus().count(), 0);
523        // the pdu was also removed, because it became unused and we did a deep removal
524        assert_eq!(system.pdus().count(), 0);
525
526        assert_eq!(channel.frame_triggerings().count(), 0);
527        assert_eq!(channel.pdu_triggerings().count(), 0);
528    }
529
530    #[test]
531    fn remove_frame() {
532        let model = AutosarModelAbstraction::create("test", AutosarVersion::LATEST);
533        let package = model.get_or_create_package("/package").unwrap();
534        let system = package.create_system("System", SystemCategory::EcuExtract).unwrap();
535        let lin_cluster = system.create_lin_cluster("Cluster", &package).unwrap();
536        let channel = lin_cluster.create_physical_channel("Channel").unwrap();
537        let frame = system.create_lin_unconditional_frame("frame", &package, 8).unwrap();
538        let pdu = system.create_isignal_ipdu("pdu", &package, 8).unwrap();
539        let frame_triggering = channel.trigger_frame(&frame, 1).unwrap();
540        let mapping = frame
541            .map_pdu(&pdu, 0, ByteOrder::MostSignificantByteLast, None)
542            .unwrap();
543        assert_eq!(frame.mapped_pdus().count(), 1);
544        assert_eq!(frame.frame_triggerings().len(), 1);
545        assert_eq!(channel.frame_triggerings().count(), 1);
546        // remove the frame with deep=false
547        frame.remove(false).unwrap();
548        // the frame should be removed
549        assert_eq!(system.frames().count(), 0);
550        // the mapping should be removed
551        assert!(mapping.element().path().is_err());
552        // the pdu should still exist
553        assert_eq!(system.pdus().count(), 1);
554        // the frame triggering should be removed
555        assert!(frame_triggering.element().path().is_err());
556        assert_eq!(channel.frame_triggerings().count(), 0);
557        assert_eq!(channel.pdu_triggerings().count(), 0);
558    }
559}