Merge branch 'master' into spawn_experiment

This commit is contained in:
Emil Fresk 2020-10-08 17:33:42 +02:00
commit c83b15b643
51 changed files with 649 additions and 467 deletions

View file

@ -85,7 +85,7 @@ jobs:
command: check
args: --target=${{ matrix.target }}
# Verify all examples
# Verify all examples, checks
checkexamples:
name: checkexamples
runs-on: ubuntu-20.04
@ -140,6 +140,51 @@ jobs:
command: check
args: --examples --target=${{ matrix.target }} --features __min_r1_43,${{ env.V7 }}
# Verify the example output with run-pass tests
testexamples:
name: testexamples
runs-on: ubuntu-20.04
strategy:
matrix:
target:
- thumbv7m-none-eabi
- thumbv6m-none-eabi
toolchain:
- stable
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Cache cargo dependencies
uses: actions/cache@v2
with:
path: |
- ~/.cargo/bin/
- ~/.cargo/registry/index/
- ~/.cargo/registry/cache/
- ~/.cargo/git/db/
key: ${{ runner.OS }}-cargo-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.OS }}-cargo-${{ hashFiles('**/Cargo.lock') }}
${{ runner.OS }}-cargo-
- name: Cache build output dependencies
uses: actions/cache@v2
with:
path: target
key: ${{ runner.OS }}-build-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.OS }}-build-${{ hashFiles('**/Cargo.lock') }}
${{ runner.OS }}-build-
- name: Install Rust ${{ matrix.toolchain }} with target (${{ matrix.target }})
uses: actions-rs/toolchain@v1
with:
toolchain: ${{ matrix.toolchain }}
target: ${{ matrix.target }}
override: true
components: llvm-tools-preview
# Use precompiled binutils
- name: cargo install cargo-binutils
uses: actions-rs/install@v0.1
@ -341,6 +386,56 @@ jobs:
command: check
args: --manifest-path macros/Cargo.toml --target=${{ matrix.target }}
# Run the macros test-suite
testmacros:
name: testmacros
runs-on: ubuntu-20.04
strategy:
matrix:
target:
- x86_64-unknown-linux-gnu
toolchain:
- stable
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Cache cargo dependencies
uses: actions/cache@v2
with:
path: |
- ~/.cargo/bin/
- ~/.cargo/registry/index/
- ~/.cargo/registry/cache/
- ~/.cargo/git/db/
key: ${{ runner.OS }}-cargo-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.OS }}-cargo-${{ hashFiles('**/Cargo.lock') }}
${{ runner.OS }}-cargo-
- name: Cache build output dependencies
uses: actions/cache@v2
with:
path: target
key: ${{ runner.OS }}-build-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.OS }}-build-${{ hashFiles('**/Cargo.lock') }}
${{ runner.OS }}-build-
- name: Install Rust ${{ matrix.toolchain }} with target (${{ matrix.target }})
uses: actions-rs/toolchain@v1
with:
toolchain: ${{ matrix.toolchain }}
target: ${{ matrix.target }}
override: true
- name: cargo check
uses: actions-rs/cargo@v1
with:
use-cross: false
command: test
args: --manifest-path macros/Cargo.toml --target=${{ matrix.target }}
# Run test suite for thumbv7m
testv7:
name: testv7
@ -513,7 +608,7 @@ jobs:
- name: mdBook Action
uses: peaceiris/actions-mdbook@v1.1.11
with:
mdbook-version: '0.3.1'
mdbook-version: 'latest'
- name: Build book in English
run: cd book/en && mdbook build
@ -541,7 +636,9 @@ jobs:
- style
- check
- checkexamples
- testexamples
- checkmacros
- testmacros
- testv7
- testv6
- docs
@ -566,8 +663,7 @@ jobs:
- name: mdBook Action
uses: peaceiris/actions-mdbook@v1.1.11
with:
mdbook-version: '0.3.1'
# mdbook-version: 'latest'
mdbook-version: 'latest'
- name: Remove cargo-config
run: rm -f .cargo/config
@ -579,13 +675,16 @@ jobs:
run: |
langs=( en ru )
devver=( dev )
# Query git for tagged releases, all releases start with "v"
# followed by MAJOR.MINOR.PATCH, see semver.org
# Then remove all pre-releases/tags with hyphens (-).
# The latest release is last, finally trim "v" and PATCH
stable=$(git tag | grep "^v" | grep -v "-" | tail -n 1 | cut -c2-4)
# The latest stable must be the first element in the array
vers=( 0.5.x 0.4.x )
# All releases start with "v"
# followed by MAJOR.MINOR.PATCH, see semver.org
# Retain MAJOR.MINOR as $stable
stable=${vers%.*}
echo "Stable version: $stable"
# Create directories
td=$(mktemp -d)
mkdir -p $td/$devver/book/
@ -630,8 +729,8 @@ jobs:
rm -rf $src
done
# Create alias for the stable release
ln -s $stable $td/stable
# Copy the stable book to the stable alias
cp -r $td/$stable $td/stable
# Forward CNAME file
cp CNAME $td/
@ -654,7 +753,9 @@ jobs:
- style
- check
- checkexamples
- testexamples
- checkmacros
- testmacros
- testv7
- testv6
- docs
@ -670,7 +771,9 @@ jobs:
- style
- check
- checkexamples
- testexamples
- checkmacros
- testmacros
- testv7
- testv6
- docs

View file

@ -4,10 +4,12 @@ A concurrency framework for building real-time systems.
Formerly known as Real-Time For the Masses.
![crates.io](https://img.shields.io/crates/v/cortex-m-rtic)
![docs.rs](https://docs.rs/cortex-m-rtic/badge.svg)
![book](https://img.shields.io/badge/web-rtic.rs-red.svg?style=flat&label=book&colorB=d33847)
![rustc](https://img.shields.io/badge/rustc-1.36+-lightgray.svg)
[![crates.io](https://img.shields.io/crates/v/cortex-m-rtic)](https://crates.io/crates/cortex-m-rtic)
[![docs.rs](https://docs.rs/cortex-m-rtic/badge.svg)](https://docs.rs/cortex-m-rtic)
[![book](https://img.shields.io/badge/web-rtic.rs-red.svg?style=flat&label=book&colorB=d33847)](https://rtic.rs/)
[![rustc](https://img.shields.io/badge/rustc-1.36+-lightgray.svg)](https://github.com/rust-lang/rust/releases/tag/1.36.0)
[![matrix](https://img.shields.io/matrix/rtic:matrix.org)](https://matrix.to/#/#rtic:matrix.org)
[![Meeting notes](https://hackmd.io/badge.svg)](https://hackmd.io/@xmis9JvZT8Gvo9lOEKyZ4Q/SkBJKsjuH)
## Features
@ -52,23 +54,29 @@ Formerly known as Real-Time For the Masses.
## [User documentation](https://rtic.rs)
## [API reference](https://rtic.rs/0.5/api/)
## [API reference](https://rtic.rs/stable/api/)
## Chat
Join us and talk about RTIC in the [Matrix room][matrix-room].
Weekly meeting notes can be found over at [HackMD][hackmd]
[matrix-room]: https://matrix.to/#/#rtic:matrix.org
[hackmd]: https://hackmd.io/@xmis9JvZT8Gvo9lOEKyZ4Q/SkBJKsjuH
## Contributing
New features and big changes should go through the RFC process in the [dedicated RFC repository][rfcs].
New features and big changes should go through the RFC process in the
[dedicated RFC repository][rfcs].
[rfcs]: https://github.com/rtic-rs/rfcs
## Acknowledgments
This crate is based on [the Real-Time For the Masses language][rtfm-lang] created by the Embedded
Systems group at [Luleå University of Technology][ltu], led by [Prof. Per
Lindgren][per].
This crate is based on [the Real-Time For the Masses language][rtfm-lang]
created by the Embedded Systems group at [Luleå University of Technology][ltu],
led by [Prof. Per Lindgren][per].
[rtfm-lang]: http://www.rtfm-lang.org/
[ltu]: https://www.ltu.se/?l=en

View file

@ -10,8 +10,10 @@
- [Types, Send and Sync](./by-example/types-send-sync.md)
- [Starting a new project](./by-example/new.md)
- [Tips & tricks](./by-example/tips.md)
- [Migrating from v0.4.x to v0.5.0](./migration.md)
- [Migrating from RTFM to RTIC](./migration_rtic.md)
- [Migration Guides](./migration.md)
- [v0.5.x to v0.6.x](./migration/migration_v5.md)
- [v0.4.x to v0.5.x](./migration/migration_v4.md)
- [RTFM to RTIC](./migration/migration_rtic.md)
- [Under the hood](./internals.md)
- [Interrupt configuration](./internals/interrupt-configuration.md)
- [Non-reentrancy](./internals/non-reentrancy.md)

View file

@ -14,3 +14,11 @@ program. Check [the embedded Rust book] for instructions on how to set up an
embedded development environment that includes QEMU.
[the embedded Rust book]: https://rust-embedded.github.io/book/intro/install.html
## Real World Examples
The following are examples of RTFM being used in real world projects.
### RTFM V0.4.2
- [etrombly/sandbox](https://github.com/etrombly/sandbox/tree/41d423bcdd0d8e42fd46b79771400a8ca349af55). A hardware zen garden that draws patterns in sand. Patterns are sent over serial using G-code.

View file

@ -1,4 +1,4 @@
## Resources
# Resources
The framework provides an abstraction to share data between any of the contexts
we saw in the previous section (task handlers, `init` and `idle`): resources.
@ -116,7 +116,9 @@ are required to access the resource even if the resource is contended by several
tasks running at different priorities. The downside is that the task only gets a
shared reference (`&-`) to the resource, limiting the operations it can perform
on it, but where a shared reference is enough this approach reduces the number
of required locks.
of required locks. In addition to simple immutable data, this shared access can
be useful where the resource type safely implements interior mutability, with
appropriate locking or atomic operations of its own.
Note that in this release of RTIC it is not possible to request both exclusive
access (`&mut-`) and shared access (`&-`) to the *same* resource from different

View file

@ -116,6 +116,7 @@ Here's an example where `heapless::Pool` is used to "box" buffers of 128 bytes.
``` rust
{{#include ../../../../examples/pool.rs}}
```
``` console
$ cargo run --example pool
{{#include ../../../../ci/expected/pool.run}}

View file

@ -1,331 +1,4 @@
# Migration of RTIC
# Migration Guides
## Migrating from v0.5.x to v0.6.0
This section describes how to upgrade from v0.5.x to v0.6.0 of the RTIC framework.
### `Cargo.toml` - version bump
Change the version of `cortex-m-rtic` to `"0.6.0"`.
### Module instead of Const
With the support of attributes on modules the `const APP` workaround is not needed.
Change
``` rust
#[rtic::app(/* .. */)]
const APP: () = {
[code here]
};
```
into
``` rust
#[rtic::app(/* .. */)]
mod app {
[code here]
}
```
Now that a regular Rust module is used it means it is possible to have custom
user code within that module.
Additionally, it means that `use`-statements for resources etc may be required.
### Init always returns late resources
In order to make the API more symmetric the #[init]-task always returns a late resource.
From this:
``` rust
#[rtic::app(device = lm3s6965)]
mod app {
#[init]
fn init(_: init::Context) {
rtic::pend(Interrupt::UART0);
}
[more code]
}
```
to this:
``` rust
#[rtic::app(device = lm3s6965)]
mod app {
#[init]
fn init(_: init::Context) -> init::LateResources {
rtic::pend(Interrupt::UART0);
init::LateResources {}
}
[more code]
}
```
### Resources struct - #[resources]
Previously the RTIC resources had to be in in a struct named exactly "Resources":
``` rust
struct Resources {
// Resources defined in here
}
```
With RTIC v0.6.0 the resources struct is annotated similarly like
`#[task]`, `#[init]`, `#[idle]`: with an attribute `#[resources]`
``` rust
#[resources]
struct Resources {
// Resources defined in here
}
```
In fact, the name of the struct is now up to the developer:
``` rust
#[resources]
struct whateveryouwant {
// Resources defined in here
}
```
would work equally well.
## Migrating from v0.4.x to v0.5.0
This section covers how to upgrade an application written against RTIC v0.4.x to
the version v0.5.0 of the framework.
### `Cargo.toml`
First, the version of the `cortex-m-rtic` dependency needs to be updated to
`"0.5.0"`. The `timer-queue` feature needs to be removed.
``` toml
[dependencies.cortex-m-rtic]
# change this
version = "0.4.3"
# into this
version = "0.5.0"
# and remove this Cargo feature
features = ["timer-queue"]
# ^^^^^^^^^^^^^
```
### `Context` argument
All functions inside the `#[rtic::app]` item need to take as first argument a
`Context` structure. This `Context` type will contain the variables that were
magically injected into the scope of the function by version v0.4.x of the
framework: `resources`, `spawn`, `schedule` -- these variables will become
fields of the `Context` structure. Each function within the `#[rtic::app]` item
gets a different `Context` type.
``` rust
#[rtic::app(/* .. */)]
const APP: () = {
// change this
#[task(resources = [x], spawn = [a], schedule = [b])]
fn foo() {
resources.x.lock(|x| /* .. */);
spawn.a(message);
schedule.b(baseline);
}
// into this
#[task(resources = [x], spawn = [a], schedule = [b])]
fn foo(mut cx: foo::Context) {
// ^^^^^^^^^^^^^^^^^^^^
cx.resources.x.lock(|x| /* .. */);
// ^^^
cx.spawn.a(message);
// ^^^
cx.schedule.b(message, baseline);
// ^^^
}
// change this
#[init]
fn init() {
// ..
}
// into this
#[init]
fn init(cx: init::Context) {
// ^^^^^^^^^^^^^^^^^
// ..
}
// ..
};
```
### Resources
The syntax used to declare resources has been changed from `static mut`
variables to a `struct Resources`.
``` rust
#[rtic::app(/* .. */)]
const APP: () = {
// change this
static mut X: u32 = 0;
static mut Y: u32 = (); // late resource
// into this
struct Resources {
#[init(0)] // <- initial value
X: u32, // NOTE: we suggest changing the naming style to `snake_case`
Y: u32, // late resource
}
// ..
};
```
### Device peripherals
If your application was accessing the device peripherals in `#[init]` through
the `device` variable then you'll need to add `peripherals = true` to the
`#[rtic::app]` attribute to continue to access the device peripherals through
the `device` field of the `init::Context` structure.
Change this:
``` rust
#[rtic::app(/* .. */)]
const APP: () = {
#[init]
fn init() {
device.SOME_PERIPHERAL.write(something);
}
// ..
};
```
Into this:
``` rust
#[rtic::app(/* .. */, peripherals = true)]
// ^^^^^^^^^^^^^^^^^^
const APP: () = {
#[init]
fn init(cx: init::Context) {
// ^^^^^^^^^^^^^^^^^
cx.device.SOME_PERIPHERAL.write(something);
// ^^^
}
// ..
};
```
### `#[interrupt]` and `#[exception]`
The `#[interrupt]` and `#[exception]` attributes have been removed. To declare
hardware tasks in v0.5.x use the `#[task]` attribute with the `binds` argument.
Change this:
``` rust
#[rtic::app(/* .. */)]
const APP: () = {
// hardware tasks
#[exception]
fn SVCall() { /* .. */ }
#[interrupt]
fn UART0() { /* .. */ }
// software task
#[task]
fn foo() { /* .. */ }
// ..
};
```
Into this:
``` rust
#[rtic::app(/* .. */)]
const APP: () = {
#[task(binds = SVCall)]
// ^^^^^^^^^^^^^^
fn svcall(cx: svcall::Context) { /* .. */ }
// ^^^^^^ we suggest you use a `snake_case` name here
#[task(binds = UART0)]
// ^^^^^^^^^^^^^
fn uart0(cx: uart0::Context) { /* .. */ }
#[task]
fn foo(cx: foo::Context) { /* .. */ }
// ..
};
```
### `schedule`
The `timer-queue` feature has been removed. To use the `schedule` API one must
first define the monotonic timer the runtime will use using the `monotonic`
argument of the `#[rtic::app]` attribute. To continue using the cycle counter
(CYCCNT) as the monotonic timer, and match the behavior of version v0.4.x, add
the `monotonic = rtic::cyccnt::CYCCNT` argument to the `#[rtic::app]` attribute.
Also, the `Duration` and `Instant` types and the `U32Ext` trait have been moved
into the `rtic::cyccnt` module. This module is only available on ARMv7-M+
devices. The removal of the `timer-queue` also brings back the `DWT` peripheral
inside the core peripherals struct, this will need to be enabled by the application
inside `init`.
Change this:
``` rust
use rtic::{Duration, Instant, U32Ext};
#[rtic::app(/* .. */)]
const APP: () = {
#[task(schedule = [b])]
fn a() {
// ..
}
};
```
Into this:
``` rust
use rtic::cyccnt::{Duration, Instant, U32Ext};
// ^^^^^^^^
#[rtic::app(/* .. */, monotonic = rtic::cyccnt::CYCCNT)]
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
const APP: () = {
#[init]
fn init(cx: init::Context) {
cx.core.DWT.enable_cycle_counter();
// optional, configure the DWT run without a debugger connected
cx.core.DCB.enable_trace();
}
#[task(schedule = [b])]
fn a(cx: a::Context) {
// ..
}
};
```
This section describes how to migrate between different version of RTIC.
It also acts as a comparing reference between versions.

View file

@ -8,14 +8,11 @@ change.
[RFC #33]: https://github.com/rtic-rs/rfcs/pull/33
## `Cargo.toml`
First, the `cortex-m-rtfm` dependency needs to be updated to
`cortex-m-rtic`.
``` toml
[dependencies]
# change this
@ -51,4 +48,3 @@ const APP: () = {
};
```

View file

@ -0,0 +1,233 @@
# Migrating from v0.4.x to v0.5.0
This section covers how to upgrade an application written against RTIC v0.4.x to
the version v0.5.0 of the framework.
## `Cargo.toml`
First, the version of the `cortex-m-rtic` dependency needs to be updated to
`"0.5.0"`. The `timer-queue` feature needs to be removed.
``` toml
[dependencies.cortex-m-rtic]
# change this
version = "0.4.3"
# into this
version = "0.5.0"
# and remove this Cargo feature
features = ["timer-queue"]
# ^^^^^^^^^^^^^
```
## `Context` argument
All functions inside the `#[rtic::app]` item need to take as first argument a
`Context` structure. This `Context` type will contain the variables that were
magically injected into the scope of the function by version v0.4.x of the
framework: `resources`, `spawn`, `schedule` -- these variables will become
fields of the `Context` structure. Each function within the `#[rtic::app]` item
gets a different `Context` type.
``` rust
#[rtic::app(/* .. */)]
const APP: () = {
// change this
#[task(resources = [x], spawn = [a], schedule = [b])]
fn foo() {
resources.x.lock(|x| /* .. */);
spawn.a(message);
schedule.b(baseline);
}
// into this
#[task(resources = [x], spawn = [a], schedule = [b])]
fn foo(mut cx: foo::Context) {
// ^^^^^^^^^^^^^^^^^^^^
cx.resources.x.lock(|x| /* .. */);
// ^^^
cx.spawn.a(message);
// ^^^
cx.schedule.b(message, baseline);
// ^^^
}
// change this
#[init]
fn init() {
// ..
}
// into this
#[init]
fn init(cx: init::Context) {
// ^^^^^^^^^^^^^^^^^
// ..
}
// ..
};
```
## Resources
The syntax used to declare resources has been changed from `static mut`
variables to a `struct Resources`.
``` rust
#[rtic::app(/* .. */)]
const APP: () = {
// change this
static mut X: u32 = 0;
static mut Y: u32 = (); // late resource
// into this
struct Resources {
#[init(0)] // <- initial value
X: u32, // NOTE: we suggest changing the naming style to `snake_case`
Y: u32, // late resource
}
// ..
};
```
## Device peripherals
If your application was accessing the device peripherals in `#[init]` through
the `device` variable then you'll need to add `peripherals = true` to the
`#[rtic::app]` attribute to continue to access the device peripherals through
the `device` field of the `init::Context` structure.
Change this:
``` rust
#[rtic::app(/* .. */)]
const APP: () = {
#[init]
fn init() {
device.SOME_PERIPHERAL.write(something);
}
// ..
};
```
Into this:
``` rust
#[rtic::app(/* .. */, peripherals = true)]
// ^^^^^^^^^^^^^^^^^^
const APP: () = {
#[init]
fn init(cx: init::Context) {
// ^^^^^^^^^^^^^^^^^
cx.device.SOME_PERIPHERAL.write(something);
// ^^^
}
// ..
};
```
## `#[interrupt]` and `#[exception]`
The `#[interrupt]` and `#[exception]` attributes have been removed. To declare
hardware tasks in v0.5.x use the `#[task]` attribute with the `binds` argument.
Change this:
``` rust
#[rtic::app(/* .. */)]
const APP: () = {
// hardware tasks
#[exception]
fn SVCall() { /* .. */ }
#[interrupt]
fn UART0() { /* .. */ }
// software task
#[task]
fn foo() { /* .. */ }
// ..
};
```
Into this:
``` rust
#[rtic::app(/* .. */)]
const APP: () = {
#[task(binds = SVCall)]
// ^^^^^^^^^^^^^^
fn svcall(cx: svcall::Context) { /* .. */ }
// ^^^^^^ we suggest you use a `snake_case` name here
#[task(binds = UART0)]
// ^^^^^^^^^^^^^
fn uart0(cx: uart0::Context) { /* .. */ }
#[task]
fn foo(cx: foo::Context) { /* .. */ }
// ..
};
```
## `schedule`
The `schedule` API no longer requires the `timer-queue` cargo feature, which has
been removed. To use the `schedule` API one must
first define the monotonic timer the runtime will use using the `monotonic`
argument of the `#[rtic::app]` attribute. To continue using the cycle counter
(CYCCNT) as the monotonic timer, and match the behavior of version v0.4.x, add
the `monotonic = rtic::cyccnt::CYCCNT` argument to the `#[rtic::app]` attribute.
Also, the `Duration` and `Instant` types and the `U32Ext` trait have been moved
into the `rtic::cyccnt` module. This module is only available on ARMv7-M+
devices. The removal of the `timer-queue` also brings back the `DWT` peripheral
inside the core peripherals struct, this will need to be enabled by the application
inside `init`.
Change this:
``` rust
use rtic::{Duration, Instant, U32Ext};
#[rtic::app(/* .. */)]
const APP: () = {
#[task(schedule = [b])]
fn a() {
// ..
}
};
```
Into this:
``` rust
use rtic::cyccnt::{Duration, Instant, U32Ext};
// ^^^^^^^^
#[rtic::app(/* .. */, monotonic = rtic::cyccnt::CYCCNT)]
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
const APP: () = {
#[init]
fn init(cx: init::Context) {
cx.core.DWT.enable_cycle_counter();
// optional, configure the DWT run without a debugger connected
cx.core.DCB.enable_trace();
}
#[task(schedule = [b])]
fn a(cx: a::Context) {
// ..
}
};
```

View file

@ -0,0 +1,96 @@
# Migrating from v0.5.x to v0.6.0
This section describes how to upgrade from v0.5.x to v0.6.0 of the RTIC framework.
## `Cargo.toml` - version bump
Change the version of `cortex-m-rtic` to `"0.6.0"`.
## Module instead of Const
With the support of attributes on modules the `const APP` workaround is not needed.
Change
``` rust
#[rtic::app(/* .. */)]
const APP: () = {
[code here]
};
```
into
``` rust
#[rtic::app(/* .. */)]
mod app {
[code here]
}
```
Now that a regular Rust module is used it means it is possible to have custom
user code within that module.
Additionally, it means that `use`-statements for resources etc may be required.
## Init always returns late resources
In order to make the API more symmetric the #[init]-task always returns a late resource.
From this:
``` rust
#[rtic::app(device = lm3s6965)]
mod app {
#[init]
fn init(_: init::Context) {
rtic::pend(Interrupt::UART0);
}
[more code]
}
```
to this:
``` rust
#[rtic::app(device = lm3s6965)]
mod app {
#[init]
fn init(_: init::Context) -> init::LateResources {
rtic::pend(Interrupt::UART0);
init::LateResources {}
}
[more code]
}
```
## Resources struct - #[resources]
Previously the RTIC resources had to be in in a struct named exactly "Resources":
``` rust
struct Resources {
// Resources defined in here
}
```
With RTIC v0.6.0 the resources struct is annotated similarly like
`#[task]`, `#[init]`, `#[idle]`: with an attribute `#[resources]`
``` rust
#[resources]
struct Resources {
// Resources defined in here
}
```
In fact, the name of the struct is now up to the developer:
``` rust
#[resources]
struct whateveryouwant {
// Resources defined in here
}
```
would work equally well.

View file

@ -13,13 +13,15 @@ use panic_semihosting as _;
#[rtic::app(device = lm3s6965, monotonic = rtic::cyccnt::CYCCNT)]
mod app {
#[init(spawn = [foo])]
fn init(cx: init::Context) {
fn init(cx: init::Context) -> init::LateResources {
// omitted: initialization of `CYCCNT`
hprintln!("init(baseline = {:?})", cx.start).unwrap();
// `foo` inherits the baseline of `init`: `Instant(0)`
cx.spawn.foo().unwrap();
init::LateResources {}
}
#[task(schedule = [foo])]

View file

@ -13,10 +13,12 @@ use panic_semihosting as _;
#[rtic::app(device = lm3s6965)]
mod app {
#[init]
fn init(_: init::Context) {
fn init(_: init::Context) -> init::LateResources {
rtic::pend(Interrupt::UART0);
hprintln!("init").unwrap();
init::LateResources {}
}
#[idle]

View file

@ -12,8 +12,10 @@ use panic_semihosting as _;
#[rtic::app(device = lm3s6965)]
mod app {
#[init]
fn init(_: init::Context) {
fn init(_: init::Context) -> init::LateResources {
rtic::pend(Interrupt::UART0);
init::LateResources {}
}
#[task(binds = UART0, spawn = [foo, bar])]

View file

@ -20,9 +20,11 @@ mod app {
}
#[init(spawn = [foo])]
fn init(cx: init::Context) {
fn init(cx: init::Context) -> init::LateResources {
cx.spawn.foo().unwrap();
cx.spawn.foo().unwrap();
init::LateResources {}
}
#[idle]

View file

@ -23,9 +23,11 @@ mod app {
}
#[init]
fn init(_: init::Context) {
fn init(_: init::Context) -> init::LateResources {
rtic::pend(Interrupt::UART0);
rtic::pend(Interrupt::UART1);
init::LateResources {}
}
// Direct destructure

View file

@ -19,9 +19,11 @@ mod app {
}
#[init]
fn init(_: init::Context) {
fn init(_: init::Context) -> init::LateResources {
rtic::pend(Interrupt::UART0);
rtic::pend(Interrupt::UART1);
init::LateResources {}
}
#[task(binds = UART0, resources = [shared])]

View file

@ -12,12 +12,14 @@ use panic_semihosting as _;
#[rtic::app(device = lm3s6965)]
mod app {
#[init]
fn init(_: init::Context) {
fn init(_: init::Context) -> init::LateResources {
// Pends the UART0 interrupt but its handler won't run until *after*
// `init` returns because interrupts are disabled
rtic::pend(Interrupt::UART0); // equivalent to NVIC::pend
hprintln!("init").unwrap();
init::LateResources {}
}
#[idle]

View file

@ -11,8 +11,10 @@ use panic_semihosting as _;
#[rtic::app(device = lm3s6965)]
mod app {
#[init]
fn init(_: init::Context) {
fn init(_: init::Context) -> init::LateResources {
hprintln!("init").unwrap();
init::LateResources {}
}
#[idle]

View file

@ -11,7 +11,7 @@ use panic_semihosting as _;
#[rtic::app(device = lm3s6965, peripherals = true)]
mod app {
#[init]
fn init(cx: init::Context) {
fn init(cx: init::Context) -> init::LateResources {
static mut X: u32 = 0;
// Cortex-M peripherals
@ -30,5 +30,7 @@ mod app {
hprintln!("init").unwrap();
debug::exit(debug::EXIT_SUCCESS);
init::LateResources {}
}
}

View file

@ -18,8 +18,10 @@ mod app {
}
#[init]
fn init(_: init::Context) {
fn init(_: init::Context) -> init::LateResources {
rtic::pend(Interrupt::GPIOA);
init::LateResources {}
}
// when omitted priority is assumed to be `1`

View file

@ -11,8 +11,10 @@ use panic_semihosting as _;
#[rtic::app(device = lm3s6965)]
mod app {
#[init(spawn = [foo])]
fn init(c: init::Context) {
fn init(c: init::Context) -> init::LateResources {
c.spawn.foo(/* no message */).unwrap();
init::LateResources {}
}
#[task(spawn = [bar])]

View file

@ -26,9 +26,11 @@ mod app {
}
#[init(spawn = [baz, quux])]
fn init(c: init::Context) {
fn init(c: init::Context) -> init::LateResources {
c.spawn.baz().unwrap();
c.spawn.quux().unwrap();
init::LateResources {}
}
#[task(spawn = [bar])]

View file

@ -26,8 +26,10 @@ mod app {
}
#[init]
fn init(_: init::Context) {
fn init(_: init::Context) -> init::LateResources {
debug::exit(debug::EXIT_SUCCESS);
init::LateResources {}
}
#[task(resources = [&shared])]

View file

@ -16,10 +16,12 @@ const PERIOD: u32 = 8_000_000;
mod app {
#[init(schedule = [foo])]
fn init(cx: init::Context) {
fn init(cx: init::Context) -> init::LateResources {
// omitted: initialization of `CYCCNT`
cx.schedule.foo(cx.start + PERIOD.cycles()).unwrap();
init::LateResources {}
}
#[task(schedule = [foo])]

View file

@ -9,8 +9,10 @@ use panic_semihosting as _;
#[rtic::app(device = lm3s6965)]
mod app {
#[init]
fn taskmain(_: taskmain::Context) {
fn init(_: init::Context) -> init::LateResources {
assert!(cortex_m::Peripherals::take().is_none());
debug::exit(debug::EXIT_SUCCESS);
init::LateResources {}
}
}

View file

@ -25,13 +25,15 @@ mod app {
use super::P;
#[init]
fn init(_: init::Context) {
fn init(_: init::Context) -> init::LateResources {
static mut MEMORY: [u8; 512] = [0; 512];
// Increase the capacity of the memory pool by ~4
P::grow(MEMORY);
rtic::pend(Interrupt::I2C0);
init::LateResources {}
}
#[task(binds = I2C0, priority = 2, spawn = [foo, bar])]

View file

@ -11,8 +11,10 @@ use rtic::app;
#[app(device = lm3s6965)]
mod app {
#[init]
fn init(_: init::Context) {
fn init(_: init::Context) -> init::LateResources {
rtic::pend(Interrupt::GPIOA);
init::LateResources {}
}
#[task(binds = GPIOA, priority = 1)]

View file

@ -11,8 +11,10 @@ use panic_semihosting as _;
#[rtic::app(device = lm3s6965)]
mod app {
#[init(spawn = [bar])]
fn init(c: init::Context) {
fn init(c: init::Context) -> init::LateResources {
c.spawn.bar().unwrap();
init::LateResources {}
}
#[inline(never)]

View file

@ -26,9 +26,11 @@ mod app {
}
#[init]
fn init(_: init::Context) {
fn init(_: init::Context) -> init::LateResources {
rtic::pend(Interrupt::UART0);
rtic::pend(Interrupt::UART1);
init::LateResources {}
}
// `shared` cannot be accessed from this context

View file

@ -19,9 +19,11 @@ mod app {
}
#[init]
fn init(_: init::Context) {
fn init(_: init::Context) -> init::LateResources {
rtic::pend(Interrupt::UART0);
rtic::pend(Interrupt::UART1);
init::LateResources {}
}
// `shared` cannot be accessed from this context

View file

@ -14,7 +14,7 @@ use rtic::cyccnt::{Instant, U32Ext as _};
#[rtic::app(device = lm3s6965, monotonic = rtic::cyccnt::CYCCNT)]
mod app {
#[init(schedule = [foo, bar])]
fn init(mut cx: init::Context) {
fn init(mut cx: init::Context) -> init::LateResources {
// Initialize (enable) the monotonic timer (CYCCNT)
cx.core.DCB.enable_trace();
// required on Cortex-M7 devices that software lock the DWT (e.g. STM32F7)
@ -32,6 +32,8 @@ mod app {
// Schedule `bar` to run 4e6 cycles in the future
cx.schedule.bar(now + 4_000_000.cycles()).unwrap();
init::LateResources {}
}
#[task]

View file

@ -23,12 +23,14 @@ mod app {
}
#[init(resources = [shared])]
fn init(c: init::Context) {
fn init(c: init::Context) -> init::LateResources {
// this `message` will be sent to task `UART0`
let message = MustBeSend;
*c.resources.shared = Some(message);
rtic::pend(Interrupt::UART0);
init::LateResources {}
}
#[task(binds = UART0, resources = [shared])]

View file

@ -10,7 +10,9 @@ use panic_halt as _;
#[rtic::app(device = lm3s6965)]
mod app {
#[init]
fn init(_: init::Context) {}
fn init(_: init::Context) -> init::LateResources {
init::LateResources {}
}
// Cortex-M exception
#[task(binds = SVCall)]

View file

@ -15,9 +15,11 @@ mod app {
}
#[init]
fn init(_: init::Context) {
fn init(_: init::Context) -> init::LateResources {
#[cfg(never)]
static mut BAR: u32 = 0;
init::LateResources {}
}
#[idle]

View file

@ -9,8 +9,10 @@ use panic_semihosting as _;
#[rtic::app(device = lm3s6965)]
mod app {
#[init]
fn init(_: init::Context) {
rtic::pend(lm3s6965::Interrupt::UART0)
fn init(_: init::Context) -> init::LateResources {
rtic::pend(lm3s6965::Interrupt::UART0);
init::LateResources {}
}
#[task(binds = UART0)]

View file

@ -9,7 +9,9 @@ use panic_semihosting as _;
#[rtic::app(device = lm3s6965)]
mod app {
#[init]
fn init(_: init::Context) {}
fn init(_: init::Context) -> init::LateResources {
init::LateResources {}
}
#[idle]
fn taskmain(_: taskmain::Context) -> ! {

View file

@ -9,7 +9,9 @@ use panic_semihosting as _;
#[rtic::app(device = lm3s6965)]
mod app {
#[init]
fn taskmain(_: taskmain::Context) {
fn init(_: init::Context) -> init::LateResources {
debug::exit(debug::EXIT_SUCCESS);
init::LateResources {}
}
}

View file

@ -32,7 +32,7 @@ mod app {
}
#[init(resources = [o1, o4, o5, o6, s3])]
fn init(c: init::Context) {
fn init(c: init::Context) -> init::LateResources {
// owned by `init` == `&'static mut`
let _: &'static mut u32 = c.resources.o1;
@ -43,6 +43,8 @@ mod app {
let _: &mut u32 = c.resources.o4;
let _: &mut u32 = c.resources.o5;
let _: &mut u32 = c.resources.s3;
init::LateResources {}
}
#[idle(resources = [o2, &o4, s1, &s3])]

View file

@ -11,10 +11,12 @@ use rtic::cyccnt::{Instant, U32Ext as _};
#[rtic::app(device = lm3s6965, monotonic = rtic::cyccnt::CYCCNT)]
mod app {
#[init(schedule = [foo, bar, baz])]
fn init(c: init::Context) {
fn init(c: init::Context) -> init::LateResources {
let _: Result<(), ()> = c.schedule.foo(c.start + 10.cycles());
let _: Result<(), u32> = c.schedule.bar(c.start + 20.cycles(), 0);
let _: Result<(), (u32, u32)> = c.schedule.baz(c.start + 30.cycles(), 0, 1);
init::LateResources {}
}
#[idle(schedule = [foo, bar, baz])]

View file

@ -10,10 +10,12 @@ use panic_halt as _;
#[rtic::app(device = lm3s6965)]
mod app {
#[init(spawn = [foo, bar, baz])]
fn init(c: init::Context) {
fn init(c: init::Context) -> init::LateResources {
let _: Result<(), ()> = c.spawn.foo();
let _: Result<(), u32> = c.spawn.bar(0);
let _: Result<(), (u32, u32)> = c.spawn.baz(0, 1);
init::LateResources {}
}
#[idle(spawn = [foo, bar, baz])]

View file

@ -9,8 +9,10 @@ use panic_semihosting as _;
#[rtic::app(device = lm3s6965)]
mod app {
#[init(spawn = [taskmain])]
fn init(cx: init::Context) {
fn init(cx: init::Context) -> init::LateResources {
cx.spawn.taskmain().ok();
init::LateResources {}
}
#[task]

View file

@ -11,8 +11,10 @@ use panic_semihosting as _;
#[rtic::app(device = lm3s6965)]
mod app {
#[init(spawn = [foo])]
fn init(c: init::Context) {
fn init(c: init::Context) -> init::LateResources {
c.spawn.foo().unwrap();
init::LateResources {}
}
#[task(spawn = [bar, baz])]

View file

@ -18,7 +18,7 @@ mod app {
}
#[init(schedule = [foo], spawn = [foo])]
fn init(cx: init::Context) {
fn init(cx: init::Context) -> init::LateResources {
let _: cyccnt::Instant = cx.start;
let _: rtic::Peripherals = cx.core;
let _: lm3s6965::Peripherals = cx.device;
@ -26,6 +26,8 @@ mod app {
let _: init::Spawn = cx.spawn;
debug::exit(debug::EXIT_SUCCESS);
init::LateResources {}
}
#[idle(schedule = [foo], spawn = [foo])]

View file

@ -36,47 +36,38 @@ pub fn codegen(
let mut root_init = vec![];
let mut user_init_imports = vec![];
let late_fields = analysis
.late_resources
.iter()
.flat_map(|resources| {
resources.iter().map(|name| {
let ty = &app.late_resources[name].ty;
let cfgs = &app.late_resources[name].cfgs;
let ret = {
let late_fields = analysis
.late_resources
.iter()
.flat_map(|resources| {
resources.iter().map(|name| {
let ty = &app.late_resources[name].ty;
let cfgs = &app.late_resources[name].cfgs;
quote!(
quote!(
#(#cfgs)*
pub #name: #ty
)
})
)
})
.collect::<Vec<_>>();
})
.collect::<Vec<_>>();
if !late_fields.is_empty() {
let late_resources = util::late_resources_ident(&name);
let mut user_init_imports = vec![];
let late_resources = util::late_resources_ident(&name);
root_init.push(quote!(
/// Resources initialized at runtime
#[allow(non_snake_case)]
pub struct #late_resources {
#(#late_fields),*
}
));
let name_late = format_ident!("{}LateResources", name);
user_init_imports.push(quote!(
#[allow(non_snake_case)]
use super::#name_late;
));
Some(quote!(-> #name::LateResources))
} else {
None
root_init.push(quote!(
/// Resources initialized at runtime
#[allow(non_snake_case)]
pub struct #late_resources {
#(#late_fields),*
}
};
));
let name_late = format_ident!("{}LateResources", name);
user_init_imports.push(quote!(
#[allow(non_snake_case)]
use super::#name_late;
));
let mut locals_pat = None;
let mut locals_new = None;
@ -95,7 +86,7 @@ pub fn codegen(
let user_init = Some(quote!(
#(#attrs)*
#[allow(non_snake_case)]
fn #name(#(#locals_pat,)* #context: #name::Context) #ret {
fn #name(#(#locals_pat,)* #context: #name::Context) -> #name::LateResources {
#(#stmts)*
}
));

View file

@ -267,14 +267,12 @@ pub fn codegen(
if let Context::Init = ctxt {
let init = &app.inits.first().unwrap();
if init.returns_late_resources {
let late_resources = util::late_resources_ident(&init.name);
let late_resources = util::late_resources_ident(&init.name);
items.push(quote!(
#[doc(inline)]
pub use super::#late_resources as LateResources;
));
}
items.push(quote!(
#[doc(inline)]
pub use super::#late_resources as LateResources;
));
}
let doc = match ctxt {

View file

@ -35,8 +35,7 @@ mod tests;
///
/// The items allowed in the module block are specified below:
///
/// # 1. `#[resources]
/// struct <resource-name>`
/// # 1. `#[resources] struct <resource-name>`
///
/// This structure contains the declaration of all the resources used by the application. Each field
/// in this structure corresponds to a different resource. Each resource may optionally be given an

View file

@ -4,11 +4,13 @@ use panic_halt as _;
#[rtic::app(device = lm3s6965)]
mod app {
#[init]
fn init(_: init::Context) {
fn init(_: init::Context) -> init::LateResources {
#[cfg(never)]
static mut FOO: u32 = 0;
FOO;
init::LateResources {}
}
#[idle]

View file

@ -5,27 +5,27 @@ error[E0425]: cannot find value `FOO` in this scope
| ^^^ not found in this scope
error[E0425]: cannot find value `FOO` in this scope
--> $DIR/locals-cfg.rs:19:9
--> $DIR/locals-cfg.rs:21:9
|
19 | FOO;
21 | FOO;
| ^^^ not found in this scope
error[E0425]: cannot find value `FOO` in this scope
--> $DIR/locals-cfg.rs:29:9
--> $DIR/locals-cfg.rs:31:9
|
29 | FOO;
31 | FOO;
| ^^^ not found in this scope
error[E0425]: cannot find value `FOO` in this scope
--> $DIR/locals-cfg.rs:37:9
--> $DIR/locals-cfg.rs:39:9
|
37 | FOO;
39 | FOO;
| ^^^ not found in this scope
error[E0425]: cannot find value `FOO` in this scope
--> $DIR/locals-cfg.rs:45:9
--> $DIR/locals-cfg.rs:47:9
|
45 | FOO;
47 | FOO;
| ^^^ not found in this scope
error: duplicate lang item in crate `panic_halt` (which `$CRATE` depends on): `panic_impl`.

View file

@ -43,12 +43,14 @@ mod app {
}
#[init(resources = [o1, o4, o5, o6, s3])]
fn init(c: init::Context) {
fn init(c: init::Context) -> init::LateResources {
c.resources.o1;
c.resources.o4;
c.resources.o5;
c.resources.o6;
c.resources.s3;
init::LateResources {}
}
#[idle(resources = [o2, &o4, s1, &s3])]

View file

@ -45,81 +45,81 @@ error[E0609]: no field `s3` on type `initResources<'_>`
= note: available fields are: `__marker__`
error[E0609]: no field `o2` on type `idleResources<'_>`
--> $DIR/resources-cfg.rs:56:21
--> $DIR/resources-cfg.rs:58:21
|
56 | c.resources.o2;
58 | c.resources.o2;
| ^^ unknown field
|
= note: available fields are: `__marker__`
error[E0609]: no field `o4` on type `idleResources<'_>`
--> $DIR/resources-cfg.rs:57:21
--> $DIR/resources-cfg.rs:59:21
|
57 | c.resources.o4;
59 | c.resources.o4;
| ^^ unknown field
|
= note: available fields are: `__marker__`
error[E0609]: no field `s1` on type `idleResources<'_>`
--> $DIR/resources-cfg.rs:58:21
--> $DIR/resources-cfg.rs:60:21
|
58 | c.resources.s1;
60 | c.resources.s1;
| ^^ unknown field
|
= note: available fields are: `__marker__`
error[E0609]: no field `s3` on type `idleResources<'_>`
--> $DIR/resources-cfg.rs:59:21
--> $DIR/resources-cfg.rs:61:21
|
59 | c.resources.s3;
61 | c.resources.s3;
| ^^ unknown field
|
= note: available fields are: `__marker__`
error[E0609]: no field `o3` on type `uart0Resources<'_>`
--> $DIR/resources-cfg.rs:66:21
--> $DIR/resources-cfg.rs:68:21
|
66 | c.resources.o3;
68 | c.resources.o3;
| ^^ unknown field
|
= note: available fields are: `__marker__`
error[E0609]: no field `s1` on type `uart0Resources<'_>`
--> $DIR/resources-cfg.rs:67:21
--> $DIR/resources-cfg.rs:69:21
|
67 | c.resources.s1;
69 | c.resources.s1;
| ^^ unknown field
|
= note: available fields are: `__marker__`
error[E0609]: no field `s2` on type `uart0Resources<'_>`
--> $DIR/resources-cfg.rs:68:21
--> $DIR/resources-cfg.rs:70:21
|
68 | c.resources.s2;
70 | c.resources.s2;
| ^^ unknown field
|
= note: available fields are: `__marker__`
error[E0609]: no field `s3` on type `uart0Resources<'_>`
--> $DIR/resources-cfg.rs:69:21
--> $DIR/resources-cfg.rs:71:21
|
69 | c.resources.s3;
71 | c.resources.s3;
| ^^ unknown field
|
= note: available fields are: `__marker__`
error[E0609]: no field `s2` on type `uart1Resources<'_>`
--> $DIR/resources-cfg.rs:74:21
--> $DIR/resources-cfg.rs:76:21
|
74 | c.resources.s2;
76 | c.resources.s2;
| ^^ unknown field
|
= note: available fields are: `__marker__`
error[E0609]: no field `o5` on type `uart1Resources<'_>`
--> $DIR/resources-cfg.rs:75:21
--> $DIR/resources-cfg.rs:77:21
|
75 | c.resources.o5;
77 | c.resources.o5;
| ^^ unknown field
|
= note: available fields are: `__marker__`

View file

@ -3,7 +3,9 @@
#[rtic::app(device = lm3s6965)]
mod app {
#[init]
fn init(_: init::Context) {}
fn init(_: init::Context) -> init::LateResources {
init::LateResources {}
}
#[task(binds = GPIOA, priority = 1)]
fn gpioa(_: gpioa::Context) {}