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 remove(self, deep: bool) -> Result<(), AutosarAbstractionError> {
392 let opt_pdu_triggering = self.pdu_triggering();
393
394 AbstractionElement::remove(self, deep)?;
395
396 if let Some(pt) = opt_pdu_triggering {
397 pt.remove(deep)?;
398 }
399
400 Ok(())
401 }
402
403 pub fn socket_connection(&self) -> Result<SocketConnection, AutosarAbstractionError> {
405 let socket_connection_elem = self.element().parent()?.unwrap().parent()?.unwrap();
407 SocketConnection::try_from(socket_connection_elem)
408 }
409
410 pub fn trigger_pdu(&self, pdu: &Pdu) -> Result<PduTriggering, AutosarAbstractionError> {
412 if let Some(old_pt) = self.pdu_triggering() {
413 old_pt.remove(false)?;
416 }
417 let channel = self
418 .socket_connection()?
419 .socket_connection_bundle()?
420 .physical_channel()?;
421 let pt = PduTriggering::new(pdu, &PhysicalChannel::Ethernet(channel))?;
422
423 self.element()
424 .get_or_create_sub_element(ElementName::PduTriggeringRef)?
425 .set_reference_target(pt.element())?;
426 Ok(pt)
427 }
428
429 #[must_use]
431 pub fn pdu_triggering(&self) -> Option<PduTriggering> {
432 self.element()
433 .get_sub_element(ElementName::PduTriggeringRef)
434 .and_then(|elem| elem.get_reference_target().ok())
435 .and_then(|pt| PduTriggering::try_from(pt).ok())
436 }
437
438 pub fn set_header_id(&self, header_id: u32) -> Result<(), AutosarAbstractionError> {
440 self.element()
441 .get_or_create_sub_element(ElementName::HeaderId)?
442 .set_character_data(header_id.to_string())?;
443 Ok(())
444 }
445
446 #[must_use]
448 pub fn header_id(&self) -> Option<u64> {
449 self.element()
450 .get_sub_element(ElementName::HeaderId)
451 .and_then(|elem| elem.character_data())
452 .and_then(|cdata| cdata.parse_integer())
453 }
454
455 pub fn set_timeout(&self, timeout: Option<f64>) -> Result<(), AutosarAbstractionError> {
457 if let Some(timeout) = timeout {
458 self.element()
459 .get_or_create_sub_element(ElementName::PduCollectionPduTimeout)?
460 .set_character_data(timeout)?;
461 } else {
462 let _ = self
463 .element()
464 .remove_sub_element_kind(ElementName::PduCollectionPduTimeout);
465 }
466 Ok(())
467 }
468
469 #[must_use]
471 pub fn timeout(&self) -> Option<f64> {
472 self.element()
473 .get_sub_element(ElementName::PduCollectionPduTimeout)
474 .and_then(|elem| elem.character_data())
475 .and_then(|cdata| cdata.float_value())
476 }
477
478 pub fn set_collection_trigger(&self, trigger: Option<PduCollectionTrigger>) -> Result<(), AutosarAbstractionError> {
480 if let Some(trigger) = trigger {
481 self.element()
482 .get_or_create_sub_element(ElementName::PduCollectionTrigger)?
483 .set_character_data::<EnumItem>(trigger.into())?;
484 } else {
485 let _ = self
486 .element()
487 .remove_sub_element_kind(ElementName::PduCollectionTrigger);
488 }
489 Ok(())
490 }
491
492 #[must_use]
494 pub fn collection_trigger(&self) -> Option<PduCollectionTrigger> {
495 self.element()
496 .get_sub_element(ElementName::PduCollectionTrigger)
497 .and_then(|elem| elem.character_data())
498 .and_then(|cdata| cdata.enum_value())
499 .and_then(|eval| eval.try_into().ok())
500 }
501
502 pub fn add_routing_group(&self, routing_group: &SoAdRoutingGroup) -> Result<(), AutosarAbstractionError> {
504 self.element()
505 .get_or_create_sub_element(ElementName::RoutingGroupRefs)?
506 .create_sub_element(ElementName::RoutingGroupRef)?
507 .set_reference_target(routing_group.element())?;
508 Ok(())
509 }
510
511 pub fn routing_groups(&self) -> impl Iterator<Item = SoAdRoutingGroup> + Send + use<> {
513 self.element()
514 .get_sub_element(ElementName::RoutingGroupRefs)
515 .into_iter()
516 .flat_map(|rgr| rgr.sub_elements())
517 .filter_map(|ref_elem| {
518 ref_elem
519 .get_reference_target()
520 .ok()
521 .and_then(|elem| SoAdRoutingGroup::try_from(elem).ok())
522 })
523 }
524}
525
526#[derive(Debug, Clone, PartialEq, Eq, Hash)]
532pub struct SoAdRoutingGroup(Element);
533abstraction_element!(SoAdRoutingGroup, SoAdRoutingGroup);
534impl IdentifiableAbstractionElement for SoAdRoutingGroup {}
535
536impl SoAdRoutingGroup {
537 pub(crate) fn new(
543 name: &str,
544 package: &ArPackage,
545 control_type: Option<EventGroupControlType>,
546 ) -> Result<Self, AutosarAbstractionError> {
547 let srg_elem: Element = package
548 .element()
549 .get_or_create_sub_element(ElementName::Elements)?
550 .create_named_sub_element(ElementName::SoAdRoutingGroup, name)?;
551 let srg = Self(srg_elem);
552
553 if let Some(control_type) = control_type {
554 srg.set_control_type(control_type)?;
555 }
556
557 Ok(srg)
558 }
559
560 pub fn set_control_type(&self, control_type: EventGroupControlType) -> Result<(), AutosarAbstractionError> {
562 self.element()
563 .get_or_create_sub_element(ElementName::EventGroupControlType)?
564 .set_character_data::<EnumItem>(control_type.into())?;
565 Ok(())
566 }
567
568 #[must_use]
570 pub fn control_type(&self) -> Option<EventGroupControlType> {
571 self.element()
572 .get_sub_element(ElementName::EventGroupControlType)
573 .and_then(|elem| elem.character_data())
574 .and_then(|cdata| cdata.enum_value())
575 .and_then(|eval| eval.try_into().ok())
576 }
577}
578
579#[cfg(test)]
582mod test {
583 use super::*;
584 use crate::{
585 AutosarModelAbstraction, SystemCategory,
586 communication::{IPv4AddressSource, NetworkEndpointAddress, SocketAddressType},
587 };
588 use autosar_data::AutosarVersion;
589
590 #[test]
591 fn test_socket_connection_bundle() {
592 let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
593 let package = model.get_or_create_package("/pkg1").unwrap();
594 let system = package.create_system("System", SystemCategory::SystemExtract).unwrap();
595 let cluster = system.create_ethernet_cluster("Cluster", &package).unwrap();
596 let channel = cluster.create_physical_channel("Channel", None).unwrap();
597 let server_endpoint = channel
598 .create_network_endpoint(
599 "ServerAddress",
600 NetworkEndpointAddress::IPv4 {
601 address: Some("192.168.0.1".to_string()),
602 address_source: Some(IPv4AddressSource::Fixed),
603 default_gateway: None,
604 network_mask: None,
605 },
606 None,
607 )
608 .unwrap();
609 let server_socket = channel
610 .create_socket_address(
611 "ServerSocket",
612 &server_endpoint,
613 &TpConfig::TcpTp {
614 port_number: Some(1234),
615 port_dynamically_assigned: None,
616 },
617 SocketAddressType::Unicast(None),
618 )
619 .unwrap();
620 let bundle = channel
621 .create_socket_connection_bundle("Bundle", &server_socket)
622 .unwrap();
623 assert_eq!(channel.socket_connection_bundles().next(), Some(bundle.clone()));
624 assert_eq!(channel.socket_connection_bundles().count(), 1);
625 assert_eq!(channel, bundle.physical_channel().unwrap());
626 assert_eq!(Some(server_socket), bundle.server_port());
627
628 let client_endpoint = channel
629 .create_network_endpoint(
630 "ClientAddress",
631 NetworkEndpointAddress::IPv4 {
632 address: Some("192.168.0.2".to_string()),
633 address_source: Some(IPv4AddressSource::Fixed),
634 default_gateway: None,
635 network_mask: None,
636 },
637 None,
638 )
639 .unwrap();
640 let client_socket = channel
641 .create_socket_address(
642 "ClientSocket",
643 &client_endpoint,
644 &TpConfig::TcpTp {
645 port_number: Some(1235),
646 port_dynamically_assigned: None,
647 },
648 SocketAddressType::Unicast(None),
649 )
650 .unwrap();
651 let connection = bundle.create_bundled_connection(&client_socket).unwrap();
652
653 let pdu = system.create_isignal_ipdu("Pdu", &package, 8).unwrap();
654 let (scii, pt) = connection
655 .create_socket_connection_ipdu_identifier(&pdu, 0x1234, Some(0.5), Some(PduCollectionTrigger::Always))
656 .unwrap();
657 assert_eq!(connection.socket_connection_ipdu_identifiers().count(), 1);
658 assert_eq!(pt, scii.pdu_triggering().unwrap());
659 assert_eq!(Some(pt.clone()), connection.pdu_triggerings().next());
660 assert_eq!(Some(0x1234), scii.header_id());
661 assert_eq!(Some(0.5), scii.timeout());
662 assert_eq!(Some(PduCollectionTrigger::Always), scii.collection_trigger());
663
664 scii.set_header_id(0x5678).unwrap();
665 assert_eq!(Some(0x5678), scii.header_id());
666 scii.set_timeout(Some(1.5)).unwrap();
667 assert_eq!(Some(1.5), scii.timeout());
668 scii.set_collection_trigger(Some(PduCollectionTrigger::Never)).unwrap();
669 assert_eq!(Some(PduCollectionTrigger::Never), scii.collection_trigger());
670 connection
671 .set_client_ip_addr_from_connection_request(Some(true))
672 .unwrap();
673 assert_eq!(connection.client_ip_addr_from_connection_request(), Some(true));
674 connection.set_client_ip_addr_from_connection_request(None).unwrap();
675 assert_eq!(connection.client_ip_addr_from_connection_request(), None);
676 connection.set_client_port_from_connection_request(Some(false)).unwrap();
677 assert_eq!(connection.client_port_from_connection_request(), Some(false));
678 connection.set_client_port_from_connection_request(None).unwrap();
679 assert_eq!(connection.client_port_from_connection_request(), None);
680 connection.set_runtime_ip_address_configuration(true).unwrap();
681 assert!(connection.runtime_ip_address_configuration());
682 connection.set_runtime_port_configuration(true).unwrap();
683 assert!(connection.runtime_port_configuration());
684 connection.set_runtime_ip_address_configuration(false).unwrap();
685 assert!(!connection.runtime_ip_address_configuration());
686 connection.set_runtime_port_configuration(false).unwrap();
687 assert!(!connection.runtime_port_configuration());
688
689 let routing_group = system
690 .create_so_ad_routing_group("RoutingGroup", &package, None)
691 .unwrap();
692 scii.add_routing_group(&routing_group).unwrap();
693 assert_eq!(scii.routing_groups().next(), Some(routing_group.clone()));
694 assert_eq!(scii.routing_groups().count(), 1);
695
696 assert_eq!(routing_group.control_type(), None);
697 routing_group
698 .set_control_type(EventGroupControlType::TriggerUnicast)
699 .unwrap();
700 assert_eq!(
701 routing_group.control_type(),
702 Some(EventGroupControlType::TriggerUnicast)
703 );
704 }
705}