From 8c23e178f3838bcdd13662a2ffefd39ec144e869 Mon Sep 17 00:00:00 2001 From: Finomnis Date: Thu, 11 Apr 2024 00:00:38 +0200 Subject: Monotonic rewrite (#874) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Rework timer_queue and monotonic architecture Goals: * make Monotonic purely internal * make Monotonic purely tick passed, no fugit involved * create a wrapper struct in the user's code via a macro that then converts the "now" from the tick based monotonic to a fugit based timestamp We need to proxy the delay functions of the timer queue anyway, so we could simply perform the conversion in those proxy functions. * Update cargo.lock * Update readme of rtic-time * CI: ESP32: Redact esp_image: Too volatile * Fixup: Changelog double entry rebase mistake --------- Co-authored-by: Henrik Tjäder --- rtic-time/src/monotonic/embedded_hal_macros.rs | 77 ++++++++++++++ .../src/monotonic/timer_queue_based_monotonic.rs | 113 +++++++++++++++++++++ 2 files changed, 190 insertions(+) create mode 100644 rtic-time/src/monotonic/embedded_hal_macros.rs create mode 100644 rtic-time/src/monotonic/timer_queue_based_monotonic.rs (limited to 'rtic-time/src/monotonic') diff --git a/rtic-time/src/monotonic/embedded_hal_macros.rs b/rtic-time/src/monotonic/embedded_hal_macros.rs new file mode 100644 index 0000000..25ac791 --- /dev/null +++ b/rtic-time/src/monotonic/embedded_hal_macros.rs @@ -0,0 +1,77 @@ +//! Macros that implement embedded-hal traits for Monotonics + +/// Implements [`embedded_hal::delay::DelayNs`] for a given monotonic. +#[macro_export] +macro_rules! impl_embedded_hal_delay_fugit { + ($t:ty) => { + impl $crate::embedded_hal::delay::DelayNs for $t { + fn delay_ns(&mut self, ns: u32) { + let now = ::now(); + let mut done = + now + ::Duration::nanos_at_least(ns.into()); + if now != done { + // Compensate for sub-tick uncertainty + done = done + ::Duration::from_ticks(1); + } + + while ::now() < done {} + } + + fn delay_us(&mut self, us: u32) { + let now = ::now(); + let mut done = + now + ::Duration::micros_at_least(us.into()); + if now != done { + // Compensate for sub-tick uncertainty + done = done + ::Duration::from_ticks(1); + } + + while ::now() < done {} + } + + fn delay_ms(&mut self, ms: u32) { + let now = ::now(); + let mut done = + now + ::Duration::millis_at_least(ms.into()); + if now != done { + // Compensate for sub-tick uncertainty + done = done + ::Duration::from_ticks(1); + } + + while ::now() < done {} + } + } + }; +} + +/// Implements [`embedded_hal_async::delay::DelayNs`] for a given monotonic. +#[macro_export] +macro_rules! impl_embedded_hal_async_delay_fugit { + ($t:ty) => { + impl $crate::embedded_hal_async::delay::DelayNs for $t { + #[inline] + async fn delay_ns(&mut self, ns: u32) { + ::delay( + ::Duration::nanos_at_least(ns.into()), + ) + .await; + } + + #[inline] + async fn delay_us(&mut self, us: u32) { + ::delay( + ::Duration::micros_at_least(us.into()), + ) + .await; + } + + #[inline] + async fn delay_ms(&mut self, ms: u32) { + ::delay( + ::Duration::millis_at_least(ms.into()), + ) + .await; + } + } + }; +} diff --git a/rtic-time/src/monotonic/timer_queue_based_monotonic.rs b/rtic-time/src/monotonic/timer_queue_based_monotonic.rs new file mode 100644 index 0000000..699958b --- /dev/null +++ b/rtic-time/src/monotonic/timer_queue_based_monotonic.rs @@ -0,0 +1,113 @@ +use crate::{timer_queue::TimerQueueBackend, TimeoutError}; + +use crate::Monotonic; + +/// A [`Monotonic`] that is backed by the [`TimerQueue`](crate::timer_queue::TimerQueue). +pub trait TimerQueueBasedMonotonic { + /// The backend for the timer queue + type Backend: TimerQueueBackend; + + /// The type for instant, defining an instant in time. + /// + /// **Note:** In all APIs in RTIC that use instants from this monotonic, this type will be used. + type Instant: TimerQueueBasedInstant::Ticks> + + core::ops::Add + + core::ops::Sub + + core::ops::Sub; + + /// The type for duration, defining a duration of time. + /// + /// **Note:** In all APIs in RTIC that use duration from this monotonic, this type will be used. + type Duration: TimerQueueBasedDuration::Ticks>; +} + +impl Monotonic for T { + type Instant = T::Instant; + type Duration = T::Duration; + + fn now() -> Self::Instant { + Self::Instant::from_ticks(T::Backend::timer_queue().now()) + } + + async fn delay(duration: Self::Duration) { + T::Backend::timer_queue().delay(duration.ticks()).await + } + + async fn delay_until(instant: Self::Instant) { + T::Backend::timer_queue().delay_until(instant.ticks()).await + } + + async fn timeout_at( + instant: Self::Instant, + future: F, + ) -> Result { + T::Backend::timer_queue() + .timeout_at(instant.ticks(), future) + .await + } + + async fn timeout_after( + duration: Self::Duration, + future: F, + ) -> Result { + T::Backend::timer_queue() + .timeout_after(duration.ticks(), future) + .await + } +} + +/// An instant that can be used in [`TimerQueueBasedMonotonic`]. +pub trait TimerQueueBasedInstant: Ord + Copy { + /// The internal type of the instant + type Ticks; + /// Convert from ticks to the instant + fn from_ticks(ticks: Self::Ticks) -> Self; + /// Convert the instant to ticks + fn ticks(self) -> Self::Ticks; +} + +/// A duration that can be used in [`TimerQueueBasedMonotonic`]. +pub trait TimerQueueBasedDuration: Copy { + /// The internal type of the duration + type Ticks; + /// Convert the duration to ticks + fn ticks(self) -> Self::Ticks; +} + +impl TimerQueueBasedInstant for fugit::Instant { + type Ticks = u64; + fn from_ticks(ticks: Self::Ticks) -> Self { + Self::from_ticks(ticks) + } + fn ticks(self) -> Self::Ticks { + Self::ticks(&self) + } +} + +impl TimerQueueBasedInstant for fugit::Instant { + type Ticks = u32; + fn from_ticks(ticks: Self::Ticks) -> Self { + Self::from_ticks(ticks) + } + fn ticks(self) -> Self::Ticks { + Self::ticks(&self) + } +} + +impl TimerQueueBasedDuration + for fugit::Duration +{ + type Ticks = u64; + fn ticks(self) -> Self::Ticks { + Self::ticks(&self) + } +} + +impl TimerQueueBasedDuration + for fugit::Duration +{ + type Ticks = u32; + fn ticks(self) -> Self::Ticks { + Self::ticks(&self) + } +} -- cgit v1.2.3