autosar_data_abstraction/communication/transport_layer/
flexray_tp.rs

1use crate::communication::{AbstractIpdu, FlexrayCluster, FlexrayCommunicationConnector, IPdu, NPdu, TpAddress};
2use crate::{
3    AbstractionElement, ArPackage, AutosarAbstractionError, EcuInstance, IdentifiableAbstractionElement,
4    abstraction_element,
5};
6use autosar_data::{Element, ElementName};
7
8/// `FlexrayTpConfig` defines exactly one `FlexRay` ISO TP Configuration
9#[derive(Debug, Clone, PartialEq, Eq, Hash)]
10pub struct FlexrayTpConfig(Element);
11abstraction_element!(FlexrayTpConfig, FlexrayTpConfig);
12impl IdentifiableAbstractionElement for FlexrayTpConfig {}
13
14impl FlexrayTpConfig {
15    pub(crate) fn new(
16        name: &str,
17        package: &ArPackage,
18        cluster: &FlexrayCluster,
19    ) -> Result<Self, AutosarAbstractionError> {
20        let pkg_elem = package.element().get_or_create_sub_element(ElementName::Elements)?;
21
22        let tp_config_elem = pkg_elem.create_named_sub_element(ElementName::FlexrayTpConfig, name)?;
23        let tp_config = Self(tp_config_elem);
24        tp_config.set_cluster(cluster)?;
25
26        Ok(tp_config)
27    }
28
29    /// set the `FlexrayCluster` of the `FlexrayTpConfig`
30    pub fn set_cluster(&self, cluster: &FlexrayCluster) -> Result<(), AutosarAbstractionError> {
31        self.element()
32            .get_or_create_sub_element(ElementName::CommunicationClusterRef)?
33            .set_reference_target(cluster.element())?;
34        Ok(())
35    }
36
37    /// get the `FlexrayCluster` of the `FlexrayTpConfig`
38    #[must_use]
39    pub fn cluster(&self) -> Option<FlexrayCluster> {
40        self.element()
41            .get_sub_element(ElementName::CommunicationClusterRef)
42            .and_then(|elem| elem.get_reference_target().ok())
43            .and_then(|elem| elem.try_into().ok())
44    }
45
46    /// create a new `FlexrayTpPduPool`
47    pub fn create_flexray_tp_pdu_pool(&self, name: &str) -> Result<FlexrayTpPduPool, AutosarAbstractionError> {
48        let pdu_pools_elem = self.element().get_or_create_sub_element(ElementName::PduPools)?;
49        FlexrayTpPduPool::new(name, &pdu_pools_elem)
50    }
51
52    /// iterate over all `FlexrayTpPduPools`
53    pub fn flexray_tp_pdu_pools(&self) -> impl Iterator<Item = FlexrayTpPduPool> + Send + use<> {
54        self.element()
55            .get_sub_element(ElementName::PduPools)
56            .into_iter()
57            .flat_map(|elem| elem.sub_elements())
58            .map(FlexrayTpPduPool)
59    }
60
61    /// create a new `TpAddress`
62    pub fn create_tp_address(&self, name: &str, address: u32) -> Result<TpAddress, AutosarAbstractionError> {
63        let tp_addresses_elem = self.element().get_or_create_sub_element(ElementName::TpAddresss)?;
64        TpAddress::new(name, &tp_addresses_elem, address)
65    }
66
67    /// iterate over all `TpAddresses`
68    pub fn tp_addresses(&self) -> impl Iterator<Item = TpAddress> + Send + use<> {
69        self.element()
70            .get_sub_element(ElementName::TpAddresss)
71            .into_iter()
72            .flat_map(|elem| elem.sub_elements())
73            .filter_map(|elem| elem.try_into().ok())
74    }
75
76    /// create a new `FlexrayTpConnection`
77    pub fn create_flexray_tp_connection<T: AbstractIpdu>(
78        &self,
79        name: Option<&str>,
80        transmitter: &FlexrayTpNode,
81        direct_tp_sdu: &T,
82        connection_control: &FlexrayTpConnectionControl,
83    ) -> Result<FlexrayTpConnection, AutosarAbstractionError> {
84        let tp_connections_elem = self.element().get_or_create_sub_element(ElementName::TpConnections)?;
85        FlexrayTpConnection::new(
86            name,
87            &tp_connections_elem,
88            transmitter,
89            &direct_tp_sdu.clone().into(),
90            connection_control,
91        )
92    }
93
94    /// iterate over all `FlexrayTpConnections`
95    pub fn flexray_tp_connections(&self) -> impl Iterator<Item = FlexrayTpConnection> + Send + use<> {
96        self.element()
97            .get_sub_element(ElementName::TpConnections)
98            .into_iter()
99            .flat_map(|elem| elem.sub_elements())
100            .map(FlexrayTpConnection)
101    }
102
103    /// create a new `FlexrayTpConnectionControl`
104    pub fn create_flexray_tp_connection_control(
105        &self,
106        name: &str,
107    ) -> Result<FlexrayTpConnectionControl, AutosarAbstractionError> {
108        let connection_controls_elem = self
109            .element()
110            .get_or_create_sub_element(ElementName::TpConnectionControls)?;
111        FlexrayTpConnectionControl::new(name, &connection_controls_elem)
112    }
113
114    /// iterate over all `FlexrayTpConnectionControls`
115    pub fn flexray_tp_connection_controls(&self) -> impl Iterator<Item = FlexrayTpConnectionControl> + Send + use<> {
116        self.element()
117            .get_sub_element(ElementName::TpConnectionControls)
118            .into_iter()
119            .flat_map(|elem| elem.sub_elements())
120            .map(FlexrayTpConnectionControl)
121    }
122
123    /// create a `FlexrayTpEcu` in the `FlexrayTpConfig`
124    pub fn create_flexray_tp_ecu(
125        &self,
126        ecu_instance: &EcuInstance,
127        full_duplex_enabled: bool,
128    ) -> Result<FlexrayTpEcu, AutosarAbstractionError> {
129        let ecu_collection = self.element().get_or_create_sub_element(ElementName::TpEcus)?;
130        FlexrayTpEcu::new(&ecu_collection, ecu_instance, full_duplex_enabled)
131    }
132
133    /// iterate over all `FlexrayTpEcus`
134    pub fn flexray_tp_ecus(&self) -> impl Iterator<Item = FlexrayTpEcu> + Send + use<> {
135        self.element()
136            .get_sub_element(ElementName::TpEcus)
137            .into_iter()
138            .flat_map(|elem| elem.sub_elements())
139            .filter_map(|elem| FlexrayTpEcu::try_from(elem).ok())
140    }
141
142    /// create a new `FlexrayTpNode`
143    pub fn create_flexray_tp_node(&self, name: &str) -> Result<FlexrayTpNode, AutosarAbstractionError> {
144        let nodes_elem = self.element().get_or_create_sub_element(ElementName::TpNodes)?;
145        FlexrayTpNode::new(name, &nodes_elem)
146    }
147
148    /// iterate over all `FlexrayTpNodes`
149    pub fn flexray_tp_nodes(&self) -> impl Iterator<Item = FlexrayTpNode> + Send + use<> {
150        self.element()
151            .get_sub_element(ElementName::TpNodes)
152            .into_iter()
153            .flat_map(|elem| elem.sub_elements())
154            .map(FlexrayTpNode)
155    }
156}
157
158//##################################################################
159
160/// A `FlexrayTpPduPool` contains a set of `NPdus` that can be used for sending and receiving
161#[derive(Debug, Clone, PartialEq, Eq, Hash)]
162pub struct FlexrayTpPduPool(Element);
163abstraction_element!(FlexrayTpPduPool, FlexrayTpPduPool);
164impl IdentifiableAbstractionElement for FlexrayTpPduPool {}
165
166impl FlexrayTpPduPool {
167    pub(crate) fn new(name: &str, parent: &Element) -> Result<Self, AutosarAbstractionError> {
168        let pdu_pool_elem = parent.create_named_sub_element(ElementName::FlexrayTpPduPool, name)?;
169        Ok(Self(pdu_pool_elem))
170    }
171
172    /// add an `NPdu` to the `PduPool`
173    pub fn add_n_pdu(&self, n_pdu: &NPdu) -> Result<(), AutosarAbstractionError> {
174        self.element()
175            .get_or_create_sub_element(ElementName::NPduRefs)?
176            .create_sub_element(ElementName::NPduRef)?
177            .set_reference_target(n_pdu.element())?;
178        Ok(())
179    }
180
181    /// iterate over all referenced `NPdus`
182    pub fn n_pdus(&self) -> impl Iterator<Item = NPdu> + Send + use<> {
183        self.element()
184            .get_sub_element(ElementName::NPduRefs)
185            .into_iter()
186            .flat_map(|elem| elem.sub_elements())
187            .filter_map(|ref_elem| {
188                ref_elem
189                    .get_reference_target()
190                    .ok()
191                    .and_then(|elem| elem.try_into().ok())
192            })
193    }
194}
195
196//##################################################################
197
198/// A `FlexrayTpConnection` defines a connection between `FlexrayTpNodes`
199#[derive(Debug, Clone, PartialEq, Eq, Hash)]
200pub struct FlexrayTpConnection(Element);
201abstraction_element!(FlexrayTpConnection, FlexrayTpConnection);
202
203impl IdentifiableAbstractionElement for FlexrayTpConnection {
204    /// get the name of the connection
205    ///
206    /// In early versions of the Autosar standard, `TpConnections` were not identifiable.
207    /// This was fixed later by adding the `Ident` sub-element. This method returns the name
208    /// provied in the `Ident` element, if it exists.
209    fn name(&self) -> Option<String> {
210        self.element()
211            .get_sub_element(ElementName::Ident)
212            .and_then(|elem| elem.item_name())
213    }
214
215    /// set the name of the connection
216    fn set_name(&self, name: &str) -> Result<(), AutosarAbstractionError> {
217        if let Some(ident_elem) = self.element().get_sub_element(ElementName::Ident) {
218            ident_elem.set_item_name(name)?;
219        } else {
220            self.element().create_named_sub_element(ElementName::Ident, name)?;
221        }
222        Ok(())
223    }
224}
225
226impl FlexrayTpConnection {
227    pub(crate) fn new(
228        name: Option<&str>,
229        parent: &Element,
230        transmitter: &FlexrayTpNode,
231        direct_tp_sdu: &IPdu,
232        connection_control: &FlexrayTpConnectionControl,
233    ) -> Result<Self, AutosarAbstractionError> {
234        let tp_connection_elem = parent.create_sub_element(ElementName::FlexrayTpConnection)?;
235        if let Some(name) = name {
236            tp_connection_elem.create_named_sub_element(ElementName::Ident, name)?;
237        }
238        let tp_connection = Self(tp_connection_elem);
239        tp_connection.set_transmitter(transmitter)?;
240        tp_connection.set_direct_tp_sdu(direct_tp_sdu)?;
241        tp_connection.set_connection_control(connection_control)?;
242
243        Ok(tp_connection)
244    }
245
246    /// set the transmitter of the connection
247    pub fn set_transmitter(&self, transmitter: &FlexrayTpNode) -> Result<(), AutosarAbstractionError> {
248        self.element()
249            .get_or_create_sub_element(ElementName::TransmitterRef)?
250            .set_reference_target(transmitter.element())?;
251        Ok(())
252    }
253
254    /// get the transmitter of the connection
255    #[must_use]
256    pub fn transmitter(&self) -> Option<FlexrayTpNode> {
257        self.element()
258            .get_sub_element(ElementName::TransmitterRef)
259            .and_then(|elem| elem.get_reference_target().ok())
260            .and_then(|elem| elem.try_into().ok())
261    }
262
263    /// set the direct TP SDU of the connection
264    pub fn set_direct_tp_sdu<T: AbstractIpdu>(&self, direct_tp_sdu: &T) -> Result<(), AutosarAbstractionError> {
265        self.element()
266            .get_or_create_sub_element(ElementName::DirectTpSduRef)?
267            .set_reference_target(direct_tp_sdu.element())?;
268        Ok(())
269    }
270
271    /// get the direct TP SDU of the connection
272    #[must_use]
273    pub fn direct_tp_sdu(&self) -> Option<IPdu> {
274        self.element()
275            .get_sub_element(ElementName::DirectTpSduRef)
276            .and_then(|elem| elem.get_reference_target().ok())
277            .and_then(|elem| elem.try_into().ok())
278    }
279
280    /// set the connection control of the connection
281    pub fn set_connection_control(
282        &self,
283        connection_control: &FlexrayTpConnectionControl,
284    ) -> Result<(), AutosarAbstractionError> {
285        self.element()
286            .get_or_create_sub_element(ElementName::TpConnectionControlRef)?
287            .set_reference_target(connection_control.element())?;
288        Ok(())
289    }
290
291    /// get the connection control of the connection
292    #[must_use]
293    pub fn connection_control(&self) -> Option<FlexrayTpConnectionControl> {
294        self.element()
295            .get_sub_element(ElementName::TpConnectionControlRef)?
296            .get_reference_target()
297            .ok()?
298            .try_into()
299            .ok()
300    }
301
302    /// add a receiver to the connection
303    pub fn add_receiver(&self, receiver: &FlexrayTpNode) -> Result<(), AutosarAbstractionError> {
304        self.element()
305            .get_or_create_sub_element(ElementName::ReceiverRefs)?
306            .create_sub_element(ElementName::ReceiverRef)?
307            .set_reference_target(receiver.element())?;
308        Ok(())
309    }
310
311    /// iterate over all receivers of the connection
312    pub fn receivers(&self) -> impl Iterator<Item = FlexrayTpNode> + Send + use<> {
313        self.element()
314            .get_sub_element(ElementName::ReceiverRefs)
315            .into_iter()
316            .flat_map(|elem| elem.sub_elements())
317            .filter_map(|ref_elem| {
318                ref_elem
319                    .get_reference_target()
320                    .ok()
321                    .and_then(|elem| elem.try_into().ok())
322            })
323    }
324
325    /// set the reversed TP SDU of the connection
326    /// This is used if the connection supports both sending and receiving
327    pub fn set_reversed_tp_sdu<T: AbstractIpdu>(&self, reversed_tp_sdu: &T) -> Result<(), AutosarAbstractionError> {
328        self.element()
329            .get_or_create_sub_element(ElementName::ReversedTpSduRef)?
330            .set_reference_target(reversed_tp_sdu.element())?;
331        Ok(())
332    }
333
334    /// get the reversed TP SDU of the connection
335    #[must_use]
336    pub fn reversed_tp_sdu(&self) -> Option<IPdu> {
337        self.element()
338            .get_sub_element(ElementName::ReversedTpSduRef)
339            .and_then(|elem| elem.get_reference_target().ok())
340            .and_then(|elem| elem.try_into().ok())
341    }
342
343    /// set the TX `FlexrayTpPduPool` of the connection
344    pub fn set_tx_pdu_pool(&self, tx_pdu_pool: &FlexrayTpPduPool) -> Result<(), AutosarAbstractionError> {
345        self.element()
346            .get_or_create_sub_element(ElementName::TxPduPoolRef)?
347            .set_reference_target(tx_pdu_pool.element())?;
348        Ok(())
349    }
350
351    /// get the TX `FlexrayTpPduPool` of the connection
352    #[must_use]
353    pub fn tx_pdu_pool(&self) -> Option<FlexrayTpPduPool> {
354        self.element()
355            .get_sub_element(ElementName::TxPduPoolRef)
356            .and_then(|elem| elem.get_reference_target().ok())
357            .and_then(|elem| elem.try_into().ok())
358    }
359
360    /// set the RX `FlexrayTpPduPool` of the connection
361    pub fn set_rx_pdu_pool(&self, rx_pdu_pool: &FlexrayTpPduPool) -> Result<(), AutosarAbstractionError> {
362        self.element()
363            .get_or_create_sub_element(ElementName::RxPduPoolRef)?
364            .set_reference_target(rx_pdu_pool.element())?;
365        Ok(())
366    }
367
368    /// get the RX `FlexrayTpPduPool` of the connection
369    #[must_use]
370    pub fn rx_pdu_pool(&self) -> Option<FlexrayTpPduPool> {
371        self.element()
372            .get_sub_element(ElementName::RxPduPoolRef)
373            .and_then(|elem| elem.get_reference_target().ok())
374            .and_then(|elem| elem.try_into().ok())
375    }
376
377    /// set the multicast `TpAddress` of the connection
378    /// This element is optional; setting None will remove the element
379    pub fn set_multicast_address(&self, multicast_address: Option<&TpAddress>) -> Result<(), AutosarAbstractionError> {
380        if let Some(multicast_address) = multicast_address {
381            // add or update the multicast address
382            self.element()
383                .get_or_create_sub_element(ElementName::MulticastRef)?
384                .set_reference_target(multicast_address.element())?;
385        } else {
386            // remove the multicast address
387            let _ = self.element().remove_sub_element_kind(ElementName::MulticastRef);
388        }
389        Ok(())
390    }
391
392    /// get the multicast `TpAddress` of the connection
393    #[must_use]
394    pub fn multicast_address(&self) -> Option<TpAddress> {
395        self.element()
396            .get_sub_element(ElementName::MulticastRef)
397            .and_then(|elem| elem.get_reference_target().ok())
398            .and_then(|elem| elem.try_into().ok())
399    }
400}
401
402//##################################################################
403
404/// A `FlexrayTpConnectionControl` defines the connection control parameters for a `FlexrayTpConnection`
405#[derive(Debug, Clone, PartialEq, Eq, Hash)]
406pub struct FlexrayTpConnectionControl(Element);
407abstraction_element!(FlexrayTpConnectionControl, FlexrayTpConnectionControl);
408impl IdentifiableAbstractionElement for FlexrayTpConnectionControl {}
409
410impl FlexrayTpConnectionControl {
411    pub(crate) fn new(name: &str, parent: &Element) -> Result<Self, AutosarAbstractionError> {
412        let connection_control_elem = parent.create_named_sub_element(ElementName::FlexrayTpConnectionControl, name)?;
413        Ok(Self(connection_control_elem))
414    }
415
416    /// set the maxFcWait value
417    pub fn set_max_fc_wait(&self, max_fc_wait: u32) -> Result<(), AutosarAbstractionError> {
418        self.element()
419            .get_or_create_sub_element(ElementName::MaxFcWait)?
420            .set_character_data(u64::from(max_fc_wait))?;
421        Ok(())
422    }
423
424    /// get the maxFcWait value
425    #[must_use]
426    pub fn max_fc_wait(&self) -> Option<u32> {
427        self.element()
428            .get_sub_element(ElementName::MaxFcWait)?
429            .character_data()?
430            .parse_integer()
431    }
432
433    /// set the maxNumberOfNpduPerCycle value
434    pub fn set_max_number_of_npdu_per_cycle(
435        &self,
436        max_number_of_npdu_per_cycle: u32,
437    ) -> Result<(), AutosarAbstractionError> {
438        self.element()
439            .get_or_create_sub_element(ElementName::MaxNumberOfNpduPerCycle)?
440            .set_character_data(u64::from(max_number_of_npdu_per_cycle))?;
441        Ok(())
442    }
443
444    /// get the maxNumberOfNpduPerCycle value
445    #[must_use]
446    pub fn max_number_of_npdu_per_cycle(&self) -> Option<u32> {
447        self.element()
448            .get_sub_element(ElementName::MaxNumberOfNpduPerCycle)?
449            .character_data()?
450            .parse_integer()
451    }
452
453    /// set the maxRetries value
454    pub fn set_max_retries(&self, max_retries: u32) -> Result<(), AutosarAbstractionError> {
455        self.element()
456            .get_or_create_sub_element(ElementName::MaxRetries)?
457            .set_character_data(u64::from(max_retries))?;
458        Ok(())
459    }
460
461    /// get the maxRetries value
462    #[must_use]
463    pub fn max_retries(&self) -> Option<u32> {
464        self.element()
465            .get_sub_element(ElementName::MaxRetries)?
466            .character_data()?
467            .parse_integer()
468    }
469
470    /// set the separationCycleExponent value
471    pub fn set_separation_cycle_exponent(&self, separation_cycle_exponent: u32) -> Result<(), AutosarAbstractionError> {
472        self.element()
473            .get_or_create_sub_element(ElementName::SeparationCycleExponent)?
474            .set_character_data(u64::from(separation_cycle_exponent))?;
475        Ok(())
476    }
477
478    /// get the separationCycleExponent value
479    #[must_use]
480    pub fn separation_cycle_exponent(&self) -> Option<u32> {
481        self.element()
482            .get_sub_element(ElementName::SeparationCycleExponent)?
483            .character_data()?
484            .parse_integer()
485    }
486}
487
488//##################################################################
489
490/// A `FlexrayTpEcu` represents an ECU within the `FlexrayTpConfig`
491#[derive(Debug, Clone, PartialEq)]
492pub struct FlexrayTpEcu(Element);
493abstraction_element!(FlexrayTpEcu, FlexrayTpEcu);
494
495impl FlexrayTpEcu {
496    pub(crate) fn new(
497        parent: &Element,
498        ecu_instance: &EcuInstance,
499        full_duplex_enabled: bool,
500    ) -> Result<Self, AutosarAbstractionError> {
501        let tp_ecu_elem = parent.create_sub_element(ElementName::FlexrayTpEcu)?;
502        let tp_ecu = Self(tp_ecu_elem);
503
504        tp_ecu.set_ecu_instance(ecu_instance)?;
505        tp_ecu.set_full_duplex_enabled(full_duplex_enabled)?;
506
507        Ok(tp_ecu)
508    }
509
510    /// set the ECU instance of the `FlexrayTpEcu`
511    pub fn set_ecu_instance(&self, ecu_instance: &EcuInstance) -> Result<(), AutosarAbstractionError> {
512        self.element()
513            .get_or_create_sub_element(ElementName::EcuInstanceRef)?
514            .set_reference_target(ecu_instance.element())?;
515        Ok(())
516    }
517
518    /// get the ECU instance of the `FlexrayTpEcu`
519    #[must_use]
520    pub fn ecu_instance(&self) -> Option<EcuInstance> {
521        self.element()
522            .get_sub_element(ElementName::EcuInstanceRef)
523            .and_then(|elem| elem.get_reference_target().ok())
524            .and_then(|elem| EcuInstance::try_from(elem).ok())
525    }
526
527    /// set the full duplex enabled status of the `FlexrayTpEcu`
528    pub fn set_full_duplex_enabled(&self, full_duplex_enabled: bool) -> Result<(), AutosarAbstractionError> {
529        self.element()
530            .get_or_create_sub_element(ElementName::FullDuplexEnabled)?
531            .set_character_data(full_duplex_enabled)?;
532        Ok(())
533    }
534
535    /// get the full duplex enabled status of the `FlexrayTpEcu`
536    #[must_use]
537    pub fn full_duplex_enabled(&self) -> Option<bool> {
538        self.element()
539            .get_sub_element(ElementName::FullDuplexEnabled)
540            .and_then(|elem| elem.character_data())
541            .and_then(|cdata| cdata.parse_bool())
542    }
543
544    /// set the cycle time of the TP main function in seconds
545    pub fn set_cycle_time_main_function(
546        &self,
547        cycle_time_main_function: Option<f64>,
548    ) -> Result<(), AutosarAbstractionError> {
549        if let Some(cycle_time_main_function) = cycle_time_main_function {
550            self.element()
551                .get_or_create_sub_element(ElementName::CycleTimeMainFunction)?
552                .set_character_data(cycle_time_main_function)?;
553        } else {
554            let _ = self
555                .element()
556                .remove_sub_element_kind(ElementName::CycleTimeMainFunction);
557        }
558        Ok(())
559    }
560
561    /// get the cycle time of the TP main function in seconds
562    #[must_use]
563    pub fn cycle_time_main_function(&self) -> Option<f64> {
564        self.element()
565            .get_sub_element(ElementName::CycleTimeMainFunction)
566            .and_then(|elem| elem.character_data())
567            .and_then(|cdata| cdata.parse_float())
568    }
569
570    /// set the cancellation status of the `FlexrayTpEcu`
571    pub fn set_cancellation(&self, cancellation: Option<bool>) -> Result<(), AutosarAbstractionError> {
572        if let Some(cancellation) = cancellation {
573            self.element()
574                .get_or_create_sub_element(ElementName::Cancellation)?
575                .set_character_data(cancellation)?;
576        } else {
577            let _ = self.element().remove_sub_element_kind(ElementName::Cancellation);
578        }
579        Ok(())
580    }
581
582    /// get the cancellation status of the `FlexrayTpEcu`
583    #[must_use]
584    pub fn cancellation(&self) -> Option<bool> {
585        self.element()
586            .get_sub_element(ElementName::Cancellation)
587            .and_then(|elem| elem.character_data())
588            .and_then(|cdata| cdata.parse_bool())
589    }
590}
591
592//##################################################################
593
594/// A `FlexrayTpNode` provides the TP address and the connection to the topology description in a `FlexrayTpConfig`
595#[derive(Debug, Clone, PartialEq, Eq, Hash)]
596pub struct FlexrayTpNode(Element);
597abstraction_element!(FlexrayTpNode, FlexrayTpNode);
598impl IdentifiableAbstractionElement for FlexrayTpNode {}
599
600impl FlexrayTpNode {
601    pub(crate) fn new(name: &str, parent: &Element) -> Result<Self, AutosarAbstractionError> {
602        let node_elem = parent.create_named_sub_element(ElementName::FlexrayTpNode, name)?;
603        Ok(Self(node_elem))
604    }
605
606    /// set or remove `FlexrayTpAddress` of the node
607    /// A TP address is mandatory for unicast nodes, but optional for multicast nodes
608    /// Setting None will remove the element
609    pub fn set_tp_address(&self, tp_address: Option<&TpAddress>) -> Result<(), AutosarAbstractionError> {
610        if let Some(tp_address) = tp_address {
611            // add or update the TP address
612            self.element()
613                .get_or_create_sub_element(ElementName::TpAddressRef)?
614                .set_reference_target(tp_address.element())?;
615        } else {
616            // remove the TP address
617            if let Some(tp_address_elem) = self.element().get_sub_element(ElementName::TpAddressRef) {
618                self.element().remove_sub_element(tp_address_elem)?;
619            }
620        }
621        Ok(())
622    }
623
624    /// get the `FlexrayTpAddress` of the node
625    #[must_use]
626    pub fn tp_address(&self) -> Option<TpAddress> {
627        self.element()
628            .get_sub_element(ElementName::TpAddressRef)
629            .and_then(|elem| elem.get_reference_target().ok())
630            .and_then(|elem| elem.try_into().ok())
631    }
632
633    /// add a `FlexrayCommunicationConnector` to the node
634    /// The node can be associated with up to 2 connectors.
635    /// In a system description this reference is mandatory.
636    pub fn add_communication_connector(
637        &self,
638        connector: &FlexrayCommunicationConnector,
639    ) -> Result<(), AutosarAbstractionError> {
640        let connector_refs = self.element().get_or_create_sub_element(ElementName::ConnectorRefs)?;
641
642        if connector_refs.sub_elements().count() >= 2 {
643            return Err(AutosarAbstractionError::InvalidParameter(
644                "A FlexrayTpNode can only have up to 2 connectors".to_string(),
645            ));
646        }
647        connector_refs
648            .create_sub_element(ElementName::ConnectorRef)?
649            .set_reference_target(connector.element())?;
650        Ok(())
651    }
652
653    /// iterate over all `FlexrayCommunicationConnectors` of the node
654    pub fn communication_connectors(&self) -> impl Iterator<Item = FlexrayCommunicationConnector> + Send + use<> {
655        self.element()
656            .get_sub_element(ElementName::ConnectorRefs)
657            .into_iter()
658            .flat_map(|elem| elem.sub_elements())
659            .filter_map(|ref_elem| {
660                ref_elem
661                    .get_reference_target()
662                    .ok()
663                    .and_then(|elem| elem.try_into().ok())
664            })
665    }
666}
667
668//##################################################################
669
670#[cfg(test)]
671mod test {
672    use super::*;
673    use crate::{
674        AutosarModelAbstraction, SystemCategory,
675        communication::{DiagPduType, FlexrayChannelName, FlexrayClusterSettings},
676    };
677    use autosar_data::AutosarVersion;
678
679    #[test]
680    fn test_flexray_iso_transport_protocol() {
681        let model = AutosarModelAbstraction::create("DoipTp.arxml", AutosarVersion::LATEST);
682        let package = model.get_or_create_package("/pkg1").unwrap();
683
684        let system = package.create_system("system", SystemCategory::EcuExtract).unwrap();
685        let flexray_cluster = system
686            .create_flexray_cluster("flexray_cluster", &package, &FlexrayClusterSettings::default())
687            .unwrap();
688        let flexray_channel = flexray_cluster
689            .create_physical_channel("flexray_channel_a", FlexrayChannelName::A)
690            .unwrap();
691        let ecu_instance = system.create_ecu_instance("ecu_instance", &package).unwrap();
692        let communication_controller = ecu_instance
693            .create_flexray_communication_controller("can_ctrl")
694            .unwrap();
695        let connector = communication_controller
696            .connect_physical_channel("name", &flexray_channel)
697            .unwrap();
698
699        // create a direct TP SDU (DCM-I-PDU)
700        let tp_sdu = system
701            .create_dcm_ipdu("diag", &package, 1024, DiagPduType::DiagRequest)
702            .unwrap();
703        // create a reversed TP SDU (DCM-I-PDU)
704        let reversed_tp_sdu = system
705            .create_dcm_ipdu("diag_rev", &package, 1024, DiagPduType::DiagResponse)
706            .unwrap();
707
708        // create some NPdus
709        let npdu1 = system.create_n_pdu("npdu1", &package, 64).unwrap();
710        let npdu2 = system.create_n_pdu("npdu2", &package, 64).unwrap();
711
712        // create a FlexrayTpConfig
713        let fr_tp_config = system
714            .create_flexray_tp_config("FrTpConfig", &package, &flexray_cluster)
715            .unwrap();
716        assert_eq!(fr_tp_config.cluster().unwrap(), flexray_cluster);
717
718        // create a FlexrayTpPduPool
719        let fr_tp_pdu_pool_tx = fr_tp_config.create_flexray_tp_pdu_pool("FrTpPduPool_Tx").unwrap();
720        fr_tp_pdu_pool_tx.add_n_pdu(&npdu1).unwrap();
721        assert_eq!(fr_tp_pdu_pool_tx.n_pdus().next(), Some(npdu1));
722        let fr_tp_pdu_pool_rx = fr_tp_config.create_flexray_tp_pdu_pool("FrTpPduPool_Rx").unwrap();
723        fr_tp_pdu_pool_rx.add_n_pdu(&npdu2).unwrap();
724        assert_eq!(fr_tp_pdu_pool_rx.n_pdus().next(), Some(npdu2));
725
726        assert!(fr_tp_config.flexray_tp_pdu_pools().count() == 2);
727
728        // create a FlexrayTpAddress
729        let tp_address_1 = fr_tp_config.create_tp_address("TpAddress1", 0x1234).unwrap();
730        assert_eq!(fr_tp_config.tp_addresses().next(), Some(tp_address_1.clone()));
731        assert_eq!(tp_address_1.address().unwrap(), 0x1234);
732        let tp_address_2 = fr_tp_config.create_tp_address("TpAddress2", 0x5678).unwrap();
733        assert_eq!(fr_tp_config.tp_addresses().count(), 2);
734
735        // create a FlexrayTpNode
736        let tp_node_1 = fr_tp_config.create_flexray_tp_node("TpNode1").unwrap();
737        tp_node_1.set_tp_address(Some(&tp_address_1)).unwrap();
738        assert_eq!(tp_node_1.tp_address().unwrap(), tp_address_1);
739        tp_node_1.add_communication_connector(&connector).unwrap();
740        assert_eq!(tp_node_1.communication_connectors().next(), Some(connector));
741        let tp_node_2 = fr_tp_config.create_flexray_tp_node("TpNode2").unwrap();
742        tp_node_2.set_tp_address(Some(&tp_address_2)).unwrap();
743
744        assert_eq!(fr_tp_config.flexray_tp_nodes().count(), 2);
745        assert_eq!(fr_tp_config.flexray_tp_nodes().next(), Some(tp_node_1.clone()));
746
747        // create a FlexrayTpConnectionControl
748        let connection_control = fr_tp_config
749            .create_flexray_tp_connection_control("ConnectionControl")
750            .unwrap();
751        assert_eq!(fr_tp_config.flexray_tp_connection_controls().count(), 1);
752        assert_eq!(
753            fr_tp_config.flexray_tp_connection_controls().next().unwrap(),
754            connection_control
755        );
756        connection_control.set_max_fc_wait(10).unwrap();
757        assert_eq!(connection_control.max_fc_wait().unwrap(), 10);
758        connection_control.set_max_number_of_npdu_per_cycle(5).unwrap();
759        assert_eq!(connection_control.max_number_of_npdu_per_cycle().unwrap(), 5);
760        connection_control.set_max_retries(3).unwrap();
761        assert_eq!(connection_control.max_retries().unwrap(), 3);
762        connection_control.set_separation_cycle_exponent(2).unwrap();
763        assert_eq!(connection_control.separation_cycle_exponent().unwrap(), 2);
764
765        // create a FlexrayTpConnection
766        let connection = fr_tp_config
767            .create_flexray_tp_connection(None, &tp_node_1, &tp_sdu, &connection_control)
768            .unwrap();
769        assert_eq!(fr_tp_config.flexray_tp_connections().count(), 1);
770        assert_eq!(fr_tp_config.flexray_tp_connections().next().unwrap(), connection);
771
772        connection.add_receiver(&tp_node_2).unwrap();
773        connection.set_tx_pdu_pool(&fr_tp_pdu_pool_tx).unwrap();
774        connection.set_rx_pdu_pool(&fr_tp_pdu_pool_rx).unwrap();
775        connection.set_multicast_address(Some(&tp_address_2)).unwrap();
776        connection.set_reversed_tp_sdu(&reversed_tp_sdu).unwrap();
777        assert_eq!(connection.receivers().count(), 1);
778        assert_eq!(connection.receivers().next(), Some(tp_node_2));
779        assert_eq!(connection.tx_pdu_pool().unwrap(), fr_tp_pdu_pool_tx);
780        assert_eq!(connection.rx_pdu_pool().unwrap(), fr_tp_pdu_pool_rx);
781        assert_eq!(connection.multicast_address().unwrap(), tp_address_2);
782        assert_eq!(connection.connection_control().unwrap(), connection_control);
783        assert_eq!(connection.transmitter().unwrap(), tp_node_1);
784        assert_eq!(connection.direct_tp_sdu().unwrap(), tp_sdu.clone().into());
785        assert_eq!(connection.reversed_tp_sdu().unwrap(), reversed_tp_sdu.clone().into());
786
787        assert_eq!(connection.name(), None);
788        connection.set_name("Connection1").unwrap();
789        assert_eq!(connection.name(), Some("Connection1".to_string()));
790
791        // add a FlexrayTpEcu to the FlexrayTpConfig
792        let fr_tp_ecu = fr_tp_config.create_flexray_tp_ecu(&ecu_instance, true).unwrap();
793        fr_tp_ecu.set_cycle_time_main_function(Some(0.01)).unwrap();
794        fr_tp_ecu.set_cancellation(Some(true)).unwrap();
795        assert_eq!(fr_tp_config.flexray_tp_ecus().count(), 1);
796        assert_eq!(fr_tp_config.flexray_tp_ecus().next().unwrap(), fr_tp_ecu);
797        assert_eq!(fr_tp_ecu.ecu_instance().unwrap(), ecu_instance);
798        assert!(fr_tp_ecu.full_duplex_enabled().unwrap());
799        assert_eq!(fr_tp_ecu.cycle_time_main_function().unwrap(), 0.01);
800        assert!(fr_tp_ecu.cancellation().unwrap());
801    }
802}