162 lines
5.2 KiB
Rust
162 lines
5.2 KiB
Rust
#[derive(Clone)]
|
|
/// A stateful button debouncer.
|
|
pub struct Buttons {
|
|
state: [Option<u32>; 4],
|
|
}
|
|
|
|
impl Buttons {
|
|
pub fn new() -> Self {
|
|
Self {
|
|
state: [None; 4],
|
|
}
|
|
}
|
|
|
|
/// Update internal state from raw input state, with given millisecond timestamp. The input
|
|
/// state is proccessed/debounced into the internal state.
|
|
pub fn update(&mut self, ts: u32, state: [bool; 4]) {
|
|
for (&s, v) in state.iter().zip(self.state.iter_mut()) {
|
|
if let Some(pressed) = v {
|
|
// Ignore recent changes (ie., debounce).
|
|
if ts - *pressed < 10 {
|
|
continue
|
|
}
|
|
|
|
if !s {
|
|
*v = None;
|
|
}
|
|
} else {
|
|
if s {
|
|
*v = Some(ts);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Return a watcher, which is used to detect edge-triggered button events. Multiple
|
|
/// independent watchers can exist, eg. for different downstream code.
|
|
pub fn watch(&self) -> ButtonWatcher {
|
|
let mut pending = [false; 4];
|
|
for (i, v) in self.state.iter().enumerate() {
|
|
if v.is_some() {
|
|
pending[i] = true;
|
|
}
|
|
}
|
|
ButtonWatcher {
|
|
state: self.state.clone(),
|
|
pending,
|
|
}
|
|
}
|
|
}
|
|
|
|
/// A edge-triggered button event watcher. Updates events from a Buttons struct and yields button
|
|
/// press events once per button press.
|
|
pub struct ButtonWatcher {
|
|
state: [Option<u32>; 4],
|
|
pending: [bool; 4],
|
|
}
|
|
|
|
impl ButtonWatcher {
|
|
/// Update internal state from Buttons. If any events are missed, a best effort is made to
|
|
/// reconstruct missing presses - but for all presses to be available, they should be processed
|
|
/// as early as possible via the events function.
|
|
pub fn update(&mut self, buttons: &Buttons) {
|
|
for (i, (v, o)) in self.state.iter_mut().zip(buttons.state.iter()).enumerate() {
|
|
|
|
match (&v, o) {
|
|
(Some(a), Some(b)) => {
|
|
// Button continues to be pressed, or new press.
|
|
if a == b {
|
|
// Do nothing.
|
|
} else {
|
|
// New press, set pending and update.
|
|
self.pending[i] = true;
|
|
*v = Some(*b);
|
|
}
|
|
},
|
|
(Some(_), None) => {
|
|
// Button released.
|
|
*v = None;
|
|
},
|
|
(None, Some(b)) => {
|
|
// Button newly pressed.
|
|
self.pending[i] = true;
|
|
*v = Some(*b);
|
|
},
|
|
(None, None) => {
|
|
// Do nothing.
|
|
},
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Returns an iterator over pending button presses. Button presses are registered as processed
|
|
/// one-by-one as the returned iterator is consumed.
|
|
pub fn events<'a>(&'a mut self) -> ButtonWatcherPending<'a> {
|
|
ButtonWatcherPending {
|
|
w: self,
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Button press iterator, yielding a button number for each pending button press (edge-triggered).
|
|
pub struct ButtonWatcherPending<'a> {
|
|
w: &'a mut ButtonWatcher,
|
|
}
|
|
|
|
impl<'a> core::iter::Iterator for ButtonWatcherPending<'a> {
|
|
type Item = usize;
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
for (i, p) in self.w.pending.iter_mut().enumerate() {
|
|
if *p {
|
|
*p = false;
|
|
return Some(i);
|
|
}
|
|
}
|
|
None
|
|
}
|
|
}
|
|
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use crate::input::Buttons;
|
|
#[test]
|
|
fn buttons_debounce() {
|
|
let mut b = Buttons::new();
|
|
b.update(100, [false, false, false, false]);
|
|
assert_eq!(b.state, [None, None, None, None]);
|
|
b.update(110, [true, false, true, false]);
|
|
assert_eq!(b.state, [Some(110), None, Some(110), None]);
|
|
b.update(110, [false, true, true, false]);
|
|
assert_eq!(b.state, [Some(110), Some(110), Some(110), None]);
|
|
b.update(112, [false, false, true, true]);
|
|
assert_eq!(b.state, [Some(110), Some(110), Some(110), Some(112)]);
|
|
b.update(120, [false, false, false, false]);
|
|
assert_eq!(b.state, [None, None, None, Some(112)]);
|
|
b.update(122, [false, false, false, true]);
|
|
assert_eq!(b.state, [None, None, None, Some(112)]);
|
|
b.update(182, [false, false, false, true]);
|
|
assert_eq!(b.state, [None, None, None, Some(112)]);
|
|
}
|
|
#[test]
|
|
fn buttons_watcher() {
|
|
let mut b = Buttons::new();
|
|
let mut w = b.watch();
|
|
assert_eq!(w.events().collect::<Vec<_>>(), vec![]);
|
|
|
|
b.update(100, [true, false, false, false]);
|
|
w.update(&b);
|
|
assert_eq!(w.events().collect::<Vec<_>>(), vec![0]);
|
|
|
|
b.update(120, [false, true, false, false]);
|
|
w.update(&b);
|
|
b.update(140, [false, false, true, false]);
|
|
w.update(&b);
|
|
assert_eq!(w.events().collect::<Vec<_>>(), vec![1, 2]);
|
|
assert_eq!(w.events().collect::<Vec<_>>(), vec![]);
|
|
b.update(150, [false, false, true, false]);
|
|
w.update(&b);
|
|
assert_eq!(w.events().collect::<Vec<_>>(), vec![]);
|
|
}
|
|
}
|