2018-04-19 18:38:12 +02:00
|
|
|
// #![deny(unsafe_code)]
|
|
|
|
// #![deny(warnings)]
|
|
|
|
#![allow(dead_code)]
|
|
|
|
#![feature(proc_macro)]
|
|
|
|
#![no_std]
|
|
|
|
|
|
|
|
#[macro_use]
|
|
|
|
extern crate cortex_m;
|
|
|
|
extern crate cortex_m_rtfm as rtfm;
|
|
|
|
extern crate panic_abort;
|
|
|
|
extern crate stm32f103xx;
|
|
|
|
|
2018-04-20 03:46:04 +02:00
|
|
|
use core::cmp;
|
|
|
|
|
2018-04-19 18:38:12 +02:00
|
|
|
use cortex_m::peripheral::syst::SystClkSource;
|
2018-04-20 06:48:59 +02:00
|
|
|
use cortex_m::peripheral::ITM;
|
|
|
|
use rtfm::ll::{Consumer, FreeList, Instant, Node, Producer, RingBuffer, Slot, TaggedPayload,
|
|
|
|
TimerQueue};
|
2018-04-19 18:38:12 +02:00
|
|
|
use rtfm::{app, Resource, Threshold};
|
|
|
|
use stm32f103xx::Interrupt;
|
|
|
|
|
|
|
|
const ACAP: usize = 2;
|
|
|
|
|
|
|
|
const MS: u32 = 8_000;
|
|
|
|
|
|
|
|
app! {
|
|
|
|
device: stm32f103xx,
|
|
|
|
|
|
|
|
resources: {
|
|
|
|
/* timer queue */
|
2018-04-20 06:48:59 +02:00
|
|
|
static TQ: TimerQueue<Task, [TaggedPayload<Task>; 2]>;
|
2018-04-19 18:38:12 +02:00
|
|
|
|
|
|
|
/* a */
|
|
|
|
// payloads w/ after
|
2018-04-20 03:46:04 +02:00
|
|
|
static AN: [Node<i32>; 2] = [Node::new(), Node::new()];
|
|
|
|
static AFL: FreeList<i32> = FreeList::new();
|
2018-04-19 18:38:12 +02:00
|
|
|
|
|
|
|
/* exti0 */
|
2018-04-20 06:48:59 +02:00
|
|
|
static Q1: RingBuffer<TaggedPayload<Task1>, [TaggedPayload<Task1>; ACAP + 1], u8> =
|
|
|
|
RingBuffer::u8();
|
|
|
|
static Q1C: Consumer<'static, TaggedPayload<Task1>, [TaggedPayload<Task1>; ACAP + 1], u8>;
|
|
|
|
static Q1P: Producer<'static, TaggedPayload<Task1>, [TaggedPayload<Task1>; ACAP + 1], u8>;
|
2018-04-19 18:38:12 +02:00
|
|
|
},
|
|
|
|
|
|
|
|
init: {
|
2018-04-20 06:48:59 +02:00
|
|
|
resources: [AN, Q1],
|
2018-04-19 18:38:12 +02:00
|
|
|
},
|
|
|
|
|
|
|
|
tasks: {
|
|
|
|
EXTI1: {
|
|
|
|
path: exti1,
|
|
|
|
resources: [TQ, AFL],
|
|
|
|
priority: 1,
|
|
|
|
|
|
|
|
// async: [a],
|
|
|
|
},
|
|
|
|
|
|
|
|
// dispatch interrupt
|
|
|
|
EXTI0: {
|
|
|
|
path: exti0,
|
2018-04-20 06:48:59 +02:00
|
|
|
resources: [Q1C, AFL],
|
2018-04-19 18:38:12 +02:00
|
|
|
priority: 1,
|
|
|
|
},
|
|
|
|
|
|
|
|
// timer queue
|
|
|
|
SYS_TICK: {
|
|
|
|
path: sys_tick,
|
2018-04-20 06:48:59 +02:00
|
|
|
resources: [TQ, Q1P],
|
2018-04-20 03:46:04 +02:00
|
|
|
priority: 2,
|
2018-04-19 18:38:12 +02:00
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn init(mut p: ::init::Peripherals, r: init::Resources) -> init::LateResources {
|
|
|
|
// ..
|
|
|
|
|
|
|
|
/* executed after `init` end */
|
|
|
|
p.core.DWT.enable_cycle_counter();
|
|
|
|
unsafe { p.core.DWT.cyccnt.write(0) };
|
|
|
|
p.core.SYST.set_clock_source(SystClkSource::Core);
|
2018-04-20 03:46:04 +02:00
|
|
|
p.core.SYST.enable_counter();
|
|
|
|
p.core.SYST.disable_interrupt();
|
2018-04-19 18:38:12 +02:00
|
|
|
|
|
|
|
// populate the free list
|
2018-04-20 03:46:04 +02:00
|
|
|
for n in r.AN {
|
|
|
|
r.AFL.push(Slot::new(n));
|
|
|
|
}
|
2018-04-19 18:38:12 +02:00
|
|
|
|
|
|
|
let (q1p, q1c) = r.Q1.split();
|
|
|
|
init::LateResources {
|
|
|
|
TQ: TimerQueue::new(p.core.SYST),
|
|
|
|
Q1C: q1c,
|
|
|
|
Q1P: q1p,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn idle() -> ! {
|
|
|
|
rtfm::set_pending(Interrupt::EXTI1);
|
|
|
|
|
|
|
|
loop {
|
|
|
|
rtfm::wfi()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-20 06:48:59 +02:00
|
|
|
fn a(_t: &mut Threshold, bl: Instant, payload: i32) {
|
2018-04-19 18:38:12 +02:00
|
|
|
unsafe {
|
|
|
|
iprintln!(
|
|
|
|
&mut (*ITM::ptr()).stim[0],
|
2018-04-20 06:48:59 +02:00
|
|
|
"a(now={:?}, bl={:?}, payload={})",
|
|
|
|
Instant::now(),
|
2018-04-19 18:38:12 +02:00
|
|
|
bl,
|
|
|
|
payload
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn exti1(t: &mut Threshold, r: EXTI1::Resources) {
|
|
|
|
/* expansion */
|
2018-04-20 06:48:59 +02:00
|
|
|
let bl = Instant::now();
|
2018-04-19 18:38:12 +02:00
|
|
|
let mut async = a::Async::new(bl, r.TQ, r.AFL);
|
|
|
|
/* end of expansion */
|
|
|
|
|
2018-04-20 06:48:59 +02:00
|
|
|
unsafe { iprintln!(&mut (*ITM::ptr()).stim[0], "EXTI0(bl={:?})", bl) }
|
2018-04-19 18:38:12 +02:00
|
|
|
async.a(t, 100 * MS, 0).unwrap();
|
|
|
|
async.a(t, 50 * MS, 1).unwrap();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* auto generated */
|
2018-04-20 06:48:59 +02:00
|
|
|
fn exti0(t: &mut Threshold, mut r: EXTI0::Resources) {
|
|
|
|
while let Some(payload) = r.Q1C.dequeue() {
|
|
|
|
match payload.tag() {
|
2018-04-19 18:38:12 +02:00
|
|
|
Task1::a => {
|
2018-04-20 06:48:59 +02:00
|
|
|
let (bl, payload, slot) = unsafe { payload.coerce() }.read();
|
|
|
|
|
|
|
|
r.AFL.claim_mut(t, |afl, _| afl.push(slot));
|
|
|
|
|
2018-04-20 03:46:04 +02:00
|
|
|
a(&mut unsafe { Threshold::new(1) }, bl, payload);
|
2018-04-19 18:38:12 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn sys_tick(t: &mut Threshold, r: SYS_TICK::Resources) {
|
|
|
|
#[allow(non_snake_case)]
|
2018-04-20 06:48:59 +02:00
|
|
|
let SYS_TICK::Resources { mut Q1P, mut TQ } = r;
|
|
|
|
|
|
|
|
enum State<T>
|
|
|
|
where
|
|
|
|
T: Copy,
|
|
|
|
{
|
|
|
|
Payload(TaggedPayload<T>),
|
|
|
|
Baseline(Instant),
|
2018-04-20 03:46:04 +02:00
|
|
|
Done,
|
|
|
|
}
|
2018-04-19 18:38:12 +02:00
|
|
|
|
2018-04-20 03:46:04 +02:00
|
|
|
loop {
|
|
|
|
let state = TQ.claim_mut(t, |tq, _| {
|
2018-04-20 06:48:59 +02:00
|
|
|
if let Some(bl) = tq.queue.peek().map(|p| p.baseline()) {
|
|
|
|
if Instant::now() >= bl {
|
2018-04-20 03:46:04 +02:00
|
|
|
// message ready
|
2018-04-20 06:48:59 +02:00
|
|
|
State::Payload(tq.queue.pop().unwrap())
|
2018-04-20 03:46:04 +02:00
|
|
|
} else {
|
2018-04-20 06:48:59 +02:00
|
|
|
// new timeout
|
|
|
|
State::Baseline(bl)
|
2018-04-20 03:46:04 +02:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// empty queue
|
|
|
|
tq.syst.disable_interrupt();
|
|
|
|
State::Done
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
match state {
|
2018-04-20 06:48:59 +02:00
|
|
|
State::Payload(p) => match p.tag() {
|
|
|
|
Task::a => {
|
|
|
|
Q1P.claim_mut(t, |q1p, _| q1p.enqueue_unchecked(p.retag(Task1::a)));
|
|
|
|
rtfm::set_pending(Interrupt::EXTI0);
|
2018-04-19 18:38:12 +02:00
|
|
|
}
|
2018-04-20 06:48:59 +02:00
|
|
|
},
|
2018-04-20 03:46:04 +02:00
|
|
|
State::Baseline(bl) => {
|
|
|
|
const MAX: u32 = 0x00ffffff;
|
2018-04-19 18:38:12 +02:00
|
|
|
|
2018-04-20 06:48:59 +02:00
|
|
|
let diff = bl - Instant::now();
|
2018-04-20 03:46:04 +02:00
|
|
|
|
|
|
|
if diff < 0 {
|
|
|
|
// message became ready
|
|
|
|
continue;
|
2018-04-19 18:38:12 +02:00
|
|
|
} else {
|
2018-04-20 03:46:04 +02:00
|
|
|
TQ.claim_mut(t, |tq, _| {
|
|
|
|
tq.syst.set_reload(cmp::min(MAX, diff as u32));
|
|
|
|
tq.syst.clear_current();
|
|
|
|
});
|
|
|
|
return;
|
2018-04-19 18:38:12 +02:00
|
|
|
}
|
|
|
|
}
|
2018-04-20 03:46:04 +02:00
|
|
|
State::Done => {
|
|
|
|
return;
|
|
|
|
}
|
2018-04-19 18:38:12 +02:00
|
|
|
}
|
2018-04-20 03:46:04 +02:00
|
|
|
}
|
2018-04-19 18:38:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Tasks dispatched at a priority of 1
|
|
|
|
#[allow(non_camel_case_types)]
|
|
|
|
#[derive(Clone, Copy)]
|
|
|
|
pub enum Task1 {
|
|
|
|
a,
|
|
|
|
}
|
|
|
|
|
|
|
|
// All tasks
|
|
|
|
#[allow(non_camel_case_types)]
|
|
|
|
#[derive(Clone, Copy)]
|
|
|
|
pub enum Task {
|
|
|
|
a,
|
|
|
|
}
|
|
|
|
|
|
|
|
mod a {
|
2018-04-20 03:46:04 +02:00
|
|
|
use cortex_m::peripheral::SCB;
|
|
|
|
|
2018-04-20 06:48:59 +02:00
|
|
|
use rtfm::ll::Instant;
|
2018-04-19 18:38:12 +02:00
|
|
|
use rtfm::{Resource, Threshold};
|
|
|
|
use Task;
|
|
|
|
|
|
|
|
#[allow(non_snake_case)]
|
|
|
|
pub struct Async {
|
2018-04-20 03:46:04 +02:00
|
|
|
// inherited baseline
|
2018-04-20 06:48:59 +02:00
|
|
|
baseline: Instant,
|
2018-04-19 18:38:12 +02:00
|
|
|
TQ: ::EXTI1::TQ,
|
|
|
|
AFL: ::EXTI1::AFL,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Async {
|
|
|
|
#[allow(non_snake_case)]
|
2018-04-20 06:48:59 +02:00
|
|
|
pub fn new(bl: Instant, TQ: ::EXTI1::TQ, AFL: ::EXTI1::AFL) -> Self {
|
2018-04-20 03:46:04 +02:00
|
|
|
Async {
|
|
|
|
baseline: bl,
|
|
|
|
TQ,
|
|
|
|
AFL,
|
|
|
|
}
|
2018-04-19 18:38:12 +02:00
|
|
|
}
|
|
|
|
|
2018-04-20 03:46:04 +02:00
|
|
|
pub fn a(&mut self, t: &mut Threshold, after: u32, payload: i32) -> Result<(), i32> {
|
2018-04-19 18:38:12 +02:00
|
|
|
if let Some(slot) = self.AFL.claim_mut(t, |afl, _| afl.pop()) {
|
2018-04-20 03:46:04 +02:00
|
|
|
let baseline = self.baseline;
|
|
|
|
self.TQ.claim_mut(t, |tq, _| {
|
|
|
|
if tq.queue.capacity() == tq.queue.len() {
|
|
|
|
// full
|
|
|
|
Err(payload)
|
|
|
|
} else {
|
2018-04-20 06:48:59 +02:00
|
|
|
let bl = baseline + after;
|
2018-04-20 03:46:04 +02:00
|
|
|
if tq.queue
|
|
|
|
.peek()
|
2018-04-20 06:48:59 +02:00
|
|
|
.map(|head| bl < head.baseline())
|
2018-04-20 03:46:04 +02:00
|
|
|
.unwrap_or(true)
|
|
|
|
{
|
|
|
|
tq.syst.enable_interrupt();
|
|
|
|
// Set SYST pending
|
|
|
|
unsafe { (*SCB::ptr()).icsr.write(1 << 26) }
|
|
|
|
}
|
|
|
|
|
2018-04-20 06:48:59 +02:00
|
|
|
tq.queue.push(slot.write(bl, payload).tag(Task::a)).ok();
|
2018-04-20 03:46:04 +02:00
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
})
|
2018-04-19 18:38:12 +02:00
|
|
|
} else {
|
|
|
|
Err(payload)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|