msf60_utils/
lib.rs

1// SPDX-License-Identifier: MIT OR Apache-2.0
2// Copyright 2022-2025 René Ladan <rene0+codeberg@freedom.nl>
3
4//! Collection of utilities for MSF receivers.
5
6//! Build with no_std for embedded platforms.
7#![cfg_attr(not(test), no_std)]
8
9use core::cmp::Ordering;
10
11use radio_datetime_utils::{RadioDateTimeUtils, radio_datetime_helpers};
12
13pub mod msf_helpers;
14
15/// Default upper limit for spike detection in microseconds.
16const SPIKE_LIMIT: u32 = 30_000;
17/// Maximum time in microseconds for a bit to be considered 0 (0/x cases).
18const ACTIVE_0_LIMIT: u32 = 150_000;
19/// Maximum time in microseconds for bit A to be considered 1.
20const ACTIVE_A_LIMIT: u32 = 250_000;
21/// Maximum time in microseconds for bit A and B to te considered 1.
22const ACTIVE_AB_LIMIT: u32 = 350_000;
23/// Maximum time in microseconds for a minute marker to be detected.
24const MINUTE_LIMIT: u32 = 550_000;
25/// Signal is considered lost after this many microseconds.
26const PASSIVE_RUNAWAY: u32 = 1_500_000;
27
28/// MSF decoder class
29#[derive(Debug)]
30pub struct MSFUtils {
31    first_minute: bool,
32    new_minute: bool,      // 0111_1110 marker seen
33    past_new_minute: bool, // long bit at begin-of-minute seen
34    new_second: bool,
35    second: u8,
36    bit_buffer_a: [Option<bool>; radio_datetime_utils::BIT_BUFFER_SIZE],
37    bit_buffer_b: [Option<bool>; radio_datetime_utils::BIT_BUFFER_SIZE],
38    radio_datetime: RadioDateTimeUtils,
39    parity_1: Option<bool>,
40    parity_2: Option<bool>,
41    parity_3: Option<bool>,
42    parity_4: Option<bool>,
43    eom: u8,
44    // below for handle_new_edge()
45    before_first_edge: bool,
46    t0: u32,
47    old_t_diff: u32,
48    spike_limit: u32,
49}
50
51impl MSFUtils {
52    /// Initialize a new MSFUtils instance.
53    pub fn new() -> Self {
54        let mut rdt = RadioDateTimeUtils::new(0);
55        rdt.set_utc_offset(0, false);
56        Self {
57            first_minute: true,
58            new_minute: false,
59            past_new_minute: false,
60            new_second: false,
61            second: 0,
62            bit_buffer_a: [None; radio_datetime_utils::BIT_BUFFER_SIZE],
63            bit_buffer_b: [None; radio_datetime_utils::BIT_BUFFER_SIZE],
64            radio_datetime: rdt,
65            parity_1: None,
66            parity_2: None,
67            parity_3: None,
68            parity_4: None,
69            eom: 0,
70            before_first_edge: true,
71            t0: 0,
72            old_t_diff: 0,
73            spike_limit: SPIKE_LIMIT,
74        }
75    }
76
77    /// Reset the MSFUtils instance including the radio_datetime field.
78    pub fn reset(&mut self) {
79        self.first_minute = true;
80        self.new_minute = false;
81        self.past_new_minute = false;
82        self.new_second = false;
83        self.second = 0;
84        self.bit_buffer_a = [None; radio_datetime_utils::BIT_BUFFER_SIZE];
85        self.bit_buffer_b = [None; radio_datetime_utils::BIT_BUFFER_SIZE];
86        self.radio_datetime.reset();
87        self.parity_1 = None;
88        self.parity_2 = None;
89        self.parity_3 = None;
90        self.parity_4 = None;
91        self.eom = 0;
92        self.before_first_edge = true;
93        self.t0 = 0;
94        self.old_t_diff = 0;
95        self.spike_limit = SPIKE_LIMIT;
96    }
97
98    /// Return if this is the first minute that is decoded.
99    pub fn is_first_minute(&self) -> bool {
100        self.first_minute
101    }
102
103    /// Return if a new minute (0111_1110 marker) has arrived.
104    pub fn is_new_minute(&self) -> bool {
105        self.new_minute
106    }
107
108    /// Return if the 500 ms long begin-of-minute marker has arrived.
109    pub fn is_past_new_minute(&self) -> bool {
110        self.past_new_minute
111    }
112
113    /// Force the arrival of a new minute (0111_1110 version).
114    ///
115    /// This could be useful when reading from a log file.
116    ///
117    /// This method must be called _before_ `increase_second()`.
118    pub fn force_new_minute(&mut self) {
119        self.new_minute = true;
120        self.past_new_minute = false;
121    }
122
123    /// Force the arrival of a new minute (begin-of-minute version).
124    ///
125    /// This could be useful when reading from a log file.
126    ///
127    /// This method must be called _before_ `increase_second()`.
128    pub fn force_past_new_minute(&mut self) {
129        self.new_minute = false;
130        self.past_new_minute = true;
131        self.second = 0;
132        self.bit_buffer_a[0] = Some(true);
133        self.eom = (self.eom << 1) + 1;
134        self.bit_buffer_b[0] = Some(true);
135    }
136
137    /// Returns if a new second has arrived.
138    pub fn is_new_second(&self) -> bool {
139        self.new_second
140    }
141
142    /// Get the second counter.
143    pub fn get_second(&self) -> u8 {
144        self.second
145    }
146
147    /// Get the value of the current A bit.
148    pub fn get_current_bit_a(&self) -> Option<bool> {
149        self.bit_buffer_a[self.second as usize]
150    }
151
152    /// Get the value of the current B bit.
153    pub fn get_current_bit_b(&self) -> Option<bool> {
154        self.bit_buffer_b[self.second as usize]
155    }
156
157    /// Set the value of the current A bit and clear the flag indicating arrival of a new minute.
158    ///
159    /// This could be useful when reading from a log file.
160    ///
161    /// This method must be called _before_ `increase_second()`.
162    ///
163    /// # Arguments
164    /// * `value` - the value to set the current bit to.
165    pub fn set_current_bit_a(&mut self, value: Option<bool>) {
166        self.bit_buffer_a[self.second as usize] = value;
167        self.eom = match value {
168            Some(b) => (self.eom << 1) + b as u8,
169            None => 0,
170        };
171        self.new_minute = false;
172        self.past_new_minute = false;
173    }
174
175    /// Set the value of the current B bit and clear the flag indicating arrival of a new minute.
176    ///
177    /// This could be useful when reading from a log file.
178    ///
179    /// This method must be called _before_ `increase_second()`.
180    ///
181    /// # Arguments
182    /// * `value` - the value to set the current bit to.
183    pub fn set_current_bit_b(&mut self, value: Option<bool>) {
184        self.bit_buffer_b[self.second as usize] = value;
185        self.new_minute = false;
186        self.past_new_minute = false;
187    }
188
189    /// Get a copy of the date/time structure.
190    pub fn get_radio_datetime(&self) -> RadioDateTimeUtils {
191        self.radio_datetime
192    }
193
194    /// Get the year parity bit, Some(true) means OK.
195    pub fn get_parity_1(&self) -> Option<bool> {
196        self.parity_1
197    }
198
199    /// Get the month/day parity bit, Some(true) means OK.
200    pub fn get_parity_2(&self) -> Option<bool> {
201        self.parity_2
202    }
203
204    /// Get the weekday parity bit, Some(true) means OK.
205    pub fn get_parity_3(&self) -> Option<bool> {
206        self.parity_3
207    }
208
209    /// Get the hour/minute parity bit, Some(true) means OK.
210    pub fn get_parity_4(&self) -> Option<bool> {
211        self.parity_4
212    }
213
214    #[deprecated(
215        since = "1.2.0",
216        note = "Please use get_dut1() from radio_datetime_utils directly"
217    )]
218    pub fn get_dut1(&self) -> Option<i8> {
219        self.radio_datetime.get_dut1()
220    }
221
222    #[deprecated(
223        since = "1.2.0",
224        note = "Please use get_jump_dut1() from radio_datetime_utils directly"
225    )]
226    pub fn get_jump_dut1(&self) -> bool {
227        self.radio_datetime.get_jump_dut1()
228    }
229
230    /// Return the current spike limit in microseconds.
231    pub fn get_spike_limit(&self) -> u32 {
232        self.spike_limit
233    }
234
235    /// Set the new spike limit in microseconds, [0(off)..ACTIVE_0_LIMIT)
236    ///
237    /// # Arguments
238    /// * `value` - the value to set the spike limit to.
239    pub fn set_spike_limit(&mut self, value: u32) {
240        if value < ACTIVE_0_LIMIT {
241            self.spike_limit = value;
242        }
243    }
244
245    /// Determine the bit value if a new edge is received and checks if a new minute has started.
246    /// None values indicate reception errors.
247    ///
248    /// This function can deal with spikes, which are arbitrarily set to `spike_limit` microseconds.
249    ///
250    /// This method must be called _before_ `increase_second()`.
251    ///
252    /// # Arguments
253    /// * `is_high_edge` - indicates that the edge has gone from low to high(as opposed to
254    ///   high-to-low).
255    /// * `t` - time stamp of the received edge, in microseconds.
256    pub fn handle_new_edge(&mut self, is_high_edge: bool, t: u32) {
257        if self.before_first_edge {
258            self.before_first_edge = false;
259            self.t0 = t;
260            return;
261        }
262        let t_diff = radio_datetime_helpers::time_diff(self.t0, t);
263        if t_diff < self.spike_limit {
264            // Shift t0 to deal with a train of spikes adding up to more than
265            // `spike_limit` microseconds.
266            self.t0 += t_diff;
267            return; // random positive or negative spike, ignore
268        }
269        self.t0 = t;
270        if !is_high_edge {
271            self.new_second = false;
272            if t_diff < ACTIVE_0_LIMIT {
273                if self.old_t_diff > 0 && self.old_t_diff < ACTIVE_0_LIMIT {
274                    self.bit_buffer_a[self.second as usize] = Some(false);
275                    self.eom <<= 1;
276                    self.bit_buffer_b[self.second as usize] = Some(true);
277                } else if self.old_t_diff > 1_000_000 - MINUTE_LIMIT {
278                    self.bit_buffer_a[self.second as usize] = Some(false);
279                    self.eom <<= 1;
280                    self.bit_buffer_b[self.second as usize] = Some(false);
281                }
282                self.new_minute = self.eom == 0x7e;
283                self.past_new_minute = false;
284            } else if t_diff < ACTIVE_A_LIMIT && self.old_t_diff > 1_000_000 - ACTIVE_AB_LIMIT {
285                self.bit_buffer_a[self.second as usize] = Some(true);
286                self.eom = (self.eom << 1) + 1;
287                self.bit_buffer_b[self.second as usize] = Some(false);
288                self.new_minute = false;
289                self.past_new_minute = false;
290            } else if t_diff < ACTIVE_AB_LIMIT && self.old_t_diff > 1_000_000 - ACTIVE_AB_LIMIT {
291                self.bit_buffer_a[self.second as usize] = Some(true);
292                self.eom = (self.eom << 1) + 1;
293                self.bit_buffer_b[self.second as usize] = Some(true);
294                self.new_minute = false;
295                self.past_new_minute = false;
296            } else if t_diff < MINUTE_LIMIT && self.old_t_diff > 1_000_000 - ACTIVE_AB_LIMIT {
297                self.second = 0;
298                self.bit_buffer_a[0] = Some(true);
299                self.eom = (self.eom << 1) + 1;
300                self.bit_buffer_b[0] = Some(true);
301                self.new_minute = false;
302                self.past_new_minute = true;
303            } else {
304                // active runaway or first low edge
305                self.bit_buffer_a[self.second as usize] = None;
306                self.eom = 0;
307                self.bit_buffer_b[self.second as usize] = None;
308                self.new_minute = false;
309                self.past_new_minute = false;
310            }
311        } else if t_diff < PASSIVE_RUNAWAY {
312            self.new_second = t_diff > 1_000_000 - MINUTE_LIMIT;
313        } else {
314            self.bit_buffer_a[self.second as usize] = None;
315            self.eom = 0;
316            self.bit_buffer_b[self.second as usize] = None;
317            self.new_minute = false;
318            self.past_new_minute = false;
319        }
320        self.old_t_diff = t_diff;
321    }
322
323    /// Determine the length of this minute in seconds.
324    pub fn get_minute_length(&self) -> u8 {
325        if (58..=60).contains(&self.second) && self.eom == 0x7e {
326            self.second + 1
327        } else if self.second == 59 && (self.eom & 0x7f) == 0x3f {
328            61
329        } else {
330            60
331        }
332    }
333
334    /// Return if the end-of-minute marker (0111_1110) is present in the A bits.
335    ///
336    /// This method must be called _before_ `increase_second()`.
337    pub fn end_of_minute_marker_present(&self) -> bool {
338        self.eom == 0x7e
339    }
340
341    /// Increase or reset `second`.
342    ///
343    /// Returns if the second counter was increased/wrapped normally (true)
344    /// or due to an overflow (false).
345    ///
346    /// This method must be called _after_ `decode_time()`, `handle_new_edge()`,
347    /// `set_current_bit_a()`, `set_current_bit_b()`, `end_of_minute_marker_present()`
348    /// `force_new_minute()`, and `force_past_new_minute()`.
349    pub fn increase_second(&mut self) -> bool {
350        let minute_length = self.get_minute_length();
351        radio_datetime_helpers::increase_second(&mut self.second, self.new_minute, minute_length)
352    }
353
354    /// Call add_minute() on `self.radio_datetime` and passes on that result.
355    ///
356    /// This could be useful for consumers just wanting to advance their current date/time.
357    pub fn add_minute(&mut self) -> bool {
358        self.radio_datetime.clear_jumps();
359        self.radio_datetime.add_minute()
360    }
361
362    /// Decode the time broadcast during the last minute and clear `first_minute` when appropriate.
363    ///
364    /// This method must be called _before_ `increase_second()`.
365    ///
366    /// # Arguments
367    /// * `need_add_minute` - add a minute to self.radio_datetime, in case `add_minute()` was not
368    ///   called before.
369    /// * `strict_checks` - checks all parities, DUT1 validity, and EOM marker presence when setting
370    ///   date/time and clearing self.first_minute.
371    pub fn decode_time(&mut self, need_add_minute: bool, strict_checks: bool) {
372        self.radio_datetime.clear_jumps();
373        let minute_length = self.get_minute_length(); // calculation depends on self.second
374        let mut added_minute = !need_add_minute;
375        if !self.first_minute && need_add_minute {
376            added_minute = self.radio_datetime.add_minute();
377        }
378        if self.second + 1 == minute_length {
379            let offset: isize = match 60.cmp(&minute_length) {
380                Ordering::Less => 1,
381                Ordering::Equal => 0,
382                Ordering::Greater => -1,
383            };
384
385            self.parity_1 = radio_datetime_helpers::decode_parity(
386                &self.bit_buffer_a,
387                (17 + offset) as usize,
388                (24 + offset) as usize,
389                self.bit_buffer_b[(54 + offset) as usize],
390            );
391            self.parity_2 = radio_datetime_helpers::decode_parity(
392                &self.bit_buffer_a,
393                (25 + offset) as usize,
394                (35 + offset) as usize,
395                self.bit_buffer_b[(55 + offset) as usize],
396            );
397            self.parity_3 = radio_datetime_helpers::decode_parity(
398                &self.bit_buffer_a,
399                (36 + offset) as usize,
400                (38 + offset) as usize,
401                self.bit_buffer_b[(56 + offset) as usize],
402            );
403            self.parity_4 = radio_datetime_helpers::decode_parity(
404                &self.bit_buffer_a,
405                (39 + offset) as usize,
406                (51 + offset) as usize,
407                self.bit_buffer_b[(57 + offset) as usize],
408            );
409
410            let dut1p = radio_datetime_helpers::decode_unary(&self.bit_buffer_b, 1, 8);
411            // bit 16 is dropped in case of a negative leap second
412            let stop = if offset == -1 { 15 } else { 16 };
413            let dut1n = radio_datetime_helpers::decode_unary(&self.bit_buffer_b, 9, stop);
414            let dut1_ok = dut1p.is_some_and(|p| dut1n.is_some_and(|n| n * p == 0));
415
416            let strict_ok = self.parity_1 == Some(true)
417                && self.parity_2 == Some(true)
418                && self.parity_3 == Some(true)
419                && self.parity_4 == Some(true)
420                && dut1_ok
421                && self.end_of_minute_marker_present();
422
423            self.radio_datetime.set_year(
424                radio_datetime_helpers::decode_bcd(
425                    &self.bit_buffer_a,
426                    (24 + offset) as usize,
427                    (17 + offset) as usize,
428                )
429                .map(|v| v as u8),
430                if strict_checks {
431                    strict_ok
432                } else {
433                    self.parity_1 == Some(true)
434                },
435                added_minute && !self.first_minute,
436            );
437            self.radio_datetime.set_month(
438                radio_datetime_helpers::decode_bcd(
439                    &self.bit_buffer_a,
440                    (29 + offset) as usize,
441                    (25 + offset) as usize,
442                )
443                .map(|v| v as u8),
444                if strict_checks {
445                    strict_ok
446                } else {
447                    self.parity_2 == Some(true)
448                },
449                added_minute && !self.first_minute,
450            );
451            self.radio_datetime.set_weekday(
452                radio_datetime_helpers::decode_bcd(
453                    &self.bit_buffer_a,
454                    (38 + offset) as usize,
455                    (36 + offset) as usize,
456                )
457                .map(|v| v as u8),
458                if strict_checks {
459                    strict_ok
460                } else {
461                    self.parity_3 == Some(true)
462                },
463                added_minute && !self.first_minute,
464            );
465            self.radio_datetime.set_day(
466                radio_datetime_helpers::decode_bcd(
467                    &self.bit_buffer_a,
468                    (35 + offset) as usize,
469                    (30 + offset) as usize,
470                )
471                .map(|v| v as u8),
472                if strict_checks {
473                    strict_ok
474                } else {
475                    self.parity_2 == Some(true)
476                },
477                added_minute && !self.first_minute,
478            );
479
480            self.radio_datetime.set_hour(
481                radio_datetime_helpers::decode_bcd(
482                    &self.bit_buffer_a,
483                    (44 + offset) as usize,
484                    (39 + offset) as usize,
485                )
486                .map(|v| v as u8),
487                if strict_checks {
488                    strict_ok
489                } else {
490                    self.parity_4 == Some(true)
491                },
492                added_minute && !self.first_minute,
493            );
494            self.radio_datetime.set_minute(
495                radio_datetime_helpers::decode_bcd(
496                    &self.bit_buffer_a,
497                    (51 + offset) as usize,
498                    (45 + offset) as usize,
499                )
500                .map(|v| v as u8),
501                if strict_checks {
502                    strict_ok
503                } else {
504                    self.parity_4 == Some(true)
505                },
506                added_minute && !self.first_minute,
507            );
508
509            self.radio_datetime.set_dst(
510                self.bit_buffer_b[(58 + offset) as usize],
511                self.bit_buffer_b[(53 + offset) as usize],
512                added_minute && !self.first_minute,
513            );
514
515            self.radio_datetime.set_dut1(
516                if dut1_ok {
517                    Some(dut1p.unwrap() as i8 - dut1n.unwrap() as i8)
518                } else {
519                    None
520                },
521                dut1_ok,
522                added_minute && !self.first_minute,
523            );
524
525            if if strict_checks {
526                strict_ok
527            } else {
528                self.radio_datetime.get_dut1().is_some()
529            } && self.radio_datetime.is_valid()
530            {
531                // allow displaying of information after the first properly decoded minute
532                self.first_minute = false;
533            }
534
535            self.radio_datetime.bump_minutes_running();
536        }
537    }
538}
539
540impl Default for MSFUtils {
541    fn default() -> Self {
542        Self::new()
543    }
544}
545
546#[cfg(test)]
547mod tests {
548    use radio_datetime_utils::DST_JUMP;
549
550    use super::*;
551
552    const BIT_BUFFER_A: [bool; 60] = [
553        true, // begin-of-minute marker
554        false, false, false, false, false, false, false, false, // unused 1-8
555        false, false, false, false, false, false, false, false, // unused 9-16
556        false, false, true, false, false, false, true, false, // year 22
557        true, false, false, false, false, // month 10
558        true, false, false, false, true, true, // day 23
559        true, true, false, // Saturday
560        false, true, false, true, false, false, // hour 14
561        true, false, true, true, false, false, false, // minute 58
562        false, true, true, true, true, true, true, false, // end-of-minute marker
563    ];
564    const BIT_BUFFER_B: [bool; 60] = [
565        true, // begin-of-minute marker,
566        false, false, false, false, false, false, false, false, // DUT1 positive
567        true, true, false, false, false, false, false, false, // DUT1 negative (-2)
568        false, false, false, false, false, false, false, false, // unused 17-24
569        false, false, false, false, false, false, false, false, // unused 25-32
570        false, false, false, false, false, false, false, false, // unused 33-40
571        false, false, false, false, false, false, false, false, // unused 41-48
572        false, false, false, false, // unused 49-52
573        false, // summer time warning
574        true,  // year parity
575        true,  // month+day parity
576        true,  // weekday parity
577        false, // hour+minute parity
578        true,  // summer time active
579        false, // unused
580    ];
581
582    #[test]
583    fn test_dut1_none_none_no_jump() {
584        let mut msf = MSFUtils::default();
585        msf.second = 59;
586        for b in 0..=59 {
587            msf.bit_buffer_a[b] = Some(BIT_BUFFER_A[b]);
588            msf.eom = (msf.eom << 1) + BIT_BUFFER_A[b] as u8;
589            msf.bit_buffer_b[b] = Some(BIT_BUFFER_B[b]);
590        }
591        msf.bit_buffer_b[1] = Some(true); // force None DUT1
592        msf.decode_time(true, false);
593        // we should have a valid decoding:
594        assert_eq!(msf.radio_datetime.get_minute(), Some(58));
595        assert_eq!(msf.radio_datetime.get_dut1(), None);
596        // bump minute to 59:
597        msf.bit_buffer_a[51] = Some(true);
598        msf.bit_buffer_b[57] = Some(true);
599        msf.decode_time(true, false);
600        assert_eq!(msf.radio_datetime.get_minute(), Some(59));
601        assert_eq!(msf.radio_datetime.get_dut1(), None);
602        assert_eq!(msf.radio_datetime.get_jump_dut1(), false);
603    }
604
605    #[test]
606    fn test_dut1_none_some_no_jump() {
607        let mut msf = MSFUtils::default();
608        msf.second = 59;
609        for b in 0..=59 {
610            msf.bit_buffer_a[b] = Some(BIT_BUFFER_A[b]);
611            msf.eom = (msf.eom << 1) + BIT_BUFFER_A[b] as u8;
612            msf.bit_buffer_b[b] = Some(BIT_BUFFER_B[b]);
613        }
614        msf.bit_buffer_b[1] = Some(true); // force None DUT1
615        msf.decode_time(true, false);
616        // we should have a valid decoding:
617        assert_eq!(msf.radio_datetime.get_minute(), Some(58));
618        assert_eq!(msf.radio_datetime.get_dut1(), None);
619        msf.bit_buffer_b[1] = Some(false); // DUT1 to -2 again
620        msf.bit_buffer_a[51] = Some(true); // bump minute to 59
621        msf.bit_buffer_b[57] = Some(true); // time parity
622        msf.decode_time(true, false);
623        assert_eq!(msf.radio_datetime.get_minute(), Some(59));
624        assert_eq!(msf.radio_datetime.get_dut1(), Some(-2));
625        assert_eq!(msf.radio_datetime.get_jump_dut1(), false);
626    }
627
628    #[test]
629    fn test_dut1_some_none_no_jump() {
630        let mut msf = MSFUtils::default();
631        msf.second = 59;
632        for b in 0..=59 {
633            msf.bit_buffer_a[b] = Some(BIT_BUFFER_A[b]);
634            msf.eom = (msf.eom << 1) + BIT_BUFFER_A[b] as u8;
635            msf.bit_buffer_b[b] = Some(BIT_BUFFER_B[b]);
636        }
637        msf.decode_time(true, false);
638        // we should have a valid decoding:
639        assert_eq!(msf.radio_datetime.get_minute(), Some(58));
640        assert_eq!(msf.radio_datetime.get_dut1(), Some(-2));
641        msf.bit_buffer_b[1] = Some(true); // should keep old DUT1
642        msf.bit_buffer_a[51] = Some(true); // bump minute to 59
643        msf.bit_buffer_b[57] = Some(true); // time parity
644        msf.decode_time(true, false);
645        assert_eq!(msf.radio_datetime.get_minute(), Some(59));
646        assert_eq!(msf.radio_datetime.get_dut1(), Some(-2));
647        assert_eq!(msf.radio_datetime.get_jump_dut1(), false);
648    }
649
650    #[test]
651    fn test_dut1_some_x_some_x_no_jump() {
652        let mut msf = MSFUtils::default();
653        msf.second = 59;
654        for b in 0..=59 {
655            msf.bit_buffer_a[b] = Some(BIT_BUFFER_A[b]);
656            msf.eom = (msf.eom << 1) + BIT_BUFFER_A[b] as u8;
657            msf.bit_buffer_b[b] = Some(BIT_BUFFER_B[b]);
658        }
659        msf.decode_time(true, false);
660        // we should have a valid decoding:
661        assert_eq!(msf.radio_datetime.get_minute(), Some(58));
662        assert_eq!(msf.radio_datetime.get_dut1(), Some(-2));
663        msf.bit_buffer_a[51] = Some(true); // bump minute to 59
664        msf.bit_buffer_b[57] = Some(true); // time parity
665        msf.decode_time(true, false);
666        assert_eq!(msf.radio_datetime.get_minute(), Some(59));
667        assert_eq!(msf.radio_datetime.get_dut1(), Some(-2));
668        assert_eq!(msf.radio_datetime.get_jump_dut1(), false);
669    }
670
671    #[test]
672    fn test_dut1_some_x_some_y_jump() {
673        let mut msf = MSFUtils::default();
674        msf.second = 59;
675        for b in 0..=59 {
676            msf.bit_buffer_a[b] = Some(BIT_BUFFER_A[b]);
677            msf.eom = (msf.eom << 1) + BIT_BUFFER_A[b] as u8;
678            msf.bit_buffer_b[b] = Some(BIT_BUFFER_B[b]);
679        }
680        msf.decode_time(true, false);
681        // we should have a valid decoding:
682        assert_eq!(msf.radio_datetime.get_minute(), Some(58));
683        assert_eq!(msf.radio_datetime.get_dut1(), Some(-2));
684        msf.bit_buffer_a[51] = Some(true); // bump minute to 59
685        msf.bit_buffer_b[57] = Some(true); // time parity
686        msf.bit_buffer_b[11] = Some(true); // DUT1 = -3
687        msf.decode_time(true, false);
688        assert_eq!(msf.radio_datetime.get_minute(), Some(59));
689        assert_eq!(msf.radio_datetime.get_dut1(), Some(-3));
690        assert_eq!(msf.radio_datetime.get_jump_dut1(), true);
691        // no jump for DUT1=-3 on next minute (15:00):
692        // reset minute to 0:
693        for b in 45..=51 {
694            msf.bit_buffer_a[b] = Some(false);
695        }
696        msf.bit_buffer_a[44] = Some(true); // bump hour to 15
697        msf.bit_buffer_b[57] = Some(false); // time parity
698        msf.decode_time(true, false);
699        assert_eq!(msf.radio_datetime.get_minute(), Some(0));
700        assert_eq!(msf.radio_datetime.get_hour(), Some(15));
701        assert_eq!(msf.get_parity_4(), Some(true));
702        assert_eq!(msf.radio_datetime.get_dut1(), Some(-3));
703        assert_eq!(msf.radio_datetime.get_jump_dut1(), false);
704    }
705
706    #[test]
707    fn test_dut1_some_x_some_x_midnight_no_jump() {
708        let mut msf = MSFUtils::default();
709        msf.second = 59;
710        for b in 0..=59 {
711            msf.bit_buffer_a[b] = Some(BIT_BUFFER_A[b]);
712            msf.eom = (msf.eom << 1) + BIT_BUFFER_A[b] as u8;
713            msf.bit_buffer_b[b] = Some(BIT_BUFFER_B[b]);
714        }
715        // bump minute to 59:
716        msf.bit_buffer_a[51] = Some(true);
717        // reset hour to 0 (BST active in sample data):
718        for b in 39..=44 {
719            msf.bit_buffer_a[b] = Some(false);
720        }
721        msf.bit_buffer_b[57] = Some(true); // time parity
722        msf.decode_time(true, false);
723        // we should have a valid decoding:
724        assert_eq!(msf.radio_datetime.get_minute(), Some(59));
725        assert_eq!(msf.radio_datetime.get_hour(), Some(0));
726        assert_eq!(msf.get_parity_4(), Some(true));
727        assert_eq!(msf.radio_datetime.get_dut1(), Some(-2));
728        // reset minute to 0:
729        for b in 45..=51 {
730            msf.bit_buffer_a[b] = Some(false);
731        }
732        msf.bit_buffer_a[44] = Some(true); // bump hour to 1
733        msf.bit_buffer_b[57] = Some(false); // time parity
734        msf.decode_time(true, false);
735        assert_eq!(msf.radio_datetime.get_minute(), Some(0));
736        assert_eq!(msf.radio_datetime.get_hour(), Some(1));
737        assert_eq!(msf.get_parity_4(), Some(true));
738        assert_eq!(msf.radio_datetime.get_dut1(), Some(-2));
739        assert_eq!(msf.radio_datetime.get_jump_dut1(), false);
740    }
741
742    #[test]
743    fn test_dut1_some_x_some_y_midnight_no_jump() {
744        let mut msf = MSFUtils::default();
745        msf.second = 59;
746        for b in 0..=59 {
747            msf.bit_buffer_a[b] = Some(BIT_BUFFER_A[b]);
748            msf.eom = (msf.eom << 1) + BIT_BUFFER_A[b] as u8;
749            msf.bit_buffer_b[b] = Some(BIT_BUFFER_B[b]);
750        }
751        // bump minute to 59:
752        msf.bit_buffer_a[51] = Some(true);
753        // reset hour to 0 (BST active in sample data):
754        for b in 39..=44 {
755            msf.bit_buffer_a[b] = Some(false);
756        }
757        msf.bit_buffer_b[57] = Some(true); // time parity
758        msf.decode_time(true, false);
759        // we should have a valid decoding:
760        assert_eq!(msf.radio_datetime.get_minute(), Some(59));
761        assert_eq!(msf.radio_datetime.get_hour(), Some(0));
762        assert_eq!(msf.get_parity_4(), Some(true));
763        assert_eq!(msf.radio_datetime.get_dut1(), Some(-2));
764        // reset minute to 0:
765        for b in 45..=51 {
766            msf.bit_buffer_a[b] = Some(false);
767        }
768        msf.bit_buffer_a[44] = Some(true); // bump hour to 1
769        msf.bit_buffer_b[57] = Some(false); // time parity
770        msf.bit_buffer_b[11] = Some(true); // DUT1 = -3
771        msf.decode_time(true, false);
772        assert_eq!(msf.radio_datetime.get_minute(), Some(0));
773        assert_eq!(msf.radio_datetime.get_hour(), Some(1));
774        assert_eq!(msf.get_parity_4(), Some(true));
775        assert_eq!(msf.radio_datetime.get_dut1(), Some(-3));
776        assert_eq!(msf.radio_datetime.get_jump_dut1(), false);
777    }
778
779    #[test]
780    fn test_new_edge_bit_0_0() {
781        const EDGE_BUFFER: [(bool, u32); 4] = [
782            // Some(false,false) bit value
783            (false, 422_994_439), // 0
784            (true, 423_907_610),  // 913_171
785            (false, 423_997_265), // 89_655
786            (true, 424_906_368),  // 909_103
787        ];
788        let mut msf = MSFUtils::default();
789        assert_eq!(msf.before_first_edge, true);
790        msf.handle_new_edge(EDGE_BUFFER[0].0, EDGE_BUFFER[0].1);
791        assert_eq!(msf.before_first_edge, false);
792        assert_eq!(msf.t0, EDGE_BUFFER[0].1); // very first edge
793
794        msf.handle_new_edge(EDGE_BUFFER[1].0, EDGE_BUFFER[1].1); // first significant edge
795        assert_eq!(msf.t0, EDGE_BUFFER[1].1); // longer than a spike
796        assert_eq!(msf.new_second, true);
797        assert_eq!(msf.past_new_minute, false);
798        assert_eq!(msf.get_current_bit_a(), None); // not yet determined, passive part
799        assert_eq!(msf.get_current_bit_b(), None); // not yet determined, passive part
800
801        msf.handle_new_edge(EDGE_BUFFER[2].0, EDGE_BUFFER[2].1);
802        assert_eq!(msf.t0, EDGE_BUFFER[2].1); // longer than a spike
803        assert_eq!(msf.new_second, false);
804        assert_eq!(msf.past_new_minute, false);
805        assert_eq!(msf.get_current_bit_a(), Some(false));
806        assert_eq!(msf.get_current_bit_b(), Some(false));
807
808        // passive part of second must keep the bit value
809        msf.handle_new_edge(EDGE_BUFFER[3].0, EDGE_BUFFER[3].1);
810        assert_eq!(msf.t0, EDGE_BUFFER[3].1); // longer than a spike
811        assert_eq!(msf.new_second, true);
812        assert_eq!(msf.past_new_minute, false);
813        assert_eq!(msf.get_current_bit_a(), Some(false)); // keep bit value
814        assert_eq!(msf.get_current_bit_b(), Some(false)); // keep bit value
815    }
816
817    #[test]
818    fn test_new_edge_bit_0_1() {
819        // TODO replace with real data once (0,1) bit pairs are broadcast again
820        const EDGE_BUFFER: [(bool, u32); 6] = [
821            // Some(false,false) bit value
822            (false, 0),         // 0
823            (true, 920_000),    // 920_000
824            (false, 1_030_000), // 110_000
825            (true, 1_128_000),  // 98_000
826            (false, 1_232_000), // 104_000
827            (true, 1_896_000),  // 644_000
828        ];
829        let mut msf = MSFUtils::default();
830        assert_eq!(msf.before_first_edge, true);
831        msf.handle_new_edge(EDGE_BUFFER[0].0, EDGE_BUFFER[0].1);
832        assert_eq!(msf.before_first_edge, false);
833        assert_eq!(msf.t0, EDGE_BUFFER[0].1); // very first edge
834
835        msf.handle_new_edge(EDGE_BUFFER[1].0, EDGE_BUFFER[1].1); // first significant edge
836        assert_eq!(msf.t0, EDGE_BUFFER[1].1); // longer than a spike
837        assert_eq!(msf.new_second, true);
838        assert_eq!(msf.past_new_minute, false);
839        assert_eq!(msf.get_current_bit_a(), None); // not yet determined, passive part
840        assert_eq!(msf.get_current_bit_b(), None); // not yet determined, passive part
841
842        // active signal part one, so we should get an intermediate (0,0) bit pair here:
843        msf.handle_new_edge(EDGE_BUFFER[2].0, EDGE_BUFFER[2].1);
844        assert_eq!(msf.t0, EDGE_BUFFER[2].1); // longer than a spike
845        assert_eq!(msf.new_second, false);
846        assert_eq!(msf.past_new_minute, false);
847        assert_eq!(msf.get_current_bit_a(), Some(false));
848        assert_eq!(msf.get_current_bit_b(), Some(false));
849
850        // passive signal part one (up to `ACTIVE_0_LIMIT` or 150_000 microseconds),
851        // keep bit values:
852        msf.handle_new_edge(EDGE_BUFFER[3].0, EDGE_BUFFER[3].1);
853        assert_eq!(msf.t0, EDGE_BUFFER[3].1); // longer than a spike
854        assert_eq!(msf.new_second, false);
855        assert_eq!(msf.past_new_minute, false);
856        assert_eq!(msf.get_current_bit_a(), Some(false));
857        assert_eq!(msf.get_current_bit_b(), Some(false));
858
859        // active signal part two, get the (0,1) bit pair:
860        msf.handle_new_edge(EDGE_BUFFER[4].0, EDGE_BUFFER[4].1);
861        assert_eq!(msf.t0, EDGE_BUFFER[4].1); // longer than a spike
862        assert_eq!(msf.new_second, false);
863        assert_eq!(msf.past_new_minute, false);
864        assert_eq!(msf.get_current_bit_a(), Some(false));
865        assert_eq!(msf.get_current_bit_b(), Some(true));
866
867        // passive signal part two, keep the bit values:
868        msf.handle_new_edge(EDGE_BUFFER[5].0, EDGE_BUFFER[5].1);
869        assert_eq!(msf.t0, EDGE_BUFFER[5].1); // longer than a spike
870        assert_eq!(msf.new_second, true);
871        assert_eq!(msf.past_new_minute, false);
872        assert_eq!(msf.get_current_bit_a(), Some(false)); // keep bit value
873        assert_eq!(msf.get_current_bit_b(), Some(true)); // keep bit value
874    }
875
876    #[test]
877    fn test_new_edge_bit_1_0() {
878        const EDGE_BUFFER: [(bool, u32); 4] = [
879            // Some(true,false) bit value
880            (false, 413_999_083), // 0
881            (true, 414_909_075),  // 918_992
882            (false, 415_090_038), // 180_963
883            (true, 415_908_781),  // 818_743
884        ];
885        let mut msf = MSFUtils::default();
886        assert_eq!(msf.before_first_edge, true);
887        msf.handle_new_edge(EDGE_BUFFER[0].0, EDGE_BUFFER[0].1);
888        assert_eq!(msf.before_first_edge, false);
889        assert_eq!(msf.t0, EDGE_BUFFER[0].1); // very first edge
890
891        msf.handle_new_edge(EDGE_BUFFER[1].0, EDGE_BUFFER[1].1); // first significant edge
892        assert_eq!(msf.t0, EDGE_BUFFER[1].1); // longer than a spike
893        assert_eq!(msf.new_second, true);
894        assert_eq!(msf.past_new_minute, false);
895        assert_eq!(msf.get_current_bit_a(), None); // not yet determined, passive part
896        assert_eq!(msf.get_current_bit_b(), None); // not yet determined, passive part
897
898        msf.handle_new_edge(EDGE_BUFFER[2].0, EDGE_BUFFER[2].1);
899        assert_eq!(msf.t0, EDGE_BUFFER[2].1); // longer than a spike
900        assert_eq!(msf.new_second, false);
901        assert_eq!(msf.past_new_minute, false);
902        assert_eq!(msf.get_current_bit_a(), Some(true));
903        assert_eq!(msf.get_current_bit_b(), Some(false));
904
905        // passive part of second must keep the bit value
906        msf.handle_new_edge(EDGE_BUFFER[3].0, EDGE_BUFFER[3].1);
907        assert_eq!(msf.t0, EDGE_BUFFER[3].1); // longer than a spike
908        assert_eq!(msf.new_second, true);
909        assert_eq!(msf.past_new_minute, false);
910        assert_eq!(msf.get_current_bit_a(), Some(true)); // keep bit value
911        assert_eq!(msf.get_current_bit_b(), Some(false)); // keep bit value
912    }
913
914    #[test]
915    fn test_new_edge_bit_1_1() {
916        const EDGE_BUFFER: [(bool, u32); 4] = [
917            // Some(true,true) bit value
918            (false, 415_090_038), // 0
919            (true, 415_908_781),  // 818_743
920            (false, 416_194_383), // 285_602
921            (true, 416_901_482),  // 707_099
922        ];
923        let mut msf = MSFUtils::default();
924        assert_eq!(msf.before_first_edge, true);
925        msf.handle_new_edge(EDGE_BUFFER[0].0, EDGE_BUFFER[0].1);
926        assert_eq!(msf.before_first_edge, false);
927        assert_eq!(msf.t0, EDGE_BUFFER[0].1); // very first edge
928
929        msf.handle_new_edge(EDGE_BUFFER[1].0, EDGE_BUFFER[1].1); // first significant edge
930        assert_eq!(msf.t0, EDGE_BUFFER[1].1); // longer than a spike
931        assert_eq!(msf.new_second, true);
932        assert_eq!(msf.past_new_minute, false);
933        assert_eq!(msf.get_current_bit_a(), None); // not yet determined, passive part
934        assert_eq!(msf.get_current_bit_b(), None); // not yet determined, passive part
935
936        msf.handle_new_edge(EDGE_BUFFER[2].0, EDGE_BUFFER[2].1);
937        assert_eq!(msf.t0, EDGE_BUFFER[2].1); // longer than a spike
938        assert_eq!(msf.new_second, false);
939        assert_eq!(msf.past_new_minute, false);
940        assert_eq!(msf.get_current_bit_a(), Some(true));
941        assert_eq!(msf.get_current_bit_b(), Some(true));
942
943        // passive part of second must keep the bit value
944        msf.handle_new_edge(EDGE_BUFFER[3].0, EDGE_BUFFER[3].1);
945        assert_eq!(msf.t0, EDGE_BUFFER[3].1); // longer than a spike
946        assert_eq!(msf.new_second, true);
947        assert_eq!(msf.past_new_minute, false);
948        assert_eq!(msf.get_current_bit_a(), Some(true)); // keep bit value
949        assert_eq!(msf.get_current_bit_b(), Some(true)); // keep bit value
950    }
951
952    #[test]
953    fn test_new_edge_minute() {
954        const EDGE_BUFFER: [(bool, u32); 3] = [
955            // new minute, (true,true) bit value
956            (false, 420_994_620), // 0
957            (true, 421_906_680),  // 912_060
958            (false, 422_389_442), // 482_762
959        ];
960        let mut msf = MSFUtils::default();
961        assert_eq!(msf.before_first_edge, true);
962        msf.handle_new_edge(EDGE_BUFFER[0].0, EDGE_BUFFER[0].1);
963        assert_eq!(msf.before_first_edge, false);
964        assert_eq!(msf.t0, EDGE_BUFFER[0].1); // very first edge
965
966        msf.handle_new_edge(EDGE_BUFFER[1].0, EDGE_BUFFER[1].1); // first significant edge
967        assert_eq!(msf.t0, EDGE_BUFFER[1].1); // longer than a spike
968        assert_eq!(msf.new_second, true);
969        assert_eq!(msf.past_new_minute, false);
970        assert_eq!(msf.get_current_bit_a(), None); // not yet determined
971        assert_eq!(msf.get_current_bit_b(), None); // not yet determined
972
973        msf.handle_new_edge(EDGE_BUFFER[2].0, EDGE_BUFFER[2].1); // new minute
974        assert_eq!(msf.t0, EDGE_BUFFER[2].1); // longer than a spike
975        assert_eq!(msf.new_second, false);
976        assert_eq!(msf.past_new_minute, true);
977        assert_eq!(msf.get_current_bit_a(), Some(true));
978        assert_eq!(msf.get_current_bit_b(), Some(true));
979    }
980
981    #[test]
982    fn test_new_edge_active_runaway() {
983        const EDGE_BUFFER: [(bool, u32); 3] = [
984            // active runaway (broken bit)
985            (false, 417_195_653), // 0
986            (true, 417_908_323),  // 712_670
987            (false, 419_193_216), // 1_284_893
988        ];
989        let mut msf = MSFUtils::default();
990        assert_eq!(msf.before_first_edge, true);
991        msf.handle_new_edge(EDGE_BUFFER[0].0, EDGE_BUFFER[0].1);
992        assert_eq!(msf.before_first_edge, false);
993        assert_eq!(msf.t0, EDGE_BUFFER[0].1); // very first edge
994
995        msf.handle_new_edge(EDGE_BUFFER[1].0, EDGE_BUFFER[1].1); // first significant edge
996        assert_eq!(msf.t0, EDGE_BUFFER[1].1); // longer than a spike
997        assert_eq!(msf.new_second, true);
998        assert_eq!(msf.past_new_minute, false);
999        assert_eq!(msf.get_current_bit_a(), None); // not yet determined, passive part
1000        assert_eq!(msf.get_current_bit_b(), None); // not yet determined, passive part
1001
1002        msf.handle_new_edge(EDGE_BUFFER[2].0, EDGE_BUFFER[2].1);
1003        assert_eq!(msf.t0, EDGE_BUFFER[2].1); // longer than a spike
1004        assert_eq!(msf.new_second, false);
1005        assert_eq!(msf.past_new_minute, false);
1006        assert_eq!(msf.get_current_bit_a(), None);
1007        assert_eq!(msf.get_current_bit_b(), None);
1008    }
1009
1010    #[test]
1011    fn test_new_edge_passive_runaway() {
1012        const EDGE_BUFFER: [(bool, u32); 4] = [
1013            // passive runaway (transmitter outage?)
1014            (false, 897_105_780), // 0
1015            (true, 898_042_361),  // 936_581
1016            (false, 898_110_362), // 68_001 (0,0) bit
1017            (true, 900_067_737),  // 1_957_375 passive runaway
1018        ];
1019        let mut msf = MSFUtils::default();
1020        assert_eq!(msf.before_first_edge, true);
1021        msf.handle_new_edge(EDGE_BUFFER[0].0, EDGE_BUFFER[0].1);
1022        assert_eq!(msf.before_first_edge, false);
1023        assert_eq!(msf.t0, EDGE_BUFFER[0].1); // very first edge
1024
1025        msf.handle_new_edge(EDGE_BUFFER[1].0, EDGE_BUFFER[1].1); // first significant edge
1026        assert_eq!(msf.t0, EDGE_BUFFER[1].1); // longer than a spike
1027        assert_eq!(msf.new_second, true);
1028        assert_eq!(msf.past_new_minute, false);
1029        assert_eq!(msf.get_current_bit_a(), None); // not yet determined, passive part
1030        assert_eq!(msf.get_current_bit_b(), None); // not yet determined, passive part
1031
1032        msf.handle_new_edge(EDGE_BUFFER[2].0, EDGE_BUFFER[2].1);
1033        assert_eq!(msf.t0, EDGE_BUFFER[2].1); // longer than a spike
1034        assert_eq!(msf.new_second, false);
1035        assert_eq!(msf.past_new_minute, false);
1036        assert_eq!(msf.get_current_bit_a(), Some(false));
1037        assert_eq!(msf.get_current_bit_b(), Some(false));
1038
1039        // passive part of second must keep the bit value
1040        msf.handle_new_edge(EDGE_BUFFER[3].0, EDGE_BUFFER[3].1);
1041        assert_eq!(msf.t0, EDGE_BUFFER[3].1); // longer than a spike
1042        assert_eq!(msf.new_second, false);
1043        assert_eq!(msf.past_new_minute, false);
1044        assert_eq!(msf.get_current_bit_a(), None);
1045        assert_eq!(msf.get_current_bit_b(), None);
1046    }
1047
1048    #[test]
1049    fn test_new_edge_spikes() {
1050        const EDGE_BUFFER: [(bool, u32); 8] = [
1051            // spikes
1052            (false, 900_122_127), // 0
1053            (true, 901_052_140),  // 930_013
1054            (false, 901_226_910), // 174_770
1055            (true, 902_069_956),  // 843_046
1056            (false, 902_085_860), // 15_904
1057            (true, 902_105_980),  // 20_120
1058            (false, 902_115_859), // 9_879
1059            (true, 903_057_346),  // 941_487
1060        ];
1061        let mut msf = MSFUtils::default();
1062        assert_eq!(msf.before_first_edge, true);
1063        msf.handle_new_edge(EDGE_BUFFER[0].0, EDGE_BUFFER[0].1);
1064        assert_eq!(msf.before_first_edge, false);
1065        assert_eq!(msf.t0, EDGE_BUFFER[0].1); // very first edge
1066
1067        msf.handle_new_edge(EDGE_BUFFER[1].0, EDGE_BUFFER[1].1); // first significant edge
1068        assert_eq!(msf.t0, EDGE_BUFFER[1].1); // longer than a spike
1069        assert_eq!(msf.new_second, true);
1070        assert_eq!(msf.past_new_minute, false);
1071        assert_eq!(msf.get_current_bit_a(), None); // not yet determined
1072        assert_eq!(msf.get_current_bit_b(), None); // not yet determined
1073
1074        msf.handle_new_edge(EDGE_BUFFER[2].0, EDGE_BUFFER[2].1);
1075        assert_eq!(msf.t0, EDGE_BUFFER[2].1); // longer than a spike
1076        assert_eq!(msf.new_second, false);
1077        assert_eq!(msf.past_new_minute, false);
1078        assert_eq!(msf.get_current_bit_a(), Some(true));
1079        assert_eq!(msf.get_current_bit_b(), Some(false));
1080
1081        msf.handle_new_edge(EDGE_BUFFER[3].0, EDGE_BUFFER[3].1); // first significant edge
1082        assert_eq!(msf.t0, EDGE_BUFFER[3].1); // longer than a spike
1083        assert_eq!(msf.new_second, true);
1084        assert_eq!(msf.past_new_minute, false);
1085        assert_eq!(msf.get_current_bit_a(), Some(true)); // keep value
1086        assert_eq!(msf.get_current_bit_b(), Some(false)); // keep value
1087
1088        // Feed a bunch of spikes of less than spike_limit us, nothing should happen
1089        let mut spike = msf.t0;
1090        for i in 4..=6 {
1091            spike += radio_datetime_helpers::time_diff(EDGE_BUFFER[i - 1].1, EDGE_BUFFER[i].1);
1092            msf.handle_new_edge(EDGE_BUFFER[i].0, EDGE_BUFFER[i].1);
1093            assert_eq!(msf.t0, spike);
1094            assert_eq!(msf.new_second, true);
1095            assert_eq!(msf.past_new_minute, false);
1096            assert_eq!(msf.get_current_bit_a(), Some(true));
1097            assert_eq!(msf.get_current_bit_b(), Some(false));
1098        }
1099        msf.handle_new_edge(EDGE_BUFFER[7].0, EDGE_BUFFER[7].1);
1100        assert_eq!(msf.t0, EDGE_BUFFER[7].1); // longer than a spike
1101        assert_eq!(msf.new_second, true); // regular new second
1102        assert_eq!(msf.past_new_minute, false);
1103        assert_eq!(msf.get_current_bit_a(), Some(true)); // keep value
1104        assert_eq!(msf.get_current_bit_b(), Some(false)); // keep value
1105    }
1106
1107    #[test]
1108    fn test_eom_marker_absent() {
1109        let mut msf = MSFUtils::default();
1110        msf.second = 59;
1111        for b in 52..=59 {
1112            msf.bit_buffer_a[b] = Some(BIT_BUFFER_A[b]);
1113            msf.eom = (msf.eom << 1) + BIT_BUFFER_A[b] as u8;
1114        }
1115        msf.bit_buffer_a[57] = None; // introduce an error
1116        msf.eom = 0;
1117        assert_eq!(msf.end_of_minute_marker_present(), false);
1118    }
1119
1120    #[test]
1121    fn test_eom_marker_present() {
1122        let mut msf = MSFUtils::default();
1123        msf.second = 59;
1124        for b in 52..=59 {
1125            msf.bit_buffer_a[b] = Some(BIT_BUFFER_A[b]);
1126            msf.eom = (msf.eom << 1) + BIT_BUFFER_A[b] as u8;
1127        }
1128        assert_eq!(msf.end_of_minute_marker_present(), true);
1129    }
1130
1131    #[test]
1132    fn test_running_negative_leap_second() {
1133        let mut msf = MSFUtils::default();
1134        msf.second = 51;
1135        for b in 51..=57 {
1136            msf.bit_buffer_a[b] = Some(BIT_BUFFER_A[b + 1]);
1137            msf.eom = (msf.eom << 1) + BIT_BUFFER_A[b + 1] as u8;
1138            assert_eq!(msf.end_of_minute_marker_present(), false); // not done yet
1139            assert_eq!(msf.get_minute_length(), 60); // default for no EOM marker
1140            assert_eq!(msf.increase_second(), true);
1141        }
1142        assert_eq!(msf.second, 58);
1143        msf.bit_buffer_a[58] = Some(BIT_BUFFER_A[59]);
1144        msf.eom = (msf.eom << 1) + BIT_BUFFER_A[59] as u8;
1145        assert_eq!(msf.end_of_minute_marker_present(), true);
1146        assert_eq!(msf.get_minute_length(), 59); // negative leap second
1147    }
1148
1149    #[test]
1150    fn test_running_no_leap_second() {
1151        let mut msf = MSFUtils::default();
1152        msf.second = 52;
1153        for b in 52..=58 {
1154            msf.bit_buffer_a[b] = Some(BIT_BUFFER_A[b]);
1155            msf.eom = (msf.eom << 1) + BIT_BUFFER_A[b] as u8;
1156            assert_eq!(msf.end_of_minute_marker_present(), false); // not done yet
1157            assert_eq!(msf.get_minute_length(), 60); // default for no EOM marker
1158            assert_eq!(msf.increase_second(), true);
1159        }
1160        assert_eq!(msf.second, 59);
1161        msf.bit_buffer_a[59] = Some(BIT_BUFFER_A[59]);
1162        msf.eom = (msf.eom << 1) + BIT_BUFFER_A[59] as u8;
1163        assert_eq!(msf.end_of_minute_marker_present(), true);
1164        assert_eq!(msf.get_minute_length(), 60); // no leap second
1165    }
1166
1167    #[test]
1168    fn test_running_positive_leap_second() {
1169        let mut msf = MSFUtils::default();
1170        msf.second = 53;
1171        for b in 53..=58 {
1172            msf.bit_buffer_a[b] = Some(BIT_BUFFER_A[b - 1]);
1173            msf.eom = (msf.eom << 1) + BIT_BUFFER_A[b - 1] as u8;
1174            assert_eq!(msf.end_of_minute_marker_present(), false); // not done yet
1175            assert_eq!(msf.get_minute_length(), 60); // default for no EOM marker
1176            assert_eq!(msf.increase_second(), true);
1177        }
1178        assert_eq!(msf.second, 59);
1179        msf.bit_buffer_a[59] = Some(BIT_BUFFER_A[58]);
1180        msf.eom = (msf.eom << 1) + BIT_BUFFER_A[58] as u8;
1181        assert_eq!(msf.end_of_minute_marker_present(), false);
1182        assert_eq!(msf.eom & 0x7f, 0x3f);
1183        assert_eq!(msf.get_minute_length(), 61); // positive leap second (without trailing 0 bit)
1184        assert_eq!(msf.increase_second(), true);
1185        assert_eq!(msf.second, 60);
1186        msf.bit_buffer_a[60] = Some(BIT_BUFFER_A[59]);
1187        msf.eom = (msf.eom << 1) + BIT_BUFFER_A[59] as u8;
1188        assert_eq!(msf.end_of_minute_marker_present(), true);
1189        assert_eq!(msf.get_minute_length(), 61); // positive leap second (with trailing 0 bit)
1190    }
1191
1192    // relaxed checks
1193    #[test]
1194    fn test_decode_time_incomplete_minute() {
1195        let mut msf = MSFUtils::default();
1196        assert_eq!(msf.first_minute, true);
1197        msf.second = 42;
1198        // note that msf.bit_buffer_[ab] are still empty
1199        assert_ne!(msf.get_minute_length(), msf.second);
1200        assert_eq!(msf.parity_1, None);
1201        msf.decode_time(true, false);
1202        // not enough seconds in this minute, so nothing should happen:
1203        assert_eq!(msf.parity_1, None);
1204    }
1205
1206    #[test]
1207    fn test_decode_time_complete_minute_ok() {
1208        let mut msf = MSFUtils::default();
1209        msf.second = 59;
1210        assert_eq!(msf.get_minute_length(), msf.second + 1); // EOM marker absent
1211        for b in 0..=59 {
1212            msf.bit_buffer_a[b] = Some(BIT_BUFFER_A[b]);
1213            msf.eom = (msf.eom << 1) + BIT_BUFFER_A[b] as u8;
1214            msf.bit_buffer_b[b] = Some(BIT_BUFFER_B[b]);
1215        }
1216        assert_eq!(msf.end_of_minute_marker_present(), true);
1217        msf.decode_time(true, false);
1218        // we should have a valid decoding:
1219        assert_eq!(msf.radio_datetime.get_minute(), Some(58));
1220        assert_eq!(msf.radio_datetime.get_hour(), Some(14));
1221        assert_eq!(msf.radio_datetime.get_weekday(), Some(6));
1222        assert_eq!(msf.radio_datetime.get_day(), Some(23));
1223        assert_eq!(msf.radio_datetime.get_month(), Some(10));
1224        assert_eq!(msf.radio_datetime.get_year(), Some(22));
1225        assert_eq!(msf.parity_1, Some(true));
1226        assert_eq!(msf.parity_2, Some(true));
1227        assert_eq!(msf.parity_3, Some(true));
1228        assert_eq!(msf.parity_4, Some(true));
1229        assert_eq!(
1230            msf.radio_datetime.get_dst(),
1231            Some(radio_datetime_utils::DST_SUMMER)
1232        );
1233        assert_eq!(msf.radio_datetime.get_leap_second(), None); // not available
1234        assert_eq!(msf.radio_datetime.get_dut1(), Some(-2));
1235    }
1236
1237    #[test]
1238    fn test_decode_time_complete_minute_ok_negative_leap_second() {
1239        let mut msf = MSFUtils::default();
1240        msf.second = 58;
1241        for b in 0..=15 {
1242            msf.bit_buffer_a[b] = Some(BIT_BUFFER_A[b]);
1243            msf.eom = (msf.eom << 1) + BIT_BUFFER_A[b] as u8;
1244            msf.bit_buffer_b[b] = Some(BIT_BUFFER_B[b]);
1245        }
1246        // bit 16 removed
1247        for b in 17..=59 {
1248            msf.bit_buffer_a[b - 1] = Some(BIT_BUFFER_A[b]);
1249            msf.eom = (msf.eom << 1) + BIT_BUFFER_A[b] as u8;
1250            msf.bit_buffer_b[b - 1] = Some(BIT_BUFFER_B[b]);
1251        }
1252        assert_eq!(msf.end_of_minute_marker_present(), true);
1253        assert_eq!(msf.get_minute_length(), msf.second + 1);
1254        msf.decode_time(true, false);
1255        // we should have a valid decoding:
1256        assert_eq!(msf.radio_datetime.get_minute(), Some(58));
1257        assert_eq!(msf.radio_datetime.get_hour(), Some(14));
1258        assert_eq!(msf.radio_datetime.get_weekday(), Some(6));
1259        assert_eq!(msf.radio_datetime.get_day(), Some(23));
1260        assert_eq!(msf.radio_datetime.get_month(), Some(10));
1261        assert_eq!(msf.radio_datetime.get_year(), Some(22));
1262        assert_eq!(msf.parity_1, Some(true));
1263        assert_eq!(msf.parity_2, Some(true));
1264        assert_eq!(msf.parity_3, Some(true));
1265        assert_eq!(msf.parity_4, Some(true));
1266        assert_eq!(
1267            msf.radio_datetime.get_dst(),
1268            Some(radio_datetime_utils::DST_SUMMER)
1269        );
1270        assert_eq!(msf.radio_datetime.get_leap_second(), None); // not available
1271        assert_eq!(msf.radio_datetime.get_dut1(), Some(-2));
1272        assert_eq!(msf.first_minute, false);
1273    }
1274
1275    #[test]
1276    fn test_decode_time_complete_minute_ok_positive_leap_second() {
1277        let mut msf = MSFUtils::default();
1278        msf.second = 60;
1279        for b in 0..=16 {
1280            msf.bit_buffer_a[b] = Some(BIT_BUFFER_A[b]);
1281            msf.eom = (msf.eom << 1) + BIT_BUFFER_A[b] as u8;
1282            msf.bit_buffer_b[b] = Some(BIT_BUFFER_B[b]);
1283        }
1284        // insert the positive leap second, left None on purpose (it should not affect decoding)
1285        msf.bit_buffer_a[17] = None;
1286        msf.eom = 0;
1287        msf.bit_buffer_b[17] = None;
1288        for b in 17..=59 {
1289            msf.bit_buffer_a[b + 1] = Some(BIT_BUFFER_A[b]);
1290            msf.eom = (msf.eom << 1) + BIT_BUFFER_A[b] as u8;
1291            msf.bit_buffer_b[b + 1] = Some(BIT_BUFFER_B[b]);
1292        }
1293        assert_eq!(msf.end_of_minute_marker_present(), true);
1294        assert_eq!(msf.get_minute_length(), msf.second + 1);
1295        msf.decode_time(true, false);
1296        // we should have a valid decoding:
1297        assert_eq!(msf.radio_datetime.get_minute(), Some(58));
1298        assert_eq!(msf.radio_datetime.get_hour(), Some(14));
1299        assert_eq!(msf.radio_datetime.get_weekday(), Some(6));
1300        assert_eq!(msf.radio_datetime.get_day(), Some(23));
1301        assert_eq!(msf.radio_datetime.get_month(), Some(10));
1302        assert_eq!(msf.radio_datetime.get_year(), Some(22));
1303        assert_eq!(msf.parity_1, Some(true));
1304        assert_eq!(msf.parity_2, Some(true));
1305        assert_eq!(msf.parity_3, Some(true));
1306        assert_eq!(msf.parity_4, Some(true));
1307        assert_eq!(
1308            msf.radio_datetime.get_dst(),
1309            Some(radio_datetime_utils::DST_SUMMER)
1310        );
1311        assert_eq!(msf.radio_datetime.get_leap_second(), None); // not available
1312        assert_eq!(msf.radio_datetime.get_dut1(), Some(-2));
1313        assert_eq!(msf.first_minute, false);
1314    }
1315
1316    #[test]
1317    fn test_decode_time_complete_minute_bad_bits() {
1318        let mut msf = MSFUtils::default();
1319        msf.second = 59;
1320        assert_eq!(msf.get_minute_length(), msf.second + 1); // EOM marker absent
1321        for b in 0..=59 {
1322            msf.bit_buffer_a[b] = Some(BIT_BUFFER_A[b]);
1323            msf.eom = (msf.eom << 1) + BIT_BUFFER_A[b] as u8;
1324            msf.bit_buffer_b[b] = Some(BIT_BUFFER_B[b]);
1325        }
1326        // introduce some distortions:
1327        msf.bit_buffer_b[1] = Some(true); // now both 1-8 and 9-16 are positive, which is an error
1328        msf.bit_buffer_a[31] = None; // None day
1329        msf.bit_buffer_a[48] = Some(false);
1330        msf.decode_time(true, false);
1331        assert_eq!(msf.radio_datetime.get_minute(), None); // bad parity and first decoding
1332        assert_eq!(msf.radio_datetime.get_hour(), None); // bad parity and first decoding
1333        assert_eq!(msf.radio_datetime.get_weekday(), Some(6));
1334        assert_eq!(msf.radio_datetime.get_day(), None); // broken bit
1335        assert_eq!(msf.radio_datetime.get_month(), None); // broken parity and first decoding
1336        assert_eq!(msf.radio_datetime.get_year(), Some(22));
1337        assert_eq!(msf.parity_1, Some(true));
1338        assert_eq!(msf.parity_2, None); // broken bit
1339        assert_eq!(msf.parity_3, Some(true));
1340        assert_eq!(msf.parity_4, Some(false)); // bad parity
1341        assert_eq!(
1342            msf.radio_datetime.get_dst(),
1343            Some(radio_datetime_utils::DST_SUMMER)
1344        );
1345        assert_eq!(msf.radio_datetime.get_leap_second(), None);
1346        assert_eq!(msf.radio_datetime.get_dut1(), None);
1347    }
1348
1349    #[test]
1350    fn continue_decode_time_complete_minute_jumped_values() {
1351        let mut msf = MSFUtils::default();
1352        msf.second = 59;
1353        assert_eq!(msf.get_minute_length(), msf.second + 1); // EOM marker absent
1354        for b in 0..=59 {
1355            msf.bit_buffer_a[b] = Some(BIT_BUFFER_A[b]);
1356            msf.eom = (msf.eom << 1) + BIT_BUFFER_A[b] as u8;
1357            msf.bit_buffer_b[b] = Some(BIT_BUFFER_B[b]);
1358        }
1359        msf.decode_time(true, false);
1360        assert_eq!(msf.radio_datetime.get_minute(), Some(58));
1361        assert_eq!(msf.radio_datetime.get_jump_minute(), false);
1362        assert_eq!(msf.first_minute, false);
1363        // minute 58 is really cool, so do not update bit 51 (and 57)
1364        msf.decode_time(true, false);
1365        assert_eq!(msf.radio_datetime.get_minute(), Some(58));
1366        assert_eq!(msf.radio_datetime.get_hour(), Some(14));
1367        assert_eq!(msf.radio_datetime.get_weekday(), Some(6));
1368        assert_eq!(msf.radio_datetime.get_day(), Some(23));
1369        assert_eq!(msf.radio_datetime.get_month(), Some(10));
1370        assert_eq!(msf.radio_datetime.get_year(), Some(22));
1371        assert_eq!(msf.parity_1, Some(true));
1372        assert_eq!(msf.parity_2, Some(true));
1373        assert_eq!(msf.parity_3, Some(true));
1374        assert_eq!(msf.parity_4, Some(true));
1375        assert_eq!(
1376            msf.radio_datetime.get_dst(),
1377            Some(radio_datetime_utils::DST_SUMMER)
1378        );
1379        assert_eq!(msf.radio_datetime.get_leap_second(), None);
1380        assert_eq!(msf.radio_datetime.get_jump_minute(), true);
1381        assert_eq!(msf.radio_datetime.get_jump_hour(), false);
1382        assert_eq!(msf.radio_datetime.get_jump_weekday(), false);
1383        assert_eq!(msf.radio_datetime.get_jump_day(), false);
1384        assert_eq!(msf.radio_datetime.get_jump_month(), false);
1385        assert_eq!(msf.radio_datetime.get_jump_year(), false);
1386    }
1387
1388    #[test]
1389    fn continue_decode_time_complete_minute_bad_bits() {
1390        let mut msf = MSFUtils::default();
1391        msf.second = 59;
1392        assert_eq!(msf.get_minute_length(), msf.second + 1); // EOM marker absent
1393        for b in 0..=59 {
1394            msf.bit_buffer_a[b] = Some(BIT_BUFFER_A[b]);
1395            msf.eom = (msf.eom << 1) + BIT_BUFFER_A[b] as u8;
1396            msf.bit_buffer_b[b] = Some(BIT_BUFFER_B[b]);
1397        }
1398        msf.decode_time(true, false);
1399        assert_eq!(msf.first_minute, false);
1400        // update for the next minute:
1401        msf.bit_buffer_a[51] = Some(true);
1402        msf.bit_buffer_b[57] = Some(true);
1403        // introduce some distortions:
1404        msf.bit_buffer_a[31] = None; // None day
1405        msf.bit_buffer_a[48] = Some(false); // minute 58->50, bad parity
1406        msf.decode_time(true, false);
1407        assert_eq!(msf.radio_datetime.get_minute(), Some(59)); // bad parity
1408        assert_eq!(msf.radio_datetime.get_hour(), Some(14)); // bad parity
1409        assert_eq!(msf.radio_datetime.get_weekday(), Some(6));
1410        assert_eq!(msf.radio_datetime.get_day(), Some(23)); // broken bit
1411        assert_eq!(msf.radio_datetime.get_month(), Some(10));
1412        assert_eq!(msf.radio_datetime.get_year(), Some(22));
1413        assert_eq!(msf.parity_1, Some(true));
1414        assert_eq!(msf.parity_2, None); // broken bit
1415        assert_eq!(msf.parity_3, Some(true));
1416        assert_eq!(msf.parity_4, Some(false)); // bad parity
1417        assert_eq!(
1418            msf.radio_datetime.get_dst(),
1419            Some(radio_datetime_utils::DST_SUMMER)
1420        );
1421        assert_eq!(msf.radio_datetime.get_leap_second(), None);
1422        assert_eq!(msf.radio_datetime.get_jump_minute(), false);
1423        assert_eq!(msf.radio_datetime.get_jump_hour(), false);
1424        assert_eq!(msf.radio_datetime.get_jump_weekday(), false);
1425        assert_eq!(msf.radio_datetime.get_jump_day(), false);
1426        assert_eq!(msf.radio_datetime.get_jump_month(), false);
1427        assert_eq!(msf.radio_datetime.get_jump_year(), false);
1428    }
1429
1430    #[test]
1431    fn continue_decode_time_complete_minute_dst_change_to_summer() {
1432        let mut msf = MSFUtils::default();
1433        msf.second = 59;
1434        for b in 0..=59 {
1435            msf.bit_buffer_a[b] = Some(BIT_BUFFER_A[b]);
1436            msf.eom = (msf.eom << 1) + BIT_BUFFER_A[b] as u8;
1437            msf.bit_buffer_b[b] = Some(BIT_BUFFER_B[b]);
1438        }
1439        // DST change must be at top of hour and
1440        // announcements only count before the hour, so set minute to 59:
1441        msf.bit_buffer_a[51] = Some(true);
1442        msf.bit_buffer_b[57] = Some(true);
1443        // announce a DST change:
1444        msf.bit_buffer_b[53] = Some(true);
1445        // flip to winter:
1446        msf.bit_buffer_b[58] = Some(false);
1447        msf.decode_time(true, false);
1448        assert_eq!(msf.radio_datetime.get_minute(), Some(59));
1449        assert_eq!(
1450            msf.radio_datetime.get_dst(),
1451            Some(radio_datetime_utils::DST_ANNOUNCED)
1452        );
1453        // next minute and hour:
1454        msf.bit_buffer_a[45] = Some(false);
1455        msf.bit_buffer_a[47] = Some(false);
1456        msf.bit_buffer_a[48] = Some(false);
1457        msf.bit_buffer_a[51] = Some(false);
1458        msf.bit_buffer_a[44] = Some(true);
1459        msf.bit_buffer_b[57] = Some(false);
1460        // which will have a DST change:
1461        msf.bit_buffer_b[53] = Some(true);
1462        // to summer:
1463        msf.bit_buffer_b[58] = Some(true);
1464        msf.decode_time(true, false);
1465        assert_eq!(msf.radio_datetime.get_minute(), Some(0));
1466        assert_eq!(msf.radio_datetime.get_hour(), Some(15));
1467        assert_eq!(
1468            msf.radio_datetime.get_dst(),
1469            Some(radio_datetime_utils::DST_PROCESSED | radio_datetime_utils::DST_SUMMER)
1470        ); // DST flipped off
1471    }
1472
1473    #[test]
1474    fn continue_decode_time_complete_minute_dst_change_to_winter() {
1475        let mut msf = MSFUtils::default();
1476        msf.second = 59;
1477        for b in 0..=59 {
1478            msf.bit_buffer_a[b] = Some(BIT_BUFFER_A[b]);
1479            msf.eom = (msf.eom << 1) + BIT_BUFFER_A[b] as u8;
1480            msf.bit_buffer_b[b] = Some(BIT_BUFFER_B[b]);
1481        }
1482        // DST change must be at top of hour and
1483        // announcements only count before the hour, so set minute to 59:
1484        msf.bit_buffer_a[51] = Some(true);
1485        msf.bit_buffer_b[57] = Some(true);
1486        // announce a DST change:
1487        msf.bit_buffer_b[53] = Some(true);
1488        msf.decode_time(true, false);
1489        assert_eq!(msf.radio_datetime.get_minute(), Some(59));
1490        assert_eq!(
1491            msf.radio_datetime.get_dst(),
1492            Some(radio_datetime_utils::DST_ANNOUNCED | radio_datetime_utils::DST_SUMMER)
1493        );
1494        // next minute and hour:
1495        msf.bit_buffer_a[45] = Some(false);
1496        msf.bit_buffer_a[47] = Some(false);
1497        msf.bit_buffer_a[48] = Some(false);
1498        msf.bit_buffer_a[51] = Some(false);
1499        msf.bit_buffer_a[44] = Some(true);
1500        msf.bit_buffer_b[57] = Some(false);
1501        // which will have a DST change:
1502        msf.bit_buffer_b[53] = Some(true);
1503        msf.bit_buffer_b[58] = Some(false);
1504        msf.decode_time(true, false);
1505        assert_eq!(msf.radio_datetime.get_minute(), Some(0));
1506        assert_eq!(msf.radio_datetime.get_hour(), Some(15));
1507        assert_eq!(
1508            msf.radio_datetime.get_dst(),
1509            Some(radio_datetime_utils::DST_PROCESSED)
1510        ); // DST flipped off
1511    }
1512
1513    // strict checks
1514    #[test]
1515    fn test_decode_time_incomplete_minute_strict() {
1516        let mut msf = MSFUtils::default();
1517        assert_eq!(msf.first_minute, true);
1518        msf.second = 42;
1519        // note that msf.bit_buffer_[ab] are still empty
1520        assert_ne!(msf.get_minute_length(), msf.second);
1521        assert_eq!(msf.parity_1, None);
1522        msf.decode_time(true, true);
1523        // not enough seconds in this minute, so nothing should happen:
1524        assert_eq!(msf.parity_1, None);
1525    }
1526
1527    #[test]
1528    fn test_decode_time_complete_minute_ok_strict() {
1529        let mut msf = MSFUtils::default();
1530        msf.second = 59;
1531        assert_eq!(msf.get_minute_length(), msf.second + 1); // EOM marker absent
1532        for b in 0..=59 {
1533            msf.bit_buffer_a[b] = Some(BIT_BUFFER_A[b]);
1534            msf.eom = (msf.eom << 1) + BIT_BUFFER_A[b] as u8;
1535            msf.bit_buffer_b[b] = Some(BIT_BUFFER_B[b]);
1536        }
1537        assert_eq!(msf.end_of_minute_marker_present(), true);
1538        msf.decode_time(true, true);
1539        // we should have a valid decoding:
1540        assert_eq!(msf.radio_datetime.get_minute(), Some(58));
1541        assert_eq!(msf.radio_datetime.get_hour(), Some(14));
1542        assert_eq!(msf.radio_datetime.get_weekday(), Some(6));
1543        assert_eq!(msf.radio_datetime.get_day(), Some(23));
1544        assert_eq!(msf.radio_datetime.get_month(), Some(10));
1545        assert_eq!(msf.radio_datetime.get_year(), Some(22));
1546        assert_eq!(msf.parity_1, Some(true));
1547        assert_eq!(msf.parity_2, Some(true));
1548        assert_eq!(msf.parity_3, Some(true));
1549        assert_eq!(msf.parity_4, Some(true));
1550        assert_eq!(
1551            msf.radio_datetime.get_dst(),
1552            Some(radio_datetime_utils::DST_SUMMER)
1553        );
1554        assert_eq!(msf.radio_datetime.get_leap_second(), None); // not available
1555        assert_eq!(msf.radio_datetime.get_dut1(), Some(-2));
1556    }
1557
1558    #[test]
1559    fn test_decode_time_complete_minute_ok_negative_leap_second_strict() {
1560        let mut msf = MSFUtils::default();
1561        msf.second = 58;
1562        for b in 0..=15 {
1563            msf.bit_buffer_a[b] = Some(BIT_BUFFER_A[b]);
1564            msf.eom = (msf.eom << 1) + BIT_BUFFER_A[b] as u8;
1565            msf.bit_buffer_b[b] = Some(BIT_BUFFER_B[b]);
1566        }
1567        // bit 16 removed
1568        for b in 17..=59 {
1569            msf.bit_buffer_a[b - 1] = Some(BIT_BUFFER_A[b]);
1570            msf.eom = (msf.eom << 1) + BIT_BUFFER_A[b] as u8;
1571            msf.bit_buffer_b[b - 1] = Some(BIT_BUFFER_B[b]);
1572        }
1573        assert_eq!(msf.end_of_minute_marker_present(), true);
1574        assert_eq!(msf.get_minute_length(), msf.second + 1);
1575        msf.decode_time(true, true);
1576        // we should have a valid decoding:
1577        assert_eq!(msf.radio_datetime.get_minute(), Some(58));
1578        assert_eq!(msf.radio_datetime.get_hour(), Some(14));
1579        assert_eq!(msf.radio_datetime.get_weekday(), Some(6));
1580        assert_eq!(msf.radio_datetime.get_day(), Some(23));
1581        assert_eq!(msf.radio_datetime.get_month(), Some(10));
1582        assert_eq!(msf.radio_datetime.get_year(), Some(22));
1583        assert_eq!(msf.parity_1, Some(true));
1584        assert_eq!(msf.parity_2, Some(true));
1585        assert_eq!(msf.parity_3, Some(true));
1586        assert_eq!(msf.parity_4, Some(true));
1587        assert_eq!(
1588            msf.radio_datetime.get_dst(),
1589            Some(radio_datetime_utils::DST_SUMMER)
1590        );
1591        assert_eq!(msf.radio_datetime.get_leap_second(), None); // not available
1592        assert_eq!(msf.radio_datetime.get_dut1(), Some(-2));
1593        assert_eq!(msf.first_minute, false);
1594    }
1595
1596    #[test]
1597    fn test_decode_time_complete_minute_ok_positive_leap_second_strict() {
1598        let mut msf = MSFUtils::default();
1599        msf.second = 60;
1600        for b in 0..=16 {
1601            msf.bit_buffer_a[b] = Some(BIT_BUFFER_A[b]);
1602            msf.eom = (msf.eom << 1) + BIT_BUFFER_A[b] as u8;
1603            msf.bit_buffer_b[b] = Some(BIT_BUFFER_B[b]);
1604        }
1605        // insert the positive leap second, left None on purpose (it should not affect decoding)
1606        msf.bit_buffer_a[17] = None;
1607        msf.eom = 0;
1608        msf.bit_buffer_b[17] = None;
1609        for b in 17..=59 {
1610            msf.bit_buffer_a[b + 1] = Some(BIT_BUFFER_A[b]);
1611            msf.eom = (msf.eom << 1) + BIT_BUFFER_A[b] as u8;
1612            msf.bit_buffer_b[b + 1] = Some(BIT_BUFFER_B[b]);
1613        }
1614        assert_eq!(msf.end_of_minute_marker_present(), true);
1615        assert_eq!(msf.get_minute_length(), msf.second + 1);
1616        msf.decode_time(true, true);
1617        // we should have a valid decoding:
1618        assert_eq!(msf.radio_datetime.get_minute(), Some(58));
1619        assert_eq!(msf.radio_datetime.get_hour(), Some(14));
1620        assert_eq!(msf.radio_datetime.get_weekday(), Some(6));
1621        assert_eq!(msf.radio_datetime.get_day(), Some(23));
1622        assert_eq!(msf.radio_datetime.get_month(), Some(10));
1623        assert_eq!(msf.radio_datetime.get_year(), Some(22));
1624        assert_eq!(msf.parity_1, Some(true));
1625        assert_eq!(msf.parity_2, Some(true));
1626        assert_eq!(msf.parity_3, Some(true));
1627        assert_eq!(msf.parity_4, Some(true));
1628        assert_eq!(
1629            msf.radio_datetime.get_dst(),
1630            Some(radio_datetime_utils::DST_SUMMER)
1631        );
1632        assert_eq!(msf.radio_datetime.get_leap_second(), None); // not available
1633        assert_eq!(msf.radio_datetime.get_dut1(), Some(-2));
1634        assert_eq!(msf.first_minute, false);
1635    }
1636
1637    #[test]
1638    fn test_decode_time_complete_minute_bad_bits_strict() {
1639        let mut msf = MSFUtils::default();
1640        msf.second = 59;
1641        assert_eq!(msf.get_minute_length(), msf.second + 1); // EOM marker absent
1642        for b in 0..=59 {
1643            msf.bit_buffer_a[b] = Some(BIT_BUFFER_A[b]);
1644            msf.eom = (msf.eom << 1) + BIT_BUFFER_A[b] as u8;
1645            msf.bit_buffer_b[b] = Some(BIT_BUFFER_B[b]);
1646        }
1647        // introduce some distortions:
1648        msf.bit_buffer_b[1] = Some(true); // now both 1-8 and 9-16 are positive, which is an error
1649        msf.bit_buffer_a[31] = None; // None day
1650        msf.bit_buffer_a[48] = Some(false); // minute 58 -> 50, bad hour/minute parity
1651        msf.decode_time(true, true);
1652        assert_eq!(msf.radio_datetime.get_minute(), None); // bad parity and first decoding
1653        assert_eq!(msf.radio_datetime.get_hour(), None); // bad parity and first decoding
1654        assert_eq!(msf.radio_datetime.get_weekday(), None); // strict check failed
1655        assert_eq!(msf.radio_datetime.get_day(), None); // broken bit
1656        assert_eq!(msf.radio_datetime.get_month(), None); // strict check failed
1657        assert_eq!(msf.radio_datetime.get_year(), None); // strict check failed
1658        assert_eq!(msf.parity_1, Some(true));
1659        assert_eq!(msf.parity_2, None); // broken bit
1660        assert_eq!(msf.parity_3, Some(true));
1661        assert_eq!(msf.parity_4, Some(false)); // bad parity
1662        assert_eq!(
1663            msf.radio_datetime.get_dst(),
1664            Some(radio_datetime_utils::DST_SUMMER)
1665        ); // not affected by strict checking
1666        assert_eq!(msf.radio_datetime.get_leap_second(), None);
1667        assert_eq!(msf.radio_datetime.get_dut1(), None);
1668    }
1669
1670    #[test]
1671    fn continue_decode_time_complete_minute_jumped_values_strict() {
1672        let mut msf = MSFUtils::default();
1673        msf.second = 59;
1674        assert_eq!(msf.get_minute_length(), msf.second + 1); // EOM marker absent
1675        for b in 0..=59 {
1676            msf.bit_buffer_a[b] = Some(BIT_BUFFER_A[b]);
1677            msf.eom = (msf.eom << 1) + BIT_BUFFER_A[b] as u8;
1678            msf.bit_buffer_b[b] = Some(BIT_BUFFER_B[b]);
1679        }
1680        msf.decode_time(true, true);
1681        assert_eq!(msf.radio_datetime.get_minute(), Some(58));
1682        assert_eq!(msf.radio_datetime.get_jump_minute(), false);
1683        assert_eq!(msf.first_minute, false);
1684        // minute 58 is really cool, so do not update bit 51 (and 57)
1685        msf.decode_time(true, true);
1686        assert_eq!(msf.radio_datetime.get_minute(), Some(58));
1687        assert_eq!(msf.radio_datetime.get_hour(), Some(14));
1688        assert_eq!(msf.radio_datetime.get_weekday(), Some(6));
1689        assert_eq!(msf.radio_datetime.get_day(), Some(23));
1690        assert_eq!(msf.radio_datetime.get_month(), Some(10));
1691        assert_eq!(msf.radio_datetime.get_year(), Some(22));
1692        assert_eq!(msf.parity_1, Some(true));
1693        assert_eq!(msf.parity_2, Some(true));
1694        assert_eq!(msf.parity_3, Some(true));
1695        assert_eq!(msf.parity_4, Some(true));
1696        assert_eq!(
1697            msf.radio_datetime.get_dst(),
1698            Some(radio_datetime_utils::DST_SUMMER)
1699        );
1700        assert_eq!(msf.radio_datetime.get_leap_second(), None);
1701        assert_eq!(msf.radio_datetime.get_jump_minute(), true);
1702        assert_eq!(msf.radio_datetime.get_jump_hour(), false);
1703        assert_eq!(msf.radio_datetime.get_jump_weekday(), false);
1704        assert_eq!(msf.radio_datetime.get_jump_day(), false);
1705        assert_eq!(msf.radio_datetime.get_jump_month(), false);
1706        assert_eq!(msf.radio_datetime.get_jump_year(), false);
1707    }
1708
1709    #[test]
1710    fn continue_decode_time_complete_minute_bad_bits_strict() {
1711        let mut msf = MSFUtils::default();
1712        msf.second = 59;
1713        assert_eq!(msf.get_minute_length(), msf.second + 1); // EOM marker absent
1714        for b in 0..=59 {
1715            msf.bit_buffer_a[b] = Some(BIT_BUFFER_A[b]);
1716            msf.eom = (msf.eom << 1) + BIT_BUFFER_A[b] as u8;
1717            msf.bit_buffer_b[b] = Some(BIT_BUFFER_B[b]);
1718        }
1719        msf.decode_time(true, true);
1720        assert_eq!(msf.first_minute, false);
1721        // update for the next minute:
1722        msf.bit_buffer_a[51] = Some(true);
1723        msf.bit_buffer_b[57] = Some(true);
1724        // introduce some distortions:
1725        // None day, broken month/day parity
1726        msf.bit_buffer_a[31] = None;
1727        // hour 58->50, bad hour/minute parity
1728        msf.bit_buffer_a[48] = Some(false);
1729
1730        // make it Sunday, should remain Saturday due to strict checking even though parity is OK
1731        msf.bit_buffer_a[36] = Some(false);
1732        msf.bit_buffer_a[37] = Some(false);
1733        msf.decode_time(true, true);
1734        assert_eq!(msf.radio_datetime.get_minute(), Some(59)); // bad parity
1735        assert_eq!(msf.radio_datetime.get_hour(), Some(14)); // bad parity
1736        assert_eq!(msf.radio_datetime.get_weekday(), Some(6)); // jumped but caught, bad parities
1737        assert_eq!(msf.radio_datetime.get_day(), Some(23)); // broken bit
1738        assert_eq!(msf.radio_datetime.get_month(), Some(10));
1739        assert_eq!(msf.radio_datetime.get_year(), Some(22));
1740        assert_eq!(msf.parity_1, Some(true));
1741        assert_eq!(msf.parity_2, None); // broken bit
1742        assert_eq!(msf.parity_3, Some(true));
1743        assert_eq!(msf.parity_4, Some(false)); // bad parity
1744        assert_eq!(
1745            msf.radio_datetime.get_dst(),
1746            Some(radio_datetime_utils::DST_SUMMER)
1747        );
1748        assert_eq!(msf.radio_datetime.get_leap_second(), None);
1749        assert_eq!(msf.radio_datetime.get_jump_minute(), false);
1750        assert_eq!(msf.radio_datetime.get_jump_hour(), false);
1751        assert_eq!(msf.radio_datetime.get_jump_weekday(), false);
1752        assert_eq!(msf.radio_datetime.get_jump_day(), false);
1753        assert_eq!(msf.radio_datetime.get_jump_month(), false);
1754        assert_eq!(msf.radio_datetime.get_jump_year(), false);
1755    }
1756
1757    #[test]
1758    fn continue_decode_time_complete_minute_dst_change_to_summer_strict() {
1759        let mut msf = MSFUtils::default();
1760        msf.second = 59;
1761        for b in 0..=59 {
1762            msf.bit_buffer_a[b] = Some(BIT_BUFFER_A[b]);
1763            msf.eom = (msf.eom << 1) + BIT_BUFFER_A[b] as u8;
1764            msf.bit_buffer_b[b] = Some(BIT_BUFFER_B[b]);
1765        }
1766        // flip to winter
1767        msf.bit_buffer_b[58] = Some(false);
1768        // DST change must be at top of hour and
1769        // announcements only count before the hour, so set minute to 59:
1770        msf.bit_buffer_a[51] = Some(true);
1771        msf.bit_buffer_b[57] = Some(true);
1772        // announce a DST change:
1773        msf.bit_buffer_b[53] = Some(true);
1774        msf.decode_time(true, true);
1775        assert_eq!(msf.radio_datetime.get_minute(), Some(59));
1776        assert_eq!(
1777            msf.radio_datetime.get_dst(),
1778            Some(radio_datetime_utils::DST_ANNOUNCED)
1779        );
1780        // next minute and hour:
1781        msf.bit_buffer_a[45] = Some(false);
1782        msf.bit_buffer_a[47] = Some(false);
1783        msf.bit_buffer_a[48] = Some(false);
1784        msf.bit_buffer_a[51] = Some(false);
1785        msf.bit_buffer_a[44] = Some(true);
1786        msf.bit_buffer_b[57] = Some(false);
1787        // which will have a DST change:
1788        msf.bit_buffer_b[53] = Some(true);
1789        msf.bit_buffer_b[58] = Some(true);
1790        msf.decode_time(true, true);
1791        assert_eq!(msf.radio_datetime.get_minute(), Some(0));
1792        assert_eq!(msf.radio_datetime.get_hour(), Some(15));
1793        assert_eq!(
1794            msf.radio_datetime.get_dst(),
1795            Some(radio_datetime_utils::DST_PROCESSED | radio_datetime_utils::DST_SUMMER)
1796        ); // DST flipped on
1797    }
1798
1799    #[test]
1800    fn continue_decode_time_complete_minute_dst_change_to_winter_strict() {
1801        let mut msf = MSFUtils::default();
1802        msf.second = 59;
1803        for b in 0..=59 {
1804            msf.bit_buffer_a[b] = Some(BIT_BUFFER_A[b]);
1805            msf.eom = (msf.eom << 1) + BIT_BUFFER_A[b] as u8;
1806            msf.bit_buffer_b[b] = Some(BIT_BUFFER_B[b]);
1807        }
1808        // DST change must be at top of hour and
1809        // announcements only count before the hour, so set minute to 59:
1810        msf.bit_buffer_a[51] = Some(true);
1811        msf.bit_buffer_b[57] = Some(true);
1812        // announce a DST change:
1813        msf.bit_buffer_b[53] = Some(true);
1814        msf.decode_time(true, true);
1815        assert_eq!(msf.radio_datetime.get_minute(), Some(59));
1816        assert_eq!(
1817            msf.radio_datetime.get_dst(),
1818            Some(radio_datetime_utils::DST_ANNOUNCED | radio_datetime_utils::DST_SUMMER)
1819        );
1820        // next minute and hour:
1821        msf.bit_buffer_a[45] = Some(false);
1822        msf.bit_buffer_a[47] = Some(false);
1823        msf.bit_buffer_a[48] = Some(false);
1824        msf.bit_buffer_a[51] = Some(false);
1825        msf.bit_buffer_a[44] = Some(true);
1826        msf.bit_buffer_b[57] = Some(false);
1827        // which will have a DST change:
1828        msf.bit_buffer_b[53] = Some(true);
1829        msf.bit_buffer_b[58] = Some(false);
1830        msf.decode_time(true, true);
1831        assert_eq!(msf.radio_datetime.get_minute(), Some(0));
1832        assert_eq!(msf.radio_datetime.get_hour(), Some(15));
1833        assert_eq!(
1834            msf.radio_datetime.get_dst(),
1835            Some(radio_datetime_utils::DST_PROCESSED)
1836        ); // DST flipped on
1837    }
1838
1839    // relaxed checks, manual add_minute
1840    #[test]
1841    fn test_decode_time_incomplete_minute_manual_add() {
1842        let mut msf = MSFUtils::default();
1843        assert_eq!(msf.first_minute, true);
1844        msf.second = 42;
1845        // note that msf.bit_buffer_[ab] are still empty
1846        assert_ne!(msf.get_minute_length(), msf.second);
1847        assert_eq!(msf.parity_1, None);
1848        msf.decode_time(false, false); // first
1849
1850        // not enough seconds in this minute, so nothing should happen:
1851        assert_eq!(msf.parity_1, None);
1852    }
1853
1854    #[test]
1855    fn test_decode_time_complete_minute_ok_manual_add() {
1856        let mut msf = MSFUtils::default();
1857        msf.second = 59;
1858        assert_eq!(msf.get_minute_length(), msf.second + 1); // EOM marker absent
1859        for b in 0..=59 {
1860            msf.bit_buffer_a[b] = Some(BIT_BUFFER_A[b]);
1861            msf.eom = (msf.eom << 1) + BIT_BUFFER_A[b] as u8;
1862            msf.bit_buffer_b[b] = Some(BIT_BUFFER_B[b]);
1863        }
1864        assert_eq!(msf.end_of_minute_marker_present(), true);
1865        msf.decode_time(false, false); // first
1866
1867        // we should have a valid decoding:
1868        assert_eq!(msf.radio_datetime.get_minute(), Some(58));
1869        assert_eq!(msf.radio_datetime.get_hour(), Some(14));
1870        assert_eq!(msf.radio_datetime.get_weekday(), Some(6));
1871        assert_eq!(msf.radio_datetime.get_day(), Some(23));
1872        assert_eq!(msf.radio_datetime.get_month(), Some(10));
1873        assert_eq!(msf.radio_datetime.get_year(), Some(22));
1874        assert_eq!(msf.parity_1, Some(true));
1875        assert_eq!(msf.parity_2, Some(true));
1876        assert_eq!(msf.parity_3, Some(true));
1877        assert_eq!(msf.parity_4, Some(true));
1878        assert_eq!(
1879            msf.radio_datetime.get_dst(),
1880            Some(radio_datetime_utils::DST_SUMMER)
1881        );
1882        assert_eq!(msf.radio_datetime.get_leap_second(), None); // not available
1883        assert_eq!(msf.radio_datetime.get_dut1(), Some(-2));
1884    }
1885
1886    #[test]
1887    fn test_decode_time_complete_minute_ok_negative_leap_second_manual_add() {
1888        let mut msf = MSFUtils::default();
1889        msf.second = 58;
1890        for b in 0..=15 {
1891            msf.bit_buffer_a[b] = Some(BIT_BUFFER_A[b]);
1892            msf.eom = (msf.eom << 1) + BIT_BUFFER_A[b] as u8;
1893            msf.bit_buffer_b[b] = Some(BIT_BUFFER_B[b]);
1894        }
1895        // bit 16 removed
1896        for b in 17..=59 {
1897            msf.bit_buffer_a[b - 1] = Some(BIT_BUFFER_A[b]);
1898            msf.eom = (msf.eom << 1) + BIT_BUFFER_A[b] as u8;
1899            msf.bit_buffer_b[b - 1] = Some(BIT_BUFFER_B[b]);
1900        }
1901        assert_eq!(msf.end_of_minute_marker_present(), true);
1902        assert_eq!(msf.get_minute_length(), msf.second + 1);
1903        msf.decode_time(false, false); // first
1904
1905        // we should have a valid decoding:
1906        assert_eq!(msf.radio_datetime.get_minute(), Some(58));
1907        assert_eq!(msf.radio_datetime.get_hour(), Some(14));
1908        assert_eq!(msf.radio_datetime.get_weekday(), Some(6));
1909        assert_eq!(msf.radio_datetime.get_day(), Some(23));
1910        assert_eq!(msf.radio_datetime.get_month(), Some(10));
1911        assert_eq!(msf.radio_datetime.get_year(), Some(22));
1912        assert_eq!(msf.parity_1, Some(true));
1913        assert_eq!(msf.parity_2, Some(true));
1914        assert_eq!(msf.parity_3, Some(true));
1915        assert_eq!(msf.parity_4, Some(true));
1916        assert_eq!(
1917            msf.radio_datetime.get_dst(),
1918            Some(radio_datetime_utils::DST_SUMMER)
1919        );
1920        assert_eq!(msf.radio_datetime.get_leap_second(), None); // not available
1921        assert_eq!(msf.radio_datetime.get_dut1(), Some(-2));
1922        assert_eq!(msf.first_minute, false);
1923    }
1924
1925    #[test]
1926    fn test_decode_time_complete_minute_ok_positive_leap_second_manual_add() {
1927        let mut msf = MSFUtils::default();
1928        msf.second = 60;
1929        for b in 0..=16 {
1930            msf.bit_buffer_a[b] = Some(BIT_BUFFER_A[b]);
1931            msf.eom = (msf.eom << 1) + BIT_BUFFER_A[b] as u8;
1932            msf.bit_buffer_b[b] = Some(BIT_BUFFER_B[b]);
1933        }
1934        // insert the positive leap second, left None on purpose (it should not affect decoding)
1935        msf.bit_buffer_a[17] = None;
1936        msf.eom = 0;
1937        msf.bit_buffer_b[17] = None;
1938        for b in 17..=59 {
1939            msf.bit_buffer_a[b + 1] = Some(BIT_BUFFER_A[b]);
1940            msf.eom = (msf.eom << 1) + BIT_BUFFER_A[b] as u8;
1941            msf.bit_buffer_b[b + 1] = Some(BIT_BUFFER_B[b]);
1942        }
1943        assert_eq!(msf.end_of_minute_marker_present(), true);
1944        assert_eq!(msf.get_minute_length(), msf.second + 1);
1945        msf.decode_time(false, false); // first
1946
1947        // we should have a valid decoding:
1948        assert_eq!(msf.radio_datetime.get_minute(), Some(58));
1949        assert_eq!(msf.radio_datetime.get_hour(), Some(14));
1950        assert_eq!(msf.radio_datetime.get_weekday(), Some(6));
1951        assert_eq!(msf.radio_datetime.get_day(), Some(23));
1952        assert_eq!(msf.radio_datetime.get_month(), Some(10));
1953        assert_eq!(msf.radio_datetime.get_year(), Some(22));
1954        assert_eq!(msf.parity_1, Some(true));
1955        assert_eq!(msf.parity_2, Some(true));
1956        assert_eq!(msf.parity_3, Some(true));
1957        assert_eq!(msf.parity_4, Some(true));
1958        assert_eq!(
1959            msf.radio_datetime.get_dst(),
1960            Some(radio_datetime_utils::DST_SUMMER)
1961        );
1962        assert_eq!(msf.radio_datetime.get_leap_second(), None); // not available
1963        assert_eq!(msf.radio_datetime.get_dut1(), Some(-2));
1964        assert_eq!(msf.first_minute, false);
1965    }
1966
1967    #[test]
1968    fn test_decode_time_complete_minute_bad_bits_manual_add() {
1969        let mut msf = MSFUtils::default();
1970        msf.second = 59;
1971        assert_eq!(msf.get_minute_length(), msf.second + 1); // EOM marker absent
1972        for b in 0..=59 {
1973            msf.bit_buffer_a[b] = Some(BIT_BUFFER_A[b]);
1974            msf.eom = (msf.eom << 1) + BIT_BUFFER_A[b] as u8;
1975            msf.bit_buffer_b[b] = Some(BIT_BUFFER_B[b]);
1976        }
1977        // introduce some distortions:
1978        msf.bit_buffer_b[1] = Some(true); // now both 1-8 and 9-16 are positive, which is an error
1979        msf.bit_buffer_a[31] = None; // None day
1980        msf.bit_buffer_a[48] = Some(false); // minute 58->50, bad hour/minute parity
1981        msf.decode_time(false, false); // first
1982        assert_eq!(msf.radio_datetime.get_minute(), None); // bad parity and first decoding
1983        assert_eq!(msf.radio_datetime.get_hour(), None); // bad parity and first decoding
1984        assert_eq!(msf.radio_datetime.get_weekday(), Some(6));
1985        assert_eq!(msf.radio_datetime.get_day(), None); // broken bit
1986        assert_eq!(msf.radio_datetime.get_month(), None); // broken month/day parity, first decode
1987        assert_eq!(msf.radio_datetime.get_year(), Some(22));
1988        assert_eq!(msf.parity_1, Some(true));
1989        assert_eq!(msf.parity_2, None); // broken bit
1990        assert_eq!(msf.parity_3, Some(true));
1991        assert_eq!(msf.parity_4, Some(false)); // bad parity
1992        assert_eq!(
1993            msf.radio_datetime.get_dst(),
1994            Some(radio_datetime_utils::DST_SUMMER)
1995        );
1996        assert_eq!(msf.radio_datetime.get_leap_second(), None);
1997        assert_eq!(msf.radio_datetime.get_dut1(), None);
1998    }
1999
2000    #[test]
2001    fn continue_decode_time_complete_minute_jumped_values_manual_add() {
2002        let mut msf = MSFUtils::default();
2003        msf.second = 59;
2004        assert_eq!(msf.get_minute_length(), msf.second + 1); // EOM marker absent
2005        for b in 0..=59 {
2006            msf.bit_buffer_a[b] = Some(BIT_BUFFER_A[b]);
2007            msf.eom = (msf.eom << 1) + BIT_BUFFER_A[b] as u8;
2008            msf.bit_buffer_b[b] = Some(BIT_BUFFER_B[b]);
2009        }
2010        msf.decode_time(false, false); // first
2011        assert_eq!(msf.radio_datetime.get_minute(), Some(58));
2012        assert_eq!(msf.radio_datetime.get_jump_minute(), false);
2013        assert_eq!(msf.first_minute, false);
2014        // minute 58 is really cool, so do not update bit 51 (and 57)
2015        msf.decode_time(true, false);
2016        assert_eq!(msf.radio_datetime.get_minute(), Some(58));
2017        assert_eq!(msf.radio_datetime.get_hour(), Some(14));
2018        assert_eq!(msf.radio_datetime.get_weekday(), Some(6));
2019        assert_eq!(msf.radio_datetime.get_day(), Some(23));
2020        assert_eq!(msf.radio_datetime.get_month(), Some(10));
2021        assert_eq!(msf.radio_datetime.get_year(), Some(22));
2022        assert_eq!(msf.parity_1, Some(true));
2023        assert_eq!(msf.parity_2, Some(true));
2024        assert_eq!(msf.parity_3, Some(true));
2025        assert_eq!(msf.parity_4, Some(true));
2026        assert_eq!(
2027            msf.radio_datetime.get_dst(),
2028            Some(radio_datetime_utils::DST_SUMMER)
2029        );
2030        assert_eq!(msf.radio_datetime.get_leap_second(), None);
2031        assert_eq!(msf.radio_datetime.get_jump_minute(), true);
2032        assert_eq!(msf.radio_datetime.get_jump_hour(), false);
2033        assert_eq!(msf.radio_datetime.get_jump_weekday(), false);
2034        assert_eq!(msf.radio_datetime.get_jump_day(), false);
2035        assert_eq!(msf.radio_datetime.get_jump_month(), false);
2036        assert_eq!(msf.radio_datetime.get_jump_year(), false);
2037    }
2038
2039    #[test]
2040    fn continue_decode_time_complete_minute_bad_bits_manual_add() {
2041        let mut msf = MSFUtils::default();
2042        msf.second = 59;
2043        assert_eq!(msf.get_minute_length(), msf.second + 1); // EOM marker absent
2044        for b in 0..=59 {
2045            msf.bit_buffer_a[b] = Some(BIT_BUFFER_A[b]);
2046            msf.eom = (msf.eom << 1) + BIT_BUFFER_A[b] as u8;
2047            msf.bit_buffer_b[b] = Some(BIT_BUFFER_B[b]);
2048        }
2049        msf.decode_time(false, false); // first
2050        assert_eq!(msf.first_minute, false);
2051        // update for the next minute:
2052        msf.bit_buffer_a[51] = Some(true);
2053        msf.bit_buffer_b[57] = Some(true);
2054        // introduce some distortions:
2055        msf.bit_buffer_a[31] = None; // None day, broken month/day parity
2056        msf.bit_buffer_a[48] = Some(false); // minute 58->50, bad hour/minute parity
2057        msf.add_minute();
2058        msf.decode_time(false, false);
2059        assert_eq!(msf.radio_datetime.get_minute(), Some(59)); // bad parity
2060        assert_eq!(msf.radio_datetime.get_hour(), Some(14)); // bad parity
2061        assert_eq!(msf.radio_datetime.get_weekday(), Some(6));
2062        assert_eq!(msf.radio_datetime.get_day(), Some(23)); // broken bit
2063        assert_eq!(msf.radio_datetime.get_month(), Some(10)); // broken parity
2064        assert_eq!(msf.radio_datetime.get_year(), Some(22));
2065        assert_eq!(msf.parity_1, Some(true));
2066        assert_eq!(msf.parity_2, None); // broken bit
2067        assert_eq!(msf.parity_3, Some(true));
2068        assert_eq!(msf.parity_4, Some(false)); // bad parity
2069        assert_eq!(
2070            msf.radio_datetime.get_dst(),
2071            Some(radio_datetime_utils::DST_SUMMER)
2072        );
2073        assert_eq!(msf.radio_datetime.get_leap_second(), None);
2074        assert_eq!(msf.radio_datetime.get_jump_minute(), false);
2075        assert_eq!(msf.radio_datetime.get_jump_hour(), false);
2076        assert_eq!(msf.radio_datetime.get_jump_weekday(), false);
2077        assert_eq!(msf.radio_datetime.get_jump_day(), false);
2078        assert_eq!(msf.radio_datetime.get_jump_month(), false);
2079        assert_eq!(msf.radio_datetime.get_jump_year(), false);
2080    }
2081
2082    #[test]
2083    fn continue_decode_time_complete_minute_dst_change_to_summer_manual_add() {
2084        let mut msf = MSFUtils::default();
2085        msf.second = 59;
2086        for b in 0..=59 {
2087            msf.bit_buffer_a[b] = Some(BIT_BUFFER_A[b]);
2088            msf.eom = (msf.eom << 1) + BIT_BUFFER_A[b] as u8;
2089            msf.bit_buffer_b[b] = Some(BIT_BUFFER_B[b]);
2090        }
2091        // DST change must be at top of hour and
2092        // announcements only count before the hour, so set minute to 59:
2093        msf.bit_buffer_a[51] = Some(true);
2094        msf.bit_buffer_b[57] = Some(true);
2095        // announce a DST change:
2096        msf.bit_buffer_b[53] = Some(true);
2097        // flip to winter:
2098        msf.bit_buffer_b[58] = Some(false);
2099        msf.decode_time(false, false); // first
2100        assert_eq!(msf.radio_datetime.get_minute(), Some(59));
2101        assert_eq!(
2102            msf.radio_datetime.get_dst(),
2103            Some(radio_datetime_utils::DST_ANNOUNCED)
2104        );
2105        // next minute and hour:
2106        msf.bit_buffer_a[45] = Some(false);
2107        msf.bit_buffer_a[47] = Some(false);
2108        msf.bit_buffer_a[48] = Some(false);
2109        msf.bit_buffer_a[51] = Some(false);
2110        msf.bit_buffer_a[44] = Some(true);
2111        msf.bit_buffer_b[57] = Some(false);
2112        // which will have a DST change:
2113        msf.bit_buffer_b[53] = Some(true);
2114        msf.bit_buffer_b[58] = Some(true);
2115        msf.add_minute();
2116        msf.decode_time(false, false);
2117        assert_eq!(msf.radio_datetime.get_minute(), Some(0));
2118        assert_eq!(msf.radio_datetime.get_hour(), Some(15));
2119        assert_eq!(
2120            msf.radio_datetime.get_dst(),
2121            Some(radio_datetime_utils::DST_PROCESSED | radio_datetime_utils::DST_SUMMER)
2122        ); // DST flipped off
2123    }
2124
2125    #[test]
2126    fn continue_decode_time_complete_minute_dst_change_to_winter_manual_add() {
2127        let mut msf = MSFUtils::default();
2128        msf.second = 59;
2129        for b in 0..=59 {
2130            msf.bit_buffer_a[b] = Some(BIT_BUFFER_A[b]);
2131            msf.eom = (msf.eom << 1) + BIT_BUFFER_A[b] as u8;
2132            msf.bit_buffer_b[b] = Some(BIT_BUFFER_B[b]);
2133        }
2134        // DST change must be at top of hour and
2135        // announcements only count before the hour, so set minute to 59:
2136        msf.bit_buffer_a[51] = Some(true);
2137        msf.bit_buffer_b[57] = Some(true);
2138        // announce a DST change:
2139        msf.bit_buffer_b[53] = Some(true);
2140        msf.decode_time(false, false); // first
2141        assert_eq!(msf.radio_datetime.get_minute(), Some(59));
2142        assert_eq!(
2143            msf.radio_datetime.get_dst(),
2144            Some(radio_datetime_utils::DST_ANNOUNCED | radio_datetime_utils::DST_SUMMER)
2145        );
2146        // next minute and hour:
2147        msf.bit_buffer_a[45] = Some(false);
2148        msf.bit_buffer_a[47] = Some(false);
2149        msf.bit_buffer_a[48] = Some(false);
2150        msf.bit_buffer_a[51] = Some(false);
2151        msf.bit_buffer_a[44] = Some(true);
2152        msf.bit_buffer_b[57] = Some(false);
2153        // which will have a DST change:
2154        msf.bit_buffer_b[53] = Some(true);
2155        msf.bit_buffer_b[58] = Some(false);
2156        msf.add_minute();
2157        msf.decode_time(false, false);
2158        assert_eq!(msf.radio_datetime.get_minute(), Some(0));
2159        assert_eq!(msf.radio_datetime.get_hour(), Some(15));
2160        assert_eq!(
2161            msf.radio_datetime.get_dst(),
2162            Some(radio_datetime_utils::DST_PROCESSED)
2163        ); // DST flipped off
2164    }
2165
2166    // strict checks
2167    #[test]
2168    fn test_decode_time_incomplete_minute_strict_manual_add() {
2169        let mut msf = MSFUtils::default();
2170        assert_eq!(msf.first_minute, true);
2171        msf.second = 42;
2172        // note that msf.bit_buffer_[ab] are still empty
2173        assert_ne!(msf.get_minute_length(), msf.second);
2174        assert_eq!(msf.parity_1, None);
2175        msf.decode_time(false, true); // first
2176
2177        // not enough seconds in this minute, so nothing should happen:
2178        assert_eq!(msf.parity_1, None);
2179    }
2180
2181    #[test]
2182    fn test_decode_time_complete_minute_ok_strict_manual_add() {
2183        let mut msf = MSFUtils::default();
2184        msf.second = 59;
2185        assert_eq!(msf.get_minute_length(), msf.second + 1); // EOM marker absent
2186        for b in 0..=59 {
2187            msf.bit_buffer_a[b] = Some(BIT_BUFFER_A[b]);
2188            msf.eom = (msf.eom << 1) + BIT_BUFFER_A[b] as u8;
2189            msf.bit_buffer_b[b] = Some(BIT_BUFFER_B[b]);
2190        }
2191        assert_eq!(msf.end_of_minute_marker_present(), true);
2192        msf.decode_time(false, true); // first
2193
2194        // we should have a valid decoding:
2195        assert_eq!(msf.radio_datetime.get_minute(), Some(58));
2196        assert_eq!(msf.radio_datetime.get_hour(), Some(14));
2197        assert_eq!(msf.radio_datetime.get_weekday(), Some(6));
2198        assert_eq!(msf.radio_datetime.get_day(), Some(23));
2199        assert_eq!(msf.radio_datetime.get_month(), Some(10));
2200        assert_eq!(msf.radio_datetime.get_year(), Some(22));
2201        assert_eq!(msf.parity_1, Some(true));
2202        assert_eq!(msf.parity_2, Some(true));
2203        assert_eq!(msf.parity_3, Some(true));
2204        assert_eq!(msf.parity_4, Some(true));
2205        assert_eq!(
2206            msf.radio_datetime.get_dst(),
2207            Some(radio_datetime_utils::DST_SUMMER)
2208        );
2209        assert_eq!(msf.radio_datetime.get_leap_second(), None); // not available
2210        assert_eq!(msf.radio_datetime.get_dut1(), Some(-2));
2211    }
2212
2213    #[test]
2214    fn test_decode_time_complete_minute_ok_negative_leap_second_strict_manual_add() {
2215        let mut msf = MSFUtils::default();
2216        msf.second = 58;
2217        for b in 0..=15 {
2218            msf.bit_buffer_a[b] = Some(BIT_BUFFER_A[b]);
2219            msf.eom = (msf.eom << 1) + BIT_BUFFER_A[b] as u8;
2220            msf.bit_buffer_b[b] = Some(BIT_BUFFER_B[b]);
2221        }
2222        // bit 16 removed
2223        for b in 17..=59 {
2224            msf.bit_buffer_a[b - 1] = Some(BIT_BUFFER_A[b]);
2225            msf.eom = (msf.eom << 1) + BIT_BUFFER_A[b] as u8;
2226            msf.bit_buffer_b[b - 1] = Some(BIT_BUFFER_B[b]);
2227        }
2228        assert_eq!(msf.end_of_minute_marker_present(), true);
2229        assert_eq!(msf.get_minute_length(), msf.second + 1);
2230        msf.decode_time(false, true); // first
2231
2232        // we should have a valid decoding:
2233        assert_eq!(msf.radio_datetime.get_minute(), Some(58));
2234        assert_eq!(msf.radio_datetime.get_hour(), Some(14));
2235        assert_eq!(msf.radio_datetime.get_weekday(), Some(6));
2236        assert_eq!(msf.radio_datetime.get_day(), Some(23));
2237        assert_eq!(msf.radio_datetime.get_month(), Some(10));
2238        assert_eq!(msf.radio_datetime.get_year(), Some(22));
2239        assert_eq!(msf.parity_1, Some(true));
2240        assert_eq!(msf.parity_2, Some(true));
2241        assert_eq!(msf.parity_3, Some(true));
2242        assert_eq!(msf.parity_4, Some(true));
2243        assert_eq!(
2244            msf.radio_datetime.get_dst(),
2245            Some(radio_datetime_utils::DST_SUMMER)
2246        );
2247        assert_eq!(msf.radio_datetime.get_leap_second(), None); // not available
2248        assert_eq!(msf.radio_datetime.get_dut1(), Some(-2));
2249        assert_eq!(msf.first_minute, false);
2250    }
2251
2252    #[test]
2253    fn test_decode_time_complete_minute_ok_positive_leap_second_strict_manual_add() {
2254        let mut msf = MSFUtils::default();
2255        msf.second = 60;
2256        for b in 0..=16 {
2257            msf.bit_buffer_a[b] = Some(BIT_BUFFER_A[b]);
2258            msf.eom = (msf.eom << 1) + BIT_BUFFER_A[b] as u8;
2259            msf.bit_buffer_b[b] = Some(BIT_BUFFER_B[b]);
2260        }
2261        // insert the positive leap second, left None on purpose (it should not affect decoding)
2262        msf.bit_buffer_a[17] = None;
2263        msf.eom = 0;
2264        msf.bit_buffer_b[17] = None;
2265        for b in 17..=59 {
2266            msf.bit_buffer_a[b + 1] = Some(BIT_BUFFER_A[b]);
2267            msf.eom = (msf.eom << 1) + BIT_BUFFER_A[b] as u8;
2268            msf.bit_buffer_b[b + 1] = Some(BIT_BUFFER_B[b]);
2269        }
2270        assert_eq!(msf.end_of_minute_marker_present(), true);
2271        assert_eq!(msf.get_minute_length(), msf.second + 1);
2272        msf.decode_time(false, true); // first
2273
2274        // we should have a valid decoding:
2275        assert_eq!(msf.radio_datetime.get_minute(), Some(58));
2276        assert_eq!(msf.radio_datetime.get_hour(), Some(14));
2277        assert_eq!(msf.radio_datetime.get_weekday(), Some(6));
2278        assert_eq!(msf.radio_datetime.get_day(), Some(23));
2279        assert_eq!(msf.radio_datetime.get_month(), Some(10));
2280        assert_eq!(msf.radio_datetime.get_year(), Some(22));
2281        assert_eq!(msf.parity_1, Some(true));
2282        assert_eq!(msf.parity_2, Some(true));
2283        assert_eq!(msf.parity_3, Some(true));
2284        assert_eq!(msf.parity_4, Some(true));
2285        assert_eq!(
2286            msf.radio_datetime.get_dst(),
2287            Some(radio_datetime_utils::DST_SUMMER)
2288        );
2289        assert_eq!(msf.radio_datetime.get_leap_second(), None); // not available
2290        assert_eq!(msf.radio_datetime.get_dut1(), Some(-2));
2291        assert_eq!(msf.first_minute, false);
2292    }
2293
2294    #[test]
2295    fn test_decode_time_complete_minute_bad_bits_strict_manual_add() {
2296        let mut msf = MSFUtils::default();
2297        msf.second = 59;
2298        assert_eq!(msf.get_minute_length(), msf.second + 1); // EOM marker absent
2299        for b in 0..=59 {
2300            msf.bit_buffer_a[b] = Some(BIT_BUFFER_A[b]);
2301            msf.eom = (msf.eom << 1) + BIT_BUFFER_A[b] as u8;
2302            msf.bit_buffer_b[b] = Some(BIT_BUFFER_B[b]);
2303        }
2304        // introduce some distortions:
2305        msf.bit_buffer_b[1] = Some(true); // now both 1-8 and 9-16 are positive, which is an error
2306        msf.bit_buffer_a[31] = None; // None day, broken month/day parity
2307        msf.bit_buffer_a[48] = Some(false); // minute 58->50, bad hour/minute parity
2308        msf.decode_time(false, true); // first
2309        assert_eq!(msf.radio_datetime.get_minute(), None); // bad parity and first decoding
2310        assert_eq!(msf.radio_datetime.get_hour(), None); // bad parity and first decoding
2311        assert_eq!(msf.radio_datetime.get_weekday(), None); // strict check failed
2312        assert_eq!(msf.radio_datetime.get_day(), None); // broken bit
2313        assert_eq!(msf.radio_datetime.get_month(), None); // strict check failed
2314        assert_eq!(msf.radio_datetime.get_year(), None); // strict check failed
2315        assert_eq!(msf.parity_1, Some(true));
2316        assert_eq!(msf.parity_2, None); // broken bit
2317        assert_eq!(msf.parity_3, Some(true));
2318        assert_eq!(msf.parity_4, Some(false)); // bad parity
2319        assert_eq!(
2320            msf.radio_datetime.get_dst(),
2321            Some(radio_datetime_utils::DST_SUMMER)
2322        ); // not affected by strict checking
2323        assert_eq!(msf.radio_datetime.get_leap_second(), None);
2324        assert_eq!(msf.radio_datetime.get_dut1(), None);
2325    }
2326
2327    #[test]
2328    fn continue_decode_time_complete_minute_jumped_values_strict_manual_add() {
2329        let mut msf = MSFUtils::default();
2330        msf.second = 59;
2331        assert_eq!(msf.get_minute_length(), msf.second + 1); // EOM marker absent
2332        for b in 0..=59 {
2333            msf.bit_buffer_a[b] = Some(BIT_BUFFER_A[b]);
2334            msf.eom = (msf.eom << 1) + BIT_BUFFER_A[b] as u8;
2335            msf.bit_buffer_b[b] = Some(BIT_BUFFER_B[b]);
2336        }
2337        msf.decode_time(false, true); // first
2338        assert_eq!(msf.radio_datetime.get_minute(), Some(58));
2339        assert_eq!(msf.radio_datetime.get_jump_minute(), false);
2340        assert_eq!(msf.first_minute, false);
2341        // minute 58 is really cool, so do not update bit 51 (and 57)
2342        msf.add_minute();
2343        msf.decode_time(false, true);
2344        assert_eq!(msf.radio_datetime.get_minute(), Some(58));
2345        assert_eq!(msf.radio_datetime.get_hour(), Some(14));
2346        assert_eq!(msf.radio_datetime.get_weekday(), Some(6));
2347        assert_eq!(msf.radio_datetime.get_day(), Some(23));
2348        assert_eq!(msf.radio_datetime.get_month(), Some(10));
2349        assert_eq!(msf.radio_datetime.get_year(), Some(22));
2350        assert_eq!(msf.parity_1, Some(true));
2351        assert_eq!(msf.parity_2, Some(true));
2352        assert_eq!(msf.parity_3, Some(true));
2353        assert_eq!(msf.parity_4, Some(true));
2354        assert_eq!(
2355            msf.radio_datetime.get_dst(),
2356            Some(radio_datetime_utils::DST_SUMMER)
2357        );
2358        assert_eq!(msf.radio_datetime.get_leap_second(), None);
2359        assert_eq!(msf.radio_datetime.get_jump_minute(), true);
2360        assert_eq!(msf.radio_datetime.get_jump_hour(), false);
2361        assert_eq!(msf.radio_datetime.get_jump_weekday(), false);
2362        assert_eq!(msf.radio_datetime.get_jump_day(), false);
2363        assert_eq!(msf.radio_datetime.get_jump_month(), false);
2364        assert_eq!(msf.radio_datetime.get_jump_year(), false);
2365    }
2366
2367    #[test]
2368    fn continue_decode_time_complete_minute_bad_bits_strict_manual_add() {
2369        let mut msf = MSFUtils::default();
2370        msf.second = 59;
2371        assert_eq!(msf.get_minute_length(), msf.second + 1); // EOM marker absent
2372        for b in 0..=59 {
2373            msf.bit_buffer_a[b] = Some(BIT_BUFFER_A[b]);
2374            msf.eom = (msf.eom << 1) + BIT_BUFFER_A[b] as u8;
2375            msf.bit_buffer_b[b] = Some(BIT_BUFFER_B[b]);
2376        }
2377        msf.decode_time(false, true); // first
2378        assert_eq!(msf.first_minute, false);
2379        // update for the next minute:
2380        msf.bit_buffer_a[51] = Some(true);
2381        msf.bit_buffer_b[57] = Some(true);
2382        // introduce some distortions:
2383        msf.bit_buffer_a[31] = None; // None day, broken month/day parity
2384        msf.bit_buffer_a[48] = Some(false); // minute 58 -> 50, bad hour/minute parity
2385
2386        // make it Sunday, should remain Saturday due to strict checking even though parity is OK
2387        msf.bit_buffer_a[36] = Some(false);
2388        msf.bit_buffer_a[37] = Some(false);
2389        msf.add_minute();
2390        msf.decode_time(false, true);
2391        assert_eq!(msf.radio_datetime.get_minute(), Some(59)); // bad parity
2392        assert_eq!(msf.radio_datetime.get_hour(), Some(14)); // bad parity
2393        assert_eq!(msf.radio_datetime.get_weekday(), Some(6));
2394        // jumped and OK parity but caught because of bad/broken parities
2395        assert_eq!(msf.radio_datetime.get_day(), Some(23)); // broken parity
2396        assert_eq!(msf.radio_datetime.get_month(), Some(10)); // broken parity
2397        assert_eq!(msf.radio_datetime.get_year(), Some(22));
2398        assert_eq!(msf.parity_1, Some(true));
2399        assert_eq!(msf.parity_2, None); // broken bit
2400        assert_eq!(msf.parity_3, Some(true));
2401        assert_eq!(msf.parity_4, Some(false)); // bad parity
2402        assert_eq!(
2403            msf.radio_datetime.get_dst(),
2404            Some(radio_datetime_utils::DST_SUMMER)
2405        );
2406        assert_eq!(msf.radio_datetime.get_leap_second(), None);
2407        assert_eq!(msf.radio_datetime.get_jump_minute(), false);
2408        assert_eq!(msf.radio_datetime.get_jump_hour(), false);
2409        assert_eq!(msf.radio_datetime.get_jump_weekday(), false);
2410        assert_eq!(msf.radio_datetime.get_jump_day(), false);
2411        assert_eq!(msf.radio_datetime.get_jump_month(), false);
2412        assert_eq!(msf.radio_datetime.get_jump_year(), false);
2413    }
2414
2415    #[test]
2416    fn continue_decode_time_complete_minute_dst_change_to_summer_strict_manual_add() {
2417        let mut msf = MSFUtils::default();
2418        msf.second = 59;
2419        for b in 0..=59 {
2420            msf.bit_buffer_a[b] = Some(BIT_BUFFER_A[b]);
2421            msf.eom = (msf.eom << 1) + BIT_BUFFER_A[b] as u8;
2422            msf.bit_buffer_b[b] = Some(BIT_BUFFER_B[b]);
2423        }
2424        // flip to winter
2425        msf.bit_buffer_b[58] = Some(false);
2426        // DST change must be at top of hour and
2427        // announcements only count before the hour, so set minute to 59:
2428        msf.bit_buffer_a[51] = Some(true);
2429        msf.bit_buffer_b[57] = Some(true);
2430        // announce a DST change:
2431        msf.bit_buffer_b[53] = Some(true);
2432        msf.decode_time(false, true); // first
2433        assert_eq!(msf.radio_datetime.get_minute(), Some(59));
2434        assert_eq!(
2435            msf.radio_datetime.get_dst(),
2436            Some(radio_datetime_utils::DST_ANNOUNCED)
2437        );
2438        // next minute and hour:
2439        msf.bit_buffer_a[45] = Some(false);
2440        msf.bit_buffer_a[47] = Some(false);
2441        msf.bit_buffer_a[48] = Some(false);
2442        msf.bit_buffer_a[51] = Some(false);
2443        msf.bit_buffer_a[44] = Some(true);
2444        msf.bit_buffer_b[57] = Some(false);
2445        // which will have a DST change:
2446        msf.bit_buffer_b[53] = Some(true);
2447        msf.bit_buffer_b[58] = Some(true);
2448        msf.add_minute();
2449        msf.decode_time(false, true);
2450        assert_eq!(msf.radio_datetime.get_minute(), Some(0));
2451        assert_eq!(msf.radio_datetime.get_hour(), Some(15));
2452        assert_eq!(
2453            msf.radio_datetime.get_dst(),
2454            Some(radio_datetime_utils::DST_PROCESSED | radio_datetime_utils::DST_SUMMER)
2455        ); // DST flipped on
2456    }
2457
2458    #[test]
2459    fn continue_decode_time_complete_minute_dst_change_to_winter_strict_manual_add() {
2460        let mut msf = MSFUtils::default();
2461        msf.second = 59;
2462        for b in 0..=59 {
2463            msf.bit_buffer_a[b] = Some(BIT_BUFFER_A[b]);
2464            msf.eom = (msf.eom << 1) + BIT_BUFFER_A[b] as u8;
2465            msf.bit_buffer_b[b] = Some(BIT_BUFFER_B[b]);
2466        }
2467        // DST change must be at top of hour and
2468        // announcements only count before the hour, so set minute to 59:
2469        msf.bit_buffer_a[51] = Some(true);
2470        msf.bit_buffer_b[57] = Some(true);
2471        // announce a DST change:
2472        msf.bit_buffer_b[53] = Some(true);
2473        msf.decode_time(false, true); // first
2474        assert_eq!(msf.radio_datetime.get_minute(), Some(59));
2475        assert_eq!(
2476            msf.radio_datetime.get_dst(),
2477            Some(radio_datetime_utils::DST_ANNOUNCED | radio_datetime_utils::DST_SUMMER)
2478        );
2479        // next minute and hour:
2480        msf.bit_buffer_a[45] = Some(false);
2481        msf.bit_buffer_a[47] = Some(false);
2482        msf.bit_buffer_a[48] = Some(false);
2483        msf.bit_buffer_a[51] = Some(false);
2484        msf.bit_buffer_a[44] = Some(true);
2485        msf.bit_buffer_b[57] = Some(false);
2486        // which will have a DST change:
2487        msf.bit_buffer_b[53] = Some(true);
2488        // to winter:
2489        msf.bit_buffer_b[58] = Some(false);
2490        msf.add_minute();
2491        msf.decode_time(false, true);
2492        assert_eq!(msf.radio_datetime.get_minute(), Some(0));
2493        assert_eq!(msf.radio_datetime.get_hour(), Some(15));
2494        assert_eq!(
2495            msf.radio_datetime.get_dst(),
2496            Some(radio_datetime_utils::DST_PROCESSED)
2497        ); // DST flipped on
2498    }
2499
2500    #[test]
2501    fn test_increase_second_same_minute_ok() {
2502        let mut msf = MSFUtils::default();
2503        msf.second = 37;
2504        assert_eq!(msf.end_of_minute_marker_present(), false);
2505        // all date/time values are None
2506        assert_eq!(msf.increase_second(), true);
2507        assert_eq!(msf.end_of_minute_marker_present(), false);
2508        assert_eq!(msf.first_minute, true);
2509        assert_eq!(msf.second, 38);
2510    }
2511
2512    #[test]
2513    fn test_increase_second_same_minute_overflow() {
2514        let mut msf = MSFUtils::default();
2515        msf.second = 59;
2516        assert_eq!(msf.get_minute_length(), msf.second + 1); // EOM marker absent
2517        assert_eq!(msf.end_of_minute_marker_present(), false);
2518        assert_eq!(msf.increase_second(), false);
2519        assert_eq!(msf.end_of_minute_marker_present(), false);
2520        assert_eq!(msf.first_minute, true);
2521        assert_eq!(msf.second, 0);
2522    }
2523
2524    #[test]
2525    fn test_increase_second_new_minute_ok() {
2526        let mut msf = MSFUtils::default();
2527        msf.new_minute = true;
2528        msf.second = 59;
2529        assert_eq!(msf.get_minute_length(), msf.second + 1); // EOM marker absent
2530        for b in 52..=59 {
2531            msf.bit_buffer_a[b] = Some(BIT_BUFFER_A[b]);
2532            msf.eom = (msf.eom << 1) + BIT_BUFFER_A[b] as u8;
2533        }
2534        assert_eq!(msf.end_of_minute_marker_present(), true);
2535        assert_eq!(msf.increase_second(), true);
2536        assert_eq!(msf.end_of_minute_marker_present(), true); // second increased but no bits were added
2537        assert_eq!(msf.first_minute, true);
2538        assert_eq!(msf.second, 0);
2539    }
2540
2541    #[test]
2542    fn test_increase_second_new_minute_none_values() {
2543        let mut msf = MSFUtils::default();
2544        msf.new_minute = true;
2545        msf.second = 59;
2546        assert_eq!(msf.end_of_minute_marker_present(), false);
2547        // all date/time values left None
2548        assert_eq!(msf.increase_second(), true);
2549        assert_eq!(msf.end_of_minute_marker_present(), false);
2550        assert_eq!(msf.first_minute, true);
2551        assert_eq!(msf.second, 0);
2552    }
2553
2554    #[test]
2555    fn test_increase_second_with_handle_new_edge() {
2556        // found by decode_datetime_pretend_live.rs example
2557        let mut msf = MSFUtils::default();
2558        // END-of-second, upcoming ab
2559        const SAMPLES: [(u32, bool); 20] = [
2560            (532997952, false), // this entry is needed to fully record bit 52a, so that time
2561            // difference with next entry is defined as 900ms and the edge logic is actually ran
2562            (533908377, true), // 51, 00
2563            (533994459, false),
2564            (534908716, true), // 52, 00
2565            (535095720, false),
2566            (535906164, true), // 53, 10
2567            (536192900, false),
2568            (536903709, true), // 54, 11
2569            (537192272, false),
2570            (537907007, true), // 55, 11
2571            (538192799, false),
2572            (538910068, true), // 56, 11
2573            (539095963, false),
2574            (539906169, true), // 57, 10
2575            (540094776, false),
2576            (540905086, true), // 58, 10
2577            (540996129, false),
2578            (541903768, true), //59, 00
2579            (542391315, false),
2580            (542903986, true), // 0, BOM
2581        ];
2582        msf.second = 51;
2583        for s in SAMPLES {
2584            msf.handle_new_edge(s.1, s.0);
2585            assert_eq!(msf.is_new_minute(), msf.second == 59);
2586            assert_eq!(msf.is_past_new_minute(), msf.second == 0);
2587            if s.1 {
2588                assert_eq!(msf.increase_second(), true);
2589            }
2590        }
2591        assert_eq!(msf.second, 1);
2592    }
2593
2594    // bug in initial DST decoding? (see photo 20240407 2037 UTC) (sometimes), but not corrected to
2595    // DST later on and also no jump indicator. Unlike DCF77, in MSF there is only one DST-active
2596    // bit. So perhaps the bit was a bit short (i.e. false non-DST) at first decode.
2597    // DCF77 == "240407 Su 223750 s", status = clear
2598    // MSF == "240407 Su 213750 w 0",status = clear
2599    #[test]
2600    fn test_long_wrong_dst_decode_jumps() {
2601        let mut msf = MSFUtils::default();
2602        msf.second = 59;
2603        for b in 0..=59 {
2604            msf.bit_buffer_a[b] = Some(BIT_BUFFER_A[b]);
2605            msf.eom = (msf.eom << 1) + BIT_BUFFER_A[b] as u8;
2606            msf.bit_buffer_b[b] = Some(BIT_BUFFER_B[b]);
2607        }
2608        msf.bit_buffer_b[58] = Some(false); // simulate too-short DST bit
2609        msf.decode_time(false, true);
2610        assert_eq!(msf.radio_datetime.get_dst(), Some(0));
2611
2612        // minute 59
2613        msf.bit_buffer_a[51] = Some(true);
2614        msf.bit_buffer_b[57] = Some(true); // time parity
2615        assert_eq!(msf.add_minute(), true);
2616        msf.decode_time(false, true);
2617        assert_eq!(msf.radio_datetime.get_minute(), Some(59));
2618        assert_eq!(msf.parity_4, Some(true));
2619        assert_eq!(msf.radio_datetime.get_dst(), Some(0)); // DST state should not change
2620
2621        // 15:00, try to flip to summer time
2622        msf.bit_buffer_a[51] = Some(false);
2623        msf.bit_buffer_a[48] = Some(false);
2624        msf.bit_buffer_a[47] = Some(false);
2625        msf.bit_buffer_a[45] = Some(false);
2626        msf.bit_buffer_a[44] = Some(true);
2627        msf.bit_buffer_b[57] = Some(false); // time parity
2628        msf.bit_buffer_b[58] = Some(true); // summer time
2629        assert_eq!(msf.add_minute(), true);
2630        msf.decode_time(false, true);
2631        assert_eq!(msf.radio_datetime.get_minute(), Some(0));
2632        assert_eq!(msf.radio_datetime.get_hour(), Some(15));
2633        assert_eq!(msf.parity_4, Some(true));
2634        assert_eq!(msf.radio_datetime.get_dst(), Some(DST_JUMP));
2635        // DST summer/winter should not change
2636    }
2637
2638    #[test]
2639    fn test_short_wrong_dst_decode_jumps() {
2640        let mut msf = MSFUtils::default();
2641        msf.second = 59;
2642        for b in 0..=59 {
2643            msf.bit_buffer_a[b] = Some(BIT_BUFFER_A[b]);
2644            msf.eom = (msf.eom << 1) + BIT_BUFFER_A[b] as u8;
2645            msf.bit_buffer_b[b] = Some(BIT_BUFFER_B[b]);
2646        }
2647        msf.bit_buffer_b[58] = Some(false); // simulate too-short DST bit
2648        msf.decode_time(false, true);
2649        assert_eq!(msf.radio_datetime.get_dst(), Some(0));
2650
2651        // minute 59, try to flip to summer time
2652        msf.bit_buffer_a[51] = Some(true);
2653        msf.bit_buffer_b[57] = Some(true); // time parity
2654        msf.bit_buffer_b[58] = Some(true); // summer time
2655        assert_eq!(msf.add_minute(), true);
2656        msf.decode_time(false, true);
2657        assert_eq!(msf.radio_datetime.get_minute(), Some(59));
2658        assert_eq!(msf.parity_4, Some(true));
2659        assert_eq!(msf.radio_datetime.get_dst(), Some(DST_JUMP));
2660        // DST summer/winter should not change
2661    }
2662
2663    // There was a (one-off?) occurrence of DUT1=2 being decoded while DUT1 was 0, which seems
2664    // impossible to write a unit-test for. It was not immediately corrected in the next minute,
2665    // but OK later on.
2666    //  displays: DCF77 = none, MSF = "240407 Su 220217 s 2", status = clear
2667
2668    // post-mortem analysis for why this situation is believed to be impossible:
2669    // time=2201 -> 4 00000000 00000000 00100100 00100 00111 000 100010 0000010 01333130
2670    //                pos=0     neg=0   y=24    m=4   d=7  w=0  h=22    m=2    p=ok,dst=s
2671    // so 54b,55b,56b are true but no indicator for wrong-minute length was present. Reception of
2672    // DCF77 was hard at the time, so perhaps super long bits 1ab,2ab ? This was when
2673    // is_new_minute() was always false in live mode because of bug in handle_new_edge() causing
2674    // new_minute to be false again at falling edge. This was fixed in
2675    // 264096185502f3e4a1625b1680015a390747be2e (2024-05-08)
2676    //
2677    // In d97353d4df73cf9a78a34fed21c4fc31e7365350 (2024-04-16) the display was changed to merge
2678    // failed increase_second() because of second-overflow into '>' (minute-too-long) instead of
2679    // showing "!SF" / "!CF77" (display shows a capital M here so increase_second() did not
2680    // overflow).
2681    //
2682    // Curiously increase_second() was called *twice* in succession without the second
2683    // counter going at two-speed, this was introduced in 7d930b27f41700887ac412a77eaf46967c55aa70
2684    // (2024-01-13). So the second counter might have been unreliable, but still good enough to
2685    // decode date/time. For MSF self.new_minute was always false because it was before 2024-05-08
2686    // so msf.second would hit minute_length (60) i.e. a 1-second overflow would occur but then the
2687    // second counter would be 1 behind so DUT1 would still be 0.
2688}