From a14d24007ae6391121dc493782b900d6edb7d992 Mon Sep 17 00:00:00 2001 From: datdenkikniet Date: Sat, 22 Apr 2023 22:47:07 +0200 Subject: Update delay.md file to be a bit easier to read, and add spoiler tags for the walls of code --- book/en/src/by-example/delay.md | 58 +++++++++++++++++++++++++---------------- 1 file changed, 36 insertions(+), 22 deletions(-) (limited to 'book/en/src/by-example/delay.md') diff --git a/book/en/src/by-example/delay.md b/book/en/src/by-example/delay.md index f286363..893ead9 100644 --- a/book/en/src/by-example/delay.md +++ b/book/en/src/by-example/delay.md @@ -1,18 +1,20 @@ # Tasks with delay -A convenient way to express *miniminal* timing requirements is by means of delaying progression. +A convenient way to express miniminal timing requirements is by delaying progression. -This can be achieved by instantiating a monotonic timer: +This can be achieved by instantiating a monotonic timer (for implementations, see [`rtic-monotonics`]): + +[`rtic-monotonics`]: https://github.com/rtic-rs/rtic/tree/master/rtic-monotonics +[`rtic-time`]: https://github.com/rtic-rs/rtic/tree/master/rtic-time ``` rust ... -rtic_monotonics::make_systick_handler!(); - #[init] fn init(cx: init::Context) -> (Shared, Local) { hprintln!("init"); - Systick::start(cx.core.SYST, 12_000_000); + let token = rtic_monotonics::create_systick_token!(); + Systick::start(cx.core.SYST, 12_000_000, token); ... ``` @@ -28,11 +30,14 @@ async fn foo(_cx: foo::Context) { ``` -Technically, the timer queue is implemented as a list based priority queue, where list-nodes are statically allocated as part of the underlying task `Future`. Thus, the timer queue is infallible at run-time (its size and allocation is determined at compile time). + + +Technically, the timer queue is implemented as a list based priority queue, where list-nodes are statically allocated as part of the underlying task `Future`. Thus, the timer queue is infallible at run-time (its size and allocation are determined at compile time). Similarly the channels implementation, the timer-queue implementation relies on a global *Critical Section* (CS) for race protection. For the examples a CS implementation is provided by adding `--features test-critical-section` to the build options. -For a complete example: +
+A complete example ``` rust {{#include ../../../../rtic/examples/async-delay.rs}} @@ -46,11 +51,15 @@ $ cargo run --target thumbv7m-none-eabi --example async-delay --features test-cr {{#include ../../../../rtic/ci/expected/async-delay.run}} ``` +
+ ## Timeout -Rust `Futures` (underlying Rust `async`/`await`) are composable. This makes it possible to `select` in between `Futures` that have completed. +Rust [`Future`]s (underlying Rust `async`/`await`) are composable. This makes it possible to `select` in between `Futures` that have completed. -A common use case is transactions with associated timeout. In the examples shown below, we introduce a fake HAL device which performs some transaction. We have modelled the time it takes based on the input parameter (`n`) as `350ms + n * 100ms)`. +[`Future`]: https://doc.rust-lang.org/std/future/trait.Future.html + +A common use case is transactions with an associated timeout. In the examples shown below, we introduce a fake HAL device that performs some transaction. We have modelled the time it takes based on the input parameter (`n`) as `350ms + n * 100ms`. Using the `select_biased` macro from the `futures` crate it may look like this: @@ -62,19 +71,13 @@ select_biased! { } ``` -Assuming the `hal_get` will take 450ms to finish, a short timeout of 200ms will expire. +Assuming the `hal_get` will take 450ms to finish, a short timeout of 200ms will expire before `hal_get` can complete. -``` rust -// Call hal with long relative timeout using `select_biased` -select_biased! { - v = hal_get(1).fuse() => hprintln!("hal returned {}", v), // hal finish first - _ = Systick::delay(1000.millis()).fuse() => hprintln!("timeout", ), -} -``` +Extending the timeout to 1000ms would cause `hal_get` will to complete first. -By extending the timeout to 1000ms, the `hal_get` will finish first. +Using `select_biased` any number of futures can be combined, so its very powerful. However, as the timeout pattern is frequently used, more ergonomic support is baked into RTIC, provided by the [`rtic-monotonics`] and [`rtic-time`] crates. -Using `select_biased` any number of futures can be combined, so its very powerful. However, as the timeout pattern is frequently used, it is directly supported by the RTIC [rtc-monotonics] and [rtic-time] crates. The second example from above using `timeout_after`: +Rewriting the second example from above using `timeout_after` gives: ``` rust // Call hal with long relative timeout using monotonic `timeout_after` @@ -84,7 +87,7 @@ match Systick::timeout_after(1000.millis(), hal_get(1)).await { } ``` -In cases you want exact control over time without drift. For this purpose we can use exact points in time using `Instance`, and spans of time using `Duration`. Operations on the `Instance` and `Duration` types are given by the [fugit] crate. +In cases where you want exact control over time without drift we can use exact points in time using `Instant`, and spans of time using `Duration`. Operations on the `Instant` and `Duration` types come from the [`fugit`] crate. [fugit]: https://crates.io/crates/fugit @@ -109,10 +112,20 @@ for n in 0..3 { } ``` -`instant = Systick::now()` gives the baseline (i.e., the absolute current point in time). We want to call `hal_get` after 1000ms relative to this absolute point in time. This can be accomplished by `Systick::delay_until(instant).await;`. We define the absolute point in time for the `timeout`, and call `Systick::timeout_at(timeout, hal_get(n)).await`. For the first loop iteration `n == 0`, and the `hal_get` will take 350ms (and finishes before the timeout). For the second iteration `n == 1`, and `hal_get` will take 450ms (and again succeeds to finish before the timeout). For the third iteration `n == 2` (`hal_get` will take 5500ms to finish). In this case we will run into a timeout. +`let mut instant = Systick::now()` sets the starting time of execution. + +We want to call `hal_get` after 1000ms relative to this starting time. This can be accomplished by using `Systick::delay_until(instant).await`. + +Then, we define a point in time called `timeout`, and call `Systick::timeout_at(timeout, hal_get(n)).await`. + +For the first iteration of the loop, with `n == 0`, the `hal_get` will take 350ms (and finishes before the timeout). + +For the second iteration, with `n == 1`, the `hal_get` will take 450ms (and again succeeds to finish before the timeout). +For the third iteration, with `n == 2`, `hal_get` will take 550ms to finish, in which case we will run into a timeout. -The complete example: +
+A complete example ``` rust {{#include ../../../../rtic/examples/async-timeout.rs}} @@ -125,3 +138,4 @@ $ cargo run --target thumbv7m-none-eabi --example async-timeout --features test- ``` console {{#include ../../../../rtic/ci/expected/async-timeout.run}} ``` +
-- cgit v1.2.3 From 0807aa548c865d12746ce17aa1c17f7968b139a9 Mon Sep 17 00:00:00 2001 From: datdenkikniet Date: Sun, 23 Apr 2023 15:33:29 +0200 Subject: Include this code as blocks instead --- book/en/src/by-example/delay.md | 44 ++++++++--------------------------------- 1 file changed, 8 insertions(+), 36 deletions(-) (limited to 'book/en/src/by-example/delay.md') diff --git a/book/en/src/by-example/delay.md b/book/en/src/by-example/delay.md index 893ead9..479fd42 100644 --- a/book/en/src/by-example/delay.md +++ b/book/en/src/by-example/delay.md @@ -9,13 +9,8 @@ This can be achieved by instantiating a monotonic timer (for implementations, se ``` rust ... -#[init] -fn init(cx: init::Context) -> (Shared, Local) { - hprintln!("init"); - - let token = rtic_monotonics::create_systick_token!(); - Systick::start(cx.core.SYST, 12_000_000, token); - ... +{{#include ../../../../rtic/examples/async-timeout.rs:init}} + ... ``` A *software* task can `await` the delay to expire: @@ -63,12 +58,8 @@ A common use case is transactions with an associated timeout. In the examples sh Using the `select_biased` macro from the `futures` crate it may look like this: -``` rust -// Call hal with short relative timeout using `select_biased` -select_biased! { - v = hal_get(1).fuse() => hprintln!("hal returned {}", v), - _ = Systick::delay(200.millis()).fuse() => hprintln!("timeout", ), // this will finish first -} +``` rust,noplayground +{{#include ../../../../rtic/examples/async-timeout.rs:select_biased}} ``` Assuming the `hal_get` will take 450ms to finish, a short timeout of 200ms will expire before `hal_get` can complete. @@ -80,11 +71,7 @@ Using `select_biased` any number of futures can be combined, so its very powerfu Rewriting the second example from above using `timeout_after` gives: ``` rust -// Call hal with long relative timeout using monotonic `timeout_after` -match Systick::timeout_after(1000.millis(), hal_get(1)).await { - Ok(v) => hprintln!("hal returned {}", v), - _ => hprintln!("timeout"), -} +{{#include ../../../../rtic/examples/async-timeout.rs:timeout_at_basic}} ``` In cases where you want exact control over time without drift we can use exact points in time using `Instant`, and spans of time using `Duration`. Operations on the `Instant` and `Duration` types come from the [`fugit`] crate. @@ -92,24 +79,9 @@ In cases where you want exact control over time without drift we can use exact p [fugit]: https://crates.io/crates/fugit ``` rust -// get the current time instance -let mut instant = Systick::now(); - -// do this 3 times -for n in 0..3 { - // absolute point in time without drift - instant += 1000.millis(); - Systick::delay_until(instant).await; - - // absolute point it time for timeout - let timeout = instant + 500.millis(); - hprintln!("now is {:?}, timeout at {:?}", Systick::now(), timeout); - - match Systick::timeout_at(timeout, hal_get(n)).await { - Ok(v) => hprintln!("hal returned {} at time {:?}", v, Systick::now()), - _ => hprintln!("timeout"), - } -} + +{{#include ../../../../rtic/examples/async-timeout.rs:timeout_at}} + ``` `let mut instant = Systick::now()` sets the starting time of execution. -- cgit v1.2.3 From a66540efa014b3716d252612bfc7f8f17ed765c4 Mon Sep 17 00:00:00 2001 From: datdenkikniet Date: Sun, 23 Apr 2023 15:33:56 +0200 Subject: Disable the playground on all of these --- book/en/src/by-example/delay.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'book/en/src/by-example/delay.md') diff --git a/book/en/src/by-example/delay.md b/book/en/src/by-example/delay.md index 479fd42..a6ad0e0 100644 --- a/book/en/src/by-example/delay.md +++ b/book/en/src/by-example/delay.md @@ -7,7 +7,7 @@ This can be achieved by instantiating a monotonic timer (for implementations, se [`rtic-monotonics`]: https://github.com/rtic-rs/rtic/tree/master/rtic-monotonics [`rtic-time`]: https://github.com/rtic-rs/rtic/tree/master/rtic-time -``` rust +``` rust,noplayground ... {{#include ../../../../rtic/examples/async-timeout.rs:init}} ... @@ -15,7 +15,7 @@ This can be achieved by instantiating a monotonic timer (for implementations, se A *software* task can `await` the delay to expire: -``` rust +``` rust,noplayground #[task] async fn foo(_cx: foo::Context) { ... @@ -34,7 +34,7 @@ Similarly the channels implementation, the timer-queue implementation relies on
A complete example -``` rust +``` rust,noplayground {{#include ../../../../rtic/examples/async-delay.rs}} ``` @@ -58,7 +58,7 @@ A common use case is transactions with an associated timeout. In the examples sh Using the `select_biased` macro from the `futures` crate it may look like this: -``` rust,noplayground +``` rust,noplayground,noplayground {{#include ../../../../rtic/examples/async-timeout.rs:select_biased}} ``` @@ -70,7 +70,7 @@ Using `select_biased` any number of futures can be combined, so its very powerfu Rewriting the second example from above using `timeout_after` gives: -``` rust +``` rust,noplayground {{#include ../../../../rtic/examples/async-timeout.rs:timeout_at_basic}} ``` @@ -78,7 +78,7 @@ In cases where you want exact control over time without drift we can use exact p [fugit]: https://crates.io/crates/fugit -``` rust +``` rust,noplayground {{#include ../../../../rtic/examples/async-timeout.rs:timeout_at}} @@ -99,7 +99,7 @@ For the third iteration, with `n == 2`, `hal_get` will take 550ms to finish, in
A complete example -``` rust +``` rust,noplayground {{#include ../../../../rtic/examples/async-timeout.rs}} ``` -- cgit v1.2.3 From 311291b95adbd24ecd037f5e555e4c30138f4339 Mon Sep 17 00:00:00 2001 From: datdenkikniet Date: Sat, 20 May 2023 12:02:51 +0200 Subject: Make Monotonic implementation more obvious --- book/en/src/by-example/delay.md | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'book/en/src/by-example/delay.md') diff --git a/book/en/src/by-example/delay.md b/book/en/src/by-example/delay.md index a6ad0e0..09091fc 100644 --- a/book/en/src/by-example/delay.md +++ b/book/en/src/by-example/delay.md @@ -6,6 +6,8 @@ This can be achieved by instantiating a monotonic timer (for implementations, se [`rtic-monotonics`]: https://github.com/rtic-rs/rtic/tree/master/rtic-monotonics [`rtic-time`]: https://github.com/rtic-rs/rtic/tree/master/rtic-time +[`Monotonic`]: https://docs.rs/rtic-time/latest/rtic_time/trait.Monotonic.html +[Implementing a `Monotonic`]: ../../monotonic_impl.md ``` rust,noplayground ... @@ -25,12 +27,6 @@ async fn foo(_cx: foo::Context) { ``` - - -Technically, the timer queue is implemented as a list based priority queue, where list-nodes are statically allocated as part of the underlying task `Future`. Thus, the timer queue is infallible at run-time (its size and allocation are determined at compile time). - -Similarly the channels implementation, the timer-queue implementation relies on a global *Critical Section* (CS) for race protection. For the examples a CS implementation is provided by adding `--features test-critical-section` to the build options. -
A complete example @@ -48,6 +44,9 @@ $ cargo run --target thumbv7m-none-eabi --example async-delay --features test-cr
+> Interested in contributing new implementations of [`Monotonic`], or more information about the inner workings of monotonics? +> Check out the [Implementing a `Monotonic`] chapter! + ## Timeout Rust [`Future`]s (underlying Rust `async`/`await`) are composable. This makes it possible to `select` in between `Futures` that have completed. -- cgit v1.2.3 From 9fa073f7936782bddf5d02b7b1949032e84de1bd Mon Sep 17 00:00:00 2001 From: datdenkikniet Date: Sat, 20 May 2023 13:08:44 +0200 Subject: Fix link --- book/en/src/by-example/delay.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'book/en/src/by-example/delay.md') diff --git a/book/en/src/by-example/delay.md b/book/en/src/by-example/delay.md index 09091fc..81f855f 100644 --- a/book/en/src/by-example/delay.md +++ b/book/en/src/by-example/delay.md @@ -7,7 +7,7 @@ This can be achieved by instantiating a monotonic timer (for implementations, se [`rtic-monotonics`]: https://github.com/rtic-rs/rtic/tree/master/rtic-monotonics [`rtic-time`]: https://github.com/rtic-rs/rtic/tree/master/rtic-time [`Monotonic`]: https://docs.rs/rtic-time/latest/rtic_time/trait.Monotonic.html -[Implementing a `Monotonic`]: ../../monotonic_impl.md +[Implementing a `Monotonic`]: ../monotonic_impl.md ``` rust,noplayground ... -- cgit v1.2.3