autosar_data_abstraction/communication/cluster/
flexray.rs

1use crate::{
2    AbstractionElement, ArPackage, AutosarAbstractionError, IdentifiableAbstractionElement, abstraction_element,
3    communication::{
4        AbstractCluster, FlexrayArTpConfig, FlexrayChannelName, FlexrayNmCluster, FlexrayPhysicalChannel,
5        FlexrayTpConfig,
6    },
7    get_reference_parents,
8};
9use autosar_data::{Element, ElementName, EnumItem};
10
11/// A `FlexrayCluster` contains all configuration items associated with a Flexray network.
12/// The cluster connects multiple ECUs.
13#[derive(Debug, Clone, PartialEq, Eq, Hash)]
14pub struct FlexrayCluster(Element);
15abstraction_element!(FlexrayCluster, FlexrayCluster);
16impl IdentifiableAbstractionElement for FlexrayCluster {}
17
18impl FlexrayCluster {
19    // create a new FlexrayCluster - internal use only. User code should call System::create_flexray_cluster
20    pub(crate) fn new(
21        name: &str,
22        package: &ArPackage,
23        settings: &FlexrayClusterSettings,
24    ) -> Result<Self, AutosarAbstractionError> {
25        let elem_pkg_elements = package.element().get_or_create_sub_element(ElementName::Elements)?;
26        let elem_cluster = elem_pkg_elements.create_named_sub_element(ElementName::FlexrayCluster, name)?;
27        if let Ok(cluster_content) = elem_cluster
28            .create_sub_element(ElementName::FlexrayClusterVariants)
29            .and_then(|fcv| fcv.create_sub_element(ElementName::FlexrayClusterConditional))
30        {
31            cluster_content
32                .create_sub_element(ElementName::ProtocolName)
33                .and_then(|pn| pn.set_character_data("FlexRay"))?;
34            cluster_content
35                .create_sub_element(ElementName::ProtocolVersion)
36                .and_then(|pv| pv.set_character_data("2.1"))?;
37
38            cluster_content.create_sub_element(ElementName::PhysicalChannels)?;
39        }
40
41        let flexray_cluster = FlexrayCluster(elem_cluster);
42        flexray_cluster.update_settings(settings);
43
44        Ok(flexray_cluster)
45    }
46
47    /// remove this `FlexrayCluster` from the model
48    pub fn remove(self, deep: bool) -> Result<(), AutosarAbstractionError> {
49        // remove the physical channels, if they exist
50        let channels_info = self.physical_channels();
51        if let Some(channel_a) = channels_info.channel_a {
52            channel_a.remove(deep)?;
53        }
54        if let Some(channel_b) = channels_info.channel_b {
55            channel_b.remove(deep)?;
56        }
57        let ref_parents = get_reference_parents(self.element())?;
58
59        // delegate to the trait implementation to clean up all other references to the element and the element itself
60        AbstractionElement::remove(self, deep)?;
61
62        // check if any FlexrayTpConfig, FlexrayArTpConfig or FlexrayNmCluster uses this FlexrayCluster
63        // The cluster reference is mandatory these elements, so we remove them together with the cluster
64        for (named_parent, _parent) in ref_parents {
65            match named_parent.element_name() {
66                ElementName::FlexrayTpConfig => {
67                    if let Ok(flexray_tp_config) = FlexrayTpConfig::try_from(named_parent) {
68                        flexray_tp_config.remove(deep)?;
69                    }
70                }
71                ElementName::FlexrayArTpConfig => {
72                    if let Ok(flexray_ar_tp_config) = FlexrayArTpConfig::try_from(named_parent) {
73                        flexray_ar_tp_config.remove(deep)?;
74                    }
75                }
76                ElementName::FlexrayNmCluster => {
77                    if let Ok(flexray_nm_cluster) = FlexrayNmCluster::try_from(named_parent) {
78                        flexray_nm_cluster.remove(deep)?;
79                    }
80                }
81                _ => {}
82            }
83        }
84
85        Ok(())
86    }
87
88    /// update the cluster settings
89    ///
90    /// The settings of a flexray cluster determine all the details of timing and slot layout.
91    /// These settings are subject to multiple cross dependencies and constraints.
92    ///
93    /// You may check the validity of the settings by calling [`FlexrayClusterSettings::verify`].
94    ///
95    /// However, the update function does not require that the settings are valid, and will
96    /// also update the model with invalid settings if desired.
97    ///
98    /// # Example
99    ///
100    /// ```
101    /// # use autosar_data::*;
102    /// # use autosar_data_abstraction::*;
103    /// # use autosar_data_abstraction::communication::*;
104    /// # fn main() -> Result<(), AutosarAbstractionError> {
105    /// # let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
106    /// # let package = model.get_or_create_package("/pkg1")?;
107    /// # let system = package.create_system("System", SystemCategory::SystemExtract)?;
108    /// let cluster = system.create_flexray_cluster("Cluster", &package, &FlexrayClusterSettings::default())?;
109    /// let mut settings = cluster.settings();
110    /// settings.macro_per_cycle = 5000;
111    /// cluster.update_settings(&settings);
112    /// # Ok(())}
113    /// ```
114    pub fn update_settings(&self, settings: &FlexrayClusterSettings) {
115        if let Ok(cluster_content) = self
116            .0
117            .get_or_create_sub_element(ElementName::FlexrayClusterVariants)
118            .and_then(|fcv| fcv.get_or_create_sub_element(ElementName::FlexrayClusterConditional))
119        {
120            let _ = cluster_content
121                .get_or_create_sub_element(ElementName::Baudrate)
122                .and_then(|br| br.set_character_data(settings.baudrate.to_string()));
123            let _ = cluster_content
124                .get_or_create_sub_element(ElementName::ActionPointOffset)
125                .and_then(|apo| apo.set_character_data(settings.action_point_offset.to_string()));
126            let _ = cluster_content
127                .get_or_create_sub_element(ElementName::Bit)
128                .and_then(|bit| bit.set_character_data(settings.bit));
129            let _ = cluster_content
130                .get_or_create_sub_element(ElementName::CasRxLowMax)
131                .and_then(|crlm| crlm.set_character_data(settings.cas_rx_low_max.to_string()));
132            let _ = cluster_content
133                .get_or_create_sub_element(ElementName::ColdStartAttempts)
134                .and_then(|csa| csa.set_character_data(settings.cold_start_attempts.to_string()));
135            let _ = cluster_content
136                .get_or_create_sub_element(ElementName::Cycle)
137                .and_then(|apo| apo.set_character_data(settings.cycle));
138            let _ = cluster_content
139                .get_or_create_sub_element(ElementName::CycleCountMax)
140                .and_then(|ccm| ccm.set_character_data(settings.cycle_count_max.to_string()));
141            let _ = cluster_content
142                .get_or_create_sub_element(ElementName::DetectNitError)
143                .and_then(|dne| dne.set_character_data(settings.detect_nit_error.to_string()));
144            let _ = cluster_content
145                .get_or_create_sub_element(ElementName::DynamicSlotIdlePhase)
146                .and_then(|dsip| dsip.set_character_data(settings.dynamic_slot_idle_phase.to_string()));
147            let _ = cluster_content
148                .get_or_create_sub_element(ElementName::IgnoreAfterTx)
149                .and_then(|iat| iat.set_character_data(settings.ignore_after_tx.to_string()));
150            let _ = cluster_content
151                .get_or_create_sub_element(ElementName::ListenNoise)
152                .and_then(|ln| ln.set_character_data(settings.listen_noise.to_string()));
153            let _ = cluster_content
154                .get_or_create_sub_element(ElementName::MacroPerCycle)
155                .and_then(|mpc| mpc.set_character_data(settings.macro_per_cycle.to_string()));
156            let _ = cluster_content
157                .get_or_create_sub_element(ElementName::MacrotickDuration)
158                .and_then(|mpc| mpc.set_character_data(settings.macrotick_duration));
159            let _ = cluster_content
160                .get_or_create_sub_element(ElementName::MaxWithoutClockCorrectionFatal)
161                .and_then(|mwccf| mwccf.set_character_data(settings.max_without_clock_correction_fatal.to_string()));
162            let _ = cluster_content
163                .get_or_create_sub_element(ElementName::MaxWithoutClockCorrectionPassive)
164                .and_then(|mwccp| mwccp.set_character_data(settings.max_without_clock_correction_passive.to_string()));
165            let _ = cluster_content
166                .get_or_create_sub_element(ElementName::MinislotActionPointOffset)
167                .and_then(|mapo| mapo.set_character_data(settings.minislot_action_point_offset.to_string()));
168            let _ = cluster_content
169                .get_or_create_sub_element(ElementName::MinislotDuration)
170                .and_then(|md| md.set_character_data(settings.minislot_duration.to_string()));
171            let _ = cluster_content
172                .get_or_create_sub_element(ElementName::NetworkIdleTime)
173                .and_then(|nit| nit.set_character_data(settings.network_idle_time.to_string()));
174            let _ = cluster_content
175                .get_or_create_sub_element(ElementName::NetworkManagementVectorLength)
176                .and_then(|nmvl| nmvl.set_character_data(settings.network_management_vector_length.to_string()));
177            let _ = cluster_content
178                .get_or_create_sub_element(ElementName::NumberOfMinislots)
179                .and_then(|nom| nom.set_character_data(settings.number_of_minislots.to_string()));
180            let _ = cluster_content
181                .get_or_create_sub_element(ElementName::NumberOfStaticSlots)
182                .and_then(|noss| noss.set_character_data(settings.number_of_static_slots.to_string()));
183            let _ = cluster_content
184                .get_or_create_sub_element(ElementName::OffsetCorrectionStart)
185                .and_then(|ocs| ocs.set_character_data(settings.offset_correction_start.to_string()));
186            let _ = cluster_content
187                .get_or_create_sub_element(ElementName::PayloadLengthStatic)
188                .and_then(|pls| pls.set_character_data(settings.payload_length_static.to_string()));
189            let _ = cluster_content
190                .get_or_create_sub_element(ElementName::SafetyMargin)
191                .and_then(|sm| sm.set_character_data(settings.safety_margin.to_string()));
192            if let Some(sample_clock_period) = settings.sample_clock_period {
193                let _ = cluster_content
194                    .get_or_create_sub_element(ElementName::SampleClockPeriod)
195                    .and_then(|scp| scp.set_character_data(sample_clock_period));
196            } else if let Some(scp) = cluster_content.get_sub_element(ElementName::SampleClockPeriod) {
197                let _ = cluster_content.remove_sub_element(scp);
198            }
199            let _ = cluster_content
200                .get_or_create_sub_element(ElementName::StaticSlotDuration)
201                .and_then(|ssd| ssd.set_character_data(settings.static_slot_duration.to_string()));
202            let _ = cluster_content
203                .get_or_create_sub_element(ElementName::SymbolWindow)
204                .and_then(|sw| sw.set_character_data(settings.symbol_window.to_string()));
205
206            if let Some(symbol_window_action_point_offset) = settings.symbol_window_action_point_offset {
207                let _ = cluster_content
208                    .get_or_create_sub_element(ElementName::SymbolWindowActionPointOffset)
209                    .and_then(|swapo| swapo.set_character_data(symbol_window_action_point_offset.to_string()));
210            } else if let Some(swapo) = cluster_content.get_sub_element(ElementName::SymbolWindowActionPointOffset) {
211                let _ = cluster_content.remove_sub_element(swapo);
212            }
213            let _ = cluster_content
214                .get_or_create_sub_element(ElementName::SyncFrameIdCountMax)
215                .and_then(|sficm| sficm.set_character_data(settings.sync_frame_id_count_max.to_string()));
216            if let Some(transceiver_standby_delay) = settings.transceiver_standby_delay {
217                let _ = cluster_content
218                    .get_or_create_sub_element(ElementName::TranceiverStandbyDelay)
219                    .and_then(|tsd| tsd.set_character_data(transceiver_standby_delay));
220            } else if let Some(tsd) = cluster_content.get_sub_element(ElementName::TranceiverStandbyDelay) {
221                let _ = cluster_content.remove_sub_element(tsd);
222            }
223            let _ = cluster_content
224                .get_or_create_sub_element(ElementName::TransmissionStartSequenceDuration)
225                .and_then(|tssd| tssd.set_character_data(settings.transmission_start_sequence_duration.to_string()));
226            let _ = cluster_content
227                .get_or_create_sub_element(ElementName::WakeupRxIdle)
228                .and_then(|wri| wri.set_character_data(settings.wakeup_rx_idle.to_string()));
229            let _ = cluster_content
230                .get_or_create_sub_element(ElementName::WakeupRxLow)
231                .and_then(|wrl| wrl.set_character_data(settings.wakeup_rx_low.to_string()));
232            let _ = cluster_content
233                .get_or_create_sub_element(ElementName::WakeupRxWindow)
234                .and_then(|wrw| wrw.set_character_data(settings.wakeup_rx_window.to_string()));
235            let _ = cluster_content
236                .get_or_create_sub_element(ElementName::WakeupTxActive)
237                .and_then(|wta| wta.set_character_data(settings.wakeup_tx_active.to_string()));
238            let _ = cluster_content
239                .get_or_create_sub_element(ElementName::WakeupTxIdle)
240                .and_then(|wti| wti.set_character_data(settings.wakeup_tx_idle.to_string()));
241        }
242    }
243
244    /// retrieve the current flexray cluster settings from a [`FlexrayCluster`]
245    ///
246    /// # Example
247    ///
248    /// ```
249    /// # use autosar_data::*;
250    /// # use autosar_data_abstraction::*;
251    /// # use autosar_data_abstraction::communication::*;
252    /// # fn main() -> Result<(), AutosarAbstractionError> {
253    /// # let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
254    /// # let package = model.get_or_create_package("/pkg1")?;
255    /// # let system = package.create_system("System", SystemCategory::SystemExtract)?;
256    /// # let mut settings_in = FlexrayClusterSettings::default();
257    /// # settings_in.macro_per_cycle = 5000;
258    /// let cluster = system.create_flexray_cluster("Cluster", &package, &settings_in)?;
259    /// let settings = cluster.settings();
260    /// # assert_eq!(settings_in, settings);
261    /// # Ok(())}
262    /// ```
263    #[must_use]
264    pub fn settings(&self) -> FlexrayClusterSettings {
265        let mut settings = FlexrayClusterSettings {
266            baudrate: 0,
267            action_point_offset: 0,
268            bit: 0.0,
269            cas_rx_low_max: 0,
270            cold_start_attempts: 0,
271            cycle: 0.0,
272            cycle_count_max: 0,
273            detect_nit_error: false,
274            dynamic_slot_idle_phase: 0,
275            ignore_after_tx: 0,
276            listen_noise: 0,
277            macro_per_cycle: 0,
278            macrotick_duration: 0.0,
279            max_without_clock_correction_fatal: 0,
280            max_without_clock_correction_passive: 0,
281            minislot_action_point_offset: 0,
282            minislot_duration: 0,
283            network_idle_time: 0,
284            network_management_vector_length: 0,
285            number_of_minislots: 0,
286            number_of_static_slots: 0,
287            offset_correction_start: 0,
288            payload_length_static: 0,
289            safety_margin: 0,
290            sample_clock_period: None,
291            static_slot_duration: 0,
292            symbol_window: 0,
293            symbol_window_action_point_offset: None,
294            sync_frame_id_count_max: 0,
295            transceiver_standby_delay: None,
296            transmission_start_sequence_duration: 0,
297            wakeup_rx_idle: 0,
298            wakeup_rx_low: 0,
299            wakeup_rx_window: 0,
300            wakeup_tx_active: 0,
301            wakeup_tx_idle: 0,
302        };
303
304        if let Some(cluster_content) = self
305            .0
306            .get_sub_element(ElementName::FlexrayClusterVariants)
307            .and_then(|fcv| fcv.get_sub_element(ElementName::FlexrayClusterConditional))
308        {
309            if let Some(baudrate) = cluster_content
310                .get_sub_element(ElementName::Baudrate)
311                .and_then(|br| br.character_data())
312                .and_then(|cdata| cdata.parse_integer())
313            {
314                settings.baudrate = baudrate;
315            }
316            if let Some(action_point_offset) = cluster_content
317                .get_sub_element(ElementName::ActionPointOffset)
318                .and_then(|apo| apo.character_data())
319                .and_then(|cdata| cdata.parse_integer())
320            {
321                settings.action_point_offset = action_point_offset;
322            }
323            if let Some(bit) = cluster_content
324                .get_sub_element(ElementName::Bit)
325                .and_then(|bit| bit.character_data())
326                .and_then(|cdata| cdata.float_value())
327            {
328                settings.bit = bit;
329            }
330            if let Some(cas_rx_low_max) = cluster_content
331                .get_sub_element(ElementName::CasRxLowMax)
332                .and_then(|crlm| crlm.character_data())
333                .and_then(|cdata| cdata.parse_integer())
334            {
335                settings.cas_rx_low_max = cas_rx_low_max;
336            }
337            if let Some(cold_start_attempts) = cluster_content
338                .get_sub_element(ElementName::ColdStartAttempts)
339                .and_then(|csa| csa.character_data())
340                .and_then(|cdata| cdata.parse_integer())
341            {
342                settings.cold_start_attempts = cold_start_attempts;
343            }
344            if let Some(cycle) = cluster_content
345                .get_sub_element(ElementName::Cycle)
346                .and_then(|apo| apo.character_data())
347                .and_then(|cdata| cdata.float_value())
348            {
349                settings.cycle = cycle;
350            }
351            if let Some(cycle_count_max) = cluster_content
352                .get_sub_element(ElementName::CycleCountMax)
353                .and_then(|ccm| ccm.character_data())
354                .and_then(|cdata| cdata.parse_integer())
355            {
356                settings.cycle_count_max = cycle_count_max;
357            }
358            if let Some(detect_nit_error) = cluster_content
359                .get_sub_element(ElementName::DetectNitError)
360                .and_then(|dne| dne.character_data())
361                .and_then(|cdata| cdata.string_value())
362            {
363                settings.detect_nit_error = (detect_nit_error == "true") || (detect_nit_error == "1");
364            }
365            if let Some(dynamic_slot_idle_phase) = cluster_content
366                .get_sub_element(ElementName::DynamicSlotIdlePhase)
367                .and_then(|dsip| dsip.character_data())
368                .and_then(|cdata| cdata.parse_integer())
369            {
370                settings.dynamic_slot_idle_phase = dynamic_slot_idle_phase;
371            }
372            if let Some(ignore_after_tx) = cluster_content
373                .get_sub_element(ElementName::IgnoreAfterTx)
374                .and_then(|iat| iat.character_data())
375                .and_then(|cdata| cdata.parse_integer())
376            {
377                settings.ignore_after_tx = ignore_after_tx;
378            }
379            if let Some(listen_noise) = cluster_content
380                .get_sub_element(ElementName::ListenNoise)
381                .and_then(|ln| ln.character_data())
382                .and_then(|cdata| cdata.parse_integer())
383            {
384                settings.listen_noise = listen_noise;
385            }
386            if let Some(macro_per_cycle) = cluster_content
387                .get_sub_element(ElementName::MacroPerCycle)
388                .and_then(|mpc| mpc.character_data())
389                .and_then(|cdata| cdata.parse_integer())
390            {
391                settings.macro_per_cycle = macro_per_cycle;
392            }
393            if let Some(macrotick_duration) = cluster_content
394                .get_sub_element(ElementName::MacrotickDuration)
395                .and_then(|mpc| mpc.character_data())
396                .and_then(|cdata| cdata.float_value())
397            {
398                settings.macrotick_duration = macrotick_duration;
399            }
400            if let Some(max_without_clock_correction_fatal) = cluster_content
401                .get_sub_element(ElementName::MaxWithoutClockCorrectionFatal)
402                .and_then(|mwccf| mwccf.character_data())
403                .and_then(|cdata| cdata.parse_integer())
404            {
405                settings.max_without_clock_correction_fatal = max_without_clock_correction_fatal;
406            }
407            if let Some(max_without_clock_correction_passive) = cluster_content
408                .get_sub_element(ElementName::MaxWithoutClockCorrectionPassive)
409                .and_then(|mwccp| mwccp.character_data())
410                .and_then(|cdata| cdata.parse_integer())
411            {
412                settings.max_without_clock_correction_passive = max_without_clock_correction_passive;
413            }
414            if let Some(minislot_action_point_offset) = cluster_content
415                .get_sub_element(ElementName::MinislotActionPointOffset)
416                .and_then(|mapo| mapo.character_data())
417                .and_then(|cdata| cdata.parse_integer())
418            {
419                settings.minislot_action_point_offset = minislot_action_point_offset;
420            }
421            if let Some(minislot_duration) = cluster_content
422                .get_sub_element(ElementName::MinislotDuration)
423                .and_then(|md| md.character_data())
424                .and_then(|cdata| cdata.parse_integer())
425            {
426                settings.minislot_duration = minislot_duration;
427            }
428            if let Some(network_idle_time) = cluster_content
429                .get_sub_element(ElementName::NetworkIdleTime)
430                .and_then(|nit| nit.character_data())
431                .and_then(|cdata| cdata.parse_integer())
432            {
433                settings.network_idle_time = network_idle_time;
434            }
435            if let Some(network_management_vector_length) = cluster_content
436                .get_sub_element(ElementName::NetworkManagementVectorLength)
437                .and_then(|nmvl| nmvl.character_data())
438                .and_then(|cdata| cdata.parse_integer())
439            {
440                settings.network_management_vector_length = network_management_vector_length;
441            }
442            if let Some(number_of_minislots) = cluster_content
443                .get_sub_element(ElementName::NumberOfMinislots)
444                .and_then(|nom| nom.character_data())
445                .and_then(|cdata| cdata.parse_integer())
446            {
447                settings.number_of_minislots = number_of_minislots;
448            }
449            if let Some(number_of_static_slots) = cluster_content
450                .get_sub_element(ElementName::NumberOfStaticSlots)
451                .and_then(|noss| noss.character_data())
452                .and_then(|cdata| cdata.parse_integer())
453            {
454                settings.number_of_static_slots = number_of_static_slots;
455            }
456            if let Some(offset_correction_start) = cluster_content
457                .get_sub_element(ElementName::OffsetCorrectionStart)
458                .and_then(|ocs| ocs.character_data())
459                .and_then(|cdata| cdata.parse_integer())
460            {
461                settings.offset_correction_start = offset_correction_start;
462            }
463            if let Some(payload_length_static) = cluster_content
464                .get_sub_element(ElementName::PayloadLengthStatic)
465                .and_then(|pls| pls.character_data())
466                .and_then(|cdata| cdata.parse_integer())
467            {
468                settings.payload_length_static = payload_length_static;
469            }
470            if let Some(safety_margin) = cluster_content
471                .get_sub_element(ElementName::SafetyMargin)
472                .and_then(|sm| sm.character_data())
473                .and_then(|cdata| cdata.parse_integer())
474            {
475                settings.safety_margin = safety_margin;
476            }
477
478            settings.sample_clock_period = cluster_content
479                .get_sub_element(ElementName::SampleClockPeriod)
480                .and_then(|scp| scp.character_data())
481                .and_then(|cdata| cdata.float_value());
482
483            if let Some(static_slot_duration) = cluster_content
484                .get_sub_element(ElementName::StaticSlotDuration)
485                .and_then(|ssd| ssd.character_data())
486                .and_then(|cdata| cdata.parse_integer())
487            {
488                settings.static_slot_duration = static_slot_duration;
489            }
490            if let Some(symbol_window) = cluster_content
491                .get_sub_element(ElementName::SymbolWindow)
492                .and_then(|sw| sw.character_data())
493                .and_then(|cdata| cdata.parse_integer())
494            {
495                settings.symbol_window = symbol_window;
496            }
497            settings.symbol_window_action_point_offset = cluster_content
498                .get_sub_element(ElementName::SymbolWindowActionPointOffset)
499                .and_then(|swapo| swapo.character_data())
500                .and_then(|cdata| cdata.parse_integer());
501
502            if let Some(sync_frame_id_count_max) = cluster_content
503                .get_sub_element(ElementName::SyncFrameIdCountMax)
504                .and_then(|sficm| sficm.character_data())
505                .and_then(|cdata| cdata.parse_integer())
506            {
507                settings.sync_frame_id_count_max = sync_frame_id_count_max;
508            }
509
510            settings.transceiver_standby_delay = cluster_content
511                .get_sub_element(ElementName::TranceiverStandbyDelay)
512                .and_then(|tsd| tsd.character_data())
513                .and_then(|cdata| cdata.float_value());
514
515            if let Some(transmission_start_sequence_duration) = cluster_content
516                .get_sub_element(ElementName::TransmissionStartSequenceDuration)
517                .and_then(|tssd| tssd.character_data())
518                .and_then(|cdata| cdata.parse_integer())
519            {
520                settings.transmission_start_sequence_duration = transmission_start_sequence_duration;
521            }
522            if let Some(wakeup_rx_idle) = cluster_content
523                .get_sub_element(ElementName::WakeupRxIdle)
524                .and_then(|wri| wri.character_data())
525                .and_then(|cdata| cdata.parse_integer())
526            {
527                settings.wakeup_rx_idle = wakeup_rx_idle;
528            }
529            if let Some(wakeup_rx_low) = cluster_content
530                .get_sub_element(ElementName::WakeupRxLow)
531                .and_then(|wrl| wrl.character_data())
532                .and_then(|cdata| cdata.parse_integer())
533            {
534                settings.wakeup_rx_low = wakeup_rx_low;
535            }
536            if let Some(wakeup_rx_window) = cluster_content
537                .get_sub_element(ElementName::WakeupRxWindow)
538                .and_then(|wrw| wrw.character_data())
539                .and_then(|cdata| cdata.parse_integer())
540            {
541                settings.wakeup_rx_window = wakeup_rx_window;
542            }
543            if let Some(wakeup_tx_active) = cluster_content
544                .get_sub_element(ElementName::WakeupTxActive)
545                .and_then(|wta| wta.character_data())
546                .and_then(|cdata| cdata.parse_integer())
547            {
548                settings.wakeup_tx_active = wakeup_tx_active;
549            }
550            if let Some(wakeup_tx_idle) = cluster_content
551                .get_sub_element(ElementName::WakeupTxIdle)
552                .and_then(|wti| wti.character_data())
553                .and_then(|cdata| cdata.parse_integer())
554            {
555                settings.wakeup_tx_idle = wakeup_tx_idle;
556            }
557        }
558
559        settings
560    }
561
562    /// Create a new physical channel for the cluster
563    ///
564    /// A cluster may contain channel A, channel B, or both A and B.
565    ///
566    /// # Example
567    ///
568    /// ```
569    /// # use autosar_data::*;
570    /// # use autosar_data_abstraction::*;
571    /// # use autosar_data_abstraction::communication::*;
572    /// # fn main() -> Result<(), AutosarAbstractionError> {
573    /// # let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
574    /// # let package = model.get_or_create_package("/pkg1")?;
575    /// # let system = package.create_system("System", SystemCategory::SystemExtract)?;
576    /// # let settings = FlexrayClusterSettings::default();
577    /// let cluster = system.create_flexray_cluster("Cluster", &package, &settings)?;
578    /// let channel = cluster.create_physical_channel("Channel", FlexrayChannelName::A)?;
579    /// # Ok(())}
580    /// ```
581    ///
582    /// # Errors
583    ///
584    /// - [`AutosarAbstractionError::ItemAlreadyExists`] There is already a physical channel in this CAN cluster
585    /// - [`AutosarAbstractionError::ModelError`] An error occurred in the Autosar model while trying to create the ECU-INSTANCE
586    pub fn create_physical_channel(
587        &self,
588        name: &str,
589        channel_name: FlexrayChannelName,
590    ) -> Result<FlexrayPhysicalChannel, AutosarAbstractionError> {
591        let phys_channels = self
592            .0
593            .get_or_create_sub_element(ElementName::FlexrayClusterVariants)?
594            .get_or_create_sub_element(ElementName::FlexrayClusterConditional)?
595            .get_or_create_sub_element(ElementName::PhysicalChannels)?;
596
597        for existing_channel in phys_channels.sub_elements() {
598            if let Some(existing_channel_name) = FlexrayPhysicalChannel::try_from(existing_channel)
599                .ok()
600                .and_then(|channel| channel.channel_name())
601                && existing_channel_name == channel_name
602            {
603                return Err(AutosarAbstractionError::ItemAlreadyExists);
604            }
605        }
606
607        let channel = phys_channels.create_named_sub_element(ElementName::FlexrayPhysicalChannel, name)?;
608
609        let cn_item = match channel_name {
610            FlexrayChannelName::A => EnumItem::ChannelA,
611            FlexrayChannelName::B => EnumItem::ChannelB,
612        };
613
614        let _ = channel
615            .create_sub_element(ElementName::ChannelName)
616            .and_then(|cn| cn.set_character_data(cn_item));
617
618        FlexrayPhysicalChannel::try_from(channel)
619    }
620
621    /// get the physical channels of this cluster
622    ///
623    /// # Example
624    ///
625    /// ```
626    /// # use autosar_data::*;
627    /// # use autosar_data_abstraction::*;
628    /// # use autosar_data_abstraction::communication::*;
629    /// # fn main() -> Result<(), AutosarAbstractionError> {
630    /// # let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
631    /// # let package = model.get_or_create_package("/pkg1")?;
632    /// # let system = package.create_system("System", SystemCategory::SystemExtract)?;
633    /// let cluster = system.create_flexray_cluster("Cluster", &package, &FlexrayClusterSettings::default())?;
634    /// let channel = cluster.create_physical_channel("Channel", FlexrayChannelName::A)?;
635    /// # Ok(())}
636    /// ```
637    #[must_use]
638    pub fn physical_channels(&self) -> FlexrayPhysicalChannelsInfo {
639        let mut channel_info = FlexrayPhysicalChannelsInfo {
640            channel_a: None,
641            channel_b: None,
642        };
643        if let Some(phys_channels) = self
644            .0
645            .get_sub_element(ElementName::FlexrayClusterVariants)
646            .and_then(|fcv| fcv.get_sub_element(ElementName::FlexrayClusterConditional))
647            .and_then(|fcc| fcc.get_sub_element(ElementName::PhysicalChannels))
648        {
649            for channel_elem in phys_channels.sub_elements() {
650                if let Ok(channel) = FlexrayPhysicalChannel::try_from(channel_elem) {
651                    match channel.channel_name() {
652                        Some(FlexrayChannelName::A) => channel_info.channel_a = Some(channel),
653                        Some(FlexrayChannelName::B) => channel_info.channel_b = Some(channel),
654                        None => {}
655                    }
656                }
657            }
658        }
659        channel_info
660    }
661}
662
663impl AbstractCluster for FlexrayCluster {}
664
665//##################################################################
666
667/// Information about the flexray physical channels present inside a cluster
668#[derive(Debug, Clone, PartialEq)]
669pub struct FlexrayPhysicalChannelsInfo {
670    /// channel A - it contains `FlexrayChannelName::A`
671    pub channel_a: Option<FlexrayPhysicalChannel>,
672    /// channel B - it contains `FlexrayChannelName::B`
673    pub channel_b: Option<FlexrayPhysicalChannel>,
674}
675
676//##################################################################
677
678/// Configuration settings of the Flexray cluster.
679///
680/// Refer to `AUTOSAR_TPS_SystemTemplate.pdf`, chapter 3.3.4 and Flexray 2.1a / 3.0 standard, appendix A + B
681/// for the meanings and ranges of these parameters.
682#[derive(Debug, Clone, PartialEq)]
683pub struct FlexrayClusterSettings {
684    /// baud rate of the Flexray cluster: one of 10000000 (10Mbit/s), 5000000 (5Mbit/s), 2500000 (2.5Mbit/s)
685    pub baudrate: u32,
686    /// gdActionPointOffset: Number of macroticks the action point is offset from the
687    /// beginning of a static slot or symbol window: in the range 1 - 63 MT
688    pub action_point_offset: u8,
689    /// gdBit: Nominal bit time; inverse of the baudrate: 0.1µs, 0.2µs, or 0.4µs
690    pub bit: f64,
691    /// gdCASRxLowMax: Upper limit of the CAS acceptance window. Range 67 - 99 gdBit
692    pub cas_rx_low_max: u8,
693    /// gColdStartAttempts: Maximum number of times a node in the cluster is permitted to attempt to start the cluster.
694    /// Range: 2 - 31
695    pub cold_start_attempts: u8,
696    /// gdCycle: Length of the cycle in seconds. Range: 10µs - 16000µs; typically 0.005s
697    pub cycle: f64,
698    /// cCycleCountMax. Must be 63 to conform with Flexray 2.1
699    pub cycle_count_max: u8,
700    /// Indicates whether network idle time (NIT) error status should be detected
701    pub detect_nit_error: bool,
702    /// gdDynamicSlotIdlePhase: Duration of the idle phase within a dynamic slot. Range 0 - 2
703    pub dynamic_slot_idle_phase: u8,
704    /// Duration for which the bitstrobing is paused after transmission
705    pub ignore_after_tx: u16,
706    /// gListenNoise: Upper limit for the startup listen timeout and wakeup listen timeout in the presence of noise.
707    /// Range 2 - 16
708    pub listen_noise: u8,
709    /// gMacroPerCycle: Number of macroticks in a communication cycle. Range: 10 - 16000 MT
710    pub macro_per_cycle: u16,
711    /// `macrotick_duration` \[s\] = cycle \[s\] / `macro_per_cycle`
712    pub macrotick_duration: f64,
713    /// gMaxWithoutClockCorrectionFatal: Threshold used for testing the vClockCorrectionFailed counter.
714    /// Range: <`max_without_clock_correction_passive`> - 15 even/odd cycle pairs
715    pub max_without_clock_correction_fatal: u8,
716    /// gMaxWithoutClockCorrectionPassive: Threshold used for testing the vClockCorrectionFailed counter.
717    /// Range: 1 - 15 even/odd cycle pairs
718    pub max_without_clock_correction_passive: u8,
719    /// gdMinislotActionPointOffset: Number of macroticks the minislot action point is offset from the beginning of a minislot. Range: 1 - 31 MT
720    pub minislot_action_point_offset: u8,
721    /// gdMinislot: Duration of a minislot. Range: 2 - 63 MT
722    pub minislot_duration: u8,
723    /// gdNIT: Duration of the Network Idle Time. 2 - 805 MT
724    pub network_idle_time: u16,
725    /// gNetworkManagementVectorLength: Length of the Network Management vector in a cluster. Range: 0 - 12 bytes
726    pub network_management_vector_length: u8,
727    /// gNumberOfMinislots: Number of minislots in the dynamic segment. Range: 0 - 7986
728    pub number_of_minislots: u16,
729    /// gNumberOfStaticSlots: Number of static slots in the static segment. Range: 2 - 1023
730    pub number_of_static_slots: u16,
731    /// gOffsetCorrectionStart: Start of the offset correction phase within the NIT, as MT from the start of the cycle. Range: 9 - 15999 MT
732    pub offset_correction_start: u16,
733    /// gPayloadLengthStatic: Payload length of a static frame, in two byte words. Range: 0 - 127 words
734    pub payload_length_static: u16,
735    /// Additional timespan in macroticks which takes jitter into account
736    pub safety_margin: u16,
737    /// gdSampleClockPeriod: Sample clock period. One of [1.25e-8 s, 2.5e-8 s, 5e-8 s]
738    pub sample_clock_period: Option<f64>,
739    /// gdStaticSlot: Duration of a static slot. Range: 4 - 661 MT
740    pub static_slot_duration: u16,
741    /// gdSymbolWindow: Duration of the symbol window. Range: 0 - 142 MT
742    pub symbol_window: u8,
743    /// Flexray 3.0 only: Number of Macroticks the action point is offset from the beginning of the symbol window. Range: 1 - 63 MT
744    pub symbol_window_action_point_offset: Option<u8>,
745    /// gSyncNodeMax: Maximum number of nodes that may send frames with the sync frame indicator bit set to one. Range: 2 - 15
746    pub sync_frame_id_count_max: u8,
747    /// The duration of timer `t_TrcvStdbyDelay` in seconds.
748    pub transceiver_standby_delay: Option<f64>,
749    /// gdTSSTransmitter: Number of bits in the Transmission Start Sequence. Range: 3 - 15 gdBit
750    pub transmission_start_sequence_duration: u8,
751    /// gdWakeupSymbolRxIdle: Number of bits used by the node to test the duration
752    /// of the 'idle' portion of a received wakeup symbol. Range: 14 - 59 gdBit
753    pub wakeup_rx_idle: u16,
754    /// gdWakeupSymbolRxLow: Number of bits used by the node to test the LOW
755    /// portion of a received wakeup symbol. Range 11 - 59 gdBit
756    pub wakeup_rx_low: u8,
757    /// gdWakeupSymbolRxWindow: The size of the window used to detect wakeups. Range: 76 - 301 gdBit
758    pub wakeup_rx_window: u16,
759    /// gdWakeupSymbolTxLow: Number of bits used by the node to transmit the LOW part of a wakeup symbol. Range: 15 - 60 gdBit
760    pub wakeup_tx_active: u16,
761    /// gdWakeupSymbolTxIdle: Number of bits used by the node to transmit the 'idle' part of a wakeup symbol. Range: 45 - 180 gdBit
762    pub wakeup_tx_idle: u16,
763}
764
765impl FlexrayClusterSettings {
766    /// Create a new `FlexrayClusterSettings` object with default values
767    #[must_use]
768    pub fn new() -> Self {
769        Self {
770            baudrate: 10_000_000,
771            action_point_offset: 4,
772            bit: 1e-7,
773            cas_rx_low_max: 80,
774            cold_start_attempts: 16,
775            cycle: 0.005,
776            cycle_count_max: 63,
777            detect_nit_error: true,
778            dynamic_slot_idle_phase: 0,
779            ignore_after_tx: 7,
780            listen_noise: 2,
781            macro_per_cycle: 5000,
782            macrotick_duration: 1e-6,
783            max_without_clock_correction_fatal: 5,
784            max_without_clock_correction_passive: 3,
785            minislot_action_point_offset: 3,
786            minislot_duration: 10,
787            network_idle_time: 46,
788            network_management_vector_length: 0,
789            number_of_minislots: 185,
790            number_of_static_slots: 50,
791            offset_correction_start: 4980,
792            payload_length_static: 32,
793            safety_margin: 1,
794            sample_clock_period: Some(1.25e-8),
795            static_slot_duration: 62,
796            symbol_window: 0,
797            symbol_window_action_point_offset: None,
798            sync_frame_id_count_max: 8,
799            transceiver_standby_delay: None,
800            transmission_start_sequence_duration: 9,
801            wakeup_rx_idle: 50,
802            wakeup_rx_low: 50,
803            wakeup_rx_window: 301,
804            wakeup_tx_active: 60,
805            wakeup_tx_idle: 180,
806        }
807    }
808
809    /// Check the plausibility of the parameter values
810    ///
811    /// Returns true if no problem was detected, of false if a problem was found.
812    /// The checks performed by this function are not comprehensive. Some problems may remain undetected.
813    ///
814    /// # Example
815    ///
816    /// ```
817    /// # use autosar_data_abstraction::communication::*;
818    /// let mut settings = FlexrayClusterSettings::default();
819    /// settings.macro_per_cycle = 1111;
820    /// assert!(!settings.verify())
821    /// ```
822    #[must_use]
823    pub fn verify(&self) -> bool {
824        // bit time must be the inverse of the baudrate: bit = 1/baudrate
825        if 1.0 / f64::from(self.baudrate) != self.bit {
826            return false;
827        }
828
829        // cdCycleMax: 16000µs
830        if self.cycle > 0.016 {
831            return false;
832        }
833
834        // cCycleCountMax: 63
835        if self.cycle_count_max != 63 {
836            return false;
837        }
838
839        // cPayloadLengthMax = 127 two-byte words
840        if self.payload_length_static > 127 {
841            return false;
842        }
843
844        // Duration of a static slot is 4 - 661 MT
845        if self.static_slot_duration < 4 || self.static_slot_duration > 661 {
846            return false;
847        }
848
849        // Duration of a minislot is 2 - 63 MT
850        if self.minislot_duration < 2 || self.minislot_duration > 63 {
851            return false;
852        }
853
854        // The action point offset must be in the range 1 - 63 MT
855        if self.action_point_offset < 1
856            || self.action_point_offset > 63
857            || u16::from(self.action_point_offset) >= self.static_slot_duration
858        {
859            return false;
860        }
861
862        // minislot action point offset must be in th range 1 - 31 MT
863        if self.minislot_action_point_offset < 1 || self.minislot_action_point_offset > 31 {
864            return false;
865        }
866
867        // the upper limit of the CAS acceptance window is in the range 67 - 99 gdBit
868        if self.cas_rx_low_max < 67 || self.cas_rx_low_max > 99 {
869            return false;
870        }
871
872        // the sample clock period must be one of [0.0125µs, 0.025µs, 0.05µs
873        if let Some(sample_clock_period) = self.sample_clock_period {
874            if sample_clock_period != 1.25e-8 && sample_clock_period != 2.5e-8 && sample_clock_period != 5e-8 {
875                return false;
876            }
877
878            if self.bit != (sample_clock_period * 8.0) {
879                return false;
880            }
881        }
882
883        // duration of the symbol window: 0 - 142 MT
884        if self.symbol_window > 142 {
885            return false;
886        }
887
888        // Macroticks per cycle: 10 - 16000 MT
889        if self.macro_per_cycle < 10 || self.macro_per_cycle > 16000 {
890            return false;
891        }
892
893        if self.cycle / f64::from(self.macro_per_cycle) != self.macrotick_duration {
894            return false;
895        }
896
897        // the valid range for the network idle time is 2 - 805MT
898        if self.network_idle_time < 2 || self.network_idle_time > 805 {
899            return false;
900        }
901
902        // idle phase in a dynamic slot is 0 - 2 minislots
903        if self.dynamic_slot_idle_phase > 2 {
904            return false;
905        }
906
907        // number of bits in the transmission start sequence: 3 - 15 bit
908        if self.transmission_start_sequence_duration < 3 || self.transmission_start_sequence_duration > 15 {
909            return false;
910        }
911
912        // cStaticSlotIDMax: 1023; cSlotIDMax: 2047
913        if self.number_of_static_slots > 1023 || self.number_of_static_slots + self.number_of_minislots > 2047 {
914            return false;
915        }
916
917        // check if the configured static and dynamic segments fit into the cycle
918        let static_segment_length = u32::from(self.static_slot_duration) * u32::from(self.number_of_static_slots);
919        let dynamic_segment_length = u32::from(self.minislot_duration) * u32::from(self.number_of_minislots);
920        if (static_segment_length + dynamic_segment_length + u32::from(self.network_idle_time))
921            > u32::from(self.macro_per_cycle)
922        {
923            return false;
924        }
925
926        // check if the static frame payload fits into the number of macroticks
927        // each static frame has a header of 5 bytes + [data] + 3-byte CRC
928        let static_frame_size = 5 + 2 * self.payload_length_static + 3;
929        let bits_per_macrotick = self.macrotick_duration / self.bit;
930        let static_frame_bits =
931            f64::from(self.static_slot_duration - u16::from(self.action_point_offset)) * bits_per_macrotick;
932        if (static_frame_bits as u32) < u32::from(static_frame_size * 8) {
933            return false;
934        }
935
936        // offset correction start must fall inside the network idle time
937        if (self.offset_correction_start > self.macro_per_cycle)
938            || (self.offset_correction_start < self.macro_per_cycle - self.network_idle_time)
939        {
940            return false;
941        }
942
943        // gColdStartAttempts: 2 - 31
944        if self.cold_start_attempts < 2 || self.cold_start_attempts > 31 {
945            return false;
946        }
947
948        // gdWakeupSymbolRxIdle: 14 - 59 gdBit
949        if self.wakeup_rx_idle < 14 || self.wakeup_rx_idle > 59 {
950            return false;
951        }
952
953        // gdWakeupSymbolRxLow 11 - 59 gdBit
954        if self.wakeup_rx_low < 11 || self.wakeup_rx_low > 59 {
955            return false;
956        }
957
958        // gdWakeupSymbolRxWindow: 76 - 301 gdBit
959        if self.wakeup_rx_window < 76 || self.wakeup_rx_window > 301 {
960            return false;
961        }
962
963        // gdWakeupSymbolTxIdle: 45 - 180 gdBit
964        if self.wakeup_tx_idle < 45 || self.wakeup_tx_idle > 180 {
965            return false;
966        }
967
968        // gdWakeupSymbolTxLow: 15 - 60 gdBit
969        if self.wakeup_tx_active < 15 || self.wakeup_tx_active > 60 {
970            return false;
971        }
972
973        // gListenNoise: 2 - 16
974        if self.listen_noise < 2 || self.listen_noise > 16 {
975            return false;
976        }
977
978        // 0 <= gMaxWithoutClockCorrectionPassive <= gMaxWithoutClockCorrectionFatal <= 15
979        if (self.max_without_clock_correction_fatal < self.max_without_clock_correction_passive)
980            || (self.max_without_clock_correction_fatal > 15)
981        {
982            return false;
983        }
984
985        if self.sync_frame_id_count_max < 2 || self.sync_frame_id_count_max > 15 {
986            return false;
987        }
988
989        true
990    }
991}
992
993impl Default for FlexrayClusterSettings {
994    fn default() -> Self {
995        Self::new()
996    }
997}
998
999//##################################################################
1000
1001#[cfg(test)]
1002mod test {
1003    use crate::{
1004        AbstractionElement, AutosarModelAbstraction, SystemCategory,
1005        communication::{AbstractCluster, FlexrayChannelName, FlexrayClusterSettings, FlexrayNmClusterSettings},
1006    };
1007    use autosar_data::AutosarVersion;
1008
1009    #[test]
1010    fn cluster() {
1011        let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
1012        let pkg = model.get_or_create_package("/test").unwrap();
1013        let system = pkg.create_system("System", SystemCategory::SystemDescription).unwrap();
1014
1015        let pkg2 = model.get_or_create_package("/flexray").unwrap();
1016        // create the Flexray cluster FlxCluster
1017        let settings = FlexrayClusterSettings::default();
1018        let result = system.create_flexray_cluster("FlxCluster", &pkg2, &settings);
1019        assert!(result.is_ok());
1020        let cluster = result.unwrap();
1021        // creating the same cluster again is not possible
1022        let settings = FlexrayClusterSettings::default();
1023        let result = system.create_flexray_cluster("FlxCluster", &pkg2, &settings);
1024        assert!(result.is_err());
1025
1026        // system link
1027        let linked_system = cluster.system().unwrap();
1028        assert_eq!(linked_system, system);
1029
1030        // create channel A
1031        let result = cluster.create_physical_channel("Channel1", FlexrayChannelName::A);
1032        assert!(result.is_ok());
1033        // create channel B
1034        let result = cluster.create_physical_channel("Channel2", FlexrayChannelName::B);
1035        assert!(result.is_ok());
1036        // can't create a third channel
1037        let result = cluster.create_physical_channel("Channel3", FlexrayChannelName::A);
1038        assert!(result.is_err());
1039
1040        let pc = cluster.physical_channels();
1041        assert!(pc.channel_a.is_some());
1042        assert!(pc.channel_b.is_some());
1043    }
1044
1045    #[test]
1046    fn flexray_settings() {
1047        let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
1048        let pkg = model.get_or_create_package("/test").unwrap();
1049        let system = pkg.create_system("System", SystemCategory::SystemDescription).unwrap();
1050        let settings = FlexrayClusterSettings::default();
1051        let cluster = system.create_flexray_cluster("FlxCluster", &pkg, &settings).unwrap();
1052
1053        let mut settings = FlexrayClusterSettings::new();
1054        assert!(settings.verify());
1055
1056        // make sure all settings values can be applied and loaded
1057        settings.sample_clock_period = Some(1.25e-8);
1058        settings.symbol_window_action_point_offset = Some(settings.action_point_offset);
1059        settings.transceiver_standby_delay = Some(1.0);
1060        assert!(settings.verify());
1061        cluster.update_settings(&settings);
1062        let settings2 = cluster.settings();
1063        assert_eq!(settings, settings2);
1064
1065        // test verification of values
1066        settings.baudrate = 0;
1067        assert!(!settings.verify());
1068        settings.baudrate = settings2.baudrate;
1069
1070        settings.cycle = 0.0161;
1071        assert!(!settings.verify());
1072        settings.cycle = settings2.cycle;
1073
1074        settings.cycle_count_max = 64;
1075        assert!(!settings.verify());
1076        settings.cycle_count_max = settings2.cycle_count_max;
1077
1078        settings.payload_length_static = 128;
1079        assert!(!settings.verify());
1080        settings.payload_length_static = settings2.payload_length_static;
1081
1082        settings.static_slot_duration = 3;
1083        assert!(!settings.verify());
1084        settings.static_slot_duration = settings2.static_slot_duration;
1085
1086        settings.minislot_duration = 64;
1087        assert!(!settings.verify());
1088        settings.minislot_duration = settings2.minislot_duration;
1089
1090        settings.action_point_offset = 64;
1091        assert!(!settings.verify());
1092        settings.action_point_offset = settings2.action_point_offset;
1093
1094        settings.minislot_action_point_offset = 32;
1095        assert!(!settings.verify());
1096        settings.minislot_action_point_offset = settings2.minislot_action_point_offset;
1097
1098        settings.cas_rx_low_max = 66;
1099        assert!(!settings.verify());
1100        settings.cas_rx_low_max = settings2.cas_rx_low_max;
1101
1102        settings.sample_clock_period = Some(1.0);
1103        assert!(!settings.verify());
1104        settings.sample_clock_period = settings2.sample_clock_period;
1105
1106        settings.symbol_window = 143;
1107        assert!(!settings.verify());
1108        settings.symbol_window = settings2.symbol_window;
1109
1110        settings.macro_per_cycle = 9;
1111        assert!(!settings.verify());
1112        settings.macro_per_cycle = settings2.macro_per_cycle;
1113
1114        settings.macro_per_cycle -= 1;
1115        assert!(!settings.verify());
1116        settings.macro_per_cycle = settings2.macro_per_cycle;
1117
1118        settings.network_idle_time = 806;
1119        assert!(!settings.verify());
1120        settings.network_idle_time = settings2.network_idle_time;
1121
1122        settings.dynamic_slot_idle_phase = 3;
1123        assert!(!settings.verify());
1124        settings.dynamic_slot_idle_phase = settings2.dynamic_slot_idle_phase;
1125
1126        settings.transmission_start_sequence_duration = 16;
1127        assert!(!settings.verify());
1128        settings.transmission_start_sequence_duration = settings2.transmission_start_sequence_duration;
1129
1130        settings.number_of_static_slots = 1024;
1131        assert!(!settings.verify());
1132        settings.number_of_static_slots = settings2.number_of_static_slots;
1133
1134        settings.number_of_static_slots += 1;
1135        assert!(!settings.verify());
1136        settings.number_of_static_slots = settings2.number_of_static_slots;
1137
1138        settings.payload_length_static += 1;
1139        assert!(!settings.verify());
1140        settings.payload_length_static = settings2.payload_length_static;
1141
1142        settings.offset_correction_start = settings.macro_per_cycle + 1;
1143        assert!(!settings.verify());
1144        settings.offset_correction_start = settings2.offset_correction_start;
1145
1146        settings.cold_start_attempts = 1;
1147        assert!(!settings.verify());
1148        settings.cold_start_attempts = settings2.cold_start_attempts;
1149
1150        settings.wakeup_rx_idle = 13;
1151        assert!(!settings.verify());
1152        settings.wakeup_rx_idle = settings2.wakeup_rx_idle;
1153
1154        settings.wakeup_rx_low = 10;
1155        assert!(!settings.verify());
1156        settings.wakeup_rx_low = settings2.wakeup_rx_low;
1157
1158        settings.wakeup_rx_window = 75;
1159        assert!(!settings.verify());
1160        settings.wakeup_rx_window = settings2.wakeup_rx_window;
1161
1162        settings.wakeup_tx_idle = 44;
1163        assert!(!settings.verify());
1164        settings.wakeup_tx_idle = settings2.wakeup_tx_idle;
1165
1166        settings.wakeup_tx_active = 14;
1167        assert!(!settings.verify());
1168        settings.wakeup_tx_active = settings2.wakeup_tx_active;
1169
1170        settings.listen_noise = 1;
1171        assert!(!settings.verify());
1172        settings.listen_noise = settings2.listen_noise;
1173
1174        settings.max_without_clock_correction_passive = settings.max_without_clock_correction_fatal + 1;
1175        assert!(!settings.verify());
1176        settings.max_without_clock_correction_passive = settings2.max_without_clock_correction_passive;
1177
1178        settings.sync_frame_id_count_max = 1;
1179        assert!(!settings.verify());
1180        settings.sync_frame_id_count_max = settings2.sync_frame_id_count_max;
1181    }
1182
1183    #[test]
1184    fn remove_cluster() {
1185        let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
1186        let pkg = model.get_or_create_package("/test").unwrap();
1187        let system = pkg.create_system("System", SystemCategory::SystemDescription).unwrap();
1188        let settings = FlexrayClusterSettings::default();
1189        let cluster = system.create_flexray_cluster("FlxCluster", &pkg, &settings).unwrap();
1190        let channel = cluster
1191            .create_physical_channel("Channel1", FlexrayChannelName::A)
1192            .unwrap();
1193
1194        let nm_config = system.create_nm_config("NmConfig", &pkg).unwrap();
1195        let settings = FlexrayNmClusterSettings {
1196            nm_data_cycle: 5,
1197            nm_remote_sleep_indication_time: 5.0,
1198            nm_repeat_message_time: 5.0,
1199            nm_repetition_cycle: 5,
1200            nm_voting_cycle: 5,
1201        };
1202        let fr_nm_cluster = nm_config
1203            .create_flexray_nm_cluster("FrNmCluster", &settings, &cluster)
1204            .unwrap();
1205        let fr_tp_config = system.create_flexray_tp_config("FrTpConfig", &pkg, &cluster).unwrap();
1206        let fr_ar_tp_config = system
1207            .create_flexray_ar_tp_config("FrArTpConfig", &pkg, &cluster)
1208            .unwrap();
1209
1210        cluster.remove(true).unwrap();
1211
1212        // check that the cluster and its channel are removed
1213        assert!(channel.element().path().is_err());
1214        assert!(fr_nm_cluster.element().path().is_err());
1215        assert!(fr_tp_config.element().path().is_err());
1216        assert!(fr_ar_tp_config.element().path().is_err());
1217    }
1218}