Merge branch 'master'

of https://github.com/rtic-rs/cortex-m-rtic
This commit is contained in:
Daniel Carosone 2020-10-07 09:22:38 +11:00
commit f386cb63cb
87 changed files with 1149 additions and 660 deletions

View file

@ -45,7 +45,6 @@ jobs:
- x86_64-unknown-linux-gnu - x86_64-unknown-linux-gnu
toolchain: toolchain:
- stable - stable
- 1.36.0
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v2 uses: actions/checkout@v2
@ -79,10 +78,6 @@ jobs:
target: ${{ matrix.target }} target: ${{ matrix.target }}
override: true override: true
- name: Disable optimisation profiles
if: matrix.toolchain == '1.36.0'
run: sed -i '/^\[profile.*build-override]$/,/^$/{/^#/!{/^$/!d}}' Cargo.toml
- name: cargo check - name: cargo check
uses: actions-rs/cargo@v1 uses: actions-rs/cargo@v1
with: with:
@ -90,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
@ -145,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
@ -306,7 +346,6 @@ jobs:
- x86_64-unknown-linux-gnu - x86_64-unknown-linux-gnu
toolchain: toolchain:
- stable - stable
- 1.36.0
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v2 uses: actions/checkout@v2
@ -340,10 +379,6 @@ jobs:
target: ${{ matrix.target }} target: ${{ matrix.target }}
override: true override: true
- name: Disable optimisation profiles
if: matrix.toolchain == '1.36.0'
run: sed -i '/^\[profile.*build-override]$/,/^$/{/^#/!{/^$/!d}}' Cargo.toml
- name: cargo check - name: cargo check
uses: actions-rs/cargo@v1 uses: actions-rs/cargo@v1
with: with:
@ -351,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
@ -382,13 +467,10 @@ jobs:
- name: Install Rust - name: Install Rust
uses: actions-rs/toolchain@v1 uses: actions-rs/toolchain@v1
with: with:
toolchain: 1.36.0 toolchain: stable
target: thumbv7m-none-eabi target: thumbv7m-none-eabi
override: true override: true
- name: Disable optimisation profiles
run: sed -i '/^\[profile.*build-override]$/,/^$/{/^#/!{/^$/!d}}' Cargo.toml
- uses: actions-rs/cargo@v1 - uses: actions-rs/cargo@v1
with: with:
use-cross: false use-cross: false
@ -426,13 +508,10 @@ jobs:
- name: Install Rust - name: Install Rust
uses: actions-rs/toolchain@v1 uses: actions-rs/toolchain@v1
with: with:
toolchain: 1.36.0 toolchain: stable
target: thumbv6m-none-eabi target: thumbv6m-none-eabi
override: true override: true
- name: Disable optimisation profiles
run: sed -i '/^\[profile.*build-override]$/,/^$/{/^#/!{/^$/!d}}' Cargo.toml
- uses: actions-rs/cargo@v1 - uses: actions-rs/cargo@v1
with: with:
use-cross: false use-cross: false
@ -529,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
@ -557,7 +636,9 @@ jobs:
- style - style
- check - check
- checkexamples - checkexamples
- testexamples
- checkmacros - checkmacros
- testmacros
- testv7 - testv7
- testv6 - testv6
- docs - docs
@ -582,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
@ -594,27 +674,37 @@ jobs:
- name: Build books - name: Build books
run: | run: |
langs=( en ru ) langs=( en ru )
latest=0.5 devver=( dev )
vers=( 0.4.x ) # 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 # Create directories
td=$(mktemp -d) td=$(mktemp -d)
mkdir -p $td/$latest/book/ mkdir -p $td/$devver/book/
cp -r target/doc $td/$latest/api cp -r target/doc $td/$devver/api
# sed fixes # Redirect the main site to the stable release
sed 's|URL|rtic/index.html|g' redirect.html > $td/$latest/api/index.html sed "s|URL|$stable|g" redirect.html > $td/index.html
sed 's|URL|0.5|g' redirect.html > $td/index.html
sed 's|URL|book/en|g' redirect.html > $td/$latest/index.html # Create the redirects for dev-version
sed 's|URL|rtic/index.html|g' redirect.html > $td/$devver/api/index.html
sed 's|URL|book/en|g' redirect.html > $td/$devver/index.html
# Build books # Build books
for lang in ${langs[@]}; do for lang in ${langs[@]}; do
( cd book/$lang && mdbook build ) ( cd book/$lang && mdbook build )
cp -r book/$lang/book $td/$latest/book/$lang cp -r book/$lang/book $td/$devver/book/$lang
cp LICENSE-* $td/$latest/book/$lang/ cp LICENSE-* $td/$devver/book/$lang/
done done
# Build older versions # Build older versions, including stable
root=$(pwd) root=$(pwd)
for ver in ${vers[@]}; do for ver in ${vers[@]}; do
prefix=${ver%.*} prefix=${ver%.*}
@ -639,6 +729,9 @@ jobs:
rm -rf $src rm -rf $src
done done
# Copy the stable book to the stable alias
cp -r $td/$stable $td/stable
# Forward CNAME file # Forward CNAME file
cp CNAME $td/ cp CNAME $td/
mv $td/ bookstodeploy mv $td/ bookstodeploy
@ -660,7 +753,9 @@ jobs:
- style - style
- check - check
- checkexamples - checkexamples
- testexamples
- checkmacros - checkmacros
- testmacros
- testv7 - testv7
- testv6 - testv6
- docs - docs
@ -676,7 +771,9 @@ jobs:
- style - style
- check - check
- checkexamples - checkexamples
- testexamples
- checkmacros - checkmacros
- testmacros
- testv7 - testv7
- testv6 - testv6
- docs - docs

View file

@ -60,6 +60,7 @@ cortex-m-rtic-macros = { path = "macros", version = "0.5.2" }
rtic-core = "0.3.0" rtic-core = "0.3.0"
cortex-m-rt = "0.6.9" cortex-m-rt = "0.6.9"
heapless = "0.5.0" heapless = "0.5.0"
bare-metal = "1.0.0"
[build-dependencies] [build-dependencies]
version_check = "0.9" version_check = "0.9"

View file

@ -4,9 +4,9 @@ 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)
## Features ## Features

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)
@ -21,5 +23,3 @@
- [Ceiling analysis](./internals/ceilings.md) - [Ceiling analysis](./internals/ceilings.md)
- [Software tasks](./internals/tasks.md) - [Software tasks](./internals/tasks.md)
- [Timer queue](./internals/timer-queue.md) - [Timer queue](./internals/timer-queue.md)
- [Homogeneous multi-core support](./homogeneous.md)
- [Heterogeneous multi-core support](./heterogeneous.md)

View file

@ -9,8 +9,16 @@ is required to follow along.
[repository]: https://github.com/rtic-rs/cortex-m-rtic [repository]: https://github.com/rtic-rs/cortex-m-rtic
To run the examples on your laptop / PC you'll need the `qemu-system-arm` To run the examples on your computer you'll need the `qemu-system-arm`
program. Check [the embedded Rust book] for instructions on how to set up an 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

@ -7,7 +7,7 @@ This is the smallest possible RTIC application:
``` ```
All RTIC applications use the [`app`] attribute (`#[app(..)]`). This attribute All RTIC applications use the [`app`] attribute (`#[app(..)]`). This attribute
must be applied to a `const` item that contains items. The `app` attribute has must be applied to a `mod`-item. The `app` attribute has
a mandatory `device` argument that takes a *path* as a value. This path must a mandatory `device` argument that takes a *path* as a value. This path must
point to a *peripheral access crate* (PAC) generated using [`svd2rust`] point to a *peripheral access crate* (PAC) generated using [`svd2rust`]
**v0.14.x** or newer. The `app` attribute will expand into a suitable entry **v0.14.x** or newer. The `app` attribute will expand into a suitable entry
@ -17,31 +17,25 @@ point so it's not required to use the [`cortex_m_rt::entry`] attribute.
[`svd2rust`]: https://crates.io/crates/svd2rust [`svd2rust`]: https://crates.io/crates/svd2rust
[`cortex_m_rt::entry`]: ../../../api/cortex_m_rt_macros/attr.entry.html [`cortex_m_rt::entry`]: ../../../api/cortex_m_rt_macros/attr.entry.html
> **ASIDE**: Some of you may be wondering why we are using a `const` item as a
> module and not a proper `mod` item. The reason is that using attributes on
> modules requires a feature gate, which requires a nightly toolchain. To make
> RTIC work on stable we use the `const` item instead. When more parts of macros
> 1.2 are stabilized we'll move from a `const` item to a `mod` item and
> eventually to a crate level attribute (`#![app]`).
## `init` ## `init`
Within the pseudo-module the `app` attribute expects to find an initialization Within the `app` module the attribute expects to find an initialization
function marked with the `init` attribute. This function must have signature function marked with the `init` attribute. This function must have signature
`fn(init::Context) [-> init::LateResources]` (the return type is not always `fn(init::Context) [-> init::LateResources]` (the return type is not always
required). required).
This initialization function will be the first part of the application to run. This initialization function will be the first part of the application to run.
The `init` function will run *with interrupts disabled* and has exclusive access The `init` function will run *with interrupts disabled* and has exclusive access
to Cortex-M and, optionally, device specific peripherals through the `core` and to Cortex-M where the `bare_metal::CriticalSection` token is available as `cs`.
`device` fields of `init::Context`. And optionally, device specific peripherals through the `core` and `device` fields
of `init::Context`.
`static mut` variables declared at the beginning of `init` will be transformed `static mut` variables declared at the beginning of `init` will be transformed
into `&'static mut` references that are safe to access. into `&'static mut` references that are safe to access.
[`rtic::Peripherals`]: ../../api/rtic/struct.Peripherals.html [`rtic::Peripherals`]: ../../api/rtic/struct.Peripherals.html
The example below shows the types of the `core` and `device` fields and The example below shows the types of the `core`, `device` and `cs` fields, and
showcases safe access to a `static mut` variable. The `device` field is only showcases safe access to a `static mut` variable. The `device` field is only
available when the `peripherals` argument is set to `true` (it defaults to available when the `peripherals` argument is set to `true` (it defaults to
`false`). `false`).
@ -61,7 +55,7 @@ $ cargo run --example init
## `idle` ## `idle`
A function marked with the `idle` attribute can optionally appear in the A function marked with the `idle` attribute can optionally appear in the
pseudo-module. This function is used as the special *idle task* and must have module. This function is used as the special *idle task* and must have
signature `fn(idle::Context) - > !`. signature `fn(idle::Context) - > !`.
When present, the runtime will execute the `idle` task after `init`. Unlike When present, the runtime will execute the `idle` task after `init`. Unlike

View file

@ -4,11 +4,13 @@ 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.
Resources are data visible only to functions declared within the `#[app]` Resources are data visible only to functions declared within the `#[app]`
pseudo-module. The framework gives the user complete control over which context module. The framework gives the user complete control over which context
can access which resource. can access which resource.
All resources are declared as a single `struct` within the `#[app]` All resources are declared as a single `struct` within the `#[app]`
pseudo-module. Each field in the structure corresponds to a different resource. module. Each field in the structure corresponds to a different resource.
The `struct` must be annotated with the following attribute: `#[resources]`.
Resources can optionally be given an initial value using the `#[init]` Resources can optionally be given an initial value using the `#[init]`
attribute. Resources that are not given an initial value are referred to as attribute. Resources that are not given an initial value are referred to as
*late* resources and are covered in more detail in a follow-up section in this *late* resources and are covered in more detail in a follow-up section in this

