mirror of
https://github.com/rtic-rs/rtic.git
synced 2024-11-29 06:54:33 +01:00
rtfm! macro take 2
This commit is contained in:
parent
2bf5401439
commit
86a360a396
27 changed files with 1367 additions and 2237 deletions
22
Cargo.toml
22
Cargo.toml
|
@ -10,24 +10,8 @@ keywords = ["arm", "cortex-m"]
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
name = "cortex-m-rtfm"
|
name = "cortex-m-rtfm"
|
||||||
repository = "https://github.com/japaric/cortex-m-rtfm"
|
repository = "https://github.com/japaric/cortex-m-rtfm"
|
||||||
version = "0.1.1"
|
version = "0.2.0"
|
||||||
|
|
||||||
[build-dependencies]
|
|
||||||
quote = "0.3.15"
|
|
||||||
syn = "0.11.10"
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
cortex-m = "0.2.6"
|
cortex-m = "0.3.0"
|
||||||
static-ref = "0.1.0"
|
static-ref = "0.2.0"
|
||||||
typenum = "1.7.0"
|
|
||||||
|
|
||||||
[dev-dependencies]
|
|
||||||
compiletest_rs = "0.2.5"
|
|
||||||
|
|
||||||
[features]
|
|
||||||
# Number of priority bits
|
|
||||||
P2 = []
|
|
||||||
P3 = []
|
|
||||||
P4 = []
|
|
||||||
P5 = []
|
|
||||||
default = ["P4"]
|
|
130
build.rs
130
build.rs
|
@ -1,137 +1,11 @@
|
||||||
#[macro_use]
|
|
||||||
extern crate quote;
|
|
||||||
extern crate syn;
|
|
||||||
|
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::fs::File;
|
|
||||||
use std::io::Write;
|
|
||||||
use std::path::PathBuf;
|
|
||||||
|
|
||||||
use syn::{Ident, IntTy, Lit};
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let target = env::var("TARGET").unwrap();
|
let target = env::var("TARGET").unwrap();
|
||||||
|
|
||||||
if target.starts_with("thumbv6m") {
|
if target.starts_with("thumbv6m-") {
|
||||||
println!("cargo:rustc-cfg=thumbv6m");
|
println!("cargo:rustc-cfg=armv6m");
|
||||||
}
|
}
|
||||||
|
|
||||||
let bits = if env::var_os("CARGO_FEATURE_P2").is_some() {
|
|
||||||
2
|
|
||||||
} else if env::var_os("CARGO_FEATURE_P3").is_some() {
|
|
||||||
3
|
|
||||||
} else if env::var_os("CARGO_FEATURE_P4").is_some() {
|
|
||||||
4
|
|
||||||
} else if env::var_os("CARGO_FEATURE_P5").is_some() {
|
|
||||||
5
|
|
||||||
} else {
|
|
||||||
panic!(
|
|
||||||
"Specify the number of priority bits through one of these Cargo \
|
|
||||||
features: P2, P3, P4 or P5"
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
let n = Lit::Int(bits, IntTy::Unsuffixed);
|
|
||||||
let mut tokens = vec![];
|
|
||||||
tokens.push(
|
|
||||||
quote! {
|
|
||||||
const PRIORITY_BITS: u8 = #n;
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
// Ceilings and thresholds
|
|
||||||
for i in 0..(1 << bits) + 1 {
|
|
||||||
let c = Ident::new(format!("C{}", i));
|
|
||||||
let t = Ident::new(format!("T{}", i));
|
|
||||||
let u = Ident::new(format!("U{}", i));
|
|
||||||
|
|
||||||
let doc = format!("A ceiling of {}", i);
|
|
||||||
tokens.push(
|
|
||||||
quote! {
|
|
||||||
#[doc = #doc]
|
|
||||||
pub type #c = ::typenum::#u;
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
let doc = format!("A preemption threshold of {}", i);
|
|
||||||
tokens.push(
|
|
||||||
quote! {
|
|
||||||
#[doc = #doc]
|
|
||||||
pub type #t = Threshold<::typenum::#u>;
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Priorities
|
|
||||||
for i in 0..(1 << bits) + 1 {
|
|
||||||
let p = Ident::new(format!("P{}", i));
|
|
||||||
let u = Ident::new(format!("U{}", i));
|
|
||||||
|
|
||||||
let doc = format!(
|
|
||||||
"A priority of {}{}",
|
|
||||||
i,
|
|
||||||
if i == 0 {
|
|
||||||
", the lowest priority"
|
|
||||||
} else if i == (1 << bits) {
|
|
||||||
", the highest priority"
|
|
||||||
} else {
|
|
||||||
""
|
|
||||||
}
|
|
||||||
);
|
|
||||||
tokens.push(
|
|
||||||
quote! {
|
|
||||||
#[doc = #doc]
|
|
||||||
pub type #p = Priority<::typenum::#u>;
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// GreaterThanOrEqual & LessThanOrEqual
|
|
||||||
for i in 0..(1 << bits) + 1 {
|
|
||||||
for j in 0..(i + 1) {
|
|
||||||
let i = Ident::new(format!("U{}", i));
|
|
||||||
let j = Ident::new(format!("U{}", j));
|
|
||||||
|
|
||||||
tokens.push(
|
|
||||||
quote! {
|
|
||||||
unsafe impl GreaterThanOrEqual<::typenum::#j> for
|
|
||||||
::typenum::#i {}
|
|
||||||
|
|
||||||
unsafe impl LessThanOrEqual<::typenum::#i> for
|
|
||||||
::typenum::#j {}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let u = Ident::new(format!("U{}", (1 << bits)));
|
|
||||||
let c = Ident::new(format!("C{}", (1 << bits)));
|
|
||||||
let p = Ident::new(format!("P{}", (1 << bits)));
|
|
||||||
let t = Ident::new(format!("T{}", (1 << bits)));
|
|
||||||
tokens.push(
|
|
||||||
quote! {
|
|
||||||
/// Maximum ceiling
|
|
||||||
pub type CMax = #c;
|
|
||||||
|
|
||||||
/// Maximum priority
|
|
||||||
pub type PMax = #p;
|
|
||||||
|
|
||||||
/// Maximum preemption threshold
|
|
||||||
pub type TMax = #t;
|
|
||||||
|
|
||||||
/// Maximum priority level
|
|
||||||
pub type UMax = ::typenum::#u;
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
let tokens = quote! {
|
|
||||||
#(#tokens)*
|
|
||||||
};
|
|
||||||
|
|
||||||
let out_dir = env::var("OUT_DIR").unwrap();
|
|
||||||
let mut out = File::create(PathBuf::from(out_dir).join("prio.rs")).unwrap();
|
|
||||||
|
|
||||||
out.write_all(tokens.as_str().as_bytes()).unwrap();
|
|
||||||
|
|
||||||
println!("cargo:rerun-if-changed=build.rs");
|
println!("cargo:rerun-if-changed=build.rs");
|
||||||
}
|
}
|
||||||
|
|
11
macros/Cargo.toml
Normal file
11
macros/Cargo.toml
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
[package]
|
||||||
|
authors = ["Jorge Aparicio <jorge@japaric.io>"]
|
||||||
|
name = "rtfm-macros"
|
||||||
|
version = "0.1.0"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
quote = "0.3.15"
|
||||||
|
syn = "0.11.11"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
plugin = true
|
17
macros/src/check.rs
Normal file
17
macros/src/check.rs
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
use syntax::Resources;
|
||||||
|
use util::{Ceiling, Ceilings};
|
||||||
|
|
||||||
|
pub fn resources(resources: &Resources, ceilings: &Ceilings) {
|
||||||
|
for resource in resources.keys() {
|
||||||
|
if let Some(ceiling) = ceilings.get(&resource) {
|
||||||
|
assert_ne!(
|
||||||
|
*ceiling,
|
||||||
|
Ceiling::Owned,
|
||||||
|
"{} should be local data",
|
||||||
|
resource
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
panic!("resource {} is unused", resource)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
63
macros/src/lib.rs
Normal file
63
macros/src/lib.rs
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
#![feature(plugin_registrar)]
|
||||||
|
#![feature(proc_macro_internals)]
|
||||||
|
#![feature(rustc_private)]
|
||||||
|
#![recursion_limit = "128"]
|
||||||
|
|
||||||
|
extern crate proc_macro;
|
||||||
|
#[macro_use]
|
||||||
|
extern crate quote;
|
||||||
|
extern crate rustc_errors;
|
||||||
|
extern crate rustc_plugin;
|
||||||
|
extern crate syn;
|
||||||
|
extern crate syntax as rustc_syntax;
|
||||||
|
|
||||||
|
use proc_macro::TokenStream;
|
||||||
|
use rustc_errors::Handler;
|
||||||
|
use rustc_errors::emitter::ColorConfig;
|
||||||
|
use rustc_plugin::Registry;
|
||||||
|
use rustc_syntax::codemap::{CodeMap, FilePathMapping};
|
||||||
|
use rustc_syntax::ext::base::SyntaxExtension;
|
||||||
|
use rustc_syntax::parse::ParseSess;
|
||||||
|
use rustc_syntax::symbol::Symbol;
|
||||||
|
use rustc_syntax::tokenstream::TokenStream as TokenStream_;
|
||||||
|
use std::rc::Rc;
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
mod check;
|
||||||
|
mod syntax;
|
||||||
|
mod trans;
|
||||||
|
mod util;
|
||||||
|
|
||||||
|
fn expand_rtfm(ts: TokenStream_) -> TokenStream_ {
|
||||||
|
let input = format!("{}", ts);
|
||||||
|
|
||||||
|
let app = syntax::parse::app(&input);
|
||||||
|
let ceilings = util::compute_ceilings(&app);
|
||||||
|
check::resources(&app.resources, &ceilings);
|
||||||
|
|
||||||
|
let output = format!("{}", trans::app(&app, &ceilings));
|
||||||
|
|
||||||
|
let mapping = FilePathMapping::empty();
|
||||||
|
let codemap = Rc::new(CodeMap::new(mapping));
|
||||||
|
|
||||||
|
let tty_handler = Handler::with_tty_emitter(
|
||||||
|
ColorConfig::Auto,
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
Some(codemap.clone()),
|
||||||
|
);
|
||||||
|
|
||||||
|
let sess = ParseSess::with_span_handler(tty_handler, codemap.clone());
|
||||||
|
proc_macro::__internal::set_parse_sess(&sess, || {
|
||||||
|
let ts = TokenStream::from_str(&output).unwrap();
|
||||||
|
proc_macro::__internal::token_stream_inner(ts)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[plugin_registrar]
|
||||||
|
pub fn plugin_registrar(reg: &mut Registry) {
|
||||||
|
reg.register_syntax_extension(
|
||||||
|
Symbol::intern("rtfm"),
|
||||||
|
SyntaxExtension::ProcMacro(Box::new(expand_rtfm)),
|
||||||
|
);
|
||||||
|
}
|
52
macros/src/syntax/mod.rs
Normal file
52
macros/src/syntax/mod.rs
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
use std::collections::{HashMap, HashSet};
|
||||||
|
|
||||||
|
use syn::Ident;
|
||||||
|
use quote::Tokens;
|
||||||
|
|
||||||
|
pub mod parse;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct App {
|
||||||
|
pub device: Tokens,
|
||||||
|
pub idle: Idle,
|
||||||
|
pub init: Init,
|
||||||
|
pub resources: Resources,
|
||||||
|
pub tasks: Tasks,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Init {
|
||||||
|
pub path: Tokens,
|
||||||
|
pub resources: HashSet<Ident>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Idle {
|
||||||
|
pub local: Resources,
|
||||||
|
pub path: Tokens,
|
||||||
|
pub resources: HashSet<Ident>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Task {
|
||||||
|
pub kind: Kind,
|
||||||
|
pub priority: u8,
|
||||||
|
pub resources: HashSet<Ident>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Kind {
|
||||||
|
Exception,
|
||||||
|
Interrupt { enabled: bool },
|
||||||
|
}
|
||||||
|
|
||||||
|
// $ident: $ty = $expr;
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Resource {
|
||||||
|
pub expr: Tokens,
|
||||||
|
pub ty: Tokens,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type Resources = HashMap<Ident, Resource>;
|
||||||
|
|
||||||
|
pub type Tasks = HashMap<Ident, Task>;
|
496
macros/src/syntax/parse.rs
Normal file
496
macros/src/syntax/parse.rs
Normal file
|
@ -0,0 +1,496 @@
|
||||||
|
use std::collections::{HashMap, HashSet};
|
||||||
|
|
||||||
|
use syn::{self, DelimToken, Ident, IntTy, Lit, Token, TokenTree};
|
||||||
|
use quote::Tokens;
|
||||||
|
|
||||||
|
use syntax::{App, Idle, Init, Kind, Resource, Resources, Task, Tasks};
|
||||||
|
|
||||||
|
pub fn app(input: &str) -> App {
|
||||||
|
let tts = syn::parse_token_trees(input).unwrap();
|
||||||
|
|
||||||
|
let mut device = None;
|
||||||
|
let mut init = None;
|
||||||
|
let mut idle = None;
|
||||||
|
let mut resources = None;
|
||||||
|
let mut tasks = None;
|
||||||
|
|
||||||
|
let mut tts = tts.into_iter();
|
||||||
|
while let Some(tt) = tts.next() {
|
||||||
|
let id = if let TokenTree::Token(Token::Ident(id)) = tt {
|
||||||
|
id
|
||||||
|
} else {
|
||||||
|
panic!("expected ident, found {:?}", tt);
|
||||||
|
};
|
||||||
|
|
||||||
|
let tt = tts.next();
|
||||||
|
assert_eq!(
|
||||||
|
tt,
|
||||||
|
Some(TokenTree::Token(Token::Colon)),
|
||||||
|
"expected colon, found {:?}",
|
||||||
|
tt
|
||||||
|
);
|
||||||
|
|
||||||
|
match id.as_ref() {
|
||||||
|
"device" => {
|
||||||
|
assert!(device.is_none(), "duplicated device field");
|
||||||
|
|
||||||
|
let mut pieces = vec![];
|
||||||
|
|
||||||
|
loop {
|
||||||
|
if let Some(tt) = tts.next() {
|
||||||
|
if tt == TokenTree::Token(Token::Comma) {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
pieces.push(tt);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
panic!("expected path, found EOM");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
device = Some(quote!(#(#pieces)*));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
"idle" => {
|
||||||
|
assert!(idle.is_none(), "duplicated idle field");
|
||||||
|
|
||||||
|
let tt = tts.next();
|
||||||
|
if let Some(TokenTree::Delimited(block)) = tt {
|
||||||
|
assert_eq!(
|
||||||
|
block.delim,
|
||||||
|
DelimToken::Brace,
|
||||||
|
"expected brace, found {:?}",
|
||||||
|
block.delim
|
||||||
|
);
|
||||||
|
|
||||||
|
idle = Some(super::parse::idle(block.tts));
|
||||||
|
} else {
|
||||||
|
panic!("expected block, found {:?}", tt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"init" => {
|
||||||
|
assert!(init.is_none(), "duplicated init field");
|
||||||
|
|
||||||
|
let tt = tts.next();
|
||||||
|
if let Some(TokenTree::Delimited(block)) = tt {
|
||||||
|
assert_eq!(
|
||||||
|
block.delim,
|
||||||
|
DelimToken::Brace,
|
||||||
|
"expected brace, found {:?}",
|
||||||
|
block.delim
|
||||||
|
);
|
||||||
|
|
||||||
|
init = Some(super::parse::init(block.tts));
|
||||||
|
} else {
|
||||||
|
panic!("expected block, found {:?}", tt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"resources" => {
|
||||||
|
assert!(resources.is_none(), "duplicated resources field");
|
||||||
|
|
||||||
|
let tt = tts.next();
|
||||||
|
if let Some(TokenTree::Delimited(block)) = tt {
|
||||||
|
assert_eq!(
|
||||||
|
block.delim,
|
||||||
|
DelimToken::Brace,
|
||||||
|
"expected brace, found {:?}",
|
||||||
|
block.delim
|
||||||
|
);
|
||||||
|
|
||||||
|
resources = Some(super::parse::resources(block.tts));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"tasks" => {
|
||||||
|
assert!(tasks.is_none(), "duplicated tasks field");
|
||||||
|
|
||||||
|
let tt = tts.next();
|
||||||
|
if let Some(TokenTree::Delimited(block)) = tt {
|
||||||
|
assert_eq!(
|
||||||
|
block.delim,
|
||||||
|
DelimToken::Brace,
|
||||||
|
"expected brace, found {:?}",
|
||||||
|
block.delim
|
||||||
|
);
|
||||||
|
|
||||||
|
tasks = Some(super::parse::tasks(block.tts));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
id => panic!("unexpected field {}", id),
|
||||||
|
}
|
||||||
|
|
||||||
|
let tt = tts.next();
|
||||||
|
assert_eq!(
|
||||||
|
tt,
|
||||||
|
Some(TokenTree::Token(Token::Comma)),
|
||||||
|
"expected comma, found {:?}",
|
||||||
|
tt
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
App {
|
||||||
|
device: device.expect("device field is missing"),
|
||||||
|
idle: idle.expect("idle field is missing"),
|
||||||
|
init: init.expect("init field is missing"),
|
||||||
|
resources: resources.expect("resources field is missing"),
|
||||||
|
tasks: tasks.expect("tasks field is missing"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn idle_init(
|
||||||
|
tts: Vec<TokenTree>,
|
||||||
|
allows_locals: bool,
|
||||||
|
) -> (Option<Resources>, Tokens, HashSet<Ident>) {
|
||||||
|
let mut tts = tts.into_iter();
|
||||||
|
|
||||||
|
let mut local = None;
|
||||||
|
let mut path = None;
|
||||||
|
let mut resources = None;
|
||||||
|
while let Some(tt) = tts.next() {
|
||||||
|
let id = if let TokenTree::Token(Token::Ident(id)) = tt {
|
||||||
|
id
|
||||||
|
} else {
|
||||||
|
panic!("expected ident, found {:?}", tt);
|
||||||
|
};
|
||||||
|
|
||||||
|
let tt = tts.next();
|
||||||
|
assert_eq!(
|
||||||
|
tt,
|
||||||
|
Some(TokenTree::Token(Token::Colon)),
|
||||||
|
"expected colon, found {:?}",
|
||||||
|
tt
|
||||||
|
);
|
||||||
|
|
||||||
|
match id.as_ref() {
|
||||||
|
"local" if allows_locals => {
|
||||||
|
assert!(local.is_none(), "duplicated local field");
|
||||||
|
|
||||||
|
let tt = tts.next();
|
||||||
|
if let Some(TokenTree::Delimited(block)) = tt {
|
||||||
|
assert_eq!(
|
||||||
|
block.delim,
|
||||||
|
DelimToken::Brace,
|
||||||
|
"expected brace, found {:?}",
|
||||||
|
block.delim
|
||||||
|
);
|
||||||
|
|
||||||
|
local = Some(super::parse::resources(block.tts));
|
||||||
|
} else {
|
||||||
|
panic!("expected block, found {:?}", tt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"path" => {
|
||||||
|
assert!(path.is_none(), "duplicated path field");
|
||||||
|
|
||||||
|
let mut pieces = vec![];
|
||||||
|
loop {
|
||||||
|
let tt = tts.next().expect("expected comma, found EOM");
|
||||||
|
|
||||||
|
if tt == TokenTree::Token(Token::Comma) {
|
||||||
|
path = Some(quote!(#(#pieces)*));
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
pieces.push(tt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
"resources" => {
|
||||||
|
assert!(resources.is_none(), "duplicated resources field");
|
||||||
|
|
||||||
|
let tt = tts.next();
|
||||||
|
if let Some(TokenTree::Delimited(array)) = tt {
|
||||||
|
assert_eq!(
|
||||||
|
array.delim,
|
||||||
|
DelimToken::Bracket,
|
||||||
|
"expected bracket, found {:?}",
|
||||||
|
array.delim
|
||||||
|
);
|
||||||
|
|
||||||
|
resources = Some(super::parse::idents(array.tts));
|
||||||
|
|
||||||
|
} else {
|
||||||
|
panic!("expected array, found {:?}", tt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
id => panic!("unexpected field {}", id),
|
||||||
|
}
|
||||||
|
|
||||||
|
let tt = tts.next();
|
||||||
|
assert_eq!(
|
||||||
|
tt,
|
||||||
|
Some(TokenTree::Token(Token::Comma)),
|
||||||
|
"expected comma, found {:?}",
|
||||||
|
tt
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
(
|
||||||
|
local,
|
||||||
|
path.expect("path field is missing"),
|
||||||
|
resources.unwrap_or(HashSet::new()),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn idle(tts: Vec<TokenTree>) -> Idle {
|
||||||
|
let (locals, path, resources) = idle_init(tts, true);
|
||||||
|
|
||||||
|
Idle {
|
||||||
|
local: locals.expect("local field is missing"),
|
||||||
|
path,
|
||||||
|
resources,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn init(tts: Vec<TokenTree>) -> Init {
|
||||||
|
let (_, path, resources) = idle_init(tts, false);
|
||||||
|
|
||||||
|
Init { path, resources }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn idents(tts: Vec<TokenTree>) -> HashSet<Ident> {
|
||||||
|
let mut idents = HashSet::new();
|
||||||
|
|
||||||
|
let mut tts = tts.into_iter();
|
||||||
|
while let Some(tt) = tts.next() {
|
||||||
|
if let TokenTree::Token(Token::Ident(id)) = tt {
|
||||||
|
assert!(!idents.contains(&id), "ident {} already listed", id);
|
||||||
|
idents.insert(id);
|
||||||
|
|
||||||
|
if let Some(tt) = tts.next() {
|
||||||
|
assert_eq!(tt, TokenTree::Token(Token::Comma));
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
panic!("expected ident, found {:?}", tt);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
idents
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn resources(tts: Vec<TokenTree>) -> Resources {
|
||||||
|
let mut resources = HashMap::new();
|
||||||
|
|
||||||
|
let mut tts = tts.into_iter();
|
||||||
|
while let Some(tt) = tts.next() {
|
||||||
|
let name = if let TokenTree::Token(Token::Ident(ident)) = tt {
|
||||||
|
ident
|
||||||
|
} else {
|
||||||
|
panic!("expected ident, found {:?}", tt);
|
||||||
|
};
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
!resources.contains_key(&name),
|
||||||
|
"resource {} already listed",
|
||||||
|
name
|
||||||
|
);
|
||||||
|
|
||||||
|
let tt = tts.next();
|
||||||
|
assert_eq!(
|
||||||
|
tt,
|
||||||
|
Some(TokenTree::Token(Token::Colon)),
|
||||||
|
"expected comma, found {:?}",
|
||||||
|
tt
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut pieces = vec![];
|
||||||
|
loop {
|
||||||
|
if let Some(tt) = tts.next() {
|
||||||
|
if tt == TokenTree::Token(Token::Eq) {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
pieces.push(tt);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
panic!("expected type, found EOM");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let ty = quote!(#(#pieces)*);
|
||||||
|
|
||||||
|
let mut pieces = vec![];
|
||||||
|
loop {
|
||||||
|
if let Some(tt) = tts.next() {
|
||||||
|
if tt == TokenTree::Token(Token::Semi) {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
pieces.push(tt);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
panic!("expected expression, found EOM");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let expr = quote!(#(#pieces)*);
|
||||||
|
|
||||||
|
let resource = Resource { expr, ty };
|
||||||
|
resources.insert(name, resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
resources
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn tasks(tts: Vec<TokenTree>) -> Tasks {
|
||||||
|
let mut tasks = HashMap::new();
|
||||||
|
|
||||||
|
let mut tts = tts.into_iter();
|
||||||
|
while let Some(tt) = tts.next() {
|
||||||
|
let name = if let TokenTree::Token(Token::Ident(ident)) = tt {
|
||||||
|
ident
|
||||||
|
} else {
|
||||||
|
panic!("expected ident, found {:?}", tt);
|
||||||
|
};
|
||||||
|
|
||||||
|
let tt = tts.next();
|
||||||
|
assert_eq!(
|
||||||
|
tt,
|
||||||
|
Some(TokenTree::Token(Token::Colon)),
|
||||||
|
"expected colon, found {:?}",
|
||||||
|
tt
|
||||||
|
);
|
||||||
|
|
||||||
|
let tt = tts.next();
|
||||||
|
if let Some(TokenTree::Delimited(block)) = tt {
|
||||||
|
assert_eq!(
|
||||||
|
block.delim,
|
||||||
|
DelimToken::Brace,
|
||||||
|
"expected brace, found {:?}",
|
||||||
|
block.delim
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(!tasks.contains_key(&name), "task {} already listed", name);
|
||||||
|
tasks.insert(name, super::parse::task(block.tts));
|
||||||
|
} else {
|
||||||
|
panic!("expected block, found {:?}", tt);
|
||||||
|
}
|
||||||
|
|
||||||
|
let tt = tts.next();
|
||||||
|
assert_eq!(
|
||||||
|
tt,
|
||||||
|
Some(TokenTree::Token(Token::Comma)),
|
||||||
|
"expected comma, found {:?}",
|
||||||
|
tt
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parses the body of a task
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// enabled: true,
|
||||||
|
/// priority: 1,
|
||||||
|
/// resources: [R1, TIM2],
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// the `enabled` field is optional and distinguishes interrupts from
|
||||||
|
/// exceptions. Interrupts have an `enabled` field, whereas exceptions don't.
|
||||||
|
fn task(tts: Vec<TokenTree>) -> Task {
|
||||||
|
let mut enabled = None;
|
||||||
|
let mut priority = None;
|
||||||
|
let mut resources = None;
|
||||||
|
|
||||||
|
let mut tts = tts.into_iter();
|
||||||
|
while let Some(tt) = tts.next() {
|
||||||
|
let ident = if let TokenTree::Token(Token::Ident(ident)) = tt {
|
||||||
|
ident
|
||||||
|
} else {
|
||||||
|
panic!("expected ident, found {:?}", tt);
|
||||||
|
};
|
||||||
|
|
||||||
|
let tt = tts.next();
|
||||||
|
assert_eq!(
|
||||||
|
tt,
|
||||||
|
Some(TokenTree::Token(Token::Colon)),
|
||||||
|
"expected colon, found {:?}",
|
||||||
|
tt
|
||||||
|
);
|
||||||
|
|
||||||
|
match ident.as_ref() {
|
||||||
|
"enabled" => {
|
||||||
|
assert!(enabled.is_none(), "duplicated enabled field");
|
||||||
|
|
||||||
|
let tt = tts.next();
|
||||||
|
|
||||||
|
if let Some(TokenTree::Token(Token::Literal(lit))) = tt {
|
||||||
|
if let Lit::Bool(b) = lit {
|
||||||
|
enabled = Some(b);
|
||||||
|
} else {
|
||||||
|
panic!("`enabled` value must be a boolean");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
panic!("expected literal, found {:?}", tt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"priority" => {
|
||||||
|
assert!(priority.is_none(), "duplicated priority field");
|
||||||
|
|
||||||
|
let tt = tts.next();
|
||||||
|
|
||||||
|
if let Some(TokenTree::Token(Token::Literal(lit))) = tt {
|
||||||
|
if let Lit::Int(val, ty) = lit {
|
||||||
|
assert_eq!(
|
||||||
|
ty,
|
||||||
|
IntTy::Unsuffixed,
|
||||||
|
"`priority` value must be an unsuffixed value"
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
val < 256,
|
||||||
|
"`priority` value must be less than 256"
|
||||||
|
);
|
||||||
|
|
||||||
|
priority = Some(val as u8);
|
||||||
|
} else {
|
||||||
|
panic!("enabled value must be a boolean");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
panic!("expected literal, found {:?}", tt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"resources" => {
|
||||||
|
assert!(resources.is_none(), "duplicated resources field");
|
||||||
|
|
||||||
|
let tt = tts.next();
|
||||||
|
if let Some(TokenTree::Delimited(block)) = tt {
|
||||||
|
assert_eq!(
|
||||||
|
block.delim,
|
||||||
|
DelimToken::Bracket,
|
||||||
|
"expected bracket, found {:?}",
|
||||||
|
block.delim
|
||||||
|
);
|
||||||
|
|
||||||
|
resources = Some(super::parse::idents(block.tts));
|
||||||
|
} else {
|
||||||
|
panic!("expected block, found {:?}", tt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
id => panic!("unexpected field {}", id),
|
||||||
|
}
|
||||||
|
|
||||||
|
let tt = tts.next();
|
||||||
|
assert_eq!(
|
||||||
|
tt,
|
||||||
|
Some(TokenTree::Token(Token::Comma)),
|
||||||
|
"expected comma, found {:?}",
|
||||||
|
tt
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let resources = resources.expect("resources field is missing");
|
||||||
|
let priority = priority.expect("priority field is missing");
|
||||||
|
let kind = if let Some(enabled) = enabled {
|
||||||
|
Kind::Interrupt { enabled }
|
||||||
|
} else {
|
||||||
|
Kind::Exception
|
||||||
|
};
|
||||||
|
|
||||||
|
Task {
|
||||||
|
kind,
|
||||||
|
priority,
|
||||||
|
resources,
|
||||||
|
}
|
||||||
|
}
|
486
macros/src/trans.rs
Normal file
486
macros/src/trans.rs
Normal file
|
@ -0,0 +1,486 @@
|
||||||
|
use quote::Tokens;
|
||||||
|
use syn::Ident;
|
||||||
|
|
||||||
|
use syntax::{App, Kind};
|
||||||
|
use util::{Ceiling, Ceilings};
|
||||||
|
|
||||||
|
fn krate() -> Ident {
|
||||||
|
Ident::new("rtfm")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn app(app: &App, ceilings: &Ceilings) -> Tokens {
|
||||||
|
let mut main = vec![];
|
||||||
|
let mut root = vec![];
|
||||||
|
|
||||||
|
super::trans::init(app, &mut main, &mut root);
|
||||||
|
super::trans::idle(app, ceilings, &mut main, &mut root);
|
||||||
|
super::trans::resources(app, ceilings, &mut root);
|
||||||
|
super::trans::tasks(app, ceilings, &mut root);
|
||||||
|
|
||||||
|
root.push(quote! {
|
||||||
|
fn main() {
|
||||||
|
#(#main)*
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
quote!(#(#root)*)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn init(app: &App, main: &mut Vec<Tokens>, root: &mut Vec<Tokens>) {
|
||||||
|
let device = &app.device;
|
||||||
|
let krate = krate();
|
||||||
|
|
||||||
|
let mut fields = vec![];
|
||||||
|
let mut exprs = vec![];
|
||||||
|
let mut lifetime = None;
|
||||||
|
for name in &app.init.resources {
|
||||||
|
lifetime = Some(quote!('a));
|
||||||
|
|
||||||
|
if let Some(resource) = app.resources.get(name) {
|
||||||
|
let ty = &resource.ty;
|
||||||
|
|
||||||
|
fields.push(quote! {
|
||||||
|
pub #name: &'a mut #ty,
|
||||||
|
});
|
||||||
|
|
||||||
|
exprs.push(quote! {
|
||||||
|
#name: &mut *super::#name.get(),
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
fields.push(quote! {
|
||||||
|
pub #name: &'a mut ::#device::#name,
|
||||||
|
});
|
||||||
|
|
||||||
|
exprs.push(quote! {
|
||||||
|
#name: &mut *::#device::#name.get(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
root.push(quote! {
|
||||||
|
mod init {
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
pub struct Resources<#lifetime> {
|
||||||
|
#(#fields)*
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<#lifetime> Resources<#lifetime> {
|
||||||
|
pub unsafe fn new() -> Self {
|
||||||
|
Resources {
|
||||||
|
#(#exprs)*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let mut exceptions = vec![];
|
||||||
|
let mut interrupts = vec![];
|
||||||
|
for (name, task) in &app.tasks {
|
||||||
|
match task.kind {
|
||||||
|
Kind::Exception => {
|
||||||
|
if exceptions.is_empty() {
|
||||||
|
exceptions.push(quote! {
|
||||||
|
let scb = #device::SCB.borrow(cs);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
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[rtfm::Exception::#name.nr() - 4].write(hw);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Kind::Interrupt { enabled } => {
|
||||||
|
if interrupts.is_empty() {
|
||||||
|
interrupts.push(quote! {
|
||||||
|
let nvic = #device::NVIC.borrow(cs);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let init = &app.init.path;
|
||||||
|
main.push(quote! {
|
||||||
|
// type check
|
||||||
|
let init: fn(init::Resources) = #init;
|
||||||
|
|
||||||
|
#krate::atomic(|cs| unsafe {
|
||||||
|
init(init::Resources::new());
|
||||||
|
|
||||||
|
#(#exceptions)*
|
||||||
|
#(#interrupts)*
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn idle(
|
||||||
|
app: &App,
|
||||||
|
ceilings: &Ceilings,
|
||||||
|
main: &mut Vec<Tokens>,
|
||||||
|
root: &mut Vec<Tokens>,
|
||||||
|
) {
|
||||||
|
let krate = krate();
|
||||||
|
|
||||||
|
let mut mod_items = vec![];
|
||||||
|
let mut tys = vec![];
|
||||||
|
let mut exprs = vec![];
|
||||||
|
|
||||||
|
if !app.idle.resources.is_empty() &&
|
||||||
|
!app.idle
|
||||||
|
.resources
|
||||||
|
.iter()
|
||||||
|
.all(|resource| ceilings[resource].is_owned())
|
||||||
|
{
|
||||||
|
tys.push(quote!(#krate::Threshold));
|
||||||
|
exprs.push(quote!(unsafe { #krate::Threshold::new(0) }));
|
||||||
|
}
|
||||||
|
|
||||||
|
if !app.idle.local.is_empty() {
|
||||||
|
let mut lexprs = vec![];
|
||||||
|
let mut lfields = vec![];
|
||||||
|
|
||||||
|
for (name, resource) in &app.idle.local {
|
||||||
|
let expr = &resource.expr;
|
||||||
|
let ty = &resource.ty;
|
||||||
|
|
||||||
|
lfields.push(quote! {
|
||||||
|
pub #name: #ty,
|
||||||
|
});
|
||||||
|
|
||||||
|
lexprs.push(quote! {
|
||||||
|
#name: #expr,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
mod_items.push(quote! {
|
||||||
|
pub struct Local {
|
||||||
|
#(#lfields)*
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
tys.push(quote!(&'static mut idle::Local));
|
||||||
|
exprs.push(quote!(unsafe { &mut LOCAL }));
|
||||||
|
|
||||||
|
main.push(quote! {
|
||||||
|
static mut LOCAL: idle::Local = idle::Local {
|
||||||
|
#(#lexprs)*
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if !app.idle.resources.is_empty() {
|
||||||
|
let device = &app.device;
|
||||||
|
let mut lifetime = None;
|
||||||
|
|
||||||
|
let mut rexprs = vec![];
|
||||||
|
let mut rfields = vec![];
|
||||||
|
for name in &app.idle.resources {
|
||||||
|
if ceilings[name].is_owned() {
|
||||||
|
lifetime = Some(quote!('a));
|
||||||
|
|
||||||
|
rfields.push(quote! {
|
||||||
|
pub #name: &'a mut ::#device::#name,
|
||||||
|
});
|
||||||
|
|
||||||
|
rexprs.push(quote! {
|
||||||
|
#name: &mut *::#device::#name.get(),
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
rfields.push(quote! {
|
||||||
|
pub #name: super::_resource::#name,
|
||||||
|
});
|
||||||
|
|
||||||
|
rexprs.push(quote! {
|
||||||
|
#name: super::_resource::#name::new(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod_items.push(quote! {
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
pub struct Resources<#lifetime> {
|
||||||
|
#(#rfields)*
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<#lifetime> Resources<#lifetime> {
|
||||||
|
pub unsafe fn new() -> Self {
|
||||||
|
Resources {
|
||||||
|
#(#rexprs)*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
tys.push(quote!(idle::Resources));
|
||||||
|
exprs.push(quote!(unsafe { idle::Resources::new() }));
|
||||||
|
}
|
||||||
|
|
||||||
|
root.push(quote! {
|
||||||
|
mod idle {
|
||||||
|
#(#mod_items)*
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let idle = &app.idle.path;
|
||||||
|
main.push(quote! {
|
||||||
|
// type check
|
||||||
|
let idle: fn(#(#tys),*) -> ! = #idle;
|
||||||
|
|
||||||
|
idle(#(#exprs),*);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tasks(app: &App, ceilings: &Ceilings, root: &mut Vec<Tokens>) {
|
||||||
|
let krate = krate();
|
||||||
|
|
||||||
|
for (name, task) in &app.tasks {
|
||||||
|
let mut exprs = vec![];
|
||||||
|
let mut fields = vec![];
|
||||||
|
let mut items = vec![];
|
||||||
|
|
||||||
|
let device = &app.device;
|
||||||
|
let mut lifetime = None;
|
||||||
|
for name in &task.resources {
|
||||||
|
match ceilings[name] {
|
||||||
|
Ceiling::Shared(ceiling) if ceiling > task.priority => {
|
||||||
|
fields.push(quote! {
|
||||||
|
pub #name: super::_resource::#name,
|
||||||
|
});
|
||||||
|
|
||||||
|
exprs.push(quote! {
|
||||||
|
#name: {
|
||||||
|
super::_resource::#name::new()
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
lifetime = Some(quote!('a));
|
||||||
|
if let Some(resource) = app.resources.get(name) {
|
||||||
|
let ty = &resource.ty;
|
||||||
|
|
||||||
|
fields.push(quote! {
|
||||||
|
pub #name: &'a mut ::#krate::Static<#ty>,
|
||||||
|
});
|
||||||
|
|
||||||
|
exprs.push(quote! {
|
||||||
|
#name: ::#krate::Static::ref_mut(
|
||||||
|
&mut *super::#name.get(),
|
||||||
|
),
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
fields.push(quote! {
|
||||||
|
pub #name: &'a mut ::#device::#name,
|
||||||
|
});
|
||||||
|
|
||||||
|
exprs.push(quote! {
|
||||||
|
#name: &mut *::#device::#name.get(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
items.push(quote! {
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
pub struct Resources<#lifetime> {
|
||||||
|
#(#fields)*
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
items.push(quote! {
|
||||||
|
impl<#lifetime> Resources<#lifetime> {
|
||||||
|
pub unsafe fn new() -> Self {
|
||||||
|
Resources {
|
||||||
|
#(#exprs)*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let priority = task.priority;
|
||||||
|
root.push(quote!{
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
mod #name {
|
||||||
|
#[deny(dead_code)]
|
||||||
|
pub const #name: u8 = #priority;
|
||||||
|
#[deny(const_err)]
|
||||||
|
const CHECK_PRIORITY: (u8, u8) = (
|
||||||
|
#priority - 1,
|
||||||
|
(1 << ::#device::NVIC_PRIO_BITS) - #priority,
|
||||||
|
);
|
||||||
|
|
||||||
|
#(#items)*
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resources(app: &App, ceilings: &Ceilings, root: &mut Vec<Tokens>) {
|
||||||
|
let krate = krate();
|
||||||
|
let device = &app.device;
|
||||||
|
|
||||||
|
let mut items = vec![];
|
||||||
|
let mut impls = vec![];
|
||||||
|
for (name, ceiling) in ceilings {
|
||||||
|
let mut impl_items = vec![];
|
||||||
|
|
||||||
|
match *ceiling {
|
||||||
|
Ceiling::Owned => continue,
|
||||||
|
Ceiling::Shared(ceiling) => {
|
||||||
|
if let Some(resource) = app.resources.get(name) {
|
||||||
|
let expr = &resource.expr;
|
||||||
|
let ty = &resource.ty;
|
||||||
|
|
||||||
|
root.push(quote! {
|
||||||
|
static #name: #krate::Resource<#ty> =
|
||||||
|
#krate::Resource::new(#expr);
|
||||||
|
});
|
||||||
|
|
||||||
|
impl_items.push(quote! {
|
||||||
|
pub fn borrow<'cs>(
|
||||||
|
&'cs self,
|
||||||
|
_cs: &'cs #krate::CriticalSection,
|
||||||
|
) -> &'cs #krate::Static<#ty> {
|
||||||
|
unsafe {
|
||||||
|
#krate::Static::ref_(&*#name.get())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn borrow_mut<'cs>(
|
||||||
|
&'cs mut self,
|
||||||
|
_cs: &'cs #krate::CriticalSection,
|
||||||
|
) -> &'cs mut #krate::Static<#ty> {
|
||||||
|
unsafe {
|
||||||
|
#krate::Static::ref_mut(&mut *#name.get())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn claim<R, F>(
|
||||||
|
&self,
|
||||||
|
t: &mut #krate::Threshold,
|
||||||
|
f: F,
|
||||||
|
) -> R
|
||||||
|
where
|
||||||
|
F: FnOnce(
|
||||||
|
&#krate::Static<#ty>,
|
||||||
|
&mut #krate::Threshold) -> R
|
||||||
|
{
|
||||||
|
unsafe {
|
||||||
|
#name.claim(
|
||||||
|
#ceiling,
|
||||||
|
#device::NVIC_PRIO_BITS,
|
||||||
|
t,
|
||||||
|
f,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn claim_mut<R, F>(
|
||||||
|
&mut self,
|
||||||
|
t: &mut #krate::Threshold,
|
||||||
|
f: F,
|
||||||
|
) -> R
|
||||||
|
where
|
||||||
|
F: FnOnce(
|
||||||
|
&mut #krate::Static<#ty>,
|
||||||
|
&mut #krate::Threshold) -> R
|
||||||
|
{
|
||||||
|
unsafe {
|
||||||
|
#name.claim_mut(
|
||||||
|
#ceiling,
|
||||||
|
#device::NVIC_PRIO_BITS,
|
||||||
|
t,
|
||||||
|
f,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
root.push(quote! {
|
||||||
|
static #name: #krate::Peripheral<#device::#name> =
|
||||||
|
#krate::Peripheral::new(#device::#name);
|
||||||
|
});
|
||||||
|
|
||||||
|
impl_items.push(quote! {
|
||||||
|
pub fn borrow<'cs>(
|
||||||
|
&'cs self,
|
||||||
|
_cs: &'cs #krate::CriticalSection,
|
||||||
|
) -> &'cs #device::#name {
|
||||||
|
unsafe {
|
||||||
|
&*#name.get()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn claim<R, F>(
|
||||||
|
&self,
|
||||||
|
t: &mut #krate::Threshold,
|
||||||
|
f: F,
|
||||||
|
) -> R
|
||||||
|
where
|
||||||
|
F: FnOnce(
|
||||||
|
&#device::#name,
|
||||||
|
&mut #krate::Threshold) -> R
|
||||||
|
{
|
||||||
|
unsafe {
|
||||||
|
#name.claim(
|
||||||
|
#ceiling,
|
||||||
|
#device::NVIC_PRIO_BITS,
|
||||||
|
t,
|
||||||
|
f,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
impls.push(quote! {
|
||||||
|
#[allow(dead_code)]
|
||||||
|
impl _resource::#name {
|
||||||
|
#(#impl_items)*
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
items.push(quote! {
|
||||||
|
#[allow(non_camel_case_types)]
|
||||||
|
pub struct #name { _0: () }
|
||||||
|
|
||||||
|
impl #name {
|
||||||
|
pub unsafe fn new() -> Self {
|
||||||
|
#name { _0: () }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
root.push(quote! {
|
||||||
|
mod _resource {
|
||||||
|
#(#items)*
|
||||||
|
}
|
||||||
|
|
||||||
|
#(#impls)*
|
||||||
|
});
|
||||||
|
}
|
48
macros/src/util.rs
Normal file
48
macros/src/util.rs
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use syn::Ident;
|
||||||
|
|
||||||
|
use syntax::App;
|
||||||
|
|
||||||
|
pub type Ceilings = HashMap<Ident, Ceiling>;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
|
pub enum Ceiling {
|
||||||
|
Owned,
|
||||||
|
Shared(u8),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Ceiling {
|
||||||
|
pub fn is_owned(&self) -> bool {
|
||||||
|
*self == Ceiling::Owned
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn compute_ceilings(app: &App) -> Ceilings {
|
||||||
|
let mut ceilings = HashMap::new();
|
||||||
|
|
||||||
|
for resource in &app.idle.resources {
|
||||||
|
ceilings.insert(resource.clone(), Ceiling::Owned);
|
||||||
|
}
|
||||||
|
|
||||||
|
for task in app.tasks.values() {
|
||||||
|
for resource in &task.resources {
|
||||||
|
if let Some(ceiling) = ceilings.get_mut(resource) {
|
||||||
|
match *ceiling {
|
||||||
|
Ceiling::Owned => *ceiling = Ceiling::Shared(task.priority),
|
||||||
|
Ceiling::Shared(old) => {
|
||||||
|
if task.priority > old {
|
||||||
|
*ceiling = Ceiling::Shared(task.priority);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ceilings.insert(resource.clone(), Ceiling::Owned);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ceilings
|
||||||
|
}
|
1110
src/lib.rs
1110
src/lib.rs
File diff suppressed because it is too large
Load diff
|
@ -1,16 +0,0 @@
|
||||||
extern crate compiletest_rs as compiletest;
|
|
||||||
|
|
||||||
use std::path::PathBuf;
|
|
||||||
|
|
||||||
use compiletest::common::Mode;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn cfail() {
|
|
||||||
let mut config = compiletest::default_config();
|
|
||||||
config.mode = Mode::CompileFail;
|
|
||||||
config.src_base = PathBuf::from(format!("tests/cfail"));
|
|
||||||
config.target_rustcflags =
|
|
||||||
Some("-L target/debug -L target/debug/deps ".to_string());
|
|
||||||
|
|
||||||
compiletest::run_tests(&config);
|
|
||||||
}
|
|
|
@ -1,35 +0,0 @@
|
||||||
extern crate cortex_m_rtfm as rtfm;
|
|
||||||
|
|
||||||
use rtfm::{C1, C2, C3, C4, C5, P2, Resource, T2};
|
|
||||||
|
|
||||||
static R1: Resource<i32, C4> = Resource::new(0);
|
|
||||||
static R2: Resource<i32, C3> = Resource::new(0);
|
|
||||||
static R3: Resource<i32, C4> = Resource::new(0);
|
|
||||||
static R4: Resource<i32, C5> = Resource::new(0);
|
|
||||||
static R5: Resource<i32, C1> = Resource::new(0);
|
|
||||||
static R6: Resource<i32, C2> = Resource::new(0);
|
|
||||||
|
|
||||||
fn j1(prio: P2, thr: T2) {
|
|
||||||
thr.raise(
|
|
||||||
&R1, |thr| {
|
|
||||||
// NOTE PT = Preemption Threshold, TP = Task Priority
|
|
||||||
|
|
||||||
// CAN access a resource with ceiling RC when PT > RC
|
|
||||||
let r2 = R2.access(&prio, thr);
|
|
||||||
|
|
||||||
// CAN access a resource with ceiling RC when PT == RC
|
|
||||||
let r3 = R3.access(&prio, thr);
|
|
||||||
|
|
||||||
// CAN'T access a resource with ceiling RC when PT < RC
|
|
||||||
let r4 = R4.access(&prio, thr);
|
|
||||||
//~^ error
|
|
||||||
|
|
||||||
// CAN'T access a resource with ceiling RC when RC < TP
|
|
||||||
let r5 = R5.access(&prio, thr);
|
|
||||||
//~^ error
|
|
||||||
|
|
||||||
// CAN access a resource with ceiling RC when RC == tP
|
|
||||||
let r6 = R6.access(&prio, thr);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
|
@ -1,29 +0,0 @@
|
||||||
extern crate cortex_m_rtfm as rtfm;
|
|
||||||
|
|
||||||
use rtfm::{C2, C3, P0, P2, Resource, T2};
|
|
||||||
|
|
||||||
static R1: Resource<(), C3> = Resource::new(());
|
|
||||||
|
|
||||||
fn j1(prio: P2, thr: T2) {
|
|
||||||
let t3 = thr.raise(
|
|
||||||
&R1, |thr| {
|
|
||||||
// forbidden: ceiling token can't outlive the critical section
|
|
||||||
thr //~ error
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// Would be bad: lockless access to a resource with ceiling = 3
|
|
||||||
let r2 = R1.access(&prio, t3);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn j2(prio: P0) {
|
|
||||||
let c16 = rtfm::atomic(
|
|
||||||
|c16| {
|
|
||||||
// forbidden: ceiling token can't outlive the critical section
|
|
||||||
c16 //~ error
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
// Would be bad: lockless access to a resource with ceiling = 16
|
|
||||||
let r1 = R1.access(&prio, c16);
|
|
||||||
}
|
|
|
@ -1,36 +0,0 @@
|
||||||
extern crate cortex_m_rtfm as rtfm;
|
|
||||||
|
|
||||||
use rtfm::{CMax, C2, P1, P2, P3, PMax, Resource, T1, T2, T3, TMax};
|
|
||||||
|
|
||||||
static R1: Resource<i32, C2> = Resource::new(0);
|
|
||||||
|
|
||||||
// You don't need to raise the ceiling to access a resource with ceiling equal
|
|
||||||
// to the task priority.
|
|
||||||
fn j1(prio: P2, thr: T2) {
|
|
||||||
thr.raise(&R1, |_| {});
|
|
||||||
//~^ error
|
|
||||||
|
|
||||||
// OK
|
|
||||||
let r1 = R1.access(&prio, &thr);
|
|
||||||
}
|
|
||||||
|
|
||||||
// You CAN access a resource with ceiling C from a task with priority P if C > P
|
|
||||||
// if you raise the preemption threshold first
|
|
||||||
fn j2(prio: P1, thr: T1) {
|
|
||||||
// OK
|
|
||||||
thr.raise(&R1, |thr| { let r1 = R1.access(&prio, thr); })
|
|
||||||
}
|
|
||||||
|
|
||||||
static R2: Resource<i32, CMax> = Resource::new(0);
|
|
||||||
|
|
||||||
// Tasks with priority less than P16 can't access a resource with ceiling CMax
|
|
||||||
fn j4(prio: P1, thr: T1) {
|
|
||||||
thr.raise(&R2, |thr| {});
|
|
||||||
//~^ error
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only tasks with priority P16 can directly access a resource with ceiling CMax
|
|
||||||
fn j5(prio: PMax, thr: TMax) {
|
|
||||||
// OK
|
|
||||||
let r2 = R2.access(&prio, &thr);
|
|
||||||
}
|
|
|
@ -1,68 +0,0 @@
|
||||||
// error-pattern: has already been defined
|
|
||||||
|
|
||||||
#![feature(used)]
|
|
||||||
|
|
||||||
#[macro_use]
|
|
||||||
extern crate cortex_m_rtfm as rtfm;
|
|
||||||
|
|
||||||
use rtfm::{P0, P1, T0, TMax};
|
|
||||||
use device::interrupt::Exti0;
|
|
||||||
|
|
||||||
peripherals!(device, {
|
|
||||||
GPIOA: Peripheral {
|
|
||||||
register_block: Gpioa,
|
|
||||||
ceiling: C1,
|
|
||||||
},
|
|
||||||
// WRONG: peripheral alias
|
|
||||||
GPIOA: Peripheral {
|
|
||||||
register_block: Gpioa,
|
|
||||||
ceiling: C2,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
tasks!(device, {});
|
|
||||||
|
|
||||||
fn init(_: P0, _: &TMax) {}
|
|
||||||
|
|
||||||
fn idle(_: P0, _: T0) -> ! {
|
|
||||||
loop {}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn j1(_task: Exti0, _prio: P1) {}
|
|
||||||
|
|
||||||
// fake device crate
|
|
||||||
extern crate core;
|
|
||||||
extern crate cortex_m;
|
|
||||||
|
|
||||||
mod device {
|
|
||||||
use cortex_m::peripheral::Peripheral;
|
|
||||||
|
|
||||||
pub const GPIOA: Peripheral<Gpioa> = unsafe { Peripheral::new(0x0) };
|
|
||||||
|
|
||||||
pub struct Gpioa;
|
|
||||||
|
|
||||||
pub mod interrupt {
|
|
||||||
use cortex_m::interrupt::Nr;
|
|
||||||
|
|
||||||
extern "C" fn default_handler<T>(_: T) {}
|
|
||||||
|
|
||||||
pub struct Handlers {
|
|
||||||
pub Exti0: extern "C" fn(Exti0),
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Exti0;
|
|
||||||
|
|
||||||
pub enum Interrupt {
|
|
||||||
Exti0,
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl Nr for Interrupt {
|
|
||||||
fn nr(&self) -> u8 {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const DEFAULT_HANDLERS: Handlers =
|
|
||||||
Handlers { Exti0: default_handler };
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,74 +0,0 @@
|
||||||
// error-pattern: symbol `GPIOA` is already defined
|
|
||||||
|
|
||||||
#![feature(const_fn)]
|
|
||||||
#![feature(used)]
|
|
||||||
|
|
||||||
#[macro_use]
|
|
||||||
extern crate cortex_m_rtfm as rtfm;
|
|
||||||
|
|
||||||
use rtfm::{P0, P1, T0, TMax};
|
|
||||||
use device::interrupt::Exti0;
|
|
||||||
|
|
||||||
peripherals!(device, {
|
|
||||||
GPIOA: Peripheral {
|
|
||||||
register_block: Gpioa,
|
|
||||||
ceiling: C1,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
mod foo {
|
|
||||||
// WRONG: peripheral alias
|
|
||||||
peripherals!(device, {
|
|
||||||
GPIOA: Peripheral {
|
|
||||||
register_block: Gpioa,
|
|
||||||
ceiling: C2,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks!(device, {});
|
|
||||||
|
|
||||||
fn init(_: P0, _: &TMax) {}
|
|
||||||
|
|
||||||
fn idle(_: P0, _: T0) -> ! {
|
|
||||||
loop {}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn j1(_task: Exti0, _prio: P1) {}
|
|
||||||
|
|
||||||
// fake device crate
|
|
||||||
extern crate core;
|
|
||||||
extern crate cortex_m;
|
|
||||||
|
|
||||||
mod device {
|
|
||||||
use cortex_m::peripheral::Peripheral;
|
|
||||||
|
|
||||||
pub const GPIOA: Peripheral<Gpioa> = unsafe { Peripheral::new(0x0) };
|
|
||||||
|
|
||||||
pub struct Gpioa;
|
|
||||||
|
|
||||||
pub mod interrupt {
|
|
||||||
use cortex_m::interrupt::Nr;
|
|
||||||
|
|
||||||
extern "C" fn default_handler<T>(_: T) {}
|
|
||||||
|
|
||||||
pub struct Handlers {
|
|
||||||
pub Exti0: extern "C" fn(Exti0),
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Exti0;
|
|
||||||
|
|
||||||
pub enum Interrupt {
|
|
||||||
Exti0,
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl Nr for Interrupt {
|
|
||||||
fn nr(&self) -> u8 {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const DEFAULT_HANDLERS: Handlers =
|
|
||||||
Handlers { Exti0: default_handler };
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,42 +0,0 @@
|
||||||
extern crate cortex_m_rtfm as rtfm;
|
|
||||||
|
|
||||||
use rtfm::{C2, P1, P3, Resource, T1, T3};
|
|
||||||
|
|
||||||
static R1: Resource<i32, C2> = Resource::new(0);
|
|
||||||
|
|
||||||
fn j1(prio: P1, thr: T1) {
|
|
||||||
thr.raise(
|
|
||||||
&R1, |thr| {
|
|
||||||
let r1 = R1.access(&prio, thr);
|
|
||||||
|
|
||||||
// `j2` preempts this critical section
|
|
||||||
rtfm::request(j2);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn j2(_task: Task, prio: P3, thr: T3) {
|
|
||||||
rtfm::atomic(
|
|
||||||
|thr| {
|
|
||||||
// OK C2 (R1's ceiling) <= T16 (preemption threshold)
|
|
||||||
// BAD C2 (R1's ceiling) < P3 (j2's priority)
|
|
||||||
let r1 = R1.access(&prio, &thr);
|
|
||||||
//~^ error
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// glue
|
|
||||||
extern crate cortex_m;
|
|
||||||
|
|
||||||
use cortex_m::ctxt::Context;
|
|
||||||
use cortex_m::interrupt::Nr;
|
|
||||||
|
|
||||||
struct Task;
|
|
||||||
|
|
||||||
unsafe impl Context for Task {}
|
|
||||||
unsafe impl Nr for Task {
|
|
||||||
fn nr(&self) -> u8 {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,43 +0,0 @@
|
||||||
extern crate cortex_m_rtfm as rtfm;
|
|
||||||
|
|
||||||
use rtfm::{C2, C4, P1, P3, Resource, T1, T3};
|
|
||||||
|
|
||||||
static R1: Resource<i32, C2> = Resource::new(0);
|
|
||||||
static R2: Resource<i32, C4> = Resource::new(0);
|
|
||||||
|
|
||||||
fn j1(prio: P1, thr: T1) {
|
|
||||||
thr.raise(
|
|
||||||
&R1, |thr| {
|
|
||||||
let r1 = R1.access(&prio, thr);
|
|
||||||
|
|
||||||
// `j2` preempts this critical section
|
|
||||||
rtfm::request(j2);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn j2(_task: Task, prio: P3, thr: T3) {
|
|
||||||
thr.raise(
|
|
||||||
&R2, |thr| {
|
|
||||||
// OK C2 (R1's ceiling) <= T4 (preemption threshold)
|
|
||||||
// BAD C2 (R1's ceiling) < P3 (j2's priority)
|
|
||||||
let r1 = R1.access(&prio, thr);
|
|
||||||
//~^ error
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// glue
|
|
||||||
extern crate cortex_m;
|
|
||||||
|
|
||||||
use cortex_m::ctxt::Context;
|
|
||||||
use cortex_m::interrupt::Nr;
|
|
||||||
|
|
||||||
struct Task;
|
|
||||||
|
|
||||||
unsafe impl Context for Task {}
|
|
||||||
unsafe impl Nr for Task {
|
|
||||||
fn nr(&self) -> u8 {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,24 +0,0 @@
|
||||||
extern crate cortex_m_rtfm as rtfm;
|
|
||||||
|
|
||||||
use rtfm::{C2, CMax, P1, P3, Resource, T1, T3};
|
|
||||||
|
|
||||||
static R1: Resource<i32, C2> = Resource::new(0);
|
|
||||||
|
|
||||||
// You CAN'T use `raise` to lower the preemption level
|
|
||||||
fn j1(prio: P3, thr: T3) {
|
|
||||||
thr.raise(&R1, |thr| {});
|
|
||||||
//~^ error
|
|
||||||
}
|
|
||||||
|
|
||||||
static R2: Resource<i32, CMax> = Resource::new(0);
|
|
||||||
|
|
||||||
// You CAN'T `raise` the preemption level to the maximum
|
|
||||||
fn j2(prio: P1, thr: T1) {
|
|
||||||
thr.raise(&R2, |thr| {});
|
|
||||||
//~^ error
|
|
||||||
|
|
||||||
// Instead use `rtfm::atomic` to access a resource with ceiling C16
|
|
||||||
rtfm::atomic(|thr| {
|
|
||||||
let r2 = R2.access(&prio, thr);
|
|
||||||
});
|
|
||||||
}
|
|
|
@ -1,92 +0,0 @@
|
||||||
// error-pattern: expected struct `typenum::Equal`, found struct `typenum::Greater`
|
|
||||||
|
|
||||||
#![feature(used)]
|
|
||||||
|
|
||||||
#[macro_use]
|
|
||||||
extern crate cortex_m_rtfm as rtfm;
|
|
||||||
|
|
||||||
use rtfm::{P0, P1, T0, T1, TMax};
|
|
||||||
use device::interrupt::Exti0;
|
|
||||||
|
|
||||||
// WRONG: Tasks can't have a priority of 0.
|
|
||||||
// Only idle and init can have a priority of 0.
|
|
||||||
tasks!(device, {
|
|
||||||
j1: Task {
|
|
||||||
interrupt: Exti0,
|
|
||||||
priority: P0,
|
|
||||||
enabled: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
fn init(_: P0, _: &TMax) {}
|
|
||||||
|
|
||||||
fn idle(_: P0, _: T0) -> ! {
|
|
||||||
loop {}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn j1(_task: Exti0, _prio: P1, _thr: T1) {}
|
|
||||||
|
|
||||||
// fake device crate
|
|
||||||
extern crate core;
|
|
||||||
extern crate cortex_m;
|
|
||||||
|
|
||||||
mod device {
|
|
||||||
pub mod interrupt {
|
|
||||||
use cortex_m::ctxt::Context;
|
|
||||||
use cortex_m::interrupt::Nr;
|
|
||||||
|
|
||||||
extern "C" fn default_handler<T>(_: T) {}
|
|
||||||
|
|
||||||
pub struct Handlers {
|
|
||||||
pub Exti0: extern "C" fn(Exti0),
|
|
||||||
pub Exti1: extern "C" fn(Exti1),
|
|
||||||
pub Exti2: extern "C" fn(Exti2),
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Exti0;
|
|
||||||
pub struct Exti1;
|
|
||||||
pub struct Exti2;
|
|
||||||
|
|
||||||
pub enum Interrupt {
|
|
||||||
Exti0,
|
|
||||||
Exti1,
|
|
||||||
Exti2,
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl Nr for Interrupt {
|
|
||||||
fn nr(&self) -> u8 {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl Context for Exti0 {}
|
|
||||||
|
|
||||||
unsafe impl Nr for Exti0 {
|
|
||||||
fn nr(&self) -> u8 {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl Context for Exti1 {}
|
|
||||||
|
|
||||||
unsafe impl Nr for Exti1 {
|
|
||||||
fn nr(&self) -> u8 {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl Context for Exti2 {}
|
|
||||||
|
|
||||||
unsafe impl Nr for Exti2 {
|
|
||||||
fn nr(&self) -> u8 {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const DEFAULT_HANDLERS: Handlers = Handlers {
|
|
||||||
Exti0: default_handler,
|
|
||||||
Exti1: default_handler,
|
|
||||||
Exti2: default_handler,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,98 +0,0 @@
|
||||||
// error-pattern: field `Exti0` specified more than once
|
|
||||||
|
|
||||||
#![feature(used)]
|
|
||||||
|
|
||||||
#[macro_use]
|
|
||||||
extern crate cortex_m_rtfm as rtfm;
|
|
||||||
|
|
||||||
use rtfm::{P0, P1, P2, T0, T1, T2, TMax};
|
|
||||||
use device::interrupt::{Exti0, Exti1};
|
|
||||||
|
|
||||||
// WRONG: Two tasks mapped to the same interrupt handler
|
|
||||||
tasks!(device, {
|
|
||||||
j1: Task {
|
|
||||||
interrupt: Exti0,
|
|
||||||
priority: P1,
|
|
||||||
enabled: true,
|
|
||||||
},
|
|
||||||
j2: Task {
|
|
||||||
interrupt: Exti0,
|
|
||||||
priority: P2,
|
|
||||||
enabled: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
fn init(_: P0, _: &TMax) {}
|
|
||||||
|
|
||||||
fn idle(_: P0, _: T0) -> ! {
|
|
||||||
loop {}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn j1(_task: Exti0, _prio: P1, _thr: T1) {}
|
|
||||||
|
|
||||||
fn j2(_task: Exti0, _prio: P2, _thr: T2) {}
|
|
||||||
|
|
||||||
// fake device crate
|
|
||||||
extern crate core;
|
|
||||||
extern crate cortex_m;
|
|
||||||
|
|
||||||
mod device {
|
|
||||||
pub mod interrupt {
|
|
||||||
use cortex_m::ctxt::Context;
|
|
||||||
use cortex_m::interrupt::Nr;
|
|
||||||
|
|
||||||
extern "C" fn default_handler<T>(_: T) {}
|
|
||||||
|
|
||||||
pub struct Handlers {
|
|
||||||
pub Exti0: extern "C" fn(Exti0),
|
|
||||||
pub Exti1: extern "C" fn(Exti1),
|
|
||||||
pub Exti2: extern "C" fn(Exti2),
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Exti0;
|
|
||||||
pub struct Exti1;
|
|
||||||
pub struct Exti2;
|
|
||||||
|
|
||||||
pub enum Interrupt {
|
|
||||||
Exti0,
|
|
||||||
Exti1,
|
|
||||||
Exti2,
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl Nr for Interrupt {
|
|
||||||
fn nr(&self) -> u8 {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl Context for Exti0 {}
|
|
||||||
|
|
||||||
unsafe impl Nr for Exti0 {
|
|
||||||
fn nr(&self) -> u8 {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl Context for Exti1 {}
|
|
||||||
|
|
||||||
unsafe impl Nr for Exti1 {
|
|
||||||
fn nr(&self) -> u8 {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl Context for Exti2 {}
|
|
||||||
|
|
||||||
unsafe impl Nr for Exti2 {
|
|
||||||
fn nr(&self) -> u8 {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const DEFAULT_HANDLERS: Handlers = Handlers {
|
|
||||||
Exti0: default_handler,
|
|
||||||
Exti1: default_handler,
|
|
||||||
Exti2: default_handler,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,89 +0,0 @@
|
||||||
// error-pattern: mismatched types
|
|
||||||
|
|
||||||
#![feature(used)]
|
|
||||||
|
|
||||||
#[macro_use]
|
|
||||||
extern crate cortex_m_rtfm as rtfm;
|
|
||||||
|
|
||||||
use device::interrupt::Exti0;
|
|
||||||
use rtfm::{P0, P1, T0, T1, TMax};
|
|
||||||
|
|
||||||
tasks!(device, {
|
|
||||||
j1: Task {
|
|
||||||
interrupt: Exti0,
|
|
||||||
priority: P1,
|
|
||||||
enabled: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
fn init(_: P0, _: &TMax) {}
|
|
||||||
|
|
||||||
// WRONG. `idle` must have signature `fn(P0, C0) -> !`
|
|
||||||
fn idle(_: P0, _: T0) {}
|
|
||||||
|
|
||||||
fn j1(_task: Exti0, _prio: P1, _thr: T1) {}
|
|
||||||
|
|
||||||
// fake device crate
|
|
||||||
extern crate core;
|
|
||||||
extern crate cortex_m;
|
|
||||||
|
|
||||||
mod device {
|
|
||||||
pub mod interrupt {
|
|
||||||
use cortex_m::ctxt::Context;
|
|
||||||
use cortex_m::interrupt::Nr;
|
|
||||||
|
|
||||||
extern "C" fn default_handler<T>(_: T) {}
|
|
||||||
|
|
||||||
pub struct Handlers {
|
|
||||||
pub Exti0: extern "C" fn(Exti0),
|
|
||||||
pub Exti1: extern "C" fn(Exti1),
|
|
||||||
pub Exti2: extern "C" fn(Exti2),
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Exti0;
|
|
||||||
pub struct Exti1;
|
|
||||||
pub struct Exti2;
|
|
||||||
|
|
||||||
pub enum Interrupt {
|
|
||||||
Exti0,
|
|
||||||
Exti1,
|
|
||||||
Exti2,
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl Nr for Interrupt {
|
|
||||||
fn nr(&self) -> u8 {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl Context for Exti0 {}
|
|
||||||
|
|
||||||
unsafe impl Nr for Exti0 {
|
|
||||||
fn nr(&self) -> u8 {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl Context for Exti1 {}
|
|
||||||
|
|
||||||
unsafe impl Nr for Exti1 {
|
|
||||||
fn nr(&self) -> u8 {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl Context for Exti2 {}
|
|
||||||
|
|
||||||
unsafe impl Nr for Exti2 {
|
|
||||||
fn nr(&self) -> u8 {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const DEFAULT_HANDLERS: Handlers = Handlers {
|
|
||||||
Exti0: default_handler,
|
|
||||||
Exti1: default_handler,
|
|
||||||
Exti2: default_handler,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,91 +0,0 @@
|
||||||
// error-pattern: mismatched types
|
|
||||||
|
|
||||||
#![feature(used)]
|
|
||||||
|
|
||||||
#[macro_use]
|
|
||||||
extern crate cortex_m_rtfm as rtfm;
|
|
||||||
|
|
||||||
use rtfm::{P0, P1, T0, T1, TMax};
|
|
||||||
use device::interrupt::Exti0;
|
|
||||||
|
|
||||||
tasks!(device, {
|
|
||||||
j1: Task {
|
|
||||||
interrupt: Exti0,
|
|
||||||
priority: P1,
|
|
||||||
enabled: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
// WRONG. `init` must have signature `fn(P0, &TMax)`
|
|
||||||
fn init(_: P0, _: &T1) {}
|
|
||||||
|
|
||||||
fn idle(_: P0, _: T0) -> ! {
|
|
||||||
loop {}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn j1(_task: Exti0, _prio: P1, _thr: T1) {}
|
|
||||||
|
|
||||||
// fake device crate
|
|
||||||
extern crate core;
|
|
||||||
extern crate cortex_m;
|
|
||||||
|
|
||||||
mod device {
|
|
||||||
pub mod interrupt {
|
|
||||||
use cortex_m::ctxt::Context;
|
|
||||||
use cortex_m::interrupt::Nr;
|
|
||||||
|
|
||||||
extern "C" fn default_handler<T>(_: T) {}
|
|
||||||
|
|
||||||
pub struct Handlers {
|
|
||||||
pub Exti0: extern "C" fn(Exti0),
|
|
||||||
pub Exti1: extern "C" fn(Exti1),
|
|
||||||
pub Exti2: extern "C" fn(Exti2),
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Exti0;
|
|
||||||
pub struct Exti1;
|
|
||||||
pub struct Exti2;
|
|
||||||
|
|
||||||
pub enum Interrupt {
|
|
||||||
Exti0,
|
|
||||||
Exti1,
|
|
||||||
Exti2,
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl Nr for Interrupt {
|
|
||||||
fn nr(&self) -> u8 {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl Context for Exti0 {}
|
|
||||||
|
|
||||||
unsafe impl Nr for Exti0 {
|
|
||||||
fn nr(&self) -> u8 {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl Context for Exti1 {}
|
|
||||||
|
|
||||||
unsafe impl Nr for Exti1 {
|
|
||||||
fn nr(&self) -> u8 {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl Context for Exti2 {}
|
|
||||||
|
|
||||||
unsafe impl Nr for Exti2 {
|
|
||||||
fn nr(&self) -> u8 {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const DEFAULT_HANDLERS: Handlers = Handlers {
|
|
||||||
Exti0: default_handler,
|
|
||||||
Exti1: default_handler,
|
|
||||||
Exti2: default_handler,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,91 +0,0 @@
|
||||||
// error-pattern: mismatched types
|
|
||||||
|
|
||||||
#![feature(used)]
|
|
||||||
|
|
||||||
#[macro_use]
|
|
||||||
extern crate cortex_m_rtfm as rtfm;
|
|
||||||
|
|
||||||
use device::interrupt::Exti0;
|
|
||||||
use rtfm::{P0, P1, P2, T0, T1, T2, TMax};
|
|
||||||
|
|
||||||
tasks!(device, {
|
|
||||||
j1: Task {
|
|
||||||
interrupt: Exti0,
|
|
||||||
priority: P1,
|
|
||||||
enabled: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
fn init(_: P0, _: &TMax) {}
|
|
||||||
|
|
||||||
fn idle(_: P0, _: T0) -> ! {
|
|
||||||
loop {}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wrong priority token. Declared P1, got P2
|
|
||||||
fn j1(_task: Exti0, _prio: P2, _thr: T2) {}
|
|
||||||
|
|
||||||
// fake device crate
|
|
||||||
extern crate core;
|
|
||||||
extern crate cortex_m;
|
|
||||||
|
|
||||||
mod device {
|
|
||||||
pub mod interrupt {
|
|
||||||
use cortex_m::ctxt::Context;
|
|
||||||
use cortex_m::interrupt::Nr;
|
|
||||||
|
|
||||||
extern "C" fn default_handler<T>(_: T) {}
|
|
||||||
|
|
||||||
pub struct Handlers {
|
|
||||||
pub Exti0: extern "C" fn(Exti0),
|
|
||||||
pub Exti1: extern "C" fn(Exti1),
|
|
||||||
pub Exti2: extern "C" fn(Exti2),
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Exti0;
|
|
||||||
pub struct Exti1;
|
|
||||||
pub struct Exti2;
|
|
||||||
|
|
||||||
pub enum Interrupt {
|
|
||||||
Exti0,
|
|
||||||
Exti1,
|
|
||||||
Exti2,
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl Nr for Interrupt {
|
|
||||||
fn nr(&self) -> u8 {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl Context for Exti0 {}
|
|
||||||
|
|
||||||
unsafe impl Nr for Exti0 {
|
|
||||||
fn nr(&self) -> u8 {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl Context for Exti1 {}
|
|
||||||
|
|
||||||
unsafe impl Nr for Exti1 {
|
|
||||||
fn nr(&self) -> u8 {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl Context for Exti2 {}
|
|
||||||
|
|
||||||
unsafe impl Nr for Exti2 {
|
|
||||||
fn nr(&self) -> u8 {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const DEFAULT_HANDLERS: Handlers = Handlers {
|
|
||||||
Exti0: default_handler,
|
|
||||||
Exti1: default_handler,
|
|
||||||
Exti2: default_handler,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,91 +0,0 @@
|
||||||
// error-pattern: mismatched types
|
|
||||||
|
|
||||||
#![feature(used)]
|
|
||||||
|
|
||||||
#[macro_use]
|
|
||||||
extern crate cortex_m_rtfm as rtfm;
|
|
||||||
|
|
||||||
use device::interrupt::{Exti0, Exti1};
|
|
||||||
use rtfm::{P0, P1, T0, T1, TMax};
|
|
||||||
|
|
||||||
tasks!(device, {
|
|
||||||
j1: Task {
|
|
||||||
interrupt: Exti0,
|
|
||||||
priority: P1,
|
|
||||||
enabled: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
fn init(_: P0, _: &TMax) {}
|
|
||||||
|
|
||||||
fn idle(_: P0, _: T0) -> ! {
|
|
||||||
loop {}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wrong task token. Declared Exti0, got Exti1
|
|
||||||
fn j1(_task: Exti1, _prio: P1, _thr: T1) {}
|
|
||||||
|
|
||||||
// fake device crate
|
|
||||||
extern crate core;
|
|
||||||
extern crate cortex_m;
|
|
||||||
|
|
||||||
mod device {
|
|
||||||
pub mod interrupt {
|
|
||||||
use cortex_m::ctxt::Context;
|
|
||||||
use cortex_m::interrupt::Nr;
|
|
||||||
|
|
||||||
extern "C" fn default_handler<T>(_: T) {}
|
|
||||||
|
|
||||||
pub struct Handlers {
|
|
||||||
pub Exti0: extern "C" fn(Exti0),
|
|
||||||
pub Exti1: extern "C" fn(Exti1),
|
|
||||||
pub Exti2: extern "C" fn(Exti2),
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Exti0;
|
|
||||||
pub struct Exti1;
|
|
||||||
pub struct Exti2;
|
|
||||||
|
|
||||||
pub enum Interrupt {
|
|
||||||
Exti0,
|
|
||||||
Exti1,
|
|
||||||
Exti2,
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl Nr for Interrupt {
|
|
||||||
fn nr(&self) -> u8 {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl Context for Exti0 {}
|
|
||||||
|
|
||||||
unsafe impl Nr for Exti0 {
|
|
||||||
fn nr(&self) -> u8 {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl Context for Exti1 {}
|
|
||||||
|
|
||||||
unsafe impl Nr for Exti1 {
|
|
||||||
fn nr(&self) -> u8 {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl Context for Exti2 {}
|
|
||||||
|
|
||||||
unsafe impl Nr for Exti2 {
|
|
||||||
fn nr(&self) -> u8 {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const DEFAULT_HANDLERS: Handlers = Handlers {
|
|
||||||
Exti0: default_handler,
|
|
||||||
Exti1: default_handler,
|
|
||||||
Exti2: default_handler,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,91 +0,0 @@
|
||||||
// error-pattern: mismatched types
|
|
||||||
|
|
||||||
#![feature(used)]
|
|
||||||
|
|
||||||
#[macro_use]
|
|
||||||
extern crate cortex_m_rtfm as rtfm;
|
|
||||||
|
|
||||||
use rtfm::{C2, P0, P1, T0, T2, TMax};
|
|
||||||
use device::interrupt::Exti0;
|
|
||||||
|
|
||||||
tasks!(device, {
|
|
||||||
j1: Task {
|
|
||||||
interrupt: Exti0,
|
|
||||||
priority: P1,
|
|
||||||
enabled: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
fn init(_: P0, _: &TMax) {}
|
|
||||||
|
|
||||||
fn idle(_: P0, _: T0) -> ! {
|
|
||||||
loop {}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wrong ceiling token. `prio` and `thr` must match in levels
|
|
||||||
fn j1(_task: Exti0, _prio: P1, _thr: T2) {}
|
|
||||||
|
|
||||||
// fake device crate
|
|
||||||
extern crate core;
|
|
||||||
extern crate cortex_m;
|
|
||||||
|
|
||||||
mod device {
|
|
||||||
pub mod interrupt {
|
|
||||||
use cortex_m::ctxt::Context;
|
|
||||||
use cortex_m::interrupt::Nr;
|
|
||||||
|
|
||||||
extern "C" fn default_handler<T>(_: T) {}
|
|
||||||
|
|
||||||
pub struct Handlers {
|
|
||||||
pub Exti0: extern "C" fn(Exti0),
|
|
||||||
pub Exti1: extern "C" fn(Exti1),
|
|
||||||
pub Exti2: extern "C" fn(Exti2),
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Exti0;
|
|
||||||
pub struct Exti1;
|
|
||||||
pub struct Exti2;
|
|
||||||
|
|
||||||
pub enum Interrupt {
|
|
||||||
Exti0,
|
|
||||||
Exti1,
|
|
||||||
Exti2,
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl Nr for Interrupt {
|
|
||||||
fn nr(&self) -> u8 {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl Context for Exti0 {}
|
|
||||||
|
|
||||||
unsafe impl Nr for Exti0 {
|
|
||||||
fn nr(&self) -> u8 {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl Context for Exti1 {}
|
|
||||||
|
|
||||||
unsafe impl Nr for Exti1 {
|
|
||||||
fn nr(&self) -> u8 {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl Context for Exti2 {}
|
|
||||||
|
|
||||||
unsafe impl Nr for Exti2 {
|
|
||||||
fn nr(&self) -> u8 {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const DEFAULT_HANDLERS: Handlers = Handlers {
|
|
||||||
Exti0: default_handler,
|
|
||||||
Exti1: default_handler,
|
|
||||||
Exti2: default_handler,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,159 +0,0 @@
|
||||||
#![feature(const_fn)]
|
|
||||||
#![feature(optin_builtin_traits)]
|
|
||||||
#![feature(used)]
|
|
||||||
|
|
||||||
#[macro_use]
|
|
||||||
extern crate cortex_m_rtfm as rtfm;
|
|
||||||
|
|
||||||
use core::cell::RefCell;
|
|
||||||
|
|
||||||
use rtfm::{C2, Local, P0, P1, P2, Resource, T0, T1, T2, TMax};
|
|
||||||
use device::interrupt::{Exti0, Exti1};
|
|
||||||
|
|
||||||
tasks!(device, {
|
|
||||||
t1: Task {
|
|
||||||
interrupt: Exti0,
|
|
||||||
priority: P1,
|
|
||||||
enabled: true,
|
|
||||||
},
|
|
||||||
t2: Task {
|
|
||||||
interrupt: Exti1,
|
|
||||||
priority: P2,
|
|
||||||
enabled: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
fn init(_: P0, _: &TMax) {}
|
|
||||||
|
|
||||||
fn idle(_: P0, _: T0) -> ! {
|
|
||||||
rtfm::request(t1);
|
|
||||||
rtfm::request(t1);
|
|
||||||
|
|
||||||
loop {}
|
|
||||||
}
|
|
||||||
|
|
||||||
static CHANNEL: Resource<RefCell<Option<Exti0>>, C2> = {
|
|
||||||
//~^ error: Send
|
|
||||||
Resource::new(RefCell::new(None))
|
|
||||||
};
|
|
||||||
|
|
||||||
static LOCAL: Local<i32, Exti0> = Local::new(0);
|
|
||||||
|
|
||||||
fn t1(mut task: Exti0, ref priority: P1, ref threshold: T1) {
|
|
||||||
// First run
|
|
||||||
static FIRST: Local<bool, Exti0> = Local::new(true);
|
|
||||||
|
|
||||||
let first = *FIRST.borrow(&task);
|
|
||||||
|
|
||||||
if first {
|
|
||||||
// toggle
|
|
||||||
*FIRST.borrow_mut(&mut task) = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if first {
|
|
||||||
threshold.raise(
|
|
||||||
&CHANNEL, move |threshold| {
|
|
||||||
let channel = CHANNEL.access(priority, threshold);
|
|
||||||
|
|
||||||
// BAD: give up task token
|
|
||||||
*channel.borrow_mut() = Some(task);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let _local = LOCAL.borrow_mut(&mut task);
|
|
||||||
|
|
||||||
// ..
|
|
||||||
|
|
||||||
// `t2` will preempt `t1`
|
|
||||||
rtfm::request(t2);
|
|
||||||
|
|
||||||
// ..
|
|
||||||
|
|
||||||
// `LOCAL` mutably borrowed up to this point
|
|
||||||
}
|
|
||||||
|
|
||||||
fn t2(_task: Exti1, ref priority: P2, ref threshold: T2) {
|
|
||||||
let channel = CHANNEL.access(priority, threshold);
|
|
||||||
let mut channel = channel.borrow_mut();
|
|
||||||
|
|
||||||
if let Some(mut other_task) = channel.take() {
|
|
||||||
// BAD: `t2` has access to `t1`'s task token
|
|
||||||
// so it can now mutably access local while `t1` is also using it
|
|
||||||
let _local = LOCAL.borrow_mut(&mut other_task);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// fake device crate
|
|
||||||
extern crate core;
|
|
||||||
extern crate cortex_m;
|
|
||||||
|
|
||||||
mod device {
|
|
||||||
pub mod interrupt {
|
|
||||||
use cortex_m::ctxt::Context;
|
|
||||||
use cortex_m::interrupt::Nr;
|
|
||||||
|
|
||||||
extern "C" fn default_handler<T>(_: T) {}
|
|
||||||
|
|
||||||
pub struct Handlers {
|
|
||||||
pub Exti0: extern "C" fn(Exti0),
|
|
||||||
pub Exti1: extern "C" fn(Exti1),
|
|
||||||
pub Exti2: extern "C" fn(Exti2),
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Exti0;
|
|
||||||
pub struct Exti1;
|
|
||||||
pub struct Exti2;
|
|
||||||
|
|
||||||
pub enum Interrupt {
|
|
||||||
Exti0,
|
|
||||||
Exti1,
|
|
||||||
Exti2,
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl Nr for Interrupt {
|
|
||||||
fn nr(&self) -> u8 {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl Context for Exti0 {}
|
|
||||||
|
|
||||||
unsafe impl Nr for Exti0 {
|
|
||||||
fn nr(&self) -> u8 {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl !Send for Exti0 {}
|
|
||||||
|
|
||||||
unsafe impl Context for Exti1 {}
|
|
||||||
|
|
||||||
unsafe impl Nr for Exti1 {
|
|
||||||
fn nr(&self) -> u8 {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl !Send for Exti1 {}
|
|
||||||
|
|
||||||
unsafe impl Context for Exti2 {}
|
|
||||||
|
|
||||||
unsafe impl Nr for Exti2 {
|
|
||||||
fn nr(&self) -> u8 {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl !Send for Exti2 {}
|
|
||||||
|
|
||||||
pub const DEFAULT_HANDLERS: Handlers = Handlers {
|
|
||||||
Exti0: default_handler,
|
|
||||||
Exti1: default_handler,
|
|
||||||
Exti2: default_handler,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in a new issue