mirror of
https://github.com/rtic-rs/rtic.git
synced 2024-12-26 03:49:34 +01:00
commit
f386cb63cb
87 changed files with 1149 additions and 660 deletions
163
.github/workflows/build.yml
vendored
163
.github/workflows/build.yml
vendored
|
@ -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
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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) {
|
||||||
// ..
|
// ..
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
```
|
```
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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.
|
||||||
|
|
||||||
|
|
|
@ -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**
|
|
|
@ -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**
|
|
|
@ -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: () = {
|
||||||
// ..
|
// ..
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
```
|
```
|
||||||
|
|
|
@ -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: () = {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ..
|
// ..
|
||||||
};
|
}
|
||||||
```
|
```
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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: () = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
```
|
```
|
||||||
|
|
|
@ -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) {
|
|
||||||
// ..
|
|
||||||
}
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
232
book/en/src/migration/migration_v4.md
Normal file
232
book/en/src/migration/migration_v4.md
Normal 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) {
|
||||||
|
// ..
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
96
book/en/src/migration/migration_v5.md
Normal file
96
book/en/src/migration/migration_v5.md
Normal 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.
|
|
@ -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}}
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
|
@ -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>) {
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
|
@ -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 {}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
|
@ -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 {}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
63
examples/resource-user-struct.rs
Normal file
63
examples/resource-user-struct.rs
Normal 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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
|
@ -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 {}
|
||||||
|
|
|
@ -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) {}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
|
@ -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 {}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
|
@ -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)*
|
||||||
};
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -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,39 +36,38 @@ 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()
|
.flat_map(|resources| {
|
||||||
.flat_map(|resources| {
|
resources.iter().map(|name| {
|
||||||
resources.iter().map(|name| {
|
let ty = &app.late_resources[name].ty;
|
||||||
let ty = &app.late_resources[name].ty;
|
let cfgs = &app.late_resources[name].cfgs;
|
||||||
let cfgs = &app.late_resources[name].cfgs;
|
|
||||||
|
|
||||||
quote!(
|
quote!(
|
||||||
#(#cfgs)*
|
#(#cfgs)*
|
||||||
pub #name: #ty
|
pub #name: #ty
|
||||||
)
|
)
|
||||||
})
|
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
if !late_fields.is_empty() {
|
let mut user_init_imports = vec![];
|
||||||
let late_resources = util::late_resources_ident(&name);
|
let late_resources = util::late_resources_ident(&name);
|
||||||
|
|
||||||
root_init.push(quote!(
|
root_init.push(quote!(
|
||||||
/// Resources initialized at runtime
|
/// Resources initialized at runtime
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
pub struct #late_resources {
|
pub struct #late_resources {
|
||||||
#(#late_fields),*
|
#(#late_fields),*
|
||||||
}
|
|
||||||
));
|
|
||||||
|
|
||||||
Some(quote!(-> #name::LateResources))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
};
|
));
|
||||||
|
|
||||||
|
let name_late = format_ident!("{}LateResources", name);
|
||||||
|
user_init_imports.push(quote!(
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
use super::#name_late;
|
||||||
|
));
|
||||||
|
|
||||||
let mut locals_pat = None;
|
let mut locals_pat = None;
|
||||||
let mut locals_new = None;
|
let mut locals_new = None;
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,14 +261,12 @@ 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!(
|
||||||
#[doc(inline)]
|
#[doc(inline)]
|
||||||
pub use super::#late_resources as LateResources;
|
pub use super::#late_resources as LateResources;
|
||||||
));
|
));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let doc = match ctxt {
|
let doc = match ctxt {
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,)*
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)*)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)*)
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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,
|
||||||
)
|
)
|
||||||
|
|
|
@ -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>;
|
||||||
|
|
|
@ -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) {}
|
||||||
};
|
}
|
||||||
|
|
|
@ -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) {}
|
||||||
};
|
}
|
||||||
|
|
|
@ -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) {}
|
||||||
};
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
|
@ -1,119 +1,125 @@
|
||||||
|
error: duplicate lang item in crate `panic_halt` (which `$CRATE` depends on): `panic_impl`.
|
||||||
|
|
|
||||||
|
= 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<'_>`
|
error[E0609]: no field `o1` on type `initResources<'_>`
|
||||||
--> $DIR/resources-cfg.rs:45:21
|
--> $DIR/resources-cfg.rs:47:21
|
||||||
|
|
|
|
||||||
45 | c.resources.o1;
|
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__`
|
||||||
|
|
|
@ -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) {}
|
||||||
};
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Reference in a new issue