sphinx-key: button state machine improvements

gets rid of counters overflowing and crashing in debug mode
release mode wraps them around
reset state machine if unexpected input at any point in the machine's
lifetime
This commit is contained in:
irriden
2023-08-01 17:14:38 +00:00
parent e371c98463
commit af5da5ef60
2 changed files with 75 additions and 16 deletions

View File

@@ -9,6 +9,8 @@ const MILLIS: u16 = 10_000;
const PAUSE: u16 = 50;
// progression is waiting -> *starting -> reset1a -> reset1 -> reset2a -> reset2 -> reset3
// state machine initialized at starting
pub fn button_loop(gpio9: gpio::Gpio9, tx: mpsc::Sender<Status>) {
thread::spawn(move || {
let mut button = PinDriver::input(gpio9).unwrap();
@@ -16,7 +18,7 @@ pub fn button_loop(gpio9: gpio::Gpio9, tx: mpsc::Sender<Status>) {
let mut pressed = false;
let mut up_times = 0;
let mut low_times = 0;
let mut last_status = Status::Starting;
let mut machine = Machine::new(tx, Status::Starting);
loop {
// we are using thread::sleep here to make sure the watchdog isn't triggered
thread::sleep(Duration::from_millis(PAUSE.into()));
@@ -28,14 +30,38 @@ pub fn button_loop(gpio9: gpio::Gpio9, tx: mpsc::Sender<Status>) {
}
if !pressed {
up_times = up_times + 1;
// back to start after waiting for a button release
if machine.state == Status::Waiting {
machine.update_status(Status::Starting);
}
// if button release while in reset2, reset
if machine.state == Status::Reset2 {
machine.update_status(Status::Starting);
}
// advance
if machine.state == Status::Reset1a {
machine.update_status(Status::Reset1);
}
if machine.state == Status::Reset3a {
machine.update_status(Status::Reset3);
}
// if stayed up, advance
if PAUSE * up_times > MILLIS {
// stayed up
if last_status == Status::Reset1 {
log::info!("send Status::Reset2!");
tx.send(Status::Reset2).unwrap();
last_status = Status::Reset2;
if machine.state == Status::Reset1 {
machine.update_status(Status::Reset2a);
}
}
// if stays up for much longer, reset
if PAUSE * up_times > 2 * MILLIS {
machine.update_status(Status::Starting);
up_times = 0;
}
}
} else {
if !pressed {
@@ -45,20 +71,49 @@ pub fn button_loop(gpio9: gpio::Gpio9, tx: mpsc::Sender<Status>) {
}
if pressed {
low_times = low_times + 1;
// if button press while in reset1, wait for a release, and reset
if machine.state == Status::Reset1 {
machine.update_status(Status::Waiting);
}
// advance
if machine.state == Status::Reset2a {
machine.update_status(Status::Reset2);
}
// if stayed held down, advance
if PAUSE * low_times > MILLIS {
// stayed held down
if last_status == Status::Reset2 {
log::info!("send Status::Reset3!");
tx.send(Status::Reset3).unwrap();
last_status = Status::Reset3;
} else if last_status != Status::Reset1 && last_status != Status::Reset3 {
log::info!("send Status::Reset1!");
tx.send(Status::Reset1).unwrap();
last_status = Status::Reset1;
if machine.state == Status::Reset2 {
machine.update_status(Status::Reset3a);
} else if machine.state == Status::Starting {
machine.update_status(Status::Reset1a);
}
}
// if stayed held down for much longer, wait for a release, and reset
if PAUSE * low_times > 2 * MILLIS {
machine.update_status(Status::Waiting);
low_times = 0;
}
}
}
}
});
}
struct Machine {
tx: mpsc::Sender<Status>,
state: Status,
}
impl Machine {
fn new(tx: mpsc::Sender<Status>, state: Status) -> Machine {
Self { tx, state }
}
fn update_status(&mut self, new_state: Status) {
log::info!("send {:?}", new_state);
self.tx.send(new_state).unwrap();
self.state = new_state;
}
}

View File

@@ -1,5 +1,6 @@
#[derive(Debug, Ord, PartialOrd, Eq, PartialEq)]
#[derive(Debug, Ord, PartialOrd, Eq, PartialEq, Clone, Copy)]
pub enum Status {
Waiting,
Starting,
MountingSDCard,
SyncingTime,
@@ -10,7 +11,10 @@ pub enum Status {
Connected,
Signing,
Ota,
Reset1a,
Reset1,
Reset2a,
Reset2,
Reset3a,
Reset3,
}