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: { 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, path: tim2,
priority: 1, priority: 1,
resources: [CO_OWNED], resources: [CO_OWNED],

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -16,8 +16,39 @@ pub struct App {
pub type Tasks = HashMap<Ident, Task>; 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 struct Task {
pub enabled: Option<bool>, pub kind: Kind,
pub path: Option<Path>, pub path: Option<Path>,
pub priority: u8, pub priority: u8,
pub resources: Idents, pub resources: Idents,
@ -31,8 +62,13 @@ pub fn app(app: check::App) -> Result<App> {
resources: app.resources, resources: app.resources,
tasks: app.tasks tasks: app.tasks
.into_iter() .into_iter()
.map(|(k, v)| (k, ::check::task(v))) .map(|(k, v)| {
.collect(), let v = ::check::task(k.as_ref(), v)
.chain_err(|| format!("checking task `{}`", k))?;
Ok((k, v))
})
.collect::<Result<_>>()?,
}; };
::check::resources(&app) ::check::resources(&app)
@ -60,11 +96,34 @@ fn resources(app: &App) -> Result<()> {
Ok(()) Ok(())
} }
fn task(task: syntax::check::Task) -> Task { fn task(name: &str, task: syntax::check::Task) -> Result<Task> {
Task { let kind = match Exception::from(name) {
enabled: task.enabled, 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, path: task.path,
priority: task.priority.unwrap_or(1), priority: task.priority.unwrap_or(1),
resources: task.resources, resources: task.resources,
} })
} }

View file

@ -2,7 +2,7 @@ use quote::{Ident, Tokens};
use syn::{Lit, StrStyle}; use syn::{Lit, StrStyle};
use analyze::{Ownership, Ownerships}; use analyze::{Ownership, Ownerships};
use check::App; use check::{App, Kind};
fn krate() -> Ident { fn krate() -> Ident {
Ident::from("rtfm") 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 exceptions = vec![];
let mut interrupts = vec![]; let mut interrupts = vec![];
for (name, task) in &app.tasks { for (name, task) in &app.tasks {
if let Some(enabled) = task.enabled { match task.kind {
// Interrupt. These can be enabled / disabled through the NVIC Kind::Exception(ref e) => {
if interrupts.is_empty() { if exceptions.is_empty() {
interrupts.push(quote! { exceptions.push(quote! {
let nvic = &*#device::NVIC.get(); let scb = &*#device::SCB.get();
}); });
} }
let priority = task.priority; let nr = e.nr();
interrupts.push(quote! { let priority = task.priority;
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() {
exceptions.push(quote! { 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; let priority = task.priority;
exceptions.push(quote! { interrupts.push(quote! {
let prio_bits = #device::NVIC_PRIO_BITS; let prio_bits = #device::NVIC_PRIO_BITS;
let hw = ((1 << prio_bits) - #priority) << (8 - prio_bits); let hw = ((1 << prio_bits) - #priority) << (8 - prio_bits);
scb.shpr[#krate::Exception::#name.nr() - 4].write(hw); 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() }; let nvic = unsafe { &*cortex_m::peripheral::NVIC.get() };
nvic.set_pending(interrupt); 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: { tasks: {
EXTI0: { EXTI0: {
enabled: true,
path: exti0, path: exti0,
priority: 1, priority: 1,
resources: [ON], resources: [ON],

View file

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

View file

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

View file

@ -7,14 +7,14 @@ extern crate stm32f103xx;
use rtfm::app; 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, device: stm32f103xx,
tasks: { tasks: {
// ERROR `enabled` needs to be specified for interrupts // ERROR this interrupt doesn't exist
EXTI0: { EXTI33: {},
priority: 1,
},
}, },
} }

View file

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

View file

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

View file

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

View file

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