autosar_data_abstraction/communication/cluster/
flexray.rs

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