Add timeout_at convenience function and example.
This commit is contained in:
		
							parent
							
								
									68be63c0e8
								
							
						
					
					
						commit
						1e698af05b
					
				| @ -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::{timeout_at, 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 [`timeout_at`] 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 timeout_at<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::{timeout_at, 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 timeout_at(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 timeout_at(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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user