#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Debounce {
state: bool,
candidate: bool,
count: u16,
samples: u16,
}
impl Debounce {
pub fn new(samples: u16, initial: bool) -> Self {
Self {
state: initial,
candidate: initial,
count: 0,
samples,
}
}
pub fn update(&mut self, raw: bool) -> bool {
if raw == self.state {
self.count = 0;
self.candidate = self.state;
} else {
if raw == self.candidate {
self.count = self.count.saturating_add(1);
} else {
self.candidate = raw;
self.count = 1;
}
if self.count >= self.samples {
self.state = raw;
self.candidate = raw;
self.count = 0;
}
}
self.state
}
pub fn state(&self) -> bool {
self.state
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn change_is_accepted_after_enough_stable_samples() {
let mut debounce = Debounce::new(3, false);
assert!(!debounce.update(true));
assert!(!debounce.update(true));
assert!(debounce.update(true)); assert!(debounce.state());
}
#[test]
fn chatter_resets_the_count() {
let mut debounce = Debounce::new(3, false);
debounce.update(true);
debounce.update(true);
assert!(!debounce.update(false)); assert!(!debounce.update(true)); assert!(!debounce.update(true));
assert!(debounce.update(true)); }
#[test]
fn one_sample_flips_immediately() {
let mut debounce = Debounce::new(1, false);
assert!(debounce.update(true));
}
#[test]
fn a_single_contrary_sample_does_not_flip() {
let mut debounce = Debounce::new(2, true);
assert!(debounce.update(false)); assert!(!debounce.update(false)); }
}