Allow initialization of resources in init.

This commit is contained in:
Jonas Schievink 2017-09-03 18:05:48 +02:00
parent 27fc7e99d2
commit 7ebba49644
4 changed files with 89 additions and 31 deletions

View file

@ -14,9 +14,10 @@ version = "0.2.1"
[dependencies] [dependencies]
cortex-m = "0.3.1" cortex-m = "0.3.1"
cortex-m-rtfm-macros = "=0.2.0" # TODO should this have been a `path` dep all along?
rtfm-core = "0.1.0" cortex-m-rtfm-macros = { path = "macros" }
static-ref = "0.2.1" # TODO revert before merging
rtfm-core = { git = "https://github.com/jonas-schievink/rtfm-core.git", branch = "init-resources" }
[target.'cfg(target_arch = "x86_64")'.dev-dependencies] [target.'cfg(target_arch = "x86_64")'.dev-dependencies]
compiletest_rs = "0.2.8" compiletest_rs = "0.2.8"

View file

@ -12,7 +12,8 @@ version = "0.2.0"
[dependencies] [dependencies]
error-chain = "0.10.0" error-chain = "0.10.0"
quote = "0.3.15" quote = "0.3.15"
rtfm-syntax = "0.1.0" # TODO undo change
rtfm-syntax = { git = "https://github.com/jonas-schievink/rtfm-syntax.git", branch = "init-resources" }
syn = "0.11.11" syn = "0.11.11"
[lib] [lib]

View file

