From 94bd4eb7d5713e4c6e679617a3e6e94671c8ff77 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 12 Jul 2021 03:10:01 +0200 Subject: embassy/time: refactor module structure --- embassy/src/executor/mod.rs | 1 - embassy/src/executor/timer.rs | 178 ------------------------------------------ embassy/src/time/delay.rs | 70 +++++++++++++++++ embassy/src/time/mod.rs | 58 +------------- embassy/src/time/timer.rs | 153 ++++++++++++++++++++++++++++++++++++ 5 files changed, 227 insertions(+), 233 deletions(-) delete mode 100644 embassy/src/executor/timer.rs create mode 100644 embassy/src/time/delay.rs create mode 100644 embassy/src/time/timer.rs diff --git a/embassy/src/executor/mod.rs b/embassy/src/executor/mod.rs index 598d4e558..d9740d56d 100644 --- a/embassy/src/executor/mod.rs +++ b/embassy/src/executor/mod.rs @@ -4,7 +4,6 @@ use core::{mem, ptr}; pub mod raw; mod run_queue; -pub(crate) mod timer; mod timer_queue; mod util; mod waker; diff --git a/embassy/src/executor/timer.rs b/embassy/src/executor/timer.rs deleted file mode 100644 index 8ee336960..000000000 --- a/embassy/src/executor/timer.rs +++ /dev/null @@ -1,178 +0,0 @@ -use core::future::Future; -use core::marker::PhantomData; -use core::pin::Pin; -use core::task::{Context, Poll}; -use futures::{future::select, future::Either, pin_mut, Stream}; - -use super::raw; -use crate::time::{Duration, Instant}; - -/// Delay abstraction using embassy's clock. -pub struct Delay { - _data: PhantomData, -} - -impl Delay { - pub fn new() -> Self { - Delay { - _data: PhantomData {}, - } - } -} - -impl crate::traits::delay::Delay for Delay { - type DelayFuture<'a> = impl Future + 'a; - - fn delay_ms<'a>(&'a mut self, millis: u64) -> Self::DelayFuture<'a> { - Timer::after(Duration::from_millis(millis)) - } - fn delay_us<'a>(&'a mut self, micros: u64) -> Self::DelayFuture<'a> { - Timer::after(Duration::from_micros(micros)) - } -} - -pub struct TimeoutError; -pub async fn with_timeout(timeout: Duration, fut: F) -> Result { - let timeout_fut = Timer::after(timeout); - 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). -pub struct Timer { - expires_at: Instant, - yielded_once: bool, -} - -impl Timer { - /// Expire at specified [Instant](struct.Instant.html) - pub fn at(expires_at: Instant) -> Self { - Self { - expires_at, - yielded_once: false, - } - } - - /// Expire after specified [Duration](struct.Duration.html). - /// This can be used as a `sleep` abstraction. - /// - /// Example: - /// ``` no_run - /// # #![feature(trait_alias)] - /// # #![feature(min_type_alias_impl_trait)] - /// # #![feature(impl_trait_in_bindings)] - /// # #![feature(type_alias_impl_trait)] - /// # - /// # fn foo() {} - /// use embassy::time::{Duration, Timer}; - /// - /// #[embassy::task] - /// async fn demo_sleep_seconds() { - /// // suspend this task for one second. - /// Timer::after(Duration::from_secs(1)).await; - /// } - /// ``` - pub fn after(duration: Duration) -> Self { - Self { - expires_at: Instant::now() + duration, - yielded_once: false, - } - } -} - -impl Unpin for Timer {} - -impl Future for Timer { - type Output = (); - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - if self.yielded_once && self.expires_at <= Instant::now() { - Poll::Ready(()) - } else { - unsafe { raw::register_timer(self.expires_at, cx.waker()) }; - self.yielded_once = true; - Poll::Pending - } - } -} - -/// Asynchronous stream that yields every Duration, indefinitely. -/// -/// This stream will tick at uniform intervals, even if blocking work is performed between ticks. -/// -/// For instance, consider the following code fragment. -/// ``` no_run -/// # #![feature(trait_alias)] -/// # #![feature(min_type_alias_impl_trait)] -/// # #![feature(impl_trait_in_bindings)] -/// # #![feature(type_alias_impl_trait)] -/// # -/// use embassy::time::{Duration, Timer}; -/// # fn foo() {} -/// -/// #[embassy::task] -/// async fn ticker_example_0() { -/// loop { -/// foo(); -/// Timer::after(Duration::from_secs(1)).await; -/// } -/// } -/// ``` -/// -/// This fragment will not call `foo` every second. -/// Instead, it will call it every second + the time it took to previously call `foo`. -/// -/// Example using ticker, which will consistently call `foo` once a second. -/// -/// ``` no_run -/// # #![feature(trait_alias)] -/// # #![feature(min_type_alias_impl_trait)] -/// # #![feature(impl_trait_in_bindings)] -/// # #![feature(type_alias_impl_trait)] -/// # -/// use embassy::time::{Duration, Ticker}; -/// use futures::StreamExt; -/// # fn foo(){} -/// -/// #[embassy::task] -/// async fn ticker_example_1() { -/// let mut ticker = Ticker::every(Duration::from_secs(1)); -/// loop { -/// foo(); -/// ticker.next().await; -/// } -/// } -/// ``` -pub struct Ticker { - expires_at: Instant, - duration: Duration, -} - -impl Ticker { - /// Creates a new ticker that ticks at the specified duration interval. - pub fn every(duration: Duration) -> Self { - let expires_at = Instant::now() + duration; - Self { - expires_at, - duration, - } - } -} - -impl Unpin for Ticker {} - -impl Stream for Ticker { - type Item = (); - fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - if self.expires_at <= Instant::now() { - let dur = self.duration; - self.expires_at += dur; - Poll::Ready(Some(())) - } else { - unsafe { raw::register_timer(self.expires_at, cx.waker()) }; - Poll::Pending - } - } -} diff --git a/embassy/src/time/delay.rs b/embassy/src/time/delay.rs new file mode 100644 index 000000000..f8b7f8400 --- /dev/null +++ b/embassy/src/time/delay.rs @@ -0,0 +1,70 @@ +use core::future::Future; + +use super::{Duration, Instant, Timer}; + +/// Async or blocking delay. +pub struct Delay; + +impl crate::traits::delay::Delay for Delay { + type DelayFuture<'a> = impl Future + 'a; + + fn delay_ms<'a>(&'a mut self, millis: u64) -> Self::DelayFuture<'a> { + Timer::after(Duration::from_millis(millis)) + } + fn delay_us<'a>(&'a mut self, micros: u64) -> Self::DelayFuture<'a> { + Timer::after(Duration::from_micros(micros)) + } +} + +/// Type used for blocking delays through embedded-hal traits. +/// +/// For this interface to work, the Executor's clock must be correctly initialized before using it. +/// The delays are implemented in a "best-effort" way, meaning that the cpu will block for at least +/// the amount provided, but accuracy can be affected by many factors, including interrupt usage. +/// Make sure to use a suitable tick rate for your use case. The tick rate can be chosen through +/// features flags of this crate. +pub struct BlockingTimer; + +impl embedded_hal::blocking::delay::DelayMs for BlockingTimer { + fn delay_ms(&mut self, ms: u8) { + block_for(Duration::from_millis(ms as u64)) + } +} + +impl embedded_hal::blocking::delay::DelayMs for BlockingTimer { + fn delay_ms(&mut self, ms: u16) { + block_for(Duration::from_millis(ms as u64)) + } +} + +impl embedded_hal::blocking::delay::DelayMs for BlockingTimer { + fn delay_ms(&mut self, ms: u32) { + block_for(Duration::from_millis(ms as u64)) + } +} + +impl embedded_hal::blocking::delay::DelayUs for BlockingTimer { + fn delay_us(&mut self, us: u8) { + block_for(Duration::from_micros(us as u64)) + } +} + +impl embedded_hal::blocking::delay::DelayUs for BlockingTimer { + fn delay_us(&mut self, us: u16) { + block_for(Duration::from_micros(us as u64)) + } +} + +impl embedded_hal::blocking::delay::DelayUs for BlockingTimer { + fn delay_us(&mut self, us: u32) { + block_for(Duration::from_micros(us as u64)) + } +} + +/// Blocks the cpu for at least `duration`. +/// +/// For this interface to work, the Executor's clock must be correctly initialized before using it. +pub fn block_for(duration: Duration) { + let expires_at = Instant::now() + duration; + while Instant::now() < expires_at {} +} diff --git a/embassy/src/time/mod.rs b/embassy/src/time/mod.rs index d50d9ef0d..9b7a4be18 100644 --- a/embassy/src/time/mod.rs +++ b/embassy/src/time/mod.rs @@ -1,13 +1,16 @@ //! Time abstractions //! To use these abstractions, first call `set_clock` with an instance of an [Clock](trait.Clock.html). //! +mod delay; mod duration; mod instant; +mod timer; mod traits; -pub use crate::executor::timer::{with_timeout, Delay, Ticker, TimeoutError, Timer}; +pub use delay::{block_for, Delay}; pub use duration::Duration; pub use instant::Instant; +pub use timer::{with_timeout, Ticker, TimeoutError, Timer}; pub use traits::*; #[cfg(any( @@ -42,56 +45,3 @@ pub unsafe fn set_clock(clock: &'static dyn Clock) { pub(crate) fn now() -> u64 { unsafe { unwrap!(CLOCK, "No clock set").now() } } - -/// Type used for blocking delays through embedded-hal traits. -/// -/// For this interface to work, the Executor's clock must be correctly initialized before using it. -/// The delays are implemented in a "best-effort" way, meaning that the cpu will block for at least -/// the amount provided, but accuracy can be affected by many factors, including interrupt usage. -/// Make sure to use a suitable tick rate for your use case. The tick rate can be chosen through -/// features flags of this crate. -pub struct BlockingTimer; - -impl embedded_hal::blocking::delay::DelayMs for BlockingTimer { - fn delay_ms(&mut self, ms: u8) { - block_for(Duration::from_millis(ms as u64)) - } -} - -impl embedded_hal::blocking::delay::DelayMs for BlockingTimer { - fn delay_ms(&mut self, ms: u16) { - block_for(Duration::from_millis(ms as u64)) - } -} - -impl embedded_hal::blocking::delay::DelayMs for BlockingTimer { - fn delay_ms(&mut self, ms: u32) { - block_for(Duration::from_millis(ms as u64)) - } -} - -impl embedded_hal::blocking::delay::DelayUs for BlockingTimer { - fn delay_us(&mut self, us: u8) { - block_for(Duration::from_micros(us as u64)) - } -} - -impl embedded_hal::blocking::delay::DelayUs for BlockingTimer { - fn delay_us(&mut self, us: u16) { - block_for(Duration::from_micros(us as u64)) - } -} - -impl embedded_hal::blocking::delay::DelayUs for BlockingTimer { - fn delay_us(&mut self, us: u32) { - block_for(Duration::from_micros(us as u64)) - } -} - -/// Blocks the cpu for at least `duration`. -/// -/// For this interface to work, the Executor's clock must be correctly initialized before using it. -pub fn block_for(duration: Duration) { - let expires_at = Instant::now() + duration; - while Instant::now() < expires_at {} -} diff --git a/embassy/src/time/timer.rs b/embassy/src/time/timer.rs new file mode 100644 index 000000000..a2a37f706 --- /dev/null +++ b/embassy/src/time/timer.rs @@ -0,0 +1,153 @@ +use core::future::Future; +use core::pin::Pin; +use core::task::{Context, Poll}; +use futures::{future::select, future::Either, pin_mut, Stream}; + +use crate::executor::raw; +use crate::time::{Duration, Instant}; + +pub struct TimeoutError; +pub async fn with_timeout(timeout: Duration, fut: F) -> Result { + let timeout_fut = Timer::after(timeout); + 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). +pub struct Timer { + expires_at: Instant, + yielded_once: bool, +} + +impl Timer { + /// Expire at specified [Instant](struct.Instant.html) + pub fn at(expires_at: Instant) -> Self { + Self { + expires_at, + yielded_once: false, + } + } + + /// Expire after specified [Duration](struct.Duration.html). + /// This can be used as a `sleep` abstraction. + /// + /// Example: + /// ``` no_run + /// # #![feature(trait_alias)] + /// # #![feature(min_type_alias_impl_trait)] + /// # #![feature(impl_trait_in_bindings)] + /// # #![feature(type_alias_impl_trait)] + /// # + /// # fn foo() {} + /// use embassy::time::{Duration, Timer}; + /// + /// #[embassy::task] + /// async fn demo_sleep_seconds() { + /// // suspend this task for one second. + /// Timer::after(Duration::from_secs(1)).await; + /// } + /// ``` + pub fn after(duration: Duration) -> Self { + Self { + expires_at: Instant::now() + duration, + yielded_once: false, + } + } +} + +impl Unpin for Timer {} + +impl Future for Timer { + type Output = (); + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + if self.yielded_once && self.expires_at <= Instant::now() { + Poll::Ready(()) + } else { + unsafe { raw::register_timer(self.expires_at, cx.waker()) }; + self.yielded_once = true; + Poll::Pending + } + } +} + +/// Asynchronous stream that yields every Duration, indefinitely. +/// +/// This stream will tick at uniform intervals, even if blocking work is performed between ticks. +/// +/// For instance, consider the following code fragment. +/// ``` no_run +/// # #![feature(trait_alias)] +/// # #![feature(min_type_alias_impl_trait)] +/// # #![feature(impl_trait_in_bindings)] +/// # #![feature(type_alias_impl_trait)] +/// # +/// use embassy::time::{Duration, Timer}; +/// # fn foo() {} +/// +/// #[embassy::task] +/// async fn ticker_example_0() { +/// loop { +/// foo(); +/// Timer::after(Duration::from_secs(1)).await; +/// } +/// } +/// ``` +/// +/// This fragment will not call `foo` every second. +/// Instead, it will call it every second + the time it took to previously call `foo`. +/// +/// Example using ticker, which will consistently call `foo` once a second. +/// +/// ``` no_run +/// # #![feature(trait_alias)] +/// # #![feature(min_type_alias_impl_trait)] +/// # #![feature(impl_trait_in_bindings)] +/// # #![feature(type_alias_impl_trait)] +/// # +/// use embassy::time::{Duration, Ticker}; +/// use futures::StreamExt; +/// # fn foo(){} +/// +/// #[embassy::task] +/// async fn ticker_example_1() { +/// let mut ticker = Ticker::every(Duration::from_secs(1)); +/// loop { +/// foo(); +/// ticker.next().await; +/// } +/// } +/// ``` +pub struct Ticker { + expires_at: Instant, + duration: Duration, +} + +impl Ticker { + /// Creates a new ticker that ticks at the specified duration interval. + pub fn every(duration: Duration) -> Self { + let expires_at = Instant::now() + duration; + Self { + expires_at, + duration, + } + } +} + +impl Unpin for Ticker {} + +impl Stream for Ticker { + type Item = (); + fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + if self.expires_at <= Instant::now() { + let dur = self.duration; + self.expires_at += dur; + Poll::Ready(Some(())) + } else { + unsafe { raw::register_timer(self.expires_at, cx.waker()) }; + Poll::Pending + } + } +} -- cgit From 35a76c364a90cae23a2a1e72e1d084c226048915 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 12 Jul 2021 03:29:09 +0200 Subject: embassy/time: make optional via Cargo feature --- embassy-nrf/Cargo.toml | 2 +- embassy-rp/Cargo.toml | 2 +- embassy-std/Cargo.toml | 2 +- embassy-stm32/Cargo.toml | 2 +- embassy/Cargo.toml | 10 ++++++---- embassy/src/executor/mod.rs | 8 +++++--- embassy/src/executor/raw.rs | 44 +++++++++++++++++++++++++++++++++----------- embassy/src/lib.rs | 1 + embassy/src/time/mod.rs | 14 +++----------- 9 files changed, 52 insertions(+), 33 deletions(-) diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml index 7b8e36414..85ded1df4 100644 --- a/embassy-nrf/Cargo.toml +++ b/embassy-nrf/Cargo.toml @@ -21,7 +21,7 @@ nrf52840 = ["nrf52840-pac"] [dependencies] -embassy = { version = "0.1.0", path = "../embassy" } +embassy = { version = "0.1.0", path = "../embassy", features = ["time-tick-32768hz"] } embassy-macros = { version = "0.1.0", path = "../embassy-macros", features = ["nrf"]} embassy-extras = {version = "0.1.0", path = "../embassy-extras" } diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml index 2313c6432..503d2c706 100644 --- a/embassy-rp/Cargo.toml +++ b/embassy-rp/Cargo.toml @@ -12,7 +12,7 @@ defmt-warn = [ ] defmt-error = [ ] [dependencies] -embassy = { version = "0.1.0", path = "../embassy" } +embassy = { version = "0.1.0", path = "../embassy", features = [ "time-tick-1mhz" ] } embassy-extras = {version = "0.1.0", path = "../embassy-extras" } embassy-macros = { version = "0.1.0", path = "../embassy-macros", features = ["rp"]} diff --git a/embassy-std/Cargo.toml b/embassy-std/Cargo.toml index 2a95838e8..2633f1232 100644 --- a/embassy-std/Cargo.toml +++ b/embassy-std/Cargo.toml @@ -5,6 +5,6 @@ authors = ["Dario Nieuwenhuis "] edition = "2018" [dependencies] -embassy = { version = "0.1.0", path = "../embassy", features = ["std"] } +embassy = { version = "0.1.0", path = "../embassy", features = ["std", "time-tick-32768hz"] } embassy-macros = { version = "0.1.0", path = "../embassy-macros", features = ["std"]} lazy_static = "1.4.0" diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 4e37c94fe..654bc98ef 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -6,7 +6,7 @@ edition = "2018" resolver = "2" [dependencies] -embassy = { version = "0.1.0", path = "../embassy" } +embassy = { version = "0.1.0", path = "../embassy", features = ["time-tick-32768hz"] } embassy-macros = { version = "0.1.0", path = "../embassy-macros", features = ["stm32"] } embassy-extras = {version = "0.1.0", path = "../embassy-extras" } embassy-traits = {version = "0.1.0", path = "../embassy-traits" } diff --git a/embassy/Cargo.toml b/embassy/Cargo.toml index 87f54409a..b2ad80495 100644 --- a/embassy/Cargo.toml +++ b/embassy/Cargo.toml @@ -5,11 +5,13 @@ authors = ["Dario Nieuwenhuis "] edition = "2018" [features] -default = ["tick-32768hz"] +default = [] std = ["futures/std", "embassy-traits/std"] -tick-32768hz = [] -tick-1000hz = [] -tick-1mhz = [] + +time = [] +time-tick-32768hz = ["time"] +time-tick-1000hz = ["time"] +time-tick-1mhz = ["time"] defmt-trace = [] defmt-debug = [] diff --git a/embassy/src/executor/mod.rs b/embassy/src/executor/mod.rs index d9740d56d..771f75ee8 100644 --- a/embassy/src/executor/mod.rs +++ b/embassy/src/executor/mod.rs @@ -4,12 +4,12 @@ use core::{mem, ptr}; pub mod raw; mod run_queue; +#[cfg(feature = "time")] mod timer_queue; mod util; mod waker; use crate::interrupt::{Interrupt, InterruptExt}; -use crate::time::Alarm; #[must_use = "Calling a task function does nothing on its own. You must pass the returned SpawnToken to Executor::spawn()"] pub struct SpawnToken { @@ -116,7 +116,8 @@ impl Executor { } } - pub fn set_alarm(&mut self, alarm: &'static dyn Alarm) { + #[cfg(feature = "time")] + pub fn set_alarm(&mut self, alarm: &'static dyn crate::time::Alarm) { self.inner.set_alarm(alarm); } @@ -160,7 +161,8 @@ impl InterruptExecutor { } } - pub fn set_alarm(&mut self, alarm: &'static dyn Alarm) { + #[cfg(feature = "time")] + pub fn set_alarm(&mut self, alarm: &'static dyn crate::time::Alarm) { self.inner.set_alarm(alarm); } diff --git a/embassy/src/executor/raw.rs b/embassy/src/executor/raw.rs index 52512c533..cd2f0446d 100644 --- a/embassy/src/executor/raw.rs +++ b/embassy/src/executor/raw.rs @@ -1,18 +1,20 @@ use atomic_polyfill::{AtomicU32, Ordering}; use core::cell::Cell; -use core::cmp::min; use core::future::Future; use core::marker::PhantomData; use core::pin::Pin; use core::ptr::NonNull; -use core::task::{Context, Poll, Waker}; +use core::task::{Context, Poll}; use core::{mem, ptr}; use super::run_queue::{RunQueue, RunQueueItem}; -use super::timer_queue::{TimerQueue, TimerQueueItem}; use super::util::UninitCell; use super::waker; use super::SpawnToken; + +#[cfg(feature = "time")] +use super::timer_queue::{TimerQueue, TimerQueueItem}; +#[cfg(feature = "time")] use crate::time::{Alarm, Instant}; /// Task is spawned (has a future) @@ -20,26 +22,33 @@ pub(crate) const STATE_SPAWNED: u32 = 1 << 0; /// Task is in the executor run queue pub(crate) const STATE_RUN_QUEUED: u32 = 1 << 1; /// Task is in the executor timer queue +#[cfg(feature = "time")] pub(crate) const STATE_TIMER_QUEUED: u32 = 1 << 2; pub struct TaskHeader { pub(crate) state: AtomicU32, pub(crate) run_queue_item: RunQueueItem, - pub(crate) expires_at: Cell, - pub(crate) timer_queue_item: TimerQueueItem, pub(crate) executor: Cell<*const Executor>, // Valid if state != 0 pub(crate) poll_fn: UninitCell)>, // Valid if STATE_SPAWNED + + #[cfg(feature = "time")] + pub(crate) expires_at: Cell, + #[cfg(feature = "time")] + pub(crate) timer_queue_item: TimerQueueItem, } impl TaskHeader { pub(crate) const fn new() -> Self { Self { state: AtomicU32::new(0), - expires_at: Cell::new(Instant::from_ticks(0)), run_queue_item: RunQueueItem::new(), - timer_queue_item: TimerQueueItem::new(), executor: Cell::new(ptr::null()), poll_fn: UninitCell::uninit(), + + #[cfg(feature = "time")] + expires_at: Cell::new(Instant::from_ticks(0)), + #[cfg(feature = "time")] + timer_queue_item: TimerQueueItem::new(), } } @@ -154,9 +163,12 @@ unsafe impl Sync for Task {} pub struct Executor { run_queue: RunQueue, - timer_queue: TimerQueue, signal_fn: fn(*mut ()), signal_ctx: *mut (), + + #[cfg(feature = "time")] + timer_queue: TimerQueue, + #[cfg(feature = "time")] alarm: Option<&'static dyn Alarm>, } @@ -164,13 +176,17 @@ impl Executor { pub const fn new(signal_fn: fn(*mut ()), signal_ctx: *mut ()) -> Self { Self { run_queue: RunQueue::new(), - timer_queue: TimerQueue::new(), signal_fn, signal_ctx, + + #[cfg(feature = "time")] + timer_queue: TimerQueue::new(), + #[cfg(feature = "time")] alarm: None, } } + #[cfg(feature = "time")] pub fn set_alarm(&mut self, alarm: &'static dyn Alarm) { self.alarm = Some(alarm); } @@ -192,6 +208,7 @@ impl Executor { } pub unsafe fn run_queued(&'static self) { + #[cfg(feature = "time")] if self.alarm.is_some() { self.timer_queue.dequeue_expired(Instant::now(), |p| { p.as_ref().enqueue(); @@ -200,6 +217,8 @@ impl Executor { self.run_queue.dequeue_all(|p| { let task = p.as_ref(); + + #[cfg(feature = "time")] task.expires_at.set(Instant::MAX); let state = task.state.fetch_and(!STATE_RUN_QUEUED, Ordering::AcqRel); @@ -216,11 +235,13 @@ impl Executor { task.poll_fn.read()(p as _); // Enqueue or update into timer_queue + #[cfg(feature = "time")] self.timer_queue.update(p); }); // If this is in the past, set_alarm will immediately trigger the alarm, // which will make the wfe immediately return so we do another loop iteration. + #[cfg(feature = "time")] if let Some(alarm) = self.alarm { let next_expiration = self.timer_queue.next_expiration(); alarm.set_callback(self.signal_fn, self.signal_ctx); @@ -242,9 +263,10 @@ pub unsafe fn wake_task(task: NonNull) { task.as_ref().enqueue(); } -pub(crate) unsafe fn register_timer(at: Instant, waker: &Waker) { +#[cfg(feature = "time")] +pub(crate) unsafe fn register_timer(at: Instant, waker: &core::task::Waker) { let task = waker::task_from_waker(waker); let task = task.as_ref(); let expires_at = task.expires_at.get(); - task.expires_at.set(min(expires_at, at)); + task.expires_at.set(expires_at.min(at)); } diff --git a/embassy/src/lib.rs b/embassy/src/lib.rs index 3a0701d38..41102a180 100644 --- a/embassy/src/lib.rs +++ b/embassy/src/lib.rs @@ -14,6 +14,7 @@ pub(crate) mod fmt; pub mod executor; pub mod interrupt; pub mod io; +#[cfg(feature = "time")] pub mod time; pub mod util; diff --git a/embassy/src/time/mod.rs b/embassy/src/time/mod.rs index 9b7a4be18..d9777c45b 100644 --- a/embassy/src/time/mod.rs +++ b/embassy/src/time/mod.rs @@ -13,21 +13,13 @@ pub use instant::Instant; pub use timer::{with_timeout, Ticker, TimeoutError, Timer}; pub use traits::*; -#[cfg(any( - all(feature = "tick-32768hz", feature = "tick-1000hz"), - all(feature = "tick-32768hz", feature = "tick-1mhz"), -))] -compile_error!( - "Disable default-features to be able to use a tick rate other than the default (32768 Hz)" -); - -#[cfg(feature = "tick-1000hz")] +#[cfg(feature = "time-tick-1000hz")] pub const TICKS_PER_SECOND: u64 = 1_000; -#[cfg(feature = "tick-32768hz")] +#[cfg(feature = "time-tick-32768hz")] pub const TICKS_PER_SECOND: u64 = 32_768; -#[cfg(feature = "tick-1mhz")] +#[cfg(feature = "time-tick-1mhz")] pub const TICKS_PER_SECOND: u64 = 1_000_000; static mut CLOCK: Option<&'static dyn Clock> = None; -- cgit From 16bb678368c7e781e8f4df867669727fe7988c42 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 12 Jul 2021 03:31:56 +0200 Subject: Merge BlockingTimer and Delay --- embassy/src/time/delay.rs | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/embassy/src/time/delay.rs b/embassy/src/time/delay.rs index f8b7f8400..c97e8b5c2 100644 --- a/embassy/src/time/delay.rs +++ b/embassy/src/time/delay.rs @@ -2,7 +2,13 @@ use core::future::Future; use super::{Duration, Instant, Timer}; -/// Async or blocking delay. +/// Type implementing async delays and blocking `embedded-hal` delays. +/// +/// For this interface to work, the Executor's clock must be correctly initialized before using it. +/// The delays are implemented in a "best-effort" way, meaning that the cpu will block for at least +/// the amount provided, but accuracy can be affected by many factors, including interrupt usage. +/// Make sure to use a suitable tick rate for your use case. The tick rate can be chosen through +/// features flags of this crate. pub struct Delay; impl crate::traits::delay::Delay for Delay { @@ -16,46 +22,37 @@ impl crate::traits::delay::Delay for Delay { } } -/// Type used for blocking delays through embedded-hal traits. -/// -/// For this interface to work, the Executor's clock must be correctly initialized before using it. -/// The delays are implemented in a "best-effort" way, meaning that the cpu will block for at least -/// the amount provided, but accuracy can be affected by many factors, including interrupt usage. -/// Make sure to use a suitable tick rate for your use case. The tick rate can be chosen through -/// features flags of this crate. -pub struct BlockingTimer; - -impl embedded_hal::blocking::delay::DelayMs for BlockingTimer { +impl embedded_hal::blocking::delay::DelayMs for Delay { fn delay_ms(&mut self, ms: u8) { block_for(Duration::from_millis(ms as u64)) } } -impl embedded_hal::blocking::delay::DelayMs for BlockingTimer { +impl embedded_hal::blocking::delay::DelayMs for Delay { fn delay_ms(&mut self, ms: u16) { block_for(Duration::from_millis(ms as u64)) } } -impl embedded_hal::blocking::delay::DelayMs for BlockingTimer { +impl embedded_hal::blocking::delay::DelayMs for Delay { fn delay_ms(&mut self, ms: u32) { block_for(Duration::from_millis(ms as u64)) } } -impl embedded_hal::blocking::delay::DelayUs for BlockingTimer { +impl embedded_hal::blocking::delay::DelayUs for Delay { fn delay_us(&mut self, us: u8) { block_for(Duration::from_micros(us as u64)) } } -impl embedded_hal::blocking::delay::DelayUs for BlockingTimer { +impl embedded_hal::blocking::delay::DelayUs for Delay { fn delay_us(&mut self, us: u16) { block_for(Duration::from_micros(us as u64)) } } -impl embedded_hal::blocking::delay::DelayUs for BlockingTimer { +impl embedded_hal::blocking::delay::DelayUs for Delay { fn delay_us(&mut self, us: u32) { block_for(Duration::from_micros(us as u64)) } -- cgit From c210a6efd1f77c4dd6c5df7b31e49c771ceb0cff Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 12 Jul 2021 02:46:16 +0200 Subject: embassy/time: remove useless impl --- embassy/src/time/traits.rs | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/embassy/src/time/traits.rs b/embassy/src/time/traits.rs index 2c97b13af..4c6134c3c 100644 --- a/embassy/src/time/traits.rs +++ b/embassy/src/time/traits.rs @@ -30,15 +30,3 @@ pub trait Alarm { /// If no alarm was set, this is a noop. fn clear(&self); } - -impl Alarm for &T { - fn set_callback(&self, callback: fn(*mut ()), ctx: *mut ()) { - T::set_callback(self, callback, ctx); - } - fn set(&self, timestamp: u64) { - T::set(self, timestamp); - } - fn clear(&self) { - T::clear(self) - } -} -- cgit