autosar_data_abstraction/communication/physical_channel/
mod.rs

1use crate::communication::{AbstractCommunicationConnector, CommunicationConnector, ISignalTriggering, PduTriggering};
2use crate::{AbstractionElement, AutosarAbstractionError, EcuInstance, IdentifiableAbstractionElement};
3use autosar_data::{Element, ElementName};
4
5mod can;
6mod ethernet;
7mod flexray;
8mod lin;
9
10pub use can::*;
11pub use ethernet::*;
12pub use flexray::*;
13pub use lin::*;
14
15//##################################################################
16
17/// trait for physical channels
18pub trait AbstractPhysicalChannel: AbstractionElement + Into<PhysicalChannel> {
19    /// the type of communication connector used by this physical channel
20    type CommunicationConnectorType: AbstractCommunicationConnector;
21
22    /// iterate over all `PduTriggerings` of this physical channel
23    fn pdu_triggerings(&self) -> impl Iterator<Item = PduTriggering> + Send + use<Self> {
24        self.element()
25            .get_sub_element(ElementName::PduTriggerings)
26            .into_iter()
27            .flat_map(|triggerings| triggerings.sub_elements())
28            .filter_map(|triggering| PduTriggering::try_from(triggering).ok())
29    }
30
31    /// iterate over all `ISignalTriggerings` of this physical channel
32    fn signal_triggerings(&self) -> impl Iterator<Item = ISignalTriggering> + Send + use<Self> {
33        self.element()
34            .get_sub_element(ElementName::ISignalTriggerings)
35            .into_iter()
36            .flat_map(|triggerings| triggerings.sub_elements())
37            .filter_map(|triggering| ISignalTriggering::try_from(triggering).ok())
38    }
39
40    /// iterate over all connectors between this physical channel and any ECU
41    ///
42    /// # Example
43    ///
44    /// ```
45    /// # use autosar_data::*;
46    /// # use autosar_data_abstraction::{*, communication::*};
47    /// # fn main() -> Result<(), AutosarAbstractionError> {
48    /// # let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
49    /// # let package = model.get_or_create_package("/pkg1")?;
50    /// # let system = package.create_system("System", SystemCategory::SystemExtract)?;
51    /// # let cluster = system.create_can_cluster("Cluster", &package, None)?;
52    /// # let can_channel = cluster.create_physical_channel("Channel")?;
53    /// # let ecu = system.create_ecu_instance("ECU", &package)?;
54    /// # let can_controller = ecu.create_can_communication_controller("Controller")?;
55    /// can_controller.connect_physical_channel("Connector", &can_channel)?;
56    /// for connector in can_channel.connectors() {
57    ///    println!("Connector: {:?}", connector);
58    /// }
59    /// # assert_eq!(can_channel.connectors().count(), 1);
60    /// # Ok(())}
61    fn connectors(&self) -> impl Iterator<Item = Self::CommunicationConnectorType> + Send + use<Self> {
62        self.element()
63            .get_sub_element(ElementName::CommConnectors)
64            .into_iter()
65            .flat_map(|connectors| connectors.sub_elements())
66            .filter_map(|ccrc| {
67                ccrc.get_sub_element(ElementName::CommunicationConnectorRef)
68                    .and_then(|connector| connector.get_reference_target().ok())
69                    .and_then(|connector| Self::CommunicationConnectorType::try_from(connector).ok())
70            })
71    }
72
73    /// get the connector element between this channel and an ecu
74    #[must_use]
75    fn ecu_connector(&self, ecu_instance: &EcuInstance) -> Option<Self::CommunicationConnectorType> {
76        // get a connector referenced by this physical channel which is contained in the ecu_instance
77        // iterate over the CommunicationConnectorRefConditionals
78        for connector in self.connectors() {
79            if let Ok(connector_ecu_instance) = connector.ecu_instance()
80                && connector_ecu_instance == *ecu_instance
81            {
82                return Some(connector);
83            }
84        }
85
86        None
87    }
88}
89
90//##################################################################
91
92/// A physical channel is a communication channel between two ECUs.
93///
94/// This enum wraps the different physical channel types.
95#[derive(Debug, Clone, PartialEq, Eq)]
96pub enum PhysicalChannel {
97    /// A CAN physical channel
98    Can(CanPhysicalChannel),
99    /// An Ethernet physical channel
100    Ethernet(EthernetPhysicalChannel),
101    /// A `FlexRay` physical channel
102    Flexray(FlexrayPhysicalChannel),
103    /// A `LIN` physical channel
104    Lin(LinPhysicalChannel),
105}
106
107impl AbstractPhysicalChannel for PhysicalChannel {
108    type CommunicationConnectorType = CommunicationConnector;
109}
110
111impl AbstractionElement for PhysicalChannel {
112    fn element(&self) -> &autosar_data::Element {
113        match self {
114            PhysicalChannel::Can(cpc) => cpc.element(),
115            PhysicalChannel::Ethernet(epc) => epc.element(),
116            PhysicalChannel::Flexray(fpc) => fpc.element(),
117            PhysicalChannel::Lin(lpc) => lpc.element(),
118        }
119    }
120}
121
122impl IdentifiableAbstractionElement for PhysicalChannel {}
123
124impl TryFrom<Element> for PhysicalChannel {
125    type Error = AutosarAbstractionError;
126
127    fn try_from(element: Element) -> Result<Self, Self::Error> {
128        match element.element_name() {
129            ElementName::CanPhysicalChannel => Ok(Self::Can(CanPhysicalChannel::try_from(element)?)),
130            ElementName::EthernetPhysicalChannel => Ok(Self::Ethernet(EthernetPhysicalChannel::try_from(element)?)),
131            ElementName::FlexrayPhysicalChannel => Ok(Self::Flexray(FlexrayPhysicalChannel::try_from(element)?)),
132            ElementName::LinPhysicalChannel => Ok(Self::Lin(LinPhysicalChannel::try_from(element)?)),
133            _ => Err(AutosarAbstractionError::ConversionError {
134                element,
135                dest: "PhysicalChannel".to_string(),
136            }),
137        }
138    }
139}
140
141//##################################################################
142
143#[cfg(test)]
144mod test {
145    use super::*;
146    use crate::{
147        AutosarModelAbstraction, ByteOrder, SystemCategory,
148        communication::{AbstractFrame, CanAddressingMode, CanFrameType, TransferProperty},
149    };
150    use autosar_data::AutosarVersion;
151
152    #[test]
153    fn abstract_physical_channel() {
154        let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
155        let pkg = model.get_or_create_package("/test").unwrap();
156        let system = pkg.create_system("System", SystemCategory::SystemDescription).unwrap();
157        let cluster = system.create_can_cluster("CanCluster", &pkg, None).unwrap();
158        let channel = cluster.create_physical_channel("channel_name").unwrap();
159
160        let ecu = system.create_ecu_instance("ECU", &pkg).unwrap();
161        let can_controller = ecu.create_can_communication_controller("Controller").unwrap();
162        let connector = can_controller.connect_physical_channel("Connector", &channel).unwrap();
163
164        let frame = system.create_can_frame("Frame", &pkg, 8).unwrap();
165        let isignal_ipdu = system.create_isignal_ipdu("ISignalIPdu", &pkg, 8).unwrap();
166
167        let system_signal = pkg.create_system_signal("SystemSignal").unwrap();
168        let signal = system.create_isignal("Signal", &pkg, 8, &system_signal, None).unwrap();
169        isignal_ipdu
170            .map_signal(
171                &signal,
172                0,
173                ByteOrder::MostSignificantByteLast,
174                None,
175                TransferProperty::Triggered,
176            )
177            .unwrap();
178        frame
179            .map_pdu(&isignal_ipdu, 0, ByteOrder::MostSignificantByteLast, None)
180            .unwrap();
181
182        let frame_triggering = channel
183            .trigger_frame(&frame, 0x100, CanAddressingMode::Standard, CanFrameType::Can20)
184            .unwrap();
185
186        assert_eq!(channel.frame_triggerings().count(), 1);
187        assert_eq!(channel.frame_triggerings().next(), Some(frame_triggering));
188        assert_eq!(channel.pdu_triggerings().count(), 1);
189        assert_eq!(
190            channel.pdu_triggerings().next().unwrap().pdu().unwrap(),
191            isignal_ipdu.into()
192        );
193        assert_eq!(channel.signal_triggerings().count(), 1);
194
195        assert_eq!(channel.connectors().count(), 1);
196        assert_eq!(channel.ecu_connector(&ecu).unwrap(), connector);
197    }
198}