#![cfg_attr(not(test), no_std)]
use core::cmp::Ordering;
use radio_datetime_utils::{radio_datetime_helpers, RadioDateTimeUtils};
pub mod npl_helpers;
const SPIKE_LIMIT: u32 = 30_000;
const ACTIVE_0_LIMIT: u32 = 150_000;
const ACTIVE_A_LIMIT: u32 = 250_000;
const ACTIVE_AB_LIMIT: u32 = 350_000;
const MINUTE_LIMIT: u32 = 550_000;
const PASSIVE_RUNAWAY: u32 = 1_500_000;
pub const BIT_BUFFER_SIZE: usize = 61 + 1;
pub struct NPLUtils {
first_minute: bool,
new_minute: bool,
new_second: bool,
second: u8,
bit_buffer_a: [Option<bool>; BIT_BUFFER_SIZE],
bit_buffer_b: [Option<bool>; BIT_BUFFER_SIZE],
radio_datetime: RadioDateTimeUtils,
parity_1: Option<bool>,
parity_2: Option<bool>,
parity_3: Option<bool>,
parity_4: Option<bool>,
dut1: Option<i8>, before_first_edge: bool,
t0: u32,
old_t_diff: u32,
spike_limit: u32,
}
impl NPLUtils {
pub fn new() -> Self {
Self {
first_minute: true,
new_minute: false,
new_second: false,
second: 0,
bit_buffer_a: [None; BIT_BUFFER_SIZE],
bit_buffer_b: [None; BIT_BUFFER_SIZE],
radio_datetime: RadioDateTimeUtils::new(0),
parity_1: None,
parity_2: None,
parity_3: None,
parity_4: None,
dut1: None,
before_first_edge: true,
t0: 0,
old_t_diff: 0,
spike_limit: SPIKE_LIMIT,
}
}
pub fn get_first_minute(&self) -> bool {
self.first_minute
}
pub fn get_new_minute(&self) -> bool {
self.new_minute
}
pub fn force_new_minute(&mut self) {
self.new_minute = true;
}
pub fn get_new_second(&self) -> bool {
self.new_second
}
pub fn get_second(&self) -> u8 {
self.second
}
pub fn get_current_bit_a(&self) -> Option<bool> {
self.bit_buffer_a[self.second as usize]
}
pub fn get_current_bit_b(&self) -> Option<bool> {
self.bit_buffer_b[self.second as usize]
}
pub fn set_current_bit_a(&mut self, value: Option<bool>) {
self.bit_buffer_a[self.second as usize] = value;
self.new_minute = false;
}
pub fn set_current_bit_b(&mut self, value: Option<bool>) {
self.bit_buffer_b[self.second as usize] = value;
self.new_minute = false;
}
pub fn get_radio_datetime(&self) -> RadioDateTimeUtils {
self.radio_datetime
}
pub fn get_parity_1(&self) -> Option<bool> {
self.parity_1
}
pub fn get_parity_2(&self) -> Option<bool> {
self.parity_2
}
pub fn get_parity_3(&self) -> Option<bool> {
self.parity_3
}
pub fn get_parity_4(&self) -> Option<bool> {
self.parity_4
}
pub fn get_dut1(&self) -> Option<i8> {
self.dut1
}
pub fn get_spike_limit(&self) -> u32 {
self.spike_limit
}
pub fn set_spike_limit(&mut self, value: u32) {
if value < ACTIVE_0_LIMIT {
self.spike_limit = value;
}
}
pub fn handle_new_edge(&mut self, is_low_edge: bool, t: u32) {
if self.before_first_edge {
self.before_first_edge = false;
self.t0 = t;
return;
}
let t_diff = radio_datetime_helpers::time_diff(self.t0, t);
if t_diff < self.spike_limit {
self.t0 += t_diff;
return; }
self.new_minute = false;
self.t0 = t;
if is_low_edge {
self.new_second = false;
if t_diff < ACTIVE_0_LIMIT {
if self.old_t_diff > 0 && self.old_t_diff < ACTIVE_0_LIMIT {
self.bit_buffer_a[self.second as usize] = Some(false);
self.bit_buffer_b[self.second as usize] = Some(true);
} else if self.old_t_diff > 1_000_000 - MINUTE_LIMIT {
self.bit_buffer_a[self.second as usize] = Some(false);
self.bit_buffer_b[self.second as usize] = Some(false);
}
} else if t_diff < ACTIVE_A_LIMIT && self.old_t_diff > 1_000_000 - ACTIVE_AB_LIMIT {
self.bit_buffer_a[self.second as usize] = Some(true);
self.bit_buffer_b[self.second as usize] = Some(false);
} else if t_diff < ACTIVE_AB_LIMIT && self.old_t_diff > 1_000_000 - ACTIVE_AB_LIMIT {
self.bit_buffer_a[self.second as usize] = Some(true);
self.bit_buffer_b[self.second as usize] = Some(true);
} else if t_diff < MINUTE_LIMIT && self.old_t_diff > 1_000_000 - ACTIVE_AB_LIMIT {
self.new_minute = true;
self.bit_buffer_a[0] = Some(true);
self.bit_buffer_b[0] = Some(true);
} else {
self.bit_buffer_a[self.second as usize] = None;
self.bit_buffer_b[self.second as usize] = None;
}
} else if t_diff < PASSIVE_RUNAWAY {
self.new_second = t_diff > 1_000_000 - MINUTE_LIMIT;
} else {
self.bit_buffer_a[self.second as usize] = None;
self.bit_buffer_b[self.second as usize] = None;
}
self.old_t_diff = t_diff;
}
pub fn get_minute_length(&self) -> u8 {
if (59..=61).contains(&self.second) && self.end_of_minute_marker_present(false) {
self.second
} else if (self.second == 60) && self.end_of_minute_marker_present(true) {
61
} else {
60
}
}
pub fn end_of_minute_marker_present(&self, look_ahead: bool) -> bool {
if self.second < 8 {
return false; }
const MARKER: [bool; 8] = [false, true, true, true, true, true, true, false];
for (idx, bit) in self.bit_buffer_a[(self.second - 8 + look_ahead as u8) as usize
..=(self.second - 1 + look_ahead as u8) as usize]
.iter()
.enumerate()
{
if bit.is_none() || *bit != Some(MARKER[idx]) {
return false;
}
}
true
}
pub fn increase_second(&mut self) {
let minute_length = self.get_minute_length();
if self.new_minute {
if self.first_minute
&& self.second == minute_length
&& self.radio_datetime.get_dst().is_some()
&& self.radio_datetime.get_year().is_some()
&& self.radio_datetime.get_month().is_some()
&& self.radio_datetime.get_day().is_some()
&& self.radio_datetime.get_weekday().is_some()
&& self.radio_datetime.get_hour().is_some()
&& self.radio_datetime.get_minute().is_some()
{
self.first_minute = false;
}
self.second = 0;
} else {
self.second += 1;
if self.second == minute_length + 1 || (self.second as usize) == BIT_BUFFER_SIZE {
self.second = 0;
}
}
}
pub fn decode_time(&mut self) {
let minute_length = self.get_minute_length();
let mut added_minute = false;
if !self.first_minute {
added_minute = self.radio_datetime.add_minute();
}
if self.second == minute_length {
let offset: isize = match 60.cmp(&minute_length) {
Ordering::Less => 1,
Ordering::Equal => 0,
Ordering::Greater => -1,
};
self.parity_1 = radio_datetime_helpers::get_parity(
&self.bit_buffer_a,
(17 + offset) as usize,
(24 + offset) as usize,
self.bit_buffer_b[(54 + offset) as usize],
);
self.radio_datetime.set_year(
radio_datetime_helpers::get_bcd_value(
&self.bit_buffer_a,
(24 + offset) as usize,
(17 + offset) as usize,
),
self.parity_1 == Some(true),
added_minute && !self.first_minute,
);
self.parity_2 = radio_datetime_helpers::get_parity(
&self.bit_buffer_a,
(25 + offset) as usize,
(35 + offset) as usize,
self.bit_buffer_b[(55 + offset) as usize],
);
self.radio_datetime.set_month(
radio_datetime_helpers::get_bcd_value(
&self.bit_buffer_a,
(29 + offset) as usize,
(25 + offset) as usize,
),
self.parity_2 == Some(true),
added_minute && !self.first_minute,
);
self.parity_3 = radio_datetime_helpers::get_parity(
&self.bit_buffer_a,
(36 + offset) as usize,
(38 + offset) as usize,
self.bit_buffer_b[(56 + offset) as usize],
);
self.radio_datetime.set_weekday(
radio_datetime_helpers::get_bcd_value(
&self.bit_buffer_a,
(38 + offset) as usize,
(36 + offset) as usize,
),
self.parity_3 == Some(true),
added_minute && !self.first_minute,
);
self.radio_datetime.set_day(
radio_datetime_helpers::get_bcd_value(
&self.bit_buffer_a,
(35 + offset) as usize,
(30 + offset) as usize,
),
self.parity_1 == Some(true)
&& self.parity_2 == Some(true)
&& self.parity_3 == Some(true),
added_minute && !self.first_minute,
);
self.parity_4 = radio_datetime_helpers::get_parity(
&self.bit_buffer_a,
(39 + offset) as usize,
(51 + offset) as usize,
self.bit_buffer_b[(57 + offset) as usize],
);
self.radio_datetime.set_hour(
radio_datetime_helpers::get_bcd_value(
&self.bit_buffer_a,
(44 + offset) as usize,
(39 + offset) as usize,
),
self.parity_4 == Some(true),
added_minute && !self.first_minute,
);
self.radio_datetime.set_minute(
radio_datetime_helpers::get_bcd_value(
&self.bit_buffer_a,
(51 + offset) as usize,
(45 + offset) as usize,
),
self.parity_4 == Some(true),
added_minute && !self.first_minute,
);
self.radio_datetime.set_dst(
self.bit_buffer_b[(58 + offset) as usize],
self.bit_buffer_b[(53 + offset) as usize],
added_minute && !self.first_minute,
);
self.dut1 = None;
if let Some(dut1p) = npl_helpers::get_unary_value(&self.bit_buffer_b, 1, 8) {
let stop = if offset == -1 { 15 } else { 16 };
if let Some(dut1n) = npl_helpers::get_unary_value(&self.bit_buffer_b, 9, stop) {
self.dut1 = if dut1p * dut1n == 0 {
Some(dut1p - dut1n)
} else {
None
};
}
}
self.radio_datetime.bump_minutes_running();
}
}
}
impl Default for NPLUtils {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
const BIT_BUFFER_A: [bool; 60] = [
true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, true, false, true, false, false, false, false, true, false, false, false, true, true, true, true, false, false, true, false, true, false, false, true, false, true, true, false, false, false, false, true, true, true, true, true, true, false, ];
const BIT_BUFFER_B: [bool; 60] = [
true, false, false, false, false, false, false, false, false, true, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, true, true, false, true, false, ];
#[test]
fn test_new_edge_bit_0_0() {
const EDGE_BUFFER: [(bool, u32); 4] = [
(!false, 422_994_439), (!true, 423_907_610), (!false, 423_997_265), (!true, 424_906_368), ];
let mut npl = NPLUtils::default();
assert_eq!(npl.before_first_edge, true);
npl.handle_new_edge(EDGE_BUFFER[0].0, EDGE_BUFFER[0].1);
assert_eq!(npl.before_first_edge, false);
assert_eq!(npl.t0, EDGE_BUFFER[0].1);
npl.handle_new_edge(EDGE_BUFFER[1].0, EDGE_BUFFER[1].1); assert_eq!(npl.t0, EDGE_BUFFER[1].1); assert_eq!(npl.new_second, true);
assert_eq!(npl.new_minute, false);
assert_eq!(npl.get_current_bit_a(), None); assert_eq!(npl.get_current_bit_b(), None);
npl.handle_new_edge(EDGE_BUFFER[2].0, EDGE_BUFFER[2].1);
assert_eq!(npl.t0, EDGE_BUFFER[2].1); assert_eq!(npl.new_second, false);
assert_eq!(npl.new_minute, false);
assert_eq!(npl.get_current_bit_a(), Some(false));
assert_eq!(npl.get_current_bit_b(), Some(false));
npl.handle_new_edge(EDGE_BUFFER[3].0, EDGE_BUFFER[3].1);
assert_eq!(npl.t0, EDGE_BUFFER[3].1); assert_eq!(npl.new_second, true);
assert_eq!(npl.new_minute, false);
assert_eq!(npl.get_current_bit_a(), Some(false)); assert_eq!(npl.get_current_bit_b(), Some(false)); }
#[test]
fn test_new_edge_bit_0_1() {
const EDGE_BUFFER: [(bool, u32); 6] = [
(!false, 0), (!true, 920_000), (!false, 1_030_000), (!true, 1_128_000), (!false, 1_232_000), (!true, 1_896_000), ];
let mut npl = NPLUtils::default();
assert_eq!(npl.before_first_edge, true);
npl.handle_new_edge(EDGE_BUFFER[0].0, EDGE_BUFFER[0].1);
assert_eq!(npl.before_first_edge, false);
assert_eq!(npl.t0, EDGE_BUFFER[0].1);
npl.handle_new_edge(EDGE_BUFFER[1].0, EDGE_BUFFER[1].1); assert_eq!(npl.t0, EDGE_BUFFER[1].1); assert_eq!(npl.new_second, true);
assert_eq!(npl.new_minute, false);
assert_eq!(npl.get_current_bit_a(), None); assert_eq!(npl.get_current_bit_b(), None);
npl.handle_new_edge(EDGE_BUFFER[2].0, EDGE_BUFFER[2].1);
assert_eq!(npl.t0, EDGE_BUFFER[2].1); assert_eq!(npl.new_second, false);
assert_eq!(npl.new_minute, false);
assert_eq!(npl.get_current_bit_a(), Some(false));
assert_eq!(npl.get_current_bit_b(), Some(false));
npl.handle_new_edge(EDGE_BUFFER[3].0, EDGE_BUFFER[3].1);
assert_eq!(npl.t0, EDGE_BUFFER[3].1); assert_eq!(npl.new_second, false);
assert_eq!(npl.new_minute, false);
assert_eq!(npl.get_current_bit_a(), Some(false));
assert_eq!(npl.get_current_bit_b(), Some(false));
npl.handle_new_edge(EDGE_BUFFER[4].0, EDGE_BUFFER[4].1);
assert_eq!(npl.t0, EDGE_BUFFER[4].1); assert_eq!(npl.new_second, false);
assert_eq!(npl.new_minute, false);
assert_eq!(npl.get_current_bit_a(), Some(false));
assert_eq!(npl.get_current_bit_b(), Some(true));
npl.handle_new_edge(EDGE_BUFFER[5].0, EDGE_BUFFER[5].1);
assert_eq!(npl.t0, EDGE_BUFFER[5].1); assert_eq!(npl.new_second, true);
assert_eq!(npl.new_minute, false);
assert_eq!(npl.get_current_bit_a(), Some(false)); assert_eq!(npl.get_current_bit_b(), Some(true)); }
#[test]
fn test_new_edge_bit_1_0() {
const EDGE_BUFFER: [(bool, u32); 4] = [
(!false, 413_999_083), (!true, 414_909_075), (!false, 415_090_038), (!true, 415_908_781), ];
let mut npl = NPLUtils::default();
assert_eq!(npl.before_first_edge, true);
npl.handle_new_edge(EDGE_BUFFER[0].0, EDGE_BUFFER[0].1);
assert_eq!(npl.before_first_edge, false);
assert_eq!(npl.t0, EDGE_BUFFER[0].1);
npl.handle_new_edge(EDGE_BUFFER[1].0, EDGE_BUFFER[1].1); assert_eq!(npl.t0, EDGE_BUFFER[1].1); assert_eq!(npl.new_second, true);
assert_eq!(npl.new_minute, false);
assert_eq!(npl.get_current_bit_a(), None); assert_eq!(npl.get_current_bit_b(), None);
npl.handle_new_edge(EDGE_BUFFER[2].0, EDGE_BUFFER[2].1);
assert_eq!(npl.t0, EDGE_BUFFER[2].1); assert_eq!(npl.new_second, false);
assert_eq!(npl.new_minute, false);
assert_eq!(npl.get_current_bit_a(), Some(true));
assert_eq!(npl.get_current_bit_b(), Some(false));
npl.handle_new_edge(EDGE_BUFFER[3].0, EDGE_BUFFER[3].1);
assert_eq!(npl.t0, EDGE_BUFFER[3].1); assert_eq!(npl.new_second, true);
assert_eq!(npl.new_minute, false);
assert_eq!(npl.get_current_bit_a(), Some(true)); assert_eq!(npl.get_current_bit_b(), Some(false)); }
#[test]
fn test_new_edge_bit_1_1() {
const EDGE_BUFFER: [(bool, u32); 4] = [
(!false, 415_090_038), (!true, 415_908_781), (!false, 416_194_383), (!true, 416_901_482), ];
let mut npl = NPLUtils::default();
assert_eq!(npl.before_first_edge, true);
npl.handle_new_edge(EDGE_BUFFER[0].0, EDGE_BUFFER[0].1);
assert_eq!(npl.before_first_edge, false);
assert_eq!(npl.t0, EDGE_BUFFER[0].1);
npl.handle_new_edge(EDGE_BUFFER[1].0, EDGE_BUFFER[1].1); assert_eq!(npl.t0, EDGE_BUFFER[1].1); assert_eq!(npl.new_second, true);
assert_eq!(npl.new_minute, false);
assert_eq!(npl.get_current_bit_a(), None); assert_eq!(npl.get_current_bit_b(), None);
npl.handle_new_edge(EDGE_BUFFER[2].0, EDGE_BUFFER[2].1);
assert_eq!(npl.t0, EDGE_BUFFER[2].1); assert_eq!(npl.new_second, false);
assert_eq!(npl.new_minute, false);
assert_eq!(npl.get_current_bit_a(), Some(true));
assert_eq!(npl.get_current_bit_b(), Some(true));
npl.handle_new_edge(EDGE_BUFFER[3].0, EDGE_BUFFER[3].1);
assert_eq!(npl.t0, EDGE_BUFFER[3].1); assert_eq!(npl.new_second, true);
assert_eq!(npl.new_minute, false);
assert_eq!(npl.get_current_bit_a(), Some(true)); assert_eq!(npl.get_current_bit_b(), Some(true)); }
#[test]
fn test_new_edge_minute() {
const EDGE_BUFFER: [(bool, u32); 3] = [
(!false, 420_994_620), (!true, 421_906_680), (!false, 422_389_442), ];
let mut npl = NPLUtils::default();
assert_eq!(npl.before_first_edge, true);
npl.handle_new_edge(EDGE_BUFFER[0].0, EDGE_BUFFER[0].1);
assert_eq!(npl.before_first_edge, false);
assert_eq!(npl.t0, EDGE_BUFFER[0].1);
npl.handle_new_edge(EDGE_BUFFER[1].0, EDGE_BUFFER[1].1); assert_eq!(npl.t0, EDGE_BUFFER[1].1); assert_eq!(npl.new_second, true);
assert_eq!(npl.new_minute, false);
assert_eq!(npl.get_current_bit_a(), None); assert_eq!(npl.get_current_bit_b(), None);
npl.handle_new_edge(EDGE_BUFFER[2].0, EDGE_BUFFER[2].1); assert_eq!(npl.t0, EDGE_BUFFER[2].1); assert_eq!(npl.new_second, false);
assert_eq!(npl.new_minute, true);
assert_eq!(npl.get_current_bit_a(), Some(true));
assert_eq!(npl.get_current_bit_b(), Some(true));
}
#[test]
fn test_new_edge_active_runaway() {
const EDGE_BUFFER: [(bool, u32); 3] = [
(!false, 417_195_653), (!true, 417_908_323), (!false, 419_193_216), ];
let mut npl = NPLUtils::default();
assert_eq!(npl.before_first_edge, true);
npl.handle_new_edge(EDGE_BUFFER[0].0, EDGE_BUFFER[0].1);
assert_eq!(npl.before_first_edge, false);
assert_eq!(npl.t0, EDGE_BUFFER[0].1);
npl.handle_new_edge(EDGE_BUFFER[1].0, EDGE_BUFFER[1].1); assert_eq!(npl.t0, EDGE_BUFFER[1].1); assert_eq!(npl.new_second, true);
assert_eq!(npl.new_minute, false);
assert_eq!(npl.get_current_bit_a(), None); assert_eq!(npl.get_current_bit_b(), None);
npl.handle_new_edge(EDGE_BUFFER[2].0, EDGE_BUFFER[2].1);
assert_eq!(npl.t0, EDGE_BUFFER[2].1); assert_eq!(npl.new_second, false);
assert_eq!(npl.new_minute, false);
assert_eq!(npl.get_current_bit_a(), None);
assert_eq!(npl.get_current_bit_b(), None);
}
#[test]
fn test_new_edge_passive_runaway() {
const EDGE_BUFFER: [(bool, u32); 4] = [
(!false, 897_105_780), (!true, 898_042_361), (!false, 898_110_362), (!true, 900_067_737), ];
let mut npl = NPLUtils::default();
assert_eq!(npl.before_first_edge, true);
npl.handle_new_edge(EDGE_BUFFER[0].0, EDGE_BUFFER[0].1);
assert_eq!(npl.before_first_edge, false);
assert_eq!(npl.t0, EDGE_BUFFER[0].1);
npl.handle_new_edge(EDGE_BUFFER[1].0, EDGE_BUFFER[1].1); assert_eq!(npl.t0, EDGE_BUFFER[1].1); assert_eq!(npl.new_second, true);
assert_eq!(npl.new_minute, false);
assert_eq!(npl.get_current_bit_a(), None); assert_eq!(npl.get_current_bit_b(), None);
npl.handle_new_edge(EDGE_BUFFER[2].0, EDGE_BUFFER[2].1);
assert_eq!(npl.t0, EDGE_BUFFER[2].1); assert_eq!(npl.new_second, false);
assert_eq!(npl.new_minute, false);
assert_eq!(npl.get_current_bit_a(), Some(false));
assert_eq!(npl.get_current_bit_b(), Some(false));
npl.handle_new_edge(EDGE_BUFFER[3].0, EDGE_BUFFER[3].1);
assert_eq!(npl.t0, EDGE_BUFFER[3].1); assert_eq!(npl.new_second, false);
assert_eq!(npl.new_minute, false);
assert_eq!(npl.get_current_bit_a(), None);
assert_eq!(npl.get_current_bit_b(), None);
}
#[test]
fn test_new_edge_spikes() {
const EDGE_BUFFER: [(bool, u32); 8] = [
(!false, 900_122_127), (!true, 901_052_140), (!false, 901_226_910), (!true, 902_069_956), (!false, 902_085_860), (!true, 902_105_980), (!false, 902_115_859), (!true, 903_057_346), ];
let mut npl = NPLUtils::default();
assert_eq!(npl.before_first_edge, true);
npl.handle_new_edge(EDGE_BUFFER[0].0, EDGE_BUFFER[0].1);
assert_eq!(npl.before_first_edge, false);
assert_eq!(npl.t0, EDGE_BUFFER[0].1);
npl.handle_new_edge(EDGE_BUFFER[1].0, EDGE_BUFFER[1].1); assert_eq!(npl.t0, EDGE_BUFFER[1].1); assert_eq!(npl.new_second, true);
assert_eq!(npl.new_minute, false);
assert_eq!(npl.get_current_bit_a(), None); assert_eq!(npl.get_current_bit_b(), None);
npl.handle_new_edge(EDGE_BUFFER[2].0, EDGE_BUFFER[2].1);
assert_eq!(npl.t0, EDGE_BUFFER[2].1); assert_eq!(npl.new_second, false);
assert_eq!(npl.new_minute, false);
assert_eq!(npl.get_current_bit_a(), Some(true));
assert_eq!(npl.get_current_bit_b(), Some(false));
npl.handle_new_edge(EDGE_BUFFER[3].0, EDGE_BUFFER[3].1); assert_eq!(npl.t0, EDGE_BUFFER[3].1); assert_eq!(npl.new_second, true);
assert_eq!(npl.new_minute, false);
assert_eq!(npl.get_current_bit_a(), Some(true)); assert_eq!(npl.get_current_bit_b(), Some(false));
let mut spike = npl.t0;
for i in 4..=6 {
spike += radio_datetime_helpers::time_diff(EDGE_BUFFER[i - 1].1, EDGE_BUFFER[i].1);
npl.handle_new_edge(EDGE_BUFFER[i].0, EDGE_BUFFER[i].1);
assert_eq!(npl.t0, spike);
assert_eq!(npl.new_second, true);
assert_eq!(npl.new_minute, false);
assert_eq!(npl.get_current_bit_a(), Some(true));
assert_eq!(npl.get_current_bit_b(), Some(false));
}
npl.handle_new_edge(EDGE_BUFFER[7].0, EDGE_BUFFER[7].1);
assert_eq!(npl.t0, EDGE_BUFFER[7].1); assert_eq!(npl.new_second, true); assert_eq!(npl.new_minute, false);
assert_eq!(npl.get_current_bit_a(), Some(true)); assert_eq!(npl.get_current_bit_b(), Some(false)); }
#[test]
fn test_eom_marker_too_short() {
let mut npl = NPLUtils::default();
npl.second = 5; for b in 0..=5 {
npl.bit_buffer_a[b] = Some(BIT_BUFFER_A[b]);
}
assert_eq!(npl.end_of_minute_marker_present(false), false);
}
#[test]
fn test_eom_marker_absent() {
let mut npl = NPLUtils::default();
npl.second = 60;
for b in 52..=59 {
npl.bit_buffer_a[b] = Some(BIT_BUFFER_A[b]);
}
npl.bit_buffer_a[57] = None; assert_eq!(npl.end_of_minute_marker_present(false), false);
}
#[test]
fn test_eom_marker_absent_ahead() {
let mut npl = NPLUtils::default();
npl.second = 60;
for b in 52..=59 {
npl.bit_buffer_a[b + 1] = Some(BIT_BUFFER_A[b]);
}
npl.bit_buffer_a[57] = None; assert_eq!(npl.end_of_minute_marker_present(true), false);
}
#[test]
fn test_eom_marker_present() {
let mut npl = NPLUtils::default();
npl.second = 60;
for b in 52..=59 {
npl.bit_buffer_a[b] = Some(BIT_BUFFER_A[b]);
}
assert_eq!(npl.end_of_minute_marker_present(false), true);
}
#[test]
fn test_eom_marker_present_ahead() {
let mut npl = NPLUtils::default();
npl.second = 60;
for b in 52..=59 {
npl.bit_buffer_a[b + 1] = Some(BIT_BUFFER_A[b]);
}
assert_eq!(npl.end_of_minute_marker_present(true), true);
}
#[test]
fn test_decode_time_incomplete_minute() {
let mut npl = NPLUtils::default();
assert_eq!(npl.first_minute, true);
npl.second = 42;
assert_ne!(npl.get_minute_length(), npl.second);
assert_eq!(npl.parity_1, None);
npl.decode_time();
assert_eq!(npl.parity_1, None);
}
#[test]
fn test_decode_time_complete_minute_ok() {
let mut npl = NPLUtils::default();
npl.second = 60;
assert_eq!(npl.get_minute_length(), npl.second);
for b in 0..=59 {
npl.bit_buffer_a[b] = Some(BIT_BUFFER_A[b]);
npl.bit_buffer_b[b] = Some(BIT_BUFFER_B[b]);
}
npl.decode_time();
assert_eq!(npl.radio_datetime.get_minute(), Some(58));
assert_eq!(npl.radio_datetime.get_hour(), Some(14));
assert_eq!(npl.radio_datetime.get_weekday(), Some(6));
assert_eq!(npl.radio_datetime.get_day(), Some(23));
assert_eq!(npl.radio_datetime.get_month(), Some(10));
assert_eq!(npl.radio_datetime.get_year(), Some(22));
assert_eq!(npl.parity_1, Some(true));
assert_eq!(npl.parity_2, Some(true));
assert_eq!(npl.parity_3, Some(true));
assert_eq!(npl.parity_4, Some(true));
assert_eq!(
npl.radio_datetime.get_dst(),
Some(radio_datetime_utils::DST_SUMMER)
);
assert_eq!(npl.radio_datetime.get_leap_second(), None); assert_eq!(npl.dut1, Some(-2));
}
#[test]
fn test_decode_time_complete_minute_ok_negative_leap_second() {
let mut npl = NPLUtils::default();
npl.second = 59;
for b in 0..=15 {
npl.bit_buffer_a[b] = Some(BIT_BUFFER_A[b]);
npl.bit_buffer_b[b] = Some(BIT_BUFFER_B[b]);
}
for b in 17..=59 {
npl.bit_buffer_a[b - 1] = Some(BIT_BUFFER_A[b]);
npl.bit_buffer_b[b - 1] = Some(BIT_BUFFER_B[b]);
}
assert_eq!(npl.get_minute_length(), npl.second);
npl.decode_time();
assert_eq!(npl.radio_datetime.get_minute(), Some(58));
assert_eq!(npl.radio_datetime.get_hour(), Some(14));
assert_eq!(npl.radio_datetime.get_weekday(), Some(6));
assert_eq!(npl.radio_datetime.get_day(), Some(23));
assert_eq!(npl.radio_datetime.get_month(), Some(10));
assert_eq!(npl.radio_datetime.get_year(), Some(22));
assert_eq!(npl.parity_1, Some(true));
assert_eq!(npl.parity_2, Some(true));
assert_eq!(npl.parity_3, Some(true));
assert_eq!(npl.parity_4, Some(true));
assert_eq!(
npl.radio_datetime.get_dst(),
Some(radio_datetime_utils::DST_SUMMER)
);
assert_eq!(npl.radio_datetime.get_leap_second(), None); assert_eq!(npl.dut1, Some(-2));
}
#[test]
fn test_decode_time_complete_minute_ok_positive_leap_second() {
let mut npl = NPLUtils::default();
npl.second = 61;
for b in 0..=16 {
npl.bit_buffer_a[b] = Some(BIT_BUFFER_A[b]);
npl.bit_buffer_b[b] = Some(BIT_BUFFER_B[b]);
}
npl.bit_buffer_a[17] = None;
npl.bit_buffer_b[17] = None;
for b in 17..=59 {
npl.bit_buffer_a[b + 1] = Some(BIT_BUFFER_A[b]);
npl.bit_buffer_b[b + 1] = Some(BIT_BUFFER_B[b]);
}
assert_eq!(npl.get_minute_length(), npl.second);
npl.decode_time();
assert_eq!(npl.radio_datetime.get_minute(), Some(58));
assert_eq!(npl.radio_datetime.get_hour(), Some(14));
assert_eq!(npl.radio_datetime.get_weekday(), Some(6));
assert_eq!(npl.radio_datetime.get_day(), Some(23));
assert_eq!(npl.radio_datetime.get_month(), Some(10));
assert_eq!(npl.radio_datetime.get_year(), Some(22));
assert_eq!(npl.parity_1, Some(true));
assert_eq!(npl.parity_2, Some(true));
assert_eq!(npl.parity_3, Some(true));
assert_eq!(npl.parity_4, Some(true));
assert_eq!(
npl.radio_datetime.get_dst(),
Some(radio_datetime_utils::DST_SUMMER)
);
assert_eq!(npl.radio_datetime.get_leap_second(), None); assert_eq!(npl.dut1, Some(-2));
}
#[test]
fn test_decode_time_complete_minute_bad_bits() {
let mut npl = NPLUtils::default();
npl.second = 60;
assert_eq!(npl.get_minute_length(), npl.second);
for b in 0..=59 {
npl.bit_buffer_a[b] = Some(BIT_BUFFER_A[b]);
npl.bit_buffer_b[b] = Some(BIT_BUFFER_B[b]);
}
npl.bit_buffer_b[1] = Some(true); npl.bit_buffer_a[31] = None; npl.bit_buffer_a[48] = Some(!npl.bit_buffer_a[48].unwrap());
npl.decode_time();
assert_eq!(npl.radio_datetime.get_minute(), None); assert_eq!(npl.radio_datetime.get_hour(), None); assert_eq!(npl.radio_datetime.get_weekday(), Some(6));
assert_eq!(npl.radio_datetime.get_day(), None); assert_eq!(npl.radio_datetime.get_month(), None); assert_eq!(npl.radio_datetime.get_year(), Some(22));
assert_eq!(npl.parity_1, Some(true));
assert_eq!(npl.parity_2, None); assert_eq!(npl.parity_3, Some(true));
assert_eq!(npl.parity_4, Some(false)); assert_eq!(
npl.radio_datetime.get_dst(),
Some(radio_datetime_utils::DST_SUMMER)
);
assert_eq!(npl.radio_datetime.get_leap_second(), None);
assert_eq!(npl.dut1, None);
}
#[test]
fn continue_decode_time_complete_minute_jumped_values() {
let mut npl = NPLUtils::default();
npl.second = 60;
assert_eq!(npl.get_minute_length(), npl.second);
for b in 0..=59 {
npl.bit_buffer_a[b] = Some(BIT_BUFFER_A[b]);
npl.bit_buffer_b[b] = Some(BIT_BUFFER_B[b]);
}
npl.decode_time();
assert_eq!(npl.radio_datetime.get_minute(), Some(58));
assert_eq!(npl.radio_datetime.get_jump_minute(), false);
npl.first_minute = false;
npl.decode_time();
assert_eq!(npl.radio_datetime.get_minute(), Some(58));
assert_eq!(npl.radio_datetime.get_hour(), Some(14));
assert_eq!(npl.radio_datetime.get_weekday(), Some(6));
assert_eq!(npl.radio_datetime.get_day(), Some(23));
assert_eq!(npl.radio_datetime.get_month(), Some(10));
assert_eq!(npl.radio_datetime.get_year(), Some(22));
assert_eq!(npl.parity_1, Some(true));
assert_eq!(npl.parity_2, Some(true));
assert_eq!(npl.parity_3, Some(true));
assert_eq!(npl.parity_4, Some(true));
assert_eq!(
npl.radio_datetime.get_dst(),
Some(radio_datetime_utils::DST_SUMMER)
);
assert_eq!(npl.radio_datetime.get_leap_second(), None);
assert_eq!(npl.radio_datetime.get_jump_minute(), true);
assert_eq!(npl.radio_datetime.get_jump_hour(), false);
assert_eq!(npl.radio_datetime.get_jump_weekday(), false);
assert_eq!(npl.radio_datetime.get_jump_day(), false);
assert_eq!(npl.radio_datetime.get_jump_month(), false);
assert_eq!(npl.radio_datetime.get_jump_year(), false);
}
#[test]
fn continue_decode_time_complete_minute_bad_bits() {
let mut npl = NPLUtils::default();
npl.second = 60;
assert_eq!(npl.get_minute_length(), npl.second);
for b in 0..=59 {
npl.bit_buffer_a[b] = Some(BIT_BUFFER_A[b]);
npl.bit_buffer_b[b] = Some(BIT_BUFFER_B[b]);
}
npl.decode_time();
npl.first_minute = false;
npl.bit_buffer_a[51] = Some(true);
npl.bit_buffer_b[57] = Some(true);
npl.bit_buffer_a[31] = None; npl.bit_buffer_a[48] = Some(!npl.bit_buffer_a[48].unwrap());
npl.decode_time();
assert_eq!(npl.radio_datetime.get_minute(), Some(59)); assert_eq!(npl.radio_datetime.get_hour(), Some(14));
assert_eq!(npl.radio_datetime.get_weekday(), Some(6)); assert_eq!(npl.radio_datetime.get_day(), Some(23)); assert_eq!(npl.radio_datetime.get_month(), Some(10)); assert_eq!(npl.radio_datetime.get_year(), Some(22)); assert_eq!(npl.parity_1, Some(true));
assert_eq!(npl.parity_2, None); assert_eq!(npl.parity_3, Some(true));
assert_eq!(npl.parity_4, Some(false)); assert_eq!(
npl.radio_datetime.get_dst(),
Some(radio_datetime_utils::DST_SUMMER)
);
assert_eq!(npl.radio_datetime.get_leap_second(), None);
assert_eq!(npl.radio_datetime.get_jump_minute(), false);
assert_eq!(npl.radio_datetime.get_jump_hour(), false);
assert_eq!(npl.radio_datetime.get_jump_weekday(), false);
assert_eq!(npl.radio_datetime.get_jump_day(), false);
assert_eq!(npl.radio_datetime.get_jump_month(), false);
assert_eq!(npl.radio_datetime.get_jump_year(), false);
}
#[test]
fn continue_decode_time_complete_minute_dst_change() {
let mut npl = NPLUtils::default();
npl.second = 60;
for b in 0..=59 {
npl.bit_buffer_a[b] = Some(BIT_BUFFER_A[b]);
npl.bit_buffer_b[b] = Some(BIT_BUFFER_B[b]);
}
npl.bit_buffer_a[51] = Some(true);
npl.bit_buffer_b[57] = Some(true);
npl.bit_buffer_b[53] = Some(true);
npl.decode_time();
assert_eq!(npl.radio_datetime.get_minute(), Some(59));
assert_eq!(
npl.radio_datetime.get_dst(),
Some(radio_datetime_utils::DST_ANNOUNCED | radio_datetime_utils::DST_SUMMER)
);
npl.bit_buffer_a[45] = Some(false);
npl.bit_buffer_a[47] = Some(false);
npl.bit_buffer_a[48] = Some(false);
npl.bit_buffer_a[51] = Some(false);
npl.bit_buffer_a[44] = Some(true);
npl.bit_buffer_b[57] = Some(false);
npl.bit_buffer_b[53] = Some(true);
npl.bit_buffer_b[58] = Some(false);
npl.decode_time();
assert_eq!(npl.radio_datetime.get_minute(), Some(0));
assert_eq!(npl.radio_datetime.get_hour(), Some(15));
assert_eq!(
npl.radio_datetime.get_dst(),
Some(radio_datetime_utils::DST_PROCESSED)
); }
#[test]
fn test_increase_second_same_minute_ok() {
let mut npl = NPLUtils::default();
npl.second = 37;
npl.increase_second();
assert_eq!(npl.first_minute, true);
assert_eq!(npl.second, 38);
}
#[test]
fn test_increase_second_same_minute_overflow() {
let mut npl = NPLUtils::default();
npl.second = 60;
npl.increase_second();
assert_eq!(npl.first_minute, true);
assert_eq!(npl.second, 0);
}
#[test]
fn test_increase_second_new_minute_ok() {
let mut npl = NPLUtils::default();
npl.new_minute = true;
npl.second = 60;
assert_eq!(npl.get_minute_length(), npl.second);
for b in 52..=59 {
npl.bit_buffer_a[b] = Some(BIT_BUFFER_A[b]);
}
npl.radio_datetime.set_year(Some(22), true, false);
npl.radio_datetime.set_month(Some(10), true, false);
npl.radio_datetime.set_weekday(Some(6), true, false);
npl.radio_datetime.set_day(Some(22), true, false);
npl.radio_datetime.set_hour(Some(12), true, false);
npl.radio_datetime.set_minute(Some(59), true, false);
npl.radio_datetime.set_dst(Some(true), Some(false), false);
npl.increase_second();
assert_eq!(npl.first_minute, false);
assert_eq!(npl.second, 0);
}
#[test]
fn test_increase_second_new_minute_none_values() {
let mut npl = NPLUtils::default();
npl.new_minute = true;
npl.second = 60;
npl.increase_second();
assert_eq!(npl.first_minute, true);
assert_eq!(npl.second, 0);
}
}