1use crate::communication::{
2 AbstractPdu, EthernetPhysicalChannel, EventGroupControlType, Pdu, PduCollectionTrigger, PduTriggering,
3 PhysicalChannel, SocketAddress, TpConfig,
4};
5use crate::{
6 AbstractionElement, ArPackage, AutosarAbstractionError, IdentifiableAbstractionElement, abstraction_element,
7};
8use autosar_data::{Element, ElementName, EnumItem};
9
10#[derive(Debug, Clone, PartialEq, Eq, Hash)]
15pub struct SocketConnectionBundle(Element);
16abstraction_element!(SocketConnectionBundle, SocketConnectionBundle);
17impl IdentifiableAbstractionElement for SocketConnectionBundle {}
18
19impl SocketConnectionBundle {
20 pub(crate) fn new(
21 name: &str,
22 server_port: &SocketAddress,
23 connections_elem: &Element,
24 ) -> Result<Self, AutosarAbstractionError> {
25 let scb_elem = connections_elem.create_named_sub_element(ElementName::SocketConnectionBundle, name)?;
26 let scb = Self(scb_elem);
27
28 scb.set_server_port(server_port)?;
29
30 Ok(scb)
31 }
32
33 pub fn physical_channel(&self) -> Result<EthernetPhysicalChannel, AutosarAbstractionError> {
66 let channel = self.element().named_parent()?.unwrap();
67 EthernetPhysicalChannel::try_from(channel)
68 }
69
70 pub fn set_server_port(&self, server_port: &SocketAddress) -> Result<(), AutosarAbstractionError> {
72 self.element()
73 .get_or_create_sub_element(ElementName::ServerPortRef)?
74 .set_reference_target(server_port.element())?;
75 Ok(())
76 }
77
78 #[must_use]
80 pub fn server_port(&self) -> Option<SocketAddress> {
81 self.element()
82 .get_sub_element(ElementName::ServerPortRef)
83 .and_then(|spr| spr.get_reference_target().ok())
84 .and_then(|sp| SocketAddress::try_from(sp).ok())
85 }
86
87 pub fn create_bundled_connection(
89 &self,
90 client_port: &SocketAddress,
91 ) -> Result<SocketConnection, AutosarAbstractionError> {
92 let Some(server_port) = self.server_port() else {
93 return Err(AutosarAbstractionError::InvalidParameter(
94 "SocketConnectionBundle has no server port".to_string(),
95 ));
96 };
97 let own_tp_config = server_port.tp_config();
98 let remote_tp_config = client_port.tp_config();
99 match (own_tp_config, remote_tp_config) {
100 (Some(TpConfig::TcpTp { .. }), Some(TpConfig::TcpTp { .. }))
101 | (Some(TpConfig::UdpTp { .. }), Some(TpConfig::UdpTp { .. }))
102 | (None, None) => { }
103 _ => {
104 return Err(AutosarAbstractionError::InvalidParameter(
105 "Both SocketAddresses must use the same transport protocol".to_string(),
106 ));
107 }
108 }
109 let conn = self
110 .0
111 .get_or_create_sub_element(ElementName::BundledConnections)?
112 .create_sub_element(ElementName::SocketConnection)?;
113
114 SocketConnection::new(conn, client_port)
115 }
116
117 pub fn bundled_connections(&self) -> impl Iterator<Item = SocketConnection> + Send + use<> {
119 self.element()
120 .get_sub_element(ElementName::BundledConnections)
121 .into_iter()
122 .flat_map(|bc| bc.sub_elements())
123 .filter_map(|elem| SocketConnection::try_from(elem).ok())
124 }
125}
126
127#[derive(Debug, Clone, PartialEq, Eq, Hash)]
131pub struct SocketConnection(Element);
132abstraction_element!(SocketConnection, SocketConnection);
133
134impl SocketConnection {
135 pub const SD_HEADER_ID: u32 = 0xFFFF_8100;
137
138 pub(crate) fn new(conn: Element, client_port: &SocketAddress) -> Result<Self, AutosarAbstractionError> {
140 let conn = Self(conn);
141 conn.set_client_port(client_port)?;
142
143 Ok(conn)
144 }
145
146 pub fn socket_connection_bundle(&self) -> Result<SocketConnectionBundle, AutosarAbstractionError> {
180 let bundle = self.element().named_parent()?.unwrap();
181 SocketConnectionBundle::try_from(bundle)
182 }
183
184 pub fn set_client_port(&self, client_port: &SocketAddress) -> Result<(), AutosarAbstractionError> {
186 self.element()
187 .get_or_create_sub_element(ElementName::ClientPortRef)?
188 .set_reference_target(client_port.element())?;
189 Ok(())
190 }
191
192 #[must_use]
194 pub fn client_port(&self) -> Option<SocketAddress> {
195 self.element()
196 .get_sub_element(ElementName::ClientPortRef)
197 .and_then(|cpr| cpr.get_reference_target().ok())
198 .and_then(|cp| SocketAddress::try_from(cp).ok())
199 }
200
201 pub fn create_socket_connection_ipdu_identifier<T: AbstractPdu>(
207 &self,
208 pdu: &T,
209 header_id: u32,
210 timeout: Option<f64>,
211 collection_trigger: Option<PduCollectionTrigger>,
212 ) -> Result<(SocketConnectionIpduIdentifier, PduTriggering), AutosarAbstractionError> {
213 SocketConnectionIpduIdentifier::new(
214 self.element(),
215 &pdu.clone().into(),
216 header_id,
217 timeout,
218 collection_trigger,
219 )
220 }
221
222 pub fn socket_connection_ipdu_identifiers(
224 &self,
225 ) -> impl Iterator<Item = SocketConnectionIpduIdentifier> + Send + use<> {
226 self.element()
227 .get_sub_element(ElementName::Pdus)
228 .into_iter()
229 .flat_map(|pdus| pdus.sub_elements())
230 .filter_map(|elem| SocketConnectionIpduIdentifier::try_from(elem).ok())
231 }
232
233 pub fn pdu_triggerings(&self) -> impl Iterator<Item = PduTriggering> + Send + use<> {
235 self.element()
236 .get_sub_element(ElementName::Pdus)
237 .into_iter()
238 .flat_map(|pdus| pdus.sub_elements())
239 .filter_map(|scii: Element| {
240 scii.get_sub_element(ElementName::PduTriggeringRef)
241 .and_then(|pt| pt.get_reference_target().ok())
242 .and_then(|pt| PduTriggering::try_from(pt).ok())
243 })
244 }
245
246 pub fn set_client_ip_addr_from_connection_request(
252 &self,
253 value: Option<bool>,
254 ) -> Result<(), AutosarAbstractionError> {
255 if let Some(value) = value {
256 self.element()
257 .get_or_create_sub_element(ElementName::ClientIpAddrFromConnectionRequest)?
258 .set_character_data(value.to_string())?;
259 } else {
260 let _ = self
261 .element()
262 .remove_sub_element_kind(ElementName::ClientIpAddrFromConnectionRequest);
263 }
264 Ok(())
265 }
266
267 #[must_use]
269 pub fn client_ip_addr_from_connection_request(&self) -> Option<bool> {
270 self.element()
271 .get_sub_element(ElementName::ClientIpAddrFromConnectionRequest)
272 .and_then(|elem| elem.character_data())
273 .and_then(|cdata| cdata.parse_bool())
274 }
275
276 pub fn set_client_port_from_connection_request(&self, value: Option<bool>) -> Result<(), AutosarAbstractionError> {
282 if let Some(value) = value {
283 self.element()
284 .get_or_create_sub_element(ElementName::ClientPortFromConnectionRequest)?
285 .set_character_data(value.to_string())?;
286 } else {
287 let _ = self
288 .element()
289 .remove_sub_element_kind(ElementName::ClientPortFromConnectionRequest);
290 }
291 Ok(())
292 }
293
294 #[must_use]
296 pub fn client_port_from_connection_request(&self) -> Option<bool> {
297 self.element()
298 .get_sub_element(ElementName::ClientPortFromConnectionRequest)
299 .and_then(|elem| elem.character_data())
300 .and_then(|cdata| cdata.parse_bool())
301 }
302
303 pub fn set_runtime_ip_address_configuration(&self, state: bool) -> Result<(), AutosarAbstractionError> {
308 if state {
309 self.element()
310 .get_or_create_sub_element(ElementName::RuntimeIpAddressConfiguration)?
311 .set_character_data(EnumItem::Sd)?;
312 } else {
313 let _ = self
314 .element()
315 .remove_sub_element_kind(ElementName::RuntimeIpAddressConfiguration);
316 }
317 Ok(())
318 }
319
320 #[must_use]
322 pub fn runtime_ip_address_configuration(&self) -> bool {
323 let enum_value = self
324 .element()
325 .get_sub_element(ElementName::RuntimeIpAddressConfiguration)
326 .and_then(|elem| elem.character_data())
327 .and_then(|cdata| cdata.enum_value());
328 enum_value == Some(EnumItem::Sd)
329 }
330
331 pub fn set_runtime_port_configuration(&self, state: bool) -> Result<(), AutosarAbstractionError> {
336 if state {
337 self.element()
338 .get_or_create_sub_element(ElementName::RuntimePortConfiguration)?
339 .set_character_data(EnumItem::Sd)?;
340 } else {
341 let _ = self
342 .element()
343 .remove_sub_element_kind(ElementName::RuntimePortConfiguration);
344 }
345 Ok(())
346 }
347
348 #[must_use]
350 pub fn runtime_port_configuration(&self) -> bool {
351 let enum_value = self
352 .element()
353 .get_sub_element(ElementName::RuntimePortConfiguration)
354 .and_then(|elem| elem.character_data())
355 .and_then(|cdata| cdata.enum_value());
356 enum_value == Some(EnumItem::Sd)
357 }
358}
359
360#[derive(Debug, Clone, PartialEq, Eq, Hash)]
367pub struct SocketConnectionIpduIdentifier(Element);
368abstraction_element!(SocketConnectionIpduIdentifier, SocketConnectionIpduIdentifier);
369
370impl SocketConnectionIpduIdentifier {
371 pub(crate) fn new<T: AbstractPdu>(
372 parent: &Element,
373 pdu: &T,
374 header_id: u32,
375 timeout: Option<f64>,
376 collection_trigger: Option<PduCollectionTrigger>,
377 ) -> Result<(Self, PduTriggering), AutosarAbstractionError> {
378 let scii_elem = parent
379 .get_or_create_sub_element(ElementName::Pdus)?
380 .create_sub_element(ElementName::SocketConnectionIpduIdentifier)?;
381 let scii = Self(scii_elem);
382 let pt = scii.trigger_pdu(&pdu.clone().into())?;
383 scii.set_header_id(header_id)?;
384 scii.set_timeout(timeout)?;
385 scii.set_collection_trigger(collection_trigger)?;
386
387 Ok((scii, pt))
388 }
389
390 pub fn socket_connection(&self) -> Result<SocketConnection, AutosarAbstractionError> {
392 let socket_connection_elem = self.element().parent()?.unwrap().parent()?.unwrap();
394 SocketConnection::try_from(socket_connection_elem)
395 }
396
397 pub fn trigger_pdu(&self, pdu: &Pdu) -> Result<PduTriggering, AutosarAbstractionError> {
399 if let Some(old_pt) = self.pdu_triggering() {
400 if let Ok(Some(parent)) = old_pt.element().parent() {
403 parent.remove_sub_element(old_pt.element().clone())?;
404 }
405 }
406 let channel = self
407 .socket_connection()?
408 .socket_connection_bundle()?
409 .physical_channel()?;
410 let pt = PduTriggering::new(pdu, &PhysicalChannel::Ethernet(channel))?;
411
412 self.element()
413 .get_or_create_sub_element(ElementName::PduTriggeringRef)?
414 .set_reference_target(pt.element())?;
415 Ok(pt)
416 }
417
418 #[must_use]
420 pub fn pdu_triggering(&self) -> Option<PduTriggering> {
421 self.element()
422 .get_sub_element(ElementName::PduTriggeringRef)
423 .and_then(|elem| elem.get_reference_target().ok())
424 .and_then(|pt| PduTriggering::try_from(pt).ok())
425 }
426
427 pub fn set_header_id(&self, header_id: u32) -> Result<(), AutosarAbstractionError> {
429 self.element()
430 .get_or_create_sub_element(ElementName::HeaderId)?
431 .set_character_data(header_id.to_string())?;
432 Ok(())
433 }
434
435 #[must_use]
437 pub fn header_id(&self) -> Option<u64> {
438 self.element()
439 .get_sub_element(ElementName::HeaderId)
440 .and_then(|elem| elem.character_data())
441 .and_then(|cdata| cdata.parse_integer())
442 }
443
444 pub fn set_timeout(&self, timeout: Option<f64>) -> Result<(), AutosarAbstractionError> {
446 if let Some(timeout) = timeout {
447 self.element()
448 .get_or_create_sub_element(ElementName::PduCollectionPduTimeout)?
449 .set_character_data(timeout)?;
450 } else {
451 let _ = self
452 .element()
453 .remove_sub_element_kind(ElementName::PduCollectionPduTimeout);
454 }
455 Ok(())
456 }
457
458 #[must_use]
460 pub fn timeout(&self) -> Option<f64> {
461 self.element()
462 .get_sub_element(ElementName::PduCollectionPduTimeout)
463 .and_then(|elem| elem.character_data())
464 .and_then(|cdata| cdata.float_value())
465 }
466
467 pub fn set_collection_trigger(&self, trigger: Option<PduCollectionTrigger>) -> Result<(), AutosarAbstractionError> {
469 if let Some(trigger) = trigger {
470 self.element()
471 .get_or_create_sub_element(ElementName::PduCollectionTrigger)?
472 .set_character_data::<EnumItem>(trigger.into())?;
473 } else {
474 let _ = self
475 .element()
476 .remove_sub_element_kind(ElementName::PduCollectionTrigger);
477 }
478 Ok(())
479 }
480
481 #[must_use]
483 pub fn collection_trigger(&self) -> Option<PduCollectionTrigger> {
484 self.element()
485 .get_sub_element(ElementName::PduCollectionTrigger)
486 .and_then(|elem| elem.character_data())
487 .and_then(|cdata| cdata.enum_value())
488 .and_then(|eval| eval.try_into().ok())
489 }
490
491 pub fn add_routing_group(&self, routing_group: &SoAdRoutingGroup) -> Result<(), AutosarAbstractionError> {
493 self.element()
494 .get_or_create_sub_element(ElementName::RoutingGroupRefs)?
495 .create_sub_element(ElementName::RoutingGroupRef)?
496 .set_reference_target(routing_group.element())?;
497 Ok(())
498 }
499
500 pub fn routing_groups(&self) -> impl Iterator<Item = SoAdRoutingGroup> + Send + use<> {
502 self.element()
503 .get_sub_element(ElementName::RoutingGroupRefs)
504 .into_iter()
505 .flat_map(|rgr| rgr.sub_elements())
506 .filter_map(|ref_elem| {
507 ref_elem
508 .get_reference_target()
509 .ok()
510 .and_then(|elem| SoAdRoutingGroup::try_from(elem).ok())
511 })
512 }
513}
514
515#[derive(Debug, Clone, PartialEq, Eq, Hash)]
521pub struct SoAdRoutingGroup(Element);
522abstraction_element!(SoAdRoutingGroup, SoAdRoutingGroup);
523impl IdentifiableAbstractionElement for SoAdRoutingGroup {}
524
525impl SoAdRoutingGroup {
526 pub(crate) fn new(
532 name: &str,
533 package: &ArPackage,
534 control_type: Option<EventGroupControlType>,
535 ) -> Result<Self, AutosarAbstractionError> {
536 let srg_elem: Element = package
537 .element()
538 .get_or_create_sub_element(ElementName::Elements)?
539 .create_named_sub_element(ElementName::SoAdRoutingGroup, name)?;
540 let srg = Self(srg_elem);
541
542 if let Some(control_type) = control_type {
543 srg.set_control_type(control_type)?;
544 }
545
546 Ok(srg)
547 }
548
549 pub fn set_control_type(&self, control_type: EventGroupControlType) -> Result<(), AutosarAbstractionError> {
551 self.element()
552 .get_or_create_sub_element(ElementName::EventGroupControlType)?
553 .set_character_data::<EnumItem>(control_type.into())?;
554 Ok(())
555 }
556
557 #[must_use]
559 pub fn control_type(&self) -> Option<EventGroupControlType> {
560 self.element()
561 .get_sub_element(ElementName::EventGroupControlType)
562 .and_then(|elem| elem.character_data())
563 .and_then(|cdata| cdata.enum_value())
564 .and_then(|eval| eval.try_into().ok())
565 }
566}
567
568#[cfg(test)]
571mod test {
572 use super::*;
573 use crate::{
574 AutosarModelAbstraction, SystemCategory,
575 communication::{IPv4AddressSource, NetworkEndpointAddress, SocketAddressType},
576 };
577 use autosar_data::AutosarVersion;
578
579 #[test]
580 fn test_socket_connection_bundle() {
581 let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
582 let package = model.get_or_create_package("/pkg1").unwrap();
583 let system = package.create_system("System", SystemCategory::SystemExtract).unwrap();
584 let cluster = system.create_ethernet_cluster("Cluster", &package).unwrap();
585 let channel = cluster.create_physical_channel("Channel", None).unwrap();
586 let server_endpoint = channel
587 .create_network_endpoint(
588 "ServerAddress",
589 NetworkEndpointAddress::IPv4 {
590 address: Some("192.168.0.1".to_string()),
591 address_source: Some(IPv4AddressSource::Fixed),
592 default_gateway: None,
593 network_mask: None,
594 },
595 None,
596 )
597 .unwrap();
598 let server_socket = channel
599 .create_socket_address(
600 "ServerSocket",
601 &server_endpoint,
602 &TpConfig::TcpTp {
603 port_number: Some(1234),
604 port_dynamically_assigned: None,
605 },
606 SocketAddressType::Unicast(None),
607 )
608 .unwrap();
609 let bundle = channel
610 .create_socket_connection_bundle("Bundle", &server_socket)
611 .unwrap();
612 assert_eq!(channel.socket_connection_bundles().next(), Some(bundle.clone()));
613 assert_eq!(channel.socket_connection_bundles().count(), 1);
614 assert_eq!(channel, bundle.physical_channel().unwrap());
615 assert_eq!(Some(server_socket), bundle.server_port());
616
617 let client_endpoint = channel
618 .create_network_endpoint(
619 "ClientAddress",
620 NetworkEndpointAddress::IPv4 {
621 address: Some("192.168.0.2".to_string()),
622 address_source: Some(IPv4AddressSource::Fixed),
623 default_gateway: None,
624 network_mask: None,
625 },
626 None,
627 )
628 .unwrap();
629 let client_socket = channel
630 .create_socket_address(
631 "ClientSocket",
632 &client_endpoint,
633 &TpConfig::TcpTp {
634 port_number: Some(1235),
635 port_dynamically_assigned: None,
636 },
637 SocketAddressType::Unicast(None),
638 )
639 .unwrap();
640 let connection = bundle.create_bundled_connection(&client_socket).unwrap();
641
642 let pdu = system.create_isignal_ipdu("Pdu", &package, 8).unwrap();
643 let (scii, pt) = connection
644 .create_socket_connection_ipdu_identifier(&pdu, 0x1234, Some(0.5), Some(PduCollectionTrigger::Always))
645 .unwrap();
646 assert_eq!(connection.socket_connection_ipdu_identifiers().count(), 1);
647 assert_eq!(pt, scii.pdu_triggering().unwrap());
648 assert_eq!(Some(pt.clone()), connection.pdu_triggerings().next());
649 assert_eq!(Some(0x1234), scii.header_id());
650 assert_eq!(Some(0.5), scii.timeout());
651 assert_eq!(Some(PduCollectionTrigger::Always), scii.collection_trigger());
652
653 scii.set_header_id(0x5678).unwrap();
654 assert_eq!(Some(0x5678), scii.header_id());
655 scii.set_timeout(Some(1.5)).unwrap();
656 assert_eq!(Some(1.5), scii.timeout());
657 scii.set_collection_trigger(Some(PduCollectionTrigger::Never)).unwrap();
658 assert_eq!(Some(PduCollectionTrigger::Never), scii.collection_trigger());
659 connection
660 .set_client_ip_addr_from_connection_request(Some(true))
661 .unwrap();
662 assert_eq!(connection.client_ip_addr_from_connection_request(), Some(true));
663 connection.set_client_ip_addr_from_connection_request(None).unwrap();
664 assert_eq!(connection.client_ip_addr_from_connection_request(), None);
665 connection.set_client_port_from_connection_request(Some(false)).unwrap();
666 assert_eq!(connection.client_port_from_connection_request(), Some(false));
667 connection.set_client_port_from_connection_request(None).unwrap();
668 assert_eq!(connection.client_port_from_connection_request(), None);
669 connection.set_runtime_ip_address_configuration(true).unwrap();
670 assert!(connection.runtime_ip_address_configuration());
671 connection.set_runtime_port_configuration(true).unwrap();
672 assert!(connection.runtime_port_configuration());
673 connection.set_runtime_ip_address_configuration(false).unwrap();
674 assert!(!connection.runtime_ip_address_configuration());
675 connection.set_runtime_port_configuration(false).unwrap();
676 assert!(!connection.runtime_port_configuration());
677
678 let routing_group = system
679 .create_so_ad_routing_group("RoutingGroup", &package, None)
680 .unwrap();
681 scii.add_routing_group(&routing_group).unwrap();
682 assert_eq!(scii.routing_groups().next(), Some(routing_group.clone()));
683 assert_eq!(scii.routing_groups().count(), 1);
684
685 assert_eq!(routing_group.control_type(), None);
686 routing_group
687 .set_control_type(EventGroupControlType::TriggerUnicast)
688 .unwrap();
689 assert_eq!(
690 routing_group.control_type(),
691 Some(EventGroupControlType::TriggerUnicast)
692 );
693 }
694}