#[cfg(not(feature = "defmt"))]
#[allow(unused_imports)]
use log::{debug, error, info, trace, warn};
#[cfg(feature = "defmt")]
#[allow(unused_imports)]
use defmt::{debug, error, info, panic, trace, warn};
struct Repetition {
prev: u8,
count: usize,
}
impl Repetition {
fn new() -> Self {
Self {
prev: 0u8,
count: 0,
}
}
fn feed(&mut self, val: u8) -> usize {
if val == self.prev {
self.count += 1;
} else {
self.count = 1;
self.prev = val;
}
self.count
}
}
pub struct RepetitionTest {
r: Repetition,
cutoff: usize,
}
impl RepetitionTest {
pub fn new(cutoff: usize) -> Self {
Self {
r: Repetition::new(),
cutoff,
}
}
pub fn test(&mut self, val: u8) -> Result<(), ()> {
if self.r.feed(val) < self.cutoff {
Ok(())
} else {
warn!("Repetition test failed for value {}", val);
Err(())
}
}
}
pub struct AdaptiveProportionTest {
val: u8,
matches: usize,
i: usize,
window: usize,
cutoff: usize,
}
impl AdaptiveProportionTest {
pub fn new(window: usize, cutoff: usize) -> Self {
Self {
val: 0,
matches: 0,
i: 0,
window,
cutoff,
}
}
pub fn test(&mut self, val: u8) -> Result<(), ()> {
if self.i == 0 {
self.val = val;
self.matches = 0;
self.i = 1;
Ok(())
} else {
if self.val == val {
self.matches += 1
}
let result = self.matches < self.cutoff;
self.i += 1;
if self.i == self.window {
self.i = 0;
self.matches = 0;
}
if result {
Ok(())
} else {
warn!("Adaptive proportion test failed for value {}", self.val);
Err(())
}
}
}
}
pub struct TotalHealth {
adaptive: AdaptiveProportionTest,
repetition: RepetitionTest,
}
impl TotalHealth {
pub fn new() -> Self {
Self {
adaptive: AdaptiveProportionTest::new(512, 410),
repetition: RepetitionTest::new(201),
}
}
pub fn test(&mut self, val: u8) -> Result<(), ()> {
self.adaptive.test(val)?;
self.repetition.test(val)?;
Ok(())
}
}