autosar_data_abstraction/communication/transport_layer/
flexray_ar_tp.rs

1use crate::communication::{AbstractIpdu, FlexrayCluster, FlexrayCommunicationConnector, IPdu, NPdu, TpAddress};
2use crate::{
3    AbstractionElement, ArPackage, AutosarAbstractionError, IdentifiableAbstractionElement, abstraction_element,
4};
5use autosar_data::{Element, ElementName, EnumItem};
6
7//#########################################################
8
9/// The `FlexrayArTpConfig` represents the configuration of the Flexray Autosar Transport Protocol
10#[derive(Debug, Clone, PartialEq, Eq, Hash)]
11pub struct FlexrayArTpConfig(Element);
12abstraction_element!(FlexrayArTpConfig, FlexrayArTpConfig);
13impl IdentifiableAbstractionElement for FlexrayArTpConfig {}
14
15impl FlexrayArTpConfig {
16    pub(crate) fn new(
17        name: &str,
18        package: &ArPackage,
19        cluster: &FlexrayCluster,
20    ) -> Result<Self, AutosarAbstractionError> {
21        let pkg_elem = package.element().get_or_create_sub_element(ElementName::Elements)?;
22
23        let tp_config_elem = pkg_elem.create_named_sub_element(ElementName::FlexrayArTpConfig, name)?;
24        let tp_config = Self(tp_config_elem);
25        tp_config.set_cluster(cluster)?;
26
27        Ok(tp_config)
28    }
29
30    /// set the Flexray cluster for the configuration
31    pub fn set_cluster(&self, cluster: &FlexrayCluster) -> Result<(), AutosarAbstractionError> {
32        self.element()
33            .get_or_create_sub_element(ElementName::CommunicationClusterRef)?
34            .set_reference_target(cluster.element())?;
35        Ok(())
36    }
37
38    /// get the Flexray cluster for the configuration
39    #[must_use]
40    pub fn cluster(&self) -> Option<FlexrayCluster> {
41        self.element()
42            .get_sub_element(ElementName::CommunicationClusterRef)
43            .and_then(|refelem| refelem.get_reference_target().ok())
44            .and_then(|elem| elem.try_into().ok())
45    }
46
47    /// create a new `TpAddress`
48    pub fn create_tp_address(&self, name: &str, address: u32) -> Result<TpAddress, AutosarAbstractionError> {
49        let tp_addresses_elem = self.element().get_or_create_sub_element(ElementName::TpAddresss)?;
50        TpAddress::new(name, &tp_addresses_elem, address)
51    }
52
53    /// iterate over all `TpAddresses`
54    pub fn tp_addresses(&self) -> impl Iterator<Item = TpAddress> + Send + use<> {
55        self.element()
56            .get_sub_element(ElementName::TpAddresss)
57            .into_iter()
58            .flat_map(|elem| elem.sub_elements())
59            .filter_map(|elem| elem.try_into().ok())
60    }
61
62    /// create a new `FlexrayArTpChannel`
63    pub fn create_flexray_ar_tp_channel(
64        &self,
65        ack_type: FrArTpAckType,
66        extended_addressing: bool,
67        maximum_message_length: MaximumMessageLengthType,
68        minimum_separation_time: f32,
69        multicast_segmentation: bool,
70    ) -> Result<FlexrayArTpChannel, AutosarAbstractionError> {
71        let tp_channels_elem = self.element().get_or_create_sub_element(ElementName::TpChannels)?;
72        FlexrayArTpChannel::new(
73            &tp_channels_elem,
74            ack_type,
75            extended_addressing,
76            maximum_message_length,
77            minimum_separation_time,
78            multicast_segmentation,
79        )
80    }
81
82    /// get an iterator over the channels in the configuration
83    pub fn flexray_ar_tp_channels(&self) -> impl Iterator<Item = FlexrayArTpChannel> + Send + use<> {
84        self.element()
85            .get_sub_element(ElementName::TpChannels)
86            .into_iter()
87            .flat_map(|tp_channels_elem| tp_channels_elem.sub_elements())
88            .filter_map(|tp_channel_elem| tp_channel_elem.try_into().ok())
89    }
90
91    /// create a new `FlexrayArTpNode`
92    pub fn create_flexray_ar_tp_node(&self, name: &str) -> Result<FlexrayArTpNode, AutosarAbstractionError> {
93        let tp_nodes_elem = self.element().get_or_create_sub_element(ElementName::TpNodes)?;
94        FlexrayArTpNode::new(name, &tp_nodes_elem)
95    }
96
97    /// get an iterator over the nodes
98    pub fn flexray_ar_tp_nodes(&self) -> impl Iterator<Item = FlexrayArTpNode> + Send + use<> {
99        self.element()
100            .get_sub_element(ElementName::TpNodes)
101            .into_iter()
102            .flat_map(|tp_nodes_elem| tp_nodes_elem.sub_elements())
103            .filter_map(|tp_node_elem| tp_node_elem.try_into().ok())
104    }
105}
106
107//#########################################################
108
109/// The `FlexrayArTpChannel` represents a channel in the Flexray Autosar Transport Protocol
110#[derive(Debug, Clone, PartialEq, Eq, Hash)]
111pub struct FlexrayArTpChannel(Element);
112abstraction_element!(FlexrayArTpChannel, FlexrayArTpChannel);
113
114impl FlexrayArTpChannel {
115    pub(crate) fn new(
116        parent: &Element,
117        ack_type: FrArTpAckType,
118        extended_addressing: bool,
119        maximum_message_length: MaximumMessageLengthType,
120        minimum_separation_time: f32,
121        multicast_segmentation: bool,
122    ) -> Result<Self, AutosarAbstractionError> {
123        let tp_channel_elem = parent.create_sub_element(ElementName::FlexrayArTpChannel)?;
124        let tp_channel = Self(tp_channel_elem);
125
126        tp_channel.set_ack_type(ack_type)?;
127        tp_channel.set_extended_addressing(extended_addressing)?;
128        tp_channel.set_maximum_message_length(maximum_message_length)?;
129        tp_channel.set_minimum_separation_time(minimum_separation_time)?;
130        tp_channel.set_multicast_segmentation(multicast_segmentation)?;
131
132        Ok(tp_channel)
133    }
134
135    /// set the ack type of the channel
136    pub fn set_ack_type(&self, ack_type: FrArTpAckType) -> Result<(), AutosarAbstractionError> {
137        self.element()
138            .get_or_create_sub_element(ElementName::AckType)?
139            .set_character_data::<EnumItem>(ack_type.into())?;
140        Ok(())
141    }
142
143    /// get the ack type of the channel
144    #[must_use]
145    pub fn ack_type(&self) -> Option<FrArTpAckType> {
146        self.element()
147            .get_sub_element(ElementName::AckType)?
148            .character_data()?
149            .enum_value()?
150            .try_into()
151            .ok()
152    }
153
154    /// set the extended addressing attribute
155    ///
156    /// When extended addressing is enabled, the TP address is 16 bit long, otherwise it is 8 bit long.
157    pub fn set_extended_addressing(&self, extended_addressing: bool) -> Result<(), AutosarAbstractionError> {
158        self.element()
159            .get_or_create_sub_element(ElementName::ExtendedAddressing)?
160            .set_character_data(extended_addressing)?;
161        Ok(())
162    }
163
164    /// get the extended addressing attribute
165    ///
166    /// When extended addressing is enabled, the TP address is 16 bit long, otherwise it is 8 bit long.
167    #[must_use]
168    pub fn extended_addressing(&self) -> Option<bool> {
169        self.element()
170            .get_sub_element(ElementName::ExtendedAddressing)?
171            .character_data()?
172            .parse_bool()
173    }
174
175    /// set the maximum message length type
176    pub fn set_maximum_message_length(
177        &self,
178        maximum_message_length: MaximumMessageLengthType,
179    ) -> Result<(), AutosarAbstractionError> {
180        self.element()
181            .get_or_create_sub_element(ElementName::MaximumMessageLength)?
182            .set_character_data::<EnumItem>(maximum_message_length.into())?;
183        Ok(())
184    }
185
186    /// get the maximum message length type
187    #[must_use]
188    pub fn maximum_message_length(&self) -> Option<MaximumMessageLengthType> {
189        self.element()
190            .get_sub_element(ElementName::MaximumMessageLength)?
191            .character_data()?
192            .enum_value()?
193            .try_into()
194            .ok()
195    }
196
197    /// set the minimum separation time
198    pub fn set_minimum_separation_time(&self, minimum_separation_time: f32) -> Result<(), AutosarAbstractionError> {
199        self.element()
200            .get_or_create_sub_element(ElementName::MinimumSeparationTime)?
201            .set_character_data(f64::from(minimum_separation_time))?;
202        Ok(())
203    }
204
205    /// get the minimum separation time
206    #[must_use]
207    pub fn minimum_separation_time(&self) -> Option<f32> {
208        self.element()
209            .get_sub_element(ElementName::MinimumSeparationTime)?
210            .character_data()?
211            .float_value()
212            .map(|v| v as f32)
213    }
214
215    /// set the multicast segmentation attribute
216    pub fn set_multicast_segmentation(&self, multicast_segmentation: bool) -> Result<(), AutosarAbstractionError> {
217        self.element()
218            .get_or_create_sub_element(ElementName::MulticastSegmentation)?
219            .set_character_data(multicast_segmentation)?;
220        Ok(())
221    }
222
223    /// get the multicast segmentation attribute
224    #[must_use]
225    pub fn multicast_segmentation(&self) -> Option<bool> {
226        self.element()
227            .get_sub_element(ElementName::MulticastSegmentation)?
228            .character_data()?
229            .parse_bool()
230    }
231
232    /// create a new `FlexrayArTpConnection` for this channel
233    pub fn create_flexray_ar_tp_connection<T: AbstractIpdu>(
234        &self,
235        name: Option<&str>,
236        direct_tp_sdu: &T,
237        source: &FlexrayArTpNode,
238        target: &FlexrayArTpNode,
239    ) -> Result<FlexrayArTpConnection, AutosarAbstractionError> {
240        let parent = self.element().get_or_create_sub_element(ElementName::TpConnections)?;
241        FlexrayArTpConnection::new(name, &parent, &direct_tp_sdu.clone().into(), source, target)
242    }
243
244    /// get an iterator over the connections in the channel
245    pub fn flexray_ar_tp_connections(&self) -> impl Iterator<Item = FlexrayArTpConnection> + Send + use<> {
246        self.element()
247            .get_sub_element(ElementName::TpConnections)
248            .into_iter()
249            .flat_map(|tp_connections_elem| tp_connections_elem.sub_elements())
250            .filter_map(|tp_connection_elem| tp_connection_elem.try_into().ok())
251    }
252
253    /// add an N-PDU to the channel
254    ///
255    /// The `NPdus` are logically assembled into a pool of Rx `NPdus` and another pool of Tx `NPdus`.
256    /// This function is supported on autosar 4.1 and later, while Autosar 4.0 uses a different approach.
257    pub fn add_n_pdu(&self, n_pdu: &NPdu) -> Result<(), AutosarAbstractionError> {
258        let npdu_refs_elem = self.element().get_or_create_sub_element(ElementName::NPduRefs)?;
259        npdu_refs_elem
260            .create_sub_element(ElementName::NPduRef)?
261            .set_reference_target(n_pdu.element())?;
262        Ok(())
263    }
264
265    /// get the `NPdus` of the channel
266    pub fn n_pdus(&self) -> impl Iterator<Item = NPdu> + Send + use<> {
267        self.element()
268            .get_sub_element(ElementName::NPduRefs)
269            .into_iter()
270            .flat_map(|npdu_refs_elem| npdu_refs_elem.sub_elements())
271            .filter_map(|npdu_ref_elem| {
272                npdu_ref_elem
273                    .get_reference_target()
274                    .ok()
275                    .and_then(|npdu_elem| npdu_elem.try_into().ok())
276            })
277    }
278}
279
280//#########################################################
281
282/// Types of Acknowledgement that can be used in an `FlexrayArTpChannel`
283#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
284pub enum FrArTpAckType {
285    /// Acknowledgement without retry
286    AckWithoutRt,
287    /// Acknowledgement with retry
288    AckWithRt,
289    /// No acknowledgement
290    NoAck,
291}
292
293impl TryFrom<EnumItem> for FrArTpAckType {
294    type Error = AutosarAbstractionError;
295
296    fn try_from(item: EnumItem) -> Result<Self, Self::Error> {
297        match item {
298            EnumItem::AckWithoutRt => Ok(Self::AckWithoutRt),
299            EnumItem::AckWithRt => Ok(Self::AckWithRt),
300            EnumItem::NoAck => Ok(Self::NoAck),
301            _ => Err(AutosarAbstractionError::ValueConversionError {
302                value: item.to_string(),
303                dest: "FrArTpAckType".to_string(),
304            }),
305        }
306    }
307}
308
309impl From<FrArTpAckType> for EnumItem {
310    fn from(val: FrArTpAckType) -> Self {
311        match val {
312            FrArTpAckType::AckWithoutRt => EnumItem::AckWithoutRt,
313            FrArTpAckType::AckWithRt => EnumItem::AckWithRt,
314            FrArTpAckType::NoAck => EnumItem::NoAck,
315        }
316    }
317}
318
319//#########################################################
320
321/// Types of Maximum Message Length that can be used in an `FlexrayArTpChannel`
322#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
323pub enum MaximumMessageLengthType {
324    /// I4G: up to (2**32)-1 byte message length
325    I4g,
326    /// ISO: up to 4095 byte message length
327    Iso,
328    /// ISO6: payload length is limited to 6 byte (SF-I, FF-I, CF). This is necessary to route TP on CAN
329    Iso6,
330}
331
332impl TryFrom<EnumItem> for MaximumMessageLengthType {
333    type Error = AutosarAbstractionError;
334
335    fn try_from(item: EnumItem) -> Result<Self, Self::Error> {
336        match item {
337            EnumItem::I4G => Ok(Self::I4g),
338            EnumItem::Iso => Ok(Self::Iso),
339            EnumItem::Iso6 => Ok(Self::Iso6),
340            _ => Err(AutosarAbstractionError::ValueConversionError {
341                value: item.to_string(),
342                dest: "MaximumMessageLengthType".to_string(),
343            }),
344        }
345    }
346}
347
348impl From<MaximumMessageLengthType> for EnumItem {
349    fn from(val: MaximumMessageLengthType) -> Self {
350        match val {
351            MaximumMessageLengthType::I4g => EnumItem::I4G,
352            MaximumMessageLengthType::Iso => EnumItem::Iso,
353            MaximumMessageLengthType::Iso6 => EnumItem::Iso6,
354        }
355    }
356}
357
358//#########################################################
359
360/// `FlexrayArTpConnection` represents a connection within a `FlexrayArTpChannel`
361///
362/// The connection identifies the sender and the receiver of this particular communication.
363/// The `FlexRay` Autosar Tp module routes a Pdu through this connection.
364#[derive(Debug, Clone, PartialEq, Eq, Hash)]
365pub struct FlexrayArTpConnection(Element);
366abstraction_element!(FlexrayArTpConnection, FlexrayArTpConnection);
367
368impl IdentifiableAbstractionElement for FlexrayArTpConnection {
369    /// get the name of the connection
370    ///
371    /// In early versions of the Autosar standard, `TpConnections` were not identifiable.
372    /// This was fixed later by adding the `Ident` sub-element. This method returns the name
373    /// provied in the `Ident` element, if it exists.
374    fn name(&self) -> Option<String> {
375        self.element()
376            .get_sub_element(ElementName::Ident)
377            .and_then(|elem| elem.item_name())
378    }
379
380    /// set the name of the connection
381    fn set_name(&self, name: &str) -> Result<(), AutosarAbstractionError> {
382        if let Some(ident_elem) = self.element().get_sub_element(ElementName::Ident) {
383            ident_elem.set_item_name(name)?;
384        } else {
385            self.element().create_named_sub_element(ElementName::Ident, name)?;
386        }
387        Ok(())
388    }
389}
390
391impl FlexrayArTpConnection {
392    pub(crate) fn new(
393        name: Option<&str>,
394        parent: &Element,
395        direct_tp_sdu: &IPdu,
396        source: &FlexrayArTpNode,
397        target: &FlexrayArTpNode,
398    ) -> Result<Self, AutosarAbstractionError> {
399        let tp_connection_elem = parent.create_sub_element(ElementName::FlexrayArTpConnection)?;
400        if let Some(name) = name {
401            tp_connection_elem.create_named_sub_element(ElementName::Ident, name)?;
402        }
403        let tp_connection = Self(tp_connection_elem);
404        tp_connection.set_direct_tp_sdu(direct_tp_sdu)?;
405        tp_connection.set_source(source)?;
406        tp_connection.add_target(target)?;
407
408        Ok(tp_connection)
409    }
410
411    /// set the direct TP SDU
412    pub fn set_direct_tp_sdu<T: AbstractIpdu>(&self, direct_tp_sdu: &T) -> Result<(), AutosarAbstractionError> {
413        self.element()
414            .get_or_create_sub_element(ElementName::DirectTpSduRef)?
415            .set_reference_target(direct_tp_sdu.element())?;
416        Ok(())
417    }
418
419    /// get the direct tp sdu
420    #[must_use]
421    pub fn direct_tp_sdu(&self) -> Option<IPdu> {
422        self.element()
423            .get_sub_element(ElementName::DirectTpSduRef)
424            .and_then(|refelem| refelem.get_reference_target().ok())
425            .and_then(|elem| elem.try_into().ok())
426    }
427
428    /// set the source of the connection
429    pub fn set_source(&self, source: &FlexrayArTpNode) -> Result<(), AutosarAbstractionError> {
430        self.element()
431            .get_or_create_sub_element(ElementName::SourceRef)?
432            .set_reference_target(source.element())?;
433        Ok(())
434    }
435
436    /// get the source
437    #[must_use]
438    pub fn source(&self) -> Option<FlexrayArTpNode> {
439        self.element()
440            .get_sub_element(ElementName::SourceRef)
441            .and_then(|refelem| refelem.get_reference_target().ok())
442            .and_then(|elem| elem.try_into().ok())
443    }
444
445    /// add a target to the connection
446    ///
447    /// The connection can have multiple targets, but at least one target is required.
448    pub fn add_target(&self, target: &FlexrayArTpNode) -> Result<(), AutosarAbstractionError> {
449        self.element()
450            .get_or_create_sub_element(ElementName::TargetRefs)?
451            .create_sub_element(ElementName::TargetRef)?
452            .set_reference_target(target.element())?;
453        Ok(())
454    }
455
456    /// get the targets
457    pub fn targets(&self) -> impl Iterator<Item = FlexrayArTpNode> + Send + use<> {
458        self.element()
459            .get_sub_element(ElementName::TargetRefs)
460            .into_iter()
461            .flat_map(|target_refs_elem| target_refs_elem.sub_elements())
462            .filter_map(|target_ref_elem| {
463                target_ref_elem
464                    .get_reference_target()
465                    .ok()
466                    .and_then(|target_elem| target_elem.try_into().ok())
467            })
468    }
469
470    /// set or remove the reversed TP SDU
471    ///
472    /// If the connection supports both directions, then the reversed TP SDU is required.
473    /// if Some(value) is passed, the reversed TP SDU is set to the given value, otherwise it is removed.
474    pub fn set_reversed_tp_sdu<T: AbstractIpdu>(
475        &self,
476        reversed_tp_sdu: Option<&T>,
477    ) -> Result<(), AutosarAbstractionError> {
478        if let Some(reversed_tp_sdu) = reversed_tp_sdu {
479            self.element()
480                .get_or_create_sub_element(ElementName::ReversedTpSduRef)?
481                .set_reference_target(reversed_tp_sdu.element())?;
482        } else if let Some(reversed_tp_sdu_elem) = self.element().get_sub_element(ElementName::ReversedTpSduRef) {
483            self.element().remove_sub_element(reversed_tp_sdu_elem)?;
484        }
485        Ok(())
486    }
487
488    /// get the reversed tp sdu
489    #[must_use]
490    pub fn reversed_tp_sdu(&self) -> Option<IPdu> {
491        self.element()
492            .get_sub_element(ElementName::ReversedTpSduRef)
493            .and_then(|refelem| refelem.get_reference_target().ok())
494            .and_then(|elem| elem.try_into().ok())
495    }
496}
497
498//#########################################################
499
500/// `FlexrayArTpNode` represents a node in the Flexray Autosar Transport Protocol
501///
502/// A TP node (sender or receiver) provides the TP address and the connection to the topology description
503#[derive(Debug, Clone, PartialEq, Eq, Hash)]
504pub struct FlexrayArTpNode(Element);
505abstraction_element!(FlexrayArTpNode, FlexrayArTpNode);
506impl IdentifiableAbstractionElement for FlexrayArTpNode {}
507
508impl FlexrayArTpNode {
509    pub(crate) fn new(name: &str, parent: &Element) -> Result<Self, AutosarAbstractionError> {
510        let tp_node_elem = parent.create_named_sub_element(ElementName::FlexrayArTpNode, name)?;
511        Ok(Self(tp_node_elem))
512    }
513
514    /// set or remove the TP address
515    ///
516    /// if Some(value) is passed, the TP address is set to the given value, otherwise it is removed.
517    pub fn set_tp_address(&self, tp_address: Option<&TpAddress>) -> Result<(), AutosarAbstractionError> {
518        if let Some(tp_address) = tp_address {
519            self.element()
520                .get_or_create_sub_element(ElementName::TpAddressRef)?
521                .set_reference_target(tp_address.element())?;
522        } else {
523            let _ = self.element().remove_sub_element_kind(ElementName::TpAddressRef);
524        }
525        Ok(())
526    }
527
528    /// get the TP address
529    #[must_use]
530    pub fn tp_address(&self) -> Option<TpAddress> {
531        self.element()
532            .get_sub_element(ElementName::TpAddressRef)
533            .and_then(|refelem| refelem.get_reference_target().ok())
534            .and_then(|elem| elem.try_into().ok())
535    }
536
537    /// add a reference to a `FlexrayCommunicationConnector`
538    ///
539    /// The connectors define the association with a `PhysicalChannel` and an ECU.
540    /// In a `SystemDescription`, this reference is mandatory, but in an `ECUExtract` it is optional.
541    /// Up to 2 connectors can be added to a node.
542    pub fn add_communication_connector(
543        &self,
544        connector: &FlexrayCommunicationConnector,
545    ) -> Result<(), AutosarAbstractionError> {
546        // Todo: enforce the limit of 2 connectors
547        self.element()
548            .get_or_create_sub_element(ElementName::ConnectorRefs)?
549            .create_sub_element(ElementName::ConnectorRef)?
550            .set_reference_target(connector.element())?;
551        Ok(())
552    }
553
554    /// get the connectors
555    pub fn communication_connectors(&self) -> impl Iterator<Item = FlexrayCommunicationConnector> + Send + use<> {
556        self.element()
557            .get_sub_element(ElementName::ConnectorRefs)
558            .into_iter()
559            .flat_map(|connector_refs_elem| connector_refs_elem.sub_elements())
560            .filter_map(|connector_ref_elem| {
561                connector_ref_elem
562                    .get_reference_target()
563                    .ok()
564                    .and_then(|connector_elem| connector_elem.try_into().ok())
565            })
566    }
567}
568
569//#########################################################
570
571#[cfg(test)]
572mod test {
573    use super::*;
574    use crate::{
575        AutosarModelAbstraction, SystemCategory,
576        communication::{DiagPduType, FlexrayChannelName, FlexrayClusterSettings},
577    };
578    use autosar_data::AutosarVersion;
579
580    #[test]
581    fn test_flexray_ar_transport_protocol() {
582        let model = AutosarModelAbstraction::create("DoipTp.arxml", AutosarVersion::LATEST);
583        let package = model.get_or_create_package("/pkg1").unwrap();
584
585        let system = package.create_system("system", SystemCategory::EcuExtract).unwrap();
586        let flexray_cluster = system
587            .create_flexray_cluster("flexray_cluster", &package, &FlexrayClusterSettings::default())
588            .unwrap();
589        let flexray_channel = flexray_cluster
590            .create_physical_channel("flexray_channel_a", FlexrayChannelName::A)
591            .unwrap();
592        let ecu_instance = system.create_ecu_instance("ecu_instance", &package).unwrap();
593        let communication_controller = ecu_instance
594            .create_flexray_communication_controller("can_ctrl")
595            .unwrap();
596        let connector = communication_controller
597            .connect_physical_channel("name", &flexray_channel)
598            .unwrap();
599
600        // create a direct TP SDU (DCM-I-PDU)
601        let tp_sdu = system
602            .create_dcm_ipdu("diag", &package, 1024, DiagPduType::DiagRequest)
603            .unwrap();
604
605        // create some NPdus
606        let npdu1 = system.create_n_pdu("npdu1", &package, 64).unwrap();
607        let npdu2 = system.create_n_pdu("npdu2", &package, 64).unwrap();
608
609        let fr_ar_tp_config = system
610            .create_flexray_ar_tp_config("FrArTpConfig", &package, &flexray_cluster)
611            .unwrap();
612        assert_eq!(fr_ar_tp_config.cluster(), Some(flexray_cluster));
613
614        let fr_ar_tp_channel = fr_ar_tp_config
615            .create_flexray_ar_tp_channel(
616                FrArTpAckType::AckWithRt,
617                true,
618                MaximumMessageLengthType::I4g,
619                0.001,
620                false,
621            )
622            .unwrap();
623        assert_eq!(fr_ar_tp_config.flexray_ar_tp_channels().count(), 1);
624        assert_eq!(fr_ar_tp_channel.ack_type(), Some(FrArTpAckType::AckWithRt));
625        assert_eq!(fr_ar_tp_channel.extended_addressing(), Some(true));
626        assert_eq!(
627            fr_ar_tp_channel.maximum_message_length(),
628            Some(MaximumMessageLengthType::I4g)
629        );
630        assert_eq!(fr_ar_tp_channel.minimum_separation_time(), Some(0.001));
631        assert_eq!(fr_ar_tp_channel.multicast_segmentation(), Some(false));
632
633        fr_ar_tp_channel.add_n_pdu(&npdu1).unwrap();
634        fr_ar_tp_channel.add_n_pdu(&npdu2).unwrap();
635        assert_eq!(fr_ar_tp_channel.n_pdus().count(), 2);
636
637        let fr_ar_tp_node_source = fr_ar_tp_config.create_flexray_ar_tp_node("node_s").unwrap();
638        let tp_address_source = fr_ar_tp_config.create_tp_address("tp_address_s", 1).unwrap();
639        fr_ar_tp_node_source.set_tp_address(Some(&tp_address_source)).unwrap();
640        assert_eq!(fr_ar_tp_node_source.tp_address(), Some(tp_address_source));
641        fr_ar_tp_node_source.add_communication_connector(&connector).unwrap();
642        assert_eq!(fr_ar_tp_node_source.communication_connectors().count(), 1);
643        assert_eq!(fr_ar_tp_node_source.communication_connectors().next(), Some(connector));
644
645        let fr_ar_tp_node_target = fr_ar_tp_config.create_flexray_ar_tp_node("node_t").unwrap();
646        let tp_address_target = fr_ar_tp_config.create_tp_address("tp_address_t", 2).unwrap();
647        fr_ar_tp_node_target.set_tp_address(Some(&tp_address_target)).unwrap();
648        assert_eq!(fr_ar_tp_node_target.tp_address(), Some(tp_address_target));
649
650        assert_eq!(fr_ar_tp_config.tp_addresses().count(), 2);
651        assert_eq!(fr_ar_tp_config.flexray_ar_tp_nodes().count(), 2);
652
653        let flexray_ar_tp_connection = fr_ar_tp_channel
654            .create_flexray_ar_tp_connection(Some("conn"), &tp_sdu, &fr_ar_tp_node_source, &fr_ar_tp_node_target)
655            .unwrap();
656        assert_eq!(fr_ar_tp_channel.flexray_ar_tp_connections().count(), 1);
657        assert_eq!(flexray_ar_tp_connection.direct_tp_sdu(), Some(tp_sdu.into()));
658        assert_eq!(flexray_ar_tp_connection.source(), Some(fr_ar_tp_node_source));
659        assert_eq!(flexray_ar_tp_connection.targets().count(), 1);
660
661        assert_eq!(flexray_ar_tp_connection.name(), Some("conn".to_string()));
662        flexray_ar_tp_connection.set_name("new_name").unwrap();
663        assert_eq!(flexray_ar_tp_connection.name(), Some("new_name".to_string()));
664
665        let reversed_tp_sdu = system
666            .create_dcm_ipdu("reversed_tp_sdu", &package, 1024, DiagPduType::DiagResponse)
667            .unwrap();
668        flexray_ar_tp_connection
669            .set_reversed_tp_sdu(Some(&reversed_tp_sdu))
670            .unwrap();
671        assert_eq!(
672            flexray_ar_tp_connection.reversed_tp_sdu(),
673            Some(reversed_tp_sdu.clone().into())
674        );
675
676        let fr_ar_tp_node_extra = fr_ar_tp_config.create_flexray_ar_tp_node("node_extra").unwrap();
677        flexray_ar_tp_connection.add_target(&fr_ar_tp_node_extra).unwrap();
678        assert_eq!(flexray_ar_tp_connection.targets().count(), 2);
679    }
680}