1use crate::communication::{
2 AbstractPdu, AbstractPhysicalChannel, CommunicationDirection, EthernetCluster, EthernetCommunicationConnector,
3 GeneralPurposePdu, Pdu, PduCollectionTrigger, PduTriggering,
4};
5use crate::{
6 AbstractionElement, ArPackage, AutosarAbstractionError, EcuInstance, IdentifiableAbstractionElement,
7 abstraction_element,
8};
9use autosar_data::{AutosarVersion, Element, ElementName, EnumItem};
10
11mod networkendpoint;
12mod soad_old;
13mod socketaddress;
14mod someip;
15mod someip_old;
16
17pub use networkendpoint::*;
18pub use soad_old::*;
19pub use socketaddress::*;
20pub use someip::*;
21pub use someip_old::*;
22
23use super::PhysicalChannel;
24
25#[derive(Debug, Clone, PartialEq)]
29pub struct EthernetVlanInfo {
30 pub vlan_name: String,
32 pub vlan_id: u16,
34}
35
36#[derive(Debug, Clone, PartialEq, Eq, Hash)]
40pub struct EthernetPhysicalChannel(Element);
41abstraction_element!(EthernetPhysicalChannel, EthernetPhysicalChannel);
42impl IdentifiableAbstractionElement for EthernetPhysicalChannel {}
43
44impl EthernetPhysicalChannel {
45 pub(crate) fn new(
47 name: &str,
48 parent: &Element,
49 vlan_info: Option<&EthernetVlanInfo>,
50 ) -> Result<EthernetPhysicalChannel, AutosarAbstractionError> {
51 let physical_channel_elem = parent.create_named_sub_element(ElementName::EthernetPhysicalChannel, name)?;
52 let physical_channel = Self(physical_channel_elem);
53
54 let result = physical_channel.set_vlan_info(vlan_info);
56 if let Err(error) = result {
57 let _ = parent.remove_sub_element(physical_channel.element().clone());
59 return Err(error);
60 }
61
62 let _ = physical_channel
64 .0
65 .create_sub_element(ElementName::Category)
66 .and_then(|cat| cat.set_character_data("WIRED"));
67
68 Ok(physical_channel)
69 }
70
71 pub fn set_vlan_info(&self, vlan_info: Option<&EthernetVlanInfo>) -> Result<(), AutosarAbstractionError> {
102 let cluster = self.cluster()?;
103 for channel in cluster.physical_channels() {
106 if &channel != self {
107 let other_vlan_info = channel.vlan_info();
108 if let (Some(v1), Some(v2)) = (&vlan_info, &other_vlan_info) {
109 if v1.vlan_id == v2.vlan_id {
110 return Err(AutosarAbstractionError::ItemAlreadyExists);
112 }
113 } else if other_vlan_info.is_none() && vlan_info.is_none() {
114 return Err(AutosarAbstractionError::ItemAlreadyExists);
116 }
117 }
118 }
119
120 let _ = self.element().remove_sub_element_kind(ElementName::Vlan);
122 if let Some(vlan_info) = vlan_info {
124 let _ = self
125 .element()
126 .create_named_sub_element(ElementName::Vlan, &vlan_info.vlan_name)
127 .and_then(|vlan| vlan.create_sub_element(ElementName::VlanIdentifier))
128 .and_then(|vlan_id| vlan_id.set_character_data(vlan_info.vlan_id.to_string()));
129 }
130
131 Ok(())
132 }
133
134 #[must_use]
159 pub fn vlan_info(&self) -> Option<EthernetVlanInfo> {
160 let vlan = self.0.get_sub_element(ElementName::Vlan)?;
161 let vlan_id = vlan
162 .get_sub_element(ElementName::VlanIdentifier)?
163 .character_data()?
164 .parse_integer::<u16>()?;
165 Some(EthernetVlanInfo {
166 vlan_name: vlan.item_name()?,
167 vlan_id,
168 })
169 }
170
171 pub fn cluster(&self) -> Result<EthernetCluster, AutosarAbstractionError> {
193 let cluster_elem = self.0.named_parent()?.unwrap();
194 EthernetCluster::try_from(cluster_elem)
195 }
196
197 pub fn create_network_endpoint(
229 &self,
230 name: &str,
231 address: NetworkEndpointAddress,
232 ecu: Option<&EcuInstance>,
233 ) -> Result<NetworkEndpoint, AutosarAbstractionError> {
234 let network_endpoint = NetworkEndpoint::new(name, self, address)?;
235
236 if let Some(ecu_instance) = ecu {
237 let version = self.0.min_version()?;
238 if version <= AutosarVersion::Autosar_00046 {
239 let ne_element = network_endpoint.element();
240
241 if let Some(connector) = self.ecu_connector(ecu_instance).map(|conn| conn.element().clone()) {
243 let _ = connector
244 .get_or_create_sub_element(ElementName::NetworkEndpointRefs)
245 .and_then(|ner| ner.create_sub_element(ElementName::NetworkEndpointRef))
246 .and_then(|ner| ner.set_reference_target(ne_element));
247 } else {
248 let _ = self
251 .element()
252 .get_sub_element(ElementName::NetworkEndpoints)
253 .and_then(|nes| nes.remove_sub_element(ne_element.clone()).ok());
254 return Err(AutosarAbstractionError::InvalidParameter(
255 "The ECU must be connected to the channel".to_string(),
256 ));
257 }
258 }
259 }
260
261 Ok(network_endpoint)
262 }
263
264 pub fn network_endpoints(&self) -> impl Iterator<Item = NetworkEndpoint> + Send + use<> {
292 self.element()
293 .get_sub_element(ElementName::NetworkEndpoints)
294 .into_iter()
295 .flat_map(|ne| ne.sub_elements())
296 .filter_map(|ne_elem| NetworkEndpoint::try_from(ne_elem).ok())
297 }
298
299 pub fn create_socket_address(
340 &self,
341 name: &str,
342 network_endpoint: &NetworkEndpoint,
343 tp_config: &TpConfig,
344 sa_type: SocketAddressType,
345 ) -> Result<SocketAddress, AutosarAbstractionError> {
346 SocketAddress::new(name, self, network_endpoint, tp_config, sa_type)
347 }
348
349 pub fn socket_addresses(&self) -> impl Iterator<Item = SocketAddress> + Send + use<> {
383 self.element()
384 .get_sub_element(ElementName::SoAdConfig)
385 .and_then(|sc| sc.get_sub_element(ElementName::SocketAddresss))
386 .into_iter()
387 .flat_map(|sa| sa.sub_elements())
388 .filter_map(|sa_elem| SocketAddress::try_from(sa_elem).ok())
389 }
390
391 pub fn create_socket_connection_bundle(
422 &self,
423 name: &str,
424 server_port: &SocketAddress,
425 ) -> Result<SocketConnectionBundle, AutosarAbstractionError> {
426 let soadcfg = self.0.get_or_create_sub_element(ElementName::SoAdConfig)?;
427 let connections = soadcfg.get_or_create_sub_element(ElementName::ConnectionBundles)?;
428
429 SocketConnectionBundle::new(name, server_port, &connections)
430 }
431
432 pub fn socket_connection_bundles(&self) -> impl Iterator<Item = SocketConnectionBundle> + Send + use<> {
437 self.element()
438 .get_sub_element(ElementName::SoAdConfig)
439 .and_then(|sc| sc.get_sub_element(ElementName::ConnectionBundles))
440 .into_iter()
441 .flat_map(|cb| cb.sub_elements())
442 .filter_map(|cb_elem| SocketConnectionBundle::try_from(cb_elem).ok())
443 }
444
445 pub fn create_static_socket_connection_pair(
488 &self,
489 name: &str,
490 port_1: &SocketAddress,
491 port_2: &SocketAddress,
492 tcp_connect_timeout: Option<f64>,
493 ) -> Result<(StaticSocketConnection, StaticSocketConnection), AutosarAbstractionError> {
494 let ssc1 = port_1.create_static_socket_connection(name, port_2, Some(TcpRole::Connect), tcp_connect_timeout)?;
495 let ssc2 = port_2.create_static_socket_connection(name, port_1, Some(TcpRole::Listen), tcp_connect_timeout)?;
496 Ok((ssc1, ssc2))
497 }
498
499 pub fn configure_service_discovery_for_ecu(
582 &self,
583 ecu: &EcuInstance,
584 unicast_socket: &SocketAddress,
585 unicast_rx_pdu: &GeneralPurposePdu,
586 unicast_tx_pdu: &GeneralPurposePdu,
587 common_config: &CommonServiceDiscoveryConfig,
588 ) -> Result<(), AutosarAbstractionError> {
589 let version = self.0.min_version()?;
590
591 if self.ecu_connector(ecu).is_none() {
593 return Err(AutosarAbstractionError::InvalidParameter(
594 "The ECU must be connected to the channel".to_string(),
595 ));
596 };
597
598 let use_scb = version < AutosarVersion::Autosar_00048
601 || self.has_socket_connections()
602 || !common_config.prefer_static_socket_connections;
603
604 if unicast_socket.physical_channel()? != *self
606 || common_config.multicast_rx_socket.physical_channel()? != *self
607 || common_config.remote_socket.physical_channel()? != *self
608 {
609 return Err(AutosarAbstractionError::InvalidParameter(
610 "All sockets must be part of the channel".to_string(),
611 ));
612 }
613
614 match unicast_socket.socket_address_type() {
616 Some(SocketAddressType::Unicast(opt_socket_ecu)) => {
617 if let Some(socket_ecu) = opt_socket_ecu {
618 if &socket_ecu != ecu {
619 return Err(AutosarAbstractionError::InvalidParameter(
620 "The unicast socket belongs to a different ECU".to_string(),
621 ));
622 }
623 }
624 }
625 None => {
626 unicast_socket.set_unicast_ecu(ecu)?;
628 }
629 _ => {
630 return Err(AutosarAbstractionError::InvalidParameter(
631 "The unicast socket is not configured as Unicast".to_string(),
632 ));
633 }
634 }
635
636 match common_config.multicast_rx_socket.socket_address_type() {
639 Some(SocketAddressType::Multicast(_)) | None => {
640 common_config.multicast_rx_socket.add_multicast_ecu(ecu)?;
641 }
642 _ => {
643 return Err(AutosarAbstractionError::InvalidParameter(
644 "The multicast rx socket is not configured as Multicast".to_string(),
645 ));
646 }
647 }
648
649 let Some(TpConfig::UdpTp {
651 port_number: unicast_port,
652 ..
653 }) = unicast_socket.tp_config()
654 else {
655 return Err(AutosarAbstractionError::InvalidParameter(
656 "The unicast port must use UDP".to_string(),
657 ));
658 };
659 let Some(TpConfig::UdpTp {
660 port_number: multicast_rx_port,
661 ..
662 }) = common_config.multicast_rx_socket.tp_config()
663 else {
664 return Err(AutosarAbstractionError::InvalidParameter(
665 "The multicast rx port must use UDP".to_string(),
666 ));
667 };
668 let Some(TpConfig::UdpTp {
669 port_number: remote_port,
670 port_dynamically_assigned: remote_dynamically_assigned,
671 }) = common_config.remote_socket.tp_config()
672 else {
673 return Err(AutosarAbstractionError::InvalidParameter(
674 "The remote port must use UDP".to_string(),
675 ));
676 };
677 if unicast_port.is_none() || unicast_port != multicast_rx_port {
678 return Err(AutosarAbstractionError::InvalidParameter(
679 "All local UDP ports must use the same port number".to_string(),
680 ));
681 }
682 if remote_port != Some(0) && remote_dynamically_assigned != Some(true) {
685 return Err(AutosarAbstractionError::InvalidParameter(
686 "The remote UDP port must be 0 / dynamically assigned".to_string(),
687 ));
688 }
689
690 let Some(remote_network_endpoint) = common_config.remote_socket.network_endpoint() else {
692 return Err(AutosarAbstractionError::InvalidParameter(
693 "The remote socket must have a network endpoint".to_string(),
694 ));
695 };
696 if !remote_network_endpoint.addresses().all(|neaddr| match neaddr {
697 NetworkEndpointAddress::IPv4 { address, .. } => address == Some("ANY".to_string()),
698 NetworkEndpointAddress::IPv6 { address, .. } => address == Some("ANY".to_string()),
699 }) {
700 return Err(AutosarAbstractionError::InvalidParameter(
701 "The IP (v4/v6) address of the remote socket must be set to ANY".to_string(),
702 ));
703 }
704
705 if use_scb {
707 self.configure_sd_socket_connection_bundle(
708 ecu,
709 unicast_socket,
710 unicast_tx_pdu,
711 unicast_rx_pdu,
712 common_config,
713 )?;
714 } else {
715 self.configure_sd_static_socket_connection(
716 common_config,
717 unicast_socket,
718 unicast_rx_pdu,
719 ecu,
720 unicast_tx_pdu,
721 )?;
722 }
723
724 Ok(())
725 }
726
727 fn configure_sd_socket_connection_bundle(
729 &self,
730 ecu: &EcuInstance,
731 unicast_socket: &SocketAddress,
732 unicast_tx_pdu: &GeneralPurposePdu,
733 unicast_rx_pdu: &GeneralPurposePdu,
734 common_config: &CommonServiceDiscoveryConfig<'_>,
735 ) -> Result<(), AutosarAbstractionError> {
736 let name_prefix = common_config.name_prefix.unwrap_or("");
737 let ecu_name = ecu.name().unwrap_or("unnamed".to_string());
738
739 let connection_bundles = self
740 .element()
741 .get_or_create_sub_element(ElementName::SoAdConfig)?
742 .get_or_create_sub_element(ElementName::ConnectionBundles)?;
743
744 let scb_unicast = self.socket_connection_bundles().find(|scb| {
746 scb.server_port().is_some_and(|sp| &sp == unicast_socket)
747 && scb.bundled_connections().any(|sc| {
748 sc.client_ip_addr_from_connection_request() == Some(true)
749 && sc.client_port().is_some_and(|cp| &cp == common_config.remote_socket)
750 && sc.pdu_triggerings().count() == 2
751 })
752 });
753
754 if scb_unicast.is_none() {
755 let scb_name = format!("{name_prefix}SD_Unicast_{ecu_name}");
757 let scb = SocketConnectionBundle::new(&scb_name, unicast_socket, &connection_bundles)?;
758 let conn = scb.create_bundled_connection(common_config.remote_socket)?;
759 conn.set_client_ip_addr_from_connection_request(Some(true))?;
760 conn.set_client_port_from_connection_request(Some(true))?;
761 let (_, pt_tx) = conn.create_socket_connection_ipdu_identifier(
762 unicast_tx_pdu,
763 SocketConnection::SD_HEADER_ID,
764 None,
765 Some(PduCollectionTrigger::Always),
766 )?;
767 let (_, pt_rx) = conn.create_socket_connection_ipdu_identifier(
768 unicast_rx_pdu,
769 SocketConnection::SD_HEADER_ID,
770 None,
771 Some(PduCollectionTrigger::Always),
772 )?;
773 pt_tx.create_pdu_port(ecu, CommunicationDirection::Out)?;
774 pt_rx.create_pdu_port(ecu, CommunicationDirection::In)?;
775 }
776
777 let scb_multicast_opt = self.socket_connection_bundles().find(|scb| {
779 scb.server_port()
780 .is_some_and(|sp| &sp == common_config.multicast_rx_socket)
781 && scb.bundled_connections().any(|sc| {
782 sc.client_ip_addr_from_connection_request() == Some(true)
783 && sc.client_port().is_some_and(|cp| &cp == common_config.remote_socket)
784 && sc.pdu_triggerings().count() == 1
785 })
786 });
787
788 let scb_multicast_pt = if let Some(pt) = scb_multicast_opt
789 .and_then(|scb| scb.bundled_connections().next())
790 .and_then(|sc| sc.pdu_triggerings().next())
791 {
792 pt
794 } else {
795 let scb_name = format!("{name_prefix}SD_Multicast_Rx");
797 let scb = SocketConnectionBundle::new(&scb_name, common_config.multicast_rx_socket, &connection_bundles)?;
798 let conn = scb.create_bundled_connection(common_config.remote_socket)?;
799 conn.set_client_ip_addr_from_connection_request(Some(true))?;
800 conn.set_client_port_from_connection_request(Some(true))?;
801 let (_, pt) = conn.create_socket_connection_ipdu_identifier(
803 common_config.multicast_rx_pdu,
804 SocketConnection::SD_HEADER_ID,
805 None,
806 Some(PduCollectionTrigger::Always),
807 )?;
808 pt
809 };
810 scb_multicast_pt.create_pdu_port(ecu, CommunicationDirection::In)?;
812
813 Ok(())
814 }
815
816 fn configure_sd_static_socket_connection(
818 &self,
819 common_config: &CommonServiceDiscoveryConfig<'_>,
820 unicast_socket: &SocketAddress,
821 unicast_rx_pdu: &GeneralPurposePdu,
822 ecu: &EcuInstance,
823 unicast_tx_pdu: &GeneralPurposePdu,
824 ) -> Result<(), AutosarAbstractionError> {
825 let name_prefix = common_config.name_prefix.unwrap_or("");
826 let ecu_name = ecu.name().unwrap_or("unnamed".to_string());
827
828 let Some(ipdu_identifier_set) = common_config.ipdu_identifier_set else {
829 return Err(AutosarAbstractionError::InvalidParameter(
830 "An IPduIdentifierSet is required for StaticSocketConnections".to_string(),
831 ));
832 };
833 let ssc_unicast = unicast_socket.static_socket_connections().find(|ssc| {
834 ssc.remote_socket().is_some_and(|rs| &rs == common_config.remote_socket)
835 && ssc.ipdu_identifiers().count() == 2
836 });
837
838 if ssc_unicast.is_none() {
839 let name = format!("{name_prefix}SD_Unicast_{ecu_name}");
841 let ssc = unicast_socket.create_static_socket_connection(&name, common_config.remote_socket, None, None)?;
842 let name = format!("{name_prefix}SD_Unicast_Rx_{ecu_name}");
844 let idpu_identifier_rx = ipdu_identifier_set.create_socon_ipdu_identifier(
845 &name,
846 unicast_rx_pdu,
847 self,
848 Some(SoConIPduIdentifier::SD_HEADER_ID),
849 None,
850 Some(PduCollectionTrigger::Always),
851 )?;
852 idpu_identifier_rx
854 .pdu_triggering()
855 .unwrap()
856 .create_pdu_port(ecu, CommunicationDirection::In)?;
857 let name = format!("{name_prefix}SD_Unicast_Tx_{ecu_name}");
859 let idpu_identifier_tx = ipdu_identifier_set.create_socon_ipdu_identifier(
860 &name,
861 unicast_tx_pdu,
862 self,
863 Some(SoConIPduIdentifier::SD_HEADER_ID),
864 None,
865 Some(PduCollectionTrigger::Always),
866 )?;
867 idpu_identifier_tx
869 .pdu_triggering()
870 .unwrap()
871 .create_pdu_port(ecu, CommunicationDirection::Out)?;
872 ssc.add_ipdu_identifier(&idpu_identifier_rx)?;
873 ssc.add_ipdu_identifier(&idpu_identifier_tx)?;
874 }
875
876 let ssc_multicast = common_config
878 .multicast_rx_socket
879 .static_socket_connections()
880 .find(|ssc| {
881 ssc.remote_socket().is_some_and(|rs| &rs == common_config.remote_socket)
882 && ssc.ipdu_identifiers().count() == 1
883 });
884
885 let pt_multicast_rx = if let Some(pt) = ssc_multicast
886 .and_then(|ssc| ssc.ipdu_identifiers().next())
887 .and_then(|ipi| ipi.pdu_triggering())
888 {
889 pt
891 } else {
892 let name = format!("{name_prefix}SD_Multicast_Rx");
894 let ssc = common_config.multicast_rx_socket.create_static_socket_connection(
895 &name,
896 common_config.remote_socket,
897 None,
898 None,
899 )?;
900 let idpu_identifier_mc_rx = ipdu_identifier_set.create_socon_ipdu_identifier(
901 &name,
902 common_config.multicast_rx_pdu,
903 self,
904 Some(SoConIPduIdentifier::SD_HEADER_ID),
905 None,
906 Some(PduCollectionTrigger::Always),
907 )?;
908 let pt = idpu_identifier_mc_rx.pdu_triggering().unwrap();
909 ssc.add_ipdu_identifier(&idpu_identifier_mc_rx)?;
910 pt
911 };
912 pt_multicast_rx.create_pdu_port(ecu, CommunicationDirection::In)?;
914 Ok(())
915 }
916
917 #[must_use]
919 pub fn has_socket_connections(&self) -> bool {
920 if let Some(soad_config) = self.element().get_sub_element(ElementName::SoAdConfig) {
921 if let Some(connection_bundles) = soad_config.get_sub_element(ElementName::ConnectionBundles) {
922 if connection_bundles.sub_elements().count() > 0 {
924 return true;
925 }
926 }
927 if let Some(connections) = soad_config.get_sub_element(ElementName::Connections) {
928 return connections.sub_elements().count() > 0;
930 }
931 }
932 false
933 }
934}
935
936impl From<EthernetPhysicalChannel> for PhysicalChannel {
937 fn from(channel: EthernetPhysicalChannel) -> Self {
938 PhysicalChannel::Ethernet(channel)
939 }
940}
941
942impl AbstractPhysicalChannel for EthernetPhysicalChannel {
943 type CommunicationConnectorType = EthernetCommunicationConnector;
944}
945
946pub struct CommonServiceDiscoveryConfig<'a> {
952 pub multicast_rx_socket: &'a SocketAddress,
954 pub multicast_rx_pdu: &'a GeneralPurposePdu,
956 pub remote_socket: &'a SocketAddress,
958 pub prefer_static_socket_connections: bool,
961 pub ipdu_identifier_set: Option<&'a SocketConnectionIpduIdentifierSet>,
963 pub name_prefix: Option<&'a str>,
965}
966
967#[derive(Debug, Clone, PartialEq, Eq, Hash)]
973pub struct StaticSocketConnection(Element);
974abstraction_element!(StaticSocketConnection, StaticSocketConnection);
975impl IdentifiableAbstractionElement for StaticSocketConnection {}
976
977impl StaticSocketConnection {
978 pub(crate) fn new(
979 name: &str,
980 parent: &Element,
981 remote_address: &SocketAddress,
982 tcp_role: Option<TcpRole>,
983 tcp_connect_timeout: Option<f64>,
984 ) -> Result<Self, AutosarAbstractionError> {
985 let connections = parent.get_or_create_sub_element(ElementName::StaticSocketConnections)?;
986 let ssc_elem = connections.create_named_sub_element(ElementName::StaticSocketConnection, name)?;
987
988 let ssc = Self(ssc_elem);
989
990 ssc.set_remote_socket(remote_address)?;
991 ssc.set_tcp_role(tcp_role)?;
992 ssc.set_tcp_connect_timeout(tcp_connect_timeout)?;
993
994 Ok(ssc)
995 }
996
997 pub fn socket_address(&self) -> Result<SocketAddress, AutosarAbstractionError> {
999 let sa = self.element().named_parent()?.unwrap();
1000 SocketAddress::try_from(sa)
1001 }
1002
1003 pub fn set_remote_socket(&self, remote_socket: &SocketAddress) -> Result<(), AutosarAbstractionError> {
1005 self.element()
1006 .get_or_create_sub_element(ElementName::RemoteAddresss)?
1007 .get_or_create_sub_element(ElementName::SocketAddressRefConditional)?
1008 .get_or_create_sub_element(ElementName::SocketAddressRef)?
1009 .set_reference_target(remote_socket.element())?;
1010 Ok(())
1011 }
1012
1013 #[must_use]
1015 pub fn remote_socket(&self) -> Option<SocketAddress> {
1016 let remote_socket = self
1017 .element()
1018 .get_sub_element(ElementName::RemoteAddresss)?
1019 .get_sub_element(ElementName::SocketAddressRefConditional)?
1020 .get_sub_element(ElementName::SocketAddressRef)?
1021 .get_reference_target()
1022 .ok()?;
1023 SocketAddress::try_from(remote_socket).ok()
1024 }
1025
1026 pub fn add_ipdu_identifier(&self, identifier: &SoConIPduIdentifier) -> Result<(), AutosarAbstractionError> {
1028 let ipdu_identifiers = self.element().get_or_create_sub_element(ElementName::IPduIdentifiers)?;
1029 let scii = ipdu_identifiers
1030 .create_sub_element(ElementName::SoConIPduIdentifierRefConditional)?
1031 .create_sub_element(ElementName::SoConIPduIdentifierRef)?;
1032 scii.set_reference_target(identifier.element())?;
1033 Ok(())
1034 }
1035
1036 pub fn ipdu_identifiers(&self) -> impl Iterator<Item = SoConIPduIdentifier> + Send + use<> {
1038 self.element()
1039 .get_sub_element(ElementName::IPduIdentifiers)
1040 .into_iter()
1041 .flat_map(|elem| elem.sub_elements())
1042 .filter_map(|scirc: Element| {
1043 scirc
1044 .get_sub_element(ElementName::SoConIPduIdentifierRef)
1045 .and_then(|sciir| sciir.get_reference_target().ok())
1046 .and_then(|scii| SoConIPduIdentifier::try_from(scii).ok())
1047 })
1048 }
1049
1050 pub fn set_tcp_role(&self, role: Option<TcpRole>) -> Result<(), AutosarAbstractionError> {
1052 if let Some(role) = role {
1053 self.element()
1054 .get_or_create_sub_element(ElementName::TcpRole)?
1055 .set_character_data::<EnumItem>(role.into())?;
1056 } else {
1057 let _ = self.element().remove_sub_element_kind(ElementName::TcpRole);
1058 }
1059 Ok(())
1060 }
1061
1062 #[must_use]
1064 pub fn tcp_role(&self) -> Option<TcpRole> {
1065 self.element()
1066 .get_sub_element(ElementName::TcpRole)
1067 .and_then(|elem| elem.character_data())
1068 .and_then(|cdata| cdata.enum_value())
1069 .and_then(|enumitem| enumitem.try_into().ok())
1070 }
1071
1072 pub fn set_tcp_connect_timeout(&self, timeout: Option<f64>) -> Result<(), AutosarAbstractionError> {
1074 if let Some(timeout) = timeout {
1075 self.element()
1076 .get_or_create_sub_element(ElementName::TcpConnectTimeout)?
1077 .set_character_data(timeout)?;
1078 } else {
1079 let _ = self.element().remove_sub_element_kind(ElementName::TcpConnectTimeout);
1080 }
1081 Ok(())
1082 }
1083
1084 #[must_use]
1086 pub fn tcp_connect_timeout(&self) -> Option<f64> {
1087 self.element()
1088 .get_sub_element(ElementName::TcpConnectTimeout)
1089 .and_then(|elem| elem.character_data())
1090 .and_then(|cdata| cdata.parse_float())
1091 }
1092}
1093
1094#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1098pub struct SocketConnectionIpduIdentifierSet(Element);
1099abstraction_element!(SocketConnectionIpduIdentifierSet, SocketConnectionIpduIdentifierSet);
1100impl IdentifiableAbstractionElement for SocketConnectionIpduIdentifierSet {}
1101
1102impl SocketConnectionIpduIdentifierSet {
1103 pub(crate) fn new(name: &str, package: &ArPackage) -> Result<Self, AutosarAbstractionError> {
1108 let sci = package
1109 .element()
1110 .get_or_create_sub_element(ElementName::Elements)?
1111 .create_named_sub_element(ElementName::SocketConnectionIpduIdentifierSet, name)?;
1112 Ok(Self(sci))
1113 }
1114
1115 pub fn create_socon_ipdu_identifier<T: AbstractPdu>(
1117 &self,
1118 name: &str,
1119 pdu: &T,
1120 channel: &EthernetPhysicalChannel,
1121 header_id: Option<u64>,
1122 timeout: Option<f64>,
1123 collection_trigger: Option<PduCollectionTrigger>,
1124 ) -> Result<SoConIPduIdentifier, AutosarAbstractionError> {
1125 let ipdu_identifiers = self.element().get_or_create_sub_element(ElementName::IPduIdentifiers)?;
1126 SoConIPduIdentifier::new(
1127 name,
1128 &ipdu_identifiers,
1129 &pdu.clone().into(),
1130 channel,
1131 header_id,
1132 timeout,
1133 collection_trigger,
1134 )
1135 }
1136
1137 pub fn socon_ipdu_identifiers(&self) -> impl Iterator<Item = SoConIPduIdentifier> + Send + use<> {
1139 self.element()
1140 .get_sub_element(ElementName::IPduIdentifiers)
1141 .into_iter()
1142 .flat_map(|elem| elem.sub_elements())
1143 .filter_map(|elem| SoConIPduIdentifier::try_from(elem).ok())
1144 }
1145}
1146
1147#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1151pub struct SoConIPduIdentifier(Element);
1152abstraction_element!(SoConIPduIdentifier, SoConIPduIdentifier);
1153impl IdentifiableAbstractionElement for SoConIPduIdentifier {}
1154
1155impl SoConIPduIdentifier {
1156 pub const SD_HEADER_ID: u64 = 0xFFFF_8100;
1158
1159 pub(crate) fn new(
1161 name: &str,
1162 parent: &Element,
1163 pdu: &Pdu,
1164 channel: &EthernetPhysicalChannel,
1165 header_id: Option<u64>,
1166 timeout: Option<f64>,
1167 collection_trigger: Option<PduCollectionTrigger>,
1168 ) -> Result<Self, AutosarAbstractionError> {
1169 let scii = Self(parent.create_named_sub_element(ElementName::SoConIPduIdentifier, name)?);
1170 scii.set_pdu_internal(pdu, channel)?;
1171
1172 if let Some(header_id) = header_id {
1173 scii.set_header_id(header_id)?;
1174 }
1175 if let Some(timeout) = timeout {
1176 scii.set_timeout(timeout)?;
1177 }
1178 if let Some(collection_trigger) = collection_trigger {
1179 scii.set_collection_trigger(collection_trigger)?;
1180 }
1181 Ok(scii)
1182 }
1183
1184 pub fn set_pdu<T: AbstractPdu>(
1186 &self,
1187 pdu: &T,
1188 channel: &EthernetPhysicalChannel,
1189 ) -> Result<(), AutosarAbstractionError> {
1190 let pdu: Pdu = pdu.clone().into();
1191 self.set_pdu_internal(&pdu, channel)
1192 }
1193
1194 fn set_pdu_internal(&self, pdu: &Pdu, channel: &EthernetPhysicalChannel) -> Result<(), AutosarAbstractionError> {
1195 if let Some(pt_old) = self
1196 .element()
1197 .get_sub_element(ElementName::PduTriggeringRef)
1198 .and_then(|pt| pt.get_reference_target().ok())
1199 {
1200 let pt_old = PduTriggering::try_from(pt_old)?;
1201 if let Some(old_pdu) = pt_old.pdu() {
1202 if old_pdu == *pdu {
1203 return Ok(());
1204 }
1205 channel
1208 .element()
1209 .get_sub_element(ElementName::PduTriggerings)
1210 .and_then(|pts| pts.remove_sub_element(pt_old.element().clone()).ok());
1211 }
1212 }
1213 let pt_new = PduTriggering::new(pdu, &PhysicalChannel::Ethernet(channel.clone()))?;
1214 self.element()
1215 .get_or_create_sub_element(ElementName::PduTriggeringRef)?
1216 .set_reference_target(pt_new.element())?;
1217 Ok(())
1218 }
1219
1220 pub fn set_header_id(&self, header_id: u64) -> Result<(), AutosarAbstractionError> {
1222 self.element()
1223 .get_or_create_sub_element(ElementName::HeaderId)?
1224 .set_character_data(header_id)?;
1225 Ok(())
1226 }
1227
1228 pub fn set_timeout(&self, timeout: f64) -> Result<(), AutosarAbstractionError> {
1230 self.element()
1231 .get_or_create_sub_element(ElementName::PduCollectionPduTimeout)?
1232 .set_character_data(timeout)?;
1233 Ok(())
1234 }
1235
1236 pub fn set_collection_trigger(&self, trigger: PduCollectionTrigger) -> Result<(), AutosarAbstractionError> {
1238 self.element()
1239 .get_or_create_sub_element(ElementName::PduCollectionTrigger)?
1240 .set_character_data::<EnumItem>(trigger.into())?;
1241 Ok(())
1242 }
1243
1244 #[must_use]
1246 pub fn pdu_triggering(&self) -> Option<PduTriggering> {
1247 let pt = self
1248 .element()
1249 .get_sub_element(ElementName::PduTriggeringRef)?
1250 .get_reference_target()
1251 .ok()?;
1252 PduTriggering::try_from(pt).ok()
1253 }
1254
1255 #[must_use]
1257 pub fn header_id(&self) -> Option<u64> {
1258 self.element()
1259 .get_sub_element(ElementName::HeaderId)?
1260 .character_data()?
1261 .parse_integer()
1262 }
1263
1264 #[must_use]
1266 pub fn timeout(&self) -> Option<f64> {
1267 self.element()
1268 .get_sub_element(ElementName::PduCollectionPduTimeout)?
1269 .character_data()?
1270 .float_value()
1271 }
1272
1273 #[must_use]
1275 pub fn collection_trigger(&self) -> Option<PduCollectionTrigger> {
1276 self.element()
1277 .get_sub_element(ElementName::PduCollectionTrigger)?
1278 .character_data()?
1279 .enum_value()?
1280 .try_into()
1281 .ok()
1282 }
1283}
1284
1285#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1289pub enum TcpRole {
1290 Connect,
1292 Listen,
1294}
1295
1296impl TryFrom<EnumItem> for TcpRole {
1297 type Error = AutosarAbstractionError;
1298
1299 fn try_from(value: EnumItem) -> Result<Self, Self::Error> {
1300 match value {
1301 EnumItem::Listen => Ok(Self::Listen),
1302 EnumItem::Connect => Ok(Self::Connect),
1303
1304 _ => Err(AutosarAbstractionError::ValueConversionError {
1305 value: value.to_string(),
1306 dest: "TcpRole".to_string(),
1307 }),
1308 }
1309 }
1310}
1311
1312impl From<TcpRole> for EnumItem {
1313 fn from(value: TcpRole) -> Self {
1314 match value {
1315 TcpRole::Listen => EnumItem::Listen,
1316 TcpRole::Connect => EnumItem::Connect,
1317 }
1318 }
1319}
1320
1321#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1325pub enum EventGroupControlType {
1326 ActivationAndTriggerUnicast,
1328 ActivationMulticast,
1330 ActivationUnicast,
1332 TriggerUnicast,
1334}
1335
1336impl From<EventGroupControlType> for EnumItem {
1337 fn from(value: EventGroupControlType) -> Self {
1338 match value {
1339 EventGroupControlType::ActivationAndTriggerUnicast => EnumItem::ActivationAndTriggerUnicast,
1340 EventGroupControlType::ActivationMulticast => EnumItem::ActivationMulticast,
1341 EventGroupControlType::ActivationUnicast => EnumItem::ActivationUnicast,
1342 EventGroupControlType::TriggerUnicast => EnumItem::TriggerUnicast,
1343 }
1344 }
1345}
1346
1347impl TryFrom<EnumItem> for EventGroupControlType {
1348 type Error = AutosarAbstractionError;
1349
1350 fn try_from(value: EnumItem) -> Result<Self, Self::Error> {
1351 match value {
1352 EnumItem::ActivationAndTriggerUnicast => Ok(Self::ActivationAndTriggerUnicast),
1353 EnumItem::ActivationMulticast => Ok(Self::ActivationMulticast),
1354 EnumItem::ActivationUnicast => Ok(Self::ActivationUnicast),
1355 EnumItem::TriggerUnicast => Ok(Self::TriggerUnicast),
1356
1357 _ => Err(AutosarAbstractionError::ValueConversionError {
1358 value: value.to_string(),
1359 dest: "EventGroupControlType".to_string(),
1360 }),
1361 }
1362 }
1363}
1364
1365#[cfg(test)]
1368mod test {
1369 use super::*;
1370 use crate::{ArPackage, AutosarModelAbstraction, System, SystemCategory, communication::GeneralPurposePduCategory};
1371 use autosar_data::AutosarVersion;
1372
1373 #[test]
1374 fn channel_basic() {
1375 let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00044);
1376 let pkg = model.get_or_create_package("/test").unwrap();
1377 let system = pkg.create_system("System", SystemCategory::SystemDescription).unwrap();
1378 let cluster = system.create_ethernet_cluster("EthCluster", &pkg).unwrap();
1379 let channel = cluster.create_physical_channel("Channel", None).unwrap();
1380
1381 let wrapped_channel: PhysicalChannel = channel.clone().into();
1382 assert_eq!(wrapped_channel, PhysicalChannel::Ethernet(channel));
1383 }
1384
1385 #[test]
1386 fn channel_network_endpoint() {
1387 let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00044);
1389 let pkg = model.get_or_create_package("/test").unwrap();
1390 let system = pkg.create_system("System", SystemCategory::SystemDescription).unwrap();
1391 let cluster = system.create_ethernet_cluster("EthCluster", &pkg).unwrap();
1392 let channel = cluster.create_physical_channel("Channel", None).unwrap();
1393
1394 let endpoint = channel
1396 .create_network_endpoint(
1397 "Endpoint",
1398 NetworkEndpointAddress::IPv4 {
1399 address: Some("192.168.0.1".to_string()),
1400 address_source: None,
1401 default_gateway: None,
1402 network_mask: None,
1403 },
1404 None,
1405 )
1406 .unwrap();
1407 assert_eq!(channel.network_endpoints().next().unwrap(), endpoint);
1408
1409 let ecu = system.create_ecu_instance("ECU", &pkg).unwrap();
1413 let result = channel.create_network_endpoint(
1414 "Endpoint1",
1415 NetworkEndpointAddress::IPv4 {
1416 address: Some("192.168.0.2".to_string()),
1417 address_source: None,
1418 default_gateway: None,
1419 network_mask: None,
1420 },
1421 Some(&ecu),
1422 );
1423 assert!(result.is_err());
1424 assert_eq!(channel.network_endpoints().next().unwrap(), endpoint);
1425
1426 let ethernet_controller = ecu
1428 .create_ethernet_communication_controller("Controller", Some("01:23:45:ab:cd:ef".to_string()))
1429 .unwrap();
1430 ethernet_controller
1431 .connect_physical_channel("connection", &channel)
1432 .unwrap();
1433 let endpoint = channel
1434 .create_network_endpoint(
1435 "Endpoint2",
1436 NetworkEndpointAddress::IPv4 {
1437 address: Some("192.168.0.2".to_string()),
1438 address_source: None,
1439 default_gateway: None,
1440 network_mask: None,
1441 },
1442 Some(&ecu),
1443 )
1444 .unwrap();
1445 assert_eq!(channel.network_endpoints().last().unwrap(), endpoint);
1446 assert_eq!(channel.network_endpoints().count(), 2);
1447 }
1448
1449 #[test]
1450 fn channel_vlan() {
1451 let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
1452 let pkg = model.get_or_create_package("/test").unwrap();
1453 let system = pkg.create_system("System", SystemCategory::SystemDescription).unwrap();
1454 let cluster = system.create_ethernet_cluster("EthCluster", &pkg).unwrap();
1455
1456 let channel = cluster.create_physical_channel("channel_name", None).unwrap();
1457 let c2 = channel.cluster().unwrap();
1458 assert_eq!(cluster, c2);
1459
1460 let vi = channel.vlan_info();
1461 assert!(vi.is_none());
1462
1463 let elem_vlan = channel
1464 .element()
1465 .create_named_sub_element(ElementName::Vlan, "VLAN_1")
1466 .unwrap();
1467 let vi = channel.vlan_info();
1468 assert!(vi.is_none());
1469
1470 let elem_vlanid = elem_vlan.create_sub_element(ElementName::VlanIdentifier).unwrap();
1471 let vi = channel.vlan_info();
1472 assert!(vi.is_none());
1473
1474 elem_vlanid.set_character_data(1).unwrap();
1475 let vi = channel.vlan_info().unwrap();
1476 assert_eq!(vi.vlan_id, 1);
1477 }
1478
1479 #[test]
1480 fn sd_configuration_old() {
1481 let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00044);
1483 let pkg = model.get_or_create_package("/test").unwrap();
1484 let system = pkg.create_system("System", SystemCategory::SystemDescription).unwrap();
1485 let cluster = system.create_ethernet_cluster("EthCluster", &pkg).unwrap();
1486 let channel = cluster.create_physical_channel("Channel", None).unwrap();
1487
1488 let ecu = system.create_ecu_instance("ECU", &pkg).unwrap();
1489 let controller = ecu
1490 .create_ethernet_communication_controller("EthController", None)
1491 .unwrap();
1492 controller.connect_physical_channel("connection", &channel).unwrap();
1493
1494 let (
1495 unicast_socket,
1496 multicast_rx_socket,
1497 remote_anyaddr_socket,
1498 unicast_rx_pdu,
1499 unicast_tx_pdu,
1500 multicast_rx_pdu,
1501 ) = prepare_sd_config_items(&pkg, &system, &channel, &ecu);
1502
1503 let common_config = CommonServiceDiscoveryConfig {
1504 multicast_rx_socket: &multicast_rx_socket,
1505 multicast_rx_pdu: &multicast_rx_pdu,
1506 remote_socket: &remote_anyaddr_socket,
1507 name_prefix: None,
1508 prefer_static_socket_connections: false,
1509 ipdu_identifier_set: None,
1510 };
1511
1512 let result = channel.configure_service_discovery_for_ecu(
1513 &ecu,
1514 &unicast_socket,
1515 &unicast_rx_pdu,
1516 &unicast_tx_pdu,
1517 &common_config,
1518 );
1519 assert!(result.is_ok());
1520
1521 assert_eq!(channel.socket_connection_bundles().count(), 2);
1522 assert!(channel.socket_connection_bundles().any(|scb| {
1523 scb.server_port().is_some_and(|sp| sp == unicast_socket)
1524 && scb.bundled_connections().any(|sc| {
1525 sc.client_ip_addr_from_connection_request() == Some(true)
1526 && sc.client_port().is_some_and(|cp| &cp == common_config.remote_socket)
1527 && sc.pdu_triggerings().count() == 2
1528 })
1529 }));
1530 assert!(channel.socket_connection_bundles().any(|scb| {
1531 scb.server_port()
1532 .is_some_and(|sp| &sp == common_config.multicast_rx_socket)
1533 && scb.bundled_connections().any(|sc| {
1534 sc.client_ip_addr_from_connection_request() == Some(true)
1535 && sc.client_port().is_some_and(|cp| &cp == common_config.remote_socket)
1536 && sc.pdu_triggerings().count() == 1
1537 })
1538 }));
1539
1540 let result = channel.configure_service_discovery_for_ecu(
1542 &ecu,
1543 &unicast_socket,
1544 &unicast_rx_pdu,
1545 &unicast_tx_pdu,
1546 &common_config,
1547 );
1548 assert!(result.is_ok());
1549 assert_eq!(channel.socket_connection_bundles().count(), 2);
1550 }
1551
1552 #[test]
1553 fn sd_configuration_new() {
1554 let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00053);
1555 let pkg = model.get_or_create_package("/test").unwrap();
1556 let system = pkg.create_system("System", SystemCategory::SystemDescription).unwrap();
1557 let cluster = system.create_ethernet_cluster("EthCluster", &pkg).unwrap();
1558 let channel = cluster.create_physical_channel("Channel", None).unwrap();
1559
1560 let ecu = system.create_ecu_instance("ECU", &pkg).unwrap();
1561 let controller = ecu
1562 .create_ethernet_communication_controller("EthController", None)
1563 .unwrap();
1564 controller.connect_physical_channel("connection", &channel).unwrap();
1565
1566 let (
1567 unicast_socket,
1568 multicast_rx_socket,
1569 remote_anyaddr_socket,
1570 unicast_rx_pdu,
1571 unicast_tx_pdu,
1572 multicast_rx_pdu,
1573 ) = prepare_sd_config_items(&pkg, &system, &channel, &ecu);
1574 let ipdu_identifier_set = system
1575 .create_socket_connection_ipdu_identifier_set("IpduIdentifierSet", &pkg)
1576 .unwrap();
1577
1578 let common_config = CommonServiceDiscoveryConfig {
1579 multicast_rx_socket: &multicast_rx_socket,
1580 multicast_rx_pdu: &multicast_rx_pdu,
1581 remote_socket: &remote_anyaddr_socket,
1582 name_prefix: None,
1583 prefer_static_socket_connections: true,
1584 ipdu_identifier_set: Some(&ipdu_identifier_set),
1585 };
1586
1587 let result = channel.configure_service_discovery_for_ecu(
1588 &ecu,
1589 &unicast_socket,
1590 &unicast_rx_pdu,
1591 &unicast_tx_pdu,
1592 &common_config,
1593 );
1594 assert!(result.is_ok());
1595
1596 assert!(unicast_socket.static_socket_connections().count() == 1);
1598 assert!(unicast_socket.static_socket_connections().any(|ssc| {
1599 ssc.remote_socket().is_some_and(|rs| &rs == common_config.remote_socket)
1600 && ssc.ipdu_identifiers().count() == 2
1601 }));
1602
1603 assert!(multicast_rx_socket.static_socket_connections().count() == 1);
1604 assert!(multicast_rx_socket.static_socket_connections().any(|ssc| {
1605 ssc.remote_socket().is_some_and(|rs| &rs == common_config.remote_socket)
1606 && ssc.ipdu_identifiers().count() == 1
1607 }));
1608
1609 let result = channel.configure_service_discovery_for_ecu(
1611 &ecu,
1612 &unicast_socket,
1613 &unicast_rx_pdu,
1614 &unicast_tx_pdu,
1615 &common_config,
1616 );
1617 assert!(result.is_ok());
1618
1619 assert!(unicast_socket.static_socket_connections().count() == 1);
1620 assert!(multicast_rx_socket.static_socket_connections().count() == 1);
1621 }
1622
1623 fn prepare_sd_config_items(
1624 pkg: &ArPackage,
1625 system: &System,
1626 channel: &EthernetPhysicalChannel,
1627 ecu: &EcuInstance,
1628 ) -> (
1629 SocketAddress,
1630 SocketAddress,
1631 SocketAddress,
1632 GeneralPurposePdu,
1633 GeneralPurposePdu,
1634 GeneralPurposePdu,
1635 ) {
1636 let network_address = NetworkEndpointAddress::IPv4 {
1637 address: Some("192.168.0.1".to_string()),
1638 address_source: Some(IPv4AddressSource::Fixed),
1639 default_gateway: Some("192.168.0.200".to_string()),
1640 network_mask: Some("255.255.255.0".to_string()),
1641 };
1642 let network_endpoint = channel
1643 .create_network_endpoint("local_endpoint", network_address, None)
1644 .unwrap();
1645 let unicast_socket = channel
1646 .create_socket_address(
1647 "UnicastSocket",
1648 &network_endpoint,
1649 &TpConfig::UdpTp {
1650 port_number: Some(30490),
1651 port_dynamically_assigned: None,
1652 },
1653 SocketAddressType::Unicast(Some(ecu.clone())),
1654 )
1655 .unwrap();
1656 let multicast_rx_endpoint = channel
1657 .create_network_endpoint(
1658 "MulticastEndpoint",
1659 NetworkEndpointAddress::IPv4 {
1660 address: Some("239.0.0.1".to_string()),
1661 address_source: Some(IPv4AddressSource::Fixed),
1662 default_gateway: None,
1663 network_mask: None,
1664 },
1665 None,
1666 )
1667 .unwrap();
1668 let multicast_rx_socket = channel
1669 .create_socket_address(
1670 "MulticastSocket",
1671 &multicast_rx_endpoint,
1672 &TpConfig::UdpTp {
1673 port_number: Some(30490),
1674 port_dynamically_assigned: None,
1675 },
1676 SocketAddressType::Multicast(vec![ecu.clone()]),
1677 )
1678 .unwrap();
1679 let remote_anyaddr_endpoint = channel
1680 .create_network_endpoint(
1681 "RemoteEndpoint",
1682 NetworkEndpointAddress::IPv4 {
1683 address: Some("ANY".to_string()),
1684 address_source: None,
1685 default_gateway: None,
1686 network_mask: None,
1687 },
1688 None,
1689 )
1690 .unwrap();
1691 let remote_anyaddr_socket = channel
1692 .create_socket_address(
1693 "RemoteSocket",
1694 &remote_anyaddr_endpoint,
1695 &TpConfig::UdpTp {
1696 port_number: None,
1697 port_dynamically_assigned: Some(true),
1698 },
1699 SocketAddressType::Unicast(None),
1700 )
1701 .unwrap();
1702 let unicast_rx_pdu = system
1703 .create_general_purpose_pdu("UnicastRxPdu", pkg, 0, GeneralPurposePduCategory::Sd)
1704 .unwrap();
1705 let unicast_tx_pdu = system
1706 .create_general_purpose_pdu("UnicastTxPdu", pkg, 0, GeneralPurposePduCategory::Sd)
1707 .unwrap();
1708 let multicast_rx_pdu = system
1709 .create_general_purpose_pdu("MulticastRxPdu", pkg, 0, GeneralPurposePduCategory::Sd)
1710 .unwrap();
1711 (
1712 unicast_socket,
1713 multicast_rx_socket,
1714 remote_anyaddr_socket,
1715 unicast_rx_pdu,
1716 unicast_tx_pdu,
1717 multicast_rx_pdu,
1718 )
1719 }
1720
1721 #[test]
1722 fn socon_ipdu_identifier() {
1723 let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
1724 let pkg = model.get_or_create_package("/test").unwrap();
1725 let system = pkg.create_system("System", SystemCategory::SystemDescription).unwrap();
1726 let cluster = system.create_ethernet_cluster("EthCluster", &pkg).unwrap();
1727 let channel = cluster.create_physical_channel("Channel", None).unwrap();
1728 let ecu = system.create_ecu_instance("ECU", &pkg).unwrap();
1729 let ipdu_identifier_set = system
1730 .create_socket_connection_ipdu_identifier_set("IpduIdentifierSet", &pkg)
1731 .unwrap();
1732 let pdu = system
1733 .create_general_purpose_pdu("Pdu", &pkg, 1, GeneralPurposePduCategory::Sd)
1734 .unwrap();
1735 let pdu2 = system
1736 .create_general_purpose_pdu("Pdu2", &pkg, 2, GeneralPurposePduCategory::Sd)
1737 .unwrap();
1738 let controller = ecu
1739 .create_ethernet_communication_controller("Controller", Some("01:23:45:ab:cd:ef".to_string()))
1740 .unwrap();
1741 controller.connect_physical_channel("connection", &channel).unwrap();
1742
1743 let socon_ipdu_identifier = ipdu_identifier_set
1744 .create_socon_ipdu_identifier(
1745 "SoConIPduIdentifier",
1746 &pdu,
1747 &channel,
1748 Some(SoConIPduIdentifier::SD_HEADER_ID),
1749 Some(0.1),
1750 Some(PduCollectionTrigger::Always),
1751 )
1752 .unwrap();
1753 assert_eq!(
1754 socon_ipdu_identifier.pdu_triggering().unwrap().pdu().unwrap(),
1755 pdu.into()
1756 );
1757 assert_eq!(
1758 socon_ipdu_identifier.header_id().unwrap(),
1759 SoConIPduIdentifier::SD_HEADER_ID
1760 );
1761 assert_eq!(socon_ipdu_identifier.timeout().unwrap(), 0.1);
1762 assert_eq!(
1763 socon_ipdu_identifier.collection_trigger().unwrap(),
1764 PduCollectionTrigger::Always
1765 );
1766
1767 socon_ipdu_identifier.set_pdu(&pdu2, &channel).unwrap();
1768 assert_eq!(
1769 socon_ipdu_identifier.pdu_triggering().unwrap().pdu().unwrap(),
1770 pdu2.into()
1771 );
1772 socon_ipdu_identifier.set_timeout(0.2).unwrap();
1773 assert_eq!(socon_ipdu_identifier.timeout().unwrap(), 0.2);
1774 socon_ipdu_identifier
1775 .set_collection_trigger(PduCollectionTrigger::Never)
1776 .unwrap();
1777 assert_eq!(
1778 socon_ipdu_identifier.collection_trigger().unwrap(),
1779 PduCollectionTrigger::Never
1780 );
1781 socon_ipdu_identifier.set_header_id(0x1234).unwrap();
1782 assert_eq!(socon_ipdu_identifier.header_id().unwrap(), 0x1234);
1783 }
1784
1785 #[test]
1786 pub fn static_socket_connection() {
1787 let model = AutosarModelAbstraction::create("filename", AutosarVersion::LATEST);
1788 let pkg = model.get_or_create_package("/test").unwrap();
1789 let system = pkg.create_system("System", SystemCategory::SystemDescription).unwrap();
1790 let cluster = system.create_ethernet_cluster("EthCluster", &pkg).unwrap();
1791 let channel = cluster.create_physical_channel("Channel", None).unwrap();
1792
1793 let remote_address = NetworkEndpointAddress::IPv4 {
1795 address: Some("192.168.0.1".to_string()),
1796 address_source: Some(IPv4AddressSource::Fixed),
1797 default_gateway: None,
1798 network_mask: None,
1799 };
1800 let remote_endpoint = channel
1801 .create_network_endpoint("RemoteAddress", remote_address, None)
1802 .unwrap();
1803 let remote_socket = channel
1804 .create_socket_address(
1805 "RemoteSocket",
1806 &remote_endpoint,
1807 &TpConfig::UdpTp {
1808 port_number: Some(12345),
1809 port_dynamically_assigned: None,
1810 },
1811 SocketAddressType::Unicast(None),
1812 )
1813 .unwrap();
1814 let local_address = NetworkEndpointAddress::IPv4 {
1815 address: Some("192.168.0.2".to_string()),
1816 address_source: Some(IPv4AddressSource::Fixed),
1817 default_gateway: None,
1818 network_mask: None,
1819 };
1820 let local_endpoint = channel
1821 .create_network_endpoint("LocalAddress", local_address, None)
1822 .unwrap();
1823 let local_socket = channel
1824 .create_socket_address(
1825 "LocalSocket",
1826 &local_endpoint,
1827 &TpConfig::UdpTp {
1828 port_number: Some(12346),
1829 port_dynamically_assigned: None,
1830 },
1831 SocketAddressType::Unicast(None),
1832 )
1833 .unwrap();
1834 let ssc = local_socket
1835 .create_static_socket_connection("ssc", &remote_socket, None, None)
1836 .unwrap();
1837 assert_eq!(ssc.remote_socket().unwrap(), remote_socket);
1838 assert_eq!(ssc.tcp_role(), None);
1839 ssc.set_tcp_role(Some(TcpRole::Connect)).unwrap();
1840 assert_eq!(ssc.tcp_role().unwrap(), TcpRole::Connect);
1841 ssc.set_tcp_connect_timeout(Some(0.3333)).unwrap();
1842 assert_eq!(ssc.tcp_connect_timeout().unwrap(), 0.3333);
1843
1844 assert_eq!(ssc.ipdu_identifiers().count(), 0);
1846 let ipdu_identifier_set = system
1847 .create_socket_connection_ipdu_identifier_set("IpduIdentifierSet", &pkg)
1848 .unwrap();
1849 let pdu = GeneralPurposePdu::new("Pdu", &pkg, 0, GeneralPurposePduCategory::Sd).unwrap();
1850 let socon_ipdu_identifier = ipdu_identifier_set
1851 .create_socon_ipdu_identifier(
1852 "SoConIPduIdentifier",
1853 &pdu,
1854 &channel,
1855 Some(SoConIPduIdentifier::SD_HEADER_ID),
1856 Some(0.1),
1857 Some(PduCollectionTrigger::Always),
1858 )
1859 .unwrap();
1860 ssc.add_ipdu_identifier(&socon_ipdu_identifier).unwrap();
1861 assert_eq!(ssc.ipdu_identifiers().count(), 1);
1862 assert_eq!(ssc.ipdu_identifiers().next().unwrap(), socon_ipdu_identifier);
1863 assert_eq!(ssc.socket_address().unwrap(), local_socket);
1864 }
1865}