Commit e019cb42 authored by Jason Heard's avatar Jason Heard
Browse files

Add button debouncing and on/off toggle

parent 4e36f874
use std::collections::HashSet;
use std::time::{
Duration,
Instant
};
use std::sync::mpsc::{
channel,
Receiver
......@@ -8,10 +12,13 @@ use rppal::gpio::Error as GpioError;
use rppal::gpio::{
Gpio,
InputPin,
Level,
Trigger
};
pub const BUTTON_COUNT: usize = 12;
pub const RELEASE_TIME: Duration = Duration::from_millis(50);
pub const PRESS_TIME: Duration = Duration::from_millis(50);
// Button pins by their "index".
// The top is the "KeyBow" silkscreen on the main board
......@@ -35,13 +42,24 @@ const BUTTON_MAP: [u8; BUTTON_COUNT] = [
];
struct ButtonEvent {
button: u8
button_index: usize,
level: Level,
timestamp: Instant
}
#[derive(Clone, Copy)]
enum ButtonState {
Pressed,
PressedReleasing(Instant),
Released,
ReleasedPressing(Instant)
}
pub struct Buttons {
_gpio: Gpio,
_pins: Vec<InputPin>,
receiver: Receiver<ButtonEvent>
receiver: Receiver<ButtonEvent>,
state: Vec<ButtonState>
}
impl Buttons {
......@@ -54,20 +72,94 @@ impl Buttons {
.into_input_pullup();
let sender_local = sender.clone();
button_pin.set_async_interrupt(Trigger::FallingEdge, move |_| sender_local.send(ButtonEvent{ button: button_index as u8 }).unwrap())?;
let button_callback = move |level| {
sender_local.send(ButtonEvent{
button_index: button_index,
level: level,
timestamp: Instant::now()
}).unwrap();
};
button_pin.set_async_interrupt(
Trigger::Both,
button_callback)?;
pins.push(button_pin);
}
Ok(Buttons {
_gpio: gpio,
_pins: pins,
receiver: receiver
receiver: receiver,
state: (0..BUTTON_COUNT)
.map(|_| ButtonState::Released)
.collect()
})
}
pub fn get_button_presses(&mut self) -> HashSet<u8> {
self.receiver.try_iter()
.map(|e| e.button)
.collect()
pub fn get_button_presses(&mut self) -> HashSet<usize> {
let mut button_presses = HashSet::new();
for event in self.receiver.try_iter() {
match self.state[event.button_index] {
ButtonState::Pressed => {
if event.level == Level::High {
self.state[event.button_index] = ButtonState::PressedReleasing(event.timestamp);
}
},
ButtonState::PressedReleasing(start) => {
let release_time = event.timestamp - start;
if event.level == Level::Low {
if release_time > RELEASE_TIME {
self.state[event.button_index] = ButtonState::ReleasedPressing(event.timestamp);
} else {
self.state[event.button_index] = ButtonState::Pressed;
}
} else if release_time > RELEASE_TIME {
self.state[event.button_index] = ButtonState::Released;
}
},
ButtonState::Released => {
if event.level == Level::Low {
self.state[event.button_index] = ButtonState::ReleasedPressing(event.timestamp);
}
},
ButtonState::ReleasedPressing(start) => {
let press_time = event.timestamp - start;
if event.level == Level::High {
if press_time > PRESS_TIME {
button_presses.insert(event.button_index);
self.state[event.button_index] = ButtonState::PressedReleasing(event.timestamp);
} else {
self.state[event.button_index] = ButtonState::Released;
}
} else if press_time > PRESS_TIME {
button_presses.insert(event.button_index);
self.state[event.button_index] = ButtonState::Pressed;
}
}
}
}
let now = Instant::now();
for (button_index, state) in self.state.clone().iter().enumerate() {
match state {
ButtonState::PressedReleasing(start) => {
let release_time = now - *start;
if release_time > RELEASE_TIME {
self.state[button_index] = ButtonState::Released;
}
},
ButtonState::ReleasedPressing(start) => {
let press_time = now - *start;
if press_time > PRESS_TIME {
button_presses.insert(button_index);
self.state[button_index] = ButtonState::Pressed;
}
},
_ => ()
}
}
button_presses
}
}
\ No newline at end of file
......@@ -44,6 +44,8 @@ fn got_terminal_signal(signals: &mut Signals) -> bool {
fn run_with_resources(mut signals: Signals, mut leds: Leds, mut buttons: Buttons) {
println!("The rainbow...");
let mut led_on = [true; LED_COUNT];
for led_index in 0..LED_COUNT {
leds.on(led_index);
}
......@@ -74,8 +76,12 @@ fn run_with_resources(mut signals: Signals, mut leds: Leds, mut buttons: Buttons
counter += 1;
for button in buttons.get_button_presses() {
println!("Button press: {}", button);
leds.off(button as usize);
led_on[button] = !led_on[button];
if led_on[button] {
leds.on(button);
} else {
leds.off(button);
}
}
leds.show();
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment