use std::time::Duration;
use super::r_trig::RTrig;
use super::simple_timer::SimpleTimer;
const MIN_DURATION: Duration = Duration::from_millis(50);
const DEFAULT_ON: Duration = Duration::from_millis(750);
const DEFAULT_OFF: Duration = Duration::from_millis(500);
#[derive(Debug, Clone)]
pub struct Beeper {
pub q: bool,
pub count: u16,
pub done: bool,
state: i32,
trigger: RTrig,
timer: SimpleTimer,
}
impl Beeper {
pub fn new() -> Self {
Self {
q: false,
count: 0,
done: false,
state: 0,
trigger: RTrig::new(),
timer: SimpleTimer::new(Duration::ZERO),
}
}
pub fn call(&mut self, execute: bool, preset: u16, t_on: Duration, t_off: Duration) {
self.trigger.call(execute);
let t_on = if t_on < MIN_DURATION { DEFAULT_ON } else { t_on };
let t_off = if t_off < MIN_DURATION { DEFAULT_OFF } else { t_off };
if !execute {
self.state = 0;
}
match self.state {
0 => {
self.q = false;
self.state = 10;
self.timer.set_preset(Duration::from_millis(20));
self.timer.start();
}
10 => {
if self.trigger.q {
self.state = 20;
self.count = 0;
self.done = false;
}
}
20 => {
if self.count == preset {
self.done = true;
self.state = 10;
} else {
self.q = true;
self.done = false;
self.timer.set_preset(t_on);
self.timer.start();
self.state = 30;
}
}
30 => {
if self.timer.is_done() {
self.count += 1;
self.q = false;
self.timer.set_preset(t_off);
self.timer.start();
self.state = 40;
}
}
40 => {
if self.timer.is_done() {
self.state = 20;
}
}
_ => {
self.state = 0;
}
}
}
}
impl Default for Beeper {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
fn run_sequence(preset: u16, t_on: Duration, t_off: Duration) -> Beeper {
let mut b = Beeper::new();
b.call(false, preset, t_on, t_off);
assert_eq!(b.q, false);
b.call(true, preset, t_on, t_off);
assert_eq!(b.count, 0);
assert_eq!(b.done, false);
for i in 0..preset {
b.call(true, preset, t_on, t_off);
assert!(b.q, "q should be true at start of beep {}", i);
std::thread::sleep(t_on + Duration::from_millis(15));
b.call(true, preset, t_on, t_off);
assert!(!b.q, "q should be false after beep {}", i);
assert_eq!(b.count, i + 1);
std::thread::sleep(t_off + Duration::from_millis(15));
b.call(true, preset, t_on, t_off);
}
b.call(true, preset, t_on, t_off);
assert!(b.done);
assert!(!b.q);
b
}
#[test]
fn test_idle_state() {
let mut b = Beeper::new();
b.call(false, 3, Duration::from_millis(100), Duration::from_millis(100));
assert_eq!(b.q, false);
assert_eq!(b.done, false);
assert_eq!(b.count, 0);
}
#[test]
fn test_single_beep() {
run_sequence(1, Duration::from_millis(50), Duration::from_millis(50));
}
#[test]
fn test_multiple_beeps() {
run_sequence(3, Duration::from_millis(50), Duration::from_millis(50));
}
#[test]
fn test_execute_false_resets() {
let mut b = Beeper::new();
let t = Duration::from_millis(50);
b.call(false, 2, t, t);
b.call(true, 2, t, t);
b.call(true, 2, t, t);
assert!(b.q);
b.call(false, 2, t, t);
assert_eq!(b.q, false);
assert_eq!(b.done, false);
}
#[test]
fn test_zero_preset_completes_immediately() {
let mut b = Beeper::new();
let t = Duration::from_millis(100);
b.call(false, 0, t, t);
b.call(true, 0, t, t);
b.call(true, 0, t, t);
assert!(b.done);
assert_eq!(b.q, false);
assert_eq!(b.count, 0);
}
#[test]
fn test_minimum_duration_clamping() {
let mut b = Beeper::new();
let too_short = Duration::from_millis(10);
b.call(false, 1, too_short, too_short);
b.call(true, 1, too_short, too_short);
b.call(true, 1, too_short, too_short);
assert!(b.q);
std::thread::sleep(Duration::from_millis(60));
b.call(true, 1, too_short, too_short);
assert!(b.q, "timer should still be running (clamped to 750ms)");
}
#[test]
fn test_retrigger_after_done() {
let mut b = run_sequence(1, Duration::from_millis(50), Duration::from_millis(50));
assert!(b.done);
let t = Duration::from_millis(50);
b.call(false, 1, t, t);
b.call(true, 1, t, t);
assert_eq!(b.count, 0);
assert_eq!(b.done, false);
b.call(true, 1, t, t);
assert!(b.q);
}
#[test]
fn test_default_trait() {
let b = Beeper::default();
assert_eq!(b.q, false);
assert_eq!(b.count, 0);
assert_eq!(b.done, false);
}
}