autosar_data_abstraction/communication/transport_layer/
doip_tp.rs1use crate::communication::{EthernetCluster, PduTriggering};
2use crate::{
3 AbstractionElement, ArPackage, AutosarAbstractionError, IdentifiableAbstractionElement, abstraction_element,
4};
5use autosar_data::{Element, ElementName};
6
7#[derive(Debug, Clone, PartialEq, Eq, Hash)]
9pub struct DoIpTpConfig(Element);
10abstraction_element!(DoIpTpConfig, DoIpTpConfig);
11impl IdentifiableAbstractionElement for DoIpTpConfig {}
12
13impl DoIpTpConfig {
14 pub(crate) fn new(
15 name: &str,
16 package: &ArPackage,
17 cluster: &EthernetCluster,
18 ) -> Result<Self, AutosarAbstractionError> {
19 let pkg_elem = package.element().get_or_create_sub_element(ElementName::Elements)?;
20
21 let tp_config_elem = pkg_elem.create_named_sub_element(ElementName::DoIpTpConfig, name)?;
22 let tp_config = Self(tp_config_elem);
23
24 tp_config.set_cluster(cluster)?;
25
26 Ok(tp_config)
27 }
28
29 pub fn set_cluster(&self, cluster: &EthernetCluster) -> Result<(), AutosarAbstractionError> {
31 self.element()
32 .get_or_create_sub_element(ElementName::CommunicationClusterRef)?
33 .set_reference_target(cluster.element())?;
34 Ok(())
35 }
36
37 #[must_use]
39 pub fn cluster(&self) -> Option<EthernetCluster> {
40 self.element()
41 .get_sub_element(ElementName::CommunicationClusterRef)
42 .and_then(|elem| elem.get_reference_target().ok())
43 .and_then(|elem| EthernetCluster::try_from(elem).ok())
44 }
45
46 pub fn create_doip_logic_address(
48 &self,
49 name: &str,
50 address: u32,
51 ) -> Result<DoIpLogicAddress, AutosarAbstractionError> {
52 let logic_addresses_elem = self
53 .element()
54 .get_or_create_sub_element(ElementName::DoIpLogicAddresss)?;
55 DoIpLogicAddress::new(name, &logic_addresses_elem, address)
56 }
57
58 pub fn doip_logic_addresses(&self) -> impl Iterator<Item = DoIpLogicAddress> + Send + use<> {
60 self.element()
61 .get_sub_element(ElementName::DoIpLogicAddresss)
62 .into_iter()
63 .flat_map(|elem| elem.sub_elements())
64 .map(DoIpLogicAddress)
65 }
66
67 pub fn create_doip_tp_connection(
69 &self,
70 name: Option<&str>,
71 source: &DoIpLogicAddress,
72 target: &DoIpLogicAddress,
73 tp_sdu_triggering: &PduTriggering,
74 ) -> Result<DoIpTpConnection, AutosarAbstractionError> {
75 let tp_connections_elem = self.element().get_or_create_sub_element(ElementName::TpConnections)?;
76 DoIpTpConnection::new(name, &tp_connections_elem, source, target, tp_sdu_triggering)
77 }
78
79 pub fn doip_tp_connections(&self) -> impl Iterator<Item = DoIpTpConnection> + Send + use<> {
81 self.element()
82 .get_sub_element(ElementName::TpConnections)
83 .into_iter()
84 .flat_map(|elem| elem.sub_elements())
85 .map(DoIpTpConnection)
86 }
87}
88
89#[derive(Debug, Clone, PartialEq, Eq, Hash)]
93pub struct DoIpLogicAddress(Element);
94abstraction_element!(DoIpLogicAddress, DoIpLogicAddress);
95impl IdentifiableAbstractionElement for DoIpLogicAddress {}
96
97impl DoIpLogicAddress {
98 pub(crate) fn new(name: &str, parent: &Element, address: u32) -> Result<Self, AutosarAbstractionError> {
99 let logic_address_elem = parent.create_named_sub_element(ElementName::DoIpLogicAddress, name)?;
100 let logic_address = Self(logic_address_elem);
101 logic_address.set_address(address)?;
102
103 Ok(logic_address)
104 }
105
106 pub fn set_address(&self, address: u32) -> Result<(), AutosarAbstractionError> {
108 self.element()
109 .get_or_create_sub_element(ElementName::Address)?
110 .set_character_data(u64::from(address))?;
111 Ok(())
112 }
113
114 #[must_use]
116 pub fn address(&self) -> Option<u32> {
117 self.element()
118 .get_sub_element(ElementName::Address)
119 .and_then(|elem| elem.character_data())
120 .and_then(|data| data.parse_integer())
121 }
122}
123
124#[derive(Debug, Clone, PartialEq, Eq, Hash)]
128pub struct DoIpTpConnection(Element);
129abstraction_element!(DoIpTpConnection, DoIpTpConnection);
130
131impl IdentifiableAbstractionElement for DoIpTpConnection {
132 fn name(&self) -> Option<String> {
138 self.element()
139 .get_sub_element(ElementName::Ident)
140 .and_then(|elem| elem.item_name())
141 }
142
143 fn set_name(&self, name: &str) -> Result<(), AutosarAbstractionError> {
145 if let Some(ident_elem) = self.element().get_sub_element(ElementName::Ident) {
146 ident_elem.set_item_name(name)?;
147 } else {
148 self.element().create_named_sub_element(ElementName::Ident, name)?;
149 }
150 Ok(())
151 }
152}
153
154impl DoIpTpConnection {
155 pub(crate) fn new(
156 name: Option<&str>,
157 parent: &Element,
158 source: &DoIpLogicAddress,
159 target: &DoIpLogicAddress,
160 tp_sdu_triggering: &PduTriggering,
161 ) -> Result<Self, AutosarAbstractionError> {
162 let tp_connection_elem = parent.create_sub_element(ElementName::DoIpTpConnection)?;
163 if let Some(name) = name {
164 tp_connection_elem.create_named_sub_element(ElementName::Ident, name)?;
165 }
166 let tp_connection = Self(tp_connection_elem);
167 tp_connection.set_source(source)?;
168 tp_connection.set_target(target)?;
169 tp_connection.set_tp_sdu_triggering(tp_sdu_triggering)?;
170
171 Ok(tp_connection)
172 }
173
174 pub fn set_source(&self, source: &DoIpLogicAddress) -> Result<(), AutosarAbstractionError> {
176 self.element()
177 .get_or_create_sub_element(ElementName::DoIpSourceAddressRef)?
178 .set_reference_target(source.element())?;
179 Ok(())
180 }
181
182 #[must_use]
184 pub fn source(&self) -> Option<DoIpLogicAddress> {
185 self.element()
186 .get_sub_element(ElementName::DoIpSourceAddressRef)
187 .and_then(|elem| elem.get_reference_target().ok())
188 .and_then(|elem| DoIpLogicAddress::try_from(elem).ok())
189 }
190
191 pub fn set_target(&self, target: &DoIpLogicAddress) -> Result<(), AutosarAbstractionError> {
193 self.element()
194 .get_or_create_sub_element(ElementName::DoIpTargetAddressRef)?
195 .set_reference_target(target.element())?;
196 Ok(())
197 }
198
199 #[must_use]
201 pub fn target(&self) -> Option<DoIpLogicAddress> {
202 self.element()
203 .get_sub_element(ElementName::DoIpTargetAddressRef)
204 .and_then(|elem| elem.get_reference_target().ok())
205 .and_then(|elem| DoIpLogicAddress::try_from(elem).ok())
206 }
207
208 pub fn set_tp_sdu_triggering(&self, tp_sdu_triggering: &PduTriggering) -> Result<(), AutosarAbstractionError> {
210 self.element()
211 .get_or_create_sub_element(ElementName::TpSduRef)?
212 .set_reference_target(tp_sdu_triggering.element())?;
213 Ok(())
214 }
215
216 #[must_use]
218 pub fn tp_sdu_triggering(&self) -> Option<PduTriggering> {
219 self.element()
220 .get_sub_element(ElementName::TpSduRef)
221 .and_then(|elem| elem.get_reference_target().ok())
222 .and_then(|elem| PduTriggering::try_from(elem).ok())
223 }
224}
225
226#[derive(Debug, Clone, PartialEq, Eq, Hash)]
232pub struct DoIpConfig(Element);
233abstraction_element!(DoIpConfig, DoIpConfig);
234
235#[cfg(test)]
238mod test {
239 use super::*;
240 use crate::{
241 AutosarModelAbstraction, SystemCategory,
242 communication::{
243 CommunicationDirection, DiagPduType, IPv4AddressSource, NetworkEndpointAddress, SocketAddressType, TpConfig,
244 },
245 };
246 use autosar_data::AutosarVersion;
247
248 #[test]
249 fn test_doip_transport_protocol() {
250 let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
251 let package = model.get_or_create_package("/pkg1").unwrap();
252
253 let system = package.create_system("system", SystemCategory::EcuExtract).unwrap();
254 let eth_cluster = system.create_ethernet_cluster("can_cluster", &package).unwrap();
255 let eth_channel = eth_cluster.create_physical_channel("can_channel", None).unwrap();
256 let ecu_instance = system.create_ecu_instance("ecu_instance", &package).unwrap();
257 let communication_controller = ecu_instance
258 .create_ethernet_communication_controller("can_ctrl", Some("ab:cd:ef:01:02:03".to_string()))
259 .unwrap();
260 let _connector = communication_controller
261 .connect_physical_channel("name", ð_channel)
262 .unwrap();
263
264 let network_address_1 = NetworkEndpointAddress::IPv4 {
266 address: Some("192.168.0.1".to_string()),
267 address_source: Some(IPv4AddressSource::Fixed),
268 default_gateway: Some("192.168.0.200".to_string()),
269 network_mask: Some("255.255.255.0".to_string()),
270 };
271 let network_endpoint_1 = eth_channel
272 .create_network_endpoint("local_endpoint", network_address_1, None)
273 .unwrap();
274 let udp_port_1 = TpConfig::UdpTp {
275 port_number: Some(1234),
276 port_dynamically_assigned: None,
277 };
278 let socket_type_1 = SocketAddressType::Unicast(Some(ecu_instance.clone()));
279 let socket_address_tcp_1 = eth_channel
280 .create_socket_address("ServerSocket", &network_endpoint_1, &udp_port_1, socket_type_1)
281 .unwrap();
282
283 let network_address_2 = NetworkEndpointAddress::IPv4 {
285 address: Some("192.168.0.2".to_string()),
286 address_source: Some(IPv4AddressSource::Fixed),
287 default_gateway: Some("192.168.0.200".to_string()),
288 network_mask: Some("255.255.255.0".to_string()),
289 };
290 let network_endpoint_2 = eth_channel
291 .create_network_endpoint("remote_endpoint", network_address_2, None)
292 .unwrap();
293 let udp_port_2 = TpConfig::UdpTp {
294 port_number: Some(5678),
295 port_dynamically_assigned: None,
296 };
297 let socket_type_2 = SocketAddressType::Unicast(None);
298 let socket_address_tcp_2 = eth_channel
299 .create_socket_address("ClientSocket", &network_endpoint_2, &udp_port_2, socket_type_2)
300 .unwrap();
301
302 let (static_socket_connection_a, static_socket_connection_b) = eth_channel
304 .create_static_socket_connection_pair(
305 "StaticSocketConnection",
306 &socket_address_tcp_1,
307 &socket_address_tcp_2,
308 None,
309 )
310 .unwrap();
311
312 let dcm_i_pdu = system
314 .create_dcm_ipdu("Diag", &package, 1024, DiagPduType::DiagRequest)
315 .unwrap();
316
317 let ipdu_identifier_set_package = model.get_or_create_package("/Network/IpduIdentifierSets").unwrap();
319 let socon_ipdu_identifier_set = system
320 .create_socket_connection_ipdu_identifier_set("IpduIdentifierSet", &ipdu_identifier_set_package)
321 .unwrap();
322 let ipdu_identifier = socon_ipdu_identifier_set
323 .create_socon_ipdu_identifier("IpduIdentifier", &dcm_i_pdu, ð_channel, Some(0x1000), None, None)
324 .unwrap();
325
326 static_socket_connection_a
328 .add_ipdu_identifier(&ipdu_identifier)
329 .unwrap();
330 static_socket_connection_b
331 .add_ipdu_identifier(&ipdu_identifier)
332 .unwrap();
333 let pdu_triggering = ipdu_identifier.pdu_triggering().unwrap();
334 pdu_triggering
335 .create_pdu_port(&ecu_instance, CommunicationDirection::Out)
336 .unwrap();
337
338 let doip_tp_config = system
339 .create_doip_tp_config("doip_tp_config", &package, ð_cluster)
340 .unwrap();
341 assert_eq!(doip_tp_config.cluster(), Some(eth_cluster.clone()));
342
343 let doip_logic_address_source = doip_tp_config.create_doip_logic_address("addr_source", 1).unwrap();
344 assert_eq!(doip_logic_address_source.address(), Some(1));
345 let doip_logic_address_target = doip_tp_config.create_doip_logic_address("addr_target", 2).unwrap();
346 assert_eq!(doip_logic_address_target.address(), Some(2));
347
348 let doip_tp_connection = doip_tp_config
349 .create_doip_tp_connection(
350 Some("connection_name"),
351 &doip_logic_address_source,
352 &doip_logic_address_target,
353 &pdu_triggering,
354 )
355 .unwrap();
356 assert_eq!(doip_tp_connection.source(), Some(doip_logic_address_source.clone()));
357 assert_eq!(doip_tp_connection.target(), Some(doip_logic_address_target.clone()));
358 assert_eq!(doip_tp_connection.tp_sdu_triggering(), Some(pdu_triggering.clone()));
359
360 assert_eq!(doip_tp_connection.name().unwrap(), "connection_name");
361 doip_tp_connection.set_name("other_name").unwrap();
362 assert_eq!(doip_tp_connection.name().unwrap(), "other_name");
363 doip_tp_connection
364 .element()
365 .remove_sub_element_kind(ElementName::Ident)
366 .unwrap();
367 assert_eq!(doip_tp_connection.name(), None);
368
369 let doip_tp_connections: Vec<DoIpTpConnection> = doip_tp_config.doip_tp_connections().collect();
370 assert_eq!(doip_tp_connections.len(), 1);
371 assert_eq!(doip_tp_connections[0], doip_tp_connection);
372
373 let doip_logic_addresses: Vec<DoIpLogicAddress> = doip_tp_config.doip_logic_addresses().collect();
374 assert_eq!(doip_logic_addresses.len(), 2);
375 assert_eq!(doip_logic_addresses[0], doip_logic_address_source);
376 }
377}