Merge pull request #2505 from CBJamo/timeout_at
Add timeout_at convenience function and example.
This commit is contained in:
commit
e05f6505ae
3 changed files with 95 additions and 2 deletions
|
@ -32,7 +32,7 @@ pub use delay::{block_for, Delay};
|
|||
pub use duration::Duration;
|
||||
pub use embassy_time_driver::TICK_HZ;
|
||||
pub use instant::Instant;
|
||||
pub use timer::{with_timeout, Ticker, TimeoutError, Timer};
|
||||
pub use timer::{with_deadline, with_timeout, Ticker, TimeoutError, Timer};
|
||||
|
||||
const fn gcd(a: u64, b: u64) -> u64 {
|
||||
if b == 0 {
|
||||
|
|
|
@ -8,7 +8,7 @@ use futures_util::{pin_mut, Stream};
|
|||
|
||||
use crate::{Duration, Instant};
|
||||
|
||||
/// Error returned by [`with_timeout`] on timeout.
|
||||
/// Error returned by [`with_timeout`] and [`with_deadline`] on timeout.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub struct TimeoutError;
|
||||
|
@ -26,6 +26,19 @@ pub async fn with_timeout<F: Future>(timeout: Duration, fut: F) -> Result<F::Out
|
|||
}
|
||||
}
|
||||
|
||||
/// Runs a given future with a deadline time.
|
||||
///
|
||||
/// If the future completes before the deadline, its output is returned. Otherwise, on timeout,
|
||||
/// work on the future is stopped (`poll` is no longer called), the future is dropped and `Err(TimeoutError)` is returned.
|
||||
pub async fn with_deadline<F: Future>(at: Instant, fut: F) -> Result<F::Output, TimeoutError> {
|
||||
let timeout_fut = Timer::at(at);
|
||||
pin_mut!(fut);
|
||||
match select(fut, timeout_fut).await {
|
||||
Either::Left((r, _)) => Ok(r),
|
||||
Either::Right(_) => Err(TimeoutError),
|
||||
}
|
||||
}
|
||||
|
||||
/// A future that completes at a specified [Instant](struct.Instant.html).
|
||||
#[must_use = "futures do nothing unless you `.await` or poll them"]
|
||||
pub struct Timer {
|
||||
|
|
80
examples/rp/src/bin/debounce.rs
Normal file
80
examples/rp/src/bin/debounce.rs
Normal file
|
@ -0,0 +1,80 @@
|
|||
//! This example shows the ease of debouncing a button with async rust.
|
||||
//! Hook up a button or switch between pin 9 and ground.
|
||||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use defmt::info;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_rp::gpio::{Input, Level, Pull};
|
||||
use embassy_time::{with_deadline, Duration, Instant, Timer};
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
pub struct Debouncer<'a> {
|
||||
input: Input<'a>,
|
||||
debounce: Duration,
|
||||
}
|
||||
|
||||
impl<'a> Debouncer<'a> {
|
||||
pub fn new(input: Input<'a>, debounce: Duration) -> Self {
|
||||
Self { input, debounce }
|
||||
}
|
||||
|
||||
pub async fn debounce(&mut self) -> Level {
|
||||
loop {
|
||||
let l1 = self.input.get_level();
|
||||
|
||||
self.input.wait_for_any_edge().await;
|
||||
|
||||
Timer::after(self.debounce).await;
|
||||
|
||||
let l2 = self.input.get_level();
|
||||
if l1 != l2 {
|
||||
break l2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(_spawner: Spawner) {
|
||||
let p = embassy_rp::init(Default::default());
|
||||
let mut btn = Debouncer::new(Input::new(p.PIN_9, Pull::Up), Duration::from_millis(20));
|
||||
|
||||
info!("Debounce Demo");
|
||||
|
||||
loop {
|
||||
// button pressed
|
||||
btn.debounce().await;
|
||||
let start = Instant::now();
|
||||
info!("Button Press");
|
||||
|
||||
match with_deadline(start + Duration::from_secs(1), btn.debounce()).await {
|
||||
// Button Released < 1s
|
||||
Ok(_) => {
|
||||
info!("Button pressed for: {}ms", start.elapsed().as_millis());
|
||||
continue;
|
||||
}
|
||||
// button held for > 1s
|
||||
Err(_) => {
|
||||
info!("Button Held");
|
||||
}
|
||||
}
|
||||
|
||||
match with_deadline(start + Duration::from_secs(5), btn.debounce()).await {
|
||||
// Button released <5s
|
||||
Ok(_) => {
|
||||
info!("Button pressed for: {}ms", start.elapsed().as_millis());
|
||||
continue;
|
||||
}
|
||||
// button held for > >5s
|
||||
Err(_) => {
|
||||
info!("Button Long Held");
|
||||
}
|
||||
}
|
||||
|
||||
// wait for button release before handling another press
|
||||
btn.debounce().await;
|
||||
info!("Button pressed for: {}ms", start.elapsed().as_millis());
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue