1use crate::communication::{
2 AbstractPhysicalChannel, ConsumedServiceInstanceV1, EthernetPhysicalChannel, NetworkEndpoint,
3 ProvidedServiceInstanceV1, SocketConnection, SocketConnectionBundle, StaticSocketConnection, TcpRole,
4};
5use crate::{
6 AbstractionElement, AutosarAbstractionError, EcuInstance, IdentifiableAbstractionElement, abstraction_element,
7 get_reference_parents,
8};
9use autosar_data::{Element, ElementName};
10
11#[derive(Debug, Clone, PartialEq, Eq, Hash)]
16pub struct SocketAddress(Element);
17abstraction_element!(SocketAddress, SocketAddress);
18impl IdentifiableAbstractionElement for SocketAddress {}
19
20impl SocketAddress {
21 pub(crate) fn new(
22 name: &str,
23 channel: &EthernetPhysicalChannel,
24 network_endpoint: &NetworkEndpoint,
25 tp_config: &TpConfig,
26 sa_type: SocketAddressType,
27 ) -> Result<Self, AutosarAbstractionError> {
28 let channel_elem = channel.element();
29 let (unicast, ecu_instances) = match sa_type {
30 SocketAddressType::Unicast(Some(ecu_instance)) => (true, vec![ecu_instance]),
31 SocketAddressType::Unicast(None) => (true, vec![]),
32 SocketAddressType::Multicast(ecu_instances) => (false, ecu_instances),
33 };
34
35 if !unicast && matches!(tp_config, TpConfig::TcpTp { .. }) {
37 return Err(AutosarAbstractionError::InvalidParameter(
38 "TCP is incomptible with multicasting".to_string(),
39 ));
40 }
41 let connectors = ecu_instances
47 .iter()
48 .filter_map(|ecu_instance| channel.ecu_connector(ecu_instance).map(|conn| conn.element().clone()))
49 .collect::<Vec<_>>();
50 if connectors.len() != ecu_instances.len() {
51 return Err(AutosarAbstractionError::InvalidParameter(
52 "All EcuInstances must be connected to the EthernetPhysicalChannel".to_string(),
53 ));
54 }
55
56 let elem = channel_elem
57 .get_or_create_sub_element(ElementName::SoAdConfig)?
58 .get_or_create_sub_element(ElementName::SocketAddresss)?
59 .create_named_sub_element(ElementName::SocketAddress, name)?;
60
61 if unicast {
62 if !connectors.is_empty() {
63 elem.create_sub_element(ElementName::ConnectorRef)
64 .unwrap()
65 .set_reference_target(&connectors[0])
66 .unwrap();
67 }
68 } else {
69 let mc_connectors = elem.create_sub_element(ElementName::MulticastConnectorRefs)?;
70 for conn in &connectors {
71 mc_connectors
72 .create_sub_element(ElementName::MulticastConnectorRef)?
73 .set_reference_target(conn)?;
74 }
75 }
76
77 let ae_name = format!("{name}_AE");
78 let ae = elem.create_named_sub_element(ElementName::ApplicationEndpoint, &ae_name)?;
79 ae.create_sub_element(ElementName::NetworkEndpointRef)?
80 .set_reference_target(network_endpoint.element())?;
81 let tp_configuration = ae.create_sub_element(ElementName::TpConfiguration)?;
82 match tp_config {
83 TpConfig::TcpTp {
84 port_number,
85 port_dynamically_assigned,
86 } => {
87 let tcptp = tp_configuration.create_sub_element(ElementName::TcpTp)?;
88 let tcptp_port = tcptp.create_sub_element(ElementName::TcpTpPort)?;
89 if let Some(portnum) = port_number {
92 tcptp_port
93 .create_sub_element(ElementName::PortNumber)?
94 .set_character_data(portnum.to_string())?;
95 } else if let Some(dyn_assign) = port_dynamically_assigned {
96 tcptp_port
97 .create_sub_element(ElementName::DynamicallyAssigned)?
98 .set_character_data(*dyn_assign)?;
99 }
100 }
101 TpConfig::UdpTp {
102 port_number,
103 port_dynamically_assigned,
104 } => {
105 let udptp_port = tp_configuration
106 .create_sub_element(ElementName::UdpTp)?
107 .create_sub_element(ElementName::UdpTpPort)?;
108 if let Some(portnum) = port_number {
111 udptp_port
112 .create_sub_element(ElementName::PortNumber)?
113 .set_character_data(portnum.to_string())?;
114 } else if let Some(dyn_assign) = port_dynamically_assigned {
115 let boolstr = if *dyn_assign { "true" } else { "false" };
116 udptp_port
117 .create_sub_element(ElementName::DynamicallyAssigned)?
118 .set_character_data(boolstr)?;
119 }
120 }
121 }
122
123 Ok(Self(elem))
124 }
125
126 pub fn remove(self, deep: bool) -> Result<(), AutosarAbstractionError> {
128 for static_socket_connection in self.static_socket_connections() {
129 static_socket_connection.remove(deep)?;
130 }
131
132 for provided_service_instance in self.provided_service_instances() {
133 provided_service_instance.remove(deep)?;
134 }
135
136 for consumed_service_instance in self.consumed_service_instances() {
137 consumed_service_instance.remove(deep)?;
138 }
139
140 let ref_parents = get_reference_parents(self.element())?;
141
142 AbstractionElement::remove(self, deep)?;
143
144 for (named_parent, _parent) in ref_parents {
145 match named_parent.element_name() {
146 ElementName::SocketConnectionBundle => {
147 if let Ok(socket_connection_bundle) = SocketConnectionBundle::try_from(named_parent) {
148 socket_connection_bundle.remove(deep)?;
149 }
150 }
151 ElementName::SocketConnection => {
152 if let Ok(socket_connection) = SocketConnection::try_from(named_parent) {
153 socket_connection.remove(deep)?;
154 }
155 }
156 _ => {}
157 }
158 }
159
160 Ok(())
161 }
162
163 #[must_use]
165 pub fn network_endpoint(&self) -> Option<NetworkEndpoint> {
166 let ne = self
167 .element()
168 .get_sub_element(ElementName::ApplicationEndpoint)?
169 .get_sub_element(ElementName::NetworkEndpointRef)?
170 .get_reference_target()
171 .ok()?;
172 ne.try_into().ok()
173 }
174
175 #[must_use]
177 pub fn socket_address_type(&self) -> Option<SocketAddressType> {
178 if let Some(connector_ref) = self.0.get_sub_element(ElementName::ConnectorRef) {
179 let ecu = EcuInstance::try_from(connector_ref.get_reference_target().ok()?.named_parent().ok()??).ok()?;
180 Some(SocketAddressType::Unicast(Some(ecu)))
181 } else if let Some(mcr) = self.0.get_sub_element(ElementName::MulticastConnectorRefs) {
182 let ecus = mcr
183 .sub_elements()
184 .filter_map(|cr| {
185 cr.get_reference_target()
186 .ok()
187 .and_then(|conn| conn.named_parent().ok().flatten())
188 })
189 .filter_map(|ecu_elem| EcuInstance::try_from(ecu_elem).ok())
190 .collect::<Vec<_>>();
191 Some(SocketAddressType::Multicast(ecus))
192 } else {
193 None
194 }
195 }
196
197 pub fn add_multicast_ecu(&self, ecu: &EcuInstance) -> Result<(), AutosarAbstractionError> {
199 let socket_type = self.socket_address_type();
200 match socket_type {
201 Some(SocketAddressType::Multicast(multicast_ecus)) => {
202 if !multicast_ecus.contains(ecu) {
204 let Some(connector) = self.physical_channel()?.ecu_connector(ecu) else {
205 return Err(AutosarAbstractionError::InvalidParameter(
206 "EcuInstance is not connected to the EthernetPhysicalChannel".to_string(),
207 ));
208 };
209 let mcr = self.0.get_or_create_sub_element(ElementName::MulticastConnectorRefs)?;
210 let mc_ref = mcr.create_sub_element(ElementName::MulticastConnectorRef)?;
211 mc_ref.set_reference_target(connector.element())?;
212 }
213 }
214 None => {
215 let Some(connector) = self.physical_channel()?.ecu_connector(ecu) else {
217 return Err(AutosarAbstractionError::InvalidParameter(
218 "EcuInstance is not connected to the EthernetPhysicalChannel".to_string(),
219 ));
220 };
221 let mcr = self.0.get_or_create_sub_element(ElementName::MulticastConnectorRefs)?;
222 let mc_ref = mcr.create_sub_element(ElementName::MulticastConnectorRef)?;
223 mc_ref.set_reference_target(connector.element())?;
224 }
225 Some(SocketAddressType::Unicast(_)) => {
226 return Err(AutosarAbstractionError::InvalidParameter(
227 "This SocketAddress is not a multicast socket".to_string(),
228 ));
229 }
230 }
231
232 Ok(())
233 }
234
235 pub fn set_unicast_ecu(&self, ecu: &EcuInstance) -> Result<(), AutosarAbstractionError> {
237 let socket_type = self.socket_address_type();
238 match socket_type {
239 None | Some(SocketAddressType::Unicast(_)) => {
240 let channel = self.physical_channel()?;
241 let Some(connector) = channel.ecu_connector(ecu) else {
242 return Err(AutosarAbstractionError::InvalidParameter(
243 "EcuInstance is not connected to the EthernetPhysicalChannel".to_string(),
244 ));
245 };
246 self.0
247 .get_or_create_sub_element(ElementName::ConnectorRef)?
248 .set_reference_target(connector.element())?;
249 }
250 Some(SocketAddressType::Multicast(_)) => {
251 return Err(AutosarAbstractionError::InvalidParameter(
252 "This SocketAddress is not a unicast socket".to_string(),
253 ));
254 }
255 }
256
257 Ok(())
258 }
259
260 #[must_use]
262 pub fn tp_config(&self) -> Option<TpConfig> {
263 let tp = self
264 .0
265 .get_sub_element(ElementName::ApplicationEndpoint)?
266 .get_sub_element(ElementName::TpConfiguration)?;
267
268 if let Some(tcp_tp) = tp.get_sub_element(ElementName::TcpTp) {
269 let port = tcp_tp.get_sub_element(ElementName::TcpTpPort)?;
270 let (port_number, port_dynamically_assigned) = Self::port_config(&port);
271 Some(TpConfig::TcpTp {
272 port_number,
273 port_dynamically_assigned,
274 })
275 } else if let Some(udp_tp) = tp.get_sub_element(ElementName::UdpTp) {
276 let port = udp_tp.get_sub_element(ElementName::UdpTpPort)?;
277 let (port_number, port_dynamically_assigned) = Self::port_config(&port);
278 Some(TpConfig::UdpTp {
279 port_number,
280 port_dynamically_assigned,
281 })
282 } else {
283 None
284 }
285 }
286
287 fn port_config(port_element: &Element) -> (Option<u16>, Option<bool>) {
289 let port_number = port_element
290 .get_sub_element(ElementName::PortNumber)
291 .and_then(|pn| pn.character_data())
292 .and_then(|cdata| cdata.parse_integer());
293 let port_dynamically_assigned = port_element
294 .get_sub_element(ElementName::DynamicallyAssigned)
295 .and_then(|da| da.character_data())
296 .and_then(|cdata| cdata.string_value())
297 .map(|val| val == "true" || val == "1");
298 (port_number, port_dynamically_assigned)
299 }
300
301 pub fn create_static_socket_connection(
303 &self,
304 name: &str,
305 remote_address: &SocketAddress,
306 tcp_role: Option<TcpRole>,
307 tcp_connect_timeout: Option<f64>,
308 ) -> Result<StaticSocketConnection, AutosarAbstractionError> {
309 let own_tp_config = self.tp_config();
310 let remote_tp_config = remote_address.tp_config();
311 match (own_tp_config, remote_tp_config) {
312 (Some(TpConfig::TcpTp { .. }), Some(TpConfig::TcpTp { .. })) => {
313 StaticSocketConnection::new(name, self.element(), remote_address, tcp_role, tcp_connect_timeout)
314 }
315 (Some(TpConfig::UdpTp { .. }), Some(TpConfig::UdpTp { .. })) | (None, None) => {
316 StaticSocketConnection::new(name, self.element(), remote_address, None, None)
317 }
318 _ => Err(AutosarAbstractionError::InvalidParameter(
319 "Both SocketAddresses must use the same transport protocol".to_string(),
320 )),
321 }
322 }
323
324 pub fn physical_channel(&self) -> Result<EthernetPhysicalChannel, AutosarAbstractionError> {
326 let named_parent = self.0.named_parent()?.unwrap();
327 named_parent.try_into()
328 }
329
330 pub fn static_socket_connections(&self) -> impl Iterator<Item = StaticSocketConnection> + Send + use<> {
332 self.0
333 .get_sub_element(ElementName::StaticSocketConnections)
334 .into_iter()
335 .flat_map(|ssc| ssc.sub_elements())
336 .filter_map(|ssc| StaticSocketConnection::try_from(ssc).ok())
337 }
338
339 pub fn create_provided_service_instance(
346 &self,
347 name: &str,
348 service_identifier: u16,
349 instance_identifier: u16,
350 ) -> Result<ProvidedServiceInstanceV1, AutosarAbstractionError> {
351 let socket_name = self.name().unwrap_or_default();
352 let ae_name = format!("{socket_name}_AE");
353 let ae = self
354 .element()
355 .get_or_create_named_sub_element(ElementName::ApplicationEndpoint, &ae_name)?;
356 let psis = ae.get_or_create_sub_element(ElementName::ProvidedServiceInstances)?;
357
358 ProvidedServiceInstanceV1::new(name, &psis, service_identifier, instance_identifier)
359 }
360
361 pub fn provided_service_instances(&self) -> impl Iterator<Item = ProvidedServiceInstanceV1> + Send + use<> {
363 self.element()
364 .get_sub_element(ElementName::ApplicationEndpoint)
365 .and_then(|ae| ae.get_sub_element(ElementName::ProvidedServiceInstances))
366 .into_iter()
367 .flat_map(|psis| psis.sub_elements())
368 .filter_map(|psi| ProvidedServiceInstanceV1::try_from(psi).ok())
369 }
370
371 pub fn create_consumed_service_instance(
378 &self,
379 name: &str,
380 provided_service_instance: &ProvidedServiceInstanceV1,
381 ) -> Result<ConsumedServiceInstanceV1, AutosarAbstractionError> {
382 let socket_name = self.name().unwrap_or_default();
383 let ae_name = format!("{socket_name}_AE");
384 let ae = self
385 .element()
386 .get_or_create_named_sub_element(ElementName::ApplicationEndpoint, &ae_name)?;
387 let csis = ae.get_or_create_sub_element(ElementName::ConsumedServiceInstances)?;
388 ConsumedServiceInstanceV1::new(name, &csis, provided_service_instance)
389 }
390
391 pub fn consumed_service_instances(&self) -> impl Iterator<Item = ConsumedServiceInstanceV1> + Send + use<> {
393 self.element()
394 .get_sub_element(ElementName::ApplicationEndpoint)
395 .and_then(|ae| ae.get_sub_element(ElementName::ConsumedServiceInstances))
396 .into_iter()
397 .flat_map(|csis| csis.sub_elements())
398 .filter_map(|csi| ConsumedServiceInstanceV1::try_from(csi).ok())
399 }
400}
401
402#[derive(Debug, Clone, PartialEq, Eq)]
406pub enum TpConfig {
407 TcpTp {
409 port_number: Option<u16>,
411 port_dynamically_assigned: Option<bool>,
413 },
415 UdpTp {
417 port_number: Option<u16>,
419 port_dynamically_assigned: Option<bool>,
421 },
422 }
424
425#[derive(Debug, Clone, PartialEq)]
429pub enum SocketAddressType {
430 Unicast(Option<EcuInstance>),
432 Multicast(Vec<EcuInstance>),
434}
435
436#[cfg(test)]
439mod test {
440 use super::*;
441 use crate::communication::{IPv4AddressSource, NetworkEndpointAddress};
442 use crate::{AutosarModelAbstraction, SystemCategory};
443 use autosar_data::AutosarVersion;
444
445 #[test]
446 fn socket_address() {
447 let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_4_3_0);
448 let package = model.get_or_create_package("/pkg1").unwrap();
449 let system = package.create_system("System", SystemCategory::SystemExtract).unwrap();
450 let cluster = system.create_ethernet_cluster("Cluster", &package).unwrap();
451 let channel = cluster.create_physical_channel("Channel", None).unwrap();
452
453 let ecu_instance = system.create_ecu_instance("Ecu", &package).unwrap();
454 let controller = ecu_instance
455 .create_ethernet_communication_controller("EthCtrl", None)
456 .unwrap();
457 controller.connect_physical_channel("connection", &channel).unwrap();
458
459 let ecu_instance2 = system.create_ecu_instance("Ecu2", &package).unwrap();
460 let controller2 = ecu_instance2
461 .create_ethernet_communication_controller("EthCtrl", None)
462 .unwrap();
463 controller2.connect_physical_channel("connection", &channel).unwrap();
464
465 let ecu_instance3 = system.create_ecu_instance("Ecu3", &package).unwrap();
466 let controller3 = ecu_instance3
467 .create_ethernet_communication_controller("EthCtrl", None)
468 .unwrap();
469 controller3.connect_physical_channel("connection", &channel).unwrap();
470
471 let endpoint_address = NetworkEndpointAddress::IPv4 {
472 address: Some("192.168.0.1".to_string()),
473 address_source: Some(IPv4AddressSource::Fixed),
474 default_gateway: Some("192.168.0.2".to_string()),
475 network_mask: Some("255.255.255.0".to_string()),
476 };
477 let network_endpoint = channel
478 .create_network_endpoint("Address", endpoint_address, Some(&ecu_instance))
479 .unwrap();
480 let tcp_port = TpConfig::UdpTp {
481 port_number: Some(1234),
482 port_dynamically_assigned: None,
483 };
484
485 let socket_type: SocketAddressType = SocketAddressType::Unicast(Some(ecu_instance.clone()));
487 let unicast_socket_address = channel
488 .create_socket_address("Socket", &network_endpoint, &tcp_port, socket_type.clone())
489 .unwrap();
490 assert_eq!(channel.socket_addresses().count(), 1);
491 assert_eq!(unicast_socket_address.network_endpoint().unwrap(), network_endpoint);
492 assert_eq!(unicast_socket_address.socket_address_type().unwrap(), socket_type);
493 unicast_socket_address.set_unicast_ecu(&ecu_instance2).unwrap();
495 assert_eq!(
496 unicast_socket_address.socket_address_type().unwrap(),
497 SocketAddressType::Unicast(Some(ecu_instance2.clone()))
498 );
499
500 let socket_type: SocketAddressType = SocketAddressType::Unicast(None);
502 let unicast_socket_address2 = channel
503 .create_socket_address("Socket2", &network_endpoint, &tcp_port, socket_type.clone())
504 .unwrap();
505 unicast_socket_address2.set_unicast_ecu(&ecu_instance).unwrap();
507 assert_eq!(
508 unicast_socket_address2.socket_address_type().unwrap(),
509 SocketAddressType::Unicast(Some(ecu_instance.clone()))
510 );
511
512 let socket_type: SocketAddressType =
514 SocketAddressType::Multicast(vec![ecu_instance.clone(), ecu_instance2.clone()]);
515 let multicast_socket_address = channel
516 .create_socket_address("Socket3", &network_endpoint, &tcp_port, socket_type.clone())
517 .unwrap();
518 assert_eq!(multicast_socket_address.socket_address_type().unwrap(), socket_type);
519 multicast_socket_address.add_multicast_ecu(&ecu_instance3).unwrap();
521 assert_eq!(
522 multicast_socket_address.socket_address_type().unwrap(),
523 SocketAddressType::Multicast(vec![ecu_instance.clone(), ecu_instance2.clone(), ecu_instance3.clone()])
524 );
525 }
526
527 #[test]
528 fn socket_sd_config() {
529 let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_4_3_0);
530 let package = model.get_or_create_package("/pkg1").unwrap();
531 let system = package.create_system("System", SystemCategory::SystemExtract).unwrap();
532 let cluster = system.create_ethernet_cluster("Cluster", &package).unwrap();
533 let channel = cluster.create_physical_channel("Channel", None).unwrap();
534
535 let endpoint_address = NetworkEndpointAddress::IPv4 {
542 address: Some("192.168.0.1".to_string()),
543 address_source: Some(IPv4AddressSource::Fixed),
544 default_gateway: None,
545 network_mask: None,
546 };
547 let network_endpoint = channel
548 .create_network_endpoint("Address", endpoint_address, None)
549 .unwrap();
550 let tcp_port = TpConfig::TcpTp {
551 port_number: Some(1234),
552 port_dynamically_assigned: None,
553 };
554 let socket_type: SocketAddressType = SocketAddressType::Unicast(None);
555 let socket = channel
556 .create_socket_address("Socket", &network_endpoint, &tcp_port, socket_type.clone())
557 .unwrap();
558
559 let provided_service_instance = socket.create_provided_service_instance("psi", 1, 2).unwrap();
560 let consumed_service_instance = socket
561 .create_consumed_service_instance("csi", &provided_service_instance)
562 .unwrap();
563
564 assert_eq!(socket.provided_service_instances().count(), 1);
565 assert_eq!(
566 socket.provided_service_instances().next().unwrap(),
567 provided_service_instance
568 );
569 assert_eq!(socket.consumed_service_instances().count(), 1);
570 assert_eq!(
571 socket.consumed_service_instances().next().unwrap(),
572 consumed_service_instance
573 );
574 }
575}