View file

@ -95,7 +95,7 @@ following snippet:
``` rust ``` rust
#[rtic::app(..)] #[rtic::app(..)]
const APP: () = { mod app {
#[init(spawn = [foo, bar])] #[init(spawn = [foo, bar])]
fn init(cx: init::Context) { fn init(cx: init::Context) {
cx.spawn.foo().unwrap(); cx.spawn.foo().unwrap();
@ -116,5 +116,5 @@ const APP: () = {
fn bar(cx: bar::Context, payload: i32) { fn bar(cx: bar::Context, payload: i32) {
// .. // ..
} }
}; }
``` ```

View file

@ -144,7 +144,7 @@ $ tail target/rtic-expansion.rs
``` rust ``` rust
#[doc = r" Implementation details"] #[doc = r" Implementation details"]
const APP: () = { mod app {
#[doc = r" Always include the device crate which contains the vector table"] #[doc = r" Always include the device crate which contains the vector table"]
use lm3s6965 as _; use lm3s6965 as _;
#[no_mangle] #[no_mangle]
@ -157,7 +157,7 @@ const APP: () = {
rtic::export::wfi() rtic::export::wfi()
} }
} }
}; }
``` ```
Or, you can use the [`cargo-expand`] sub-command. This sub-command will expand Or, you can use the [`cargo-expand`] sub-command. This sub-command will expand

View file

@ -1,6 +1,6 @@
# Types, Send and Sync # Types, Send and Sync
Every function within the `APP` pseudo-module has a `Context` structure as its Every function within the `app` module has a `Context` structure as its
first parameter. All the fields of these structures have predictable, first parameter. All the fields of these structures have predictable,
non-anonymous types so you can write plain functions that take them as arguments. non-anonymous types so you can write plain functions that take them as arguments.

View file

@ -1,6 +0,0 @@
# Heterogeneous multi-core support
This section covers the *experimental* heterogeneous multi-core support provided
by RTIC behind the `heterogeneous` Cargo feature.
**Content coming soon**

View file

@ -1,6 +0,0 @@
# Homogeneous multi-core support
This section covers the *experimental* homogeneous multi-core support provided
by RTIC behind the `homogeneous` Cargo feature.
**Content coming soon**

View file

@ -15,7 +15,7 @@ To achieve the fine-grained access control where tasks can only access the
static variables (resources) that they have specified in their RTIC attribute static variables (resources) that they have specified in their RTIC attribute
the RTIC framework performs a source code level transformation. This the RTIC framework performs a source code level transformation. This
transformation consists of placing the resources (static variables) specified by transformation consists of placing the resources (static variables) specified by
the user *inside* a `const` item and the user code *outside* the `const` item. the user *inside* a module and the user code *outside* the module.
This makes it impossible for the user code to refer to these static variables. This makes it impossible for the user code to refer to these static variables.
Access to the resources is then given to each task using a `Resources` struct Access to the resources is then given to each task using a `Resources` struct
@ -29,7 +29,7 @@ happens behind the scenes:
``` rust ``` rust
#[rtic::app(device = ..)] #[rtic::app(device = ..)]
const APP: () = { mod app {
static mut X: u64: 0; static mut X: u64: 0;
static mut Y: bool: 0; static mut Y: bool: 0;
@ -49,7 +49,7 @@ const APP: () = {
} }
// .. // ..
}; }
``` ```
The framework produces codes like this: The framework produces codes like this:
@ -103,8 +103,8 @@ pub mod bar {
} }
/// Implementation details /// Implementation details
const APP: () = { mod app {
// everything inside this `const` item is hidden from user code // everything inside this module is hidden from user code
static mut X: u64 = 0; static mut X: u64 = 0;
static mut Y: bool = 0; static mut Y: bool = 0;
@ -154,5 +154,5 @@ const APP: () = {
// .. // ..
}); });
} }
}; }
``` ```

View file

@ -28,7 +28,7 @@ An example to illustrate the ceiling analysis:
``` rust ``` rust
#[rtic::app(device = ..)] #[rtic::app(device = ..)]
const APP: () = { mod app {
struct Resources { struct Resources {
// accessed by `foo` (prio = 1) and `bar` (prio = 2) // accessed by `foo` (prio = 1) and `bar` (prio = 2)
// -> CEILING = 2 // -> CEILING = 2
@ -80,5 +80,5 @@ const APP: () = {
} }
// .. // ..
}; }
``` ```

View file

@ -32,7 +32,7 @@ The example below shows the different types handed out to each task:
``` rust ``` rust
#[rtic::app(device = ..)] #[rtic::app(device = ..)]
const APP: () = { mut app {
struct Resources { struct Resources {
#[init(0)] #[init(0)]
x: u64, x: u64,
@ -57,7 +57,7 @@ const APP: () = {
} }
// .. // ..
}; }
``` ```
Now let's see how these types are created by the framework. Now let's see how these types are created by the framework.
@ -99,7 +99,7 @@ pub mod bar {
} }
} }
const APP: () = { mod app {
static mut x: u64 = 0; static mut x: u64 = 0;
impl rtic::Mutex for resources::x { impl rtic::Mutex for resources::x {
@ -129,7 +129,7 @@ const APP: () = {
// .. // ..
}) })
} }
}; }
``` ```
## `lock` ## `lock`
@ -225,7 +225,7 @@ Consider this program:
``` rust ``` rust
#[rtic::app(device = ..)] #[rtic::app(device = ..)]
const APP: () = { mod app {
struct Resources { struct Resources {
#[init(0)] #[init(0)]
x: u64, x: u64,
@ -277,7 +277,7 @@ const APP: () = {
} }
// .. // ..
}; }
``` ```
The code generated by the framework looks like this: The code generated by the framework looks like this:
@ -315,7 +315,7 @@ pub mod foo {
} }
} }
const APP: () = { mod app {
use cortex_m::register::basepri; use cortex_m::register::basepri;
#[no_mangle] #[no_mangle]
@ -368,7 +368,7 @@ const APP: () = {
} }
// repeat for resource `y` // repeat for resource `y`
}; }
``` ```
At the end the compiler will optimize the function `foo` into something like At the end the compiler will optimize the function `foo` into something like
@ -430,7 +430,7 @@ handler through preemption. This is best observed in the following example:
``` rust ``` rust
#[rtic::app(device = ..)] #[rtic::app(device = ..)]
const APP: () = { mod app {
struct Resources { struct Resources {
#[init(0)] #[init(0)]
x: u64, x: u64,
@ -484,7 +484,7 @@ const APP: () = {
// .. // ..
} }
}; }
``` ```
IMPORTANT: let's say we *forget* to roll back `BASEPRI` in `UART1` -- this would IMPORTANT: let's say we *forget* to roll back `BASEPRI` in `UART1` -- this would
@ -493,7 +493,7 @@ be a bug in the RTIC code generator.
``` rust ``` rust
// code generated by RTIC // code generated by RTIC
const APP: () = { mod app {
// .. // ..
#[no_mangle] #[no_mangle]
@ -513,7 +513,7 @@ const APP: () = {
// BUG: FORGOT to roll back the BASEPRI to the snapshot value we took before // BUG: FORGOT to roll back the BASEPRI to the snapshot value we took before
basepri::write(initial); basepri::write(initial);
} }
}; }
``` ```
The consequence is that `idle` will run at a dynamic priority of `2` and in fact The consequence is that `idle` will run at a dynamic priority of `2` and in fact

View file

@ -13,7 +13,7 @@ This example gives you an idea of the code that the RTIC framework runs:
``` rust ``` rust
#[rtic::app(device = lm3s6965)] #[rtic::app(device = lm3s6965)]
const APP: () = { mod app {
#[init] #[init]
fn init(c: init::Context) { fn init(c: init::Context) {
// .. user code .. // .. user code ..
@ -28,7 +28,7 @@ const APP: () = {
fn foo(c: foo::Context) { fn foo(c: foo::Context) {
// .. user code .. // .. user code ..
} }
}; }
``` ```
The framework generates an entry point that looks like this: The framework generates an entry point that looks like this:

View file

@ -10,7 +10,7 @@ initialize late resources.
``` rust ``` rust
#[rtic::app(device = ..)] #[rtic::app(device = ..)]
const APP: () = { mod app {
struct Resources { struct Resources {
x: Thing, x: Thing,
} }
@ -34,7 +34,7 @@ const APP: () = {
} }
// .. // ..
}; }
``` ```
The code generated by the framework looks like this: The code generated by the framework looks like this:
@ -69,7 +69,7 @@ pub mod foo {
} }
/// Implementation details /// Implementation details
const APP: () = { mod app {
// uninitialized static // uninitialized static
static mut x: MaybeUninit<Thing> = MaybeUninit::uninit(); static mut x: MaybeUninit<Thing> = MaybeUninit::uninit();
@ -101,7 +101,7 @@ const APP: () = {
// .. // ..
}) })
} }
}; }
``` ```
An important detail here is that `interrupt::enable` behaves like a *compiler An important detail here is that `interrupt::enable` behaves like a *compiler

View file

