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            {
557                if existing_channel_name == channel_name {
558                    return Err(AutosarAbstractionError::ItemAlreadyExists);
559                }
560            }
561        }
562
563        let channel = phys_channels.create_named_sub_element(ElementName::FlexrayPhysicalChannel, name)?;
564
565        let cn_item = match channel_name {
566            FlexrayChannelName::A => EnumItem::ChannelA,
567            FlexrayChannelName::B => EnumItem::ChannelB,
568        };
569
570        let _ = channel
571            .create_sub_element(ElementName::ChannelName)
572            .and_then(|cn| cn.set_character_data(cn_item));
573
574        FlexrayPhysicalChannel::try_from(channel)
575    }
576
577    /// get the physical channels of this cluster
578    ///
579    /// # Example
580    ///
581    /// ```
582    /// # use autosar_data::*;
583    /// # use autosar_data_abstraction::*;
584    /// # use autosar_data_abstraction::communication::*;
585    /// # fn main() -> Result<(), AutosarAbstractionError> {
586    /// # let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
587    /// # let package = model.get_or_create_package("/pkg1")?;
588    /// # let system = package.create_system("System", SystemCategory::SystemExtract)?;
589    /// let cluster = system.create_flexray_cluster("Cluster", &package, &FlexrayClusterSettings::default())?;
590    /// let channel = cluster.create_physical_channel("Channel", FlexrayChannelName::A)?;
591    /// # Ok(())}
592    /// ```
593    #[must_use]
594    pub fn physical_channels(&self) -> FlexrayPhysicalChannelsInfo {
595        let mut channel_info = FlexrayPhysicalChannelsInfo {
596            channel_a: None,
597            channel_b: None,
598        };
599        if let Some(phys_channels) = self
600            .0
601            .get_sub_element(ElementName::FlexrayClusterVariants)
602            .and_then(|fcv| fcv.get_sub_element(ElementName::FlexrayClusterConditional))
603            .and_then(|fcc| fcc.get_sub_element(ElementName::PhysicalChannels))
604        {
605            for channel_elem in phys_channels.sub_elements() {
606                if let Ok(channel) = FlexrayPhysicalChannel::try_from(channel_elem) {
607                    match channel.channel_name() {
608                        Some(FlexrayChannelName::A) => channel_info.channel_a = Some(channel),
609                        Some(FlexrayChannelName::B) => channel_info.channel_b = Some(channel),
610                        None => {}
611                    }
612                }
613            }
614        }
615        channel_info
616    }
617}
618
619impl AbstractCluster for FlexrayCluster {}
620
621//##################################################################
622
623/// Information about the flexray physical channels present inside a cluster
624#[derive(Debug, Clone, PartialEq)]
625pub struct FlexrayPhysicalChannelsInfo {
626    /// channel A - it contains `FlexrayChannelName::A`
627    pub channel_a: Option<FlexrayPhysicalChannel>,
628    /// channel B - it contains `FlexrayChannelName::B`
629    pub channel_b: Option<FlexrayPhysicalChannel>,
630}
631
632//##################################################################
633
634/// Configuration settings of the Flexray cluster.
635///
636/// Refer to `AUTOSAR_TPS_SystemTemplate.pdf`, chapter 3.3.4 and Flexray 2.1a / 3.0 standard, appendix A + B
637/// for the meanings and ranges of these parameters.
638#[derive(Debug, Clone, PartialEq)]
639pub struct FlexrayClusterSettings {
640    /// baud rate of the Flexray cluster: one of 10000000 (10Mbit/s), 5000000 (5Mbit/s), 2500000 (2.5Mbit/s)
641    pub baudrate: u32,
642    /// gdActionPointOffset: Number of macroticks the action point is offset from the
643    /// beginning of a static slot or symbol window: in the range 1 - 63 MT
644    pub action_point_offset: u8,
645    /// gdBit: Nominal bit time; inverse of the baudrate: 0.1µs, 0.2µs, or 0.4µs
646    pub bit: f64,
647    /// gdCASRxLowMax: Upper limit of the CAS acceptance window. Range 67 - 99 gdBit
648    pub cas_rx_low_max: u8,
649    /// gColdStartAttempts: Maximum number of times a node in the cluster is permitted to attempt to start the cluster.
650    /// Range: 2 - 31
651    pub cold_start_attempts: u8,
652    /// gdCycle: Length of the cycle in seconds. Range: 10µs - 16000µs; typically 0.005s
653    pub cycle: f64,
654    /// cCycleCountMax. Must be 63 to conform with Flexray 2.1
655    pub cycle_count_max: u8,
656    /// Indicates whether network idle time (NIT) error status should be detected
657    pub detect_nit_error: bool,
658    /// gdDynamicSlotIdlePhase: Duration of the idle phase within a dynamic slot. Range 0 - 2
659    pub dynamic_slot_idle_phase: u8,
660    /// Duration for which the bitstrobing is paused after transmission
661    pub ignore_after_tx: u16,
662    /// gListenNoise: Upper limit for the startup listen timeout and wakeup listen timeout in the presence of noise.
663    /// Range 2 - 16
664    pub listen_noise: u8,
665    /// gMacroPerCycle: Number of macroticks in a communication cycle. Range: 10 - 16000 MT
666    pub macro_per_cycle: u16,
667    /// `macrotick_duration` \[s\] = cycle \[s\] / `macro_per_cycle`
668    pub macrotick_duration: f64,
669    /// gMaxWithoutClockCorrectionFatal: Threshold used for testing the vClockCorrectionFailed counter.
670    /// Range: <`max_without_clock_correction_passive`> - 15 even/odd cycle pairs
671    pub max_without_clock_correction_fatal: u8,
672    /// gMaxWithoutClockCorrectionPassive: Threshold used for testing the vClockCorrectionFailed counter.
673    /// Range: 1 - 15 even/odd cycle pairs
674    pub max_without_clock_correction_passive: u8,
675    /// gdMinislotActionPointOffset: Number of macroticks the minislot action point is offset from the beginning of a minislot. Range: 1 - 31 MT
676    pub minislot_action_point_offset: u8,
677    /// gdMinislot: Duration of a minislot. Range: 2 - 63 MT
678    pub minislot_duration: u8,
679    /// gdNIT: Duration of the Network Idle Time. 2 - 805 MT
680    pub network_idle_time: u16,
681    /// gNetworkManagementVectorLength: Length of the Network Management vector in a cluster. Range: 0 - 12 bytes
682    pub network_management_vector_length: u8,
683    /// gNumberOfMinislots: Number of minislots in the dynamic segment. Range: 0 - 7986
684    pub number_of_minislots: u16,
685    /// gNumberOfStaticSlots: Number of static slots in the static segment. Range: 2 - 1023
686    pub number_of_static_slots: u16,
687    /// gOffsetCorrectionStart: Start of the offset correction phase within the NIT, as MT from the start of the cycle. Range: 9 - 15999 MT
688    pub offset_correction_start: u16,
689    /// gPayloadLengthStatic: Payload length of a static frame, in two byte words. Range: 0 - 127 words
690    pub payload_length_static: u16,
691    /// Additional timespan in macroticks which takes jitter into account
692    pub safety_margin: u16,
693    /// gdSampleClockPeriod: Sample clock period. One of [1.25e-8 s, 2.5e-8 s, 5e-8 s]
694    pub sample_clock_period: Option<f64>,
695    /// gdStaticSlot: Duration of a static slot. Range: 4 - 661 MT
696    pub static_slot_duration: u16,
697    /// gdSymbolWindow: Duration of the symbol window. Range: 0 - 142 MT
698    pub symbol_window: u8,
699    /// Flexray 3.0 only: Number of Macroticks the action point is offset from the beginning of the symbol window. Range: 1 - 63 MT
700    pub symbol_window_action_point_offset: Option<u8>,
701    /// gSyncNodeMax: Maximum number of nodes that may send frames with the sync frame indicator bit set to one. Range: 2 - 15
702    pub sync_frame_id_count_max: u8,
703    /// The duration of timer `t_TrcvStdbyDelay` in seconds.
704    pub transceiver_standby_delay: Option<f64>,
705    /// gdTSSTransmitter: Number of bits in the Transmission Start Sequence. Range: 3 - 15 gdBit
706    pub transmission_start_sequence_duration: u8,
707    /// gdWakeupSymbolRxIdle: Number of bits used by the node to test the duration
708    /// of the 'idle' portion of a received wakeup symbol. Range: 14 - 59 gdBit
709    pub wakeup_rx_idle: u16,
710    /// gdWakeupSymbolRxLow: Number of bits used by the node to test the LOW
711    /// portion of a received wakeup symbol. Range 11 - 59 gdBit
712    pub wakeup_rx_low: u8,
713    /// gdWakeupSymbolRxWindow: The size of the window used to detect wakeups. Range: 76 - 301 gdBit
714    pub wakeup_rx_window: u16,
715    /// gdWakeupSymbolTxLow: Number of bits used by the node to transmit the LOW part of a wakeup symbol. Range: 15 - 60 gdBit
716    pub wakeup_tx_active: u16,
717    /// gdWakeupSymbolTxIdle: Number of bits used by the node to transmit the 'idle' part of a wakeup symbol. Range: 45 - 180 gdBit
718    pub wakeup_tx_idle: u16,
719}
720
721impl FlexrayClusterSettings {
722    /// Create a new `FlexrayClusterSettings` object with default values
723    #[must_use]
724    pub fn new() -> Self {
725        Self {
726            baudrate: 10_000_000,
727            action_point_offset: 4,
728            bit: 1e-7,
729            cas_rx_low_max: 80,
730            cold_start_attempts: 16,
731            cycle: 0.005,
732            cycle_count_max: 63,
733            detect_nit_error: true,
734            dynamic_slot_idle_phase: 0,
735            ignore_after_tx: 7,
736            listen_noise: 2,
737            macro_per_cycle: 5000,
738            macrotick_duration: 1e-6,
739            max_without_clock_correction_fatal: 5,
740            max_without_clock_correction_passive: 3,
741            minislot_action_point_offset: 3,
742            minislot_duration: 10,
743            network_idle_time: 46,
744            network_management_vector_length: 0,
745            number_of_minislots: 185,
746            number_of_static_slots: 50,
747            offset_correction_start: 4980,
748            payload_length_static: 32,
749            safety_margin: 1,
750            sample_clock_period: Some(1.25e-8),
751            static_slot_duration: 62,
752            symbol_window: 0,
753            symbol_window_action_point_offset: None,
754            sync_frame_id_count_max: 8,
755            transceiver_standby_delay: None,
756            transmission_start_sequence_duration: 9,
757            wakeup_rx_idle: 50,
758            wakeup_rx_low: 50,
759            wakeup_rx_window: 301,
760            wakeup_tx_active: 60,
761            wakeup_tx_idle: 180,
762        }
763    }
764
765    /// Check the plausibility of the parameter values
766    ///
767    /// Returns true if no problem was detected, of false if a problem was found.
768    /// The checks performed by this function are not comprehensive. Some problems may remain undetected.
769    ///
770    /// # Example
771    ///
772    /// ```
773    /// # use autosar_data_abstraction::communication::*;
774    /// let mut settings = FlexrayClusterSettings::default();
775    /// settings.macro_per_cycle = 1111;
776    /// assert!(!settings.verify())
777    /// ```
778    #[must_use]
779    pub fn verify(&self) -> bool {
780        // bit time must be the inverse of the baudrate: bit = 1/baudrate
781        if 1.0 / f64::from(self.baudrate) != self.bit {
782            return false;
783        }
784
785        // cdCycleMax: 16000µs
786        if self.cycle > 0.016 {
787            return false;
788        }
789
790        // cCycleCountMax: 63
791        if self.cycle_count_max != 63 {
792            return false;
793        }
794
795        // cPayloadLengthMax = 127 two-byte words
796        if self.payload_length_static > 127 {
797            return false;
798        }
799
800        // Duration of a static slot is 4 - 661 MT
801        if self.static_slot_duration < 4 || self.static_slot_duration > 661 {
802            return false;
803        }
804
805        // Duration of a minislot is 2 - 63 MT
806        if self.minislot_duration < 2 || self.minislot_duration > 63 {
807            return false;
808        }
809
810        // The action point offset must be in the range 1 - 63 MT
811        if self.action_point_offset < 1
812            || self.action_point_offset > 63
813            || u16::from(self.action_point_offset) >= self.static_slot_duration
814        {
815            return false;
816        }
817
818        // minislot action point offset must be in th range 1 - 31 MT
819        if self.minislot_action_point_offset < 1 || self.minislot_action_point_offset > 31 {
820            return false;
821        }
822
823        // the upper limit of the CAS acceptance window is in the range 67 - 99 gdBit
824        if self.cas_rx_low_max < 67 || self.cas_rx_low_max > 99 {
825            return false;
826        }
827
828        // the sample clock period must be one of [0.0125µs, 0.025µs, 0.05µs
829        if let Some(sample_clock_period) = self.sample_clock_period {
830            if sample_clock_period != 1.25e-8 && sample_clock_period != 2.5e-8 && sample_clock_period != 5e-8 {
831                return false;
832            }
833
834            if self.bit != (sample_clock_period * 8.0) {
835                return false;
836            }
837        }
838
839        // duration of the symbol window: 0 - 142 MT
840        if self.symbol_window > 142 {
841            return false;
842        }
843
844        // Macroticks per cycle: 10 - 16000 MT
845        if self.macro_per_cycle < 10 || self.macro_per_cycle > 16000 {
846            return false;
847        }
848
849        if self.cycle / f64::from(self.macro_per_cycle) != self.macrotick_duration {
850            return false;
851        }
852
853        // the valid range for the network idle time is 2 - 805MT
854        if self.network_idle_time < 2 || self.network_idle_time > 805 {
855            return false;
856        }
857
858        // idle phase in a dynamic slot is 0 - 2 minislots
859        if self.dynamic_slot_idle_phase > 2 {
860            return false;
861        }
862
863        // number of bits in the transmission start sequence: 3 - 15 bit
864        if self.transmission_start_sequence_duration < 3 || self.transmission_start_sequence_duration > 15 {
865            return false;
866        }
867
868        // cStaticSlotIDMax: 1023; cSlotIDMax: 2047
869        if self.number_of_static_slots > 1023 || self.number_of_static_slots + self.number_of_minislots > 2047 {
870            return false;
871        }
872
873        // check if the configured static and dynamic segments fit into the cycle
874        let static_segment_length = u32::from(self.static_slot_duration) * u32::from(self.number_of_static_slots);
875        let dynamic_segment_length = u32::from(self.minislot_duration) * u32::from(self.number_of_minislots);
876        if (static_segment_length + dynamic_segment_length + u32::from(self.network_idle_time))
877            > u32::from(self.macro_per_cycle)
878        {
879            return false;
880        }
881
882        // check if the static frame payload fits into the number of macroticks
883        // each static frame has a header of 5 bytes + [data] + 3-byte CRC
884        let static_frame_size = 5 + 2 * self.payload_length_static + 3;
885        let bits_per_macrotick = self.macrotick_duration / self.bit;
886        let static_frame_bits =
887            f64::from(self.static_slot_duration - u16::from(self.action_point_offset)) * bits_per_macrotick;
888        if (static_frame_bits as u32) < u32::from(static_frame_size * 8) {
889            return false;
890        }
891
892        // offset correction start must fall inside the network idle time
893        if (self.offset_correction_start > self.macro_per_cycle)
894            || (self.offset_correction_start < self.macro_per_cycle - self.network_idle_time)
895        {
896            return false;
897        }
898
899        // gColdStartAttempts: 2 - 31
900        if self.cold_start_attempts < 2 || self.cold_start_attempts > 31 {
901            return false;
902        }
903
904        // gdWakeupSymbolRxIdle: 14 - 59 gdBit
905        if self.wakeup_rx_idle < 14 || self.wakeup_rx_idle > 59 {
906            return false;
907        }
908
909        // gdWakeupSymbolRxLow 11 - 59 gdBit
910        if self.wakeup_rx_low < 11 || self.wakeup_rx_low > 59 {
911            return false;
912        }
913
914        // gdWakeupSymbolRxWindow: 76 - 301 gdBit
915        if self.wakeup_rx_window < 76 || self.wakeup_rx_window > 301 {
916            return false;
917        }
918
919        // gdWakeupSymbolTxIdle: 45 - 180 gdBit
920        if self.wakeup_tx_idle < 45 || self.wakeup_tx_idle > 180 {
921            return false;
922        }
923
924        // gdWakeupSymbolTxLow: 15 - 60 gdBit
925        if self.wakeup_tx_active < 15 || self.wakeup_tx_active > 60 {
926            return false;
927        }
928
929        // gListenNoise: 2 - 16
930        if self.listen_noise < 2 || self.listen_noise > 16 {
931            return false;
932        }
933
934        // 0 <= gMaxWithoutClockCorrectionPassive <= gMaxWithoutClockCorrectionFatal <= 15
935        if (self.max_without_clock_correction_fatal < self.max_without_clock_correction_passive)
936            || (self.max_without_clock_correction_fatal > 15)
937        {
938            return false;
939        }
940
941        if self.sync_frame_id_count_max < 2 || self.sync_frame_id_count_max > 15 {
942            return false;
943        }
944
945        true
946    }
947}
948
949impl Default for FlexrayClusterSettings {
950    fn default() -> Self {
951        Self::new()
952    }
953}
954
955//##################################################################
956
957#[cfg(test)]
958mod test {
959    use crate::{
960        AutosarModelAbstraction, SystemCategory,
961        communication::{AbstractCluster, FlexrayChannelName, FlexrayClusterSettings},
962    };
963    use autosar_data::AutosarVersion;
964
965    #[test]
966    fn cluster() {
967        let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
968        let pkg = model.get_or_create_package("/test").unwrap();
969        let system = pkg.create_system("System", SystemCategory::SystemDescription).unwrap();
970
971        let pkg2 = model.get_or_create_package("/flexray").unwrap();
972        // create the Flexray cluster FlxCluster
973        let settings = FlexrayClusterSettings::default();
974        let result = system.create_flexray_cluster("FlxCluster", &pkg2, &settings);
975        assert!(result.is_ok());
976        let cluster = result.unwrap();
977        // creating the same cluster again is not possible
978        let settings = FlexrayClusterSettings::default();
979        let result = system.create_flexray_cluster("FlxCluster", &pkg2, &settings);
980        assert!(result.is_err());
981
982        // system link
983        let linked_system = cluster.system().unwrap();
984        assert_eq!(linked_system, system);
985
986        // create channel A
987        let result = cluster.create_physical_channel("Channel1", FlexrayChannelName::A);
988        assert!(result.is_ok());
989        // create channel B
990        let result = cluster.create_physical_channel("Channel2", FlexrayChannelName::B);
991        assert!(result.is_ok());
992        // can't create a third channel
993        let result = cluster.create_physical_channel("Channel3", FlexrayChannelName::A);
994        assert!(result.is_err());
995
996        let pc = cluster.physical_channels();
997        assert!(pc.channel_a.is_some());
998        assert!(pc.channel_b.is_some());
999    }
1000
1001    #[test]
1002    fn flexray_settings() {
1003        let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
1004        let pkg = model.get_or_create_package("/test").unwrap();
1005        let system = pkg.create_system("System", SystemCategory::SystemDescription).unwrap();
1006        let settings = FlexrayClusterSettings::default();
1007        let cluster = system.create_flexray_cluster("FlxCluster", &pkg, &settings).unwrap();
1008
1009        let mut settings = FlexrayClusterSettings::new();
1010        assert!(settings.verify());
1011
1012        // make sure all settings values can be applied and loaded
1013        settings.sample_clock_period = Some(1.25e-8);
1014        settings.symbol_window_action_point_offset = Some(settings.action_point_offset);
1015        settings.transceiver_standby_delay = Some(1.0);
1016        assert!(settings.verify());
1017        cluster.update_settings(&settings);
1018        let settings2 = cluster.settings();
1019        assert_eq!(settings, settings2);
1020
1021        // test verification of values
1022        settings.baudrate = 0;
1023        assert!(!settings.verify());
1024        settings.baudrate = settings2.baudrate;
1025
1026        settings.cycle = 0.0161;
1027        assert!(!settings.verify());
1028        settings.cycle = settings2.cycle;
1029
1030        settings.cycle_count_max = 64;
1031        assert!(!settings.verify());
1032        settings.cycle_count_max = settings2.cycle_count_max;
1033
1034        settings.payload_length_static = 128;
1035        assert!(!settings.verify());
1036        settings.payload_length_static = settings2.payload_length_static;
1037
1038        settings.static_slot_duration = 3;
1039        assert!(!settings.verify());
1040        settings.static_slot_duration = settings2.static_slot_duration;
1041
1042        settings.minislot_duration = 64;
1043        assert!(!settings.verify());
1044        settings.minislot_duration = settings2.minislot_duration;
1045
1046        settings.action_point_offset = 64;
1047        assert!(!settings.verify());
1048        settings.action_point_offset = settings2.action_point_offset;
1049
1050        settings.minislot_action_point_offset = 32;
1051        assert!(!settings.verify());
1052        settings.minislot_action_point_offset = settings2.minislot_action_point_offset;
1053
1054        settings.cas_rx_low_max = 66;
1055        assert!(!settings.verify());
1056        settings.cas_rx_low_max = settings2.cas_rx_low_max;
1057
1058        settings.sample_clock_period = Some(1.0);
1059        assert!(!settings.verify());
1060        settings.sample_clock_period = settings2.sample_clock_period;
1061
1062        settings.symbol_window = 143;
1063        assert!(!settings.verify());
1064        settings.symbol_window = settings2.symbol_window;
1065
1066        settings.macro_per_cycle = 9;
1067        assert!(!settings.verify());
1068        settings.macro_per_cycle = settings2.macro_per_cycle;
1069
1070        settings.macro_per_cycle -= 1;
1071        assert!(!settings.verify());
1072        settings.macro_per_cycle = settings2.macro_per_cycle;
1073
1074        settings.network_idle_time = 806;
1075        assert!(!settings.verify());
1076        settings.network_idle_time = settings2.network_idle_time;
1077
1078        settings.dynamic_slot_idle_phase = 3;
1079        assert!(!settings.verify());
1080        settings.dynamic_slot_idle_phase = settings2.dynamic_slot_idle_phase;
1081
1082        settings.transmission_start_sequence_duration = 16;
1083        assert!(!settings.verify());
1084        settings.transmission_start_sequence_duration = settings2.transmission_start_sequence_duration;
1085
1086        settings.number_of_static_slots = 1024;
1087        assert!(!settings.verify());
1088        settings.number_of_static_slots = settings2.number_of_static_slots;
1089
1090        settings.number_of_static_slots += 1;
1091        assert!(!settings.verify());
1092        settings.number_of_static_slots = settings2.number_of_static_slots;
1093
1094        settings.payload_length_static += 1;
1095        assert!(!settings.verify());
1096        settings.payload_length_static = settings2.payload_length_static;
1097
1098        settings.offset_correction_start = settings.macro_per_cycle + 1;
1099        assert!(!settings.verify());
1100        settings.offset_correction_start = settings2.offset_correction_start;
1101
1102        settings.cold_start_attempts = 1;
1103        assert!(!settings.verify());
1104        settings.cold_start_attempts = settings2.cold_start_attempts;
1105
1106        settings.wakeup_rx_idle = 13;
1107        assert!(!settings.verify());
1108        settings.wakeup_rx_idle = settings2.wakeup_rx_idle;
1109
1110        settings.wakeup_rx_low = 10;
1111        assert!(!settings.verify());
1112        settings.wakeup_rx_low = settings2.wakeup_rx_low;
1113
1114        settings.wakeup_rx_window = 75;
1115        assert!(!settings.verify());
1116        settings.wakeup_rx_window = settings2.wakeup_rx_window;
1117
1118        settings.wakeup_tx_idle = 44;
1119        assert!(!settings.verify());
1120        settings.wakeup_tx_idle = settings2.wakeup_tx_idle;
1121
1122        settings.wakeup_tx_active = 14;
1123        assert!(!settings.verify());
1124        settings.wakeup_tx_active = settings2.wakeup_tx_active;
1125
1126        settings.listen_noise = 1;
1127        assert!(!settings.verify());
1128        settings.listen_noise = settings2.listen_noise;
1129
1130        settings.max_without_clock_correction_passive = settings.max_without_clock_correction_fatal + 1;
1131        assert!(!settings.verify());
1132        settings.max_without_clock_correction_passive = settings2.max_without_clock_correction_passive;
1133
1134        settings.sync_frame_id_count_max = 1;
1135        assert!(!settings.verify());
1136        settings.sync_frame_id_count_max = settings2.sync_frame_id_count_max;
1137    }
1138}