autosar_data_abstraction/communication/
mod.rs

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

use crate::AutosarAbstractionError;
use autosar_data::EnumItem;

mod cluster;
mod controller;
mod datatransformation;
mod frame;
mod network_management;
mod pdu;
mod physical_channel;
mod signal;
mod transport_layer;

pub use cluster::*;
pub use controller::*;
pub use datatransformation::*;
pub use frame::*;
pub use network_management::*;
pub use pdu::*;
pub use physical_channel::*;
pub use signal::*;
pub use transport_layer::*;

//#########################################################

/// The [`CommunicationDirection`] is used by the communication ports for frames, PDUs and signals
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CommunicationDirection {
    /// The communication is incoming
    In,
    /// The communication is outgoing
    Out,
}

impl TryFrom<EnumItem> for CommunicationDirection {
    type Error = AutosarAbstractionError;

    fn try_from(value: EnumItem) -> Result<Self, Self::Error> {
        match value {
            EnumItem::In => Ok(CommunicationDirection::In),
            EnumItem::Out => Ok(CommunicationDirection::Out),
            _ => Err(AutosarAbstractionError::ValueConversionError {
                value: value.to_string(),
                dest: "CommunicationDirection".to_string(),
            }),
        }
    }
}

impl From<CommunicationDirection> for EnumItem {
    fn from(value: CommunicationDirection) -> Self {
        match value {
            CommunicationDirection::In => EnumItem::In,
            CommunicationDirection::Out => EnumItem::Out,
        }
    }
}

//#########################################################

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn test_communication_direction() {
        // convert from CommunicationDirection to EnumItem
        let in_dir = CommunicationDirection::In;
        let out_dir = CommunicationDirection::Out;
        let in_enum: EnumItem = in_dir.into();
        let out_enum: EnumItem = out_dir.into();
        assert_eq!(in_enum, EnumItem::In);
        assert_eq!(out_enum, EnumItem::Out);

        // convert from EnumItem to CommunicationDirection
        let in_dir_converted: CommunicationDirection = in_enum.try_into().unwrap();
        let out_dir_converted: CommunicationDirection = out_enum.try_into().unwrap();
        assert_eq!(in_dir_converted, CommunicationDirection::In);
        assert_eq!(out_dir_converted, CommunicationDirection::Out);
        // conversion of an enumItem other than In or Out should fail
        let bad = CommunicationDirection::try_from(EnumItem::Abstract);
        assert!(bad.is_err());
    }
}