@ -12,7 +12,7 @@ are discouraged from directly invoking an interrupt handler.
``` rust ``` rust
#[rtic::app(device = ..)] #[rtic::app(device = ..)]
const APP: () = { mod app {
#[init] #[init]
fn init(c: init::Context) { .. } fn init(c: init::Context) { .. }
@ -39,7 +39,7 @@ const APP: () = {
// in aliasing of the static variable `X` // in aliasing of the static variable `X`
unsafe { UART0() } unsafe { UART0() }
} }
}; }
``` ```
The RTIC framework must generate the interrupt handler code that calls the user The RTIC framework must generate the interrupt handler code that calls the user
@ -57,7 +57,7 @@ fn bar(c: bar::Context) {
// .. user code .. // .. user code ..
} }
const APP: () = { mod app {
// everything in this block is not visible to user code // everything in this block is not visible to user code
#[no_mangle] #[no_mangle]
@ -69,7 +69,7 @@ const APP: () = {
unsafe fn USART1() { unsafe fn USART1() {
bar(..); bar(..);
} }
}; }
``` ```
## By hardware ## By hardware

View file

@ -28,7 +28,7 @@ Consider this example:
``` rust ``` rust
#[rtic::app(device = ..)] #[rtic::app(device = ..)]
const APP: () = { mod app {
// .. // ..
#[interrupt(binds = UART0, priority = 2, spawn = [bar, baz])] #[interrupt(binds = UART0, priority = 2, spawn = [bar, baz])]
@ -51,7 +51,7 @@ const APP: () = {
extern "C" { extern "C" {
fn UART1(); fn UART1();
} }
}; }
``` ```
The framework produces the following task dispatcher which consists of an The framework produces the following task dispatcher which consists of an
@ -62,7 +62,7 @@ fn bar(c: bar::Context) {
// .. user code .. // .. user code ..
} }
const APP: () = { mod app {
use heapless::spsc::Queue; use heapless::spsc::Queue;
use cortex_m::register::basepri; use cortex_m::register::basepri;
@ -110,7 +110,7 @@ const APP: () = {
// BASEPRI invariant // BASEPRI invariant
basepri::write(snapshot); basepri::write(snapshot);
} }
}; }
``` ```
## Spawning a task ## Spawning a task
@ -144,7 +144,7 @@ mod foo {
} }
} }
const APP: () = { mod app {
// .. // ..
// Priority ceiling for the producer endpoint of the `RQ1` // Priority ceiling for the producer endpoint of the `RQ1`
@ -194,7 +194,7 @@ const APP: () = {
} }
} }
} }
}; }
``` ```
Using `bar_FQ` to limit the number of `bar` tasks that can be spawned may seem Using `bar_FQ` to limit the number of `bar` tasks that can be spawned may seem
@ -211,7 +211,7 @@ fn baz(c: baz::Context, input: u64) {
// .. user code .. // .. user code ..
} }
const APP: () = { mod app {
// .. // ..
// Now we show the full contents of the `Ready` struct // Now we show the full contents of the `Ready` struct
@ -263,13 +263,13 @@ const APP: () = {
} }
} }
} }
}; }
``` ```
And now let's look at the real implementation of the task dispatcher: And now let's look at the real implementation of the task dispatcher:
``` rust ``` rust
const APP: () = { mod app {
// .. // ..
#[no_mangle] #[no_mangle]
@ -304,7 +304,7 @@ const APP: () = {
// BASEPRI invariant // BASEPRI invariant
basepri::write(snapshot); basepri::write(snapshot);
} }
}; }
``` ```
`INPUTS` plus `FQ`, the free queue, is effectively a memory pool. However, `INPUTS` plus `FQ`, the free queue, is effectively a memory pool. However,
@ -357,7 +357,7 @@ Consider the following example:
``` rust ``` rust
#[rtic::app(device = ..)] #[rtic::app(device = ..)]
const APP: () = { mod app {
#[idle(spawn = [foo, bar])] #[idle(spawn = [foo, bar])]
fn idle(c: idle::Context) -> ! { fn idle(c: idle::Context) -> ! {
// .. // ..
@ -382,7 +382,7 @@ const APP: () = {
fn quux(c: quux::Context) { fn quux(c: quux::Context) {
// .. // ..
} }
}; }
``` ```
This is how the ceiling analysis would go: This is how the ceiling analysis would go:

View file

@ -12,7 +12,7 @@ Let's see how this in implemented in code. Consider the following program:
``` rust ``` rust
#[rtic::app(device = ..)] #[rtic::app(device = ..)]
const APP: () = { mod app {
// .. // ..
#[task(capacity = 2, schedule = [foo])] #[task(capacity = 2, schedule = [foo])]
@ -24,7 +24,7 @@ const APP: () = {
extern "C" { extern "C" {
fn UART0(); fn UART0();
} }
}; }
``` ```
## `schedule` ## `schedule`
@ -46,7 +46,7 @@ mod foo {
} }
} }
const APP: () = { mod app {
type Instant = <path::to::user::monotonic::timer as rtic::Monotonic>::Instant; type Instant = <path::to::user::monotonic::timer as rtic::Monotonic>::Instant;
// all tasks that can be `schedule`-d // all tasks that can be `schedule`-d
@ -100,7 +100,7 @@ const APP: () = {
} }
} }
} }
}; }
``` ```
This looks very similar to the `Spawn` implementation. In fact, the same This looks very similar to the `Spawn` implementation. In fact, the same
@ -123,7 +123,7 @@ is up.
Let's see the associated code. Let's see the associated code.
``` rust ``` rust
const APP: () = { mod app {
#[no_mangle] #[no_mangle]
fn SysTick() { fn SysTick() {
const PRIORITY: u8 = 1; const PRIORITY: u8 = 1;
@ -146,7 +146,7 @@ const APP: () = {
} }
} }
} }
}; }
``` ```
This looks similar to a task dispatcher except that instead of running the This looks similar to a task dispatcher except that instead of running the
@ -197,7 +197,7 @@ able to insert the task in the timer queue; this lets us omit runtime checks.
## System timer priority ## System timer priority
The priority of the system timer can't set by the user; it is chosen by the The priority of the system timer can't be set by the user; it is chosen by the
framework. To ensure that lower priority tasks don't prevent higher priority framework. To ensure that lower priority tasks don't prevent higher priority
tasks from running we choose the priority of the system timer to be the maximum tasks from running we choose the priority of the system timer to be the maximum
of all the `schedule`-able tasks. of all the `schedule`-able tasks.
@ -222,7 +222,7 @@ To illustrate, consider the following example:
``` rust ``` rust
#[rtic::app(device = ..)] #[rtic::app(device = ..)]
const APP: () = { mod app {
#[task(priority = 3, spawn = [baz])] #[task(priority = 3, spawn = [baz])]
fn foo(c: foo::Context) { fn foo(c: foo::Context) {
// .. // ..
@ -237,7 +237,7 @@ const APP: () = {
fn baz(c: baz::Context) { fn baz(c: baz::Context) {
// .. // ..
} }
}; }
``` ```
The ceiling analysis would go like this: The ceiling analysis would go like this:
@ -246,7 +246,7 @@ The ceiling analysis would go like this:
`SysTick` must run at the highest priority between these two, that is `3`. `SysTick` must run at the highest priority between these two, that is `3`.
- `foo::Spawn` (prio = 3) and `bar::Schedule` (prio = 2) contend over the - `foo::Spawn` (prio = 3) and `bar::Schedule` (prio = 2) contend over the
consumer endpoind of `baz_FQ`; this leads to a priority ceiling of `3`. consumer endpoint of `baz_FQ`; this leads to a priority ceiling of `3`.
- `bar::Schedule` (prio = 2) has exclusive access over the consumer endpoint of - `bar::Schedule` (prio = 2) has exclusive access over the consumer endpoint of
`foo_FQ`; thus the priority ceiling of `foo_FQ` is effectively `2`. `foo_FQ`; thus the priority ceiling of `foo_FQ` is effectively `2`.
@ -270,7 +270,7 @@ run; this `Instant` is read in the task dispatcher and passed to the user code
as part of the task context. as part of the task context.
``` rust ``` rust
const APP: () = { mod app {
// .. // ..
#[no_mangle] #[no_mangle]
@ -303,7 +303,7 @@ const APP: () = {
// BASEPRI invariant // BASEPRI invariant
basepri::write(snapshot); basepri::write(snapshot);
} }
}; }
``` ```
Conversely, the `spawn` implementation needs to write a value to the `INSTANTS` Conversely, the `spawn` implementation needs to write a value to the `INSTANTS`
@ -333,7 +333,7 @@ mod foo {
} }
} }
const APP: () = { mod app {
impl<'a> foo::Spawn<'a> { impl<'a> foo::Spawn<'a> {
/// Spawns the `baz` task /// Spawns the `baz` task
pub fn baz(&self, message: u64) -> Result<(), u64> { pub fn baz(&self, message: u64) -> Result<(), u64> {
@ -364,5 +364,5 @@ const APP: () = {
} }
} }
} }
}; }
``` ```

View file

@ -1,232 +1,4 @@
# Migrating from v0.4.x to v0.5.0 # Migration Guides
This section covers how to upgrade an application written against RTIC v0.4.x to This section describes how to migrate between different version of RTIC.
the version v0.5.0 of the framework. It also acts as a comparing reference between versions.
## `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

@ -0,0 +1,232 @@
# 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

@ -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,8 +13,10 @@ There is a translation of this book in [Russian].
[Russian]: ../ru/index.html [Russian]: ../ru/index.html
This is the documentation of v0.5.x of RTIC; for the documentation of version This is the documentation of v0.6.x of RTIC; for the documentation of version
v0.4.x go [here](/0.4).
* v0.5.x go [here](/0.5).
* v0.4.x go [here](/0.4).
{{#include ../../../README.md:7:46}} {{#include ../../../README.md:7:46}}

View file

@ -11,15 +11,17 @@ use panic_semihosting as _;
// NOTE: does NOT properly work on QEMU // NOTE: does NOT properly work on QEMU
#[rtic::app(device = lm3s6965, monotonic = rtic::cyccnt::CYCCNT)] #[rtic::app(device = lm3s6965, monotonic = rtic::cyccnt::CYCCNT)]
const 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])]
@ -51,4 +53,4 @@ const APP: () = {
extern "C" { extern "C" {
fn SSI0(); fn SSI0();
} }
}; }

View file

@ -11,12 +11,14 @@ use panic_semihosting as _;
// `examples/interrupt.rs` rewritten to use `binds` // `examples/interrupt.rs` rewritten to use `binds`
#[rtic::app(device = lm3s6965)] #[rtic::app(device = lm3s6965)]
const 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]
@ -45,4 +47,4 @@ const APP: () = {
) )
.unwrap(); .unwrap();
} }
}; }

View file

@ -10,10 +10,12 @@ use lm3s6965::Interrupt;
use panic_semihosting as _; use panic_semihosting as _;
#[rtic::app(device = lm3s6965)] #[rtic::app(device = lm3s6965)]
const 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])]
@ -44,4 +46,4 @@ const APP: () = {
extern "C" { extern "C" {
fn SSI0(); fn SSI0();
} }
}; }

View file

@ -11,7 +11,8 @@ use cortex_m_semihosting::hprintln;
use panic_semihosting as _; use panic_semihosting as _;
#[rtic::app(device = lm3s6965)] #[rtic::app(device = lm3s6965)]
const APP: () = { mod app {
#[resources]
struct Resources { struct Resources {
#[cfg(debug_assertions)] // <- `true` when using the `dev` profile #[cfg(debug_assertions)] // <- `true` when using the `dev` profile
#[init(0)] #[init(0)]
@ -19,9 +20,11 @@ const 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]
@ -66,4 +69,4 @@ const APP: () = {
fn SSI0(); fn SSI0();
fn QEI0(); fn QEI0();
} }
}; }

View file

@ -10,7 +10,8 @@ use lm3s6965::Interrupt;
use panic_semihosting as _; use panic_semihosting as _;
#[rtic::app(device = lm3s6965)] #[rtic::app(device = lm3s6965)]
const APP: () = { mod app {
#[resources]
struct Resources { struct Resources {
// Some resources to work with // Some resources to work with
#[init(0)] #[init(0)]
@ -22,9 +23,11 @@ const 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
@ -44,4 +47,4 @@ const APP: () = {
hprintln!("UART0: a = {}, b = {}, c = {}", a, b, c).unwrap(); hprintln!("UART0: a = {}, b = {}, c = {}", a, b, c).unwrap();
} }
}; }

View file

@ -9,7 +9,9 @@ use panic_semihosting as _;
use rtic::cyccnt::U32Ext; use rtic::cyccnt::U32Ext;
#[rtic::app(device = lm3s6965, monotonic = rtic::cyccnt::CYCCNT)] #[rtic::app(device = lm3s6965, monotonic = rtic::cyccnt::CYCCNT)]
const APP: () = { mod app {
#[resources]
struct Resources { struct Resources {
nothing: (), nothing: (),
} }
@ -34,4 +36,4 @@ const APP: () = {
extern "C" { extern "C" {
fn SSI0(); fn SSI0();
} }
}; }

View file

@ -11,16 +11,19 @@ use panic_semihosting as _;
use rtic::{Exclusive, Mutex}; use rtic::{Exclusive, Mutex};
#[rtic::app(device = lm3s6965)] #[rtic::app(device = lm3s6965)]
const APP: () = { mod app {
#[resources]
struct Resources { struct Resources {
#[init(0)] #[init(0)]
shared: u32, shared: u32,
} }
#[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])]
@ -49,7 +52,7 @@ const APP: () = {
// second argument has type `Exclusive<u32>` // second argument has type `Exclusive<u32>`
advance(STATE, Exclusive(c.resources.shared)); advance(STATE, Exclusive(c.resources.shared));
} }
}; }
// the second parameter is generic: it can be any type that implements the `Mutex` trait // the second parameter is generic: it can be any type that implements the `Mutex` trait
fn advance(state: &mut u32, mut shared: impl Mutex<T = u32>) { fn advance(state: &mut u32, mut shared: impl Mutex<T = u32>) {

View file

@ -10,14 +10,16 @@ use lm3s6965::Interrupt;
use panic_semihosting as _; use panic_semihosting as _;
#[rtic::app(device = lm3s6965)] #[rtic::app(device = lm3s6965)]
const 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]
@ -49,4 +51,4 @@ const APP: () = {
) )
.unwrap(); .unwrap();
} }
}; }

View file

@ -9,10 +9,12 @@ use cortex_m_semihosting::{debug, hprintln};
use panic_semihosting as _; use panic_semihosting as _;
#[rtic::app(device = lm3s6965)] #[rtic::app(device = lm3s6965)]
const 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]
@ -30,4 +32,4 @@ const APP: () = {
cortex_m::asm::nop(); cortex_m::asm::nop();
} }
} }
}; }

View file

@ -9,9 +9,9 @@ use cortex_m_semihosting::{debug, hprintln};
use panic_semihosting as _; use panic_semihosting as _;
#[rtic::app(device = lm3s6965, peripherals = true)] #[rtic::app(device = lm3s6965, peripherals = true)]
const 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
@ -23,8 +23,14 @@ const APP: () = {
// Safe access to local `static mut` variable // Safe access to local `static mut` variable
let _x: &'static mut u32 = X; let _x: &'static mut u32 = X;
// Access to the critical section token,
// to indicate that this is a critical seciton
let _cs_token: bare_metal::CriticalSection = cx.cs;
hprintln!("init").unwrap(); hprintln!("init").unwrap();
debug::exit(debug::EXIT_SUCCESS); debug::exit(debug::EXIT_SUCCESS);
init::LateResources {}
} }
}; }

View file

@ -15,8 +15,13 @@ use lm3s6965::Interrupt;
use panic_semihosting as _; use panic_semihosting as _;
#[rtic::app(device = lm3s6965)] #[rtic::app(device = lm3s6965)]
const APP: () = { mod app {
use heapless::{
consts::*,
spsc::{Consumer, Producer},
};
// Late resources // Late resources
#[resources]
struct Resources { struct Resources {
p: Producer<'static, u32, U4>, p: Producer<'static, u32, U4>,
c: Consumer<'static, u32, U4>, c: Consumer<'static, u32, U4>,
@ -49,4 +54,4 @@ const APP: () = {
fn uart0(c: uart0::Context) { fn uart0(c: uart0::Context) {
c.resources.p.enqueue(42).unwrap(); c.resources.p.enqueue(42).unwrap();
} }
}; }

View file

@ -10,15 +10,18 @@ use lm3s6965::Interrupt;
use panic_semihosting as _; use panic_semihosting as _;
#[rtic::app(device = lm3s6965)] #[rtic::app(device = lm3s6965)]
const APP: () = { mod app {
#[resources]
struct Resources { struct Resources {
#[init(0)] #[init(0)]
shared: u32, shared: u32,
} }
#[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`
@ -59,4 +62,4 @@ const APP: () = {
fn gpioc(_: gpioc::Context) { fn gpioc(_: gpioc::Context) {
hprintln!("C").unwrap(); hprintln!("C").unwrap();
} }
}; }

View file

@ -9,10 +9,12 @@ use cortex_m_semihosting::{debug, hprintln};
use panic_semihosting as _; use panic_semihosting as _;
#[rtic::app(device = lm3s6965)] #[rtic::app(device = lm3s6965)]
const 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])]
@ -49,4 +51,4 @@ const APP: () = {
extern "C" { extern "C" {
fn SSI0(); fn SSI0();
} }
}; }

View file

@ -16,16 +16,21 @@ pub struct NotSend {
} }
#[app(device = lm3s6965)] #[app(device = lm3s6965)]
const APP: () = { mod app {
use super::NotSend;
#[resources]
struct Resources { struct Resources {
#[init(None)] #[init(None)]
shared: Option<NotSend>, shared: Option<NotSend>,
} }
#[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])]
@ -60,4 +65,4 @@ const APP: () = {
fn SSI0(); fn SSI0();
fn QEI0(); fn QEI0();
} }
}; }

View file

@ -15,15 +15,21 @@ pub struct NotSync {
} }
#[rtic::app(device = lm3s6965)] #[rtic::app(device = lm3s6965)]
const APP: () = { mod app {
use super::NotSync;
use core::marker::PhantomData;
#[resources]
struct Resources { struct Resources {
#[init(NotSync { _0: PhantomData })] #[init(NotSync { _0: PhantomData })]
shared: NotSync, shared: NotSync,
} }
#[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])]
@ -42,4 +48,4 @@ const APP: () = {
extern "C" { extern "C" {
fn SSI0(); fn SSI0();
} }
}; }

View file

@ -10,7 +10,8 @@ use lm3s6965::Interrupt;
use panic_semihosting as _; use panic_semihosting as _;
#[rtic::app(device = lm3s6965)] #[rtic::app(device = lm3s6965)]
const APP: () = { mod app {
#[resources]
struct Resources { struct Resources {
key: u32, key: u32,
} }
@ -35,4 +36,4 @@ const APP: () = {
fn uart1(cx: uart1::Context) { fn uart1(cx: uart1::Context) {
hprintln!("UART1(key = {:#x})", cx.resources.key).unwrap(); hprintln!("UART1(key = {:#x})", cx.resources.key).unwrap();
} }
}; }

View file

@ -13,12 +13,15 @@ const PERIOD: u32 = 8_000_000;
// NOTE: does NOT work on QEMU! // NOTE: does NOT work on QEMU!
#[rtic::app(device = lm3s6965, monotonic = rtic::cyccnt::CYCCNT)] #[rtic::app(device = lm3s6965, monotonic = rtic::cyccnt::CYCCNT)]
const 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])]
@ -35,4 +38,4 @@ const APP: () = {
extern "C" { extern "C" {
fn SSI0(); fn SSI0();
} }
}; }

View file

@ -7,10 +7,12 @@ use cortex_m_semihosting::debug;
use panic_semihosting as _; use panic_semihosting as _;
#[rtic::app(device = lm3s6965)] #[rtic::app(device = lm3s6965)]
const APP: () = { mod app {
#[init] #[init]
fn main(_: main::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

@ -18,15 +18,22 @@ use rtic::app;
pool!(P: [u8; 128]); pool!(P: [u8; 128]);
#[app(device = lm3s6965)] #[app(device = lm3s6965)]
const APP: () = { mod app {
use crate::Box;
// Import the memory pool into scope
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])]
@ -66,4 +73,4 @@ const APP: () = {
fn SSI0(); fn SSI0();
fn QEI0(); fn QEI0();
} }
}; }

View file

@ -9,10 +9,12 @@ use panic_semihosting as _;
use rtic::app; use rtic::app;
#[app(device = lm3s6965)] #[app(device = lm3s6965)]
const 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)]
@ -34,4 +36,4 @@ const APP: () = {
rtic::pend(Interrupt::GPIOB); rtic::pend(Interrupt::GPIOB);
hprintln!(" GPIOC - end").unwrap(); hprintln!(" GPIOC - end").unwrap();
} }
}; }

View file

@ -9,10 +9,12 @@ use cortex_m_semihosting::{debug, hprintln};
use panic_semihosting as _; use panic_semihosting as _;
#[rtic::app(device = lm3s6965)] #[rtic::app(device = lm3s6965)]
const 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)]
@ -38,4 +40,4 @@ const APP: () = {
#[link_section = ".data.UART1"] #[link_section = ".data.UART1"]
fn UART1(); fn UART1();
} }
}; }

View file

@ -0,0 +1,63 @@
//! examples/resource.rs
#![deny(unsafe_code)]
#![deny(warnings)]
#![no_main]
#![no_std]
use cortex_m_semihosting::{debug, hprintln};
use lm3s6965::Interrupt;
use panic_semihosting as _;
#[rtic::app(device = lm3s6965)]
mod app {
#[resources]
struct Resources {
// A resource
#[init(0)]
shared: u32,
}
// Should not collide with the struct above
#[allow(dead_code)]
struct Resources2 {
// A resource
shared: u32,
}
#[init]
fn init(_: init::Context) -> init::LateResources {
rtic::pend(Interrupt::UART0);
rtic::pend(Interrupt::UART1);
init::LateResources {}
}
// `shared` cannot be accessed from this context
#[idle]
fn idle(_cx: idle::Context) -> ! {
debug::exit(debug::EXIT_SUCCESS);
// error: no `resources` field in `idle::Context`
// _cx.resources.shared += 1;
loop {}
}
// `shared` can be accessed from this context
#[task(binds = UART0, resources = [shared])]
fn uart0(cx: uart0::Context) {
let shared: &mut u32 = cx.resources.shared;
*shared += 1;
hprintln!("UART0: shared = {}", shared).unwrap();
}
// `shared` can be accessed from this context
#[task(binds = UART1, resources = [shared])]
fn uart1(cx: uart1::Context) {
*cx.resources.shared += 1;
hprintln!("UART1: shared = {}", cx.resources.shared).unwrap();
}
}

View file

@ -10,7 +10,8 @@ use lm3s6965::Interrupt;
use panic_semihosting as _; use panic_semihosting as _;
#[rtic::app(device = lm3s6965)] #[rtic::app(device = lm3s6965)]
const APP: () = { mod app {
#[resources]
struct Resources { struct Resources {
// A resource // A resource
#[init(0)] #[init(0)]
@ -18,9 +19,11 @@ const 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
@ -52,4 +55,4 @@ const APP: () = {
hprintln!("UART1: shared = {}", cx.resources.shared).unwrap(); hprintln!("UART1: shared = {}", cx.resources.shared).unwrap();
} }
}; }

View file

@ -12,9 +12,9 @@ use rtic::cyccnt::{Instant, U32Ext as _};
// NOTE: does NOT work on QEMU! // NOTE: does NOT work on QEMU!
#[rtic::app(device = lm3s6965, monotonic = rtic::cyccnt::CYCCNT)] #[rtic::app(device = lm3s6965, monotonic = rtic::cyccnt::CYCCNT)]
const 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 @@ const 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]
@ -50,4 +52,4 @@ const APP: () = {
extern "C" { extern "C" {
fn SSI0(); fn SSI0();
} }
}; }

View file

@ -13,19 +13,24 @@ use rtic::app;
pub struct MustBeSend; pub struct MustBeSend;
#[app(device = lm3s6965)] #[app(device = lm3s6965)]
const APP: () = { mod app {
use super::MustBeSend;
#[resources]
struct Resources { struct Resources {
#[init(None)] #[init(None)]
shared: Option<MustBeSend>, shared: Option<MustBeSend>,
} }
#[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])]
@ -37,4 +42,4 @@ const APP: () = {
debug::exit(debug::EXIT_SUCCESS); debug::exit(debug::EXIT_SUCCESS);
} }
} }
}; }

View file

@ -7,4 +7,4 @@ use panic_semihosting as _; // panic handler
use rtic::app; use rtic::app;
#[app(device = lm3s6965)] #[app(device = lm3s6965)]
const APP: () = {}; mod app {}

View file

@ -8,9 +8,11 @@
use panic_halt as _; use panic_halt as _;
#[rtic::app(device = lm3s6965)] #[rtic::app(device = lm3s6965)]
const 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)]
@ -23,7 +25,7 @@ const APP: () = {
fn bar(c: bar::Context) { fn bar(c: bar::Context) {
bar_trampoline(c) bar_trampoline(c)
} }
}; }
#[allow(dead_code)] #[allow(dead_code)]
fn foo_trampoline(_: foo::Context) {} fn foo_trampoline(_: foo::Context) {}

View file

@ -6,19 +6,17 @@
use panic_halt as _; use panic_halt as _;
#[rtic::app(device = lm3s6965)] #[rtic::app(device = lm3s6965)]
const APP: () = { mod app {
#[resources]
struct Resources { struct Resources {
// A resource // A resource
#[init(0)] #[init(0)]
shared: u32, shared: u32,
// A conditionally compiled resource behind feature_x // A conditionally compiled resource behind feature_x
#[cfg(feature = "feature_x")] #[cfg(feature = "feature_x")]
x: u32, x: u32,
dummy: (), // dummy such that we have at least one late resource
dummy: (),
} }
#[init] #[init]
fn init(_: init::Context) -> init::LateResources { fn init(_: init::Context) -> init::LateResources {
init::LateResources { init::LateResources {
@ -35,4 +33,4 @@ const APP: () = {
cortex_m::asm::nop(); cortex_m::asm::nop();
} }
} }
}; }

View file

@ -6,7 +6,8 @@
use panic_halt as _; use panic_halt as _;
#[rtic::app(device = lm3s6965, monotonic = rtic::cyccnt::CYCCNT)] #[rtic::app(device = lm3s6965, monotonic = rtic::cyccnt::CYCCNT)]
const APP: () = { mod app {
#[resources]
struct Resources { struct Resources {
#[cfg(never)] #[cfg(never)]
#[init(0)] #[init(0)]
@ -14,9 +15,11 @@ const 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]
@ -52,4 +55,4 @@ const APP: () = {
fn SSI0(); fn SSI0();
fn QEI0(); fn QEI0();
} }
}; }

View file

@ -7,14 +7,16 @@ use cortex_m_semihosting::debug;
use panic_semihosting as _; use panic_semihosting as _;
#[rtic::app(device = lm3s6965)] #[rtic::app(device = lm3s6965)]
const 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)]
fn main(_: main::Context) { fn taskmain(_: taskmain::Context) {
debug::exit(debug::EXIT_SUCCESS); debug::exit(debug::EXIT_SUCCESS);
} }
}; }

View file

@ -7,15 +7,17 @@ use cortex_m_semihosting::debug;
use panic_semihosting as _; use panic_semihosting as _;
#[rtic::app(device = lm3s6965)] #[rtic::app(device = lm3s6965)]
const APP: () = { mod app {
#[init] #[init]
fn init(_: init::Context) {} fn init(_: init::Context) -> init::LateResources {
init::LateResources {}
}
#[idle] #[idle]
fn main(_: main::Context) -> ! { fn taskmain(_: taskmain::Context) -> ! {
debug::exit(debug::EXIT_SUCCESS); debug::exit(debug::EXIT_SUCCESS);
loop { loop {
cortex_m::asm::nop(); cortex_m::asm::nop();
} }
} }
}; }

View file

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

View file

@ -12,7 +12,10 @@ pub struct NotSend {
} }
#[rtic::app(device = lm3s6965)] #[rtic::app(device = lm3s6965)]
const APP: () = { mod app {
use super::NotSend;
#[resources]
struct Resources { struct Resources {
x: NotSend, x: NotSend,
#[init(None)] #[init(None)]
@ -35,4 +38,4 @@ const APP: () = {
cortex_m::asm::nop(); cortex_m::asm::nop();
} }
} }
}; }

View file

@ -8,7 +8,8 @@
use panic_halt as _; use panic_halt as _;
#[rtic::app(device = lm3s6965)] #[rtic::app(device = lm3s6965)]
const APP: () = { mod app {
#[resources]
struct Resources { struct Resources {
#[init(0)] #[init(0)]
o1: u32, // init o1: u32, // init
@ -31,7 +32,7 @@ const 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;
@ -42,6 +43,8 @@ const 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])]
@ -86,4 +89,4 @@ const APP: () = {
// no `Mutex` proxy when co-owned by cooperative (same priority) tasks // no `Mutex` proxy when co-owned by cooperative (same priority) tasks
let _: &mut u32 = c.resources.s2; let _: &mut u32 = c.resources.s2;
} }
}; }

View file

@ -9,12 +9,14 @@ use panic_halt as _;
use rtic::cyccnt::{Instant, U32Ext as _}; use rtic::cyccnt::{Instant, U32Ext as _};
#[rtic::app(device = lm3s6965, monotonic = rtic::cyccnt::CYCCNT)] #[rtic::app(device = lm3s6965, monotonic = rtic::cyccnt::CYCCNT)]
const 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])]
@ -61,4 +63,4 @@ const APP: () = {
extern "C" { extern "C" {
fn SSI0(); fn SSI0();
} }
}; }

View file

@ -8,12 +8,14 @@
use panic_halt as _; use panic_halt as _;
#[rtic::app(device = lm3s6965)] #[rtic::app(device = lm3s6965)]
const 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])]
@ -60,4 +62,4 @@ const APP: () = {
extern "C" { extern "C" {
fn SSI0(); fn SSI0();
} }
}; }

View file

@ -7,14 +7,16 @@ use cortex_m_semihosting::debug;
use panic_semihosting as _; use panic_semihosting as _;
#[rtic::app(device = lm3s6965)] #[rtic::app(device = lm3s6965)]
const APP: () = { mod app {
#[init(spawn = [main])] #[init(spawn = [taskmain])]
fn init(cx: init::Context) { fn init(cx: init::Context) -> init::LateResources {
cx.spawn.main().ok(); cx.spawn.taskmain().ok();
init::LateResources {}
} }
#[task] #[task]
fn main(_: main::Context) { fn taskmain(_: taskmain::Context) {
debug::exit(debug::EXIT_SUCCESS); debug::exit(debug::EXIT_SUCCESS);
} }
@ -24,4 +26,4 @@ const APP: () = {
extern "C" { extern "C" {
fn SSI0(); fn SSI0();
} }
}; }

View file

@ -9,10 +9,12 @@ use cortex_m_semihosting::{debug, hprintln};
use panic_semihosting as _; use panic_semihosting as _;
#[rtic::app(device = lm3s6965)] #[rtic::app(device = lm3s6965)]
const 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])]
@ -52,4 +54,4 @@ const APP: () = {
fn SSI0(); fn SSI0();
fn QEI0(); fn QEI0();
} }
}; }

View file

@ -10,14 +10,15 @@ use panic_semihosting as _;
use rtic::cyccnt; use rtic::cyccnt;
#[rtic::app(device = lm3s6965, peripherals = true, monotonic = rtic::cyccnt::CYCCNT)] #[rtic::app(device = lm3s6965, peripherals = true, monotonic = rtic::cyccnt::CYCCNT)]
const APP: () = { mod app {
#[resources]
struct Resources { struct Resources {
#[init(0)] #[init(0)]
shared: u32, shared: u32,
} }
#[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;
@ -25,6 +26,8 @@ const 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])]
@ -60,4 +63,4 @@ const APP: () = {
extern "C" { extern "C" {
fn SSI0(); fn SSI0();
} }
}; }

View file

@ -25,21 +25,36 @@ mod util;
// TODO document the syntax here or in `rtic-syntax` // TODO document the syntax here or in `rtic-syntax`
pub fn app(app: &App, analysis: &Analysis, extra: &Extra) -> TokenStream2 { pub fn app(app: &App, analysis: &Analysis, extra: &Extra) -> TokenStream2 {
let mut const_app = vec![]; let mut mod_app = vec![];
let mut mod_app_imports = vec![];
let mut mains = vec![]; let mut mains = vec![];
let mut root = vec![]; let mut root = vec![];
let mut user = vec![]; let mut user = vec![];
let mut imports = vec![];
// Generate the `main` function // Generate the `main` function
let assertion_stmts = assertions::codegen(analysis); let assertion_stmts = assertions::codegen(analysis);
let pre_init_stmts = pre_init::codegen(&app, analysis, extra); let pre_init_stmts = pre_init::codegen(&app, analysis, extra);
let (const_app_init, root_init, user_init, call_init) = init::codegen(app, analysis, extra); let (mod_app_init, root_init, user_init, user_init_imports, call_init) =
init::codegen(app, analysis, extra);
let post_init_stmts = post_init::codegen(&app, analysis); let post_init_stmts = post_init::codegen(&app, analysis);
let (const_app_idle, root_idle, user_idle, call_idle) = idle::codegen(app, analysis, extra); let (mod_app_idle, root_idle, user_idle, user_idle_imports, call_idle) =
idle::codegen(app, analysis, extra);
if user_init.is_some() {
mod_app_imports.push(quote!(
use super::init;
))
}
if user_idle.is_some() {
mod_app_imports.push(quote!(
use super::idle;
))
}
user.push(quote!( user.push(quote!(
#user_init #user_init
@ -47,16 +62,21 @@ pub fn app(app: &App, analysis: &Analysis, extra: &Extra) -> TokenStream2 {
#user_idle #user_idle
)); ));
imports.push(quote!(
#(#user_init_imports)*
#(#user_idle_imports)*
));
root.push(quote!( root.push(quote!(
#(#root_init)* #(#root_init)*
#(#root_idle)* #(#root_idle)*
)); ));
const_app.push(quote!( mod_app.push(quote!(
#const_app_init #mod_app_init
#const_app_idle #mod_app_idle
)); ));
let main = util::suffixed("main"); let main = util::suffixed("main");
@ -77,22 +97,33 @@ pub fn app(app: &App, analysis: &Analysis, extra: &Extra) -> TokenStream2 {
} }
)); ));
let (const_app_resources, mod_resources) = resources::codegen(app, analysis, extra); let (mod_app_resources, mod_resources, mod_resources_imports) =
resources::codegen(app, analysis, extra);
let (const_app_hardware_tasks, root_hardware_tasks, user_hardware_tasks) = let (
hardware_tasks::codegen(app, analysis, extra); mod_app_hardware_tasks,
root_hardware_tasks,
user_hardware_tasks,
user_hardware_tasks_imports,
) = hardware_tasks::codegen(app, analysis, extra);
let (const_app_software_tasks, root_software_tasks, user_software_tasks) = let (
software_tasks::codegen(app, analysis, extra); mod_app_software_tasks,
root_software_tasks,
user_software_tasks,
user_software_tasks_imports,
) = software_tasks::codegen(app, analysis, extra);
let const_app_dispatchers = dispatchers::codegen(app, analysis, extra); let mod_app_dispatchers = dispatchers::codegen(app, analysis, extra);
let const_app_spawn = spawn::codegen(app, analysis, extra); let mod_app_spawn = spawn::codegen(app, analysis, extra);
let const_app_timer_queue = timer_queue::codegen(app, analysis, extra); let mod_app_timer_queue = timer_queue::codegen(app, analysis, extra);
let const_app_schedule = schedule::codegen(app, extra); let mod_app_schedule = schedule::codegen(app, extra);
let user_imports = app.user_imports.clone();
let user_code = app.user_code.clone();
let name = &app.name; let name = &app.name;
let device = extra.device; let device = extra.device;
quote!( quote!(
@ -111,28 +142,41 @@ pub fn app(app: &App, analysis: &Analysis, extra: &Extra) -> TokenStream2 {
#(#root_software_tasks)* #(#root_software_tasks)*
/// Implementation details /// Implementation details
// The user can't access the items within this `const` item mod #name {
const #name: () = {
/// Always include the device crate which contains the vector table /// Always include the device crate which contains the vector table
use #device as _; use #device as _;
#(#imports)*
#(#user_imports)*
#(#const_app)* /// User code from within the module
#(#user_code)*
/// User code end
#(#const_app_resources)*
#(#const_app_hardware_tasks)* #(#user_hardware_tasks_imports)*
#(#const_app_software_tasks)* #(#user_software_tasks_imports)*
#(#const_app_dispatchers)* #(#mod_resources_imports)*
#(#const_app_spawn)* /// app module
#(#mod_app)*
#(#const_app_timer_queue)* #(#mod_app_resources)*
#(#const_app_schedule)* #(#mod_app_hardware_tasks)*
#(#mod_app_software_tasks)*
#(#mod_app_dispatchers)*
#(#mod_app_spawn)*
#(#mod_app_timer_queue)*
#(#mod_app_schedule)*
#(#mains)* #(#mains)*
}; }
) )
} }

