aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Emil Fresk <emil.fresk@gmail.com> 2021-03-11 19:12:02 +0100
committerGravatar Emil Fresk <emil.fresk@gmail.com> 2021-03-13 10:50:56 +0100
commit1087f2ee64a5be1aedf3b702ccb5d86cc64708d9 (patch)
tree312e099ce019124a40345949491475aaac26a7ce
parent4bdc1879122d6389adab0bebb14795954c491aaf (diff)
downloadrtic-1087f2ee64a5be1aedf3b702ccb5d86cc64708d9.tar.gz
rtic-1087f2ee64a5be1aedf3b702ccb5d86cc64708d9.tar.zst
rtic-1087f2ee64a5be1aedf3b702ccb5d86cc64708d9.zip
Added interface for cancel/reschedule
Use wrapping add for marker No need to store handle to queue Remove unnecessary `SpawnHandle::new` Fix test Updated interface to follow proposal
-rw-r--r--examples/t-schedule.rs23
-rw-r--r--macros/src/codegen/module.rs74
-rw-r--r--macros/src/codegen/timer_queue.rs11
-rw-r--r--macros/src/codegen/util.rs5
-rw-r--r--src/cyccnt.rs221
-rw-r--r--src/tq.rs23
6 files changed, 108 insertions, 249 deletions
diff --git a/examples/t-schedule.rs b/examples/t-schedule.rs
index bd0ab668..6b6245eb 100644
--- a/examples/t-schedule.rs
+++ b/examples/t-schedule.rs
@@ -26,18 +26,29 @@ mod app {
let mono = DwtSystick::new(&mut dcb, dwt, systick, 8_000_000);
- let _: Result<(), ()> = foo::spawn_after(Seconds(1_u32));
- let _: Result<(), u32> = bar::spawn_after(Seconds(2_u32), 0);
- let _: Result<(), (u32, u32)> = baz::spawn_after(Seconds(3_u32), 0, 1);
+ let a: Result<foo::MyMono::SpawnHandle, ()> = foo::spawn_after(Seconds(1_u32));
+ if let Ok(handle) = a {
+ let _: Result<foo::MyMono::SpawnHandle, ()> = handle.reschedule_after(Seconds(1_u32));
+ }
+
+ let b: Result<bar::MyMono::SpawnHandle, u32> = bar::spawn_after(Seconds(2_u32), 0);
+ if let Ok(handle) = b {
+ let _: Result<u32, ()> = handle.cancel();
+ }
+
+ let _: Result<baz::MyMono::SpawnHandle, (u32, u32)> =
+ baz::spawn_after(Seconds(3_u32), 0, 1);
(init::LateResources {}, init::Monotonics(mono))
}
#[idle]
fn idle(_: idle::Context) -> ! {
- let _: Result<(), ()> = foo::spawn_at(MyMono::now() + Seconds(3_u32));
- let _: Result<(), u32> = bar::spawn_at(MyMono::now() + Seconds(4_u32), 0);
- let _: Result<(), (u32, u32)> = baz::spawn_at(MyMono::now() + Seconds(5_u32), 0, 1);
+ let _: Result<foo::MyMono::SpawnHandle, ()> = foo::spawn_at(MyMono::now() + Seconds(3_u32));
+ let _: Result<bar::MyMono::SpawnHandle, u32> =
+ bar::spawn_at(MyMono::now() + Seconds(4_u32), 0);
+ let _: Result<baz::MyMono::SpawnHandle, (u32, u32)> =
+ baz::spawn_at(MyMono::now() + Seconds(5_u32), 0, 1);
loop {
cortex_m::asm::nop();
diff --git a/macros/src/codegen/module.rs b/macros/src/codegen/module.rs
index 75435b54..fb028e01 100644
--- a/macros/src/codegen/module.rs
+++ b/macros/src/codegen/module.rs
@@ -264,15 +264,64 @@ pub fn codegen(
};
let user_imports = &app.user_imports;
+ let tq_marker = util::mark_internal_ident(&util::timer_queue_marker_ident());
items.push(quote!(
/// Holds methods related to this monotonic
pub mod #m {
+ #[allow(unused_imports)]
+ use #app_path::#tq_marker;
+ #[allow(unused_imports)]
+ use #app_path::#t;
#(
#[allow(unused_imports)]
#user_imports
)*
+ pub struct SpawnHandle {
+ #[doc(hidden)]
+ marker: u32,
+ }
+
+ // TODO: remove
+ impl core::fmt::Debug for SpawnHandle
+ {
+ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+ let handle = unsafe { &#app_path::#tq as *const _ as u32 };
+ f.debug_struct("SpawnHandle")
+ .field("marker", &self.marker)
+ .field("handle", &handle)
+ .finish()
+ }
+ }
+
+ impl SpawnHandle {
+ pub fn cancel(self) -> Result<#ty, ()> {
+ // TODO: Actually cancel...
+ // &mut #app_path::#tq;
+
+ Err(())
+ }
+
+ #[inline]
+ pub fn reschedule_after<D>(self, duration: D) -> Result<Self, ()>
+ where D: rtic::time::duration::Duration + rtic::time::fixed_point::FixedPoint,
+ D::T: Into<<#app_path::#mono_type as rtic::time::Clock>::T>,
+ {
+ self.reschedule_at(#app_path::#m::now() + duration)
+ }
+
+ pub fn reschedule_at(self, instant: rtic::time::Instant<#app_path::#mono_type>) -> Result<Self, ()>
+ {
+ let _ = instant;
+
+ // TODO: Actually reschedule...
+ // &mut #app_path::#tq;
+
+ Err(())
+ }
+ }
+
#(#cfgs)*
/// Spawns the task after a set duration relative to the current time
///
@@ -281,7 +330,7 @@ pub fn codegen(
pub fn spawn_after<D>(
duration: D
#(,#args)*
- ) -> Result<(), #ty>
+ ) -> Result<SpawnHandle, #ty>
where D: rtic::time::duration::Duration + rtic::time::fixed_point::FixedPoint,
D::T: Into<<#app_path::#mono_type as rtic::time::Clock>::T>,
{
@@ -300,7 +349,7 @@ pub fn codegen(
pub fn spawn_at(
instant: rtic::time::Instant<#app_path::#mono_type>
#(,#args)*
- ) -> Result<(), #ty> {
+ ) -> Result<SpawnHandle, #ty> {
unsafe {
let input = #tupled;
if let Some(index) = rtic::export::interrupt::free(|_| #app_path::#fq.dequeue()) {
@@ -314,13 +363,17 @@ pub fn codegen(
.as_mut_ptr()
.write(instant);
- let nr = rtic::export::NotReady {
- instant,
- index,
- task: #app_path::#t::#name,
- };
+ rtic::export::interrupt::free(|_| {
+ let marker = #tq_marker;
+ let nr = rtic::export::NotReady {
+ instant,
+ index,
+ task: #app_path::#t::#name,
+ marker,
+ };
+
+ #tq_marker = #tq_marker.wrapping_add(1);
- rtic::export::interrupt::free(|_|
if let Some(mono) = #app_path::#m_ident.as_mut() {
#app_path::#tq.enqueue_unchecked(
nr,
@@ -331,9 +384,10 @@ pub fn codegen(
// We can only use the timer queue if `init` has returned, and it
// writes the `Some(monotonic)` we are accessing here.
core::hint::unreachable_unchecked()
- });
+ }
- Ok(())
+ Ok(SpawnHandle { marker })
+ })
} else {
Err(input)
}
diff --git a/macros/src/codegen/timer_queue.rs b/macros/src/codegen/timer_queue.rs
index 82d0ac98..33905516 100644
--- a/macros/src/codegen/timer_queue.rs
+++ b/macros/src/codegen/timer_queue.rs
@@ -9,6 +9,15 @@ pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec<TokenStrea
let mut items = vec![];
if !app.monotonics.is_empty() {
+ // Generate the marker counter used to track for `cancel` and `reschedule`
+ let tq_marker = util::mark_internal_ident(&util::timer_queue_marker_ident());
+ items.push(quote!(
+ // #[doc = #doc]
+ #[doc(hidden)]
+ #[allow(non_camel_case_types)]
+ static mut #tq_marker: u32 = 0;
+ ));
+
let t = util::schedule_t_ident();
// Enumeration of `schedule`-able tasks
@@ -32,7 +41,7 @@ pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec<TokenStrea
#[doc(hidden)]
#[allow(non_camel_case_types)]
#[derive(Clone, Copy)]
- enum #t {
+ pub enum #t {
#(#variants,)*
}
));
diff --git a/macros/src/codegen/util.rs b/macros/src/codegen/util.rs
index 6589f62d..9ccdbf78 100644
--- a/macros/src/codegen/util.rs
+++ b/macros/src/codegen/util.rs
@@ -89,6 +89,11 @@ pub fn interrupt_ident() -> Ident {
Ident::new("interrupt", span)
}
+pub fn timer_queue_marker_ident() -> Ident {
+ let span = Span::call_site();
+ Ident::new("TIMER_QUEUE_MARKER", span)
+}
+
/// Whether `name` is an exception with configurable priority
pub fn is_exception(name: &Ident) -> bool {
let s = name.to_string();
diff --git a/src/cyccnt.rs b/src/cyccnt.rs
deleted file mode 100644
index 8e07b001..00000000
--- a/src/cyccnt.rs
+++ /dev/null
@@ -1,221 +0,0 @@
-//! Data Watchpoint Trace (DWT) unit's CYCle CouNTer (CYCCNT)
-
-use core::{
- cmp::Ordering,
- convert::{Infallible, TryInto},
- fmt, ops,
-};
-
-use cortex_m::peripheral::DWT;
-
-use crate::Fraction;
-
-/// A measurement of the CYCCNT. Opaque and useful only with `Duration`
-///
-/// This data type is only available on ARMv7-M
-///
-/// # Correctness
-///
-/// Adding or subtracting a `Duration` of more than `(1 << 31)` cycles to an `Instant` effectively
-/// makes it "wrap around" and creates an incorrect value. This is also true if the operation is
-/// done in steps, e.g. `(instant + dur) + dur` where `dur` is `(1 << 30)` ticks.
-#[derive(Clone, Copy, Eq, PartialEq)]
-pub struct Instant {
- inner: i32,
-}
-
-impl Instant {
- /// Returns an instant corresponding to "now"
- ///
- /// *HEADS UP* this function can, and will, return nonsensical values if called within `init`.
- /// Only use it in `idle` and tasks. In `init`, use the `init::Context.start` field, or the
- /// `CYCCNT::zero` function, instead of this function
- pub fn now() -> Self {
- Instant {
- inner: DWT::get_cycle_count() as i32,
- }
- }
-
- /// Returns the amount of time elapsed since this instant was created.
- pub fn elapsed(&self) -> Duration {
- let diff = Instant::now().inner.wrapping_sub(self.inner);
- assert!(diff >= 0, "instant now is earlier than self");
- Duration { inner: diff as u32 }
- }
-
- /// Returns the amount of time elapsed from another instant to this one.
- pub fn duration_since(&self, earlier: Instant) -> Duration {
- let diff = self.inner.wrapping_sub(earlier.inner);
- assert!(diff >= 0, "second instant is later than self");
- Duration { inner: diff as u32 }
- }
-}
-
-impl fmt::Debug for Instant {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_tuple("Instant")
- .field(&(self.inner as u32))
- .finish()
- }
-}
-
-impl ops::AddAssign<Duration> for Instant {
- fn add_assign(&mut self, dur: Duration) {
- // NOTE this is a debug assertion because there's no foolproof way to detect a wrap around;
- // the user may write `(instant + dur) + dur` where `dur` is `(1<<31)-1` ticks.
- debug_assert!(dur.inner < (1 << 31));
- self.inner = self.inner.wrapping_add(dur.inner as i32);
- }
-}
-
-impl ops::Add<Duration> for Instant {
- type Output = Self;
-
- fn add(mut self, dur: Duration) -> Self {
- self += dur;
- self
- }
-}
-
-impl ops::SubAssign<Duration> for Instant {
- fn sub_assign(&mut self, dur: Duration) {
- // NOTE see the NOTE in `<Instant as AddAssign<Duration>>::add_assign`
- debug_assert!(dur.inner < (1 << 31));
- self.inner = self.inner.wrapping_sub(dur.inner as i32);
- }
-}
-
-impl ops::Sub<Duration> for Instant {
- type Output = Self;
-
- fn sub(mut self, dur: Duration) -> Self {
- self -= dur;
- self
- }
-}
-
-impl ops::Sub<Instant> for Instant {
- type Output = Duration;
-
- fn sub(self, other: Instant) -> Duration {
- self.duration_since(other)
- }
-}
-
-impl Ord for Instant {
- fn cmp(&self, rhs: &Self) -> Ordering {
- self.inner.wrapping_sub(rhs.inner).cmp(&0)
- }
-}
-
-impl PartialOrd for Instant {
- fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
- Some(self.cmp(rhs))
- }
-}
-
-/// A `Duration` type to represent a span of time.
-///
-/// This data type is only available on ARMv7-M
-///
-/// # Correctness
-///
-/// This type is *not* appropriate for representing time spans in the order of, or larger than,
-/// seconds because it can hold a maximum of `(1 << 31)` "ticks" where each tick is the inverse of
-/// the CPU frequency, which usually is dozens of MHz.
-#[derive(Clone, Copy, Default, Eq, Ord, PartialEq, PartialOrd)]
-pub struct Duration {
- inner: u32,
-}
-
-impl Duration {
- /// Creates a new `Duration` from the specified number of clock cycles
- pub fn from_cycles(cycles: u32) -> Self {
- Duration { inner: cycles }
- }
-
- /// Returns the total number of clock cycles contained by this `Duration`
- pub fn as_cycles(&self) -> u32 {
- self.inner
- }
-}
-
-impl TryInto<u32> for Duration {
- type Error = Infallible;
-
- fn try_into(self) -> Result<u32, Infallible> {
- Ok(self.as_cycles())
- }
-}
-
-impl ops::AddAssign for Duration {
- fn add_assign(&mut self, dur: Duration) {
- self.inner += dur.inner;
- }
-}
-
-impl ops::Add<Duration> for Duration {
- type Output = Self;
-
- fn add(self, other: Self) -> Self {
- Duration {
- inner: self.inner + other.inner,
- }
- }
-}
-
-impl ops::SubAssign for Duration {
- fn sub_assign(&mut self, rhs: Duration) {
- self.inner -= rhs.inner;
- }
-}
-
-impl ops::Sub<Duration> for Duration {
- type Output = Self;
-
- fn sub(self, rhs: Self) -> Self {
- Duration {
- inner: self.inner - rhs.inner,
- }
- }
-}
-
-/// Adds the `cycles` method to the `u32` type
-///
-/// This trait is only available on ARMv7-M
-pub trait U32Ext {
- /// Converts the `u32` value into clock cycles
- fn cycles(self) -> Duration;
-}
-
-impl U32Ext for u32 {
- fn cycles(self) -> Duration {
- Duration { inner: self }
- }
-}
-
-/// Implementation of the `Monotonic` trait based on CYCle CouNTer
-pub struct CYCCNT;
-
-impl crate::Monotonic for CYCCNT {
- type Instant = Instant;
-
- fn ratio() -> Fraction {
- Fraction {
- numerator: 1,
- denominator: 1,
- }
- }
-
- unsafe fn reset() {
- (0xE0001004 as *mut u32).write_volatile(0)
- }
-
- fn now() -> Instant {
- Instant::now()
- }
-
- fn zero() -> Instant {
- Instant { inner: 0 }
- }
-}
diff --git a/src/tq.rs b/src/tq.rs
index 063bbd8e..f341d8cc 100644
--- a/src/tq.rs
+++ b/src/tq.rs
@@ -5,6 +5,15 @@ use crate::{
use core::cmp::Ordering;
use heapless::{binary_heap::Min, ArrayLength, BinaryHeap};
+#[inline]
+fn unwrapper<T, E>(val: Result<T, E>) -> T {
+ if let Ok(v) = val {
+ v
+ } else {
+ unreachable!("Your monotonic is not infallible")
+ }
+}
+
pub struct TimerQueue<Mono, Task, N>(pub BinaryHeap<NotReady<Mono, Task>, N, Min>)
where
Mono: Monotonic,
@@ -66,15 +75,6 @@ where
self.0.is_empty()
}
- #[inline]
- fn unwrapper<T, E>(val: Result<T, E>) -> T {
- if let Ok(v) = val {
- v
- } else {
- unreachable!("Your monotonic is not infallible")
- }
- }
-
/// Dequeue a task from the TimerQueue
#[inline]
pub fn dequeue<F>(&mut self, disable_interrupt: F, mono: &mut Mono) -> Option<(Task, u8)>
@@ -84,7 +84,7 @@ where
mono.clear_compare_flag();
if let Some(instant) = self.0.peek().map(|p| p.instant) {
- if instant <= Self::unwrapper(Clock::try_now(mono)) {
+ if instant <= unwrapper(Clock::try_now(mono)) {
// task became ready
let nr = unsafe { self.0.pop_unchecked() };
@@ -97,7 +97,7 @@ where
// dequeue. If the monotonic is fast enough it can happen that from the
// read of now to the set of the compare, the time can overflow. This is to
// guard against this.
- if instant <= Self::unwrapper(Clock::try_now(mono)) {
+ if instant <= unwrapper(Clock::try_now(mono)) {
let nr = unsafe { self.0.pop_unchecked() };
Some((nr.task, nr.index))
@@ -125,6 +125,7 @@ where
pub index: u8,
pub instant: Instant<Mono>,
pub task: Task,
+ pub marker: u32,
}
impl<Mono, Task> Eq for NotReady<Mono, Task>