From 032a54c77f124922e4f73b5de2c954c8c0931079 Mon Sep 17 00:00:00 2001
From: Per <Per Lindgren>
Date: Fri, 18 Jan 2019 15:47:36 +0100
Subject: [PATCH] marcus

---
 .vscode/launch.json     |  34 +++-
 .vscode/tasks.json      |  24 +++
 Cargo.toml              |   3 +-
 examples/bare4.rs       |   1 -
 examples/bare5.rs       |   1 -
 examples/bare7.rs       |   1 -
 examples/equivalence.rs | 231 ++++++++++++++++++++++++
 examples/marcus.rs      | 388 ++++++++++++++++++++++++++++++++++++++++
 8 files changed, 678 insertions(+), 5 deletions(-)
 create mode 100644 examples/equivalence.rs
 create mode 100644 examples/marcus.rs

diff --git a/.vscode/launch.json b/.vscode/launch.json
index 8a61829..6ff145f 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -641,7 +641,7 @@
             "type": "cortex-debug",
             "request": "launch",
             "servertype": "openocd",
-            "name": "bare10 (reselase)",
+            "name": "bare10 (release)",
             "preLaunchTask": "cargo build --example bare10 --release",
             "executable": "./target/thumbv7em-none-eabihf/release/examples/bare10",
             "configFiles": [
@@ -701,5 +701,37 @@
             "svdFile": "STM32F413.svd",
             "cwd": "${workspaceRoot}"
         },
+        {
+            "type": "cortex-debug",
+            "request": "launch",
+            "servertype": "openocd",
+            "name": "marcus (release)",
+            "preLaunchTask": "cargo build --example marcus --release",
+            "executable": "./target/thumbv7em-none-eabihf/release/examples/marcus",
+            "configFiles": [
+                "interface/stlink.cfg",
+                "target/stm32f4x.cfg"
+            ],
+            "swoConfig": {
+                "enabled": true,
+                "cpuFrequency": 16000000,
+                "swoFrequency": 2000000,
+                "source": "probe",
+                "decoders": [
+                    {
+                        "type": "console",
+                        "label": "ITM0",
+                        "port": 0
+                    },
+                    {
+                        "type": "console",
+                        "label": "ITM1",
+                        "port": 1
+                    }
+                ]
+            },
+            "svdFile": "STM32F413.svd",
+            "cwd": "${workspaceRoot}"
+        },
     ]
 }
\ No newline at end of file
diff --git a/.vscode/tasks.json b/.vscode/tasks.json
index bf7899a..69ff234 100644
--- a/.vscode/tasks.json
+++ b/.vscode/tasks.json
@@ -303,5 +303,29 @@
                 "isDefault": true
             }
         },
+        {
+            "type": "shell",
+            "label": "cargo build --example marcus --release",
+            "command": "cargo build --example marcus --release --features \"hal rtfm-tq\"",
+            "problemMatcher": [
+                "$rustc"
+            ],
+            "group": {
+                "kind": "build",
+                "isDefault": true
+            }
+        },
+        {
+            "type": "shell",
+            "label": "cargo build --example equivalence --release",
+            "command": "cargo build --example equivalence --release --features \"hal rtfm-tq\"",
+            "problemMatcher": [
+                "$rustc"
+            ],
+            "group": {
+                "kind": "build",
+                "isDefault": true
+            }
+        },
     ]
 }
\ No newline at end of file
diff --git a/Cargo.toml b/Cargo.toml
index a6f3ab5..030ea8f 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -44,9 +44,10 @@ features = ["stm32f413", "rt"]
 optional = true
 
 [features]
+pac = ["stm32f4"]
 hal = ["stm32f4", "stm32f4xx-hal"]
 rtfm = ["cortex-m-rtfm"]
-pac = ["stm32f4"]
+rtfm-tq = ["cortex-m-rtfm/timer-queue"]
 
 # this lets you use `cargo fix`!
 [[bin]]
diff --git a/examples/bare4.rs b/examples/bare4.rs
index b5f1d5a..5b7184b 100644
--- a/examples/bare4.rs
+++ b/examples/bare4.rs
@@ -8,7 +8,6 @@
 //! - busses and clocking
 //! - gpio
 
-#![feature(uniform_paths)] // requires nightly
 #![no_std]
 #![no_main]
 
diff --git a/examples/bare5.rs b/examples/bare5.rs
index 3600a68..514f5a1 100644
--- a/examples/bare5.rs
+++ b/examples/bare5.rs
@@ -6,7 +6,6 @@
 //! - abstractions in Rust
 //! - structs and implementations
 
-#![feature(uniform_paths)] // requires nightly
 #![no_std]
 #![no_main]
 
diff --git a/examples/bare7.rs b/examples/bare7.rs
index f438100..3de0f05 100644
--- a/examples/bare7.rs
+++ b/examples/bare7.rs
@@ -5,7 +5,6 @@
 //! - working with the svd2rust API
 
 #![deny(unsafe_code)]
-#![feature(uniform_paths)]
 #![deny(warnings)]
 #![no_main]
 #![no_std]
diff --git a/examples/equivalence.rs b/examples/equivalence.rs
new file mode 100644
index 0000000..f629b00
--- /dev/null
+++ b/examples/equivalence.rs
@@ -0,0 +1,231 @@
+//! The RTFM framework
+//!
+//! What it covers:
+//! - Priority based scheduling
+//! - Message passing
+
+#![no_main]
+#![no_std]
+
+extern crate panic_halt;
+
+use cortex_m::{asm, iprintln};
+
+extern crate stm32f4xx_hal as hal;
+// use stm32f4::stm32f413::GPIOA;
+use crate::hal::prelude::*;
+use crate::hal::serial::{self, config::Config, Rx, Serial, Tx};
+use hal::{gpio::Alternate, gpio::AF0, stm32::ITM};
+
+// use heapless::consts::*;
+// use heapless::spsc::{Consumer, Producer, Queue};
+
+use nb::block;
+
+use rtfm::{app, Instant};
+
+// Our error type
+#[derive(Debug)]
+pub enum Error {
+    RingBufferOverflow,
+    UsartSendOverflow,
+    UsartReceiveOverflow,
+}
+
+#[derive(Debug)]
+pub enum Event {
+    Timout,
+    ChannelA,
+    ChannelB,
+}
+
+#[derive(Debug, Copy, Clone)]
+pub struct Data {
+    a: bool,
+    b: bool,
+    event_counter: u32,
+    out: bool,
+}
+
+const TIMEOUT: u32 = 16_000_000;
+
+#[app(device = hal::stm32)]
+const APP: () = {
+    // Late resources
+    static mut TX: Tx<hal::stm32::USART2> = ();
+    static mut RX: Rx<hal::stm32::USART2> = ();
+    static mut ITM: ITM = ();
+    static mut LED: hal::gpio::gpioa::PA5<Alternate<AF0>> = ();
+
+    // app resources
+    static mut DATA: Data = Data {
+        a: false,
+        b: false,
+        event_counter: 0,
+        out: false,
+    };
+
+    // init runs in an interrupt free section>
+    #[init]
+    fn init() {
+        let stim = &mut core.ITM.stim[0];
+        iprintln!(stim, "start");
+
+        // power on GPIOA, RM0368 6.3.11
+        device.RCC.ahb1enr.modify(|_, w| w.gpioaen().set_bit());
+        // configure PA5 as output, RM0368 8.4.1
+        device.GPIOA.moder.modify(|_, w| w.moder5().bits(1));
+
+        let rcc = device.RCC.constrain();
+
+        // 16 MHz (default, all clocks)
+        let clocks = rcc.cfgr.freeze();
+
+        let gpioa = device.GPIOA.split();
+
+        let tx = gpioa.pa2.into_alternate_af7();
+        let rx = gpioa.pa3.into_alternate_af7();
+        let led = gpioa.pa5.into_alternate_af0();
+
+        let mut serial = Serial::usart2(
+            device.USART2,
+            (tx, rx),
+            Config::default().baudrate(115_200.bps()),
+            clocks,
+        )
+        .unwrap();
+
+        // generate interrupt on Rxne
+        serial.listen(serial::Event::Rxne);
+        // Separate out the sender and receiver of the serial port
+        let (tx, rx) = serial.split();
+
+        // pass on late resources
+        LED = led;
+
+        // Our split serial
+        TX = tx;
+        RX = rx;
+
+        // For debugging
+        ITM = core.ITM;
+    }
+
+    // idle may be interrupted by other interrupt/tasks in the system
+    // #[idle(resources = [RX, TX, ITM])]
+    #[idle]
+    fn idle() -> ! {
+        loop {
+            asm::wfi();
+        }
+    }
+
+    #[task(priority = 1, resources = [ITM])]
+    fn trace_data(byte: u8) {
+        let stim = &mut resources.ITM.stim[0];
+        iprintln!(stim, "data {}", byte);
+    }
+
+    #[task(priority = 1, resources = [ITM])]
+    fn trace_error(error: Error) {
+        let stim = &mut resources.ITM.stim[0];
+        iprintln!(stim, "{:?}", error);
+    }
+
+    #[interrupt(priority = 3, resources = [RX], spawn = [trace_data, trace_error, echo])]
+    fn USART2() {
+        match resources.RX.read() {
+            Ok(byte) => {
+                spawn.echo(byte).unwrap();
+                if spawn.trace_data(byte).is_err() {
+                    spawn.trace_error(Error::RingBufferOverflow).unwrap();
+                }
+            }
+            Err(_err) => {
+                spawn.trace_error(Error::UsartReceiveOverflow).unwrap()
+            }
+        }
+    }
+
+    #[task(priority = 2, resources = [TX], spawn = [trace_error, event_a, event_b])]
+    fn echo(byte: u8) {
+        let tx = resources.TX;
+
+        if block!(tx.write(byte)).is_err() {
+            spawn.trace_error(Error::UsartSendOverflow).unwrap();
+        }
+
+        match byte {
+            b'a' => spawn.event_a(false).unwrap(),
+            b'b' => spawn.event_b(false).unwrap(),
+            b'A' => spawn.event_a(true).unwrap(),
+            b'B' => spawn.event_b(true).unwrap(),
+            _ => (),
+        }
+    }
+
+    #[task(priority = 1, resources = [ITM, DATA], schedule = [discrepency])]
+    fn event_a(val: bool) {
+        let stim = &mut resources.ITM.stim[0];
+        iprintln!(stim, "event a {}", val);
+
+        let data = &mut resources.DATA;
+        data.a = val;
+        // evaluate equivalenc.
+        data.event_counter += 1;
+        if data.a ^ data.b {
+            schedule
+                .discrepency(scheduled + TIMEOUT.cycles(), data.clone())
+                .unwrap();
+            data.out = false;
+            iprintln!(stim, "disc {:?}", data);
+        }
+    }
+
+    #[task(priority = 1, resources = [ITM, DATA], spawn = [discrepency])]
+    fn event_b(val: bool) {
+        let stim = &mut resources.ITM.stim[0];
+        iprintln!(stim, "event b {}", val);
+        //evaluate_equivalence(scheduled, &mut resources.DATA);
+    }
+
+    #[task(priority = 1, resources = [ITM, DATA])]
+    fn discrepency(data: Data) {
+        let stim = &mut resources.ITM.stim[0];
+        iprintln!(stim, "a {} b {}", data.a, data.b);
+        if data.event_counter == resources.DATA.event_counter {
+            iprintln!(stim, "timeout");
+            // data.force_reinit =
+        }
+    }
+
+    #[task (priority = 1, resources = [LED])]
+    fn periodic() {
+        static mut TOGGLE: bool = false;
+
+        if *TOGGLE {
+            resources.LED.set_low();
+        } else {
+            resources.LED.set_high();
+        }
+
+        *TOGGLE = !*TOGGLE;
+    }
+
+    extern "C" {
+        fn EXTI0();
+        fn EXTI1();
+        fn EXTI2();
+        fn EXTI3();
+        fn EXTI4();
+    }
+};
+
+// fn evaluate_equivalence(scheduled: Instant, data: &mut Data,  d: event_a::Spawn) {
+//     data.EventCounter += 1;
+//     if data.A ^ data.B {
+
+//         // spawn.discrepency(scheduled + TIMEOUT.cycles(), data.EventCounter, data.A, data.B);
+
+//     }
+// }
diff --git a/examples/marcus.rs b/examples/marcus.rs
new file mode 100644
index 0000000..0114062
--- /dev/null
+++ b/examples/marcus.rs
@@ -0,0 +1,388 @@
+//! The RTFM framework
+//!
+//! What it covers:
+//! - Priority based scheduling
+//! - Message passing
+
+#![no_main]
+#![no_std]
+
+extern crate panic_halt;
+
+use cortex_m::{asm, iprintln};
+
+extern crate stm32f4xx_hal as hal;
+use crate::hal::prelude::*;
+use crate::hal::serial::{self, config::Config, Rx, Serial, Tx};
+use hal::stm32::ITM;
+
+// use heapless::consts::*;
+// use heapless::spsc::{Consumer, Producer, Queue};
+
+use nb::block;
+
+use rtfm::{app, Instant};
+
+// Our error type
+#[derive(Debug)]
+pub enum Error {
+    RingBufferOverflow,
+    UsartSendOverflow,
+    UsartReceiveOverflow,
+}
+
+#[derive(Debug)]
+pub enum Event {
+    Timout,
+    ChannelA,
+    ChannelB,
+}
+
+#[derive(Debug, Copy, Clone)]
+pub struct Data {
+    state: State,
+    a: bool,
+    b: bool,
+    event_counter: u32,
+    out: bool,
+}
+
+#[derive(Debug, Copy, Clone)]
+pub enum State {
+    S8000,
+    S8001,
+    S8004,
+    S8014,
+    S8005,
+    C001,
+    C002,
+    C003,
+}
+
+const TIMEOUT: u32 = 16_000_000;
+
+#[app(device = hal::stm32)]
+const APP: () = {
+    // Late resources
+    static mut TX: Tx<hal::stm32::USART2> = ();
+    static mut RX: Rx<hal::stm32::USART2> = ();
+    static mut ITM: ITM = ();
+
+    // app resources
+    static mut DATA: Data = Data {
+        state: State::S8001,
+        a: false,
+        b: false,
+        event_counter: 0,
+        out: false,
+    };
+
+    // init runs in an interrupt free section>
+    #[init(resources = [DATA])]
+    fn init() {
+        let stim = &mut core.ITM.stim[0];
+        iprintln!(stim, "Start {:?}", resources.DATA);
+
+        let rcc = device.RCC.constrain();
+
+        // 16 MHz (default, all clocks)
+        let clocks = rcc.cfgr.freeze();
+
+        let gpioa = device.GPIOA.split();
+
+        let tx = gpioa.pa2.into_alternate_af7();
+        let rx = gpioa.pa3.into_alternate_af7(); // try comment out
+
+        let mut serial = Serial::usart2(
+            device.USART2,
+            (tx, rx),
+            Config::default().baudrate(115_200.bps()),
+            clocks,
+        )
+        .unwrap();
+
+        // generate interrupt on Rxne
+        serial.listen(serial::Event::Rxne);
+        // Separate out the sender and receiver of the serial port
+        let (tx, rx) = serial.split();
+
+        // Our split serial
+        TX = tx;
+        RX = rx;
+
+        // For debugging
+        ITM = core.ITM;
+    }
+
+    // idle may be interrupted by other interrupt/tasks in the system
+    // #[idle(resources = [RX, TX, ITM])]
+    #[idle]
+    fn idle() -> ! {
+        loop {
+            asm::wfi();
+        }
+    }
+
+    #[task(priority = 1, resources = [ITM])]
+    fn trace_data(byte: u8) {
+        let stim = &mut resources.ITM.stim[0];
+        iprintln!(stim, "data {}", byte);
+    }
+
+    #[task(priority = 1, resources = [ITM])]
+    fn trace_error(error: Error) {
+        let stim = &mut resources.ITM.stim[0];
+        iprintln!(stim, "{:?}", error);
+    }
+
+    #[interrupt(priority = 3, resources = [RX], spawn = [trace_data, trace_error, echo])]
+    fn USART2() {
+        match resources.RX.read() {
+            Ok(byte) => {
+                spawn.echo(byte).unwrap();
+                if spawn.trace_data(byte).is_err() {
+                    spawn.trace_error(Error::RingBufferOverflow).unwrap();
+                }
+            }
+            Err(_err) => {
+                spawn.trace_error(Error::UsartReceiveOverflow).unwrap()
+            }
+        }
+    }
+
+    #[task(priority = 2, resources = [TX], spawn = [trace_error, event_a, event_b])]
+    fn echo(byte: u8) {
+        let tx = resources.TX;
+
+        if block!(tx.write(byte)).is_err() {
+            spawn.trace_error(Error::UsartSendOverflow).unwrap();
+        }
+
+        match byte {
+            b'a' => spawn.event_a(false).unwrap(),
+            b'b' => spawn.event_b(false).unwrap(),
+            b'A' => spawn.event_a(true).unwrap(),
+            b'B' => spawn.event_b(true).unwrap(),
+            _ => (),
+        }
+    }
+
+    #[task(priority = 1, resources = [ITM, DATA], schedule = [discrepency])]
+    fn event_a(val: bool) {
+        let stim = &mut resources.ITM.stim[0];
+        iprintln!(stim, "event a {}", val);
+
+
+        let data = &mut resources.DATA;
+        data.a = val;
+        iprintln!(stim, "Start {:?}", data);
+        // let data = resources.DATA;
+
+        match data.state {
+            State::S8000 => {
+                if data.a ^ data.b {
+                    schedule
+                        .discrepency(scheduled + TIMEOUT.cycles(), data.event_counter, data.state)
+                        .unwrap();
+                    data.out = false;
+                    data.state = State::S8005;
+                } else if !data.a & !data.b {
+                    data.state = State::S8001
+                } else {
+                    return;
+                }
+            }
+            State::S8001 => {
+                if data.a & !data.b {
+                    schedule
+                        .discrepency(scheduled + TIMEOUT.cycles(), data.event_counter, data.state)
+                        .unwrap();
+                    data.out = false;
+                    data.state = State::S8004;
+                } else if !data.a & data.b {
+                    schedule
+                        .discrepency(scheduled + TIMEOUT.cycles(), data.event_counter, data.state)
+                        .unwrap();
+                    data.out = false;
+                    data.state = State::S8014;
+                } else if data.a & data.b {
+                    data.out = true;
+                    data.state = State::S8000;
+                }
+            }
+            State::S8004 => {
+                if !data.a {
+                    data.event_counter += 1;
+                    data.out = false;
+                    data.state = State::S8001;
+                } else if data.b {
+                    data.event_counter += 1;
+                    data.out = true;
+                    data.state = State::S8000;
+                } else {
+                    data.out = false;
+                }
+            }
+            State::S8014 => {
+                if !data.b {
+                    data.event_counter += 1;
+                    data.out = false;
+                    data.state = State::S8001;
+                } else if data.a {
+                    data.event_counter += 1;
+                    data.out = true;
+                    data.state = State::S8000;
+                } else {
+                    data.out = false;
+                }
+            }
+            State::S8005 => {
+                if !data.a & !data.b {
+                    data.event_counter += 1;
+                    data.out = false;
+                    data.state = State::S8001;
+                } else {
+                    data.out = false;
+                }
+            }
+
+            _ => {
+                if !data.a & !data.b {
+                    data.out = false;
+                    data.state = State::S8001;
+                } else {
+                    data.out = false;
+                }
+            }
+        }
+        iprintln!(stim, "Start {:?}", resources.DATA);
+    }
+
+    #[task(priority = 1, resources = [ITM, DATA],  schedule = [discrepency])]
+    fn event_b(val: bool) {
+        let stim = &mut resources.ITM.stim[0];
+        iprintln!(stim, "event b {}", val);
+
+        let data = &mut resources.DATA;
+        data.b = val;
+        iprintln!(stim, "Start {:?}", data);
+        
+        match data.state {
+            State::S8000 => {
+                if data.a ^ data.b {
+                    schedule
+                        .discrepency(scheduled + TIMEOUT.cycles(), data.event_counter, data.state)
+                        .unwrap();
+                    data.out = false;
+                    data.state = State::S8005;
+                } else if !data.a & !data.b {
+                    data.state = State::S8001
+                } else {
+                    return;
+                }
+            }
+            State::S8001 => {
+                if data.a & !data.b {
+                    schedule
+                        .discrepency(scheduled + TIMEOUT.cycles(), data.event_counter, data.state)
+                        .unwrap();
+                    data.out = false;
+                    data.state = State::S8004;
+                } else if !data.a & data.b {
+                    schedule
+                        .discrepency(scheduled + TIMEOUT.cycles(), data.event_counter, data.state)
+                        .unwrap();
+                    data.out = false;
+                    data.state = State::S8014;
+                } else if data.a & data.b {
+                    data.out = true;
+                    data.state = State::S8000;
+                }
+            }
+            State::S8004 => {
+                if !data.a {
+                    data.event_counter += 1;
+                    data.out = false;
+                    data.state = State::S8001;
+                } else if data.b {
+                    data.event_counter += 1;
+                    data.out = true;
+                    data.state = State::S8000;
+                } else {
+                    data.out = false;
+                }
+            }
+            State::S8014 => {
+                if !data.b {
+                    data.event_counter += 1;
+                    data.out = false;
+                    data.state = State::S8001;
+                } else if data.a {
+                    data.event_counter += 1;
+                    data.out = true;
+                    data.state = State::S8000;
+                } else {
+                    data.out = false;
+                }
+            }
+            State::S8005 => {
+                if !data.a & !data.b {
+                    data.event_counter += 1;
+                    data.out = false;
+                    data.state = State::S8001;
+                } else {
+                    data.out = false;
+                }
+            }
+
+            _ => {
+                if !data.a & !data.b {
+                    data.out = false;
+                    data.state = State::S8001;
+                } else {
+                    data.out = false;
+                }
+            }
+        }
+    }
+
+    #[task(priority = 1, resources = [ITM])]
+    fn discrepency(counter: u32, state:State) {
+        let stim = &mut resources.ITM.stim[0];
+        iprintln!(stim, "counter {} state {:?}", counter, state);
+        // if data.event_counter == resources.DATA.event_counter {
+        //     iprintln!(stim, "timeout");
+        //     // data.force_reinit =
+        // }
+    }
+
+    extern "C" {
+        fn EXTI0();
+        fn EXTI1();
+        fn EXTI2();
+        fn EXTI3();
+        fn EXTI4();
+    }
+};
+
+// fn evaluate_equivalence(scheduled: Instant, data: &mut Data,  d: event_a::Spawn) {
+//     data.EventCounter += 1;
+//     if data.A ^ data.B {
+
+//         // spawn.discrepency(scheduled + TIMEOUT.cycles(), data.EventCounter, data.A, data.B);
+
+//     }
+// }
+//
+//
+//
+//
+//  invariants
+//  out = true -> A & B
+//
+//  event A false -> A = false
+//  event A true  -> A = true
+//  event B false -> B = false
+//  event B true  -> B = true
+//
+//  A ^ B -- TIMEOUT --> !(A & B) -> out = false
-- 
GitLab