diff --git a/Cargo.toml b/Cargo.toml index f345689e92..448282d2ba 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,9 +14,10 @@ version = "0.2.1" [dependencies] cortex-m = "0.3.1" -cortex-m-rtfm-macros = "=0.2.0" -rtfm-core = "0.1.0" -static-ref = "0.2.1" +# TODO should this have been a `path` dep all along? +cortex-m-rtfm-macros = { path = "macros" } +# 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] compiletest_rs = "0.2.8" @@ -30,4 +31,4 @@ features = ["rt"] version = "0.7.1" [profile.release] -lto = true \ No newline at end of file +lto = true diff --git a/macros/Cargo.toml b/macros/Cargo.toml index eda10c57dd..b825de2ebc 100644 --- a/macros/Cargo.toml +++ b/macros/Cargo.toml @@ -12,7 +12,8 @@ version = "0.2.0" [dependencies] error-chain = "0.10.0" 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" [lib] diff --git a/macros/src/trans.rs b/macros/src/trans.rs index c65aaa522e..ef23aa5fd7 100644 --- a/macros/src/trans.rs +++ b/macros/src/trans.rs @@ -157,14 +157,23 @@ fn init(app: &App, main: &mut Vec, root: &mut Vec) { let mut tys = vec![quote!(#device::Peripherals)]; let mut exprs = vec![quote!(#device::Peripherals::all())]; + let mut ret = None; 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 lifetime = None; 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())); lifetime = Some(quote!('a)); @@ -204,6 +213,46 @@ fn init(app: &App, main: &mut Vec, root: &mut Vec) { 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! { #[allow(unsafe_code)] mod init { @@ -263,10 +312,11 @@ fn init(app: &App, main: &mut Vec, root: &mut Vec) { let init = &app.init.path; main.push(quote! { // type check - let init: fn(#(#tys,)*) = #init; + let init: fn(#(#tys,)*) #ret = #init; #krate::atomic(unsafe { &mut #krate::Threshold::new(0) }, |_t| unsafe { - init(#(#exprs,)*); + let _late_resources = init(#(#exprs,)*); + #(#late_resources)* #(#exceptions)* #(#interrupts)* @@ -281,33 +331,34 @@ fn resources(app: &App, ownerships: &Ownerships, root: &mut Vec) { let mut items = vec![]; let mut impls = vec![]; for (name, ownership) in ownerships { + let _name = Ident::new(format!("_{}", name.as_ref())); + + if let Some(resource) = app.resources.get(name) { + // Declare the static that holds the resource + let expr = &resource.expr; + let ty = &resource.ty; + + root.push(match *expr { + Some(ref expr) => quote! { + static mut #_name: #ty = #expr; + }, + None => quote! { + // Resource initialized in `init` + static mut #_name: #krate::LateResource<#ty> = #krate::LateResource { uninit: () }; + }, + }); + } + let mut impl_items = vec![]; - let _name = Ident::new(format!("_{}", name.as_ref())); match *ownership { Ownership::Owned { .. } => { - if let Some(resource) = app.resources.get(name) { - // For owned resources we don't need claim() or borrow() - let expr = &resource.expr; - let ty = &resource.ty; - - root.push(quote! { - static mut #_name: #ty = #expr; - }); - } else { - // Peripheral - continue; - } + // For owned resources we don't need claim() or borrow() } Ownership::Shared { ceiling } => { if let Some(resource) = app.resources.get(name) { - let expr = &resource.expr; let ty = &resource.ty; - root.push(quote! { - static mut #_name: #ty = #expr; - }); - impl_items.push(quote! { type Data = #ty; @@ -530,8 +581,14 @@ fn tasks(app: &App, ownerships: &Ownerships, root: &mut Vec) { pub #name: &'a mut ::#krate::Static<#ty>, }); - exprs.push(quote! { - #name: ::#krate::Static::ref_mut(&mut ::#_name), + exprs.push(if resource.expr.is_some() { + quote! { + #name: ::#krate::Static::ref_mut(&mut ::#_name), + } + } else { + quote! { + #name: ::#krate::Static::ref_mut(&mut ::#_name.init), + } }); } else { fields.push(quote! { diff --git a/src/lib.rs b/src/lib.rs index 3fde2ddc10..072e635969 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -80,11 +80,10 @@ extern crate cortex_m; extern crate cortex_m_rtfm_macros; extern crate rtfm_core; -extern crate static_ref; 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_rtfm_macros::app; use cortex_m::interrupt::{self, Nr};