@ -157,14 +157,23 @@ fn init(app: &App, main: &mut Vec<Tokens>, root: &mut Vec<Tokens>) {
let mut tys = vec![quote!(#device::Peripherals)]; let mut tys = vec![quote!(#device::Peripherals)];
let mut exprs = vec![quote!(#device::Peripherals::all())]; let mut exprs = vec![quote!(#device::Peripherals::all())];
let mut ret = None;
let mut mod_items = vec![]; let mut mod_items = vec![];
if !app.resources.is_empty() { // Write resources usable by `init`, if any
// Are there any resources that have an initializer? Those can be used by `init`.
let has_initialized_resources = app.resources.iter()
.find(|&(_, res)| res.expr.is_some()).is_some();
if has_initialized_resources {
let mut fields = vec![]; let mut fields = vec![];
let mut lifetime = None; let mut lifetime = None;
let mut rexprs = vec![]; let mut rexprs = vec![];
for (name, resource) in &app.resources { for (name, resource) in app.resources.iter()
.filter(|&(_, res)| res.expr.is_some()) {
let _name = Ident::new(format!("_{}", name.as_ref())); let _name = Ident::new(format!("_{}", name.as_ref()));
lifetime = Some(quote!('a)); lifetime = Some(quote!('a));
@ -204,6 +213,46 @@ fn init(app: &App, main: &mut Vec<Tokens>, root: &mut Vec<Tokens>) {
exprs.push(quote!(init::Resources::new())); exprs.push(quote!(init::Resources::new()));
} }
let mut late_resources = vec![];
let has_late_resources = app.resources.iter()
.find(|&(_, res)| res.expr.is_none()).is_some();
if has_late_resources {
// `init` must initialize and return resources
let mut fields = vec![];
for (name, resource) in app.resources.iter()
.filter(|&(_, res)| res.expr.is_none()) {
let _name = Ident::new(format!("_{}", name.as_ref()));
let ty = &resource.ty;
fields.push(quote! {
pub #name: #ty,
});
late_resources.push(quote! {
#_name = #krate::LateResource { init: _late_resources.#name };
});
}
root.push(quote! {
#[allow(non_camel_case_types)]
#[allow(non_snake_case)]
pub struct _initLateResourceValues {
#(#fields)*
}
});
mod_items.push(quote! {
pub use ::_initLateResourceValues as LateResourceValues;
});
// `init` must return the initialized resources
ret = Some(quote!( -> ::init::LateResourceValues));
}
root.push(quote! { root.push(quote! {
#[allow(unsafe_code)] #[allow(unsafe_code)]
mod init { mod init {
@ -263,10 +312,11 @@ fn init(app: &App, main: &mut Vec<Tokens>, root: &mut Vec<Tokens>) {
let init = &app.init.path; let init = &app.init.path;
main.push(quote! { main.push(quote! {
// type check // type check
let init: fn(#(#tys,)*) = #init; let init: fn(#(#tys,)*) #ret = #init;
#krate::atomic(unsafe { &mut #krate::Threshold::new(0) }, |_t| unsafe { #krate::atomic(unsafe { &mut #krate::Threshold::new(0) }, |_t| unsafe {
init(#(#exprs,)*); let _late_resources = init(#(#exprs,)*);
#(#late_resources)*
#(#exceptions)* #(#exceptions)*
#(#interrupts)* #(#interrupts)*
@ -281,33 +331,34 @@ fn resources(app: &App, ownerships: &Ownerships, root: &mut Vec<Tokens>) {
let mut items = vec![]; let mut items = vec![];
let mut impls = vec![]; let mut impls = vec![];
for (name, ownership) in ownerships { for (name, ownership) in ownerships {
let mut impl_items = vec![];
let _name = Ident::new(format!("_{}", name.as_ref())); let _name = Ident::new(format!("_{}", name.as_ref()));
match *ownership {
Ownership::Owned { .. } => {
if let Some(resource) = app.resources.get(name) { if let Some(resource) = app.resources.get(name) {
// For owned resources we don't need claim() or borrow() // Declare the static that holds the resource
let expr = &resource.expr; let expr = &resource.expr;
let ty = &resource.ty; let ty = &resource.ty;
root.push(quote! { root.push(match *expr {
Some(ref expr) => quote! {
static mut #_name: #ty = #expr; static mut #_name: #ty = #expr;
},
None => quote! {
// Resource initialized in `init`
static mut #_name: #krate::LateResource<#ty> = #krate::LateResource { uninit: () };
},
}); });
} else {
// Peripheral
continue;
} }
let mut impl_items = vec![];
match *ownership {
Ownership::Owned { .. } => {
// For owned resources we don't need claim() or borrow()
} }
Ownership::Shared { ceiling } => { Ownership::Shared { ceiling } => {
if let Some(resource) = app.resources.get(name) { if let Some(resource) = app.resources.get(name) {
let expr = &resource.expr;
let ty = &resource.ty; let ty = &resource.ty;
root.push(quote! {
static mut #_name: #ty = #expr;
});
impl_items.push(quote! { impl_items.push(quote! {
type Data = #ty; type Data = #ty;
@ -530,8 +581,14 @@ fn tasks(app: &App, ownerships: &Ownerships, root: &mut Vec<Tokens>) {
pub #name: &'a mut ::#krate::Static<#ty>, pub #name: &'a mut ::#krate::Static<#ty>,
}); });
exprs.push(quote! { exprs.push(if resource.expr.is_some() {
quote! {
#name: ::#krate::Static::ref_mut(&mut ::#_name), #name: ::#krate::Static::ref_mut(&mut ::#_name),
}
} else {
quote! {
#name: ::#krate::Static::ref_mut(&mut ::#_name.init),
}
}); });
} else { } else {
fields.push(quote! { fields.push(quote! {

View file

@ -80,11 +80,10 @@
extern crate cortex_m; extern crate cortex_m;
extern crate cortex_m_rtfm_macros; extern crate cortex_m_rtfm_macros;
extern crate rtfm_core; extern crate rtfm_core;
extern crate static_ref;
use core::u8; use core::u8;
pub use rtfm_core::{Resource, Static, Threshold}; pub use rtfm_core::{Resource, LateResource, Static, Threshold};
pub use cortex_m::asm::{bkpt, wfi}; pub use cortex_m::asm::{bkpt, wfi};
pub use cortex_m_rtfm_macros::app; pub use cortex_m_rtfm_macros::app;
use cortex_m::interrupt::{self, Nr}; use cortex_m::interrupt::{self, Nr};