From c391ea71f7cd5271612bea42a19a529d2c042a4e Mon Sep 17 00:00:00 2001
From: Per Lindgren <per.lindgren@ltu.se>
Date: Sun, 7 Mar 2021 15:44:02 +0100
Subject: [PATCH] updated rtic_bare7

---
 examples/rtic_bare7.rs | 111 +++++++++++++++++++++++++++++++++--------
 1 file changed, 90 insertions(+), 21 deletions(-)

diff --git a/examples/rtic_bare7.rs b/examples/rtic_bare7.rs
index 6813067..fc08f00 100644
--- a/examples/rtic_bare7.rs
+++ b/examples/rtic_bare7.rs
@@ -1,15 +1,26 @@
 //! rtic_bare7.rs
 //!
-//! Clocking
+//! HAL OutputPin abstractions
 //!
 //! What it covers:
 //! - using embedded hal, and the OutputPin abstraction
 
+#![no_main]
+#![no_std]
+
 use panic_rtt_target as _;
 use rtic::cyccnt::{Instant, U32Ext as _};
 use rtt_target::{rprintln, rtt_init_print};
 use stm32f4xx_hal::stm32;
 
+use stm32f4xx_hal::{
+    gpio::{gpioa::PA5, Output, PushPull},
+    prelude::*,
+};
+
+use core::convert::Infallible;
+use embedded_hal::digital::v2::{OutputPin, ToggleableOutputPin};
+
 const OFFSET: u32 = 8_000_000;
 
 #[rtic::app(device = stm32f4xx_hal::stm32, monotonic = rtic::cyccnt::CYCCNT, peripherals = true)]
@@ -17,6 +28,7 @@ const APP: () = {
     struct Resources {
         // late resources
         GPIOA: stm32::GPIOA,
+        // led: PA5<Output<PushPull>>,
     }
     #[init(schedule = [toggle])]
     fn init(cx: init::Context) -> init::LateResources {
@@ -76,23 +88,38 @@ const APP: () = {
     }
 };
 
+fn _toggle_generic(led: &mut dyn OutputPin<Error = Infallible>, toggle: &mut bool) {
+    if *toggle {
+        led.set_high().ok();
+    } else {
+        led.set_low().ok();
+    }
+
+    *toggle = !*toggle;
+}
+
+fn _toggleable_generic(led: &mut dyn ToggleableOutputPin<Error = Infallible>) {
+    led.toggle().ok();
+}
+
 // 1. In this example you will use RTT.
 //
 //    > cargo run --example rtic_bare7
 //
-//    Now look at the documentation for `embedded_hal::digital::v2::OutputPin`.
+//    Look in the generated documentation for `set_high`/`set_low`.
 //    (You created documentation for your dependencies in previous exercise
 //    so you can just search (press `S`) for `OutputPin`).
+//    You will find that these methods are implemented for `Output` pins.
 //
-//    You see that the OutputPin trait defines `set_low`/`set_high` functions.
-//    Your task is to alter the code to use the `set_low`/`set_high` API.
+//    Now change your code to use these functions instead of the low-level GPIO API.
 //
 //    HINTS:
 //    - A GPIOx peripheral can be `split` into individual PINs Px0..Px15).
 //    - A Pxy, can be turned into an `Output` by `into_push_pull_output`.
 //    - You may optionally set other pin properties as well (such as `speed`).
 //    - An `Output` pin provides `set_low`/`set_high`
-//      (and implements the `OutputPin` trait in embedded-hal).
+//    - Instead of passing `GPIO` resource to the `toggle` task pass the
+//      `led: PA5<Output<PushPull>>` resource instead.
 //
 //    Comment your code to explain the steps taken.
 //
@@ -101,29 +128,71 @@ const APP: () = {
 //
 //    Commit your code (bare7_1)
 //
-// 2. Optional
+// 2. Further generalizations:
 //
-//    Use the `toggle` function instead to further simply your code.
+//    Now look at the documentation for `embedded_hal::digital::v2::OutputPin`.
+//
+//    You see that the OutputPin trait defines `set_low`/`set_high` functions.
+//    Your task is to alter the code to use the `set_low`/`set_high` API.
 //
-//    Notice:
-//    The `ToggleableOutputPin` abstraction requires `embedded-hal`
-//    to compiled with the `unproven` feature.
+//    The function `_toggle_generic` is generic to any object that
+//    implements the `OutputPin<Error = Infallible>` trait.
 //
-//    The `embedded-hal` traits is mostly used to write drivers
-//    that is hardware agnostic (and thus cross platform).
+//    The type parameter `Error = Infallible` indicates that
+//    there are no errors to be expected (hence infallible).
 //
-//    However:
-//    In our case we can use `toggle` directly as implemented by the `stm32f4xx-hal`.
+//    Our `PA5<Output<PushPull>>` (led) is such an implementor.
+//    Additionally, `_toggle_generic` takes a mutable reference
+//    `toggle: &mut bool`, so you need to pass your `TOGGLE` variable.
 //
-//    Confirm that your implementation correctly toggles the LED.
+//    As you see, `TOGGLE` holds the "state", switching between
+//    `true` and `false` (to make your led blink).
 //
-//    Which one do you prefer and why (what problem does it solve)?
+//    Change your code into using the `_toggle_generic` function.
+//    (You may rename it to `toggle_generic` if wished.)
+//
+//    Confirm that your implementation correctly toggles the LED as in
+//    previous exercise.
+//
+//    Commit your code (bare7_2)
+//
+// 3. What about the state?
+//
+//    In your code `TOGGLE` holds the "state". However, the underlying
+//    hardware ALSO holds the state (if the corresponding bit is set/cleared). 
+//
+//    What if we can leverage that, and guess what we can!!!!
+//
+//    Look at the documentation for `embedded_hal::digital::v2::ToggleableOutputPin`,
+//    and the implementation of:
+//
+//    fn _toggleable_generic(led: &mut dyn ToggleableOutputPin<Error = Infallible>) {
+//      led.toggle().ok();
+//    }
+//
+//    The latter does not take any state variable, instead it directly `toggle()`
+//    the `ToggleableOutputPin`.
+//
+//    Now alter your code to leverage on the `_toggleable_generic` function.
+//    (You should be able to remove the `TOGGLE` state variable altogether.)
+//
+//    Confirm that your implementation correctly toggles the LED as in
+//    previous exercise.
 //
-//    ** your answer here **
+//    Commit your code (bare7_3)
 //
-//    Commit your answer (bare7_2)
+// 4. Discussion:
+//   
+//    In this exercise you have gone from a very hardware specific implementation,
+//    to leveraging abstractions (batteries included).
 //
-// 3. Discussion
+//    Your final code amounts to "configuration" rather than "coding".
 //
-//    In this exercise you have learned more on navigating the generated documentation
-//    and to use abstractions to simplify and generalize your code.
+//    This reduces the risk of errors (as you let the libraries do the heavy lifting).
+// 
+//    This also improves code-re use. E.g., if you were to do something less
+//    trivial then merely toggling you can do that in a generic manner,
+//    breaking out functionality into "components" re-usable in other applications.
+//      
+//    Of course the example is trivial, you don't gain much here, but the principle
+//    is the same behind drivers for USART communication, USB, PMW3389 etc.
-- 
GitLab