Commit 1ae55852 authored by Per's avatar Per

loopback

parent 53157279
//! 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"),
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment