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 command: check
args: --target=${{ matrix.target }} args: --target=${{ matrix.target }}
# Verify all examples # Verify all examples, checks
checkexamples: checkexamples:
name: checkexamples name: checkexamples
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
@ -140,6 +140,51 @@ jobs:
command: check command: check
args: --examples --target=${{ matrix.target }} --features __min_r1_43,${{ env.V7 }} 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 # Use precompiled binutils
- name: cargo install cargo-binutils - name: cargo install cargo-binutils
uses: actions-rs/install@v0.1 uses: actions-rs/install@v0.1
@ -341,6 +386,56 @@ jobs:
command: check command: check
args: --manifest-path macros/Cargo.toml --target=${{ matrix.target }} 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 # Run test suite for thumbv7m
testv7: testv7:
name: testv7 name: testv7
@ -513,7 +608,7 @@ jobs:
- name: mdBook Action - name: mdBook Action
uses: peaceiris/actions-mdbook@v1.1.11 uses: peaceiris/actions-mdbook@v1.1.11
with: with:
mdbook-version: '0.3.1' mdbook-version: 'latest'
- name: Build book in English - name: Build book in English
run: cd book/en && mdbook build run: cd book/en && mdbook build
@ -541,7 +636,9 @@ jobs:
- style - style
- check - check
- checkexamples - checkexamples
- testexamples
- checkmacros - checkmacros
- testmacros
- testv7 - testv7
- testv6 - testv6
- docs - docs
@ -566,8 +663,7 @@ jobs:
- name: mdBook Action - name: mdBook Action
uses: peaceiris/actions-mdbook@v1.1.11 uses: peaceiris/actions-mdbook@v1.1.11
with: with:
mdbook-version: '0.3.1' mdbook-version: 'latest'
# mdbook-version: 'latest'
- name: Remove cargo-config - name: Remove cargo-config
run: rm -f .cargo/config run: rm -f .cargo/config
@ -579,13 +675,16 @@ jobs:
run: | run: |
langs=( en ru ) langs=( en ru )
devver=( dev ) devver=( dev )
# Query git for tagged releases, all releases start with "v" # The latest stable must be the first element in the array
# 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)
vers=( 0.5.x 0.4.x ) 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 # Create directories
td=$(mktemp -d) td=$(mktemp -d)
mkdir -p $td/$devver/book/ mkdir -p $td/$devver/book/
@ -630,8 +729,8 @@ jobs:
rm -rf $src rm -rf $src
done done
# Create alias for the stable release # Copy the stable book to the stable alias
ln -s $stable $td/stable cp -r $td/$stable $td/stable
# Forward CNAME file # Forward CNAME file
cp CNAME $td/ cp CNAME $td/
@ -654,7 +753,9 @@ jobs:
- style - style
- check - check
- checkexamples - checkexamples
- testexamples
- checkmacros - checkmacros
- testmacros
- testv7 - testv7
- testv6 - testv6
- docs - docs
@ -670,7 +771,9 @@ jobs:
- style - style
- check - check
- checkexamples - checkexamples
- testexamples
- checkmacros - checkmacros
- testmacros
- testv7 - testv7
- testv6 - testv6
- docs - docs

View file

@ -4,10 +4,12 @@ A concurrency framework for building real-time systems.
Formerly known as Real-Time For the Masses. Formerly known as Real-Time For the Masses.
![crates.io](https://img.shields.io/crates/v/cortex-m-rtic) [![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) [![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) [![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) [![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 ## Features
@ -52,23 +54,29 @@ Formerly known as Real-Time For the Masses.
## [User documentation](https://rtic.rs) ## [User documentation](https://rtic.rs)
## [API reference](https://rtic.rs/0.5/api/) ## [API reference](https://rtic.rs/stable/api/)
## Chat ## Chat
Join us and talk about RTIC in the [Matrix room][matrix-room]. 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 [matrix-room]: https://matrix.to/#/#rtic:matrix.org
[hackmd]: https://hackmd.io/@xmis9JvZT8Gvo9lOEKyZ4Q/SkBJKsjuH
## Contributing ## 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 [rfcs]: https://github.com/rtic-rs/rfcs
## Acknowledgments ## Acknowledgments
This crate is based on [the Real-Time For the Masses language][rtfm-lang] created by the Embedded This crate is based on [the Real-Time For the Masses language][rtfm-lang]
Systems group at [Luleå University of Technology][ltu], led by [Prof. Per created by the Embedded Systems group at [Luleå University of Technology][ltu],
Lindgren][per]. led by [Prof. Per Lindgren][per].
[rtfm-lang]: http://www.rtfm-lang.org/ [rtfm-lang]: http://www.rtfm-lang.org/
[ltu]: https://www.ltu.se/?l=en [ltu]: https://www.ltu.se/?l=en

View file

@ -10,8 +10,10 @@
- [Types, Send and Sync](./by-example/types-send-sync.md) - [Types, Send and Sync](./by-example/types-send-sync.md)
- [Starting a new project](./by-example/new.md) - [Starting a new project](./by-example/new.md)
- [Tips & tricks](./by-example/tips.md) - [Tips & tricks](./by-example/tips.md)
- [Migrating from v0.4.x to v0.5.0](./migration.md) - [Migration Guides](./migration.md)
- [Migrating from RTFM to RTIC](./migration_rtic.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) - [Under the hood](./internals.md)
- [Interrupt configuration](./internals/interrupt-configuration.md) - [Interrupt configuration](./internals/interrupt-configuration.md)
- [Non-reentrancy](./internals/non-reentrancy.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. embedded development environment that includes QEMU.
[the embedded Rust book]: https://rust-embedded.github.io/book/intro/install.html [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 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. 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 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 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 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 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 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 ``` rust
{{#include ../../../../examples/pool.rs}} {{#include ../../../../examples/pool.rs}}
``` ```
``` console ``` console
$ cargo run --example pool $ cargo run --example pool
{{#include ../../../../ci/expected/pool.run}} {{#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 migrate between different version of RTIC.
It also acts as a comparing reference between versions.
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) {
// ..
}
};
```

View file

@ -8,14 +8,11 @@ change.
[RFC #33]: https://github.com/rtic-rs/rfcs/pull/33 [RFC #33]: https://github.com/rtic-rs/rfcs/pull/33
## `Cargo.toml` ## `Cargo.toml`
First, the `cortex-m-rtfm` dependency needs to be updated to First, the `cortex-m-rtfm` dependency needs to be updated to
`cortex-m-rtic`. `cortex-m-rtic`.
``` toml ``` toml
[dependencies] [dependencies]
# change this # 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)] #[rtic::app(device = lm3s6965, monotonic = rtic::cyccnt::CYCCNT)]
mod app { mod app {
#[init(spawn = [foo])] #[init(spawn = [foo])]
fn init(cx: init::Context) { fn init(cx: init::Context) -> init::LateResources {
// omitted: initialization of `CYCCNT` // omitted: initialization of `CYCCNT`
hprintln!("init(baseline = {:?})", cx.start).unwrap(); hprintln!("init(baseline = {:?})", cx.start).unwrap();
// `foo` inherits the baseline of `init`: `Instant(0)` // `foo` inherits the baseline of `init`: `Instant(0)`
cx.spawn.foo().unwrap(); cx.spawn.foo().unwrap();
init::LateResources {}
} }
#[task(schedule = [foo])] #[task(schedule = [foo])]

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -19,9 +19,11 @@ mod app {
} }
#[init] #[init]
fn init(_: init::Context) { fn init(_: init::Context) -> init::LateResources {
rtic::pend(Interrupt::UART0); rtic::pend(Interrupt::UART0);
rtic::pend(Interrupt::UART1); rtic::pend(Interrupt::UART1);
init::LateResources {}
} }
// `shared` cannot be accessed from this context // `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)] #[rtic::app(device = lm3s6965, monotonic = rtic::cyccnt::CYCCNT)]
mod app { mod app {
#[init(schedule = [foo, bar])] #[init(schedule = [foo, bar])]
fn init(mut cx: init::Context) { fn init(mut cx: init::Context) -> init::LateResources {
// Initialize (enable) the monotonic timer (CYCCNT) // Initialize (enable) the monotonic timer (CYCCNT)
cx.core.DCB.enable_trace(); cx.core.DCB.enable_trace();
// required on Cortex-M7 devices that software lock the DWT (e.g. STM32F7) // 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 // Schedule `bar` to run 4e6 cycles in the future
cx.schedule.bar(now + 4_000_000.cycles()).unwrap(); cx.schedule.bar(now + 4_000_000.cycles()).unwrap();
init::LateResources {}
} }
#[task] #[task]

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -32,7 +32,7 @@ mod app {
} }
#[init(resources = [o1, o4, o5, o6, s3])] #[init(resources = [o1, o4, o5, o6, s3])]
fn init(c: init::Context) { fn init(c: init::Context) -> init::LateResources {
// owned by `init` == `&'static mut` // owned by `init` == `&'static mut`
let _: &'static mut u32 = c.resources.o1; let _: &'static mut u32 = c.resources.o1;
@ -43,6 +43,8 @@ mod app {
let _: &mut u32 = c.resources.o4; let _: &mut u32 = c.resources.o4;
let _: &mut u32 = c.resources.o5; let _: &mut u32 = c.resources.o5;
let _: &mut u32 = c.resources.s3; let _: &mut u32 = c.resources.s3;
init::LateResources {}
} }
#[idle(resources = [o2, &o4, s1, &s3])] #[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)] #[rtic::app(device = lm3s6965, monotonic = rtic::cyccnt::CYCCNT)]
mod app { mod app {
#[init(schedule = [foo, bar, baz])] #[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<(), ()> = c.schedule.foo(c.start + 10.cycles());
let _: Result<(), u32> = c.schedule.bar(c.start + 20.cycles(), 0); let _: Result<(), u32> = c.schedule.bar(c.start + 20.cycles(), 0);
let _: Result<(), (u32, u32)> = c.schedule.baz(c.start + 30.cycles(), 0, 1); let _: Result<(), (u32, u32)> = c.schedule.baz(c.start + 30.cycles(), 0, 1);
init::LateResources {}
} }
#[idle(schedule = [foo, bar, baz])] #[idle(schedule = [foo, bar, baz])]

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -35,8 +35,7 @@ mod tests;
/// ///
/// The items allowed in the module block are specified below: /// The items allowed in the module block are specified below:
/// ///
/// # 1. `#[resources] /// # 1. `#[resources] struct <resource-name>`
/// struct <resource-name>`
/// ///
/// This structure contains the declaration of all the resources used by the application. Each field /// 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 /// 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)] #[rtic::app(device = lm3s6965)]
mod app { mod app {
#[init] #[init]
fn init(_: init::Context) { fn init(_: init::Context) -> init::LateResources {
#[cfg(never)] #[cfg(never)]
static mut FOO: u32 = 0; static mut FOO: u32 = 0;
FOO; FOO;
init::LateResources {}
} }
#[idle] #[idle]

View file

@ -5,27 +5,27 @@ error[E0425]: cannot find value `FOO` in this scope
| ^^^ not found in this scope | ^^^ not found in this scope
error[E0425]: cannot find value `FOO` 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 | ^^^ not found in this scope
error[E0425]: cannot find value `FOO` 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 | ^^^ not found in this scope
error[E0425]: cannot find value `FOO` 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 | ^^^ not found in this scope
error[E0425]: cannot find value `FOO` 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 | ^^^ not found in this scope
error: duplicate lang item in crate `panic_halt` (which `$CRATE` depends on): `panic_impl`. 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])] #[init(resources = [o1, o4, o5, o6, s3])]
fn init(c: init::Context) { fn init(c: init::Context) -> init::LateResources {
c.resources.o1; c.resources.o1;
c.resources.o4; c.resources.o4;
c.resources.o5; c.resources.o5;
c.resources.o6; c.resources.o6;
c.resources.s3; c.resources.s3;
init::LateResources {}
} }
#[idle(resources = [o2, &o4, s1, &s3])] #[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__` = note: available fields are: `__marker__`
error[E0609]: no field `o2` on type `idleResources<'_>` 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 | ^^ unknown field
| |
= note: available fields are: `__marker__` = note: available fields are: `__marker__`
error[E0609]: no field `o4` on type `idleResources<'_>` 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 | ^^ unknown field
| |
= note: available fields are: `__marker__` = note: available fields are: `__marker__`
error[E0609]: no field `s1` on type `idleResources<'_>` 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 | ^^ unknown field
| |
= note: available fields are: `__marker__` = note: available fields are: `__marker__`
error[E0609]: no field `s3` on type `idleResources<'_>` 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 | ^^ unknown field
| |
= note: available fields are: `__marker__` = note: available fields are: `__marker__`
error[E0609]: no field `o3` on type `uart0Resources<'_>` 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 | ^^ unknown field
| |
= note: available fields are: `__marker__` = note: available fields are: `__marker__`
error[E0609]: no field `s1` on type `uart0Resources<'_>` 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 | ^^ unknown field
| |
= note: available fields are: `__marker__` = note: available fields are: `__marker__`
error[E0609]: no field `s2` on type `uart0Resources<'_>` 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 | ^^ unknown field
| |
= note: available fields are: `__marker__` = note: available fields are: `__marker__`
error[E0609]: no field `s3` on type `uart0Resources<'_>` 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 | ^^ unknown field
| |
= note: available fields are: `__marker__` = note: available fields are: `__marker__`
error[E0609]: no field `s2` on type `uart1Resources<'_>` 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 | ^^ unknown field
| |
= note: available fields are: `__marker__` = note: available fields are: `__marker__`
error[E0609]: no field `o5` on type `uart1Resources<'_>` 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 | ^^ unknown field
| |
= note: available fields are: `__marker__` = note: available fields are: `__marker__`

View file

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