autosar_data_abstraction/communication/
mod.rs

1//! # Communication between ECUs in a system
2//!
3//! This module contains the communication related elements of the AUTOSAR metamodel.
4//!
5//! Currently, the following bus types are supported:
6//! - CAN
7//! - Ethernet
8//! - Flexray
9//!
10//! For each of the bus types, the following elements are available:
11//! - Communication using Frames, PDUs and signals
12//! - Network management
13//! - Diagnostic transport protocol
14//!
15//! Ethernet also has support for:
16//! - Old communication odel (using `SocketConnectionBundles`)
17//! - New communication model (using `StaticSocketConnections`)
18//! - `SomeIP`
19//!
20//! # Example
21//!
22//! ```
23//! use autosar_data::*;
24//! use autosar_data_abstraction::*;
25//! use autosar_data_abstraction::communication::*;
26//! use autosar_data_abstraction::datatype::*;
27//!
28//! # fn main() -> Result<(), AutosarAbstractionError> {
29//! let model = AutosarModelAbstraction::create("can.arxml", AutosarVersion::LATEST);
30//! let system_package = model.get_or_create_package("/System")?;
31//! let system = system_package.create_system("System", SystemCategory::SystemExtract)?;
32//! let cluster_package = model.get_or_create_package("/Network/Clusters")?;
33//!  
34//! let can_cluster = system.create_can_cluster("CanCluster", &cluster_package, Some(500_000))?;
35//! can_cluster.set_can_fd_baudrate(Some(2_000_000))?;
36//! assert_eq!(can_cluster.element().element_name(), ElementName::CanCluster);
37//! let can_channel = can_cluster.create_physical_channel("CanChannel")?;
38//!  
39//! let ecu_package = model.get_or_create_package("/Ecus")?;
40//!  
41//! // create ECU A and connect it to the CAN channel
42//! let ecu_instance_a = system.create_ecu_instance("Ecu_A", &ecu_package)?;
43//! let canctrl_a = ecu_instance_a.create_can_communication_controller("CanController")?;
44//! let channels_iter = canctrl_a.connected_channels();
45//! assert_eq!(channels_iter.count(), 0);
46//! canctrl_a.connect_physical_channel("Ecu_A_connector", &can_channel)?;
47//! let channels_iter = canctrl_a.connected_channels();
48//! assert_eq!(channels_iter.count(), 1);
49//!  
50//! // create ECU B and connect it to the CAN channel
51//! let ecu_instance_b = system.create_ecu_instance("Ecu_B", &ecu_package)?;
52//! let canctrl_b = ecu_instance_b.create_can_communication_controller("CanController")?;
53//! canctrl_b.connect_physical_channel("Ecu_B_connector", &can_channel)?;
54//!  
55//! let frame_package = model.get_or_create_package("/Network/Frames")?;
56//! let pdu_package = model.get_or_create_package("/Network/Pdus")?;
57//! let isignal_package = model.get_or_create_package("/Network/Signals")?;
58//! let syssignal_package = model.get_or_create_package("/System/Signals")?;
59//!  
60//! // create a base type for the CAN signals
61//! let base_type_package = model.get_or_create_package("/BaseTypes")?;
62//! let base_type_u8 = base_type_package.create_sw_base_type(
63//!     "uint8",
64//!     8,
65//!     BaseTypeEncoding::None,
66//!     None,
67//!     None,
68//!     Some("uint8"),
69//! )?;
70//!  
71//! // create a frame which contains one Pdu: Id 0x101, length 8
72//! let frame = system.create_can_frame("frame", &frame_package, 8)?;
73//! let pdu = system.create_isignal_ipdu("pdu", &pdu_package, 8)?;
74//! let ss_pdusignal1 = syssignal_package.create_system_signal("ss_pdusignal1")?;
75//! let pdusignal1 = system
76//!     .create_isignal("pdusignal1", &isignal_package, 4, &ss_pdusignal1, Some(&base_type_u8))?;
77//! let ss_pdusignal2 = syssignal_package.create_system_signal("ss_pdusignal2")?;
78//! let pdusignal2 = system
79//!     .create_isignal("pdusignal2", &isignal_package, 4, &ss_pdusignal2, Some(&base_type_u8))?;
80//! // map signal 1 to the first 4 bytes of the Pdu
81//! pdu.map_signal(
82//!     &pdusignal1,
83//!     0,
84//!     ByteOrder::MostSignificantByteFirst,
85//!     None,
86//!     TransferProperty::Triggered,
87//! )?;
88//! // map signal 2 to the second 4 bytes of the Pdu
89//! pdu.map_signal(
90//!     &pdusignal2,
91//!     8, // since this signal uses ByteOrder::MostSignificantByteFirst, it starts at byte 8 and ends at byte 4
92//!     ByteOrder::MostSignificantByteFirst,
93//!     None,
94//!     TransferProperty::Triggered,
95//! )?;
96//! // map the pdu to the frame
97//! frame.map_pdu(
98//!     &pdu,
99//!     0,
100//!     ByteOrder::MostSignificantByteLast,
101//!     None,
102//! )?;
103//! // trigger the frame on the CAN channel (id 0x101)
104//! let frame_triggering = can_channel
105//!     .trigger_frame(&frame, 0x101, CanAddressingMode::Standard, CanFrameType::Can20)?;
106//!  
107//! // frame connection: Ecu_B -> Ecu_A
108//! frame_triggering.connect_to_ecu(&ecu_instance_a, CommunicationDirection::In)?;
109//! frame_triggering.connect_to_ecu(&ecu_instance_b, CommunicationDirection::Out)?;
110//! # Ok(())}
111//! ```
112
113use crate::AutosarAbstractionError;
114use autosar_data::EnumItem;
115
116mod cluster;
117mod controller;
118mod data_transformation;
119mod frame;
120mod network_management;
121mod pdu;
122mod physical_channel;
123mod signal;
124mod transport_layer;
125
126pub use cluster::*;
127pub use controller::*;
128pub use data_transformation::*;
129pub use frame::*;
130pub use network_management::*;
131pub use pdu::*;
132pub use physical_channel::*;
133pub use signal::*;
134pub use transport_layer::*;
135
136//#########################################################
137
138/// The [`CommunicationDirection`] is used by the communication ports for frames, PDUs and signals
139#[derive(Debug, Clone, Copy, PartialEq, Eq)]
140pub enum CommunicationDirection {
141    /// The communication is incoming
142    In,
143    /// The communication is outgoing
144    Out,
145}
146
147impl TryFrom<EnumItem> for CommunicationDirection {
148    type Error = AutosarAbstractionError;
149
150    fn try_from(value: EnumItem) -> Result<Self, Self::Error> {
151        match value {
152            EnumItem::In => Ok(CommunicationDirection::In),
153            EnumItem::Out => Ok(CommunicationDirection::Out),
154            _ => Err(AutosarAbstractionError::ValueConversionError {
155                value: value.to_string(),
156                dest: "CommunicationDirection".to_string(),
157            }),
158        }
159    }
160}
161
162impl From<CommunicationDirection> for EnumItem {
163    fn from(value: CommunicationDirection) -> Self {
164        match value {
165            CommunicationDirection::In => EnumItem::In,
166            CommunicationDirection::Out => EnumItem::Out,
167        }
168    }
169}
170
171//#########################################################
172
173#[cfg(test)]
174mod test {
175    use super::*;
176
177    #[test]
178    fn test_communication_direction() {
179        // convert from CommunicationDirection to EnumItem
180        let in_dir = CommunicationDirection::In;
181        let out_dir = CommunicationDirection::Out;
182        let in_enum: EnumItem = in_dir.into();
183        let out_enum: EnumItem = out_dir.into();
184        assert_eq!(in_enum, EnumItem::In);
185        assert_eq!(out_enum, EnumItem::Out);
186
187        // convert from EnumItem to CommunicationDirection
188        let in_dir_converted: CommunicationDirection = in_enum.try_into().unwrap();
189        let out_dir_converted: CommunicationDirection = out_enum.try_into().unwrap();
190        assert_eq!(in_dir_converted, CommunicationDirection::In);
191        assert_eq!(out_dir_converted, CommunicationDirection::Out);
192        // conversion of an enumItem other than In or Out should fail
193        let bad = CommunicationDirection::try_from(EnumItem::Abstract);
194        assert!(bad.is_err());
195    }
196}