mirror of
https://github.com/rtic-rs/rtic.git
synced 2024-11-25 21:19:35 +01:00
Merge branch 'master' into always_late_resources
This commit is contained in:
commit
eec0908024
84 changed files with 757 additions and 382 deletions
104
.github/workflows/build.yml
vendored
104
.github/workflows/build.yml
vendored
|
@ -45,7 +45,6 @@ jobs:
|
|||
- x86_64-unknown-linux-gnu
|
||||
toolchain:
|
||||
- stable
|
||||
- 1.36.0
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
|
@ -79,10 +78,6 @@ jobs:
|
|||
target: ${{ matrix.target }}
|
||||
override: true
|
||||
|
||||
- name: Disable optimisation profiles
|
||||
if: matrix.toolchain == '1.36.0'
|
||||
run: sed -i '/^\[profile.*build-override]$/,/^$/{/^#/!{/^$/!d}}' Cargo.toml
|
||||
|
||||
- name: cargo check
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
|
@ -90,7 +85,7 @@ jobs:
|
|||
command: check
|
||||
args: --target=${{ matrix.target }}
|
||||
|
||||
# Verify all examples
|
||||
# Verify all examples, checks
|
||||
checkexamples:
|
||||
name: checkexamples
|
||||
runs-on: ubuntu-20.04
|
||||
|
@ -145,6 +140,51 @@ jobs:
|
|||
command: check
|
||||
args: --examples --target=${{ matrix.target }} --features __min_r1_43,${{ env.V7 }}
|
||||
|
||||
# Verify the example output with run-pass tests
|
||||
testexamples:
|
||||
name: testexamples
|
||||
runs-on: ubuntu-20.04
|
||||
strategy:
|
||||
matrix:
|
||||
target:
|
||||
- thumbv7m-none-eabi
|
||||
- thumbv6m-none-eabi
|
||||
toolchain:
|
||||
- stable
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Cache cargo dependencies
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
- ~/.cargo/bin/
|
||||
- ~/.cargo/registry/index/
|
||||
- ~/.cargo/registry/cache/
|
||||
- ~/.cargo/git/db/
|
||||
key: ${{ runner.OS }}-cargo-${{ hashFiles('**/Cargo.lock') }}
|
||||
restore-keys: |
|
||||
${{ runner.OS }}-cargo-${{ hashFiles('**/Cargo.lock') }}
|
||||
${{ runner.OS }}-cargo-
|
||||
|
||||
- name: Cache build output dependencies
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: target
|
||||
key: ${{ runner.OS }}-build-${{ hashFiles('**/Cargo.lock') }}
|
||||
restore-keys: |
|
||||
${{ runner.OS }}-build-${{ hashFiles('**/Cargo.lock') }}
|
||||
${{ runner.OS }}-build-
|
||||
|
||||
- name: Install Rust ${{ matrix.toolchain }} with target (${{ matrix.target }})
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: ${{ matrix.toolchain }}
|
||||
target: ${{ matrix.target }}
|
||||
override: true
|
||||
components: llvm-tools-preview
|
||||
|
||||
# Use precompiled binutils
|
||||
- name: cargo install cargo-binutils
|
||||
uses: actions-rs/install@v0.1
|
||||
|
@ -306,7 +346,6 @@ jobs:
|
|||
- x86_64-unknown-linux-gnu
|
||||
toolchain:
|
||||
- stable
|
||||
- 1.36.0
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
|
@ -340,10 +379,6 @@ jobs:
|
|||
target: ${{ matrix.target }}
|
||||
override: true
|
||||
|
||||
- name: Disable optimisation profiles
|
||||
if: matrix.toolchain == '1.36.0'
|
||||
run: sed -i '/^\[profile.*build-override]$/,/^$/{/^#/!{/^$/!d}}' Cargo.toml
|
||||
|
||||
- name: cargo check
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
|
@ -382,13 +417,10 @@ jobs:
|
|||
- name: Install Rust
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: 1.36.0
|
||||
toolchain: stable
|
||||
target: thumbv7m-none-eabi
|
||||
override: true
|
||||
|
||||
- name: Disable optimisation profiles
|
||||
run: sed -i '/^\[profile.*build-override]$/,/^$/{/^#/!{/^$/!d}}' Cargo.toml
|
||||
|
||||
- uses: actions-rs/cargo@v1
|
||||
with:
|
||||
use-cross: false
|
||||
|
@ -426,13 +458,10 @@ jobs:
|
|||
- name: Install Rust
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: 1.36.0
|
||||
toolchain: stable
|
||||
target: thumbv6m-none-eabi
|
||||
override: true
|
||||
|
||||
- name: Disable optimisation profiles
|
||||
run: sed -i '/^\[profile.*build-override]$/,/^$/{/^#/!{/^$/!d}}' Cargo.toml
|
||||
|
||||
- uses: actions-rs/cargo@v1
|
||||
with:
|
||||
use-cross: false
|
||||
|
@ -594,27 +623,37 @@ jobs:
|
|||
- name: Build books
|
||||
run: |
|
||||
langs=( en ru )
|
||||
latest=0.5
|
||||
vers=( 0.4.x )
|
||||
devver=( dev )
|
||||
# The latest stable must be the first element in the array
|
||||
vers=( 0.5.x 0.4.x )
|
||||
|
||||
# All releases start with "v"
|
||||
# followed by MAJOR.MINOR.PATCH, see semver.org
|
||||
# Retain MAJOR.MINOR as $stable
|
||||
stable=${vers%.*}
|
||||
|
||||
echo "Stable version: $stable"
|
||||
|
||||
# Create directories
|
||||
td=$(mktemp -d)
|
||||
mkdir -p $td/$latest/book/
|
||||
cp -r target/doc $td/$latest/api
|
||||
mkdir -p $td/$devver/book/
|
||||
cp -r target/doc $td/$devver/api
|
||||
|
||||
# sed fixes
|
||||
sed 's|URL|rtic/index.html|g' redirect.html > $td/$latest/api/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
|
||||
# Redirect the main site to the stable release
|
||||
sed "s|URL|$stable|g" redirect.html > $td/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
|
||||
for lang in ${langs[@]}; do
|
||||
( cd book/$lang && mdbook build )
|
||||
cp -r book/$lang/book $td/$latest/book/$lang
|
||||
cp LICENSE-* $td/$latest/book/$lang/
|
||||
cp -r book/$lang/book $td/$devver/book/$lang
|
||||
cp LICENSE-* $td/$devver/book/$lang/
|
||||
done
|
||||
|
||||
# Build older versions
|
||||
# Build older versions, including stable
|
||||
root=$(pwd)
|
||||
for ver in ${vers[@]}; do
|
||||
prefix=${ver%.*}
|
||||
|
@ -639,6 +678,9 @@ jobs:
|
|||
rm -rf $src
|
||||
done
|
||||
|
||||
# Copy the stable book to the stable alias
|
||||
cp -r $td/$stable $td/stable
|
||||
|
||||
# Forward CNAME file
|
||||
cp CNAME $td/
|
||||
mv $td/ bookstodeploy
|
||||
|
@ -660,6 +702,7 @@ jobs:
|
|||
- style
|
||||
- check
|
||||
- checkexamples
|
||||
- testexamples
|
||||
- checkmacros
|
||||
- testv7
|
||||
- testv6
|
||||
|
@ -676,6 +719,7 @@ jobs:
|
|||
- style
|
||||
- check
|
||||
- checkexamples
|
||||
- testexamples
|
||||
- checkmacros
|
||||
- testv7
|
||||
- testv6
|
||||
|
|
|
@ -60,6 +60,7 @@ cortex-m-rtic-macros = { path = "macros", version = "0.5.2" }
|
|||
rtic-core = "0.3.0"
|
||||
cortex-m-rt = "0.6.9"
|
||||
heapless = "0.5.0"
|
||||
bare-metal = "1.0.0"
|
||||
|
||||
[build-dependencies]
|
||||
version_check = "0.9"
|
||||
|
|
|
@ -21,5 +21,3 @@
|
|||
- [Ceiling analysis](./internals/ceilings.md)
|
||||
- [Software tasks](./internals/tasks.md)
|
||||
- [Timer queue](./internals/timer-queue.md)
|
||||
- [Homogeneous multi-core support](./homogeneous.md)
|
||||
- [Heterogeneous multi-core support](./heterogeneous.md)
|
||||
|
|
|
@ -9,7 +9,7 @@ is required to follow along.
|
|||
|
||||
[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
|
||||
embedded development environment that includes QEMU.
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ This is the smallest possible RTIC application:
|
|||
```
|
||||
|
||||
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
|
||||
point to a *peripheral access crate* (PAC) generated using [`svd2rust`]
|
||||
**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
|
||||
[`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`
|
||||
|
||||
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
|
||||
`fn(init::Context) [-> init::LateResources]` (the return type is not always
|
||||
required).
|
||||
|
||||
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
|
||||
to Cortex-M and, optionally, device specific peripherals through the `core` and
|
||||
`device` fields of `init::Context`.
|
||||
to Cortex-M where the `bare_metal::CriticalSection` token is available as `cs`.
|
||||
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
|
||||
into `&'static mut` references that are safe to access.
|
||||
|
||||
[`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
|
||||
available when the `peripherals` argument is set to `true` (it defaults to
|
||||
`false`).
|
||||
|
@ -55,12 +49,13 @@ process.
|
|||
|
||||
``` console
|
||||
$ cargo run --example init
|
||||
{{#include ../../../../ci/expected/init.run}}```
|
||||
{{#include ../../../../ci/expected/init.run}}
|
||||
```
|
||||
|
||||
## `idle`
|
||||
|
||||
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) - > !`.
|
||||
|
||||
When present, the runtime will execute the `idle` task after `init`. Unlike
|
||||
|
@ -86,7 +81,8 @@ in LLVM which miss-optimizes empty loops to a `UDF` instruction in release mode.
|
|||
|
||||
``` console
|
||||
$ cargo run --example idle
|
||||
{{#include ../../../../ci/expected/idle.run}}```
|
||||
{{#include ../../../../ci/expected/idle.run}}
|
||||
```
|
||||
|
||||
## Hardware tasks
|
||||
|
||||
|
@ -107,7 +103,8 @@ mut` variables are safe to use within a hardware task.
|
|||
|
||||
``` console
|
||||
$ cargo run --example hardware
|
||||
{{#include ../../../../ci/expected/hardware.run}}```
|
||||
{{#include ../../../../ci/expected/hardware.run}}
|
||||
```
|
||||
|
||||
So far all the RTIC applications we have seen look no different than the
|
||||
applications one can write using only the `cortex-m-rt` crate. From this point
|
||||
|
@ -139,7 +136,8 @@ The following example showcases the priority based scheduling of tasks.
|
|||
|
||||
``` console
|
||||
$ cargo run --example preempt
|
||||
{{#include ../../../../ci/expected/preempt.run}}```
|
||||
{{#include ../../../../ci/expected/preempt.run}}
|
||||
```
|
||||
|
||||
Note that the task `gpiob` does *not* preempt task `gpioc` because its priority
|
||||
is the *same* as `gpioc`'s. However, once `gpioc` terminates the execution of
|
||||
|
|
|
@ -63,4 +63,5 @@ $ cargo add panic-semihosting
|
|||
``` console
|
||||
$ # NOTE: I have uncommented the `runner` option in `.cargo/config`
|
||||
$ cargo run
|
||||
{{#include ../../../../ci/expected/init.run}}```
|
||||
{{#include ../../../../ci/expected/init.run}}
|
||||
```
|
||||
|
|
|
@ -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.
|
||||
|
||||
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.
|
||||
|
||||
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]`
|
||||
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
|
||||
|
@ -29,7 +31,8 @@ access to a resource named `shared`.
|
|||
|
||||
``` console
|
||||
$ cargo run --example resource
|
||||
{{#include ../../../../ci/expected/resource.run}}```
|
||||
{{#include ../../../../ci/expected/resource.run}}
|
||||
```
|
||||
|
||||
Note that the `shared` resource cannot be accessed from `idle`. Attempting to do
|
||||
so results in a compile error.
|
||||
|
@ -71,7 +74,8 @@ lowest priority handler.
|
|||
|
||||
``` console
|
||||
$ cargo run --example lock
|
||||
{{#include ../../../../ci/expected/lock.run}}```
|
||||
{{#include ../../../../ci/expected/lock.run}}
|
||||
```
|
||||
|
||||
## Late resources
|
||||
|
||||
|
@ -97,7 +101,8 @@ the consumer resource.
|
|||
|
||||
``` console
|
||||
$ cargo run --example late
|
||||
{{#include ../../../../ci/expected/late.run}}```
|
||||
{{#include ../../../../ci/expected/late.run}}
|
||||
```
|
||||
|
||||
## Only shared access
|
||||
|
||||
|
@ -127,4 +132,5 @@ any kind of lock.
|
|||
|
||||
``` console
|
||||
$ cargo run --example only-shared-access
|
||||
{{#include ../../../../ci/expected/only-shared-access.run}}```
|
||||
{{#include ../../../../ci/expected/only-shared-access.run}}
|
||||
```
|
||||
|
|
|
@ -25,7 +25,8 @@ priorities. The three software tasks are mapped to 2 interrupts handlers.
|
|||
|
||||
``` console
|
||||
$ cargo run --example task
|
||||
{{#include ../../../../ci/expected/task.run}}```
|
||||
{{#include ../../../../ci/expected/task.run}}
|
||||
```
|
||||
|
||||
## Message passing
|
||||
|
||||
|
@ -41,7 +42,8 @@ The example below showcases three tasks, two of them expect a message.
|
|||
|
||||
``` console
|
||||
$ cargo run --example message
|
||||
{{#include ../../../../ci/expected/message.run}}```
|
||||
{{#include ../../../../ci/expected/message.run}}
|
||||
```
|
||||
|
||||
## Capacity
|
||||
|
||||
|
@ -63,7 +65,8 @@ fail (panic).
|
|||
|
||||
``` console
|
||||
$ cargo run --example capacity
|
||||
{{#include ../../../../ci/expected/capacity.run}}```
|
||||
{{#include ../../../../ci/expected/capacity.run}}
|
||||
```
|
||||
|
||||
## Error handling
|
||||
|
||||
|
@ -92,7 +95,7 @@ following snippet:
|
|||
|
||||
``` rust
|
||||
#[rtic::app(..)]
|
||||
const APP: () = {
|
||||
mod app {
|
||||
#[init(spawn = [foo, bar])]
|
||||
fn init(cx: init::Context) {
|
||||
cx.spawn.foo().unwrap();
|
||||
|
@ -113,5 +116,5 @@ const APP: () = {
|
|||
fn bar(cx: bar::Context, payload: i32) {
|
||||
// ..
|
||||
}
|
||||
};
|
||||
}
|
||||
```
|
||||
|
|
|
@ -24,7 +24,8 @@ Here's one such example:
|
|||
|
||||
``` console
|
||||
$ cargo run --example generics
|
||||
{{#include ../../../../ci/expected/generics.run}}```
|
||||
{{#include ../../../../ci/expected/generics.run}}
|
||||
```
|
||||
|
||||
Using generics also lets you change the static priorities of tasks during
|
||||
development without having to rewrite a bunch code every time.
|
||||
|
@ -47,7 +48,8 @@ the program has been compiled using the `dev` profile.
|
|||
$ cargo run --example cfg --release
|
||||
|
||||
$ cargo run --example cfg
|
||||
{{#include ../../../../ci/expected/cfg.run}}```
|
||||
{{#include ../../../../ci/expected/cfg.run}}
|
||||
```
|
||||
|
||||
## Running tasks from RAM
|
||||
|
||||
|
@ -78,7 +80,8 @@ Running this program produces the expected output.
|
|||
|
||||
``` console
|
||||
$ cargo run --example ramfunc
|
||||
{{#include ../../../../ci/expected/ramfunc.run}}```
|
||||
{{#include ../../../../ci/expected/ramfunc.run}}
|
||||
```
|
||||
|
||||
One can look at the output of `cargo-nm` to confirm that `bar` ended in RAM
|
||||
(`0x2000_0000`), whereas `foo` ended in Flash (`0x0000_0000`).
|
||||
|
@ -115,7 +118,8 @@ Here's an example where `heapless::Pool` is used to "box" buffers of 128 bytes.
|
|||
```
|
||||
``` console
|
||||
$ cargo run --example pool
|
||||
{{#include ../../../../ci/expected/pool.run}}```
|
||||
{{#include ../../../../ci/expected/pool.run}}
|
||||
```
|
||||
|
||||
## Inspecting the expanded code
|
||||
|
||||
|
@ -139,7 +143,7 @@ $ tail target/rtic-expansion.rs
|
|||
|
||||
``` rust
|
||||
#[doc = r" Implementation details"]
|
||||
const APP: () = {
|
||||
mod app {
|
||||
#[doc = r" Always include the device crate which contains the vector table"]
|
||||
use lm3s6965 as _;
|
||||
#[no_mangle]
|
||||
|
@ -152,7 +156,7 @@ const APP: () = {
|
|||
rtic::export::wfi()
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
Or, you can use the [`cargo-expand`] sub-command. This sub-command will expand
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# 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,
|
||||
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
|
||||
the RTIC framework performs a source code level transformation. This
|
||||
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.
|
||||
|
||||
Access to the resources is then given to each task using a `Resources` struct
|
||||
|
@ -29,7 +29,7 @@ happens behind the scenes:
|
|||
|
||||
``` rust
|
||||
#[rtic::app(device = ..)]
|
||||
const APP: () = {
|
||||
mod app {
|
||||
static mut X: u64: 0;
|
||||
static mut Y: bool: 0;
|
||||
|
||||
|
@ -49,7 +49,7 @@ const APP: () = {
|
|||
}
|
||||
|
||||
// ..
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
The framework produces codes like this:
|
||||
|
@ -103,8 +103,8 @@ pub mod bar {
|
|||
}
|
||||
|
||||
/// Implementation details
|
||||
const APP: () = {
|
||||
// everything inside this `const` item is hidden from user code
|
||||
mod app {
|
||||
// everything inside this module is hidden from user code
|
||||
|
||||
static mut X: u64 = 0;
|
||||
static mut Y: bool = 0;
|
||||
|
@ -154,5 +154,5 @@ const APP: () = {
|
|||
// ..
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
```
|
||||
|
|
|
@ -28,7 +28,7 @@ An example to illustrate the ceiling analysis:
|
|||
|
||||
``` rust
|
||||
#[rtic::app(device = ..)]
|
||||
const APP: () = {
|
||||
mod app {
|
||||
struct Resources {
|
||||
// accessed by `foo` (prio = 1) and `bar` (prio = 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
|
||||
#[rtic::app(device = ..)]
|
||||
const APP: () = {
|
||||
mut app {
|
||||
struct Resources {
|
||||
#[init(0)]
|
||||
x: u64,
|
||||
|
@ -57,7 +57,7 @@ const APP: () = {
|
|||
}
|
||||
|
||||
// ..
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
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;
|
||||
|
||||
impl rtic::Mutex for resources::x {
|
||||
|
@ -129,7 +129,7 @@ const APP: () = {
|
|||
// ..
|
||||
})
|
||||
}
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
## `lock`
|
||||
|
@ -225,7 +225,7 @@ Consider this program:
|
|||
|
||||
``` rust
|
||||
#[rtic::app(device = ..)]
|
||||
const APP: () = {
|
||||
mod app {
|
||||
struct Resources {
|
||||
#[init(0)]
|
||||
x: u64,
|
||||
|
@ -277,7 +277,7 @@ const APP: () = {
|
|||
}
|
||||
|
||||
// ..
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
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;
|
||||
|
||||
#[no_mangle]
|
||||
|
@ -368,7 +368,7 @@ const APP: () = {
|
|||
}
|
||||
|
||||
// repeat for resource `y`
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
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
|
||||
#[rtic::app(device = ..)]
|
||||
const APP: () = {
|
||||
mod app {
|
||||
struct Resources {
|
||||
#[init(0)]
|
||||
x: u64,
|
||||
|
@ -484,7 +484,7 @@ const APP: () = {
|
|||
// ..
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
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
|
||||
// code generated by RTIC
|
||||
|
||||
const APP: () = {
|
||||
mod app {
|
||||
// ..
|
||||
|
||||
#[no_mangle]
|
||||
|
@ -513,7 +513,7 @@ const APP: () = {
|
|||
// BUG: FORGOT to roll back the BASEPRI to the snapshot value we took before
|
||||
basepri::write(initial);
|
||||
}
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
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
|
||||
#[rtic::app(device = lm3s6965)]
|
||||
const APP: () = {
|
||||
mod app {
|
||||
#[init]
|
||||
fn init(c: init::Context) {
|
||||
// .. user code ..
|
||||
|
@ -28,7 +28,7 @@ const APP: () = {
|
|||
fn foo(c: foo::Context) {
|
||||
// .. user code ..
|
||||
}
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
The framework generates an entry point that looks like this:
|
||||
|
|
|
@ -10,7 +10,7 @@ initialize late resources.
|
|||
|
||||
``` rust
|
||||
#[rtic::app(device = ..)]
|
||||
const APP: () = {
|
||||
mod app {
|
||||
struct Resources {
|
||||
x: Thing,
|
||||
}
|
||||
|
@ -34,7 +34,7 @@ const APP: () = {
|
|||
}
|
||||
|
||||
// ..
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
The code generated by the framework looks like this:
|
||||
|
@ -69,7 +69,7 @@ pub mod foo {
|
|||
}
|
||||
|
||||
/// Implementation details
|
||||
const APP: () = {
|
||||
mod app {
|
||||
// uninitialized static
|
||||
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
|
||||
|
|
|
@ -12,7 +12,7 @@ are discouraged from directly invoking an interrupt handler.
|
|||
|
||||
``` rust
|
||||
#[rtic::app(device = ..)]
|
||||
const APP: () = {
|
||||
mod app {
|
||||
#[init]
|
||||
fn init(c: init::Context) { .. }
|
||||
|
||||
|
@ -39,7 +39,7 @@ const APP: () = {
|
|||
// in aliasing of the static variable `X`
|
||||
unsafe { UART0() }
|
||||
}
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
The RTIC framework must generate the interrupt handler code that calls the user
|
||||
|
@ -57,7 +57,7 @@ fn bar(c: bar::Context) {
|
|||
// .. user code ..
|
||||
}
|
||||
|
||||
const APP: () = {
|
||||
mod app {
|
||||
// everything in this block is not visible to user code
|
||||
|
||||
#[no_mangle]
|
||||
|
@ -69,7 +69,7 @@ const APP: () = {
|
|||
unsafe fn USART1() {
|
||||
bar(..);
|
||||
}
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
## By hardware
|
||||
|
|
|
@ -28,7 +28,7 @@ Consider this example:
|
|||
|
||||
``` rust
|
||||
#[rtic::app(device = ..)]
|
||||
const APP: () = {
|
||||
mod app {
|
||||
// ..
|
||||
|
||||
#[interrupt(binds = UART0, priority = 2, spawn = [bar, baz])]
|
||||
|
@ -51,7 +51,7 @@ const APP: () = {
|
|||
extern "C" {
|
||||
fn UART1();
|
||||
}
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
The framework produces the following task dispatcher which consists of an
|
||||
|
@ -62,7 +62,7 @@ fn bar(c: bar::Context) {
|
|||
// .. user code ..
|
||||
}
|
||||
|
||||
const APP: () = {
|
||||
mod app {
|
||||
use heapless::spsc::Queue;
|
||||
use cortex_m::register::basepri;
|
||||
|
||||
|
@ -110,7 +110,7 @@ const APP: () = {
|
|||
// BASEPRI invariant
|
||||
basepri::write(snapshot);
|
||||
}
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
## Spawning a task
|
||||
|
@ -144,7 +144,7 @@ mod foo {
|
|||
}
|
||||
}
|
||||
|
||||
const APP: () = {
|
||||
mod app {
|
||||
// ..
|
||||
|
||||
// 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
|
||||
|
@ -211,7 +211,7 @@ fn baz(c: baz::Context, input: u64) {
|
|||
// .. user code ..
|
||||
}
|
||||
|
||||
const APP: () = {
|
||||
mod app {
|
||||
// ..
|
||||
|
||||
// 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:
|
||||
|
||||
``` rust
|
||||
const APP: () = {
|
||||
mod app {
|
||||
// ..
|
||||
|
||||
#[no_mangle]
|
||||
|
@ -304,7 +304,7 @@ const APP: () = {
|
|||
// BASEPRI invariant
|
||||
basepri::write(snapshot);
|
||||
}
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
`INPUTS` plus `FQ`, the free queue, is effectively a memory pool. However,
|
||||
|
@ -357,7 +357,7 @@ Consider the following example:
|
|||
|
||||
``` rust
|
||||
#[rtic::app(device = ..)]
|
||||
const APP: () = {
|
||||
mod app {
|
||||
#[idle(spawn = [foo, bar])]
|
||||
fn idle(c: idle::Context) -> ! {
|
||||
// ..
|
||||
|
@ -382,7 +382,7 @@ const APP: () = {
|
|||
fn quux(c: quux::Context) {
|
||||
// ..
|
||||
}
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
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
|
||||
#[rtic::app(device = ..)]
|
||||
const APP: () = {
|
||||
mod app {
|
||||
// ..
|
||||
|
||||
#[task(capacity = 2, schedule = [foo])]
|
||||
|
@ -24,7 +24,7 @@ const APP: () = {
|
|||
extern "C" {
|
||||
fn UART0();
|
||||
}
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
## `schedule`
|
||||
|
@ -46,7 +46,7 @@ mod foo {
|
|||
}
|
||||
}
|
||||
|
||||
const APP: () = {
|
||||
mod app {
|
||||
type Instant = <path::to::user::monotonic::timer as rtic::Monotonic>::Instant;
|
||||
|
||||
// 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
|
||||
|
@ -123,7 +123,7 @@ is up.
|
|||
Let's see the associated code.
|
||||
|
||||
``` rust
|
||||
const APP: () = {
|
||||
mod app {
|
||||
#[no_mangle]
|
||||
fn SysTick() {
|
||||
const PRIORITY: u8 = 1;
|
||||
|
@ -146,7 +146,7 @@ const APP: () = {
|
|||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
tasks from running we choose the priority of the system timer to be the maximum
|
||||
of all the `schedule`-able tasks.
|
||||
|
@ -222,7 +222,7 @@ To illustrate, consider the following example:
|
|||
|
||||
``` rust
|
||||
#[rtic::app(device = ..)]
|
||||
const APP: () = {
|
||||
mod app {
|
||||
#[task(priority = 3, spawn = [baz])]
|
||||
fn foo(c: foo::Context) {
|
||||
// ..
|
||||
|
@ -237,7 +237,7 @@ const APP: () = {
|
|||
fn baz(c: baz::Context) {
|
||||
// ..
|
||||
}
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
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`.
|
||||
|
||||
- `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
|
||||
`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.
|
||||
|
||||
``` rust
|
||||
const APP: () = {
|
||||
mod app {
|
||||
// ..
|
||||
|
||||
#[no_mangle]
|
||||
|
@ -303,7 +303,7 @@ const APP: () = {
|
|||
// BASEPRI invariant
|
||||
basepri::write(snapshot);
|
||||
}
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
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> {
|
||||
/// Spawns the `baz` task
|
||||
pub fn baz(&self, message: u64) -> Result<(), u64> {
|
||||
|
@ -364,5 +364,5 @@ const APP: () = {
|
|||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
```
|
||||
|
|
|
@ -1,14 +1,112 @@
|
|||
# Migrating from v0.4.x to v0.5.0
|
||||
# Migration of RTIC
|
||||
|
||||
## Migrating from v0.5.x to v0.6.0
|
||||
|
||||
This section describes how to upgrade from v0.5.x to v0.6.0 of the RTIC framework.
|
||||
|
||||
### `Cargo.toml` - version bump
|
||||
|
||||
Change the version of `cortex-m-rtic` to `"0.6.0"`.
|
||||
|
||||
### Module instead of Const
|
||||
|
||||
With the support of attributes on modules the `const APP` workaround is not needed.
|
||||
|
||||
Change
|
||||
|
||||
``` rust
|
||||
#[rtic::app(/* .. */)]
|
||||
const APP: () = {
|
||||
[code here]
|
||||
};
|
||||
```
|
||||
|
||||
into
|
||||
|
||||
``` rust
|
||||
#[rtic::app(/* .. */)]
|
||||
mod app {
|
||||
[code here]
|
||||
}
|
||||
```
|
||||
|
||||
Now that a regular Rust module is used it means it is possible to have custom
|
||||
user code within that module.
|
||||
Additionally, it means that `use`-statements for resources etc may be required.
|
||||
|
||||
### Init always returns late resources
|
||||
|
||||
In order to make the API more symmetric the #[init]-task always returns a late resource.
|
||||
|
||||
From this:
|
||||
|
||||
``` rust
|
||||
#[rtic::app(device = lm3s6965)]
|
||||
mod app {
|
||||
#[init]
|
||||
fn init(_: init::Context) {
|
||||
rtic::pend(Interrupt::UART0);
|
||||
}
|
||||
[more code]
|
||||
}
|
||||
```
|
||||
|
||||
to this:
|
||||
|
||||
``` rust
|
||||
#[rtic::app(device = lm3s6965)]
|
||||
mod app {
|
||||
#[init]
|
||||
fn init(_: init::Context) -> init::LateResources {
|
||||
rtic::pend(Interrupt::UART0);
|
||||
|
||||
init::LateResources {}
|
||||
}
|
||||
[more code]
|
||||
}
|
||||
```
|
||||
|
||||
### Resources struct - #[resources]
|
||||
|
||||
Previously the RTIC resources had to be in in a struct named exactly "Resources":
|
||||
|
||||
``` rust
|
||||
struct Resources {
|
||||
// Resources defined in here
|
||||
}
|
||||
```
|
||||
|
||||
With RTIC v0.6.0 the resources struct is annotated similarly like
|
||||
`#[task]`, `#[init]`, `#[idle]`: with an attribute `#[resources]`
|
||||
|
||||
``` rust
|
||||
#[resources]
|
||||
struct Resources {
|
||||
// Resources defined in here
|
||||
}
|
||||
```
|
||||
|
||||
In fact, the name of the struct is now up to the developer:
|
||||
|
||||
``` rust
|
||||
#[resources]
|
||||
struct whateveryouwant {
|
||||
// Resources defined in here
|
||||
}
|
||||
```
|
||||
|
||||
would work equally well.
|
||||
|
||||
## Migrating from v0.4.x to v0.5.0
|
||||
|
||||
This section covers how to upgrade an application written against RTIC v0.4.x to
|
||||
the version v0.5.0 of the framework.
|
||||
|
||||
## `Cargo.toml`
|
||||
### `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
|
||||
|
@ -22,7 +120,7 @@ features = ["timer-queue"]
|
|||
# ^^^^^^^^^^^^^
|
||||
```
|
||||
|
||||
## `Context` argument
|
||||
### `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
|
||||
|
@ -74,7 +172,7 @@ const APP: () = {
|
|||
};
|
||||
```
|
||||
|
||||
## Resources
|
||||
### Resources
|
||||
|
||||
The syntax used to declare resources has been changed from `static mut`
|
||||
variables to a `struct Resources`.
|
||||
|
@ -98,7 +196,7 @@ const APP: () = {
|
|||
};
|
||||
```
|
||||
|
||||
## Device peripherals
|
||||
### 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
|
||||
|
@ -136,7 +234,7 @@ const APP: () = {
|
|||
};
|
||||
```
|
||||
|
||||
## `#[interrupt]` and `#[exception]`
|
||||
### `#[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.
|
||||
|
@ -182,7 +280,7 @@ const APP: () = {
|
|||
};
|
||||
```
|
||||
|
||||
## `schedule`
|
||||
### `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`
|
||||
|
@ -194,7 +292,7 @@ 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`.
|
||||
inside `init`.
|
||||
|
||||
Change this:
|
||||
|
||||
|
|
|
@ -13,8 +13,10 @@ There is a translation of this book in [Russian].
|
|||
|
||||
[Russian]: ../ru/index.html
|
||||
|
||||
This is the documentation of v0.5.x of RTIC; for the documentation of version
|
||||
v0.4.x go [here](/0.4).
|
||||
This is the documentation of v0.6.x of RTIC; for the documentation of version
|
||||
|
||||
* v0.5.x go [here](/0.5).
|
||||
* v0.4.x go [here](/0.4).
|
||||
|
||||
{{#include ../../../README.md:7:46}}
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ use panic_semihosting as _;
|
|||
|
||||
// NOTE: does NOT properly work on QEMU
|
||||
#[rtic::app(device = lm3s6965, monotonic = rtic::cyccnt::CYCCNT)]
|
||||
const APP: () = {
|
||||
mod app {
|
||||
#[init(spawn = [foo])]
|
||||
fn init(cx: init::Context) -> init::LateResources {
|
||||
// omitted: initialization of `CYCCNT`
|
||||
|
@ -53,4 +53,4 @@ const APP: () = {
|
|||
extern "C" {
|
||||
fn SSI0();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ use panic_semihosting as _;
|
|||
|
||||
// `examples/interrupt.rs` rewritten to use `binds`
|
||||
#[rtic::app(device = lm3s6965)]
|
||||
const APP: () = {
|
||||
mod app {
|
||||
#[init]
|
||||
fn init(_: init::Context) -> init::LateResources {
|
||||
rtic::pend(Interrupt::UART0);
|
||||
|
@ -47,4 +47,4 @@ const APP: () = {
|
|||
)
|
||||
.unwrap();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ use lm3s6965::Interrupt;
|
|||
use panic_semihosting as _;
|
||||
|
||||
#[rtic::app(device = lm3s6965)]
|
||||
const APP: () = {
|
||||
mod app {
|
||||
#[init]
|
||||
fn init(_: init::Context) -> init::LateResources {
|
||||
rtic::pend(Interrupt::UART0);
|
||||
|
@ -46,4 +46,4 @@ const APP: () = {
|
|||
extern "C" {
|
||||
fn SSI0();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -11,7 +11,8 @@ use cortex_m_semihosting::hprintln;
|
|||
use panic_semihosting as _;
|
||||
|
||||
#[rtic::app(device = lm3s6965)]
|
||||
const APP: () = {
|
||||
mod app {
|
||||
#[resources]
|
||||
struct Resources {
|
||||
#[cfg(debug_assertions)] // <- `true` when using the `dev` profile
|
||||
#[init(0)]
|
||||
|
@ -68,4 +69,4 @@ const APP: () = {
|
|||
fn SSI0();
|
||||
fn QEI0();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -10,7 +10,8 @@ use lm3s6965::Interrupt;
|
|||
use panic_semihosting as _;
|
||||
|
||||
#[rtic::app(device = lm3s6965)]
|
||||
const APP: () = {
|
||||
mod app {
|
||||
#[resources]
|
||||
struct Resources {
|
||||
// Some resources to work with
|
||||
#[init(0)]
|
||||
|
@ -46,4 +47,4 @@ const APP: () = {
|
|||
|
||||
hprintln!("UART0: a = {}, b = {}, c = {}", a, b, c).unwrap();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -9,7 +9,9 @@ use panic_semihosting as _;
|
|||
use rtic::cyccnt::U32Ext;
|
||||
|
||||
#[rtic::app(device = lm3s6965, monotonic = rtic::cyccnt::CYCCNT)]
|
||||
const APP: () = {
|
||||
mod app {
|
||||
|
||||
#[resources]
|
||||
struct Resources {
|
||||
nothing: (),
|
||||
}
|
||||
|
@ -34,4 +36,4 @@ const APP: () = {
|
|||
extern "C" {
|
||||
fn SSI0();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -11,7 +11,8 @@ use panic_semihosting as _;
|
|||
use rtic::{Exclusive, Mutex};
|
||||
|
||||
#[rtic::app(device = lm3s6965)]
|
||||
const APP: () = {
|
||||
mod app {
|
||||
#[resources]
|
||||
struct Resources {
|
||||
#[init(0)]
|
||||
shared: u32,
|
||||
|
@ -51,7 +52,7 @@ const APP: () = {
|
|||
// second argument has type `Exclusive<u32>`
|
||||
advance(STATE, Exclusive(c.resources.shared));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// 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>) {
|
||||
|
|
|
@ -10,7 +10,7 @@ use lm3s6965::Interrupt;
|
|||
use panic_semihosting as _;
|
||||
|
||||
#[rtic::app(device = lm3s6965)]
|
||||
const APP: () = {
|
||||
mod app {
|
||||
#[init]
|
||||
fn init(_: init::Context) -> init::LateResources {
|
||||
// Pends the UART0 interrupt but its handler won't run until *after*
|
||||
|
@ -51,4 +51,4 @@ const APP: () = {
|
|||
)
|
||||
.unwrap();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ use cortex_m_semihosting::{debug, hprintln};
|
|||
use panic_semihosting as _;
|
||||
|
||||
#[rtic::app(device = lm3s6965)]
|
||||
const APP: () = {
|
||||
mod app {
|
||||
#[init]
|
||||
fn init(_: init::Context) -> init::LateResources {
|
||||
hprintln!("init").unwrap();
|
||||
|
@ -32,4 +32,4 @@ const APP: () = {
|
|||
cortex_m::asm::nop();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ use cortex_m_semihosting::{debug, hprintln};
|
|||
use panic_semihosting as _;
|
||||
|
||||
#[rtic::app(device = lm3s6965, peripherals = true)]
|
||||
const APP: () = {
|
||||
mod app {
|
||||
#[init]
|
||||
fn init(cx: init::Context) -> init::LateResources {
|
||||
static mut X: u32 = 0;
|
||||
|
@ -23,10 +23,14 @@ const APP: () = {
|
|||
// Safe access to local `static mut` variable
|
||||
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();
|
||||
|
||||
debug::exit(debug::EXIT_SUCCESS);
|
||||
|
||||
init::LateResources {}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -15,8 +15,13 @@ use lm3s6965::Interrupt;
|
|||
use panic_semihosting as _;
|
||||
|
||||
#[rtic::app(device = lm3s6965)]
|
||||
const APP: () = {
|
||||
mod app {
|
||||
use heapless::{
|
||||
consts::*,
|
||||
spsc::{Consumer, Producer},
|
||||
};
|
||||
// Late resources
|
||||
#[resources]
|
||||
struct Resources {
|
||||
p: Producer<'static, u32, U4>,
|
||||
c: Consumer<'static, u32, U4>,
|
||||
|
@ -49,4 +54,4 @@ const APP: () = {
|
|||
fn uart0(c: uart0::Context) {
|
||||
c.resources.p.enqueue(42).unwrap();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -10,7 +10,8 @@ use lm3s6965::Interrupt;
|
|||
use panic_semihosting as _;
|
||||
|
||||
#[rtic::app(device = lm3s6965)]
|
||||
const APP: () = {
|
||||
mod app {
|
||||
#[resources]
|
||||
struct Resources {
|
||||
#[init(0)]
|
||||
shared: u32,
|
||||
|
@ -61,4 +62,4 @@ const APP: () = {
|
|||
fn gpioc(_: gpioc::Context) {
|
||||
hprintln!("C").unwrap();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ use cortex_m_semihosting::{debug, hprintln};
|
|||
use panic_semihosting as _;
|
||||
|
||||
#[rtic::app(device = lm3s6965)]
|
||||
const APP: () = {
|
||||
mod app {
|
||||
#[init(spawn = [foo])]
|
||||
fn init(c: init::Context) -> init::LateResources {
|
||||
c.spawn.foo(/* no message */).unwrap();
|
||||
|
@ -51,4 +51,4 @@ const APP: () = {
|
|||
extern "C" {
|
||||
fn SSI0();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -16,7 +16,10 @@ pub struct NotSend {
|
|||
}
|
||||
|
||||
#[app(device = lm3s6965)]
|
||||
const APP: () = {
|
||||
mod app {
|
||||
use super::NotSend;
|
||||
|
||||
#[resources]
|
||||
struct Resources {
|
||||
#[init(None)]
|
||||
shared: Option<NotSend>,
|
||||
|
@ -62,4 +65,4 @@ const APP: () = {
|
|||
fn SSI0();
|
||||
fn QEI0();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -15,7 +15,11 @@ pub struct NotSync {
|
|||
}
|
||||
|
||||
#[rtic::app(device = lm3s6965)]
|
||||
const APP: () = {
|
||||
mod app {
|
||||
use super::NotSync;
|
||||
use core::marker::PhantomData;
|
||||
|
||||
#[resources]
|
||||
struct Resources {
|
||||
#[init(NotSync { _0: PhantomData })]
|
||||
shared: NotSync,
|
||||
|
@ -44,4 +48,4 @@ const APP: () = {
|
|||
extern "C" {
|
||||
fn SSI0();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -10,7 +10,8 @@ use lm3s6965::Interrupt;
|
|||
use panic_semihosting as _;
|
||||
|
||||
#[rtic::app(device = lm3s6965)]
|
||||
const APP: () = {
|
||||
mod app {
|
||||
#[resources]
|
||||
struct Resources {
|
||||
key: u32,
|
||||
}
|
||||
|
@ -35,4 +36,4 @@ const APP: () = {
|
|||
fn uart1(cx: uart1::Context) {
|
||||
hprintln!("UART1(key = {:#x})", cx.resources.key).unwrap();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -13,7 +13,8 @@ const PERIOD: u32 = 8_000_000;
|
|||
|
||||
// NOTE: does NOT work on QEMU!
|
||||
#[rtic::app(device = lm3s6965, monotonic = rtic::cyccnt::CYCCNT)]
|
||||
const APP: () = {
|
||||
mod app {
|
||||
|
||||
#[init(schedule = [foo])]
|
||||
fn init(cx: init::Context) -> init::LateResources {
|
||||
// omitted: initialization of `CYCCNT`
|
||||
|
@ -37,4 +38,4 @@ const APP: () = {
|
|||
extern "C" {
|
||||
fn SSI0();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -7,12 +7,12 @@ use cortex_m_semihosting::debug;
|
|||
use panic_semihosting as _;
|
||||
|
||||
#[rtic::app(device = lm3s6965)]
|
||||
const APP: () = {
|
||||
mod app {
|
||||
#[init]
|
||||
fn main(_: main::Context) -> main::LateResources {
|
||||
fn init(_: init::Context) -> init::LateResources {
|
||||
assert!(cortex_m::Peripherals::take().is_none());
|
||||
debug::exit(debug::EXIT_SUCCESS);
|
||||
|
||||
main::LateResources {}
|
||||
init::LateResources {}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -18,7 +18,12 @@ use rtic::app;
|
|||
pool!(P: [u8; 128]);
|
||||
|
||||
#[app(device = lm3s6965)]
|
||||
const APP: () = {
|
||||
mod app {
|
||||
use crate::Box;
|
||||
|
||||
// Import the memory pool into scope
|
||||
use super::P;
|
||||
|
||||
#[init]
|
||||
fn init(_: init::Context) -> init::LateResources {
|
||||
static mut MEMORY: [u8; 512] = [0; 512];
|
||||
|
@ -68,4 +73,4 @@ const APP: () = {
|
|||
fn SSI0();
|
||||
fn QEI0();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ use panic_semihosting as _;
|
|||
use rtic::app;
|
||||
|
||||
#[app(device = lm3s6965)]
|
||||
const APP: () = {
|
||||
mod app {
|
||||
#[init]
|
||||
fn init(_: init::Context) -> init::LateResources {
|
||||
rtic::pend(Interrupt::GPIOA);
|
||||
|
@ -36,4 +36,4 @@ const APP: () = {
|
|||
rtic::pend(Interrupt::GPIOB);
|
||||
hprintln!(" GPIOC - end").unwrap();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ use cortex_m_semihosting::{debug, hprintln};
|
|||
use panic_semihosting as _;
|
||||
|
||||
#[rtic::app(device = lm3s6965)]
|
||||
const APP: () = {
|
||||
mod app {
|
||||
#[init(spawn = [bar])]
|
||||
fn init(c: init::Context) -> init::LateResources {
|
||||
c.spawn.bar().unwrap();
|
||||
|
@ -40,4 +40,4 @@ const APP: () = {
|
|||
#[link_section = ".data.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 _;
|
||||
|
||||
#[rtic::app(device = lm3s6965)]
|
||||
const APP: () = {
|
||||
mod app {
|
||||
#[resources]
|
||||
struct Resources {
|
||||
// A resource
|
||||
#[init(0)]
|
||||
|
@ -54,4 +55,4 @@ const APP: () = {
|
|||
|
||||
hprintln!("UART1: shared = {}", cx.resources.shared).unwrap();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ use rtic::cyccnt::{Instant, U32Ext as _};
|
|||
|
||||
// NOTE: does NOT work on QEMU!
|
||||
#[rtic::app(device = lm3s6965, monotonic = rtic::cyccnt::CYCCNT)]
|
||||
const APP: () = {
|
||||
mod app {
|
||||
#[init(schedule = [foo, bar])]
|
||||
fn init(mut cx: init::Context) -> init::LateResources {
|
||||
// Initialize (enable) the monotonic timer (CYCCNT)
|
||||
|
@ -52,4 +52,4 @@ const APP: () = {
|
|||
extern "C" {
|
||||
fn SSI0();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -13,7 +13,10 @@ use rtic::app;
|
|||
pub struct MustBeSend;
|
||||
|
||||
#[app(device = lm3s6965)]
|
||||
const APP: () = {
|
||||
mod app {
|
||||
use super::MustBeSend;
|
||||
|
||||
#[resources]
|
||||
struct Resources {
|
||||
#[init(None)]
|
||||
shared: Option<MustBeSend>,
|
||||
|
@ -39,4 +42,4 @@ const APP: () = {
|
|||
debug::exit(debug::EXIT_SUCCESS);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -7,4 +7,4 @@ use panic_semihosting as _; // panic handler
|
|||
use rtic::app;
|
||||
|
||||
#[app(device = lm3s6965)]
|
||||
const APP: () = {};
|
||||
mod app {}
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
use panic_halt as _;
|
||||
|
||||
#[rtic::app(device = lm3s6965)]
|
||||
const APP: () = {
|
||||
mod app {
|
||||
#[init]
|
||||
fn init(_: init::Context) -> init::LateResources {
|
||||
init::LateResources {}
|
||||
|
@ -25,7 +25,7 @@ const APP: () = {
|
|||
fn bar(c: bar::Context) {
|
||||
bar_trampoline(c)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn foo_trampoline(_: foo::Context) {}
|
||||
|
|
|
@ -6,19 +6,17 @@
|
|||
use panic_halt as _;
|
||||
|
||||
#[rtic::app(device = lm3s6965)]
|
||||
const APP: () = {
|
||||
mod app {
|
||||
#[resources]
|
||||
struct Resources {
|
||||
// A resource
|
||||
#[init(0)]
|
||||
shared: u32,
|
||||
|
||||
// A conditionally compiled resource behind feature_x
|
||||
#[cfg(feature = "feature_x")]
|
||||
x: u32,
|
||||
|
||||
dummy: (),
|
||||
dummy: (), // dummy such that we have at least one late resource
|
||||
}
|
||||
|
||||
#[init]
|
||||
fn init(_: init::Context) -> init::LateResources {
|
||||
init::LateResources {
|
||||
|
@ -35,4 +33,4 @@ const APP: () = {
|
|||
cortex_m::asm::nop();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -6,7 +6,8 @@
|
|||
use panic_halt as _;
|
||||
|
||||
#[rtic::app(device = lm3s6965, monotonic = rtic::cyccnt::CYCCNT)]
|
||||
const APP: () = {
|
||||
mod app {
|
||||
#[resources]
|
||||
struct Resources {
|
||||
#[cfg(never)]
|
||||
#[init(0)]
|
||||
|
@ -54,4 +55,4 @@ const APP: () = {
|
|||
fn SSI0();
|
||||
fn QEI0();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ use cortex_m_semihosting::debug;
|
|||
use panic_semihosting as _;
|
||||
|
||||
#[rtic::app(device = lm3s6965)]
|
||||
const APP: () = {
|
||||
mod app {
|
||||
#[init]
|
||||
fn init(_: init::Context) -> init::LateResources {
|
||||
rtic::pend(lm3s6965::Interrupt::UART0);
|
||||
|
@ -16,7 +16,7 @@ const APP: () = {
|
|||
}
|
||||
|
||||
#[task(binds = UART0)]
|
||||
fn main(_: main::Context) {
|
||||
fn taskmain(_: taskmain::Context) {
|
||||
debug::exit(debug::EXIT_SUCCESS);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -7,17 +7,17 @@ use cortex_m_semihosting::debug;
|
|||
use panic_semihosting as _;
|
||||
|
||||
#[rtic::app(device = lm3s6965)]
|
||||
const APP: () = {
|
||||
mod app {
|
||||
#[init]
|
||||
fn init(_: init::Context) -> init::LateResources {
|
||||
init::LateResources {}
|
||||
}
|
||||
|
||||
#[idle]
|
||||
fn main(_: main::Context) -> ! {
|
||||
fn taskmain(_: taskmain::Context) -> ! {
|
||||
debug::exit(debug::EXIT_SUCCESS);
|
||||
loop {
|
||||
cortex_m::asm::nop();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -7,11 +7,11 @@ use cortex_m_semihosting::debug;
|
|||
use panic_semihosting as _;
|
||||
|
||||
#[rtic::app(device = lm3s6965)]
|
||||
const APP: () = {
|
||||
mod app {
|
||||
#[init]
|
||||
fn main(_: main::Context) -> main::LateResources {
|
||||
fn init(_: init::Context) -> init::LateResources {
|
||||
debug::exit(debug::EXIT_SUCCESS);
|
||||
|
||||
main::LateResources {}
|
||||
init::LateResources {}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -12,7 +12,10 @@ pub struct NotSend {
|
|||
}
|
||||
|
||||
#[rtic::app(device = lm3s6965)]
|
||||
const APP: () = {
|
||||
mod app {
|
||||
use super::NotSend;
|
||||
|
||||
#[resources]
|
||||
struct Resources {
|
||||
x: NotSend,
|
||||
#[init(None)]
|
||||
|
@ -35,4 +38,4 @@ const APP: () = {
|
|||
cortex_m::asm::nop();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -8,7 +8,8 @@
|
|||
use panic_halt as _;
|
||||
|
||||
#[rtic::app(device = lm3s6965)]
|
||||
const APP: () = {
|
||||
mod app {
|
||||
#[resources]
|
||||
struct Resources {
|
||||
#[init(0)]
|
||||
o1: u32, // init
|
||||
|
@ -88,4 +89,4 @@ const APP: () = {
|
|||
// no `Mutex` proxy when co-owned by cooperative (same priority) tasks
|
||||
let _: &mut u32 = c.resources.s2;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ use panic_halt as _;
|
|||
use rtic::cyccnt::{Instant, U32Ext as _};
|
||||
|
||||
#[rtic::app(device = lm3s6965, monotonic = rtic::cyccnt::CYCCNT)]
|
||||
const APP: () = {
|
||||
mod app {
|
||||
#[init(schedule = [foo, bar, baz])]
|
||||
fn init(c: init::Context) -> init::LateResources {
|
||||
let _: Result<(), ()> = c.schedule.foo(c.start + 10.cycles());
|
||||
|
@ -63,4 +63,4 @@ const APP: () = {
|
|||
extern "C" {
|
||||
fn SSI0();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
use panic_halt as _;
|
||||
|
||||
#[rtic::app(device = lm3s6965)]
|
||||
const APP: () = {
|
||||
mod app {
|
||||
#[init(spawn = [foo, bar, baz])]
|
||||
fn init(c: init::Context) -> init::LateResources {
|
||||
let _: Result<(), ()> = c.spawn.foo();
|
||||
|
@ -62,4 +62,4 @@ const APP: () = {
|
|||
extern "C" {
|
||||
fn SSI0();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -7,16 +7,16 @@ use cortex_m_semihosting::debug;
|
|||
use panic_semihosting as _;
|
||||
|
||||
#[rtic::app(device = lm3s6965)]
|
||||
const APP: () = {
|
||||
#[init(spawn = [main])]
|
||||
mod app {
|
||||
#[init(spawn = [taskmain])]
|
||||
fn init(cx: init::Context) -> init::LateResources {
|
||||
cx.spawn.main().ok();
|
||||
cx.spawn.taskmain().ok();
|
||||
|
||||
init::LateResources {}
|
||||
}
|
||||
|
||||
#[task]
|
||||
fn main(_: main::Context) {
|
||||
fn taskmain(_: taskmain::Context) {
|
||||
debug::exit(debug::EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
|
@ -26,4 +26,4 @@ const APP: () = {
|
|||
extern "C" {
|
||||
fn SSI0();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ use cortex_m_semihosting::{debug, hprintln};
|
|||
use panic_semihosting as _;
|
||||
|
||||
#[rtic::app(device = lm3s6965)]
|
||||
const APP: () = {
|
||||
mod app {
|
||||
#[init(spawn = [foo])]
|
||||
fn init(c: init::Context) -> init::LateResources {
|
||||
c.spawn.foo().unwrap();
|
||||
|
@ -54,4 +54,4 @@ const APP: () = {
|
|||
fn SSI0();
|
||||
fn QEI0();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -10,7 +10,8 @@ use panic_semihosting as _;
|
|||
use rtic::cyccnt;
|
||||
|
||||
#[rtic::app(device = lm3s6965, peripherals = true, monotonic = rtic::cyccnt::CYCCNT)]
|
||||
const APP: () = {
|
||||
mod app {
|
||||
#[resources]
|
||||
struct Resources {
|
||||
#[init(0)]
|
||||
shared: u32,
|
||||
|
@ -62,4 +63,4 @@ const APP: () = {
|
|||
extern "C" {
|
||||
fn SSI0();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -25,21 +25,36 @@ mod util;
|
|||
|
||||
// TODO document the syntax here or in `rtic-syntax`
|
||||
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 root = vec![];
|
||||
let mut user = vec![];
|
||||
let mut imports = vec![];
|
||||
|
||||
// Generate the `main` function
|
||||
let assertion_stmts = assertions::codegen(analysis);
|
||||
|
||||
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 (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_init
|
||||
|
@ -47,16 +62,21 @@ pub fn app(app: &App, analysis: &Analysis, extra: &Extra) -> TokenStream2 {
|
|||
#user_idle
|
||||
));
|
||||
|
||||
imports.push(quote!(
|
||||
#(#user_init_imports)*
|
||||
#(#user_idle_imports)*
|
||||
));
|
||||
|
||||
root.push(quote!(
|
||||
#(#root_init)*
|
||||
|
||||
#(#root_idle)*
|
||||
));
|
||||
|
||||
const_app.push(quote!(
|
||||
#const_app_init
|
||||
mod_app.push(quote!(
|
||||
#mod_app_init
|
||||
|
||||
#const_app_idle
|
||||
#mod_app_idle
|
||||
));
|
||||
|
||||
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) =
|
||||
hardware_tasks::codegen(app, analysis, extra);
|
||||
let (
|
||||
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) =
|
||||
software_tasks::codegen(app, analysis, extra);
|
||||
let (
|
||||
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 device = extra.device;
|
||||
quote!(
|
||||
|
@ -111,28 +142,41 @@ pub fn app(app: &App, analysis: &Analysis, extra: &Extra) -> TokenStream2 {
|
|||
#(#root_software_tasks)*
|
||||
|
||||
/// Implementation details
|
||||
// The user can't access the items within this `const` item
|
||||
const #name: () = {
|
||||
mod #name {
|
||||
/// Always include the device crate which contains the vector table
|
||||
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)*
|
||||
};
|
||||
}
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use proc_macro2::TokenStream as TokenStream2;
|
||||
use quote::quote;
|
||||
use quote::{format_ident, quote};
|
||||
use rtic_syntax::{ast::App, Context};
|
||||
|
||||
use crate::{
|
||||
|
@ -14,7 +14,7 @@ pub fn codegen(
|
|||
analysis: &Analysis,
|
||||
extra: &Extra,
|
||||
) -> (
|
||||
// const_app_hardware_tasks -- interrupt handlers and `${task}Resources` constructors
|
||||
// mod_app_hardware_tasks -- interrupt handlers and `${task}Resources` constructors
|
||||
Vec<TokenStream2>,
|
||||
// root_hardware_tasks -- items that must be placed in the root of the crate:
|
||||
// - `${task}Locals` structs
|
||||
|
@ -23,10 +23,13 @@ pub fn codegen(
|
|||
Vec<TokenStream2>,
|
||||
// user_hardware_tasks -- the `#[task]` functions written by the user
|
||||
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 user_tasks = vec![];
|
||||
let mut hardware_tasks_imports = vec![];
|
||||
|
||||
for (name, task) in &app.hardware_tasks {
|
||||
let (let_instant, instant) = if app.uses_schedule() {
|
||||
|
@ -49,7 +52,7 @@ pub fn codegen(
|
|||
let symbol = task.args.binds.clone();
|
||||
let priority = task.args.priority;
|
||||
|
||||
const_app.push(quote!(
|
||||
mod_app.push(quote!(
|
||||
#[allow(non_snake_case)]
|
||||
#[no_mangle]
|
||||
unsafe fn #symbol() {
|
||||
|
@ -78,9 +81,16 @@ pub fn codegen(
|
|||
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);
|
||||
|
||||
const_app.push(constructor);
|
||||
mod_app.push(constructor);
|
||||
}
|
||||
|
||||
root.push(module::codegen(
|
||||
|
@ -112,7 +122,13 @@ pub fn codegen(
|
|||
#(#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 quote::quote;
|
||||
use quote::{format_ident, quote};
|
||||
use rtic_syntax::{ast::App, Context};
|
||||
|
||||
use crate::{
|
||||
|
@ -14,7 +14,7 @@ pub fn codegen(
|
|||
analysis: &Analysis,
|
||||
extra: &Extra,
|
||||
) -> (
|
||||
// const_app_idle -- the `${idle}Resources` constructor
|
||||
// mod_app_idle -- the `${idle}Resources` constructor
|
||||
Option<TokenStream2>,
|
||||
// root_idle -- items that must be placed in the root of the crate:
|
||||
// - the `${idle}Locals` struct
|
||||
|
@ -23,26 +23,37 @@ pub fn codegen(
|
|||
Vec<TokenStream2>,
|
||||
// user_idle
|
||||
Option<TokenStream2>,
|
||||
// user_idle_imports
|
||||
Vec<TokenStream2>,
|
||||
// call_idle
|
||||
TokenStream2,
|
||||
) {
|
||||
if app.idles.len() > 0 {
|
||||
let idle = &app.idles.first().unwrap();
|
||||
let mut needs_lt = false;
|
||||
let mut const_app = None;
|
||||
let mut mod_app = None;
|
||||
let mut root_idle = vec![];
|
||||
let mut locals_pat = None;
|
||||
let mut locals_new = None;
|
||||
|
||||
let mut user_idle_imports = vec![];
|
||||
|
||||
let name = &idle.name;
|
||||
|
||||
if !idle.args.resources.is_empty() {
|
||||
let (item, constructor) =
|
||||
resources_struct::codegen(Context::Idle, 0, &mut needs_lt, app, analysis);
|
||||
|
||||
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() {
|
||||
let (locals, pat) = locals::codegen(Context::Idle, &idle.locals, app);
|
||||
|
||||
|
@ -66,6 +77,11 @@ pub fn codegen(
|
|||
#(#stmts)*
|
||||
}
|
||||
));
|
||||
user_idle_imports.push(quote!(
|
||||
#(#attrs)*
|
||||
#[allow(non_snake_case)]
|
||||
use super::#name;
|
||||
));
|
||||
|
||||
let locals_new = locals_new.iter();
|
||||
let call_idle = quote!(crate::#name(
|
||||
|
@ -73,12 +89,13 @@ pub fn codegen(
|
|||
#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 {
|
||||
(
|
||||
None,
|
||||
vec![],
|
||||
None,
|
||||
vec![],
|
||||
quote!(loop {
|
||||
rtic::export::wfi()
|
||||
}),
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use proc_macro2::TokenStream as TokenStream2;
|
||||
use quote::quote;
|
||||
use quote::{format_ident, quote};
|
||||
use rtic_syntax::{ast::App, Context};
|
||||
|
||||
use crate::{
|
||||
|
@ -14,7 +14,7 @@ pub fn codegen(
|
|||
analysis: &Analysis,
|
||||
extra: &Extra,
|
||||
) -> (
|
||||
// const_app_idle -- the `${init}Resources` constructor
|
||||
// mod_app_idle -- the `${init}Resources` constructor
|
||||
Option<TokenStream2>,
|
||||
// root_init -- items that must be placed in the root of the crate:
|
||||
// - the `${init}Locals` struct
|
||||
|
@ -24,6 +24,8 @@ pub fn codegen(
|
|||
Vec<TokenStream2>,
|
||||
// user_init -- the `#[init]` function written by the user
|
||||
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
|
||||
Option<TokenStream2>,
|
||||
) {
|
||||
|
@ -43,13 +45,14 @@ pub fn codegen(
|
|||
let cfgs = &app.late_resources[name].cfgs;
|
||||
|
||||
quote!(
|
||||
#(#cfgs)*
|
||||
pub #name: #ty
|
||||
#(#cfgs)*
|
||||
pub #name: #ty
|
||||
)
|
||||
})
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let mut user_init_imports = vec![];
|
||||
let late_resources = util::late_resources_ident(&name);
|
||||
|
||||
root_init.push(quote!(
|
||||
|
@ -81,14 +84,25 @@ pub fn codegen(
|
|||
#(#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() {
|
||||
let (item, constructor) =
|
||||
resources_struct::codegen(Context::Init, 0, &mut needs_lt, app, analysis);
|
||||
|
||||
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();
|
||||
|
@ -98,8 +112,8 @@ pub fn codegen(
|
|||
|
||||
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 {
|
||||
(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()));
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
|
|
|
@ -10,13 +10,16 @@ pub fn codegen(
|
|||
analysis: &Analysis,
|
||||
extra: &Extra,
|
||||
) -> (
|
||||
// const_app -- the `static [mut]` variables behind the proxies
|
||||
// mod_app -- the `static [mut]` variables behind the proxies
|
||||
Vec<TokenStream2>,
|
||||
// mod_resources -- the `resources` module
|
||||
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_imports = vec![];
|
||||
|
||||
for (name, res, expr, _) in app.resources(analysis) {
|
||||
let cfgs = &res.cfgs;
|
||||
|
@ -39,7 +42,7 @@ pub fn codegen(
|
|||
};
|
||||
|
||||
let attrs = &res.attrs;
|
||||
const_app.push(quote!(
|
||||
mod_app.push(quote!(
|
||||
#[allow(non_upper_case_globals)]
|
||||
#(#attrs)*
|
||||
#(#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,
|
||||
cfgs,
|
||||
true,
|
||||
|
@ -97,6 +106,11 @@ pub fn codegen(
|
|||
let mod_resources = if mod_resources.is_empty() {
|
||||
quote!()
|
||||
} else {
|
||||
// Also import the resource module
|
||||
mod_resources_imports.push(quote!(
|
||||
use super::resources;
|
||||
));
|
||||
|
||||
quote!(mod resources {
|
||||
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!(
|
||||
impl<#lt> #ident<#lt> {
|
||||
#[inline(always)]
|
||||
unsafe fn new(#arg) -> Self {
|
||||
pub unsafe fn new(#arg) -> Self {
|
||||
#ident {
|
||||
#(#values,)*
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ pub fn codegen(app: &App, extra: &Extra) -> Vec<TokenStream2> {
|
|||
|
||||
methods.push(quote!(
|
||||
#(#cfgs)*
|
||||
fn #name(&self, instant: #instant #(,#args)*) -> Result<(), #ty> {
|
||||
pub fn #name(&self, instant: #instant #(,#args)*) -> Result<(), #ty> {
|
||||
#body
|
||||
}
|
||||
));
|
||||
|
@ -49,7 +49,7 @@ pub fn codegen(app: &App, extra: &Extra) -> Vec<TokenStream2> {
|
|||
|
||||
items.push(quote!(
|
||||
#(#cfgs)*
|
||||
unsafe fn #schedule(
|
||||
pub unsafe fn #schedule(
|
||||
priority: &rtic::export::Priority,
|
||||
instant: #instant
|
||||
#(,#args)*
|
||||
|
@ -62,7 +62,7 @@ pub fn codegen(app: &App, extra: &Extra) -> Vec<TokenStream2> {
|
|||
methods.push(quote!(
|
||||
#(#cfgs)*
|
||||
#[inline(always)]
|
||||
fn #name(&self, instant: #instant #(,#args)*) -> Result<(), #ty> {
|
||||
pub fn #name(&self, instant: #instant #(,#args)*) -> Result<(), #ty> {
|
||||
unsafe {
|
||||
#schedule(self.priority(), instant #(,#untupled)*)
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use proc_macro2::TokenStream as TokenStream2;
|
||||
use quote::quote;
|
||||
use quote::{format_ident, quote};
|
||||
use rtic_syntax::{ast::App, Context};
|
||||
|
||||
use crate::{
|
||||
|
@ -13,7 +13,7 @@ pub fn codegen(
|
|||
analysis: &Analysis,
|
||||
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>,
|
||||
// root_software_tasks -- items that must be placed in the root of the crate:
|
||||
// - `${task}Locals` structs
|
||||
|
@ -22,10 +22,13 @@ pub fn codegen(
|
|||
Vec<TokenStream2>,
|
||||
// user_software_tasks -- the `#[task]` functions written by the user
|
||||
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 user_tasks = vec![];
|
||||
let mut software_tasks_imports = vec![];
|
||||
|
||||
for (name, task) in &app.software_tasks {
|
||||
let inputs = &task.inputs;
|
||||
|
@ -48,7 +51,7 @@ pub fn codegen(
|
|||
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
|
||||
/// the following buffers
|
||||
static mut #fq: #fq_ty = #fq_expr;
|
||||
|
@ -56,13 +59,13 @@ pub fn codegen(
|
|||
|
||||
// Generate a resource proxy if needed
|
||||
if let Some(ceiling) = ceiling {
|
||||
const_app.push(quote!(
|
||||
mod_app.push(quote!(
|
||||
struct #fq<'a> {
|
||||
priority: &'a rtic::export::Priority,
|
||||
}
|
||||
));
|
||||
|
||||
const_app.push(util::impl_mutex(
|
||||
mod_app.push(util::impl_mutex(
|
||||
extra,
|
||||
&[],
|
||||
false,
|
||||
|
@ -82,7 +85,7 @@ pub fn codegen(
|
|||
let instants = util::instants_ident(name);
|
||||
|
||||
let uninit = mk_uninit();
|
||||
const_app.push(quote!(
|
||||
mod_app.push(quote!(
|
||||
#uninit
|
||||
/// Buffer that holds the instants associated to the inputs of a task
|
||||
static mut #instants:
|
||||
|
@ -93,7 +96,7 @@ pub fn codegen(
|
|||
|
||||
let uninit = mk_uninit();
|
||||
let inputs = util::inputs_ident(name);
|
||||
const_app.push(quote!(
|
||||
mod_app.push(quote!(
|
||||
#uninit
|
||||
/// Buffer that holds the inputs of a task
|
||||
static mut #inputs: [core::mem::MaybeUninit<#input_ty>; #cap_lit] =
|
||||
|
@ -112,9 +115,16 @@ pub fn codegen(
|
|||
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);
|
||||
|
||||
const_app.push(constructor);
|
||||
mod_app.push(constructor);
|
||||
}
|
||||
|
||||
// `${task}Locals`
|
||||
|
@ -135,12 +145,17 @@ pub fn codegen(
|
|||
#(#attrs)*
|
||||
#(#cfgs)*
|
||||
#[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 _;
|
||||
|
||||
#(#stmts)*
|
||||
}
|
||||
));
|
||||
software_tasks_imports.push(quote!(
|
||||
#(#cfgs)*
|
||||
#[allow(non_snake_case)]
|
||||
use super::#name;
|
||||
));
|
||||
|
||||
root.push(module::codegen(
|
||||
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!(
|
||||
#(#cfgs)*
|
||||
fn #name(&self #(,#args)*) -> Result<(), #ty> {
|
||||
pub fn #name(&self #(,#args)*) -> Result<(), #ty> {
|
||||
#let_instant
|
||||
#body
|
||||
}
|
||||
|
@ -92,7 +92,7 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream
|
|||
methods.push(quote!(
|
||||
#(#cfgs)*
|
||||
#[inline(always)]
|
||||
fn #name(&self #(,#args)*) -> Result<(), #ty> {
|
||||
pub fn #name(&self #(,#args)*) -> Result<(), #ty> {
|
||||
unsafe {
|
||||
#let_instant
|
||||
#spawn(self.priority() #instant #(,#untupled)*)
|
||||
|
|
|
@ -15,8 +15,7 @@ mod tests;
|
|||
|
||||
/// Attribute used to declare a RTIC application
|
||||
///
|
||||
/// This attribute must be applied to a `const` item of type `()`. The `const` item is effectively
|
||||
/// used as a `mod` item: its value must be a block that contains items commonly found in modules,
|
||||
/// This attribute must be applied to a module block that contains items commonly found in modules,
|
||||
/// like functions and `static` variables.
|
||||
///
|
||||
/// The `app` attribute has one mandatory argument:
|
||||
|
@ -34,9 +33,10 @@ mod tests;
|
|||
/// - `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.
|
||||
///
|
||||
/// 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
|
||||
/// 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(
|
||||
quote!(device = pac),
|
||||
quote!(
|
||||
const APP: () = {
|
||||
mod app {
|
||||
#[task(priority = 1)]
|
||||
fn a(_: a::Context) {}
|
||||
|
||||
|
@ -20,7 +20,7 @@ fn analyze() {
|
|||
fn B();
|
||||
fn A();
|
||||
}
|
||||
};
|
||||
}
|
||||
),
|
||||
settings,
|
||||
)
|
||||
|
|
|
@ -4,6 +4,7 @@ use core::{
|
|||
};
|
||||
|
||||
pub use crate::tq::{NotReady, TimerQueue};
|
||||
pub use bare_metal::CriticalSection;
|
||||
#[cfg(armv7m)]
|
||||
pub use cortex_m::register::basepri;
|
||||
pub use cortex_m::{
|
||||
|
@ -15,8 +16,6 @@ pub use cortex_m::{
|
|||
use heapless::spsc::SingleCore;
|
||||
pub use heapless::{consts, i::Queue as iQueue, spsc::Queue};
|
||||
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 SCRQ<T, N> = Queue<(T, u8), N, u8, SingleCore>;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#![no_main]
|
||||
|
||||
#[rtic::app(device = lm3s6965)]
|
||||
const APP: () = {
|
||||
mod app {
|
||||
#[task(binds = NonMaskableInt)]
|
||||
fn nmi(_: nmi::Context) {}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
#![no_main]
|
||||
|
||||
#[rtic::app(device = lm3s6965)]
|
||||
const APP: () = {
|
||||
mod app {
|
||||
#[task(binds = SysTick)]
|
||||
fn sys_tick(_: sys_tick::Context) {}
|
||||
|
||||
#[task(schedule = [foo])]
|
||||
fn foo(_: foo::Context) {}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#![no_main]
|
||||
|
||||
#[rtic::app(device = lm3s6965)]
|
||||
const APP: () = {
|
||||
mod app {
|
||||
#[task]
|
||||
fn a(_: a::Context) {}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
#![no_main]
|
||||
|
||||
#[rtic::app(device = lm3s6965)]
|
||||
const APP: () = {
|
||||
mod app {
|
||||
#[task(binds = UART0)]
|
||||
fn a(_: a::Context) {}
|
||||
|
||||
extern "C" {
|
||||
fn UART0();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
#![no_main]
|
||||
use panic_halt as _;
|
||||
|
||||
#[rtic::app(device = lm3s6965)]
|
||||
const APP: () = {
|
||||
mod app {
|
||||
#[init]
|
||||
fn init(_: init::Context) -> init::LateResources {
|
||||
#[cfg(never)]
|
||||
|
@ -49,4 +50,4 @@ const APP: () = {
|
|||
extern "C" {
|
||||
fn UART1();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,37 +1,41 @@
|
|||
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
|
||||
|
||||
error[E0425]: cannot find value `FOO` in this scope
|
||||
--> $DIR/locals-cfg.rs:20:9
|
||||
--> $DIR/locals-cfg.rs:21:9
|
||||
|
|
||||
20 | FOO;
|
||||
21 | FOO;
|
||||
| ^^^ not found in this scope
|
||||
|
||||
error[E0425]: cannot find value `FOO` in this scope
|
||||
--> $DIR/locals-cfg.rs:30:9
|
||||
--> $DIR/locals-cfg.rs:31:9
|
||||
|
|
||||
30 | FOO;
|
||||
31 | FOO;
|
||||
| ^^^ not found in this scope
|
||||
|
||||
error[E0425]: cannot find value `FOO` in this scope
|
||||
--> $DIR/locals-cfg.rs:38:9
|
||||
--> $DIR/locals-cfg.rs:39:9
|
||||
|
|
||||
38 | FOO;
|
||||
39 | FOO;
|
||||
| ^^^ not found in this scope
|
||||
|
||||
error[E0425]: cannot find value `FOO` in this scope
|
||||
--> $DIR/locals-cfg.rs:46:9
|
||||
--> $DIR/locals-cfg.rs:47:9
|
||||
|
|
||||
46 | FOO;
|
||||
47 | FOO;
|
||||
| ^^^ 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/.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`.
|
||||
|
|
||||
= 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]
|
||||
use panic_halt as _;
|
||||
|
||||
#[rtic::app(device = lm3s6965)]
|
||||
const APP: () = {
|
||||
mod app {
|
||||
#[resources]
|
||||
struct Resources {
|
||||
#[cfg(never)]
|
||||
#[init(0)]
|
||||
|
@ -74,4 +76,4 @@ const APP: () = {
|
|||
c.resources.s2;
|
||||
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<'_>`
|
||||
--> $DIR/resources-cfg.rs:45:21
|
||||
--> $DIR/resources-cfg.rs:47:21
|
||||
|
|
||||
45 | c.resources.o1;
|
||||
47 | c.resources.o1;
|
||||
| ^^ unknown field
|
||||
|
|
||||
= note: available fields are: `__marker__`
|
||||
|
||||
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
|
||||
|
|
||||
= note: available fields are: `__marker__`
|
||||
|
||||
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
|
||||
|
|
||||
= note: available fields are: `__marker__`
|
||||
|
||||
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
|
||||
|
|
||||
= note: available fields are: `__marker__`
|
||||
|
||||
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
|
||||
|
|
||||
= note: available fields are: `__marker__`
|
||||
|
||||
error[E0609]: no field `o2` on type `idleResources<'_>`
|
||||
--> $DIR/resources-cfg.rs:56:21
|
||||
--> $DIR/resources-cfg.rs:58:21
|
||||
|
|
||||
56 | c.resources.o2;
|
||||
58 | c.resources.o2;
|
||||
| ^^ unknown field
|
||||
|
|
||||
= note: available fields are: `__marker__`
|
||||
|
||||
error[E0609]: no field `o4` on type `idleResources<'_>`
|
||||
--> $DIR/resources-cfg.rs:57:21
|
||||
--> $DIR/resources-cfg.rs:59:21
|
||||
|
|
||||
57 | c.resources.o4;
|
||||
59 | c.resources.o4;
|
||||
| ^^ unknown field
|
||||
|
|
||||
= note: available fields are: `__marker__`
|
||||
|
||||
error[E0609]: no field `s1` on type `idleResources<'_>`
|
||||
--> $DIR/resources-cfg.rs:58:21
|
||||
--> $DIR/resources-cfg.rs:60:21
|
||||
|
|
||||
58 | c.resources.s1;
|
||||
60 | c.resources.s1;
|
||||
| ^^ unknown field
|
||||
|
|
||||
= note: available fields are: `__marker__`
|
||||
|
||||
error[E0609]: no field `s3` on type `idleResources<'_>`
|
||||
--> $DIR/resources-cfg.rs:59:21
|
||||
--> $DIR/resources-cfg.rs:61:21
|
||||
|
|
||||
59 | c.resources.s3;
|
||||
61 | c.resources.s3;
|
||||
| ^^ unknown field
|
||||
|
|
||||
= note: available fields are: `__marker__`
|
||||
|
||||
error[E0609]: no field `o3` on type `uart0Resources<'_>`
|
||||
--> $DIR/resources-cfg.rs:66:21
|
||||
--> $DIR/resources-cfg.rs:68:21
|
||||
|
|
||||
66 | c.resources.o3;
|
||||
68 | c.resources.o3;
|
||||
| ^^ unknown field
|
||||
|
|
||||
= note: available fields are: `__marker__`
|
||||
|
||||
error[E0609]: no field `s1` on type `uart0Resources<'_>`
|
||||
--> $DIR/resources-cfg.rs:67:21
|
||||
--> $DIR/resources-cfg.rs:69:21
|
||||
|
|
||||
67 | c.resources.s1;
|
||||
69 | c.resources.s1;
|
||||
| ^^ unknown field
|
||||
|
|
||||
= note: available fields are: `__marker__`
|
||||
|
||||
error[E0609]: no field `s2` on type `uart0Resources<'_>`
|
||||
--> $DIR/resources-cfg.rs:68:21
|
||||
--> $DIR/resources-cfg.rs:70:21
|
||||
|
|
||||
68 | c.resources.s2;
|
||||
70 | c.resources.s2;
|
||||
| ^^ unknown field
|
||||
|
|
||||
= note: available fields are: `__marker__`
|
||||
|
||||
error[E0609]: no field `s3` on type `uart0Resources<'_>`
|
||||
--> $DIR/resources-cfg.rs:69:21
|
||||
--> $DIR/resources-cfg.rs:71:21
|
||||
|
|
||||
69 | c.resources.s3;
|
||||
71 | c.resources.s3;
|
||||
| ^^ unknown field
|
||||
|
|
||||
= note: available fields are: `__marker__`
|
||||
|
||||
error[E0609]: no field `s2` on type `uart1Resources<'_>`
|
||||
--> $DIR/resources-cfg.rs:74:21
|
||||
--> $DIR/resources-cfg.rs:76:21
|
||||
|
|
||||
74 | c.resources.s2;
|
||||
76 | c.resources.s2;
|
||||
| ^^ unknown field
|
||||
|
|
||||
= note: available fields are: `__marker__`
|
||||
|
||||
error[E0609]: no field `o5` on type `uart1Resources<'_>`
|
||||
--> $DIR/resources-cfg.rs:75:21
|
||||
--> $DIR/resources-cfg.rs:77:21
|
||||
|
|
||||
75 | c.resources.o5;
|
||||
77 | c.resources.o5;
|
||||
| ^^ unknown field
|
||||
|
|
||||
= note: available fields are: `__marker__`
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
#![no_main]
|
||||
|
||||
use rtic::app;
|
||||
|
||||
#[rtic::app(device = lm3s6965)]
|
||||
const APP: () = {
|
||||
mod app {
|
||||
#[init]
|
||||
fn init(_: init::Context) -> init::LateResources {
|
||||
init::LateResources {}
|
||||
|
@ -37,4 +35,4 @@ const APP: () = {
|
|||
// this value is too high!
|
||||
#[task(binds = I2C0, priority = 9)]
|
||||
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
|
||||
--> $DIR/task-priority-too-high.rs:5:1
|
||||
--> $DIR/task-priority-too-high.rs:3:1
|
||||
|
|
||||
5 | #[rtic::app(device = lm3s6965)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to subtract with overflow
|
||||
3 | #[rtic::app(device = lm3s6965)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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