make task.$T.enabled optional

and move the logic that differentiates interrupts from exceptions from the crate
to the procedural macro logic
This commit is contained in:
Jorge Aparicio 2017-07-27 17:08:42 -05:00
parent ad2a523cf9
commit d396da5950
17 changed files with 112 additions and 92 deletions

View file

@ -37,7 +37,9 @@ app! {
},
TIM2: {
enabled: true,
// tasks are enabled, between `init` and `idle`, by default but they
// can start disabled if `false` is specified here
enabled: false,
path: tim2,
priority: 1,
resources: [CO_OWNED],

View file

@ -15,14 +15,12 @@ app! {
tasks: {
EXTI0: {
enabled: true,
path: exti0,
priority: 1,
resources: [GPIOA, SPI1],
},
EXTI1: {
enabled: true,
path: exti1,
priority: 2,
resources: [GPIOA, SPI1],

View file

@ -31,14 +31,11 @@ app! {
tasks: {
SYS_TICK: {
path: tasks::sys_tick,
priority: 1,
resources: [CO_OWNED, ON, SHARED],
},
TIM2: {
enabled: true,
path: tasks::tim2,
priority: 1,
resources: [CO_OWNED],
},
},

View file

@ -24,21 +24,18 @@ app! {
tasks: {
EXTI0: {
enabled: true,
path: exti0,
priority: 1,
resources: [LOW, HIGH],
},
EXTI1: {
enabled: true,
path: exti1,
priority: 2,
resources: [LOW],
},
EXTI2: {
enabled: true,
path: exti2,
priority: 3,
resources: [HIGH],

View file

@ -25,7 +25,6 @@ app! {
},
TIM2: {
enabled: true,
path: tim2,
priority: 1,
resources: [COUNTER],

View file

@ -33,7 +33,6 @@ app! {
// For interrupts the `enabled` field must be specified. It
// indicates if the interrupt will be enabled or disabled once
// `idle` starts
enabled: true,
path: tim2,
priority: 1,
resources: [COUNTER],

View file

@ -16,8 +16,39 @@ pub struct App {
pub type Tasks = HashMap<Ident, Task>;
#[allow(non_camel_case_types)]
pub enum Exception {
PENDSV,
SVCALL,
SYS_TICK,
}
impl Exception {
pub fn from(s: &str) -> Option<Self> {
Some(match s {
"PENDSV" => Exception::PENDSV,
"SVCALL" => Exception::SVCALL,
"SYS_TICK" => Exception::SYS_TICK,
_ => return None,
})
}
pub fn nr(&self) -> usize {
match *self {
Exception::PENDSV => 14,
Exception::SVCALL => 11,
Exception::SYS_TICK => 15,
}
}
}
pub enum Kind {
Exception(Exception),
Interrupt { enabled: bool },
}
pub struct Task {
pub enabled: Option<bool>,
pub kind: Kind,
pub path: Option<Path>,
pub priority: u8,
pub resources: Idents,
@ -31,8 +62,13 @@ pub fn app(app: check::App) -> Result<App> {
resources: app.resources,
tasks: app.tasks
.into_iter()
.map(|(k, v)| (k, ::check::task(v)))
.collect(),
.map(|(k, v)| {
let v = ::check::task(k.as_ref(), v)
.chain_err(|| format!("checking task `{}`", k))?;
Ok((k, v))
})
.collect::<Result<_>>()?,
};
::check::resources(&app)
@ -60,11 +96,34 @@ fn resources(app: &App) -> Result<()> {
Ok(())
}
fn task(task: syntax::check::Task) -> Task {
Task {
enabled: task.enabled,
fn task(name: &str, task: syntax::check::Task) -> Result<Task> {
let kind = match Exception::from(name) {
Some(e) => {
ensure!(
task.enabled.is_none(),
"`enabled` field is not valid for exceptions"
);
Kind::Exception(e)
}
None => {
if task.enabled == Some(true) {
bail!(
"`enabled: true` is the default value; this line can be \
omitted"
);
}
Kind::Interrupt {
enabled: task.enabled.unwrap_or(true),
}
}
};
Ok(Task {
kind,
path: task.path,
priority: task.priority.unwrap_or(1),
resources: task.resources,
}
})
}

View file

@ -2,7 +2,7 @@ use quote::{Ident, Tokens};
use syn::{Lit, StrStyle};
use analyze::{Ownership, Ownerships};
use check::App;
use check::{App, Kind};
fn krate() -> Ident {
Ident::from("rtfm")
@ -236,44 +236,47 @@ fn init(app: &App, main: &mut Vec<Tokens>, root: &mut Vec<Tokens>) {
let mut exceptions = vec![];
let mut interrupts = vec![];
for (name, task) in &app.tasks {
if let Some(enabled) = task.enabled {
// Interrupt. These can be enabled / disabled through the NVIC
if interrupts.is_empty() {
interrupts.push(quote! {
let nvic = &*#device::NVIC.get();
});
}
match task.kind {
Kind::Exception(ref e) => {
if exceptions.is_empty() {
exceptions.push(quote! {
let scb = &*#device::SCB.get();
});
}
let priority = task.priority;
interrupts.push(quote! {
let prio_bits = #device::NVIC_PRIO_BITS;
let hw = ((1 << prio_bits) - #priority) << (8 - prio_bits);
nvic.set_priority(#device::Interrupt::#name, hw);
});
if enabled {
interrupts.push(quote! {
nvic.enable(#device::Interrupt::#name);
});
} else {
interrupts.push(quote! {
nvic.disable(#device::Interrupt::#name);
});
}
} else {
// Exception
if exceptions.is_empty() {
let nr = e.nr();
let priority = task.priority;
exceptions.push(quote! {
let scb = &*#device::SCB.get();
let prio_bits = #device::NVIC_PRIO_BITS;
let hw = ((1 << prio_bits) - #priority) << (8 - prio_bits);
scb.shpr[#nr - 4].write(hw);
});
}
Kind::Interrupt { enabled } => {
// Interrupt. These can be enabled / disabled through the NVIC
if interrupts.is_empty() {
interrupts.push(quote! {
let nvic = &*#device::NVIC.get();
});
}
let priority = task.priority;
exceptions.push(quote! {
let prio_bits = #device::NVIC_PRIO_BITS;
let hw = ((1 << prio_bits) - #priority) << (8 - prio_bits);
scb.shpr[#krate::Exception::#name.nr() - 4].write(hw);
});
let priority = task.priority;
interrupts.push(quote! {
let prio_bits = #device::NVIC_PRIO_BITS;
let hw = ((1 << prio_bits) - #priority) << (8 - prio_bits);
nvic.set_priority(#device::Interrupt::#name, hw);
});
if enabled {
interrupts.push(quote! {
nvic.enable(#device::Interrupt::#name);
});
} else {
interrupts.push(quote! {
nvic.disable(#device::Interrupt::#name);
});
}
}
}
}

View file

@ -140,25 +140,3 @@ where
let nvic = unsafe { &*cortex_m::peripheral::NVIC.get() };
nvic.set_pending(interrupt);
}
#[allow(non_camel_case_types)]
#[doc(hidden)]
pub enum Exception {
/// System service call via SWI instruction
SVCALL,
/// Pendable request for system service
PENDSV,
/// System tick timer
SYS_TICK,
}
impl Exception {
#[doc(hidden)]
pub fn nr(&self) -> usize {
match *self {
Exception::SVCALL => 11,
Exception::PENDSV => 14,
Exception::SYS_TICK => 15,
}
}
}

View file

@ -21,7 +21,6 @@ app! {
tasks: {
EXTI0: {
enabled: true,
path: exti0,
priority: 1,
resources: [ON],

View file

@ -9,7 +9,6 @@ use rtfm::app;
app! {
//~^ error proc macro panicked
//~| help parsing
device: stm32f103xx,
tasks: {

View file

@ -7,9 +7,7 @@ extern crate stm32f103xx;
use rtfm::app;
app! {
//~^ error no associated item named `SYS_TICK` found for type
//~| error no associated item named `SYS_TICK` found for type
app! { //~ error proc macro panicked
device: stm32f103xx,
tasks: {

View file

@ -7,14 +7,14 @@ extern crate stm32f103xx;
use rtfm::app;
app! { //~ error no associated item named `EXTI0` found for type
app! {
//~^ error no associated item named `EXTI33` found for type
//~| error no associated item named `EXTI33` found for type
device: stm32f103xx,
tasks: {
// ERROR `enabled` needs to be specified for interrupts
EXTI0: {
priority: 1,
},
// ERROR this interrupt doesn't exist
EXTI33: {},
},
}

View file

@ -18,21 +18,18 @@ app! {
tasks: {
EXTI0: {
enabled: true,
path: exti0,
priority: 1,
resources: [MAX, ON],
},
EXTI1: {
enabled: true,
path: exti1,
priority: 2,
resources: [ON],
},
EXTI2: {
enabled: true,
path: exti2,
priority: 16,
resources: [MAX],

View file

@ -17,14 +17,12 @@ app! {
tasks: {
EXTI0: {
enabled: true,
path: exti0,
priority: 1,
resources: [STATE],
},
EXTI1: {
enabled: true,
path: exti1,
priority: 2,
resources: [STATE],

View file

@ -17,7 +17,6 @@ app! { //~ error bound `rtfm::Threshold: core::marker::Send` is not satisfied
tasks: {
EXTI0: {
enabled: true,
path: exti0,
priority: 1,
resources: [TOKEN],

View file

@ -18,14 +18,12 @@ app! {
tasks: {
EXTI0: {
enabled: true,
path: exti0,
priority: 1,
resources: [A, B],
},
EXTI1: {
enabled: true,
path: exti1,
priority: 2,
resources: [A, B],