View file

@ -1,5 +1,5 @@
use proc_macro2::TokenStream as TokenStream2; use proc_macro2::TokenStream as TokenStream2;
use quote::quote; use quote::{format_ident, quote};
use rtic_syntax::{ast::App, Context}; use rtic_syntax::{ast::App, Context};
use crate::{ use crate::{
@ -14,7 +14,7 @@ pub fn codegen(
analysis: &Analysis, analysis: &Analysis,
extra: &Extra, extra: &Extra,
) -> ( ) -> (
// const_app_hardware_tasks -- interrupt handlers and `${task}Resources` constructors // mod_app_hardware_tasks -- interrupt handlers and `${task}Resources` constructors
Vec<TokenStream2>, Vec<TokenStream2>,
// root_hardware_tasks -- items that must be placed in the root of the crate: // root_hardware_tasks -- items that must be placed in the root of the crate:
// - `${task}Locals` structs // - `${task}Locals` structs
@ -23,10 +23,13 @@ pub fn codegen(
Vec<TokenStream2>, Vec<TokenStream2>,
// user_hardware_tasks -- the `#[task]` functions written by the user // user_hardware_tasks -- the `#[task]` functions written by the user
Vec<TokenStream2>, Vec<TokenStream2>,
// user_hardware_tasks_imports -- the imports for `#[task]` functions written by the user
Vec<TokenStream2>,
) { ) {
let mut const_app = vec![]; let mut mod_app = vec![];
let mut root = vec![]; let mut root = vec![];
let mut user_tasks = vec![]; let mut user_tasks = vec![];
let mut hardware_tasks_imports = vec![];
for (name, task) in &app.hardware_tasks { for (name, task) in &app.hardware_tasks {
let (let_instant, instant) = if app.uses_schedule() { let (let_instant, instant) = if app.uses_schedule() {
@ -49,7 +52,7 @@ pub fn codegen(
let symbol = task.args.binds.clone(); let symbol = task.args.binds.clone();
let priority = task.args.priority; let priority = task.args.priority;
const_app.push(quote!( mod_app.push(quote!(
#[allow(non_snake_case)] #[allow(non_snake_case)]
#[no_mangle] #[no_mangle]
unsafe fn #symbol() { unsafe fn #symbol() {
@ -78,9 +81,16 @@ pub fn codegen(
analysis, analysis,
); );
// Add resources to imports
let name_res = format_ident!("{}Resources", name);
hardware_tasks_imports.push(quote!(
#[allow(non_snake_case)]
use super::#name_res;
));
root.push(item); root.push(item);
const_app.push(constructor); mod_app.push(constructor);
} }
root.push(module::codegen( root.push(module::codegen(
@ -112,7 +122,13 @@ pub fn codegen(
#(#stmts)* #(#stmts)*
} }
)); ));
hardware_tasks_imports.push(quote!(
#(#attrs)*
#[allow(non_snake_case)]
use super::#name;
));
} }
(const_app, root, user_tasks) (mod_app, root, user_tasks, hardware_tasks_imports)
} }

View file

@ -1,5 +1,5 @@
use proc_macro2::TokenStream as TokenStream2; use proc_macro2::TokenStream as TokenStream2;
use quote::quote; use quote::{format_ident, quote};
use rtic_syntax::{ast::App, Context}; use rtic_syntax::{ast::App, Context};
use crate::{ use crate::{
@ -14,7 +14,7 @@ pub fn codegen(
analysis: &Analysis, analysis: &Analysis,
extra: &Extra, extra: &Extra,
) -> ( ) -> (
// const_app_idle -- the `${idle}Resources` constructor // mod_app_idle -- the `${idle}Resources` constructor
Option<TokenStream2>, Option<TokenStream2>,
// root_idle -- items that must be placed in the root of the crate: // root_idle -- items that must be placed in the root of the crate:
// - the `${idle}Locals` struct // - the `${idle}Locals` struct
@ -23,26 +23,37 @@ pub fn codegen(
Vec<TokenStream2>, Vec<TokenStream2>,
// user_idle // user_idle
Option<TokenStream2>, Option<TokenStream2>,
// user_idle_imports
Vec<TokenStream2>,
// call_idle // call_idle
TokenStream2, TokenStream2,
) { ) {
if app.idles.len() > 0 { if app.idles.len() > 0 {
let idle = &app.idles.first().unwrap(); let idle = &app.idles.first().unwrap();
let mut needs_lt = false; let mut needs_lt = false;
let mut const_app = None; let mut mod_app = None;
let mut root_idle = vec![]; let mut root_idle = vec![];
let mut locals_pat = None; let mut locals_pat = None;
let mut locals_new = None; let mut locals_new = None;
let mut user_idle_imports = vec![];
let name = &idle.name;
if !idle.args.resources.is_empty() { if !idle.args.resources.is_empty() {
let (item, constructor) = let (item, constructor) =
resources_struct::codegen(Context::Idle, 0, &mut needs_lt, app, analysis); resources_struct::codegen(Context::Idle, 0, &mut needs_lt, app, analysis);
root_idle.push(item); root_idle.push(item);
const_app = Some(constructor); mod_app = Some(constructor);
let name_resource = format_ident!("{}Resources", name);
user_idle_imports.push(quote!(
#[allow(non_snake_case)]
use super::#name_resource;
));
} }
let name = &idle.name;
if !idle.locals.is_empty() { if !idle.locals.is_empty() {
let (locals, pat) = locals::codegen(Context::Idle, &idle.locals, app); let (locals, pat) = locals::codegen(Context::Idle, &idle.locals, app);
@ -66,6 +77,11 @@ pub fn codegen(
#(#stmts)* #(#stmts)*
} }
)); ));
user_idle_imports.push(quote!(
#(#attrs)*
#[allow(non_snake_case)]
use super::#name;
));
let locals_new = locals_new.iter(); let locals_new = locals_new.iter();
let call_idle = quote!(crate::#name( let call_idle = quote!(crate::#name(
@ -73,12 +89,13 @@ pub fn codegen(
#name::Context::new(&rtic::export::Priority::new(0)) #name::Context::new(&rtic::export::Priority::new(0))
)); ));
(const_app, root_idle, user_idle, call_idle) (mod_app, root_idle, user_idle, user_idle_imports, call_idle)
} else { } else {
( (
None, None,
vec![], vec![],
None, None,
vec![],
quote!(loop { quote!(loop {
rtic::export::wfi() rtic::export::wfi()
}), }),

View file

@ -1,5 +1,5 @@
use proc_macro2::TokenStream as TokenStream2; use proc_macro2::TokenStream as TokenStream2;
use quote::quote; use quote::{format_ident, quote};
use rtic_syntax::{ast::App, Context}; use rtic_syntax::{ast::App, Context};
use crate::{ use crate::{
@ -14,7 +14,7 @@ pub fn codegen(
analysis: &Analysis, analysis: &Analysis,
extra: &Extra, extra: &Extra,
) -> ( ) -> (
// const_app_idle -- the `${init}Resources` constructor // mod_app_idle -- the `${init}Resources` constructor
Option<TokenStream2>, Option<TokenStream2>,
// root_init -- items that must be placed in the root of the crate: // root_init -- items that must be placed in the root of the crate:
// - the `${init}Locals` struct // - the `${init}Locals` struct
@ -24,6 +24,8 @@ pub fn codegen(
Vec<TokenStream2>, Vec<TokenStream2>,
// user_init -- the `#[init]` function written by the user // user_init -- the `#[init]` function written by the user
Option<TokenStream2>, Option<TokenStream2>,
// user_init_imports -- the imports for `#[init]` functio written by the user
Vec<TokenStream2>,
// call_init -- the call to the user `#[init]` if there's one // call_init -- the call to the user `#[init]` if there's one
Option<TokenStream2>, Option<TokenStream2>,
) { ) {
@ -34,7 +36,6 @@ pub fn codegen(
let mut root_init = vec![]; let mut root_init = vec![];
let ret = {
let late_fields = analysis let late_fields = analysis
.late_resources .late_resources
.iter() .iter()
@ -51,7 +52,7 @@ pub fn codegen(
}) })
.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!(
@ -62,11 +63,11 @@ pub fn codegen(
} }
)); ));
Some(quote!(-> #name::LateResources)) let name_late = format_ident!("{}LateResources", name);
} else { user_init_imports.push(quote!(
None #[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;
@ -85,18 +86,29 @@ 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)*
} }
)); ));
user_init_imports.push(quote!(
#(#attrs)*
#[allow(non_snake_case)]
use super::#name;
));
let mut const_app = None; let mut mod_app = None;
if !init.args.resources.is_empty() { if !init.args.resources.is_empty() {
let (item, constructor) = let (item, constructor) =
resources_struct::codegen(Context::Init, 0, &mut needs_lt, app, analysis); resources_struct::codegen(Context::Init, 0, &mut needs_lt, app, analysis);
root_init.push(item); root_init.push(item);
const_app = Some(constructor); mod_app = Some(constructor);
let name_late = format_ident!("{}Resources", name);
user_init_imports.push(quote!(
#[allow(non_snake_case)]
use super::#name_late;
));
} }
let locals_new = locals_new.iter(); let locals_new = locals_new.iter();
@ -106,8 +118,8 @@ pub fn codegen(
root_init.push(module::codegen(Context::Init, needs_lt, app, extra)); root_init.push(module::codegen(Context::Init, needs_lt, app, extra));
(const_app, root_init, user_init, call_init) (mod_app, root_init, user_init, user_init_imports, call_init)
} else { } else {
(None, vec![], None, None) (None, vec![], None, vec![], None)
} }
} }

View file

@ -47,6 +47,14 @@ pub fn codegen(ctxt: Context, resources_tick: bool, app: &App, extra: &Extra) ->
values.push(quote!(device: #device::Peripherals::steal())); values.push(quote!(device: #device::Peripherals::steal()));
} }
lt = Some(quote!('a));
fields.push(quote!(
/// Critical section token for init
pub cs: rtic::export::CriticalSection<#lt>
));
values.push(quote!(cs: rtic::export::CriticalSection::new()));
values.push(quote!(core)); values.push(quote!(core));
} }
@ -253,7 +261,6 @@ pub fn codegen(ctxt: Context, resources_tick: bool, app: &App, extra: &Extra) ->
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!(
@ -261,7 +268,6 @@ pub fn codegen(ctxt: Context, resources_tick: bool, app: &App, extra: &Extra) ->
pub use super::#late_resources as LateResources; pub use super::#late_resources as LateResources;
)); ));
} }
}
let doc = match ctxt { let doc = match ctxt {
Context::Idle => "Idle loop", Context::Idle => "Idle loop",

View file

@ -10,13 +10,16 @@ pub fn codegen(
analysis: &Analysis, analysis: &Analysis,
extra: &Extra, extra: &Extra,
) -> ( ) -> (
// const_app -- the `static [mut]` variables behind the proxies // mod_app -- the `static [mut]` variables behind the proxies
Vec<TokenStream2>, Vec<TokenStream2>,
// mod_resources -- the `resources` module // mod_resources -- the `resources` module
TokenStream2, TokenStream2,
// mod_resources_imports -- the `resources` module imports
Vec<TokenStream2>,
) { ) {
let mut const_app = vec![]; let mut mod_app = vec![];
let mut mod_resources = vec![]; let mut mod_resources = vec![];
let mut mod_resources_imports = vec![];
for (name, res, expr, _) in app.resources(analysis) { for (name, res, expr, _) in app.resources(analysis) {
let cfgs = &res.cfgs; let cfgs = &res.cfgs;
@ -39,7 +42,7 @@ pub fn codegen(
}; };
let attrs = &res.attrs; let attrs = &res.attrs;
const_app.push(quote!( mod_app.push(quote!(
#[allow(non_upper_case_globals)] #[allow(non_upper_case_globals)]
#(#attrs)* #(#attrs)*
#(#cfgs)* #(#cfgs)*
@ -82,7 +85,13 @@ pub fn codegen(
) )
}; };
const_app.push(util::impl_mutex( mod_resources_imports.push(quote!(
#[allow(non_camel_case_types)]
#(#cfgs)*
use super::resources::#name;
));
mod_app.push(util::impl_mutex(
extra, extra,
cfgs, cfgs,
true, true,
@ -97,6 +106,11 @@ pub fn codegen(
let mod_resources = if mod_resources.is_empty() { let mod_resources = if mod_resources.is_empty() {
quote!() quote!()
} else { } else {
// Also import the resource module
mod_resources_imports.push(quote!(
use super::resources;
));
quote!(mod resources { quote!(mod resources {
use rtic::export::Priority; use rtic::export::Priority;
@ -104,5 +118,5 @@ pub fn codegen(
}) })
}; };
(const_app, mod_resources) (mod_app, mod_resources, mod_resources_imports)
} }

View file

@ -165,7 +165,7 @@ pub fn codegen(
let constructor = quote!( let constructor = quote!(
impl<#lt> #ident<#lt> { impl<#lt> #ident<#lt> {
#[inline(always)] #[inline(always)]
unsafe fn new(#arg) -> Self { pub unsafe fn new(#arg) -> Self {
#ident { #ident {
#(#values,)* #(#values,)*
} }

View file

@ -34,7 +34,7 @@ pub fn codegen(app: &App, extra: &Extra) -> Vec<TokenStream2> {
methods.push(quote!( methods.push(quote!(
#(#cfgs)* #(#cfgs)*
fn #name(&self, instant: #instant #(,#args)*) -> Result<(), #ty> { pub fn #name(&self, instant: #instant #(,#args)*) -> Result<(), #ty> {
#body #body
} }
)); ));
@ -49,7 +49,7 @@ pub fn codegen(app: &App, extra: &Extra) -> Vec<TokenStream2> {
items.push(quote!( items.push(quote!(
#(#cfgs)* #(#cfgs)*
unsafe fn #schedule( pub unsafe fn #schedule(
priority: &rtic::export::Priority, priority: &rtic::export::Priority,
instant: #instant instant: #instant
#(,#args)* #(,#args)*
@ -62,7 +62,7 @@ pub fn codegen(app: &App, extra: &Extra) -> Vec<TokenStream2> {
methods.push(quote!( methods.push(quote!(
#(#cfgs)* #(#cfgs)*
#[inline(always)] #[inline(always)]
fn #name(&self, instant: #instant #(,#args)*) -> Result<(), #ty> { pub fn #name(&self, instant: #instant #(,#args)*) -> Result<(), #ty> {
unsafe { unsafe {
#schedule(self.priority(), instant #(,#untupled)*) #schedule(self.priority(), instant #(,#untupled)*)
} }

View file

@ -1,5 +1,5 @@
use proc_macro2::TokenStream as TokenStream2; use proc_macro2::TokenStream as TokenStream2;
use quote::quote; use quote::{format_ident, quote};
use rtic_syntax::{ast::App, Context}; use rtic_syntax::{ast::App, Context};
use crate::{ use crate::{
@ -13,7 +13,7 @@ pub fn codegen(
analysis: &Analysis, analysis: &Analysis,
extra: &Extra, extra: &Extra,
) -> ( ) -> (
// const_app_software_tasks -- free queues, buffers and `${task}Resources` constructors // mod_app_software_tasks -- free queues, buffers and `${task}Resources` constructors
Vec<TokenStream2>, Vec<TokenStream2>,
// root_software_tasks -- items that must be placed in the root of the crate: // root_software_tasks -- items that must be placed in the root of the crate:
// - `${task}Locals` structs // - `${task}Locals` structs
@ -22,10 +22,13 @@ pub fn codegen(
Vec<TokenStream2>, Vec<TokenStream2>,
// user_software_tasks -- the `#[task]` functions written by the user // user_software_tasks -- the `#[task]` functions written by the user
Vec<TokenStream2>, Vec<TokenStream2>,
// user_software_tasks_imports -- the imports for `#[task]` functions written by the user
Vec<TokenStream2>,
) { ) {
let mut const_app = vec![]; let mut mod_app = vec![];
let mut root = vec![]; let mut root = vec![];
let mut user_tasks = vec![]; let mut user_tasks = vec![];
let mut software_tasks_imports = vec![];
for (name, task) in &app.software_tasks { for (name, task) in &app.software_tasks {
let inputs = &task.inputs; let inputs = &task.inputs;
@ -48,7 +51,7 @@ pub fn codegen(
Box::new(|| util::link_section_uninit(true)), Box::new(|| util::link_section_uninit(true)),
) )
}; };
const_app.push(quote!( mod_app.push(quote!(
/// Queue version of a free-list that keeps track of empty slots in /// Queue version of a free-list that keeps track of empty slots in
/// the following buffers /// the following buffers
static mut #fq: #fq_ty = #fq_expr; static mut #fq: #fq_ty = #fq_expr;
@ -56,13 +59,13 @@ pub fn codegen(
// Generate a resource proxy if needed // Generate a resource proxy if needed
if let Some(ceiling) = ceiling { if let Some(ceiling) = ceiling {
const_app.push(quote!( mod_app.push(quote!(
struct #fq<'a> { struct #fq<'a> {
priority: &'a rtic::export::Priority, priority: &'a rtic::export::Priority,
} }
)); ));
const_app.push(util::impl_mutex( mod_app.push(util::impl_mutex(
extra, extra,
&[], &[],
false, false,
@ -82,7 +85,7 @@ pub fn codegen(
let instants = util::instants_ident(name); let instants = util::instants_ident(name);
let uninit = mk_uninit(); let uninit = mk_uninit();
const_app.push(quote!( mod_app.push(quote!(
#uninit #uninit
/// Buffer that holds the instants associated to the inputs of a task /// Buffer that holds the instants associated to the inputs of a task
static mut #instants: static mut #instants:
@ -93,7 +96,7 @@ pub fn codegen(
let uninit = mk_uninit(); let uninit = mk_uninit();
let inputs = util::inputs_ident(name); let inputs = util::inputs_ident(name);
const_app.push(quote!( mod_app.push(quote!(
#uninit #uninit
/// Buffer that holds the inputs of a task /// Buffer that holds the inputs of a task
static mut #inputs: [core::mem::MaybeUninit<#input_ty>; #cap_lit] = static mut #inputs: [core::mem::MaybeUninit<#input_ty>; #cap_lit] =
@ -112,9 +115,16 @@ pub fn codegen(
analysis, analysis,
); );
// Add resources to imports
let name_res = format_ident!("{}Resources", name);
software_tasks_imports.push(quote!(
#[allow(non_snake_case)]
use super::#name_res;
));
root.push(item); root.push(item);
const_app.push(constructor); mod_app.push(constructor);
} }
// `${task}Locals` // `${task}Locals`
@ -135,12 +145,17 @@ pub fn codegen(
#(#attrs)* #(#attrs)*
#(#cfgs)* #(#cfgs)*
#[allow(non_snake_case)] #[allow(non_snake_case)]
fn #name(#(#locals_pat,)* #context: #name::Context #(,#inputs)*) { pub fn #name(#(#locals_pat,)* #context: #name::Context #(,#inputs)*) {
use rtic::Mutex as _; use rtic::Mutex as _;
#(#stmts)* #(#stmts)*
} }
)); ));
software_tasks_imports.push(quote!(
#(#cfgs)*
#[allow(non_snake_case)]
use super::#name;
));
root.push(module::codegen( root.push(module::codegen(
Context::SoftwareTask(name), Context::SoftwareTask(name),
@ -150,5 +165,5 @@ pub fn codegen(
)); ));
} }
(const_app, root, user_tasks) (mod_app, root, user_tasks, software_tasks_imports)
} }

View file

@ -40,7 +40,7 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream
methods.push(quote!( methods.push(quote!(
#(#cfgs)* #(#cfgs)*
fn #name(&self #(,#args)*) -> Result<(), #ty> { pub fn #name(&self #(,#args)*) -> Result<(), #ty> {
#let_instant #let_instant
#body #body
} }
@ -92,7 +92,7 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream
methods.push(quote!( methods.push(quote!(
#(#cfgs)* #(#cfgs)*
#[inline(always)] #[inline(always)]
fn #name(&self #(,#args)*) -> Result<(), #ty> { pub fn #name(&self #(,#args)*) -> Result<(), #ty> {
unsafe { unsafe {
#let_instant #let_instant
#spawn(self.priority() #instant #(,#untupled)*) #spawn(self.priority() #instant #(,#untupled)*)

View file

@ -15,8 +15,7 @@ mod tests;
/// Attribute used to declare a RTIC application /// Attribute used to declare a RTIC application
/// ///
/// This attribute must be applied to a `const` item of type `()`. The `const` item is effectively /// This attribute must be applied to a module block that contains items commonly found in modules,
/// used as a `mod` item: its value must be a block that contains items commonly found in modules,
/// like functions and `static` variables. /// like functions and `static` variables.
/// ///
/// The `app` attribute has one mandatory argument: /// The `app` attribute has one mandatory argument:
@ -34,9 +33,9 @@ mod tests;
/// - `monotonic = <path>`. This is a path to a zero-sized structure (e.g. `struct Foo;`) that /// - `monotonic = <path>`. This is a path to a zero-sized structure (e.g. `struct Foo;`) that
/// implements the `Monotonic` trait. This argument must be provided to use the `schedule` API. /// implements the `Monotonic` trait. This argument must be provided to use the `schedule` API.
/// ///
/// The items allowed in the block value of the `const` item are specified below: /// The items allowed in the module block are specified below:
/// ///
/// # 1. `struct Resources` /// # 1. `#[resources] 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

@ -8,7 +8,7 @@ fn analyze() {
let (app, analysis) = rtic_syntax::parse2( let (app, analysis) = rtic_syntax::parse2(
quote!(device = pac), quote!(device = pac),
quote!( quote!(
const APP: () = { mod app {
#[task(priority = 1)] #[task(priority = 1)]
fn a(_: a::Context) {} fn a(_: a::Context) {}
@ -20,7 +20,7 @@ fn analyze() {
fn B(); fn B();
fn A(); fn A();
} }
}; }
), ),
settings, settings,
) )

View file

@ -4,6 +4,7 @@ use core::{
}; };
pub use crate::tq::{NotReady, TimerQueue}; pub use crate::tq::{NotReady, TimerQueue};
pub use bare_metal::CriticalSection;
#[cfg(armv7m)] #[cfg(armv7m)]
pub use cortex_m::register::basepri; pub use cortex_m::register::basepri;
pub use cortex_m::{ pub use cortex_m::{
@ -15,8 +16,6 @@ pub use cortex_m::{
use heapless::spsc::SingleCore; use heapless::spsc::SingleCore;
pub use heapless::{consts, i::Queue as iQueue, spsc::Queue}; pub use heapless::{consts, i::Queue as iQueue, spsc::Queue};
pub use heapless::{i::BinaryHeap as iBinaryHeap, BinaryHeap}; pub use heapless::{i::BinaryHeap as iBinaryHeap, BinaryHeap};
#[cfg(feature = "heterogeneous")]
pub use microamp::shared;
pub type SCFQ<N> = Queue<u8, N, u8, SingleCore>; pub type SCFQ<N> = Queue<u8, N, u8, SingleCore>;
pub type SCRQ<T, N> = Queue<(T, u8), N, u8, SingleCore>; pub type SCRQ<T, N> = Queue<(T, u8), N, u8, SingleCore>;

View file

@ -1,7 +1,7 @@
#![no_main] #![no_main]
#[rtic::app(device = lm3s6965)] #[rtic::app(device = lm3s6965)]
const APP: () = { mod app {
#[task(binds = NonMaskableInt)] #[task(binds = NonMaskableInt)]
fn nmi(_: nmi::Context) {} fn nmi(_: nmi::Context) {}
}; }

View file

@ -1,10 +1,10 @@
#![no_main] #![no_main]
#[rtic::app(device = lm3s6965)] #[rtic::app(device = lm3s6965)]
const APP: () = { mod app {
#[task(binds = SysTick)] #[task(binds = SysTick)]
fn sys_tick(_: sys_tick::Context) {} fn sys_tick(_: sys_tick::Context) {}
#[task(schedule = [foo])] #[task(schedule = [foo])]
fn foo(_: foo::Context) {} fn foo(_: foo::Context) {}
}; }

View file

@ -1,7 +1,7 @@
#![no_main] #![no_main]
#[rtic::app(device = lm3s6965)] #[rtic::app(device = lm3s6965)]
const APP: () = { mod app {
#[task] #[task]
fn a(_: a::Context) {} fn a(_: a::Context) {}
}; }

View file

@ -1,11 +1,11 @@
#![no_main] #![no_main]
#[rtic::app(device = lm3s6965)] #[rtic::app(device = lm3s6965)]
const APP: () = { mod app {
#[task(binds = UART0)] #[task(binds = UART0)]
fn a(_: a::Context) {} fn a(_: a::Context) {}
extern "C" { extern "C" {
fn UART0(); fn UART0();
} }
}; }

View file

@ -1,13 +1,16 @@
#![no_main] #![no_main]
use panic_halt as _;
#[rtic::app(device = lm3s6965)] #[rtic::app(device = lm3s6965)]
const 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]
@ -47,4 +50,4 @@ const APP: () = {
extern "C" { extern "C" {
fn UART1(); fn UART1();
} }
}; }

View file

@ -1,37 +1,41 @@
error[E0425]: cannot find value `FOO` in this scope error[E0425]: cannot find value `FOO` in this scope
--> $DIR/locals-cfg.rs:10:9 --> $DIR/locals-cfg.rs:11:9
| |
10 | FOO; 11 | 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:18:9 --> $DIR/locals-cfg.rs:21:9
| |
18 | 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:28:9 --> $DIR/locals-cfg.rs:31:9
| |
28 | 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:36:9 --> $DIR/locals-cfg.rs:39:9
| |
36 | 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:44:9 --> $DIR/locals-cfg.rs:47:9
| |
44 | FOO; 47 | FOO;
| ^^^ not found in this scope | ^^^ not found in this scope
error: duplicate lang item in crate `panic_halt`: `panic_impl`. error: duplicate lang item in crate `panic_halt` (which `$CRATE` depends on): `panic_impl`.
| |
= note: first defined in crate `std`. = note: the lang item is first defined in crate `std` (which `$CRATE` depends on)
= note: first definition in `std` loaded from /usr/share/rust/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libstd-cf0f33af3a901778.rlib
= note: second definition in `panic_halt` loaded from $DIR/target/tests/target/x86_64-unknown-linux-gnu/debug/deps/libpanic_halt-ba6f0ab3439cbc7e.rmeta
error: duplicate lang item in crate `panic_semihosting`: `panic_impl`. error: duplicate lang item in crate `panic_semihosting`: `panic_impl`.
| |
= note: first defined in crate `panic_halt`. = note: the lang item is first defined in crate `panic_halt` (which `$CRATE` depends on)
= note: first definition in `panic_halt` loaded from $DIR/target/tests/target/x86_64-unknown-linux-gnu/debug/deps/libpanic_halt-ba6f0ab3439cbc7e.rmeta
= note: second definition in `panic_semihosting` loaded from $DIR/target/tests/target/x86_64-unknown-linux-gnu/debug/deps/libpanic_semihosting-805015f4a2d05965.rmeta

View file

@ -1,7 +1,9 @@
#![no_main] #![no_main]
use panic_halt as _;
#[rtic::app(device = lm3s6965)] #[rtic::app(device = lm3s6965)]
const APP: () = { mod app {
#[resources]
struct Resources { struct Resources {
#[cfg(never)] #[cfg(never)]
#[init(0)] #[init(0)]
@ -41,12 +43,14 @@ const 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])]
@ -72,4 +76,4 @@ const APP: () = {
c.resources.s2; c.resources.s2;
c.resources.o5; c.resources.o5;
} }
}; }

View file

@ -1,119 +1,125 @@
error[E0609]: no field `o1` on type `initResources<'_>` error: duplicate lang item in crate `panic_halt` (which `$CRATE` depends on): `panic_impl`.
--> $DIR/resources-cfg.rs:45:21
| |
45 | c.resources.o1; = note: the lang item is first defined in crate `std` (which `$CRATE` depends on)
= note: first definition in `std` loaded from /usr/share/rust/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libstd-cf0f33af3a901778.rlib
= note: second definition in `panic_halt` loaded from $DIR/target/tests/target/x86_64-unknown-linux-gnu/debug/deps/libpanic_halt-ba6f0ab3439cbc7e.rmeta
error[E0609]: no field `o1` on type `initResources<'_>`
--> $DIR/resources-cfg.rs:47:21
|
47 | c.resources.o1;
| ^^ unknown field | ^^ unknown field
| |
= note: available fields are: `__marker__` = note: available fields are: `__marker__`
error[E0609]: no field `o4` on type `initResources<'_>` error[E0609]: no field `o4` on type `initResources<'_>`
--> $DIR/resources-cfg.rs:46:21 --> $DIR/resources-cfg.rs:48:21
| |
46 | c.resources.o4; 48 | c.resources.o4;
| ^^ unknown field | ^^ unknown field
| |
= note: available fields are: `__marker__` = note: available fields are: `__marker__`
error[E0609]: no field `o5` on type `initResources<'_>` error[E0609]: no field `o5` on type `initResources<'_>`
--> $DIR/resources-cfg.rs:47:21 --> $DIR/resources-cfg.rs:49:21
| |
47 | c.resources.o5; 49 | c.resources.o5;
| ^^ unknown field | ^^ unknown field
| |
= note: available fields are: `__marker__` = note: available fields are: `__marker__`
error[E0609]: no field `o6` on type `initResources<'_>` error[E0609]: no field `o6` on type `initResources<'_>`
--> $DIR/resources-cfg.rs:48:21 --> $DIR/resources-cfg.rs:50:21
| |
48 | c.resources.o6; 50 | c.resources.o6;
| ^^ unknown field | ^^ unknown field
| |
= note: available fields are: `__marker__` = note: available fields are: `__marker__`
error[E0609]: no field `s3` on type `initResources<'_>` error[E0609]: no field `s3` on type `initResources<'_>`
--> $DIR/resources-cfg.rs:49:21 --> $DIR/resources-cfg.rs:51:21
| |
49 | c.resources.s3; 51 | c.resources.s3;
| ^^ unknown field | ^^ unknown field
| |
= 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:54:21 --> $DIR/resources-cfg.rs:58:21
| |
54 | 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:55:21 --> $DIR/resources-cfg.rs:59:21
| |
55 | 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:56:21 --> $DIR/resources-cfg.rs:60:21
| |
56 | 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:57:21 --> $DIR/resources-cfg.rs:61:21
| |
57 | 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:64:21 --> $DIR/resources-cfg.rs:68:21
| |
64 | 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:65:21 --> $DIR/resources-cfg.rs:69:21
| |
65 | 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:66:21 --> $DIR/resources-cfg.rs:70:21
| |
66 | 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:67:21 --> $DIR/resources-cfg.rs:71:21
| |
67 | 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:72:21 --> $DIR/resources-cfg.rs:76:21
| |
72 | 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:73:21 --> $DIR/resources-cfg.rs:77:21
| |
73 | c.resources.o5; 77 | c.resources.o5;
| ^^ unknown field | ^^ unknown field
| |
= note: available fields are: `__marker__` = note: available fields are: `__marker__`

View file

@ -1,11 +1,11 @@
#![no_main] #![no_main]
use rtic::app;
#[rtic::app(device = lm3s6965)] #[rtic::app(device = lm3s6965)]
const 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) {}
@ -35,4 +35,4 @@ const APP: () = {
// this value is too high! // this value is too high!
#[task(binds = I2C0, priority = 9)] #[task(binds = I2C0, priority = 9)]
fn i2c0(_: i2c0::Context) {} fn i2c0(_: i2c0::Context) {}
}; }

View file

@ -1,13 +1,7 @@
warning: unused import: `rtic::app`
--> $DIR/task-priority-too-high.rs:3:5
|
3 | use rtic::app;
| ^^^^^^^^^
|
= note: #[warn(unused_imports)] on by default
error[E0080]: evaluation of constant value failed error[E0080]: evaluation of constant value failed
--> $DIR/task-priority-too-high.rs:5:1 --> $DIR/task-priority-too-high.rs:3:1
| |
5 | #[rtic::app(device = lm3s6965)] 3 | #[rtic::app(device = lm3s6965)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to subtract with overflow | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to compute `8_usize - 9_usize` which would overflow
|
= note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info)