Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
  • exam
  • exper
  • klee
  • master
  • simple
  • v0.1.0
  • v0.1.1
  • v0.2.0
  • v0.2.1
  • v0.2.2
  • v0.3.0
  • v0.3.1
  • v0.3.2
13 results

Target

Select target project
  • KLEE/cortex-m-rtfm-klee
  • grammers/cortex-m-rtfm-klee
2 results
Select Git revision
  • exam
  • exper
  • klee
  • master
  • simple
  • v0.1.0
  • v0.1.1
  • v0.2.0
  • v0.2.1
  • v0.2.2
  • v0.3.0
  • v0.3.1
12 results
Show changes
Commits on Source (21)
Showing with 461 additions and 271 deletions
**/*.rs.bk
*.org
.#*
.gdb_history
Cargo.lock
target/
......@@ -5,6 +5,33 @@ This project adheres to [Semantic Versioning](http://semver.org/).
## [Unreleased]
## [v0.3.1] - 2018-01-16
### Fixed
- Documentation link
## [v0.3.0] - 2018-01-15
### Added
- [feat] `&'static mut` references can be safely created by assigning resources to `init`. See the
`init.resources` section of the `app!` macro documentation and the `safe-static-mut-ref` example
for details.
### Changed
- [breaking-change] svd2rust dependency has been bumped to v0.12.0
- [breaking-change] resources assigned to tasks, or to idle, that were not declared in the top
`resources` field generate compiler errors. Before these were assumed to be peripherals, that's no
longer the case.
- [breaking-change] the layout of `init::Peripherals` has changed. This struct now has two fields:
`core` and `device`. The value of the `core` field is a struct that owns all the core peripherals
of the device and the value of the `device` field is a struct that owns all the device specific
peripherals of the device.
## [v0.2.2] - 2017-11-22
### Added
......@@ -56,7 +83,9 @@ This project adheres to [Semantic Versioning](http://semver.org/).
- Initial release
[Unreleased]: https://github.com/japaric/cortex-m-rtfm/compare/v0.2.2...HEAD
[Unreleased]: https://github.com/japaric/cortex-m-rtfm/compare/v0.3.1...HEAD
[v0.3.1]: https://github.com/japaric/cortex-m-rtfm/compare/v0.3.0...v0.3.1
[v0.3.0]: https://github.com/japaric/cortex-m-rtfm/compare/v0.2.2...v0.3.0
[v0.2.2]: https://github.com/japaric/cortex-m-rtfm/compare/v0.2.1...v0.2.2
[v0.2.1]: https://github.com/japaric/cortex-m-rtfm/compare/v0.2.0...v0.2.1
[v0.2.0]: https://github.com/japaric/cortex-m-rtfm/compare/v0.1.1...v0.2.0
......
......@@ -10,25 +10,27 @@ keywords = ["arm", "cortex-m"]
license = "MIT OR Apache-2.0"
name = "cortex-m-rtfm"
repository = "https://github.com/japaric/cortex-m-rtfm"
version = "0.3.0"
version = "0.3.1"
[dependencies]
cortex-m = { git = "https://github.com/japaric/cortex-m" }
cortex-m = "0.4.0"
cortex-m-rtfm-macros = { path = "macros", version = "0.3.0" }
rtfm-core = "0.2.0"
untagged-option = "0.1.1"
rtfm-core = "0.1.0"
cortex-m-rtfm-macros = { path = "macros" }
[target.'cfg(target_arch = "x86_64")'.dev-dependencies]
compiletest_rs = "0.3.3"
compiletest_rs = "0.3.5"
[dev-dependencies.cortex-m-rt]
features = ["abort-on-panic"]
version = "0.3.3"
version = "0.3.9"
[dev-dependencies.stm32f103xx]
features = ["rt"]
git = "https://github.com/japaric/stm32f103xx"
# version = "0.8.0"
version = "0.8.0"
[features]
cm7-r0p1 = ["cortex-m/cm7-r0p1"]
[profile.release]
lto = true
......@@ -7,7 +7,14 @@ main() {
return
fi
xargo build --target $TARGET
case $TARGET in
thumbv7em-none-eabi*)
xargo check --target $TARGET --features cm7-r0p1
xargo check --target $TARGET --features cm7-r0p1 --examples
;;
esac
xargo check --target $TARGET
xargo check --target $TARGET --examples
}
......
#![deny(unsafe_code)]
#![deny(warnings)]
#![feature(proc_macro)]
#![no_std]
extern crate cortex_m_rtfm as rtfm;
extern crate stm32f103xx;
use rtfm::{app, Threshold};
pub struct Foo;
app! {
device: stm32f103xx,
resources: {
static CO_OWNED: Foo = Foo;
static ON: Foo = Foo;
static OWNED: Foo = Foo;
static SHARED: Foo = Foo;
},
idle: {
resources: [OWNED, SHARED],
},
tasks: {
SYS_TICK: {
path: sys_tick,
resources: [CO_OWNED, ON, SHARED],
},
TIM2: {
enabled: false,
path: tim2,
priority: 1,
resources: [CO_OWNED],
},
},
}
fn init(_p: ::init::Peripherals, _r: ::init::Resources) {}
fn idle(_t: &mut Threshold, _r: ::idle::Resources) -> ! {
loop {}
}
fn sys_tick(_t: &mut Threshold, _r: SYS_TICK::Resources) {}
fn tim2(_t: &mut Threshold, _r: TIM2::Resources) {}
......@@ -63,22 +63,22 @@ mod main {
*r.OWNED != *r.OWNED;
if *r.OWNED {
if r.SHARED.claim(t, |shared, _| **shared) {
if r.SHARED.claim(t, |shared, _| *shared) {
rtfm::wfi();
}
} else {
r.SHARED.claim_mut(t, |shared, _| **shared = !**shared);
r.SHARED.claim_mut(t, |shared, _| *shared = !*shared);
}
}
}
}
fn sys_tick(_t: &mut Threshold, r: SYS_TICK::Resources) {
**r.ON = !**r.ON;
fn sys_tick(_t: &mut Threshold, mut r: SYS_TICK::Resources) {
*r.ON = !*r.ON;
**r.CO_OWNED += 1;
*r.CO_OWNED += 1;
}
fn tim2(_t: &mut Threshold, r: TIM2::Resources) {
**r.CO_OWNED += 1;
fn tim2(_t: &mut Threshold, mut r: TIM2::Resources) {
*r.CO_OWNED += 1;
}
......@@ -70,5 +70,5 @@ fn exti0(t: &mut Threshold, r: EXTI0::Resources) {
// This task has direct access to the resources
fn exti1(t: &mut Threshold, r: EXTI1::Resources) {
work(t, r.GPIOA, r.SPI1);
work(t, &r.GPIOA, &r.SPI1);
}
//! Demonstrates initialization of resources in `init`.
#![deny(unsafe_code)]
#![deny(warnings)]
#![feature(proc_macro)]
......
......@@ -43,7 +43,7 @@ app! {
}
}
fn init(p: init::Peripherals, r: init::Resources) {
fn init(mut p: init::Peripherals, r: init::Resources) {
// `init` can modify all the `resources` declared in `app!`
r.ON;
......@@ -77,11 +77,11 @@ fn idle() -> ! {
// `r` is the set of resources this task has access to. `SYS_TICK::Resources`
// has one field per resource declared in `app!`.
#[allow(unsafe_code)]
fn sys_tick(_t: &mut Threshold, r: SYS_TICK::Resources) {
fn sys_tick(_t: &mut Threshold, mut r: SYS_TICK::Resources) {
// toggle state
**r.ON = !**r.ON;
*r.ON = !*r.ON;
if **r.ON {
if *r.ON {
// set the pin PC13 high
// NOTE(unsafe) atomic write to a stateless register
unsafe {
......
......@@ -42,12 +42,12 @@ fn idle() -> ! {
}
}
fn sys_tick(_t: &mut Threshold, r: SYS_TICK::Resources) {
fn sys_tick(_t: &mut Threshold, mut r: SYS_TICK::Resources) {
// ..
// This task can't be preempted by `tim2` so it has direct access to the
// resource data
**r.COUNTER += 1;
*r.COUNTER += 1;
// ..
}
......@@ -61,7 +61,7 @@ fn tim2(t: &mut Threshold, mut r: TIM2::Resources) {
// lead to undefined behavior.
r.COUNTER.claim_mut(t, |counter, _t| {
// `claim_mut` creates a critical section
**counter += 1;
*counter += 1;
});
// ..
......
//! Safe creation of `&'static mut` references
#![deny(unsafe_code)]
#![deny(warnings)]
#![feature(proc_macro)]
#![no_std]
extern crate cortex_m_rtfm as rtfm;
extern crate stm32f103xx;
use rtfm::app;
app! {
device: stm32f103xx,
resources: {
static BUFFER: [u8; 16] = [0; 16];
},
init: {
resources: [BUFFER],
},
}
fn init(_p: init::Peripherals, r: init::Resources) {
let _buf: &'static mut [u8; 16] = r.BUFFER;
}
fn idle() -> ! {
loop {
rtfm::wfi();
}
}
......@@ -42,18 +42,18 @@ fn idle() -> ! {
// As both tasks are running at the same priority one can't preempt the other.
// Thus both tasks have direct access to the resource
fn sys_tick(_t: &mut Threshold, r: SYS_TICK::Resources) {
fn sys_tick(_t: &mut Threshold, mut r: SYS_TICK::Resources) {
// ..
**r.COUNTER += 1;
*r.COUNTER += 1;
// ..
}
fn tim2(_t: &mut Threshold, r: TIM2::Resources) {
fn tim2(_t: &mut Threshold, mut r: TIM2::Resources) {
// ..
**r.COUNTER += 1;
*r.COUNTER += 1;
// ..
}
......@@ -11,6 +11,7 @@ main() {
preemption
nested
late-resources
safe-static-mut-ref
generics
full-syntax
)
......
......@@ -7,12 +7,12 @@ keywords = ["arm", "cortex-m"]
license = "MIT OR Apache-2.0"
name = "cortex-m-rtfm-macros"
repository = "https://github.com/japaric/cortex-m-rtfm"
version = "0.2.1"
version = "0.3.0"
[dependencies]
error-chain = "0.10.0"
quote = "0.3.15"
rtfm-syntax = "0.2.0"
rtfm-syntax = "0.2.1"
syn = "0.11.11"
[lib]
......
......@@ -17,6 +17,13 @@ pub enum Ownership {
}
impl Ownership {
pub fn ceiling(&self) -> u8 {
match *self {
Ownership::Owned { priority } => priority,
Ownership::Shared { ceiling } => ceiling,
}
}
pub fn is_owned(&self) -> bool {
match *self {
Ownership::Owned { .. } => true,
......
......@@ -77,7 +77,38 @@ pub fn app(app: check::App) -> Result<App> {
}
fn resources(app: &App) -> Result<()> {
for name in &app.init.resources {
if let Some(resource) = app.resources.get(name) {
ensure!(
resource.expr.is_some(),
"resource `{}`, allocated to `init`, must have an initial value",
name
);
} else {
bail!(
"resource `{}`, allocated to `init`, must be a data resource",
name
);
}
ensure!(
!app.idle.resources.contains(name),
"resources assigned to `init` can't be shared with `idle`"
);
ensure!(
app.tasks
.iter()
.all(|(_, task)| !task.resources.contains(name)),
"resources assigned to `init` can't be shared with tasks"
)
}
for resource in app.resources.keys() {
if app.init.resources.contains(resource) {
continue;
}
if app.idle.resources.contains(resource) {
continue;
}
......
......@@ -58,7 +58,7 @@ mod trans;
/// ```
///
/// The initial value of a resource can be omitted. This means that the resource will be runtime
/// initialized.
/// initialized; these runtime initialized resources are also known as *late resources*.
///
/// If this key is omitted its value defaults to an empty list.
///
......@@ -79,6 +79,18 @@ mod trans;
///
/// If the key is omitted its value defaults to `init`.
///
/// ## `init.resources`
///
/// This key is optional. Its value is a set of resources the `init` function *owns*. The resources
/// in this list must be a subset of the resources listed in the top `resources` key. Note that some
/// restrictions apply:
///
/// - The resources in this list can't be late resources.
/// - The resources that appear in this list can't appear in other list like `idle.resources` or
/// `tasks.$TASK.resources`
///
/// If this key is omitted its value is assumed to be an empty list.
///
/// # `idle`
///
/// This key is optional. Its value is a set of key values. All the possible keys are shown below:
......@@ -100,9 +112,7 @@ mod trans;
/// ## `idle.resources`
///
/// This key is optional. Its value is a list of resources the `idle` loop has access to. The
/// resources in this list can refer to the resources listed in the top `resources` key. If the name
/// doesn't match one of the resources /// listed in the top `resources` key the resource is assumed
/// to be a peripheral.
/// resources in this list must be a subset of the resources listed in the top `resources` key.
///
/// If omitted its value defaults to an empty list.
///
......@@ -154,9 +164,7 @@ mod trans;
/// ## `tasks.$TASK.resources`
///
/// This key is optional. Its value is a list of resources this task has access to. The resources in
/// this list can refer to the resources listed in the top `resources` key. If the name doesn't
/// match one of the resources listed in the top `resources` key the resource is assumed to be a
/// peripheral.
/// this list must be a subset of the resources listed in the top `resources` key.
///
/// If omitted its value defaults to an empty list.
#[proc_macro]
......
use quote::{Ident, Tokens};
use syn::{Lit, StrStyle};
use analyze::{Ownership, Ownerships};
use analyze::Ownerships;
use check::{App, Kind};
fn krate() -> Ident {
......@@ -81,11 +81,11 @@ fn idle(app: &App, ownerships: &Ownerships, main: &mut Vec<Tokens>, root: &mut V
});
} else {
rfields.push(quote! {
pub #name: #super_::_resource::#name,
pub #name: ::idle::#name,
});
rexprs.push(quote! {
#name: #super_::_resource::#name::new(),
#name: ::idle::#name { _0: core::marker::PhantomData },
});
}
}
......@@ -126,6 +126,85 @@ fn idle(app: &App, ownerships: &Ownerships, main: &mut Vec<Tokens>, root: &mut V
exprs.push(quote!(unsafe { idle::Resources::new() }));
}
let device = &app.device;
for name in &app.idle.resources {
let ceiling = ownerships[name].ceiling();
// owned resource
if ceiling == 0 {
continue
}
let _name = Ident::new(format!("_{}", name.as_ref()));
let resource = app.resources
.get(name)
.expect(&format!("BUG: resource {} has no definition", name));
let ty = &resource.ty;
let _static = if resource.expr.is_some() {
quote!(#_name)
} else {
quote!(#_name.some)
};
mod_items.push(quote! {
#[allow(non_camel_case_types)]
pub struct #name { _0: core::marker::PhantomData<*const ()> }
});
root.push(quote! {
#[allow(unsafe_code)]
unsafe impl #krate::Resource for idle::#name {
type Data = #ty;
fn borrow<'cs>(&'cs self, t: &'cs Threshold) -> &'cs Self::Data {
assert!(t.value() >= #ceiling);
unsafe { &#_static }
}
fn borrow_mut<'cs>(
&'cs mut self,
t: &'cs Threshold,
) -> &'cs mut Self::Data {
assert!(t.value() >= #ceiling);
unsafe { &mut #_static }
}
fn claim<R, F>(&self, t: &mut Threshold, f: F) -> R
where
F: FnOnce(&Self::Data, &mut Threshold) -> R
{
unsafe {
#krate::claim(
&#_static,
#ceiling,
#device::NVIC_PRIO_BITS,
t,
f,
)
}
}
fn claim_mut<R, F>(&mut self, t: &mut Threshold, f: F) -> R
where
F: FnOnce(&mut Self::Data, &mut Threshold) -> R
{
unsafe {
#krate::claim(
&mut #_static,
#ceiling,
#device::NVIC_PRIO_BITS,
t,
f,
)
}
}
}
});
}
if !mod_items.is_empty() {
root.push(quote! {
#[allow(unsafe_code)]
......@@ -170,19 +249,31 @@ fn init(app: &App, main: &mut Vec<Tokens>, root: &mut Vec<Tokens>) {
let mut rexprs = vec![];
for (name, resource) in init_resources {
let ty = &resource.ty;
if app.init.resources.contains(name) {
fields.push(quote! {
pub #name: &'static mut #ty,
});
let expr = &resource.expr;
rexprs.push(quote!(#name: {
static mut #name: #ty = #expr;
&mut #name
},));
} else {
let _name = Ident::new(format!("_{}", name.as_ref()));
lifetime = Some(quote!('a));
let ty = &resource.ty;
fields.push(quote! {
pub #name: &'a mut #krate::Static<#ty>,
pub #name: &'a mut #ty,
});
rexprs.push(quote! {
#name: ::#krate::Static::ref_mut(&mut ::#_name),
#name: &mut ::#_name,
});
}
}
root.push(quote! {
#[allow(non_camel_case_types)]
......@@ -279,10 +370,10 @@ fn init(app: &App, main: &mut Vec<Tokens>, root: &mut Vec<Tokens>) {
});
}
Kind::Interrupt { enabled } => {
// Interrupt. These can be enabled / disabled through the NVIC
// Interrupt. These are enabled / disabled through the NVIC
if interrupts.is_empty() {
interrupts.push(quote! {
let nvic = &*#device::NVIC::ptr();
let mut nvic: #device::NVIC = core::mem::transmute(());
});
}
......@@ -323,15 +414,15 @@ fn init(app: &App, main: &mut Vec<Tokens>, root: &mut Vec<Tokens>) {
fn resources(app: &App, ownerships: &Ownerships, root: &mut Vec<Tokens>) {
let krate = krate();
let device = &app.device;
let mut items = vec![];
let mut impls = vec![];
for (name, ownership) in ownerships {
for name in ownerships.keys() {
let _name = Ident::new(format!("_{}", name.as_ref()));
if let Some(resource) = app.resources.get(name) {
// Declare the static that holds the resource
let resource = app.resources
.get(name)
.expect(&format!("BUG: resource {} has no definition", name));
let expr = &resource.expr;
let ty = &resource.ty;
......@@ -341,64 +432,71 @@ fn resources(app: &App, ownerships: &Ownerships, root: &mut Vec<Tokens>) {
},
None => quote! {
// Resource initialized in `init`
static mut #_name: #krate::UntaggedOption<#ty> = #krate::UntaggedOption { none: () };
static mut #_name: #krate::UntaggedOption<#ty> =
#krate::UntaggedOption { none: () };
},
});
}
}
fn tasks(app: &App, ownerships: &Ownerships, root: &mut Vec<Tokens>) {
let device = &app.device;
let krate = krate();
let mut impl_items = vec![];
for (tname, task) in &app.tasks {
let mut exprs = vec![];
let mut fields = vec![];
let mut items = vec![];
match *ownership {
Ownership::Owned { .. } => {
// For owned resources we don't need claim() or borrow()
}
Ownership::Shared { ceiling } => {
let has_resources = !task.resources.is_empty();
if has_resources {
for rname in &task.resources {
let ceiling = ownerships[rname].ceiling();
let _rname = Ident::new(format!("_{}", rname.as_ref()));
let resource = app.resources
.get(name)
.expect(&format!("BUG: resource {} has no definition", name));
.get(rname)
.expect(&format!("BUG: resource {} has no definition", rname));
let ty = &resource.ty;
let res_rvalue = if resource.expr.is_some() {
quote!(#_name)
let _static = if resource.expr.is_some() {
quote!(#_rname)
} else {
quote!(#_name.some)
quote!(#_rname.some)
};
impl_items.push(quote! {
items.push(quote! {
#[allow(non_camel_case_types)]
pub struct #rname { _0: PhantomData<*const ()> }
});
root.push(quote! {
#[allow(unsafe_code)]
unsafe impl #krate::Resource for #tname::#rname {
type Data = #ty;
fn borrow<'cs>(
&'cs self,
t: &'cs #krate::Threshold,
) -> &'cs #krate::Static<#ty> {
fn borrow<'cs>(&'cs self, t: &'cs Threshold) -> &'cs Self::Data {
assert!(t.value() >= #ceiling);
unsafe { #krate::Static::ref_(&#res_rvalue) }
unsafe { &#_static }
}
fn borrow_mut<'cs>(
&'cs mut self,
t: &'cs #krate::Threshold,
) -> &'cs mut #krate::Static<#ty> {
t: &'cs Threshold,
) -> &'cs mut Self::Data {
assert!(t.value() >= #ceiling);
unsafe {
#krate::Static::ref_mut(&mut #res_rvalue)
}
unsafe { &mut #_static }
}
fn claim<R, F>(
&self,
t: &mut #krate::Threshold,
f: F,
) -> R
fn claim<R, F>(&self, t: &mut Threshold, f: F) -> R
where
F: FnOnce(
&#krate::Static<#ty>,
&mut #krate::Threshold) -> R
F: FnOnce(&Self::Data, &mut Threshold) -> R
{
unsafe {
#krate::claim(
#krate::Static::ref_(&#res_rvalue),
&#_static,
#ceiling,
#device::NVIC_PRIO_BITS,
t,
......@@ -407,19 +505,13 @@ fn resources(app: &App, ownerships: &Ownerships, root: &mut Vec<Tokens>) {
}
}
fn claim_mut<R, F>(
&mut self,
t: &mut #krate::Threshold,
f: F,
) -> R
fn claim_mut<R, F>(&mut self, t: &mut Threshold, f: F) -> R
where
F: FnOnce(
&mut #krate::Static<#ty>,
&mut #krate::Threshold) -> R
F: FnOnce(&mut Self::Data, &mut Threshold) -> R
{
unsafe {
#krate::claim(
#krate::Static::ref_mut(&mut #res_rvalue),
&mut #_static,
#ceiling,
#device::NVIC_PRIO_BITS,
t,
......@@ -427,130 +519,48 @@ fn resources(app: &App, ownerships: &Ownerships, root: &mut Vec<Tokens>) {
)
}
}
});
impls.push(quote! {
#[allow(unsafe_code)]
unsafe impl #krate::Resource for _resource::#name {
#(#impl_items)*
}
});
items.push(quote! {
#[allow(non_camel_case_types)]
pub struct #name { _0: PhantomData<*const ()> }
if ceiling <= task.priority {
root.push(quote! {
#[allow(unsafe_code)]
impl #name {
pub unsafe fn new() -> Self {
#name { _0: PhantomData }
}
}
});
}
impl core::ops::Deref for #tname::#rname {
type Target = #ty;
fn deref(&self) -> &Self::Target {
unsafe { &#_static }
}
}
if !items.is_empty() {
root.push(quote! {
#[allow(unsafe_code)]
mod _resource {
use core::marker::PhantomData;
#(#items)*
impl core::ops::DerefMut for #tname::#rname {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { &mut #_static }
}
})
}
root.push(quote! {
#(#impls)*
});
})
}
fn tasks(app: &App, ownerships: &Ownerships, root: &mut Vec<Tokens>) {
let device = &app.device;
let krate = krate();
for (name, task) in &app.tasks {
let mut exprs = vec![];
let mut fields = vec![];
let mut items = vec![];
let mut lifetime = None;
let mut needs_reexport = false;
let mut needs_threshold = false;
let has_resources = !task.resources.is_empty();
if has_resources {
needs_threshold = !task.resources.is_empty();
for name in &task.resources {
let _name = Ident::new(format!("_{}", name.as_ref()));
match ownerships[name] {
Ownership::Shared { ceiling } if ceiling > task.priority => {
needs_threshold = true;
fields.push(quote! {
pub #name: ::_resource::#name,
pub #rname: #rname,
});
exprs.push(quote! {
#name: {
::_resource::#name::new()
},
#rname: #rname { _0: PhantomData },
});
}
_ => {
lifetime = Some(quote!('a));
let resource = app.resources
.get(name)
.expect(&format!("BUG: resource {} has no definition", name));
needs_reexport = true;
let ty = &resource.ty;
fields.push(quote! {
pub #name: &'a mut ::#krate::Static<#ty>,
});
exprs.push(if resource.expr.is_some() {
quote! {
#name: ::#krate::Static::ref_mut(&mut ::#_name),
}
} else {
quote! {
#name: ::#krate::Static::ref_mut(::#_name.as_mut()),
}
});
}
}
}
if needs_reexport {
let rname = Ident::new(format!("_{}Resources", name));
root.push(quote! {
#[allow(non_camel_case_types)]
#[allow(non_snake_case)]
pub struct #rname<#lifetime> {
#(#fields)*
}
});
items.push(quote! {
pub use ::#rname as Resources;
});
} else {
items.push(quote! {
#[allow(non_snake_case)]
pub struct Resources<#lifetime> {
pub struct Resources {
#(#fields)*
}
});
}
items.push(quote! {
#[allow(unsafe_code)]
impl<#lifetime> Resources<#lifetime> {
impl Resources {
pub unsafe fn new() -> Self {
Resources {
#(#exprs)*
......@@ -564,7 +574,7 @@ fn tasks(app: &App, ownerships: &Ownerships, root: &mut Vec<Tokens>) {
let mut exprs = vec![];
let priority = task.priority;
if needs_threshold {
if has_resources {
tys.push(quote!(&mut #krate::Threshold));
exprs.push(quote! {
&mut if #priority == 1 << #device::NVIC_PRIO_BITS {
......@@ -576,18 +586,18 @@ fn tasks(app: &App, ownerships: &Ownerships, root: &mut Vec<Tokens>) {
}
if has_resources {
tys.push(quote!(#name::Resources));
exprs.push(quote!(#name::Resources::new()));
tys.push(quote!(#tname::Resources));
exprs.push(quote!(#tname::Resources::new()));
}
let path = &task.path;
let _name = Ident::new(format!("_{}", name));
let export_name = Lit::Str(name.as_ref().to_owned(), StrStyle::Cooked);
let _tname = Ident::new(format!("_{}", tname));
let export_name = Lit::Str(tname.as_ref().to_owned(), StrStyle::Cooked);
root.push(quote! {
#[allow(non_snake_case)]
#[allow(unsafe_code)]
#[export_name = #export_name]
pub unsafe extern "C" fn #_name() {
pub unsafe extern "C" fn #_tname() {
let f: fn(#(#tys,)*) = #path;
f(#(#exprs,)*)
......@@ -597,7 +607,9 @@ fn tasks(app: &App, ownerships: &Ownerships, root: &mut Vec<Tokens>) {
root.push(quote!{
#[allow(non_snake_case)]
#[allow(unsafe_code)]
mod #name {
mod #tname {
use core::marker::PhantomData;
#[allow(dead_code)]
#[deny(const_err)]
const CHECK_PRIORITY: (u8, u8) = (
......
......@@ -2,6 +2,7 @@
//!
//! ```
//! #![deny(unsafe_code)]
//! #![deny(warnings)]
//! // IMPORTANT always include this feature gate
//! #![feature(proc_macro)]
//! #![no_std]
......@@ -27,8 +28,9 @@
//! // this function.
//! fn init(p: init::Peripherals) {
//! // This function has access to all the peripherals of the device
//! p.GPIOA;
//! p.RCC;
//! p.core.SYST;
//! p.device.GPIOA;
//! p.device.RCC;
//! // ..
//! }
//!
......
......@@ -2,6 +2,7 @@
//!
//! ```
//! #![deny(unsafe_code)]
//! #![deny(warnings)]
//! #![feature(proc_macro)]
//! #![no_std]
//!
......@@ -9,8 +10,9 @@
//! extern crate cortex_m_rtfm as rtfm;
//! extern crate stm32f103xx;
//!
//! use cortex_m::peripheral::SystClkSource;
//! use cortex_m::peripheral::syst::SystClkSource;
//! use rtfm::{app, Threshold};
//! use stm32f103xx::GPIOC;
//!
//! app! {
//! device: stm32f103xx,
......@@ -37,31 +39,31 @@
//!
//! // These are the resources this task has access to.
//! //
//! // A resource can be a peripheral like `GPIOC` or a static variable
//! // like `ON`
//! resources: [GPIOC, ON],
//! // The resources listed here must also appear in `app.resources`
//! resources: [ON],
//! },
//! }
//! }
//!
//! fn init(p: init::Peripherals, r: init::Resources) {
//! fn init(mut p: init::Peripherals, r: init::Resources) {
//! // `init` can modify all the `resources` declared in `app!`
//! r.ON;
//!
//! // power on GPIOC
//! p.RCC.apb2enr.modify(|_, w| w.iopcen().enabled());
//! p.device.RCC.apb2enr.modify(|_, w| w.iopcen().enabled());
//!
//! // configure PC13 as output
//! p.GPIOC.bsrr.write(|w| w.bs13().set());
//! p.GPIOC
//! p.device.GPIOC.bsrr.write(|w| w.bs13().set());
//! p.device
//! .GPIOC
//! .crh
//! .modify(|_, w| w.mode13().output().cnf13().push());
//!
//! // configure the system timer to generate one interrupt every second
//! p.SYST.set_clock_source(SystClkSource::Core);
//! p.SYST.set_reload(8_000_000); // 1s
//! p.SYST.enable_interrupt();
//! p.SYST.enable_counter();
//! p.core.SYST.set_clock_source(SystClkSource::Core);
//! p.core.SYST.set_reload(8_000_000); // 1s
//! p.core.SYST.enable_interrupt();
//! p.core.SYST.enable_counter();
//! }
//!
//! fn idle() -> ! {
......@@ -76,16 +78,23 @@
//! //
//! // `r` is the set of resources this task has access to. `SYS_TICK::Resources`
//! // has one field per resource declared in `app!`.
//! fn sys_tick(_t: &mut Threshold, r: SYS_TICK::Resources) {
//! #[allow(unsafe_code)]
//! fn sys_tick(_t: &mut Threshold, mut r: SYS_TICK::Resources) {
//! // toggle state
//! **r.ON = !**r.ON;
//! *r.ON = !*r.ON;
//!
//! if **r.ON {
//! if *r.ON {
//! // set the pin PC13 high
//! r.GPIOC.bsrr.write(|w| w.bs13().set());
//! // NOTE(unsafe) atomic write to a stateless register
//! unsafe {
//! (*GPIOC::ptr()).bsrr.write(|w| w.bs13().set());
//! }
//! } else {
//! // set the pin PC13 low
//! r.GPIOC.bsrr.write(|w| w.br13().reset());
//! // NOTE(unsafe) atomic write to a stateless register
//! unsafe {
//! (*GPIOC::ptr()).bsrr.write(|w| w.br13().reset());
//! }
//! }
//! }
//! ```
......