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