Strange behavior with Button
mariogeiger opened this issue · comments
Hi, Thanks for the nice library, it's faster than python ;-)
I am using a raspberry pi and I tried the following code:
use rust_gpiozero::Debounce;
use rust_gpiozero::*;
use std::{thread, time::Duration};
fn main() -> ! {
let mut red_button = Button::new(2).debounce(Duration::from_millis(100));
red_button
.when_pressed(|x| {
println!("button pressed {x:?}");
})
.unwrap();
red_button
.when_released(|x| {
println!("button released {x:?}");
})
.unwrap();
}
What I see when I press the button twice:
$ cargo run
Compiling rationalizer v0.1.0 (/home/happy/rationalizer)
Finished dev [unoptimized + debuginfo] target(s) in 3.75s
Running `target/debug/rationalizer`
button released Low
button released Low
button released Low
button released Low
What I expected:
$ cargo run
Compiling rationalizer v0.1.0 (/home/happy/rationalizer)
Finished dev [unoptimized + debuginfo] target(s) in 3.75s
Running `target/debug/rationalizer`
button pressed High
button released Low
button pressed High
button released Low
I can confirm the issue (though rather than four button released Low
I get two when pressing twice). I tried switching the order: when when_pressed
comes after when_released
, the output is two button pressed High
. I also tried without debounce
and that didn't change anything, though perhaps @thepacketgeek has thoughts nonetheless having worked on some button functionality?
tl; dr: Any previous async interrupt pin triggers are cleared when set_async_interrupt
is called, hence setting when_released
clears the trigger when_pressed
in your example. Closing since this behavior originates from a dependency.
Details: Both when_pressed
and when_released
call action_on
, which calls self.pin.set_async_interrupt(trigger, action)
of the dependency rppal
. The function set_async_interrupt
has the following documentation:
/// Configures an asynchronous interrupt trigger, which executes the callback on a
/// separate thread when the interrupt is triggered.
///
/// The callback closure or function pointer is called with a single [`Level`] argument.
///
/// Any previously configured (a)synchronous interrupt triggers for this pin are cleared
/// when `set_async_interrupt` is called, or when `InputPin` goes out of scope.
///
/// [`clear_async_interrupt`]: #method.clear_async_interrupt
/// [`Level`]: enum.Level.html
pub fn set_async_interrupt<C>(&mut self, trigger: Trigger, callback: C) -> Result<()>
where
C: FnMut(Level) + Send + 'static,
{