#![feature(const_fn)]
#![feature(used)]
#![no_std]
extern crate cast;
extern crate cortex_m_rt;
#[macro_use]
extern crate cortex_m_rtfm as rtfm;
extern crate f3;
extern crate heapless;
use core::cell::Cell;
use cast::{u8, usize};
use f3::led::{self, LEDS};
use f3::serial::Serial;
use f3::stm32f30x::interrupt::{Tim7, Usart1Exti25};
use f3::stm32f30x;
use f3::timer::Timer;
use heapless::Vec;
use rtfm::{C1, Local, P0, P1, Resource, T0, T1, TMax};
struct State {
direction: Cell<Direction>,
mode: Cell<Mode>,
}
impl State {
const fn new() -> Self {
State {
direction: Cell::new(Direction::Clockwise),
mode: Cell::new(Mode::Continuous),
}
}
}
#[derive(Clone, Copy)]
enum Direction {
Clockwise,
Counterclockwise,
}
impl Direction {
fn reverse(self) -> Self {
match self {
Direction::Clockwise => Direction::Counterclockwise,
Direction::Counterclockwise => Direction::Clockwise,
}
}
}
#[derive(Clone, Copy, PartialEq)]
enum Mode {
Bounce,
Continuous,
}
pub const BAUD_RATE: u32 = 115_200; const FREQUENCY: u32 = 4;
peripherals!(stm32f30x, {
GPIOA: Peripheral {
register_block: Gpioa,
ceiling: C0,
},
GPIOE: Peripheral {
register_block: Gpioe,
ceiling: C0,
},
RCC: Peripheral {
register_block: Rcc,
ceiling: C0,
},
TIM7: Peripheral {
register_block: Tim7,
ceiling: C1,
},
USART1: Peripheral {
register_block: Usart1,
ceiling: C1,
},
});
static SHARED: Resource<State, C1> = Resource::new(State::new());
fn init(ref priority: P0, threshold: &TMax) {
let gpioa = GPIOA.access(priority, threshold);
let gpioe = GPIOE.access(priority, threshold);
let rcc = RCC.access(priority, threshold);
let tim7 = TIM7.access(priority, threshold);
let timer = Timer(&tim7);
let usart1 = USART1.access(priority, threshold);
led::init(&gpioe, &rcc);
timer.init(&rcc, FREQUENCY);
Serial(&usart1).init(&gpioa, &rcc, BAUD_RATE);
timer.resume();
}
fn idle(_priority: P0, _threshold: T0) -> ! {
loop {
rtfm::wfi();
}
}
tasks!(stm32f30x, {
roulette: Task {
interrupt: Tim7,
priority: P1,
enabled: true,
},
receive: Task {
interrupt: Usart1Exti25,
priority: P1,
enabled: true,
},
});
fn receive(mut task: Usart1Exti25, ref priority: P1, ref threshold: T1) {
static BUFFER: Local<Vec<u8, [u8; 16]>, Usart1Exti25> = {
Local::new(Vec::new([0; 16]))
};
let usart1 = USART1.access(priority, threshold);
let serial = Serial(&usart1);
if let Ok(byte) = serial.read() {
if serial.write(byte).is_err() {
#[cfg(debug_assertions)]
unreachable!()
}
let buffer = BUFFER.borrow_mut(&mut task);
if byte == b'\r' {
let shared = SHARED.access(priority, threshold);
match &**buffer {
b"bounce" => shared.mode.set(Mode::Bounce),
b"continuous" => shared.mode.set(Mode::Continuous),
b"reverse" => {
shared.direction.set(shared.direction.get().reverse());
}
_ => {}
}
buffer.clear();
} else {
if buffer.push(byte).is_err() {
buffer.clear();
}
}
} else {
#[cfg(debug_assertions)]
unreachable!()
}
}
fn roulette(mut task: Tim7, ref priority: P1, ref threshold: T1) {
static STATE: Local<u8, Tim7> = Local::new(0);
let tim7 = TIM7.access(priority, threshold);
let timer = Timer(&tim7);
if timer.clear_update_flag().is_ok() {
let state = STATE.borrow_mut(&mut task);
let curr = *state;
let shared = SHARED.access(priority, threshold);
let mut direction = shared.direction.get();
if curr == 0 && shared.mode.get() == Mode::Bounce {
direction = direction.reverse();
shared.direction.set(direction);
}
let n = u8(LEDS.len()).unwrap();
let next = match direction {
Direction::Clockwise => (curr + 1) % n,
Direction::Counterclockwise => curr.checked_sub(1).unwrap_or(n - 1),
};
LEDS[usize(curr)].off();
LEDS[usize(next)].on();
*state = next;
} else {
#[cfg(debug_assertion)]
unreachable!()
}
}