From 1ae558524bcec663bf77761cd55437223c5a8806 Mon Sep 17 00:00:00 2001
From: Per <Per Lindgren>
Date: Fri, 23 Feb 2018 01:33:45 +0100
Subject: [PATCH] loopback

---
 examples/loopback.rs | 190 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 190 insertions(+)
 create mode 100644 examples/loopback.rs

diff --git a/examples/loopback.rs b/examples/loopback.rs
new file mode 100644
index 0000000..4a1e705
--- /dev/null
+++ b/examples/loopback.rs
@@ -0,0 +1,190 @@
+//! Serial interface loopback
+#![deny(unsafe_code)]
+//#![deny(warnings)]
+#![feature(proc_macro)]
+#![no_std]
+
+extern crate cortex_m_rtfm as rtfm;
+extern crate f4;
+extern crate heapless;
+
+#[macro_use]
+extern crate cortex_m_debug;
+
+use f4::prelude::*;
+use f4::Serial;
+use f4::serial::Event;
+use f4::time::Hertz;
+//use heapless::{RingBuffer, Vec};
+use heapless::RingBuffer;
+use rtfm::{app, Resource, Threshold};
+
+// CONFIGURATION
+const BAUD_RATE: Hertz = Hertz(115_200);
+
+// TASKS & RESOURCES
+app! {
+    device: f4::stm32f40x,
+
+    resources: {
+        static SEND: RingBuffer<u8, [u8; 4]> = RingBuffer::new();
+        static RECEIVE: RingBuffer<u8, [u8; 6]> = RingBuffer::new();
+    },
+
+    tasks: {
+        USART2: {
+            path: usart2_handler,
+            priority: 3,
+            resources: [USART2, RECEIVE, SEND],
+        },
+        EXTI1: {
+            path: command,
+            priority: 2,
+            resources: [USART2, RECEIVE, SEND],
+        },
+        EXTI2: {
+            path: error_receive_buffer_full,
+            priority: 1,
+        },
+        EXTI3: {
+            path: error_usart_overflow,
+            priority: 1,
+        },
+    }
+}
+
+// INITIALIZATION PHASE
+fn init(p: init::Peripherals, r: init::Resources) {
+    ipln!("init");
+    let serial = Serial(p.USART2);
+
+    serial.init(BAUD_RATE.invert(), Some(p.DMA1), p.GPIOA, p.RCC);
+    serial.listen(Event::Rxne);
+    serial.listen(Event::Txe);
+
+    let _ = r.SEND.enqueue('a' as u8);
+    let _ = r.SEND.enqueue('b' as u8);
+    let _ = r.SEND.enqueue('c' as u8);
+
+    rtfm::set_pending(f4::stm32f40x::Interrupt::USART2); // trigger USART2 task
+}
+
+// IDLE LOOP
+fn idle() -> ! {
+    // Sleep
+    loop {
+        rtfm::wfi();
+    }
+}
+
+// USART2 task
+fn usart2_handler(_t: &mut Threshold, r: USART2::Resources) {
+    let serial = Serial(&**r.USART2);
+    let sr = r.USART2.sr.read();
+    if sr.rxne().bit_is_set() {
+        // interrupt due to data received
+        match serial.read() {
+            Ok(b) => {
+                if b == '\n' as u8 || b == '\r' as u8 {
+                    // we have received a `return`, trigger command to process it
+                    rtfm::set_pending(f4::stm32f40x::Interrupt::EXTI1);
+                } else {
+                    match r.RECEIVE.enqueue(b) {
+                        Err(_) => {
+                            // trigger error_handler on buffer overflow
+                            rtfm::set_pending(f4::stm32f40x::Interrupt::EXTI2);
+                        }
+                        _ => {}
+                    }
+                }
+            }
+            Err(_) => {
+                // trigger error on usart overflow
+                rtfm::set_pending(f4::stm32f40x::Interrupt::EXTI3);
+                r.USART2.dr.read(); // clear the error by reading the data register
+            }
+        }
+    }
+
+    match r.SEND.dequeue() {
+        Some(b) => {
+            // we (still) have something in the queue to send
+            let _ = serial.write(b);
+        }
+        _ => {
+            // the que was empty so the last item was already sent
+            serial.unlisten(Event::Txe);
+        }
+    }
+}
+
+#[allow(non_snake_case)]
+fn command(
+    t: &mut Threshold,
+    EXTI1::Resources {
+        USART2,
+        mut SEND,
+        mut RECEIVE,
+    }: EXTI1::Resources,
+) {
+    ipln!("command");
+
+    match SEND.claim_mut(t, |send, t1| {
+        RECEIVE.claim_mut(t1, |receive, _| {
+            let mut err = Ok(());
+            while let Some(e) = receive.dequeue() {
+                err = send.enqueue(e);
+            }
+            err
+        })
+    }) {
+        Err(err) => {
+            // error handling outside the critical section
+            ipln!("SEND {:?}", err);
+        }
+        _ => {}
+    }
+
+    // here we assume that
+    USART2.claim(t, |usart, _| {
+        Serial(&**usart).listen(Event::Txe);
+    });
+    // trigger the usart to send queued data
+    rtfm::set_pending(f4::stm32f40x::Interrupt::USART2);
+}
+
+fn error_receive_buffer_full() {
+    ipln!("error_receive_buffer_full");
+}
+
+fn error_usart_overflow() {
+    ipln!("error_usart_overflow");
+}
+
+#[derive(Debug)]
+enum Command {
+    Start,
+    Stop,
+    Freq(u32),
+}
+
+fn parse(s: &str) -> Result<Command, &str> {
+    let mut iter = s.split(' ').filter(|c| !(c == &""));
+
+    match iter.next() {
+        Some("Stop") => Ok(Command::Stop),
+        Some("Start") => Ok(Command::Start),
+        Some("Freq") => match iter.next() {
+            Some(fs) => {
+                if let Ok(f) = fs.parse::<u32>() {
+                    Ok(Command::Freq(f))
+                } else {
+                    Err("Invalid frequency")
+                }
+            }
+            None => Err("No frequency"),
+        },
+        Some(_) => Err("Invalid command"),
+        None => Err("No input"),
+    }
+}
-- 
GitLab