mirror of
https://github.com/rtic-rs/rtic.git
synced 2024-12-24 19:09:33 +01:00
Merge #176
176: implement RFCs 147 and 155, fix #141, etc. r=japaric a=japaric This PR: - Implements RFC 147: "all functions must be safe" - Implements RFC 155: "explicit Context parameter" - Implements the pending breaking change #141: reject assign syntax in `init` (which was used to initialize late resources) - Refactors code generation to make it more readable -- there are no more random identifiers in the output -- and align it with the book description of RTFM internals (see PR #175). - Makes the framework hard depend on `core::mem::MaybeUninit` and thus will require nightly until that API is stabilized. - Fixes a ceiling analysis bug where the priority of the system timer was not considered in the analysis (TODO backport this into the v0.4.x branch). - Shrinks the size of all the internal queues by turning `AtomicUsize` indices into `AtomicU8`s. - Removes the integration with `owned_singleton`. closes #141 closes #147 closes #155 Additionally: - This changes CI to push v0.5.x docs to https://japaric.github.io/rtfm5/book/en/ -- we need to do this because our official docs are hosted on https://japaric.github.io/cortex-m-rtfm and we need to keep them on v0.4.x until we release v0.5.0 - I propose that we use the master branch to develop the upcoming v0.5.0. - I have created a branch v0.4.x for backports; new v0.4.x releases will come from that branch. r? @korken89 @texitoi, sorry for doing all the impl work in a single commit -- I know that makes things harder to review for you. Suggestions for compile-pass and compile-fail tests are welcome Co-authored-by: Jorge Aparicio <jorge@japaric.io>
This commit is contained in:
commit
bc024f1979
97 changed files with 3090 additions and 3012 deletions
12
.travis.yml
12
.travis.yml
|
@ -3,17 +3,17 @@ language: rust
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
# NOTE used to build docs on successful merges to master
|
# NOTE used to build docs on successful merges to master
|
||||||
- env: TARGET=x86_64-unknown-linux-gnu
|
# - env: TARGET=x86_64-unknown-linux-gnu
|
||||||
|
|
||||||
- env: TARGET=thumbv6m-none-eabi
|
# - env: TARGET=thumbv6m-none-eabi
|
||||||
if: (branch = staging OR branch = trying) OR (type = pull_request AND branch = master)
|
# if: (branch = staging OR branch = trying) OR (type = pull_request AND branch = master)
|
||||||
|
|
||||||
- env: TARGET=thumbv7m-none-eabi
|
# - env: TARGET=thumbv7m-none-eabi
|
||||||
if: (branch = staging OR branch = trying) OR (type = pull_request AND branch = master)
|
# if: (branch = staging OR branch = trying) OR (type = pull_request AND branch = master)
|
||||||
|
|
||||||
- env: TARGET=x86_64-unknown-linux-gnu
|
- env: TARGET=x86_64-unknown-linux-gnu
|
||||||
rust: nightly
|
rust: nightly
|
||||||
if: (branch = staging OR branch = trying) OR (type = pull_request AND branch = master)
|
# if: (branch = staging OR branch = trying) OR (type = pull_request AND branch = master)
|
||||||
|
|
||||||
- env: TARGET=thumbv6m-none-eabi
|
- env: TARGET=thumbv6m-none-eabi
|
||||||
rust: nightly
|
rust: nightly
|
||||||
|
|
29
CHANGELOG.md
29
CHANGELOG.md
|
@ -5,6 +5,35 @@ This project adheres to [Semantic Versioning](http://semver.org/).
|
||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
## v0.5.0 - 2019-??-?? (ALPHA pre-release)
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- [breaking-change][] [RFC 155] "explicit `Context` parameter" has been
|
||||||
|
implemented.
|
||||||
|
|
||||||
|
[RFC 155]: https://github.com/japaric/cortex-m-rtfm/issues/155
|
||||||
|
|
||||||
|
- [breaking-change][] [RFC 147] "all functions must be safe" has been
|
||||||
|
implemented.
|
||||||
|
|
||||||
|
[RFC 147]: https://github.com/japaric/cortex-m-rtfm/issues/147
|
||||||
|
|
||||||
|
- All the queues internally used by the framework now use `AtomicU8` indices
|
||||||
|
instead of `AtomicUsize`; this reduces the static memory used by the
|
||||||
|
framework.
|
||||||
|
|
||||||
|
### Removed
|
||||||
|
|
||||||
|
- [breaking-change] the integration with the `owned_singleton` crate has been
|
||||||
|
removed. You can use `heapless::Pool` instead of `alloc_singleton`.
|
||||||
|
|
||||||
|
- [breaking-change] late resources can no longer be initialized using the assign
|
||||||
|
syntax. `init::LateResources` is the only method to initialize late resources.
|
||||||
|
See [PR #140] for more details.
|
||||||
|
|
||||||
|
[PR #140]: https://github.com/japaric/cortex-m-rtfm/pull/140
|
||||||
|
|
||||||
## [v0.4.3] - 2019-04-21
|
## [v0.4.3] - 2019-04-21
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
17
Cargo.toml
17
Cargo.toml
|
@ -12,7 +12,7 @@ license = "MIT OR Apache-2.0"
|
||||||
name = "cortex-m-rtfm"
|
name = "cortex-m-rtfm"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
repository = "https://github.com/japaric/cortex-m-rtfm"
|
repository = "https://github.com/japaric/cortex-m-rtfm"
|
||||||
version = "0.4.3"
|
version = "0.5.0-alpha.1"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
name = "rtfm"
|
name = "rtfm"
|
||||||
|
@ -25,6 +25,12 @@ required-features = ["timer-queue"]
|
||||||
name = "periodic"
|
name = "periodic"
|
||||||
required-features = ["timer-queue"]
|
required-features = ["timer-queue"]
|
||||||
|
|
||||||
|
[[example]]
|
||||||
|
name = "pool"
|
||||||
|
# this example doesn't need this feature but only works on ARMv7-M
|
||||||
|
# specifying the feature here avoids compiling this for ARMv6-M
|
||||||
|
required-features = ["timer-queue"]
|
||||||
|
|
||||||
[[example]]
|
[[example]]
|
||||||
name = "schedule"
|
name = "schedule"
|
||||||
required-features = ["timer-queue"]
|
required-features = ["timer-queue"]
|
||||||
|
@ -36,12 +42,13 @@ required-features = ["timer-queue"]
|
||||||
[dependencies]
|
[dependencies]
|
||||||
cortex-m = "0.5.8"
|
cortex-m = "0.5.8"
|
||||||
cortex-m-rt = "0.6.7"
|
cortex-m-rt = "0.6.7"
|
||||||
cortex-m-rtfm-macros = { path = "macros", version = "0.4.3" }
|
cortex-m-rtfm-macros = { path = "macros", version = "0.5.0-alpha.1" }
|
||||||
heapless = "0.4.1"
|
|
||||||
owned-singleton = "0.1.0"
|
[dependencies.heapless]
|
||||||
|
features = ["smaller-atomics", "min-const-fn"]
|
||||||
|
version = "0.4.3"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
alloc-singleton = "0.1.0"
|
|
||||||
cortex-m-semihosting = "0.3.2"
|
cortex-m-semihosting = "0.3.2"
|
||||||
lm3s6965 = "0.1.3"
|
lm3s6965 = "0.1.3"
|
||||||
panic-halt = "0.2.0"
|
panic-halt = "0.2.0"
|
||||||
|
|
|
@ -41,13 +41,13 @@ A concurrency framework for building real time systems.
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
- Rust 1.31.0+
|
- Rust 1.36.0+
|
||||||
|
|
||||||
- Applications must be written using the 2018 edition.
|
- Applications must be written using the 2018 edition.
|
||||||
|
|
||||||
## [User documentation](https://japaric.github.io/cortex-m-rtfm/book/en)
|
## [User documentation](https://japaric.github.io/rtfm5/book/en)
|
||||||
|
|
||||||
## [API reference](https://japaric.github.io/cortex-m-rtfm/api/rtfm/index.html)
|
## [API reference](https://japaric.github.io/rtfm5/api/rtfm/index.html)
|
||||||
|
|
||||||
## Acknowledgments
|
## Acknowledgments
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
- [Resources](./by-example/resources.md)
|
- [Resources](./by-example/resources.md)
|
||||||
- [Tasks](./by-example/tasks.md)
|
- [Tasks](./by-example/tasks.md)
|
||||||
- [Timer queue](./by-example/timer-queue.md)
|
- [Timer queue](./by-example/timer-queue.md)
|
||||||
- [Singletons](./by-example/singletons.md)
|
|
||||||
- [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)
|
||||||
|
|
|
@ -28,15 +28,14 @@ not required to use the [`cortex_m_rt::entry`] attribute.
|
||||||
|
|
||||||
Within the pseudo-module the `app` attribute expects to find an initialization
|
Within the pseudo-module the `app` 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
|
||||||
`[unsafe] fn()`.
|
`fn(init::Context) [-> init::LateResources]`.
|
||||||
|
|
||||||
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 device specific peripherals through the `core` and `device`
|
to Cortex-M and device specific peripherals through the `core` and `device`
|
||||||
variables, which are injected in the scope of `init` by the `app` attribute. Not
|
variables fields of `init::Context`. Not all Cortex-M peripherals are available
|
||||||
all Cortex-M peripherals are available in `core` because the RTFM runtime takes
|
in `core` because the RTFM runtime takes ownership of some of them -- for more
|
||||||
ownership of some of them -- for more details see the [`rtfm::Peripherals`]
|
details see the [`rtfm::Peripherals`] struct.
|
||||||
struct.
|
|
||||||
|
|
||||||
`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.
|
||||||
|
@ -61,7 +60,7 @@ $ cargo run --example init
|
||||||
|
|
||||||
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
|
pseudo-module. This function is used as the special *idle task* and must have
|
||||||
signature `[unsafe] fn() - > !`.
|
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
|
||||||
`init`, `idle` will run *with interrupts enabled* and it's not allowed to return
|
`init`, `idle` will run *with interrupts enabled* and it's not allowed to return
|
||||||
|
|
|
@ -40,7 +40,7 @@ $ rm memory.x build.rs
|
||||||
`timer-queue` feature.
|
`timer-queue` feature.
|
||||||
|
|
||||||
``` console
|
``` console
|
||||||
$ cargo add cortex-m-rtfm
|
$ cargo add cortex-m-rtfm --allow-prerelease
|
||||||
```
|
```
|
||||||
|
|
||||||
4. Write your RTFM application.
|
4. Write your RTFM application.
|
||||||
|
@ -49,7 +49,7 @@ Here I'll use the `init` example from the `cortex-m-rtfm` crate.
|
||||||
|
|
||||||
``` console
|
``` console
|
||||||
$ curl \
|
$ curl \
|
||||||
-L https://github.com/japaric/cortex-m-rtfm/raw/v0.4.0/examples/init.rs \
|
-L https://github.com/japaric/cortex-m-rtfm/raw/v0.5.0-alpha.1/examples/init.rs \
|
||||||
> src/main.rs
|
> src/main.rs
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ have enough information to optimize the access to the shared data.
|
||||||
The `app` attribute has a full view of the application thus it can optimize
|
The `app` attribute has a full view of the application thus it can optimize
|
||||||
access to `static` variables. In RTFM we refer to the `static` variables
|
access to `static` variables. In RTFM we refer to the `static` variables
|
||||||
declared inside the `app` pseudo-module as *resources*. To access a resource the
|
declared inside the `app` pseudo-module as *resources*. To access a resource the
|
||||||
context (`init`, `idle`, `interrupt` or `exception`) must first declare the
|
context (`init`, `idle`, `interrupt` or `exception`) one must first declare the
|
||||||
resource in the `resources` argument of its attribute.
|
resource in the `resources` argument of its attribute.
|
||||||
|
|
||||||
In the example below two interrupt handlers access the same resource. No `Mutex`
|
In the example below two interrupt handlers access the same resource. No `Mutex`
|
||||||
|
@ -30,7 +30,7 @@ $ cargo run --example resource
|
||||||
|
|
||||||
The priority of each handler can be declared in the `interrupt` and `exception`
|
The priority of each handler can be declared in the `interrupt` and `exception`
|
||||||
attributes. It's not possible to set the priority in any other way because the
|
attributes. It's not possible to set the priority in any other way because the
|
||||||
runtime takes ownership of the `NVIC` peripheral; it's also not possible to
|
runtime takes ownership of the `NVIC` peripheral thus it's also not possible to
|
||||||
change the priority of a handler / task at runtime. Thanks to this restriction
|
change the priority of a handler / task at runtime. Thanks to this restriction
|
||||||
the framework has knowledge about the *static* priorities of all interrupt and
|
the framework has knowledge about the *static* priorities of all interrupt and
|
||||||
exception handlers.
|
exception handlers.
|
||||||
|
@ -71,10 +71,10 @@ $ cargo run --example lock
|
||||||
|
|
||||||
One more note about priorities: choosing a priority higher than what the device
|
One more note about priorities: choosing a priority higher than what the device
|
||||||
supports (that is `1 << NVIC_PRIO_BITS`) will result in a compile error. Due to
|
supports (that is `1 << NVIC_PRIO_BITS`) will result in a compile error. Due to
|
||||||
limitations in the language the error is currently far from helpful: it will say
|
limitations in the language the error message is currently far from helpful: it
|
||||||
something along the lines of "evaluation of constant value failed" and the span
|
will say something along the lines of "evaluation of constant value failed" and
|
||||||
of the error will *not* point out to the problematic interrupt value -- we are
|
the span of the error will *not* point out to the problematic interrupt value --
|
||||||
sorry about this!
|
we are sorry about this!
|
||||||
|
|
||||||
## Late resources
|
## Late resources
|
||||||
|
|
||||||
|
|
|
@ -1,26 +0,0 @@
|
||||||
# Singletons
|
|
||||||
|
|
||||||
The `app` attribute is aware of [`owned-singleton`] crate and its [`Singleton`]
|
|
||||||
attribute. When this attribute is applied to one of the resources the runtime
|
|
||||||
will perform the `unsafe` initialization of the singleton for you, ensuring that
|
|
||||||
only a single instance of the singleton is ever created.
|
|
||||||
|
|
||||||
[`owned-singleton`]: ../../api/owned_singleton/index.html
|
|
||||||
[`Singleton`]: ../../api/owned_singleton_macros/attr.Singleton.html
|
|
||||||
|
|
||||||
Note that when using the `Singleton` attribute you'll need to have the
|
|
||||||
`owned_singleton` in your dependencies.
|
|
||||||
|
|
||||||
Below is an example that uses the `Singleton` attribute on a chunk of memory
|
|
||||||
and then uses the singleton instance as a fixed-size memory pool using one of
|
|
||||||
the [`alloc-singleton`] abstractions.
|
|
||||||
|
|
||||||
[`alloc-singleton`]: https://crates.io/crates/alloc-singleton
|
|
||||||
|
|
||||||
``` rust
|
|
||||||
{{#include ../../../../examples/singleton.rs}}
|
|
||||||
```
|
|
||||||
|
|
||||||
``` console
|
|
||||||
$ cargo run --example singleton
|
|
||||||
{{#include ../../../../ci/expected/singleton.run}}```
|
|
|
@ -24,8 +24,8 @@ of tasks.
|
||||||
|
|
||||||
You can use conditional compilation (`#[cfg]`) on resources (`static [mut]`
|
You can use conditional compilation (`#[cfg]`) on resources (`static [mut]`
|
||||||
items) and tasks (`fn` items). The effect of using `#[cfg]` attributes is that
|
items) and tasks (`fn` items). The effect of using `#[cfg]` attributes is that
|
||||||
the resource / task will *not* be injected into the prelude of tasks that use
|
the resource / task will *not* be available through the corresponding `Context`
|
||||||
them (see `resources`, `spawn` and `schedule`) if the condition doesn't hold.
|
`struct` if the condition doesn't hold.
|
||||||
|
|
||||||
The example below logs a message whenever the `foo` task is spawned, but only if
|
The example below logs a message whenever the `foo` task is spawned, but only if
|
||||||
the program has been compiled using the `dev` profile.
|
the program has been compiled using the `dev` profile.
|
||||||
|
@ -37,7 +37,7 @@ the program has been compiled using the `dev` profile.
|
||||||
## Running tasks from RAM
|
## Running tasks from RAM
|
||||||
|
|
||||||
The main goal of moving the specification of RTFM applications to attributes in
|
The main goal of moving the specification of RTFM applications to attributes in
|
||||||
RTFM v0.4.x was to allow inter-operation with other attributes. For example, the
|
RTFM v0.4.0 was to allow inter-operation with other attributes. For example, the
|
||||||
`link_section` attribute can be applied to tasks to place them in RAM; this can
|
`link_section` attribute can be applied to tasks to place them in RAM; this can
|
||||||
improve performance in some cases.
|
improve performance in some cases.
|
||||||
|
|
||||||
|
@ -78,8 +78,6 @@ $ cargo nm --example ramfunc --release | grep ' bar::'
|
||||||
|
|
||||||
## `binds`
|
## `binds`
|
||||||
|
|
||||||
**NOTE**: Requires RTFM ~0.4.2
|
|
||||||
|
|
||||||
You can give hardware tasks more task-like names using the `binds` argument: you
|
You can give hardware tasks more task-like names using the `binds` argument: you
|
||||||
name the function as you wish and specify the name of the interrupt / exception
|
name the function as you wish and specify the name of the interrupt / exception
|
||||||
in the `binds` argument. Types like `Spawn` will be placed in a module named
|
in the `binds` argument. Types like `Spawn` will be placed in a module named
|
||||||
|
@ -91,3 +89,27 @@ after the function, not the interrupt / exception. Example below:
|
||||||
``` console
|
``` console
|
||||||
$ cargo run --example binds
|
$ cargo run --example binds
|
||||||
{{#include ../../../../ci/expected/binds.run}}```
|
{{#include ../../../../ci/expected/binds.run}}```
|
||||||
|
|
||||||
|
## Indirection for faster message passing
|
||||||
|
|
||||||
|
Message passing always involves copying the payload from the sender into a
|
||||||
|
static variable and then from the static variable into the receiver. Thus
|
||||||
|
sending a large buffer, like a `[u8; 128]`, as a message involves two expensive
|
||||||
|
`memcpy`s. To minimize the message passing overhead one can use indirection:
|
||||||
|
instead of sending the buffer by value, one can send an owning pointer into the
|
||||||
|
buffer.
|
||||||
|
|
||||||
|
One can use a global allocator to achieve indirection (`alloc::Box`,
|
||||||
|
`alloc::Rc`, etc.), which requires using the nightly channel as of Rust v1.34.0,
|
||||||
|
or one can use a statically allocated memory pool like [`heapless::Pool`].
|
||||||
|
|
||||||
|
[`heapless::Pool`]: https://docs.rs/heapless/0.4.3/heapless/pool/index.html
|
||||||
|
|
||||||
|
Here's an example where `heapless::Pool` is used to "box" buffers of 128 bytes.
|
||||||
|
|
||||||
|
``` rust
|
||||||
|
{{#include ../../../../examples/pool.rs}}
|
||||||
|
```
|
||||||
|
``` console
|
||||||
|
$ cargo run --example binds
|
||||||
|
{{#include ../../../../ci/expected/pool.run}}```
|
||||||
|
|
|
@ -7,8 +7,7 @@ write plain functions that take them as arguments.
|
||||||
The API reference specifies how these types are generated from the input. You
|
The API reference specifies how these types are generated from the input. You
|
||||||
can also generate documentation for you binary crate (`cargo doc --bin <name>`);
|
can also generate documentation for you binary crate (`cargo doc --bin <name>`);
|
||||||
in the documentation you'll find `Context` structs (e.g. `init::Context` and
|
in the documentation you'll find `Context` structs (e.g. `init::Context` and
|
||||||
`idle::Context`) whose fields represent the variables injected into each
|
`idle::Context`).
|
||||||
function.
|
|
||||||
|
|
||||||
The example below shows the different types generates by the `app` attribute.
|
The example below shows the different types generates by the `app` attribute.
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,9 @@ There is a translation of this book in [Russian].
|
||||||
|
|
||||||
[Russian]: ../ru/index.html
|
[Russian]: ../ru/index.html
|
||||||
|
|
||||||
|
**HEADS UP** This is an **alpha** pre-release; there may be breaking changes in
|
||||||
|
the API and semantics before a proper release is made.
|
||||||
|
|
||||||
{{#include ../../../README.md:5:46}}
|
{{#include ../../../README.md:5:46}}
|
||||||
|
|
||||||
{{#include ../../../README.md:52:}}
|
{{#include ../../../README.md:52:}}
|
||||||
|
|
|
@ -23,7 +23,8 @@ main() {
|
||||||
./ghp-import/ghp_import.py $td
|
./ghp-import/ghp_import.py $td
|
||||||
|
|
||||||
set +x
|
set +x
|
||||||
git push -fq https://$GH_TOKEN@github.com/$TRAVIS_REPO_SLUG.git gh-pages && echo OK
|
# NOTE push documentation to a different repository
|
||||||
|
git push -fq https://$GH_TOKEN@github.com/japaric/rtfm5.git gh-pages && echo OK
|
||||||
|
|
||||||
rm -rf $td
|
rm -rf $td
|
||||||
}
|
}
|
||||||
|
|
2
ci/expected/pool.run
Normal file
2
ci/expected/pool.run
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
bar(0x2000008c)
|
||||||
|
foo(0x20000110)
|
36
ci/script.sh
36
ci/script.sh
|
@ -104,14 +104,13 @@ main() {
|
||||||
message
|
message
|
||||||
capacity
|
capacity
|
||||||
|
|
||||||
singleton
|
|
||||||
|
|
||||||
types
|
types
|
||||||
not-send
|
not-send
|
||||||
not-sync
|
not-sync
|
||||||
shared-with-init
|
shared-with-init
|
||||||
|
|
||||||
generics
|
generics
|
||||||
|
pool
|
||||||
ramfunc
|
ramfunc
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -121,6 +120,31 @@ main() {
|
||||||
continue
|
continue
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [ $ex = pool ]; then
|
||||||
|
if [ $TARGET != thumbv6m-none-eabi ]; then
|
||||||
|
local td=$(mktemp -d)
|
||||||
|
|
||||||
|
local features="$nightly,timer-queue"
|
||||||
|
cargo run --example $ex --target $TARGET --features $features >\
|
||||||
|
$td/pool.run
|
||||||
|
grep 'foo(0x2' $td/pool.run
|
||||||
|
grep 'bar(0x2' $td/pool.run
|
||||||
|
arm-none-eabi-objcopy -O ihex target/$TARGET/debug/examples/$ex \
|
||||||
|
ci/builds/${ex}_${features/,/_}_debug_1.hex
|
||||||
|
|
||||||
|
cargo run --example $ex --target $TARGET --features $features --release >\
|
||||||
|
$td/pool.run
|
||||||
|
grep 'foo(0x2' $td/pool.run
|
||||||
|
grep 'bar(0x2' $td/pool.run
|
||||||
|
arm-none-eabi-objcopy -O ihex target/$TARGET/release/examples/$ex \
|
||||||
|
ci/builds/${ex}_${features/,/_}_release_1.hex
|
||||||
|
|
||||||
|
rm -rf $td
|
||||||
|
fi
|
||||||
|
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
if [ $ex != types ]; then
|
if [ $ex != types ]; then
|
||||||
arm_example "run" $ex "debug" "$nightly" "1"
|
arm_example "run" $ex "debug" "$nightly" "1"
|
||||||
arm_example "run" $ex "release" "$nightly" "1"
|
arm_example "run" $ex "release" "$nightly" "1"
|
||||||
|
@ -140,13 +164,7 @@ main() {
|
||||||
continue
|
continue
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ $ex = singleton ]; then
|
if [ $ex != types ] && [ $ex != pool ]; then
|
||||||
# singleton build is currently not reproducible due to
|
|
||||||
# https://github.com/japaric/owned-singleton/issues/2
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ $ex != types ]; then
|
|
||||||
arm_example "build" $ex "debug" "$nightly" "2"
|
arm_example "build" $ex "debug" "$nightly" "2"
|
||||||
cmp ci/builds/${ex}_${nightly/nightly/nightly_}debug_1.hex \
|
cmp ci/builds/${ex}_${nightly/nightly/nightly_}debug_1.hex \
|
||||||
ci/builds/${ex}_${nightly/nightly/nightly_}debug_2.hex
|
ci/builds/${ex}_${nightly/nightly/nightly_}debug_2.hex
|
||||||
|
|
|
@ -9,24 +9,23 @@ extern crate panic_semihosting;
|
||||||
|
|
||||||
use cortex_m_semihosting::{debug, hprintln};
|
use cortex_m_semihosting::{debug, hprintln};
|
||||||
use lm3s6965::Interrupt;
|
use lm3s6965::Interrupt;
|
||||||
use rtfm::app;
|
|
||||||
|
|
||||||
// NOTE: does NOT properly work on QEMU
|
// NOTE: does NOT properly work on QEMU
|
||||||
#[app(device = lm3s6965)]
|
#[rtfm::app(device = lm3s6965)]
|
||||||
const APP: () = {
|
const APP: () = {
|
||||||
#[init(spawn = [foo])]
|
#[init(spawn = [foo])]
|
||||||
fn init() {
|
fn init(c: init::Context) {
|
||||||
hprintln!("init(baseline = {:?})", start).unwrap();
|
hprintln!("init(baseline = {:?})", c.start).unwrap();
|
||||||
|
|
||||||
// `foo` inherits the baseline of `init`: `Instant(0)`
|
// `foo` inherits the baseline of `init`: `Instant(0)`
|
||||||
spawn.foo().unwrap();
|
c.spawn.foo().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[task(schedule = [foo])]
|
#[task(schedule = [foo])]
|
||||||
fn foo() {
|
fn foo(c: foo::Context) {
|
||||||
static mut ONCE: bool = true;
|
static mut ONCE: bool = true;
|
||||||
|
|
||||||
hprintln!("foo(baseline = {:?})", scheduled).unwrap();
|
hprintln!("foo(baseline = {:?})", c.scheduled).unwrap();
|
||||||
|
|
||||||
if *ONCE {
|
if *ONCE {
|
||||||
*ONCE = false;
|
*ONCE = false;
|
||||||
|
@ -38,11 +37,11 @@ const APP: () = {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[interrupt(spawn = [foo])]
|
#[interrupt(spawn = [foo])]
|
||||||
fn UART0() {
|
fn UART0(c: UART0::Context) {
|
||||||
hprintln!("UART0(baseline = {:?})", start).unwrap();
|
hprintln!("UART0(baseline = {:?})", c.start).unwrap();
|
||||||
|
|
||||||
// `foo` inherits the baseline of `UART0`: its `start` time
|
// `foo` inherits the baseline of `UART0`: its `start` time
|
||||||
spawn.foo().unwrap();
|
c.spawn.foo().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
|
@ -9,20 +9,19 @@ extern crate panic_semihosting;
|
||||||
|
|
||||||
use cortex_m_semihosting::{debug, hprintln};
|
use cortex_m_semihosting::{debug, hprintln};
|
||||||
use lm3s6965::Interrupt;
|
use lm3s6965::Interrupt;
|
||||||
use rtfm::app;
|
|
||||||
|
|
||||||
// `examples/interrupt.rs` rewritten to use `binds`
|
// `examples/interrupt.rs` rewritten to use `binds`
|
||||||
#[app(device = lm3s6965)]
|
#[rtfm::app(device = lm3s6965)]
|
||||||
const APP: () = {
|
const APP: () = {
|
||||||
#[init]
|
#[init]
|
||||||
fn init() {
|
fn init(_: init::Context) {
|
||||||
rtfm::pend(Interrupt::UART0);
|
rtfm::pend(Interrupt::UART0);
|
||||||
|
|
||||||
hprintln!("init").unwrap();
|
hprintln!("init").unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[idle]
|
#[idle]
|
||||||
fn idle() -> ! {
|
fn idle(_: idle::Context) -> ! {
|
||||||
hprintln!("idle").unwrap();
|
hprintln!("idle").unwrap();
|
||||||
|
|
||||||
rtfm::pend(Interrupt::UART0);
|
rtfm::pend(Interrupt::UART0);
|
||||||
|
@ -33,7 +32,7 @@ const APP: () = {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[interrupt(binds = UART0)]
|
#[interrupt(binds = UART0)]
|
||||||
fn foo() {
|
fn foo(_: foo::Context) {
|
||||||
static mut TIMES: u32 = 0;
|
static mut TIMES: u32 = 0;
|
||||||
|
|
||||||
*TIMES += 1;
|
*TIMES += 1;
|
||||||
|
|
|
@ -9,32 +9,31 @@ extern crate panic_semihosting;
|
||||||
|
|
||||||
use cortex_m_semihosting::{debug, hprintln};
|
use cortex_m_semihosting::{debug, hprintln};
|
||||||
use lm3s6965::Interrupt;
|
use lm3s6965::Interrupt;
|
||||||
use rtfm::app;
|
|
||||||
|
|
||||||
#[app(device = lm3s6965)]
|
#[rtfm::app(device = lm3s6965)]
|
||||||
const APP: () = {
|
const APP: () = {
|
||||||
#[init]
|
#[init]
|
||||||
fn init() {
|
fn init(_: init::Context) {
|
||||||
rtfm::pend(Interrupt::UART0);
|
rtfm::pend(Interrupt::UART0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[interrupt(spawn = [foo, bar])]
|
#[interrupt(spawn = [foo, bar])]
|
||||||
fn UART0() {
|
fn UART0(c: UART0::Context) {
|
||||||
spawn.foo(0).unwrap();
|
c.spawn.foo(0).unwrap();
|
||||||
spawn.foo(1).unwrap();
|
c.spawn.foo(1).unwrap();
|
||||||
spawn.foo(2).unwrap();
|
c.spawn.foo(2).unwrap();
|
||||||
spawn.foo(3).unwrap();
|
c.spawn.foo(3).unwrap();
|
||||||
|
|
||||||
spawn.bar().unwrap();
|
c.spawn.bar().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[task(capacity = 4)]
|
#[task(capacity = 4)]
|
||||||
fn foo(x: u32) {
|
fn foo(_: foo::Context, x: u32) {
|
||||||
hprintln!("foo({})", x).unwrap();
|
hprintln!("foo({})", x).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[task]
|
#[task]
|
||||||
fn bar() {
|
fn bar(_: bar::Context) {
|
||||||
hprintln!("bar").unwrap();
|
hprintln!("bar").unwrap();
|
||||||
|
|
||||||
debug::exit(debug::EXIT_SUCCESS);
|
debug::exit(debug::EXIT_SUCCESS);
|
||||||
|
|
|
@ -9,25 +9,24 @@ extern crate panic_semihosting;
|
||||||
|
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
use cortex_m_semihosting::hprintln;
|
use cortex_m_semihosting::hprintln;
|
||||||
use rtfm::app;
|
|
||||||
|
|
||||||
#[app(device = lm3s6965)]
|
#[rtfm::app(device = lm3s6965)]
|
||||||
const APP: () = {
|
const APP: () = {
|
||||||
#[cfg(debug_assertions)] // <- `true` when using the `dev` profile
|
#[cfg(debug_assertions)] // <- `true` when using the `dev` profile
|
||||||
static mut COUNT: u32 = 0;
|
static mut COUNT: u32 = 0;
|
||||||
|
|
||||||
#[init]
|
#[init]
|
||||||
fn init() {
|
fn init(_: init::Context) {
|
||||||
// ..
|
// ..
|
||||||
}
|
}
|
||||||
|
|
||||||
#[task(priority = 3, resources = [COUNT], spawn = [log])]
|
#[task(priority = 3, resources = [COUNT], spawn = [log])]
|
||||||
fn foo() {
|
fn foo(c: foo::Context) {
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
{
|
{
|
||||||
*resources.COUNT += 1;
|
*c.resources.COUNT += 1;
|
||||||
|
|
||||||
spawn.log(*resources.COUNT).ok();
|
c.spawn.log(*c.resources.COUNT).ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
// this wouldn't compile in `release` mode
|
// this wouldn't compile in `release` mode
|
||||||
|
@ -38,7 +37,7 @@ const APP: () = {
|
||||||
|
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
#[task]
|
#[task]
|
||||||
fn log(n: u32) {
|
fn log(_: log::Context, n: u32) {
|
||||||
hprintln!(
|
hprintln!(
|
||||||
"foo has been called {} time{}",
|
"foo has been called {} time{}",
|
||||||
n,
|
n,
|
||||||
|
|
|
@ -9,25 +9,25 @@ extern crate panic_semihosting;
|
||||||
|
|
||||||
use cortex_m_semihosting::{debug, hprintln};
|
use cortex_m_semihosting::{debug, hprintln};
|
||||||
use lm3s6965::Interrupt;
|
use lm3s6965::Interrupt;
|
||||||
use rtfm::{app, Mutex};
|
use rtfm::Mutex;
|
||||||
|
|
||||||
#[app(device = lm3s6965)]
|
#[rtfm::app(device = lm3s6965)]
|
||||||
const APP: () = {
|
const APP: () = {
|
||||||
static mut SHARED: u32 = 0;
|
static mut SHARED: u32 = 0;
|
||||||
|
|
||||||
#[init]
|
#[init]
|
||||||
fn init() {
|
fn init(_: init::Context) {
|
||||||
rtfm::pend(Interrupt::UART0);
|
rtfm::pend(Interrupt::UART0);
|
||||||
rtfm::pend(Interrupt::UART1);
|
rtfm::pend(Interrupt::UART1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[interrupt(resources = [SHARED])]
|
#[interrupt(resources = [SHARED])]
|
||||||
fn UART0() {
|
fn UART0(c: UART0::Context) {
|
||||||
static mut STATE: u32 = 0;
|
static mut STATE: u32 = 0;
|
||||||
|
|
||||||
hprintln!("UART0(STATE = {})", *STATE).unwrap();
|
hprintln!("UART0(STATE = {})", *STATE).unwrap();
|
||||||
|
|
||||||
advance(STATE, resources.SHARED);
|
advance(STATE, c.resources.SHARED);
|
||||||
|
|
||||||
rtfm::pend(Interrupt::UART1);
|
rtfm::pend(Interrupt::UART1);
|
||||||
|
|
||||||
|
@ -35,17 +35,17 @@ const APP: () = {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[interrupt(priority = 2, resources = [SHARED])]
|
#[interrupt(priority = 2, resources = [SHARED])]
|
||||||
fn UART1() {
|
fn UART1(mut c: UART1::Context) {
|
||||||
static mut STATE: u32 = 0;
|
static mut STATE: u32 = 0;
|
||||||
|
|
||||||
hprintln!("UART1(STATE = {})", *STATE).unwrap();
|
hprintln!("UART1(STATE = {})", *STATE).unwrap();
|
||||||
|
|
||||||
// just to show that `SHARED` can be accessed directly and ..
|
// just to show that `SHARED` can be accessed directly and ..
|
||||||
*resources.SHARED += 0;
|
*c.resources.SHARED += 0;
|
||||||
// .. also through a (no-op) `lock`
|
// .. also through a (no-op) `lock`
|
||||||
resources.SHARED.lock(|shared| *shared += 0);
|
c.resources.SHARED.lock(|shared| *shared += 0);
|
||||||
|
|
||||||
advance(STATE, resources.SHARED);
|
advance(STATE, c.resources.SHARED);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -8,17 +8,16 @@
|
||||||
extern crate panic_semihosting;
|
extern crate panic_semihosting;
|
||||||
|
|
||||||
use cortex_m_semihosting::{debug, hprintln};
|
use cortex_m_semihosting::{debug, hprintln};
|
||||||
use rtfm::app;
|
|
||||||
|
|
||||||
#[app(device = lm3s6965)]
|
#[rtfm::app(device = lm3s6965)]
|
||||||
const APP: () = {
|
const APP: () = {
|
||||||
#[init]
|
#[init]
|
||||||
fn init() {
|
fn init(_: init::Context) {
|
||||||
hprintln!("init").unwrap();
|
hprintln!("init").unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[idle]
|
#[idle]
|
||||||
fn idle() -> ! {
|
fn idle(_: idle::Context) -> ! {
|
||||||
static mut X: u32 = 0;
|
static mut X: u32 = 0;
|
||||||
|
|
||||||
// Safe access to local `static mut` variable
|
// Safe access to local `static mut` variable
|
||||||
|
|
|
@ -8,19 +8,18 @@
|
||||||
extern crate panic_semihosting;
|
extern crate panic_semihosting;
|
||||||
|
|
||||||
use cortex_m_semihosting::{debug, hprintln};
|
use cortex_m_semihosting::{debug, hprintln};
|
||||||
use rtfm::app;
|
|
||||||
|
|
||||||
#[app(device = lm3s6965)]
|
#[rtfm::app(device = lm3s6965)]
|
||||||
const APP: () = {
|
const APP: () = {
|
||||||
#[init]
|
#[init]
|
||||||
fn init() {
|
fn init(c: init::Context) {
|
||||||
static mut X: u32 = 0;
|
static mut X: u32 = 0;
|
||||||
|
|
||||||
// Cortex-M peripherals
|
// Cortex-M peripherals
|
||||||
let _core: rtfm::Peripherals = core;
|
let _core: rtfm::Peripherals = c.core;
|
||||||
|
|
||||||
// Device specific peripherals
|
// Device specific peripherals
|
||||||
let _device: lm3s6965::Peripherals = device;
|
let _device: lm3s6965::Peripherals = c.device;
|
||||||
|
|
||||||
// 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;
|
||||||
|
|
|
@ -9,12 +9,11 @@ extern crate panic_semihosting;
|
||||||
|
|
||||||
use cortex_m_semihosting::{debug, hprintln};
|
use cortex_m_semihosting::{debug, hprintln};
|
||||||
use lm3s6965::Interrupt;
|
use lm3s6965::Interrupt;
|
||||||
use rtfm::app;
|
|
||||||
|
|
||||||
#[app(device = lm3s6965)]
|
#[rtfm::app(device = lm3s6965)]
|
||||||
const APP: () = {
|
const APP: () = {
|
||||||
#[init]
|
#[init]
|
||||||
fn init() {
|
fn init(_: init::Context) {
|
||||||
// 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
|
||||||
rtfm::pend(Interrupt::UART0);
|
rtfm::pend(Interrupt::UART0);
|
||||||
|
@ -23,7 +22,7 @@ const APP: () = {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[idle]
|
#[idle]
|
||||||
fn idle() -> ! {
|
fn idle(_: idle::Context) -> ! {
|
||||||
// interrupts are enabled again; the `UART0` handler runs at this point
|
// interrupts are enabled again; the `UART0` handler runs at this point
|
||||||
|
|
||||||
hprintln!("idle").unwrap();
|
hprintln!("idle").unwrap();
|
||||||
|
@ -36,7 +35,7 @@ const APP: () = {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[interrupt]
|
#[interrupt]
|
||||||
fn UART0() {
|
fn UART0(_: UART0::Context) {
|
||||||
static mut TIMES: u32 = 0;
|
static mut TIMES: u32 = 0;
|
||||||
|
|
||||||
// Safe access to local `static mut` variable
|
// Safe access to local `static mut` variable
|
||||||
|
|
|
@ -13,16 +13,15 @@ use heapless::{
|
||||||
spsc::{Consumer, Producer, Queue},
|
spsc::{Consumer, Producer, Queue},
|
||||||
};
|
};
|
||||||
use lm3s6965::Interrupt;
|
use lm3s6965::Interrupt;
|
||||||
use rtfm::app;
|
|
||||||
|
|
||||||
#[app(device = lm3s6965)]
|
#[rtfm::app(device = lm3s6965)]
|
||||||
const APP: () = {
|
const APP: () = {
|
||||||
// Late resources
|
// Late resources
|
||||||
static mut P: Producer<'static, u32, U4> = ();
|
static mut P: Producer<'static, u32, U4> = ();
|
||||||
static mut C: Consumer<'static, u32, U4> = ();
|
static mut C: Consumer<'static, u32, U4> = ();
|
||||||
|
|
||||||
#[init]
|
#[init]
|
||||||
fn init() -> init::LateResources {
|
fn init(_: init::Context) -> init::LateResources {
|
||||||
// NOTE: we use `Option` here to work around the lack of
|
// NOTE: we use `Option` here to work around the lack of
|
||||||
// a stable `const` constructor
|
// a stable `const` constructor
|
||||||
static mut Q: Option<Queue<u32, U4>> = None;
|
static mut Q: Option<Queue<u32, U4>> = None;
|
||||||
|
@ -35,9 +34,9 @@ const APP: () = {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[idle(resources = [C])]
|
#[idle(resources = [C])]
|
||||||
fn idle() -> ! {
|
fn idle(c: idle::Context) -> ! {
|
||||||
loop {
|
loop {
|
||||||
if let Some(byte) = resources.C.dequeue() {
|
if let Some(byte) = c.resources.C.dequeue() {
|
||||||
hprintln!("received message: {}", byte).unwrap();
|
hprintln!("received message: {}", byte).unwrap();
|
||||||
|
|
||||||
debug::exit(debug::EXIT_SUCCESS);
|
debug::exit(debug::EXIT_SUCCESS);
|
||||||
|
@ -48,7 +47,7 @@ const APP: () = {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[interrupt(resources = [P])]
|
#[interrupt(resources = [P])]
|
||||||
fn UART0() {
|
fn UART0(c: UART0::Context) {
|
||||||
resources.P.enqueue(42).unwrap();
|
c.resources.P.enqueue(42).unwrap();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -9,24 +9,23 @@ extern crate panic_semihosting;
|
||||||
|
|
||||||
use cortex_m_semihosting::{debug, hprintln};
|
use cortex_m_semihosting::{debug, hprintln};
|
||||||
use lm3s6965::Interrupt;
|
use lm3s6965::Interrupt;
|
||||||
use rtfm::app;
|
|
||||||
|
|
||||||
#[app(device = lm3s6965)]
|
#[rtfm::app(device = lm3s6965)]
|
||||||
const APP: () = {
|
const APP: () = {
|
||||||
static mut SHARED: u32 = 0;
|
static mut SHARED: u32 = 0;
|
||||||
|
|
||||||
#[init]
|
#[init]
|
||||||
fn init() {
|
fn init(_: init::Context) {
|
||||||
rtfm::pend(Interrupt::GPIOA);
|
rtfm::pend(Interrupt::GPIOA);
|
||||||
}
|
}
|
||||||
|
|
||||||
// when omitted priority is assumed to be `1`
|
// when omitted priority is assumed to be `1`
|
||||||
#[interrupt(resources = [SHARED])]
|
#[interrupt(resources = [SHARED])]
|
||||||
fn GPIOA() {
|
fn GPIOA(mut c: GPIOA::Context) {
|
||||||
hprintln!("A").unwrap();
|
hprintln!("A").unwrap();
|
||||||
|
|
||||||
// the lower priority task requires a critical section to access the data
|
// the lower priority task requires a critical section to access the data
|
||||||
resources.SHARED.lock(|shared| {
|
c.resources.SHARED.lock(|shared| {
|
||||||
// data can only be modified within this critical section (closure)
|
// data can only be modified within this critical section (closure)
|
||||||
*shared += 1;
|
*shared += 1;
|
||||||
|
|
||||||
|
@ -47,15 +46,15 @@ const APP: () = {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[interrupt(priority = 2, resources = [SHARED])]
|
#[interrupt(priority = 2, resources = [SHARED])]
|
||||||
fn GPIOB() {
|
fn GPIOB(mut c: GPIOB::Context) {
|
||||||
// the higher priority task does *not* need a critical section
|
// the higher priority task does *not* need a critical section
|
||||||
*resources.SHARED += 1;
|
*c.resources.SHARED += 1;
|
||||||
|
|
||||||
hprintln!("D - SHARED = {}", *resources.SHARED).unwrap();
|
hprintln!("D - SHARED = {}", *c.resources.SHARED).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[interrupt(priority = 3)]
|
#[interrupt(priority = 3)]
|
||||||
fn GPIOC() {
|
fn GPIOC(_: GPIOC::Context) {
|
||||||
hprintln!("C").unwrap();
|
hprintln!("C").unwrap();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -8,41 +8,40 @@
|
||||||
extern crate panic_semihosting;
|
extern crate panic_semihosting;
|
||||||
|
|
||||||
use cortex_m_semihosting::{debug, hprintln};
|
use cortex_m_semihosting::{debug, hprintln};
|
||||||
use rtfm::app;
|
|
||||||
|
|
||||||
#[app(device = lm3s6965)]
|
#[rtfm::app(device = lm3s6965)]
|
||||||
const APP: () = {
|
const APP: () = {
|
||||||
#[init(spawn = [foo])]
|
#[init(spawn = [foo])]
|
||||||
fn init() {
|
fn init(c: init::Context) {
|
||||||
spawn.foo(/* no message */).unwrap();
|
c.spawn.foo(/* no message */).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[task(spawn = [bar])]
|
#[task(spawn = [bar])]
|
||||||
fn foo() {
|
fn foo(c: foo::Context) {
|
||||||
static mut COUNT: u32 = 0;
|
static mut COUNT: u32 = 0;
|
||||||
|
|
||||||
hprintln!("foo").unwrap();
|
hprintln!("foo").unwrap();
|
||||||
|
|
||||||
spawn.bar(*COUNT).unwrap();
|
c.spawn.bar(*COUNT).unwrap();
|
||||||
*COUNT += 1;
|
*COUNT += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[task(spawn = [baz])]
|
#[task(spawn = [baz])]
|
||||||
fn bar(x: u32) {
|
fn bar(c: bar::Context, x: u32) {
|
||||||
hprintln!("bar({})", x).unwrap();
|
hprintln!("bar({})", x).unwrap();
|
||||||
|
|
||||||
spawn.baz(x + 1, x + 2).unwrap();
|
c.spawn.baz(x + 1, x + 2).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[task(spawn = [foo])]
|
#[task(spawn = [foo])]
|
||||||
fn baz(x: u32, y: u32) {
|
fn baz(c: baz::Context, x: u32, y: u32) {
|
||||||
hprintln!("baz({}, {})", x, y).unwrap();
|
hprintln!("baz({}, {})", x, y).unwrap();
|
||||||
|
|
||||||
if x + y > 4 {
|
if x + y > 4 {
|
||||||
debug::exit(debug::EXIT_SUCCESS);
|
debug::exit(debug::EXIT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
spawn.foo().unwrap();
|
c.spawn.foo().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
|
@ -21,32 +21,32 @@ const APP: () = {
|
||||||
static mut SHARED: Option<NotSend> = None;
|
static mut SHARED: Option<NotSend> = None;
|
||||||
|
|
||||||
#[init(spawn = [baz, quux])]
|
#[init(spawn = [baz, quux])]
|
||||||
fn init() {
|
fn init(c: init::Context) {
|
||||||
spawn.baz().unwrap();
|
c.spawn.baz().unwrap();
|
||||||
spawn.quux().unwrap();
|
c.spawn.quux().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[task(spawn = [bar])]
|
#[task(spawn = [bar])]
|
||||||
fn foo() {
|
fn foo(c: foo::Context) {
|
||||||
// scenario 1: message passed to task that runs at the same priority
|
// scenario 1: message passed to task that runs at the same priority
|
||||||
spawn.bar(NotSend { _0: PhantomData }).ok();
|
c.spawn.bar(NotSend { _0: PhantomData }).ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[task]
|
#[task]
|
||||||
fn bar(_x: NotSend) {
|
fn bar(_: bar::Context, _x: NotSend) {
|
||||||
// scenario 1
|
// scenario 1
|
||||||
}
|
}
|
||||||
|
|
||||||
#[task(priority = 2, resources = [SHARED])]
|
#[task(priority = 2, resources = [SHARED])]
|
||||||
fn baz() {
|
fn baz(mut c: baz::Context) {
|
||||||
// scenario 2: resource shared between tasks that run at the same priority
|
// scenario 2: resource shared between tasks that run at the same priority
|
||||||
*resources.SHARED = Some(NotSend { _0: PhantomData });
|
*c.resources.SHARED = Some(NotSend { _0: PhantomData });
|
||||||
}
|
}
|
||||||
|
|
||||||
#[task(priority = 2, resources = [SHARED])]
|
#[task(priority = 2, resources = [SHARED])]
|
||||||
fn quux() {
|
fn quux(mut c: quux::Context) {
|
||||||
// scenario 2
|
// scenario 2
|
||||||
let _not_send = resources.SHARED.take().unwrap();
|
let _not_send = c.resources.SHARED.take().unwrap();
|
||||||
|
|
||||||
debug::exit(debug::EXIT_SUCCESS);
|
debug::exit(debug::EXIT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,29 +10,28 @@ extern crate panic_halt;
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
|
|
||||||
use cortex_m_semihosting::debug;
|
use cortex_m_semihosting::debug;
|
||||||
use rtfm::app;
|
|
||||||
|
|
||||||
pub struct NotSync {
|
pub struct NotSync {
|
||||||
_0: PhantomData<*const ()>,
|
_0: PhantomData<*const ()>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[app(device = lm3s6965)]
|
#[rtfm::app(device = lm3s6965)]
|
||||||
const APP: () = {
|
const APP: () = {
|
||||||
static SHARED: NotSync = NotSync { _0: PhantomData };
|
static SHARED: NotSync = NotSync { _0: PhantomData };
|
||||||
|
|
||||||
#[init]
|
#[init]
|
||||||
fn init() {
|
fn init(_: init::Context) {
|
||||||
debug::exit(debug::EXIT_SUCCESS);
|
debug::exit(debug::EXIT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[task(resources = [SHARED])]
|
#[task(resources = [SHARED])]
|
||||||
fn foo() {
|
fn foo(c: foo::Context) {
|
||||||
let _: &NotSync = resources.SHARED;
|
let _: &NotSync = c.resources.SHARED;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[task(resources = [SHARED])]
|
#[task(resources = [SHARED])]
|
||||||
fn bar() {
|
fn bar(c: bar::Context) {
|
||||||
let _: &NotSync = resources.SHARED;
|
let _: &NotSync = c.resources.SHARED;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
|
@ -8,24 +8,24 @@
|
||||||
extern crate panic_semihosting;
|
extern crate panic_semihosting;
|
||||||
|
|
||||||
use cortex_m_semihosting::hprintln;
|
use cortex_m_semihosting::hprintln;
|
||||||
use rtfm::{app, Instant};
|
use rtfm::Instant;
|
||||||
|
|
||||||
const PERIOD: u32 = 8_000_000;
|
const PERIOD: u32 = 8_000_000;
|
||||||
|
|
||||||
// NOTE: does NOT work on QEMU!
|
// NOTE: does NOT work on QEMU!
|
||||||
#[app(device = lm3s6965)]
|
#[rtfm::app(device = lm3s6965)]
|
||||||
const APP: () = {
|
const APP: () = {
|
||||||
#[init(schedule = [foo])]
|
#[init(schedule = [foo])]
|
||||||
fn init() {
|
fn init(c: init::Context) {
|
||||||
schedule.foo(Instant::now() + PERIOD.cycles()).unwrap();
|
c.schedule.foo(Instant::now() + PERIOD.cycles()).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[task(schedule = [foo])]
|
#[task(schedule = [foo])]
|
||||||
fn foo() {
|
fn foo(c: foo::Context) {
|
||||||
let now = Instant::now();
|
let now = Instant::now();
|
||||||
hprintln!("foo(scheduled = {:?}, now = {:?})", scheduled, now).unwrap();
|
hprintln!("foo(scheduled = {:?}, now = {:?})", c.scheduled, now).unwrap();
|
||||||
|
|
||||||
schedule.foo(scheduled + PERIOD.cycles()).unwrap();
|
c.schedule.foo(c.scheduled + PERIOD.cycles()).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
67
examples/pool.rs
Normal file
67
examples/pool.rs
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
//! examples/pool.rs
|
||||||
|
|
||||||
|
#![deny(unsafe_code)]
|
||||||
|
#![deny(warnings)]
|
||||||
|
#![no_main]
|
||||||
|
#![no_std]
|
||||||
|
|
||||||
|
extern crate panic_semihosting;
|
||||||
|
|
||||||
|
use cortex_m_semihosting::{debug, hprintln};
|
||||||
|
use heapless::{
|
||||||
|
pool,
|
||||||
|
pool::singleton::{Box, Pool},
|
||||||
|
};
|
||||||
|
use lm3s6965::Interrupt;
|
||||||
|
use rtfm::app;
|
||||||
|
|
||||||
|
// Declare a pool of 128-byte memory blocks
|
||||||
|
pool!(P: [u8; 128]);
|
||||||
|
|
||||||
|
#[app(device = lm3s6965)]
|
||||||
|
const APP: () = {
|
||||||
|
#[init]
|
||||||
|
fn init(_: init::Context) {
|
||||||
|
static mut MEMORY: [u8; 512] = [0; 512];
|
||||||
|
|
||||||
|
// Increase the capacity of the memory pool by ~4
|
||||||
|
P::grow(MEMORY);
|
||||||
|
|
||||||
|
rtfm::pend(Interrupt::I2C0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[interrupt(priority = 2, spawn = [foo, bar])]
|
||||||
|
fn I2C0(c: I2C0::Context) {
|
||||||
|
// claim a memory block, leave it uninitialized and ..
|
||||||
|
let x = P::alloc().unwrap().freeze();
|
||||||
|
|
||||||
|
// .. send it to the `foo` task
|
||||||
|
c.spawn.foo(x).ok().unwrap();
|
||||||
|
|
||||||
|
// send another block to the task `bar`
|
||||||
|
c.spawn.bar(P::alloc().unwrap().freeze()).ok().unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[task]
|
||||||
|
fn foo(_: foo::Context, x: Box<P>) {
|
||||||
|
hprintln!("foo({:?})", x.as_ptr()).unwrap();
|
||||||
|
|
||||||
|
// explicitly return the block to the pool
|
||||||
|
drop(x);
|
||||||
|
|
||||||
|
debug::exit(debug::EXIT_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[task(priority = 2)]
|
||||||
|
fn bar(_: bar::Context, x: Box<P>) {
|
||||||
|
hprintln!("bar({:?})", x.as_ptr()).unwrap();
|
||||||
|
|
||||||
|
// this is done automatically so we can omit the call to `drop`
|
||||||
|
// drop(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
fn UART0();
|
||||||
|
fn UART1();
|
||||||
|
}
|
||||||
|
};
|
|
@ -8,18 +8,17 @@
|
||||||
extern crate panic_semihosting;
|
extern crate panic_semihosting;
|
||||||
|
|
||||||
use cortex_m_semihosting::{debug, hprintln};
|
use cortex_m_semihosting::{debug, hprintln};
|
||||||
use rtfm::app;
|
|
||||||
|
|
||||||
#[app(device = lm3s6965)]
|
#[rtfm::app(device = lm3s6965)]
|
||||||
const APP: () = {
|
const APP: () = {
|
||||||
#[init(spawn = [bar])]
|
#[init(spawn = [bar])]
|
||||||
fn init() {
|
fn init(c: init::Context) {
|
||||||
spawn.bar().unwrap();
|
c.spawn.bar().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
#[task]
|
#[task]
|
||||||
fn foo() {
|
fn foo(_: foo::Context) {
|
||||||
hprintln!("foo").unwrap();
|
hprintln!("foo").unwrap();
|
||||||
|
|
||||||
debug::exit(debug::EXIT_SUCCESS);
|
debug::exit(debug::EXIT_SUCCESS);
|
||||||
|
@ -29,8 +28,8 @@ const APP: () = {
|
||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
#[link_section = ".data.bar"]
|
#[link_section = ".data.bar"]
|
||||||
#[task(priority = 2, spawn = [foo])]
|
#[task(priority = 2, spawn = [foo])]
|
||||||
fn bar() {
|
fn bar(c: bar::Context) {
|
||||||
spawn.foo().unwrap();
|
c.spawn.foo().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
|
@ -9,21 +9,20 @@ extern crate panic_semihosting;
|
||||||
|
|
||||||
use cortex_m_semihosting::{debug, hprintln};
|
use cortex_m_semihosting::{debug, hprintln};
|
||||||
use lm3s6965::Interrupt;
|
use lm3s6965::Interrupt;
|
||||||
use rtfm::app;
|
|
||||||
|
|
||||||
#[app(device = lm3s6965)]
|
#[rtfm::app(device = lm3s6965)]
|
||||||
const APP: () = {
|
const APP: () = {
|
||||||
// A resource
|
// A resource
|
||||||
static mut SHARED: u32 = 0;
|
static mut SHARED: u32 = 0;
|
||||||
|
|
||||||
#[init]
|
#[init]
|
||||||
fn init() {
|
fn init(_: init::Context) {
|
||||||
rtfm::pend(Interrupt::UART0);
|
rtfm::pend(Interrupt::UART0);
|
||||||
rtfm::pend(Interrupt::UART1);
|
rtfm::pend(Interrupt::UART1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[idle]
|
#[idle]
|
||||||
fn idle() -> ! {
|
fn idle(_: idle::Context) -> ! {
|
||||||
debug::exit(debug::EXIT_SUCCESS);
|
debug::exit(debug::EXIT_SUCCESS);
|
||||||
|
|
||||||
// error: `SHARED` can't be accessed from this context
|
// error: `SHARED` can't be accessed from this context
|
||||||
|
@ -34,17 +33,17 @@ const APP: () = {
|
||||||
|
|
||||||
// `SHARED` can be access from this context
|
// `SHARED` can be access from this context
|
||||||
#[interrupt(resources = [SHARED])]
|
#[interrupt(resources = [SHARED])]
|
||||||
fn UART0() {
|
fn UART0(mut c: UART0::Context) {
|
||||||
*resources.SHARED += 1;
|
*c.resources.SHARED += 1;
|
||||||
|
|
||||||
hprintln!("UART0: SHARED = {}", resources.SHARED).unwrap();
|
hprintln!("UART0: SHARED = {}", c.resources.SHARED).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
// `SHARED` can be access from this context
|
// `SHARED` can be access from this context
|
||||||
#[interrupt(resources = [SHARED])]
|
#[interrupt(resources = [SHARED])]
|
||||||
fn UART1() {
|
fn UART1(mut c: UART1::Context) {
|
||||||
*resources.SHARED += 1;
|
*c.resources.SHARED += 1;
|
||||||
|
|
||||||
hprintln!("UART1: SHARED = {}", resources.SHARED).unwrap();
|
hprintln!("UART1: SHARED = {}", c.resources.SHARED).unwrap();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -8,31 +8,31 @@
|
||||||
extern crate panic_semihosting;
|
extern crate panic_semihosting;
|
||||||
|
|
||||||
use cortex_m_semihosting::hprintln;
|
use cortex_m_semihosting::hprintln;
|
||||||
use rtfm::{app, Instant};
|
use rtfm::Instant;
|
||||||
|
|
||||||
// NOTE: does NOT work on QEMU!
|
// NOTE: does NOT work on QEMU!
|
||||||
#[app(device = lm3s6965)]
|
#[rtfm::app(device = lm3s6965)]
|
||||||
const APP: () = {
|
const APP: () = {
|
||||||
#[init(schedule = [foo, bar])]
|
#[init(schedule = [foo, bar])]
|
||||||
fn init() {
|
fn init(c: init::Context) {
|
||||||
let now = Instant::now();
|
let now = Instant::now();
|
||||||
|
|
||||||
hprintln!("init @ {:?}", now).unwrap();
|
hprintln!("init @ {:?}", now).unwrap();
|
||||||
|
|
||||||
// Schedule `foo` to run 8e6 cycles (clock cycles) in the future
|
// Schedule `foo` to run 8e6 cycles (clock cycles) in the future
|
||||||
schedule.foo(now + 8_000_000.cycles()).unwrap();
|
c.schedule.foo(now + 8_000_000.cycles()).unwrap();
|
||||||
|
|
||||||
// Schedule `bar` to run 4e6 cycles in the future
|
// Schedule `bar` to run 4e6 cycles in the future
|
||||||
schedule.bar(now + 4_000_000.cycles()).unwrap();
|
c.schedule.bar(now + 4_000_000.cycles()).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[task]
|
#[task]
|
||||||
fn foo() {
|
fn foo(_: foo::Context) {
|
||||||
hprintln!("foo @ {:?}", Instant::now()).unwrap();
|
hprintln!("foo @ {:?}", Instant::now()).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[task]
|
#[task]
|
||||||
fn bar() {
|
fn bar(_: bar::Context) {
|
||||||
hprintln!("bar @ {:?}", Instant::now()).unwrap();
|
hprintln!("bar @ {:?}", Instant::now()).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,17 +18,17 @@ const APP: () = {
|
||||||
static mut SHARED: Option<MustBeSend> = None;
|
static mut SHARED: Option<MustBeSend> = None;
|
||||||
|
|
||||||
#[init(resources = [SHARED])]
|
#[init(resources = [SHARED])]
|
||||||
fn init() {
|
fn init(c: init::Context) {
|
||||||
// this `message` will be sent to task `UART0`
|
// this `message` will be sent to task `UART0`
|
||||||
let message = MustBeSend;
|
let message = MustBeSend;
|
||||||
*resources.SHARED = Some(message);
|
*c.resources.SHARED = Some(message);
|
||||||
|
|
||||||
rtfm::pend(Interrupt::UART0);
|
rtfm::pend(Interrupt::UART0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[interrupt(resources = [SHARED])]
|
#[interrupt(resources = [SHARED])]
|
||||||
fn UART0() {
|
fn UART0(c: UART0::Context) {
|
||||||
if let Some(message) = resources.SHARED.take() {
|
if let Some(message) = c.resources.SHARED.take() {
|
||||||
// `message` has been received
|
// `message` has been received
|
||||||
drop(message);
|
drop(message);
|
||||||
|
|
||||||
|
|
|
@ -1,61 +0,0 @@
|
||||||
//! examples/singleton.rs
|
|
||||||
|
|
||||||
#![deny(unsafe_code)]
|
|
||||||
#![deny(warnings)]
|
|
||||||
#![no_main]
|
|
||||||
#![no_std]
|
|
||||||
|
|
||||||
extern crate panic_semihosting;
|
|
||||||
|
|
||||||
use alloc_singleton::stable::pool::{Box, Pool};
|
|
||||||
use cortex_m_semihosting::{debug, hprintln};
|
|
||||||
use lm3s6965::Interrupt;
|
|
||||||
use rtfm::app;
|
|
||||||
|
|
||||||
#[app(device = lm3s6965)]
|
|
||||||
const APP: () = {
|
|
||||||
#[Singleton(Send)]
|
|
||||||
static mut M: [u32; 2] = [0; 2];
|
|
||||||
|
|
||||||
static mut P: Pool<M> = ();
|
|
||||||
|
|
||||||
#[init(resources = [M])]
|
|
||||||
fn init() -> init::LateResources {
|
|
||||||
rtfm::pend(Interrupt::I2C0);
|
|
||||||
|
|
||||||
init::LateResources {
|
|
||||||
P: Pool::new(resources.M),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[interrupt(
|
|
||||||
priority = 2,
|
|
||||||
resources = [P],
|
|
||||||
spawn = [foo, bar],
|
|
||||||
)]
|
|
||||||
fn I2C0() {
|
|
||||||
spawn.foo(resources.P.alloc(1).unwrap()).unwrap();
|
|
||||||
spawn.bar(resources.P.alloc(2).unwrap()).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[task(resources = [P])]
|
|
||||||
fn foo(x: Box<M>) {
|
|
||||||
hprintln!("foo({})", x).unwrap();
|
|
||||||
|
|
||||||
resources.P.lock(|p| p.dealloc(x));
|
|
||||||
|
|
||||||
debug::exit(debug::EXIT_SUCCESS);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[task(priority = 2, resources = [P])]
|
|
||||||
fn bar(x: Box<M>) {
|
|
||||||
hprintln!("bar({})", x).unwrap();
|
|
||||||
|
|
||||||
resources.P.dealloc(x);
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" {
|
|
||||||
fn UART0();
|
|
||||||
fn UART1();
|
|
||||||
}
|
|
||||||
};
|
|
|
@ -13,5 +13,5 @@ use rtfm::app;
|
||||||
#[app(device = lm3s6965)]
|
#[app(device = lm3s6965)]
|
||||||
const APP: () = {
|
const APP: () = {
|
||||||
#[init]
|
#[init]
|
||||||
fn init() {}
|
fn init(_: init::Context) {}
|
||||||
};
|
};
|
||||||
|
|
|
@ -9,14 +9,13 @@ extern crate panic_semihosting;
|
||||||
|
|
||||||
use cortex_m_semihosting::{debug, hprintln};
|
use cortex_m_semihosting::{debug, hprintln};
|
||||||
use lm3s6965::Interrupt;
|
use lm3s6965::Interrupt;
|
||||||
use rtfm::app;
|
|
||||||
|
|
||||||
#[app(device = lm3s6965)]
|
#[rtfm::app(device = lm3s6965)]
|
||||||
const APP: () = {
|
const APP: () = {
|
||||||
static KEY: u32 = ();
|
static KEY: u32 = ();
|
||||||
|
|
||||||
#[init]
|
#[init]
|
||||||
fn init() -> init::LateResources {
|
fn init(_: init::Context) -> init::LateResources {
|
||||||
rtfm::pend(Interrupt::UART0);
|
rtfm::pend(Interrupt::UART0);
|
||||||
rtfm::pend(Interrupt::UART1);
|
rtfm::pend(Interrupt::UART1);
|
||||||
|
|
||||||
|
@ -24,14 +23,14 @@ const APP: () = {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[interrupt(resources = [KEY])]
|
#[interrupt(resources = [KEY])]
|
||||||
fn UART0() {
|
fn UART0(c: UART0::Context) {
|
||||||
hprintln!("UART0(KEY = {:#x})", resources.KEY).unwrap();
|
hprintln!("UART0(KEY = {:#x})", c.resources.KEY).unwrap();
|
||||||
|
|
||||||
debug::exit(debug::EXIT_SUCCESS);
|
debug::exit(debug::EXIT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[interrupt(priority = 2, resources = [KEY])]
|
#[interrupt(priority = 2, resources = [KEY])]
|
||||||
fn UART1() {
|
fn UART1(c: UART1::Context) {
|
||||||
hprintln!("UART1(KEY = {:#x})", resources.KEY).unwrap();
|
hprintln!("UART1(KEY = {:#x})", c.resources.KEY).unwrap();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -8,38 +8,37 @@
|
||||||
extern crate panic_semihosting;
|
extern crate panic_semihosting;
|
||||||
|
|
||||||
use cortex_m_semihosting::{debug, hprintln};
|
use cortex_m_semihosting::{debug, hprintln};
|
||||||
use rtfm::app;
|
|
||||||
|
|
||||||
#[app(device = lm3s6965)]
|
#[rtfm::app(device = lm3s6965)]
|
||||||
const APP: () = {
|
const APP: () = {
|
||||||
#[init(spawn = [foo])]
|
#[init(spawn = [foo])]
|
||||||
fn init() {
|
fn init(c: init::Context) {
|
||||||
spawn.foo().unwrap();
|
c.spawn.foo().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[task(spawn = [bar, baz])]
|
#[task(spawn = [bar, baz])]
|
||||||
fn foo() {
|
fn foo(c: foo::Context) {
|
||||||
hprintln!("foo").unwrap();
|
hprintln!("foo").unwrap();
|
||||||
|
|
||||||
// spawns `bar` onto the task scheduler
|
// spawns `bar` onto the task scheduler
|
||||||
// `foo` and `bar` have the same priority so `bar` will not run until
|
// `foo` and `bar` have the same priority so `bar` will not run until
|
||||||
// after `foo` terminates
|
// after `foo` terminates
|
||||||
spawn.bar().unwrap();
|
c.spawn.bar().unwrap();
|
||||||
|
|
||||||
// spawns `baz` onto the task scheduler
|
// spawns `baz` onto the task scheduler
|
||||||
// `baz` has higher priority than `foo` so it immediately preempts `foo`
|
// `baz` has higher priority than `foo` so it immediately preempts `foo`
|
||||||
spawn.baz().unwrap();
|
c.spawn.baz().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[task]
|
#[task]
|
||||||
fn bar() {
|
fn bar(_: bar::Context) {
|
||||||
hprintln!("bar").unwrap();
|
hprintln!("bar").unwrap();
|
||||||
|
|
||||||
debug::exit(debug::EXIT_SUCCESS);
|
debug::exit(debug::EXIT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[task(priority = 2)]
|
#[task(priority = 2)]
|
||||||
fn baz() {
|
fn baz(_: baz::Context) {
|
||||||
hprintln!("baz").unwrap();
|
hprintln!("baz").unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,45 +8,45 @@
|
||||||
extern crate panic_semihosting;
|
extern crate panic_semihosting;
|
||||||
|
|
||||||
use cortex_m_semihosting::debug;
|
use cortex_m_semihosting::debug;
|
||||||
use rtfm::{app, Exclusive, Instant};
|
use rtfm::{Exclusive, Instant};
|
||||||
|
|
||||||
#[app(device = lm3s6965)]
|
#[rtfm::app(device = lm3s6965)]
|
||||||
const APP: () = {
|
const APP: () = {
|
||||||
static mut SHARED: u32 = 0;
|
static mut SHARED: u32 = 0;
|
||||||
|
|
||||||
#[init(schedule = [foo], spawn = [foo])]
|
#[init(schedule = [foo], spawn = [foo])]
|
||||||
fn init() {
|
fn init(c: init::Context) {
|
||||||
let _: Instant = start;
|
let _: Instant = c.start;
|
||||||
let _: rtfm::Peripherals = core;
|
let _: rtfm::Peripherals = c.core;
|
||||||
let _: lm3s6965::Peripherals = device;
|
let _: lm3s6965::Peripherals = c.device;
|
||||||
let _: init::Schedule = schedule;
|
let _: init::Schedule = c.schedule;
|
||||||
let _: init::Spawn = spawn;
|
let _: init::Spawn = c.spawn;
|
||||||
|
|
||||||
debug::exit(debug::EXIT_SUCCESS);
|
debug::exit(debug::EXIT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[exception(schedule = [foo], spawn = [foo])]
|
#[exception(schedule = [foo], spawn = [foo])]
|
||||||
fn SVCall() {
|
fn SVCall(c: SVCall::Context) {
|
||||||
let _: Instant = start;
|
let _: Instant = c.start;
|
||||||
let _: SVCall::Schedule = schedule;
|
let _: SVCall::Schedule = c.schedule;
|
||||||
let _: SVCall::Spawn = spawn;
|
let _: SVCall::Spawn = c.spawn;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[interrupt(resources = [SHARED], schedule = [foo], spawn = [foo])]
|
#[interrupt(resources = [SHARED], schedule = [foo], spawn = [foo])]
|
||||||
fn UART0() {
|
fn UART0(c: UART0::Context) {
|
||||||
let _: Instant = start;
|
let _: Instant = c.start;
|
||||||
let _: resources::SHARED = resources.SHARED;
|
let _: resources::SHARED = c.resources.SHARED;
|
||||||
let _: UART0::Schedule = schedule;
|
let _: UART0::Schedule = c.schedule;
|
||||||
let _: UART0::Spawn = spawn;
|
let _: UART0::Spawn = c.spawn;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[task(priority = 2, resources = [SHARED], schedule = [foo], spawn = [foo])]
|
#[task(priority = 2, resources = [SHARED], schedule = [foo], spawn = [foo])]
|
||||||
fn foo() {
|
fn foo(c: foo::Context) {
|
||||||
let _: Instant = scheduled;
|
let _: Instant = c.scheduled;
|
||||||
let _: Exclusive<u32> = resources.SHARED;
|
let _: Exclusive<u32> = c.resources.SHARED;
|
||||||
let _: foo::Resources = resources;
|
let _: foo::Resources = c.resources;
|
||||||
let _: foo::Schedule = schedule;
|
let _: foo::Schedule = c.schedule;
|
||||||
let _: foo::Spawn = spawn;
|
let _: foo::Spawn = c.spawn;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
|
@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0"
|
||||||
name = "cortex-m-rtfm-macros"
|
name = "cortex-m-rtfm-macros"
|
||||||
readme = "../README.md"
|
readme = "../README.md"
|
||||||
repository = "https://github.com/japaric/cortex-m-rtfm"
|
repository = "https://github.com/japaric/cortex-m-rtfm"
|
||||||
version = "0.4.3"
|
version = "0.5.0-alpha.1"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
proc-macro = true
|
proc-macro = true
|
||||||
|
@ -22,10 +22,6 @@ proc-macro2 = "0.4.24"
|
||||||
features = ["extra-traits", "full"]
|
features = ["extra-traits", "full"]
|
||||||
version = "0.15.23"
|
version = "0.15.23"
|
||||||
|
|
||||||
[dependencies.rand]
|
|
||||||
default-features = false
|
|
||||||
version = "0.5.5"
|
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
timer-queue = []
|
timer-queue = []
|
||||||
nightly = []
|
nightly = []
|
|
@ -190,19 +190,20 @@ pub fn app(app: &App) -> Analysis {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ceiling analysis of free queues (consumer end point) -- first pass
|
// Ceiling analysis of free queues (consumer end point) -- first pass
|
||||||
// Ceiling analysis of ready queues (producer end point)
|
// Ceiling analysis of ready queues (producer end point) -- first pass
|
||||||
// Also compute more Send-ness requirements
|
// Also compute more Send-ness requirements
|
||||||
let mut free_queues: HashMap<_, _> = app.tasks.keys().map(|task| (task.clone(), 0)).collect();
|
let mut free_queues = HashMap::new();
|
||||||
let mut ready_queues: HashMap<_, _> = dispatchers.keys().map(|level| (*level, 0)).collect();
|
let mut ready_queues = HashMap::new();
|
||||||
for (priority, task) in app.spawn_calls() {
|
for (priority, task) in app.spawn_calls() {
|
||||||
if let Some(priority) = priority {
|
if let Some(priority) = priority {
|
||||||
// Users of `spawn` contend for the to-be-spawned task FREE_QUEUE
|
// Users of `spawn` contend for the spawnee FREE_QUEUE
|
||||||
let c = free_queues.get_mut(task).expect("BUG: free_queue.get_mut");
|
let c = free_queues.entry(task.clone()).or_default();
|
||||||
*c = cmp::max(*c, priority);
|
*c = cmp::max(*c, priority);
|
||||||
|
|
||||||
|
// Users of `spawn` contend for the spawnee's dispatcher READY_QUEUE
|
||||||
let c = ready_queues
|
let c = ready_queues
|
||||||
.get_mut(&app.tasks[task].args.priority)
|
.entry(app.tasks[task].args.priority)
|
||||||
.expect("BUG: ready_queues.get_mut");
|
.or_default();
|
||||||
*c = cmp::max(*c, priority);
|
*c = cmp::max(*c, priority);
|
||||||
|
|
||||||
// Send is required when sending messages from a task whose priority doesn't match the
|
// Send is required when sending messages from a task whose priority doesn't match the
|
||||||
|
@ -215,16 +216,23 @@ pub fn app(app: &App) -> Analysis {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ceiling analysis of ready queues (producer end point) -- second pass
|
||||||
// Ceiling analysis of free queues (consumer end point) -- second pass
|
// Ceiling analysis of free queues (consumer end point) -- second pass
|
||||||
// Ceiling analysis of the timer queue
|
// Ceiling analysis of the timer queue
|
||||||
let mut tq_ceiling = tq_priority;
|
let mut tq_ceiling = tq_priority;
|
||||||
for (priority, task) in app.schedule_calls() {
|
for (priority, task) in app.schedule_calls() {
|
||||||
|
// the system timer handler contends for the spawnee's dispatcher READY_QUEUE
|
||||||
|
let c = ready_queues
|
||||||
|
.entry(app.tasks[task].args.priority)
|
||||||
|
.or_default();
|
||||||
|
*c = cmp::max(*c, tq_priority);
|
||||||
|
|
||||||
if let Some(priority) = priority {
|
if let Some(priority) = priority {
|
||||||
// Users of `schedule` contend for the to-be-spawned task FREE_QUEUE (consumer end point)
|
// Users of `schedule` contend for the spawnee task FREE_QUEUE
|
||||||
let c = free_queues.get_mut(task).expect("BUG: free_queue.get_mut");
|
let c = free_queues.entry(task.clone()).or_default();
|
||||||
*c = cmp::max(*c, priority);
|
*c = cmp::max(*c, priority);
|
||||||
|
|
||||||
// Users of `schedule` contend for the timer queu
|
// Users of `schedule` contend for the timer queue
|
||||||
tq_ceiling = cmp::max(tq_ceiling, priority);
|
tq_ceiling = cmp::max(tq_ceiling, priority);
|
||||||
} else {
|
} else {
|
||||||
// spawns from `init` are excluded from the ceiling analysis
|
// spawns from `init` are excluded from the ceiling analysis
|
||||||
|
|
|
@ -35,21 +35,12 @@ pub fn app(app: &App) -> parse::Result<()> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that all late resources have been initialized in `#[init]` if `init` has signature
|
// Check that `init` returns `LateResources` if there's any declared late resource
|
||||||
// `fn()`
|
if !app.init.returns_late_resources && app.resources.iter().any(|(_, res)| res.expr.is_none()) {
|
||||||
if !app.init.returns_late_resources {
|
return Err(parse::Error::new(
|
||||||
for res in
|
app.init.span,
|
||||||
app.resources
|
"late resources have been specified so `init` must return `init::LateResources`",
|
||||||
.iter()
|
));
|
||||||
.filter_map(|(name, res)| if res.expr.is_none() { Some(name) } else { None })
|
|
||||||
{
|
|
||||||
if app.init.assigns.iter().all(|assign| assign.left != *res) {
|
|
||||||
return Err(parse::Error::new(
|
|
||||||
res.span(),
|
|
||||||
"late resources MUST be initialized at the end of `init`",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that all referenced tasks have been declared
|
// Check that all referenced tasks have been declared
|
||||||
|
@ -128,7 +119,7 @@ pub fn app(app: &App) -> parse::Result<()> {
|
||||||
} else if app.init.returns_late_resources {
|
} else if app.init.returns_late_resources {
|
||||||
return Err(parse::Error::new(
|
return Err(parse::Error::new(
|
||||||
Span::call_site(),
|
Span::call_site(),
|
||||||
"`init` signature must be `[unsafe] fn()` if there are no late resources",
|
"`init` signature must be `fn(init::Context)` if there are no late resources",
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -288,9 +288,9 @@ mod syntax;
|
||||||
pub fn app(args: TokenStream, input: TokenStream) -> TokenStream {
|
pub fn app(args: TokenStream, input: TokenStream) -> TokenStream {
|
||||||
// Parse
|
// Parse
|
||||||
let args = parse_macro_input!(args as syntax::AppArgs);
|
let args = parse_macro_input!(args as syntax::AppArgs);
|
||||||
let items = parse_macro_input!(input as syntax::Input).items;
|
let input = parse_macro_input!(input as syntax::Input);
|
||||||
|
|
||||||
let app = match syntax::App::parse(items, args) {
|
let app = match syntax::App::parse(input.items, args) {
|
||||||
Err(e) => return e.to_compile_error().into(),
|
Err(e) => return e.to_compile_error().into(),
|
||||||
Ok(app) => app,
|
Ok(app) => app,
|
||||||
};
|
};
|
||||||
|
@ -304,5 +304,5 @@ pub fn app(args: TokenStream, input: TokenStream) -> TokenStream {
|
||||||
let analysis = analyze::app(&app);
|
let analysis = analyze::app(&app);
|
||||||
|
|
||||||
// Code generation
|
// Code generation
|
||||||
codegen::app(&app, &analysis).into()
|
codegen::app(&input.ident, &app, &analysis).into()
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,8 +11,8 @@ use syn::{
|
||||||
spanned::Spanned,
|
spanned::Spanned,
|
||||||
token::Brace,
|
token::Brace,
|
||||||
ArgCaptured, AttrStyle, Attribute, Expr, FnArg, ForeignItem, Ident, IntSuffix, Item, ItemFn,
|
ArgCaptured, AttrStyle, Attribute, Expr, FnArg, ForeignItem, Ident, IntSuffix, Item, ItemFn,
|
||||||
ItemForeignMod, ItemStatic, LitInt, Path, PathArguments, PathSegment, ReturnType, Stmt, Token,
|
ItemForeignMod, ItemStatic, LitInt, Pat, Path, PathArguments, ReturnType, Stmt, Token, Type,
|
||||||
Type, TypeTuple, Visibility,
|
TypeTuple, Visibility,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct AppArgs {
|
pub struct AppArgs {
|
||||||
|
@ -70,7 +70,7 @@ impl Parse for AppArgs {
|
||||||
|
|
||||||
pub struct Input {
|
pub struct Input {
|
||||||
_const_token: Token![const],
|
_const_token: Token![const],
|
||||||
_ident: Ident,
|
pub ident: Ident,
|
||||||
_colon_token: Token![:],
|
_colon_token: Token![:],
|
||||||
_ty: TypeTuple,
|
_ty: TypeTuple,
|
||||||
_eq_token: Token![=],
|
_eq_token: Token![=],
|
||||||
|
@ -94,7 +94,7 @@ impl Parse for Input {
|
||||||
let content;
|
let content;
|
||||||
Ok(Input {
|
Ok(Input {
|
||||||
_const_token: input.parse()?,
|
_const_token: input.parse()?,
|
||||||
_ident: input.parse()?,
|
ident: input.parse()?,
|
||||||
_colon_token: input.parse()?,
|
_colon_token: input.parse()?,
|
||||||
_ty: input.parse()?,
|
_ty: input.parse()?,
|
||||||
_eq_token: input.parse()?,
|
_eq_token: input.parse()?,
|
||||||
|
@ -435,7 +435,7 @@ pub type FreeInterrupts = BTreeMap<Ident, FreeInterrupt>;
|
||||||
pub struct Idle {
|
pub struct Idle {
|
||||||
pub args: IdleArgs,
|
pub args: IdleArgs,
|
||||||
pub attrs: Vec<Attribute>,
|
pub attrs: Vec<Attribute>,
|
||||||
pub unsafety: Option<Token![unsafe]>,
|
pub context: Pat,
|
||||||
pub statics: BTreeMap<Ident, Static>,
|
pub statics: BTreeMap<Ident, Static>,
|
||||||
pub stmts: Vec<Stmt>,
|
pub stmts: Vec<Stmt>,
|
||||||
}
|
}
|
||||||
|
@ -444,34 +444,29 @@ pub type IdleArgs = InitArgs;
|
||||||
|
|
||||||
impl Idle {
|
impl Idle {
|
||||||
fn check(args: IdleArgs, item: ItemFn) -> parse::Result<Self> {
|
fn check(args: IdleArgs, item: ItemFn) -> parse::Result<Self> {
|
||||||
let valid_signature = item.vis == Visibility::Inherited
|
let valid_signature =
|
||||||
&& item.constness.is_none()
|
check_signature(&item) && item.decl.inputs.len() == 1 && is_bottom(&item.decl.output);
|
||||||
&& item.asyncness.is_none()
|
|
||||||
&& item.abi.is_none()
|
|
||||||
&& item.decl.generics.params.is_empty()
|
|
||||||
&& item.decl.generics.where_clause.is_none()
|
|
||||||
&& item.decl.inputs.is_empty()
|
|
||||||
&& item.decl.variadic.is_none()
|
|
||||||
&& is_bottom(&item.decl.output);
|
|
||||||
|
|
||||||
let span = item.span();
|
let span = item.span();
|
||||||
|
|
||||||
if !valid_signature {
|
if valid_signature {
|
||||||
return Err(parse::Error::new(
|
if let Some((context, _)) = check_inputs(item.decl.inputs, "idle") {
|
||||||
span,
|
let (statics, stmts) = extract_statics(item.block.stmts);
|
||||||
"`idle` must have type signature `[unsafe] fn() -> !`",
|
|
||||||
));
|
return Ok(Idle {
|
||||||
|
args,
|
||||||
|
attrs: item.attrs,
|
||||||
|
context,
|
||||||
|
statics: Static::parse(statics)?,
|
||||||
|
stmts,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let (statics, stmts) = extract_statics(item.block.stmts);
|
Err(parse::Error::new(
|
||||||
|
span,
|
||||||
Ok(Idle {
|
"`idle` must have type signature `fn(idle::Context) -> !`",
|
||||||
args,
|
))
|
||||||
attrs: item.attrs,
|
|
||||||
unsafety: item.unsafety,
|
|
||||||
statics: Static::parse(statics)?,
|
|
||||||
stmts,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -596,34 +591,21 @@ impl Parse for InitArgs {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO remove in v0.5.x
|
|
||||||
pub struct Assign {
|
|
||||||
pub attrs: Vec<Attribute>,
|
|
||||||
pub left: Ident,
|
|
||||||
pub right: Box<Expr>,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Init {
|
pub struct Init {
|
||||||
pub args: InitArgs,
|
pub args: InitArgs,
|
||||||
pub attrs: Vec<Attribute>,
|
pub attrs: Vec<Attribute>,
|
||||||
pub unsafety: Option<Token![unsafe]>,
|
|
||||||
pub statics: BTreeMap<Ident, Static>,
|
pub statics: BTreeMap<Ident, Static>,
|
||||||
|
pub context: Pat,
|
||||||
pub stmts: Vec<Stmt>,
|
pub stmts: Vec<Stmt>,
|
||||||
// TODO remove in v0.5.x
|
|
||||||
pub assigns: Vec<Assign>,
|
|
||||||
pub returns_late_resources: bool,
|
pub returns_late_resources: bool,
|
||||||
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Init {
|
impl Init {
|
||||||
fn check(args: InitArgs, item: ItemFn) -> parse::Result<Self> {
|
fn check(args: InitArgs, item: ItemFn) -> parse::Result<Self> {
|
||||||
let mut valid_signature = item.vis == Visibility::Inherited
|
let mut valid_signature = check_signature(&item) && item.decl.inputs.len() == 1;
|
||||||
&& item.constness.is_none()
|
|
||||||
&& item.asyncness.is_none()
|
const DONT_CARE: bool = false;
|
||||||
&& item.abi.is_none()
|
|
||||||
&& item.decl.generics.params.is_empty()
|
|
||||||
&& item.decl.generics.where_clause.is_none()
|
|
||||||
&& item.decl.inputs.is_empty()
|
|
||||||
&& item.decl.variadic.is_none();
|
|
||||||
|
|
||||||
let returns_late_resources = match &item.decl.output {
|
let returns_late_resources = match &item.decl.output {
|
||||||
ReturnType::Default => false,
|
ReturnType::Default => false,
|
||||||
|
@ -636,36 +618,25 @@ impl Init {
|
||||||
} else {
|
} else {
|
||||||
valid_signature = false;
|
valid_signature = false;
|
||||||
|
|
||||||
false // don't care
|
DONT_CARE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Type::Path(p) => {
|
Type::Path(_) => {
|
||||||
let mut segments = p.path.segments.iter();
|
if is_path(ty, &["init", "LateResources"]) {
|
||||||
if p.qself.is_none()
|
|
||||||
&& p.path.leading_colon.is_none()
|
|
||||||
&& p.path.segments.len() == 2
|
|
||||||
&& segments.next().map(|s| {
|
|
||||||
s.arguments == PathArguments::None && s.ident.to_string() == "init"
|
|
||||||
}) == Some(true)
|
|
||||||
&& segments.next().map(|s| {
|
|
||||||
s.arguments == PathArguments::None
|
|
||||||
&& s.ident.to_string() == "LateResources"
|
|
||||||
}) == Some(true)
|
|
||||||
{
|
|
||||||
// -> init::LateResources
|
// -> init::LateResources
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
valid_signature = false;
|
valid_signature = false;
|
||||||
|
|
||||||
false // don't care
|
DONT_CARE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => {
|
_ => {
|
||||||
valid_signature = false;
|
valid_signature = false;
|
||||||
|
|
||||||
false // don't care
|
DONT_CARE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -673,29 +644,26 @@ impl Init {
|
||||||
|
|
||||||
let span = item.span();
|
let span = item.span();
|
||||||
|
|
||||||
if !valid_signature {
|
if valid_signature {
|
||||||
return Err(parse::Error::new(
|
if let Some((context, _)) = check_inputs(item.decl.inputs, "init") {
|
||||||
span,
|
let (statics, stmts) = extract_statics(item.block.stmts);
|
||||||
"`init` must have type signature `[unsafe] fn() [-> init::LateResources]`",
|
|
||||||
));
|
return Ok(Init {
|
||||||
|
args,
|
||||||
|
attrs: item.attrs,
|
||||||
|
statics: Static::parse(statics)?,
|
||||||
|
context,
|
||||||
|
stmts,
|
||||||
|
returns_late_resources,
|
||||||
|
span,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let (statics, stmts) = extract_statics(item.block.stmts);
|
Err(parse::Error::new(
|
||||||
let (stmts, assigns) = if returns_late_resources {
|
span,
|
||||||
(stmts, vec![])
|
"`init` must have type signature `fn(init::Context) [-> init::LateResources]`",
|
||||||
} else {
|
))
|
||||||
extract_assignments(stmts)
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(Init {
|
|
||||||
args,
|
|
||||||
attrs: item.attrs,
|
|
||||||
unsafety: item.unsafety,
|
|
||||||
statics: Static::parse(statics)?,
|
|
||||||
stmts,
|
|
||||||
assigns,
|
|
||||||
returns_late_resources,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -725,8 +693,8 @@ impl Default for Args {
|
||||||
pub struct Exception {
|
pub struct Exception {
|
||||||
pub args: ExceptionArgs,
|
pub args: ExceptionArgs,
|
||||||
pub attrs: Vec<Attribute>,
|
pub attrs: Vec<Attribute>,
|
||||||
pub unsafety: Option<Token![unsafe]>,
|
|
||||||
pub statics: BTreeMap<Ident, Static>,
|
pub statics: BTreeMap<Ident, Static>,
|
||||||
|
pub context: Pat,
|
||||||
pub stmts: Vec<Stmt>,
|
pub stmts: Vec<Stmt>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -770,61 +738,67 @@ impl Parse for ExceptionArgs {
|
||||||
|
|
||||||
impl Exception {
|
impl Exception {
|
||||||
fn check(args: ExceptionArgs, item: ItemFn) -> parse::Result<Self> {
|
fn check(args: ExceptionArgs, item: ItemFn) -> parse::Result<Self> {
|
||||||
let valid_signature = item.vis == Visibility::Inherited
|
let valid_signature =
|
||||||
&& item.constness.is_none()
|
check_signature(&item) && item.decl.inputs.len() == 1 && is_unit(&item.decl.output);
|
||||||
&& item.asyncness.is_none()
|
|
||||||
&& item.abi.is_none()
|
|
||||||
&& item.decl.generics.params.is_empty()
|
|
||||||
&& item.decl.generics.where_clause.is_none()
|
|
||||||
&& item.decl.inputs.is_empty()
|
|
||||||
&& item.decl.variadic.is_none()
|
|
||||||
&& is_unit(&item.decl.output);
|
|
||||||
|
|
||||||
if !valid_signature {
|
let span = item.span();
|
||||||
return Err(parse::Error::new(
|
|
||||||
item.span(),
|
|
||||||
"`exception` handlers must have type signature `[unsafe] fn()`",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
let span = item.ident.span();
|
let name = item.ident.to_string();
|
||||||
match &*args.binds.as_ref().unwrap_or(&item.ident).to_string() {
|
if valid_signature {
|
||||||
"MemoryManagement" | "BusFault" | "UsageFault" | "SecureFault" | "SVCall"
|
if let Some((context, _)) = check_inputs(item.decl.inputs, &name) {
|
||||||
| "DebugMonitor" | "PendSV" => {} // OK
|
let span = item.ident.span();
|
||||||
"SysTick" => {
|
match &*args
|
||||||
if cfg!(feature = "timer-queue") {
|
.binds
|
||||||
return Err(parse::Error::new(
|
.as_ref()
|
||||||
|
.map(|ident| ident.to_string())
|
||||||
|
.unwrap_or(name)
|
||||||
|
{
|
||||||
|
"MemoryManagement" | "BusFault" | "UsageFault" | "SecureFault" | "SVCall"
|
||||||
|
| "DebugMonitor" | "PendSV" => {} // OK
|
||||||
|
"SysTick" => {
|
||||||
|
if cfg!(feature = "timer-queue") {
|
||||||
|
return Err(parse::Error::new(
|
||||||
|
span,
|
||||||
|
"the `SysTick` exception can't be used because it's used by \
|
||||||
|
the runtime when the `timer-queue` feature is enabled",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return Err(parse::Error::new(
|
||||||
span,
|
span,
|
||||||
"the `SysTick` exception can't be used because it's used by \
|
"only exceptions with configurable priority can be used as hardware tasks",
|
||||||
the runtime when the `timer-queue` feature is enabled",
|
|
||||||
));
|
));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
_ => {
|
let (statics, stmts) = extract_statics(item.block.stmts);
|
||||||
return Err(parse::Error::new(
|
|
||||||
span,
|
return Ok(Exception {
|
||||||
"only exceptions with configurable priority can be used as hardware tasks",
|
args,
|
||||||
));
|
attrs: item.attrs,
|
||||||
|
statics: Static::parse(statics)?,
|
||||||
|
context,
|
||||||
|
stmts,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let (statics, stmts) = extract_statics(item.block.stmts);
|
Err(parse::Error::new(
|
||||||
|
span,
|
||||||
Ok(Exception {
|
&format!(
|
||||||
args,
|
"this `exception` handler must have type signature `fn({}::Context)`",
|
||||||
attrs: item.attrs,
|
name
|
||||||
unsafety: item.unsafety,
|
),
|
||||||
statics: Static::parse(statics)?,
|
))
|
||||||
stmts,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Interrupt {
|
pub struct Interrupt {
|
||||||
pub args: InterruptArgs,
|
pub args: InterruptArgs,
|
||||||
pub attrs: Vec<Attribute>,
|
pub attrs: Vec<Attribute>,
|
||||||
pub unsafety: Option<Token![unsafe]>,
|
|
||||||
pub statics: BTreeMap<Ident, Static>,
|
pub statics: BTreeMap<Ident, Static>,
|
||||||
|
pub context: Pat,
|
||||||
pub stmts: Vec<Stmt>,
|
pub stmts: Vec<Stmt>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -832,49 +806,47 @@ pub type InterruptArgs = ExceptionArgs;
|
||||||
|
|
||||||
impl Interrupt {
|
impl Interrupt {
|
||||||
fn check(args: InterruptArgs, item: ItemFn) -> parse::Result<Self> {
|
fn check(args: InterruptArgs, item: ItemFn) -> parse::Result<Self> {
|
||||||
let valid_signature = item.vis == Visibility::Inherited
|
let valid_signature =
|
||||||
&& item.constness.is_none()
|
check_signature(&item) && item.decl.inputs.len() == 1 && is_unit(&item.decl.output);
|
||||||
&& item.asyncness.is_none()
|
|
||||||
&& item.abi.is_none()
|
|
||||||
&& item.decl.generics.params.is_empty()
|
|
||||||
&& item.decl.generics.where_clause.is_none()
|
|
||||||
&& item.decl.inputs.is_empty()
|
|
||||||
&& item.decl.variadic.is_none()
|
|
||||||
&& is_unit(&item.decl.output);
|
|
||||||
|
|
||||||
let span = item.span();
|
let span = item.span();
|
||||||
|
|
||||||
if !valid_signature {
|
let name = item.ident.to_string();
|
||||||
return Err(parse::Error::new(
|
if valid_signature {
|
||||||
span,
|
if let Some((context, _)) = check_inputs(item.decl.inputs, &name) {
|
||||||
"`interrupt` handlers must have type signature `[unsafe] fn()`",
|
match &*name {
|
||||||
));
|
"init" | "idle" | "resources" => {
|
||||||
}
|
return Err(parse::Error::new(
|
||||||
|
span,
|
||||||
|
"`interrupt` handlers can NOT be named `idle`, `init` or `resources`",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
match &*item.ident.to_string() {
|
let (statics, stmts) = extract_statics(item.block.stmts);
|
||||||
"init" | "idle" | "resources" => {
|
|
||||||
return Err(parse::Error::new(
|
return Ok(Interrupt {
|
||||||
span,
|
args,
|
||||||
"`interrupt` handlers can NOT be named `idle`, `init` or `resources`",
|
attrs: item.attrs,
|
||||||
));
|
statics: Static::parse(statics)?,
|
||||||
|
context,
|
||||||
|
stmts,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let (statics, stmts) = extract_statics(item.block.stmts);
|
Err(parse::Error::new(
|
||||||
|
span,
|
||||||
Ok(Interrupt {
|
format!(
|
||||||
args,
|
"this `interrupt` handler must have type signature `fn({}::Context)`",
|
||||||
attrs: item.attrs,
|
name
|
||||||
unsafety: item.unsafety,
|
),
|
||||||
statics: Static::parse(statics)?,
|
))
|
||||||
stmts,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Resource {
|
pub struct Resource {
|
||||||
pub singleton: bool,
|
|
||||||
pub cfgs: Vec<Attribute>,
|
pub cfgs: Vec<Attribute>,
|
||||||
pub attrs: Vec<Attribute>,
|
pub attrs: Vec<Attribute>,
|
||||||
pub mutability: Option<Token![mut]>,
|
pub mutability: Option<Token![mut]>,
|
||||||
|
@ -883,7 +855,7 @@ pub struct Resource {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Resource {
|
impl Resource {
|
||||||
fn check(mut item: ItemStatic) -> parse::Result<Resource> {
|
fn check(item: ItemStatic) -> parse::Result<Resource> {
|
||||||
if item.vis != Visibility::Inherited {
|
if item.vis != Visibility::Inherited {
|
||||||
return Err(parse::Error::new(
|
return Err(parse::Error::new(
|
||||||
item.span(),
|
item.span(),
|
||||||
|
@ -896,19 +868,9 @@ impl Resource {
|
||||||
_ => false,
|
_ => false,
|
||||||
};
|
};
|
||||||
|
|
||||||
let pos = item.attrs.iter().position(|attr| eq(attr, "Singleton"));
|
|
||||||
|
|
||||||
if let Some(pos) = pos {
|
|
||||||
item.attrs[pos].path.segments.insert(
|
|
||||||
0,
|
|
||||||
PathSegment::from(Ident::new("owned_singleton", Span::call_site())),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
let (cfgs, attrs) = extract_cfgs(item.attrs);
|
let (cfgs, attrs) = extract_cfgs(item.attrs);
|
||||||
|
|
||||||
Ok(Resource {
|
Ok(Resource {
|
||||||
singleton: pos.is_some(),
|
|
||||||
cfgs,
|
cfgs,
|
||||||
attrs,
|
attrs,
|
||||||
mutability: item.mutability,
|
mutability: item.mutability,
|
||||||
|
@ -1177,66 +1139,61 @@ pub struct Task {
|
||||||
pub args: TaskArgs,
|
pub args: TaskArgs,
|
||||||
pub cfgs: Vec<Attribute>,
|
pub cfgs: Vec<Attribute>,
|
||||||
pub attrs: Vec<Attribute>,
|
pub attrs: Vec<Attribute>,
|
||||||
pub unsafety: Option<Token![unsafe]>,
|
|
||||||
pub inputs: Vec<ArgCaptured>,
|
pub inputs: Vec<ArgCaptured>,
|
||||||
|
pub context: Pat,
|
||||||
pub statics: BTreeMap<Ident, Static>,
|
pub statics: BTreeMap<Ident, Static>,
|
||||||
pub stmts: Vec<Stmt>,
|
pub stmts: Vec<Stmt>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Task {
|
impl Task {
|
||||||
fn check(args: TaskArgs, item: ItemFn) -> parse::Result<Self> {
|
fn check(args: TaskArgs, item: ItemFn) -> parse::Result<Self> {
|
||||||
let valid_signature = item.vis == Visibility::Inherited
|
let valid_signature =
|
||||||
&& item.constness.is_none()
|
check_signature(&item) && !item.decl.inputs.is_empty() && is_unit(&item.decl.output);
|
||||||
&& item.asyncness.is_none()
|
|
||||||
&& item.abi.is_none()
|
|
||||||
&& item.decl.generics.params.is_empty()
|
|
||||||
&& item.decl.generics.where_clause.is_none()
|
|
||||||
&& item.decl.variadic.is_none()
|
|
||||||
&& is_unit(&item.decl.output);
|
|
||||||
|
|
||||||
let span = item.span();
|
let span = item.span();
|
||||||
|
|
||||||
if !valid_signature {
|
let name = item.ident.to_string();
|
||||||
return Err(parse::Error::new(
|
if valid_signature {
|
||||||
span,
|
if let Some((context, rest)) = check_inputs(item.decl.inputs, &name) {
|
||||||
"`task` handlers must have type signature `[unsafe] fn(..)`",
|
let (statics, stmts) = extract_statics(item.block.stmts);
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
let (statics, stmts) = extract_statics(item.block.stmts);
|
let inputs = rest.map_err(|arg| {
|
||||||
|
parse::Error::new(
|
||||||
|
arg.span(),
|
||||||
|
"inputs must be named arguments (e.f. `foo: u32`) and not include `self`",
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
|
||||||
let mut inputs = vec![];
|
match &*name {
|
||||||
for input in item.decl.inputs {
|
"init" | "idle" | "resources" => {
|
||||||
if let FnArg::Captured(capture) = input {
|
return Err(parse::Error::new(
|
||||||
inputs.push(capture);
|
span,
|
||||||
} else {
|
"`task` handlers can NOT be named `idle`, `init` or `resources`",
|
||||||
return Err(parse::Error::new(
|
));
|
||||||
span,
|
}
|
||||||
"inputs must be named arguments (e.f. `foo: u32`) and not include `self`",
|
_ => {}
|
||||||
));
|
}
|
||||||
|
|
||||||
|
let (cfgs, attrs) = extract_cfgs(item.attrs);
|
||||||
|
return Ok(Task {
|
||||||
|
args,
|
||||||
|
cfgs,
|
||||||
|
attrs,
|
||||||
|
inputs,
|
||||||
|
context,
|
||||||
|
statics: Static::parse(statics)?,
|
||||||
|
stmts,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
match &*item.ident.to_string() {
|
Err(parse::Error::new(
|
||||||
"init" | "idle" | "resources" => {
|
span,
|
||||||
return Err(parse::Error::new(
|
&format!(
|
||||||
span,
|
"this `task` handler must have type signature `fn({}::Context, ..)`",
|
||||||
"`task` handlers can NOT be named `idle`, `init` or `resources`",
|
name
|
||||||
));
|
),
|
||||||
}
|
))
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
|
|
||||||
let (cfgs, attrs) = extract_cfgs(item.attrs);
|
|
||||||
Ok(Task {
|
|
||||||
args,
|
|
||||||
cfgs,
|
|
||||||
attrs,
|
|
||||||
unsafety: item.unsafety,
|
|
||||||
inputs,
|
|
||||||
statics: Static::parse(statics)?,
|
|
||||||
stmts,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1335,38 +1292,69 @@ fn extract_statics(stmts: Vec<Stmt>) -> (Statics, Vec<Stmt>) {
|
||||||
(statics, stmts)
|
(statics, stmts)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO remove in v0.5.x
|
// checks that the list of arguments has the form `#pat: #name::Context, (..)`
|
||||||
fn extract_assignments(stmts: Vec<Stmt>) -> (Vec<Stmt>, Vec<Assign>) {
|
//
|
||||||
let mut istmts = stmts.into_iter().rev();
|
// if the check succeeds it returns `#pat` plus the remaining arguments
|
||||||
|
fn check_inputs(
|
||||||
|
inputs: Punctuated<FnArg, Token![,]>,
|
||||||
|
name: &str,
|
||||||
|
) -> Option<(Pat, Result<Vec<ArgCaptured>, FnArg>)> {
|
||||||
|
let mut inputs = inputs.into_iter();
|
||||||
|
|
||||||
let mut assigns = vec![];
|
match inputs.next() {
|
||||||
let mut stmts = vec![];
|
Some(FnArg::Captured(first)) => {
|
||||||
while let Some(stmt) = istmts.next() {
|
if is_path(&first.ty, &[name, "Context"]) {
|
||||||
match stmt {
|
let rest = inputs
|
||||||
Stmt::Semi(Expr::Assign(assign), semi) => {
|
.map(|arg| match arg {
|
||||||
if let Expr::Path(ref expr) = *assign.left {
|
FnArg::Captured(arg) => Ok(arg),
|
||||||
if expr.path.segments.len() == 1 {
|
_ => Err(arg),
|
||||||
assigns.push(Assign {
|
})
|
||||||
attrs: assign.attrs,
|
.collect::<Result<Vec<_>, _>>();
|
||||||
left: expr.path.segments[0].ident.clone(),
|
|
||||||
right: assign.right,
|
|
||||||
});
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
stmts.push(Stmt::Semi(Expr::Assign(assign), semi));
|
Some((first.pat, rest))
|
||||||
}
|
} else {
|
||||||
_ => {
|
None
|
||||||
stmts.push(stmt);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_ => None,
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
stmts.extend(istmts);
|
/// checks that a function signature
|
||||||
|
///
|
||||||
|
/// - has no bounds (like where clauses)
|
||||||
|
/// - is not `async`
|
||||||
|
/// - is not `const`
|
||||||
|
/// - is not `unsafe`
|
||||||
|
/// - is not generic (has no type parametrs)
|
||||||
|
/// - is not variadic
|
||||||
|
/// - uses the Rust ABI (and not e.g. "C")
|
||||||
|
fn check_signature(item: &ItemFn) -> bool {
|
||||||
|
item.vis == Visibility::Inherited
|
||||||
|
&& item.constness.is_none()
|
||||||
|
&& item.asyncness.is_none()
|
||||||
|
&& item.abi.is_none()
|
||||||
|
&& item.unsafety.is_none()
|
||||||
|
&& item.decl.generics.params.is_empty()
|
||||||
|
&& item.decl.generics.where_clause.is_none()
|
||||||
|
&& item.decl.variadic.is_none()
|
||||||
|
}
|
||||||
|
|
||||||
(stmts.into_iter().rev().collect(), assigns)
|
fn is_path(ty: &Type, segments: &[&str]) -> bool {
|
||||||
|
match ty {
|
||||||
|
Type::Path(tpath) if tpath.qself.is_none() => {
|
||||||
|
tpath.path.segments.len() == segments.len()
|
||||||
|
&& tpath
|
||||||
|
.path
|
||||||
|
.segments
|
||||||
|
.iter()
|
||||||
|
.zip(segments)
|
||||||
|
.all(|(lhs, rhs)| lhs.ident == **rhs)
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_bottom(ty: &ReturnType) -> bool {
|
fn is_bottom(ty: &ReturnType) -> bool {
|
||||||
|
|
113
src/export.rs
113
src/export.rs
|
@ -1,7 +1,5 @@
|
||||||
//! IMPLEMENTATION DETAILS. DO NOT USE ANYTHING IN THIS MODULE
|
//! IMPLEMENTATION DETAILS. DO NOT USE ANYTHING IN THIS MODULE
|
||||||
|
|
||||||
#[cfg(not(feature = "nightly"))]
|
|
||||||
use core::ptr;
|
|
||||||
use core::{cell::Cell, u8};
|
use core::{cell::Cell, u8};
|
||||||
|
|
||||||
#[cfg(armv7m)]
|
#[cfg(armv7m)]
|
||||||
|
@ -14,25 +12,31 @@ pub use heapless::consts;
|
||||||
use heapless::spsc::{Queue, SingleCore};
|
use heapless::spsc::{Queue, SingleCore};
|
||||||
|
|
||||||
#[cfg(feature = "timer-queue")]
|
#[cfg(feature = "timer-queue")]
|
||||||
pub use crate::tq::{isr as sys_tick, NotReady, TimerQueue};
|
pub use crate::tq::{NotReady, TimerQueue};
|
||||||
|
|
||||||
pub type FreeQueue<N> = Queue<u8, N, usize, SingleCore>;
|
pub type FreeQueue<N> = Queue<u8, N, u8, SingleCore>;
|
||||||
pub type ReadyQueue<T, N> = Queue<(T, u8), N, usize, SingleCore>;
|
pub type ReadyQueue<T, N> = Queue<(T, u8), N, u8, SingleCore>;
|
||||||
|
|
||||||
#[cfg(armv7m)]
|
#[cfg(armv7m)]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn run<F>(f: F)
|
pub fn run<F>(priority: u8, f: F)
|
||||||
where
|
where
|
||||||
F: FnOnce(),
|
F: FnOnce(),
|
||||||
{
|
{
|
||||||
let initial = basepri::read();
|
if priority == 1 {
|
||||||
f();
|
// if the priority of this interrupt is `1` then BASEPRI can only be `0`
|
||||||
unsafe { basepri::write(initial) }
|
f();
|
||||||
|
unsafe { basepri::write(0) }
|
||||||
|
} else {
|
||||||
|
let initial = basepri::read();
|
||||||
|
f();
|
||||||
|
unsafe { basepri::write(initial) }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(armv7m))]
|
#[cfg(not(armv7m))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn run<F>(f: F)
|
pub fn run<F>(_priority: u8, f: F)
|
||||||
where
|
where
|
||||||
F: FnOnce(),
|
F: FnOnce(),
|
||||||
{
|
{
|
||||||
|
@ -52,7 +56,7 @@ impl Priority {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// these two methods are used by claim (see below) but can't be used from the RTFM application
|
// these two methods are used by `lock` (see below) but can't be used from the RTFM application
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn set(&self, value: u8) {
|
fn set(&self, value: u8) {
|
||||||
self.inner.set(value)
|
self.inner.set(value)
|
||||||
|
@ -64,13 +68,12 @@ impl Priority {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "nightly")]
|
// We newtype `core::mem::MaybeUninit` so the end-user doesn't need `#![feature(maybe_uninit)]` in
|
||||||
|
// their code
|
||||||
pub struct MaybeUninit<T> {
|
pub struct MaybeUninit<T> {
|
||||||
// we newtype so the end-user doesn't need `#![feature(maybe_uninit)]` in their code
|
|
||||||
inner: core::mem::MaybeUninit<T>,
|
inner: core::mem::MaybeUninit<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "nightly")]
|
|
||||||
impl<T> MaybeUninit<T> {
|
impl<T> MaybeUninit<T> {
|
||||||
pub const fn uninit() -> Self {
|
pub const fn uninit() -> Self {
|
||||||
MaybeUninit {
|
MaybeUninit {
|
||||||
|
@ -86,64 +89,15 @@ impl<T> MaybeUninit<T> {
|
||||||
self.inner.as_mut_ptr()
|
self.inner.as_mut_ptr()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub unsafe fn read(&self) -> T {
|
||||||
|
self.inner.read()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn write(&mut self, value: T) -> &mut T {
|
pub fn write(&mut self, value: T) -> &mut T {
|
||||||
self.inner.write(value)
|
self.inner.write(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "nightly"))]
|
|
||||||
pub struct MaybeUninit<T> {
|
|
||||||
value: Option<T>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(feature = "nightly"))]
|
|
||||||
const MSG: &str =
|
|
||||||
"you have hit a bug (UB) in RTFM implementation; try enabling this crate 'nightly' feature";
|
|
||||||
|
|
||||||
#[cfg(not(feature = "nightly"))]
|
|
||||||
impl<T> MaybeUninit<T> {
|
|
||||||
pub const fn uninit() -> Self {
|
|
||||||
MaybeUninit { value: None }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn as_ptr(&self) -> *const T {
|
|
||||||
if let Some(x) = self.value.as_ref() {
|
|
||||||
x
|
|
||||||
} else {
|
|
||||||
unreachable!(MSG)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn as_mut_ptr(&mut self) -> *mut T {
|
|
||||||
if let Some(x) = self.value.as_mut() {
|
|
||||||
x
|
|
||||||
} else {
|
|
||||||
unreachable!(MSG)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub unsafe fn get_ref(&self) -> &T {
|
|
||||||
if let Some(x) = self.value.as_ref() {
|
|
||||||
x
|
|
||||||
} else {
|
|
||||||
unreachable!(MSG)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub unsafe fn get_mut(&mut self) -> &mut T {
|
|
||||||
if let Some(x) = self.value.as_mut() {
|
|
||||||
x
|
|
||||||
} else {
|
|
||||||
unreachable!(MSG)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn write(&mut self, val: T) {
|
|
||||||
// NOTE(volatile) we have observed UB when this uses a plain `ptr::write`
|
|
||||||
unsafe { ptr::write_volatile(&mut self.value, Some(val)) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn assert_send<T>()
|
pub fn assert_send<T>()
|
||||||
where
|
where
|
||||||
|
@ -160,19 +114,16 @@ where
|
||||||
|
|
||||||
#[cfg(armv7m)]
|
#[cfg(armv7m)]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub unsafe fn claim<T, R, F>(
|
pub unsafe fn lock<T, R>(
|
||||||
ptr: *mut T,
|
ptr: *mut T,
|
||||||
priority: &Priority,
|
priority: &Priority,
|
||||||
ceiling: u8,
|
ceiling: u8,
|
||||||
nvic_prio_bits: u8,
|
nvic_prio_bits: u8,
|
||||||
f: F,
|
f: impl FnOnce(&mut T) -> R,
|
||||||
) -> R
|
) -> R {
|
||||||
where
|
|
||||||
F: FnOnce(&mut T) -> R,
|
|
||||||
{
|
|
||||||
let current = priority.get();
|
let current = priority.get();
|
||||||
|
|
||||||
if priority.get() < ceiling {
|
if current < ceiling {
|
||||||
if ceiling == (1 << nvic_prio_bits) {
|
if ceiling == (1 << nvic_prio_bits) {
|
||||||
priority.set(u8::MAX);
|
priority.set(u8::MAX);
|
||||||
let r = interrupt::free(|_| f(&mut *ptr));
|
let r = interrupt::free(|_| f(&mut *ptr));
|
||||||
|
@ -193,19 +144,16 @@ where
|
||||||
|
|
||||||
#[cfg(not(armv7m))]
|
#[cfg(not(armv7m))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub unsafe fn claim<T, R, F>(
|
pub unsafe fn lock<T, R>(
|
||||||
ptr: *mut T,
|
ptr: *mut T,
|
||||||
priority: &Priority,
|
priority: &Priority,
|
||||||
ceiling: u8,
|
ceiling: u8,
|
||||||
_nvic_prio_bits: u8,
|
_nvic_prio_bits: u8,
|
||||||
f: F,
|
f: impl FnOnce(&mut T) -> R,
|
||||||
) -> R
|
) -> R {
|
||||||
where
|
|
||||||
F: FnOnce(&mut T) -> R,
|
|
||||||
{
|
|
||||||
let current = priority.get();
|
let current = priority.get();
|
||||||
|
|
||||||
if priority.get() < ceiling {
|
if current < ceiling {
|
||||||
priority.set(u8::MAX);
|
priority.set(u8::MAX);
|
||||||
let r = interrupt::free(|_| f(&mut *ptr));
|
let r = interrupt::free(|_| f(&mut *ptr));
|
||||||
priority.set(current);
|
priority.set(current);
|
||||||
|
@ -215,8 +163,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(armv7m)]
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn logical2hw(logical: u8, nvic_prio_bits: u8) -> u8 {
|
pub fn logical2hw(logical: u8, nvic_prio_bits: u8) -> u8 {
|
||||||
((1 << nvic_prio_bits) - logical) << (8 - nvic_prio_bits)
|
((1 << nvic_prio_bits) - logical) << (8 - nvic_prio_bits)
|
||||||
}
|
}
|
||||||
|
|
32
src/lib.rs
32
src/lib.rs
|
@ -1,5 +1,8 @@
|
||||||
//! Real Time For the Masses (RTFM) framework for ARM Cortex-M microcontrollers
|
//! Real Time For the Masses (RTFM) framework for ARM Cortex-M microcontrollers
|
||||||
//!
|
//!
|
||||||
|
//! **HEADS UP** This is an **alpha** pre-release; there may be breaking changes in the API and
|
||||||
|
//! semantics before a proper release is made.
|
||||||
|
//!
|
||||||
//! **IMPORTANT**: This crate is published as [`cortex-m-rtfm`] on crates.io but the name of the
|
//! **IMPORTANT**: This crate is published as [`cortex-m-rtfm`] on crates.io but the name of the
|
||||||
//! library is `rtfm`.
|
//! library is `rtfm`.
|
||||||
//!
|
//!
|
||||||
|
@ -7,7 +10,7 @@
|
||||||
//!
|
//!
|
||||||
//! The user level documentation can be found [here].
|
//! The user level documentation can be found [here].
|
||||||
//!
|
//!
|
||||||
//! [here]: https://japaric.github.io/cortex-m-rtfm/book/en/
|
//! [here]: https://japaric.github.io/rtfm5/book/en/
|
||||||
//!
|
//!
|
||||||
//! Don't forget to check the documentation of the [`#[app]`] attribute, which is the main component
|
//! Don't forget to check the documentation of the [`#[app]`] attribute, which is the main component
|
||||||
//! of the framework.
|
//! of the framework.
|
||||||
|
@ -16,7 +19,7 @@
|
||||||
//!
|
//!
|
||||||
//! # Minimum Supported Rust Version (MSRV)
|
//! # Minimum Supported Rust Version (MSRV)
|
||||||
//!
|
//!
|
||||||
//! This crate is guaranteed to compile on stable Rust 1.31 (2018 edition) and up. It *might*
|
//! This crate is guaranteed to compile on stable Rust 1.36 (2018 edition) and up. It *might*
|
||||||
//! compile on older versions but that may change in any new patch release.
|
//! compile on older versions but that may change in any new patch release.
|
||||||
//!
|
//!
|
||||||
//! # Semantic Versioning
|
//! # Semantic Versioning
|
||||||
|
@ -36,12 +39,11 @@
|
||||||
//! [`Instant`]: struct.Instant.html
|
//! [`Instant`]: struct.Instant.html
|
||||||
//! [`Duration`]: struct.Duration.html
|
//! [`Duration`]: struct.Duration.html
|
||||||
//!
|
//!
|
||||||
//! - `nightly`. Enabling this opt-in feature makes RTFM internally use the unstable
|
//! - `nightly`. Enabling this opt-in feature makes RTFM internally use the unstable `const_fn`
|
||||||
//! `core::mem::MaybeUninit` API and unstable `const_fn` language feature to reduce static memory
|
//! language feature to reduce static memory usage, runtime overhead and initialization overhead.
|
||||||
//! usage, runtime overhead and initialization overhead. This feature requires a nightly compiler
|
//! This feature requires a nightly compiler and may stop working at any time!
|
||||||
//! and may stop working at any time!
|
|
||||||
|
|
||||||
#![cfg_attr(feature = "nightly", feature(maybe_uninit))]
|
#![feature(maybe_uninit)]
|
||||||
#![deny(missing_docs)]
|
#![deny(missing_docs)]
|
||||||
#![deny(warnings)]
|
#![deny(warnings)]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
@ -132,7 +134,7 @@ pub struct Instant(i32);
|
||||||
impl Instant {
|
impl Instant {
|
||||||
/// IMPLEMENTATION DETAIL. DO NOT USE
|
/// IMPLEMENTATION DETAIL. DO NOT USE
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub fn artificial(timestamp: i32) -> Self {
|
pub unsafe fn artificial(timestamp: i32) -> Self {
|
||||||
Instant(timestamp)
|
Instant(timestamp)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -290,9 +292,7 @@ pub trait Mutex {
|
||||||
type T;
|
type T;
|
||||||
|
|
||||||
/// Creates a critical section and grants temporary access to the protected data
|
/// Creates a critical section and grants temporary access to the protected data
|
||||||
fn lock<R, F>(&mut self, f: F) -> R
|
fn lock<R>(&mut self, f: impl FnOnce(&mut Self::T) -> R) -> R;
|
||||||
where
|
|
||||||
F: FnOnce(&mut Self::T) -> R;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, M> Mutex for &'a mut M
|
impl<'a, M> Mutex for &'a mut M
|
||||||
|
@ -301,10 +301,7 @@ where
|
||||||
{
|
{
|
||||||
type T = M::T;
|
type T = M::T;
|
||||||
|
|
||||||
fn lock<R, F>(&mut self, f: F) -> R
|
fn lock<R>(&mut self, f: impl FnOnce(&mut M::T) -> R) -> R {
|
||||||
where
|
|
||||||
F: FnOnce(&mut Self::T) -> R,
|
|
||||||
{
|
|
||||||
(**self).lock(f)
|
(**self).lock(f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -317,10 +314,7 @@ pub struct Exclusive<'a, T>(pub &'a mut T);
|
||||||
impl<'a, T> Mutex for Exclusive<'a, T> {
|
impl<'a, T> Mutex for Exclusive<'a, T> {
|
||||||
type T = T;
|
type T = T;
|
||||||
|
|
||||||
fn lock<R, F>(&mut self, f: F) -> R
|
fn lock<R>(&mut self, f: impl FnOnce(&mut T) -> R) -> R {
|
||||||
where
|
|
||||||
F: FnOnce(&mut Self::T) -> R,
|
|
||||||
{
|
|
||||||
f(self.0)
|
f(self.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
78
src/tq.rs
78
src/tq.rs
|
@ -3,7 +3,7 @@ use core::cmp::{self, Ordering};
|
||||||
use cortex_m::peripheral::{SCB, SYST};
|
use cortex_m::peripheral::{SCB, SYST};
|
||||||
use heapless::{binary_heap::Min, ArrayLength, BinaryHeap};
|
use heapless::{binary_heap::Min, ArrayLength, BinaryHeap};
|
||||||
|
|
||||||
use crate::{Instant, Mutex};
|
use crate::Instant;
|
||||||
|
|
||||||
pub struct TimerQueue<T, N>
|
pub struct TimerQueue<T, N>
|
||||||
where
|
where
|
||||||
|
@ -43,11 +43,39 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
// set SysTick pending
|
// set SysTick pending
|
||||||
(*SCB::ptr()).icsr.write(1 << 26);
|
SCB::set_pendst();
|
||||||
}
|
}
|
||||||
|
|
||||||
self.queue.push_unchecked(nr);
|
self.queue.push_unchecked(nr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn dequeue(&mut self) -> Option<(T, u8)> {
|
||||||
|
if let Some(instant) = self.queue.peek().map(|p| p.instant) {
|
||||||
|
let diff = instant.0.wrapping_sub(Instant::now().0);
|
||||||
|
|
||||||
|
if diff < 0 {
|
||||||
|
// task became ready
|
||||||
|
let nr = unsafe { self.queue.pop_unchecked() };
|
||||||
|
|
||||||
|
Some((nr.task, nr.index))
|
||||||
|
} else {
|
||||||
|
// set a new timeout
|
||||||
|
const MAX: u32 = 0x00ffffff;
|
||||||
|
|
||||||
|
self.syst.set_reload(cmp::min(MAX, diff as u32));
|
||||||
|
|
||||||
|
// start counting down from the new reload
|
||||||
|
self.syst.clear_current();
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// the queue is empty
|
||||||
|
self.syst.disable_interrupt();
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct NotReady<T>
|
pub struct NotReady<T>
|
||||||
|
@ -87,49 +115,3 @@ where
|
||||||
Some(self.cmp(&other))
|
Some(self.cmp(&other))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn isr<TQ, T, N, F>(mut tq: TQ, mut f: F)
|
|
||||||
where
|
|
||||||
TQ: Mutex<T = TimerQueue<T, N>>,
|
|
||||||
T: Copy + Send,
|
|
||||||
N: ArrayLength<NotReady<T>>,
|
|
||||||
F: FnMut(T, u8),
|
|
||||||
{
|
|
||||||
loop {
|
|
||||||
// XXX does `#[inline(always)]` improve performance or not?
|
|
||||||
let next = tq.lock(#[inline(always)]
|
|
||||||
|tq| {
|
|
||||||
if let Some(instant) = tq.queue.peek().map(|p| p.instant) {
|
|
||||||
let diff = instant.0.wrapping_sub(Instant::now().0);
|
|
||||||
|
|
||||||
if diff < 0 {
|
|
||||||
// task became ready
|
|
||||||
let m = unsafe { tq.queue.pop_unchecked() };
|
|
||||||
|
|
||||||
Some((m.task, m.index))
|
|
||||||
} else {
|
|
||||||
// set a new timeout
|
|
||||||
const MAX: u32 = 0x00ffffff;
|
|
||||||
|
|
||||||
tq.syst.set_reload(cmp::min(MAX, diff as u32));
|
|
||||||
|
|
||||||
// start counting down from the new reload
|
|
||||||
tq.syst.clear_current();
|
|
||||||
|
|
||||||
None
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// the queue is empty
|
|
||||||
tq.syst.disable_interrupt();
|
|
||||||
None
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if let Some((task, index)) = next {
|
|
||||||
f(task, index)
|
|
||||||
} else {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -30,35 +30,35 @@ const APP: () = {
|
||||||
static S3: u32 = 0;
|
static S3: u32 = 0;
|
||||||
|
|
||||||
#[init(resources = [O1, O4, O5, O6, S3])]
|
#[init(resources = [O1, O4, O5, O6, S3])]
|
||||||
fn init() {
|
fn init(c: init::Context) {
|
||||||
resources.O1; //~ ERROR no field `O1`
|
c.resources.O1; //~ ERROR no field `O1`
|
||||||
resources.O4; //~ ERROR no field `O4`
|
c.resources.O4; //~ ERROR no field `O4`
|
||||||
resources.O5; //~ ERROR no field `O5`
|
c.resources.O5; //~ ERROR no field `O5`
|
||||||
resources.O6; //~ ERROR no field `O6`
|
c.resources.O6; //~ ERROR no field `O6`
|
||||||
resources.S3; //~ ERROR no field `S3`
|
c.resources.S3; //~ ERROR no field `S3`
|
||||||
}
|
}
|
||||||
|
|
||||||
#[idle(resources = [O2, O4, S1, S3])]
|
#[idle(resources = [O2, O4, S1, S3])]
|
||||||
fn idle() -> ! {
|
fn idle(c: idle::Context) -> ! {
|
||||||
resources.O2; //~ ERROR no field `O2`
|
c.resources.O2; //~ ERROR no field `O2`
|
||||||
resources.O4; //~ ERROR no field `O4`
|
c.resources.O4; //~ ERROR no field `O4`
|
||||||
resources.S1; //~ ERROR no field `S1`
|
c.resources.S1; //~ ERROR no field `S1`
|
||||||
resources.S3; //~ ERROR no field `S3`
|
c.resources.S3; //~ ERROR no field `S3`
|
||||||
|
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[interrupt(resources = [O3, S1, S2, S3])]
|
#[interrupt(resources = [O3, S1, S2, S3])]
|
||||||
fn UART0() {
|
fn UART0(c: UART0::Context) {
|
||||||
resources.O3; //~ ERROR no field `O3`
|
c.resources.O3; //~ ERROR no field `O3`
|
||||||
resources.S1; //~ ERROR no field `S1`
|
c.resources.S1; //~ ERROR no field `S1`
|
||||||
resources.S2; //~ ERROR no field `S2`
|
c.resources.S2; //~ ERROR no field `S2`
|
||||||
resources.S3; //~ ERROR no field `S3`
|
c.resources.S3; //~ ERROR no field `S3`
|
||||||
}
|
}
|
||||||
|
|
||||||
#[interrupt(resources = [S2, O5])]
|
#[interrupt(resources = [S2, O5])]
|
||||||
fn UART1() {
|
fn UART1(c: UART1::Context) {
|
||||||
resources.S2; //~ ERROR no field `S2`
|
c.resources.S2; //~ ERROR no field `S2`
|
||||||
resources.O5; //~ ERROR no field `O5`
|
c.resources.O5; //~ ERROR no field `O5`
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -10,7 +10,7 @@ use rtfm::app;
|
||||||
#[app(device = lm3s6965)]
|
#[app(device = lm3s6965)]
|
||||||
const APP: () = {
|
const APP: () = {
|
||||||
#[init]
|
#[init]
|
||||||
fn init() {
|
fn init(_: init::Context) {
|
||||||
#[cfg(never)]
|
#[cfg(never)]
|
||||||
static mut FOO: u32 = 0;
|
static mut FOO: u32 = 0;
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ const APP: () = {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[idle]
|
#[idle]
|
||||||
fn idle() -> ! {
|
fn idle(_: idle::Context) -> ! {
|
||||||
#[cfg(never)]
|
#[cfg(never)]
|
||||||
static mut FOO: u32 = 0;
|
static mut FOO: u32 = 0;
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ const APP: () = {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[exception]
|
#[exception]
|
||||||
fn SVCall() {
|
fn SVCall(_: SVCall::Context) {
|
||||||
#[cfg(never)]
|
#[cfg(never)]
|
||||||
static mut FOO: u32 = 0;
|
static mut FOO: u32 = 0;
|
||||||
|
|
||||||
|
@ -36,7 +36,7 @@ const APP: () = {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[interrupt]
|
#[interrupt]
|
||||||
fn UART0() {
|
fn UART0(_: UART0::Context) {
|
||||||
#[cfg(never)]
|
#[cfg(never)]
|
||||||
static mut FOO: u32 = 0;
|
static mut FOO: u32 = 0;
|
||||||
|
|
||||||
|
@ -44,7 +44,7 @@ const APP: () = {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[task]
|
#[task]
|
||||||
fn foo() {
|
fn foo(_: foo::Context) {
|
||||||
#[cfg(never)]
|
#[cfg(never)]
|
||||||
static mut FOO: u32 = 0;
|
static mut FOO: u32 = 0;
|
||||||
|
|
||||||
|
|
|
@ -10,13 +10,13 @@ use rtfm::app;
|
||||||
#[app(device = lm3s6965)]
|
#[app(device = lm3s6965)]
|
||||||
const APP: () = {
|
const APP: () = {
|
||||||
#[init]
|
#[init]
|
||||||
fn init() {}
|
fn init(_: init::Context) {}
|
||||||
|
|
||||||
#[task(
|
#[task(
|
||||||
priority = 1,
|
priority = 1,
|
||||||
priority = 2, //~ ERROR argument appears more than once
|
priority = 2, //~ ERROR argument appears more than once
|
||||||
)]
|
)]
|
||||||
fn foo() {}
|
fn foo(_: foo::Context) {}
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
fn UART0();
|
fn UART0();
|
||||||
|
|
|
@ -10,13 +10,13 @@ use rtfm::app;
|
||||||
#[app(device = lm3s6965)]
|
#[app(device = lm3s6965)]
|
||||||
const APP: () = {
|
const APP: () = {
|
||||||
#[init]
|
#[init]
|
||||||
fn init() {}
|
fn init(_: init::Context) {}
|
||||||
|
|
||||||
#[task(
|
#[task(
|
||||||
capacity = 1,
|
capacity = 1,
|
||||||
capacity = 2, //~ ERROR argument appears more than once
|
capacity = 2, //~ ERROR argument appears more than once
|
||||||
)]
|
)]
|
||||||
fn foo() {}
|
fn foo(_: foo::Context) {}
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
fn UART0();
|
fn UART0();
|
||||||
|
|
|
@ -1,29 +0,0 @@
|
||||||
#![no_main]
|
|
||||||
#![no_std]
|
|
||||||
|
|
||||||
extern crate lm3s6965;
|
|
||||||
extern crate panic_halt;
|
|
||||||
extern crate rtfm;
|
|
||||||
|
|
||||||
use rtfm::app;
|
|
||||||
|
|
||||||
#[app(device = lm3s6965)]
|
|
||||||
const APP: () = {
|
|
||||||
static mut UNINITIALIZED: bool = ();
|
|
||||||
|
|
||||||
#[init]
|
|
||||||
fn init() {
|
|
||||||
if false {
|
|
||||||
return; //~ ERROR `init` is *not* allowed to early return
|
|
||||||
}
|
|
||||||
|
|
||||||
UNINITIALIZED = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[interrupt(resources = [UNINITIALIZED])]
|
|
||||||
fn UART0() {
|
|
||||||
if resources.UNINITIALIZED {
|
|
||||||
// UB
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
|
@ -1,32 +0,0 @@
|
||||||
#![no_main]
|
|
||||||
#![no_std]
|
|
||||||
|
|
||||||
extern crate lm3s6965;
|
|
||||||
extern crate panic_halt;
|
|
||||||
extern crate rtfm;
|
|
||||||
|
|
||||||
use rtfm::app;
|
|
||||||
|
|
||||||
#[app(device = lm3s6965)]
|
|
||||||
const APP: () = {
|
|
||||||
static mut UNINITIALIZED: bool = ();
|
|
||||||
|
|
||||||
#[init]
|
|
||||||
fn init() {
|
|
||||||
let x = || {
|
|
||||||
// this is OK
|
|
||||||
return 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
return; //~ ERROR `init` is *not* allowed to early return
|
|
||||||
|
|
||||||
UNINITIALIZED = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[interrupt(resources = [UNINITIALIZED])]
|
|
||||||
fn UART0() {
|
|
||||||
if resources.UNINITIALIZED {
|
|
||||||
// UB
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
|
@ -10,11 +10,11 @@ use rtfm::app;
|
||||||
#[app(device = lm3s6965)]
|
#[app(device = lm3s6965)]
|
||||||
const APP: () = {
|
const APP: () = {
|
||||||
#[init]
|
#[init]
|
||||||
fn init() {}
|
fn init(_: init::Context) {}
|
||||||
|
|
||||||
#[exception]
|
#[exception]
|
||||||
fn SVCall() -> ! {
|
fn SVCall(_: SVCall::Context) -> ! {
|
||||||
//~^ ERROR `exception` handlers must have type signature `[unsafe] fn()`
|
//~^ ERROR this `exception` handler must have type signature `fn(SVCall::Context)`
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -10,10 +10,10 @@ use rtfm::app;
|
||||||
#[app(device = lm3s6965)]
|
#[app(device = lm3s6965)]
|
||||||
const APP: () = {
|
const APP: () = {
|
||||||
#[init]
|
#[init]
|
||||||
fn init() {}
|
fn init(_: init::Context) {}
|
||||||
|
|
||||||
#[exception]
|
#[exception]
|
||||||
fn SVCall(undef: u32) {
|
fn SVCall(_: SVCall::Context, undef: u32) {
|
||||||
//~^ ERROR `exception` handlers must have type signature `[unsafe] fn()`
|
//~^ ERROR this `exception` handler must have type signature `fn(SVCall::Context)`
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -10,10 +10,10 @@ use rtfm::app;
|
||||||
#[app(device = lm3s6965)]
|
#[app(device = lm3s6965)]
|
||||||
const APP: () = {
|
const APP: () = {
|
||||||
#[init]
|
#[init]
|
||||||
fn init() {}
|
fn init(_: init::Context) {}
|
||||||
|
|
||||||
#[exception]
|
#[exception]
|
||||||
fn NonMaskableInt() {
|
fn NonMaskableInt(_: NonMaskableInt::Context) {
|
||||||
//~^ ERROR only exceptions with configurable priority can be used as hardware tasks
|
//~^ ERROR only exceptions with configurable priority can be used as hardware tasks
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -10,11 +10,11 @@ use rtfm::app;
|
||||||
#[app(device = lm3s6965)]
|
#[app(device = lm3s6965)]
|
||||||
const APP: () = {
|
const APP: () = {
|
||||||
#[init]
|
#[init]
|
||||||
fn init() {}
|
fn init(_: init::Context) {}
|
||||||
|
|
||||||
#[exception]
|
#[exception]
|
||||||
fn SVCall() -> u32 {
|
fn SVCall(_: SVCall::Context) -> u32 {
|
||||||
//~^ ERROR `exception` handlers must have type signature `[unsafe] fn()`
|
//~^ ERROR this `exception` handler must have type signature `fn(SVCall::Context)`
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -10,10 +10,10 @@ use rtfm::app;
|
||||||
#[app(device = lm3s6965)]
|
#[app(device = lm3s6965)]
|
||||||
const APP: () = {
|
const APP: () = {
|
||||||
#[init]
|
#[init]
|
||||||
fn init() {}
|
fn init(_: init::Context) {}
|
||||||
|
|
||||||
#[exception]
|
#[exception]
|
||||||
fn SysTick() {
|
fn SysTick(_: SysTick::Context) {
|
||||||
//~^ ERROR the `SysTick` exception can't be used because it's used by the runtime
|
//~^ ERROR the `SysTick` exception can't be used because it's used by the runtime
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -10,10 +10,10 @@ use rtfm::app;
|
||||||
#[app(device = lm3s6965)]
|
#[app(device = lm3s6965)]
|
||||||
const APP: () = {
|
const APP: () = {
|
||||||
#[init]
|
#[init]
|
||||||
fn init() {}
|
fn init(_: init::Context) {}
|
||||||
|
|
||||||
#[idle]
|
#[idle]
|
||||||
fn idle(undef: u32) {
|
fn idle(_: idle::Context, undef: u32) {
|
||||||
//~^ ERROR `idle` must have type signature `[unsafe] fn() -> !`
|
//~^ ERROR `idle` must have type signature `fn(idle::Context) -> !`
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -10,10 +10,10 @@ use rtfm::app;
|
||||||
#[app(device = lm3s6965)]
|
#[app(device = lm3s6965)]
|
||||||
const APP: () = {
|
const APP: () = {
|
||||||
#[init]
|
#[init]
|
||||||
fn init() {}
|
fn init(_: init::Context) {}
|
||||||
|
|
||||||
#[idle]
|
#[idle]
|
||||||
fn idle() {
|
fn idle(_: idle::Context) {
|
||||||
//~^ ERROR `idle` must have type signature `[unsafe] fn() -> !`
|
//~^ ERROR `idle` must have type signature `fn(idle::Context) -> !`
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -10,8 +10,8 @@ use rtfm::app;
|
||||||
#[app(device = lm3s6965)]
|
#[app(device = lm3s6965)]
|
||||||
const APP: () = {
|
const APP: () = {
|
||||||
#[init]
|
#[init]
|
||||||
fn init() -> ! {
|
fn init(_: init::Context) -> ! {
|
||||||
//~^ ERROR `init` must have type signature `[unsafe] fn() [-> init::LateResources]`
|
//~^ ERROR `init` must have type signature `fn(init::Context) [-> init::LateResources]`
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -10,7 +10,7 @@ use rtfm::app;
|
||||||
#[app(device = lm3s6965)]
|
#[app(device = lm3s6965)]
|
||||||
const APP: () = {
|
const APP: () = {
|
||||||
#[init]
|
#[init]
|
||||||
fn init(undef: u32) {
|
fn init(_: init::Context, undef: u32) {
|
||||||
//~^ ERROR `init` must have type signature `[unsafe] fn() [-> init::LateResources]`
|
//~^ ERROR `init` must have type signature `fn(init::Context) [-> init::LateResources]`
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
//! This is equivalent to the `late-not-send` cfail test
|
//! This is equivalent to the `late-not-send` cfail test
|
||||||
|
|
||||||
#![feature(extern_crate_item_prelude)] // ???
|
|
||||||
#![no_main]
|
#![no_main]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
|
@ -21,10 +20,10 @@ const APP: () = {
|
||||||
static mut X: Option<NotSend> = None;
|
static mut X: Option<NotSend> = None;
|
||||||
|
|
||||||
#[init(resources = [X])]
|
#[init(resources = [X])]
|
||||||
fn init() {
|
fn init(c: init::Context) {
|
||||||
*resources.X = Some(NotSend { _0: PhantomData })
|
*c.resources.X = Some(NotSend { _0: PhantomData })
|
||||||
}
|
}
|
||||||
|
|
||||||
#[interrupt(resources = [X])]
|
#[interrupt(resources = [X])]
|
||||||
fn UART0() {}
|
fn UART0(_: UART0::Context) {}
|
||||||
};
|
};
|
||||||
|
|
|
@ -10,8 +10,8 @@ use rtfm::app;
|
||||||
#[app(device = lm3s6965)]
|
#[app(device = lm3s6965)]
|
||||||
const APP: () = {
|
const APP: () = {
|
||||||
#[init]
|
#[init]
|
||||||
fn init() -> u32 {
|
fn init(_: init::Context) -> u32 {
|
||||||
//~^ ERROR `init` must have type signature `[unsafe] fn() [-> init::LateResources]`
|
//~^ ERROR `init` must have type signature `fn(init::Context) [-> init::LateResources]`
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -10,8 +10,8 @@ use rtfm::app;
|
||||||
#[app(device = lm3s6965)] //~ ERROR 1 free interrupt (`extern { .. }`) is required
|
#[app(device = lm3s6965)] //~ ERROR 1 free interrupt (`extern { .. }`) is required
|
||||||
const APP: () = {
|
const APP: () = {
|
||||||
#[init]
|
#[init]
|
||||||
fn init() {}
|
fn init(_: init::Context) {}
|
||||||
|
|
||||||
#[task]
|
#[task]
|
||||||
fn foo() {}
|
fn foo(_: foo::Context) {}
|
||||||
};
|
};
|
||||||
|
|
|
@ -10,11 +10,11 @@ use rtfm::app;
|
||||||
#[app(device = lm3s6965)]
|
#[app(device = lm3s6965)]
|
||||||
const APP: () = {
|
const APP: () = {
|
||||||
#[init]
|
#[init]
|
||||||
fn init() {}
|
fn init(_: init::Context) {}
|
||||||
|
|
||||||
#[interrupt]
|
#[interrupt]
|
||||||
fn UART0() -> ! {
|
fn UART0(_: UART0::Context) -> ! {
|
||||||
//~^ ERROR `interrupt` handlers must have type signature `[unsafe] fn()`
|
//~^ ERROR this `interrupt` handler must have type signature `fn(UART0::Context)`
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -10,10 +10,10 @@ use rtfm::app;
|
||||||
#[app(device = lm3s6965)]
|
#[app(device = lm3s6965)]
|
||||||
const APP: () = {
|
const APP: () = {
|
||||||
#[init]
|
#[init]
|
||||||
fn init() {}
|
fn init(_: init::Context) {}
|
||||||
|
|
||||||
#[interrupt]
|
#[interrupt]
|
||||||
fn UART0(undef: u32) {
|
fn UART0(_: UART0::Context, undef: u32) {
|
||||||
//~^ ERROR `interrupt` handlers must have type signature `[unsafe] fn()`
|
//~^ ERROR this `interrupt` handler must have type signature `fn(UART0::Context)`
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -10,11 +10,11 @@ use rtfm::app;
|
||||||
#[app(device = lm3s6965)]
|
#[app(device = lm3s6965)]
|
||||||
const APP: () = {
|
const APP: () = {
|
||||||
#[init]
|
#[init]
|
||||||
fn init() {}
|
fn init(_: init::Context) {}
|
||||||
|
|
||||||
#[interrupt]
|
#[interrupt]
|
||||||
fn UART0() -> u32 {
|
fn UART0(_: UART0::Context) -> u32 {
|
||||||
//~^ ERROR `interrupt` handlers must have type signature `[unsafe] fn()`
|
//~^ ERROR this `interrupt` handler must have type signature `fn(UART0::Context)`
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -12,5 +12,5 @@ const APP: () = {
|
||||||
static mut X: u32 = ();
|
static mut X: u32 = ();
|
||||||
|
|
||||||
#[init(resources = [X])] //~ ERROR late resources can NOT be assigned to `init`
|
#[init(resources = [X])] //~ ERROR late resources can NOT be assigned to `init`
|
||||||
fn init() {}
|
fn init(_: init::Context) {}
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
//! `init` has a static priority of `0`. Initializing resources from it is equivalent to sending a
|
//! `init` has a static priority of `0`. Initializing resources from it is equivalent to sending a
|
||||||
//! message to the task that will own the resource
|
//! message to the task that will own the resource
|
||||||
|
|
||||||
#![feature(extern_crate_item_prelude)] // ???
|
|
||||||
#![no_main]
|
#![no_main]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
|
@ -22,12 +21,12 @@ const APP: () = {
|
||||||
static mut X: NotSend = ();
|
static mut X: NotSend = ();
|
||||||
|
|
||||||
#[init]
|
#[init]
|
||||||
fn init() -> init::LateResources {
|
fn init(_: init::Context) -> init::LateResources {
|
||||||
init::LateResources {
|
init::LateResources {
|
||||||
X: NotSend { _0: PhantomData },
|
X: NotSend { _0: PhantomData },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[interrupt(resources = [X])]
|
#[interrupt(resources = [X])]
|
||||||
fn UART0() {}
|
fn UART0(_: UART0::Context) {}
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
#![feature(extern_crate_item_prelude)] // ???
|
|
||||||
#![no_main]
|
#![no_main]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
|
@ -19,10 +18,10 @@ unsafe impl Sync for NotSend {}
|
||||||
#[app(device = lm3s6965)] //~ ERROR cannot be sent between threads safely
|
#[app(device = lm3s6965)] //~ ERROR cannot be sent between threads safely
|
||||||
const APP: () = {
|
const APP: () = {
|
||||||
#[init(spawn = [foo])]
|
#[init(spawn = [foo])]
|
||||||
fn init() {}
|
fn init(_: init::Context) {}
|
||||||
|
|
||||||
#[task]
|
#[task]
|
||||||
fn foo(_x: NotSend) {}
|
fn foo(_: foo::Context, _x: NotSend) {}
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
fn UART0();
|
fn UART0();
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
#![feature(extern_crate_item_prelude)] // ???
|
|
||||||
#![no_main]
|
#![no_main]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
|
@ -21,13 +20,13 @@ const APP: () = {
|
||||||
static X: NotSync = NotSync { _0: PhantomData };
|
static X: NotSync = NotSync { _0: PhantomData };
|
||||||
|
|
||||||
#[init(spawn = [foo])]
|
#[init(spawn = [foo])]
|
||||||
fn init() {}
|
fn init(_: init::Context) {}
|
||||||
|
|
||||||
#[task(priority = 1, resources = [X])]
|
#[task(priority = 1, resources = [X])]
|
||||||
fn foo() {}
|
fn foo(_: foo::Context) {}
|
||||||
|
|
||||||
#[task(priority = 2, resources = [X])]
|
#[task(priority = 2, resources = [X])]
|
||||||
fn bar() {}
|
fn bar(_: bar::Context) {}
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
fn UART0();
|
fn UART0();
|
||||||
|
|
|
@ -10,13 +10,13 @@ use rtfm::app;
|
||||||
#[app(device = lm3s6965)] //~ error evaluation of constant value failed
|
#[app(device = lm3s6965)] //~ error evaluation of constant value failed
|
||||||
const APP: () = {
|
const APP: () = {
|
||||||
#[init]
|
#[init]
|
||||||
fn init() {}
|
fn init(_: init::Context) {}
|
||||||
|
|
||||||
// OK, this is the maximum priority supported by the device
|
// OK, this is the maximum priority supported by the device
|
||||||
#[interrupt(priority = 8)]
|
#[interrupt(priority = 8)]
|
||||||
fn UART0() {}
|
fn UART0(_: UART0::Context) {}
|
||||||
|
|
||||||
// this value is too high!
|
// this value is too high!
|
||||||
#[interrupt(priority = 9)]
|
#[interrupt(priority = 9)]
|
||||||
fn UART1() {}
|
fn UART1(_: UART1::Context) {}
|
||||||
};
|
};
|
||||||
|
|
|
@ -10,13 +10,13 @@ use rtfm::app;
|
||||||
#[app(device = lm3s6965)]
|
#[app(device = lm3s6965)]
|
||||||
const APP: () = {
|
const APP: () = {
|
||||||
#[init]
|
#[init]
|
||||||
fn init() {}
|
fn init(_: init::Context) {}
|
||||||
|
|
||||||
// OK, this is the minimum priority that tasks can have
|
// OK, this is the minimum priority that tasks can have
|
||||||
#[interrupt(priority = 1)]
|
#[interrupt(priority = 1)]
|
||||||
fn UART0() {}
|
fn UART0(_: UART0::Context) {}
|
||||||
|
|
||||||
// this value is too low!
|
// this value is too low!
|
||||||
#[interrupt(priority = 0)] //~ error this literal must be in the range 1...255
|
#[interrupt(priority = 0)] //~ error this literal must be in the range 1...255
|
||||||
fn UART1() {}
|
fn UART1(_: UART1::Context) {}
|
||||||
};
|
};
|
||||||
|
|
|
@ -10,5 +10,5 @@ use rtfm::app;
|
||||||
#[app(device = lm3s6965)]
|
#[app(device = lm3s6965)]
|
||||||
const APP: () = {
|
const APP: () = {
|
||||||
#[init(resources = [X])] //~ ERROR this resource has NOT been declared
|
#[init(resources = [X])] //~ ERROR this resource has NOT been declared
|
||||||
fn init() {}
|
fn init(_: init::Context) {}
|
||||||
};
|
};
|
||||||
|
|
|
@ -13,5 +13,5 @@ const APP: () = {
|
||||||
//~^ ERROR resources must have inherited / private visibility
|
//~^ ERROR resources must have inherited / private visibility
|
||||||
|
|
||||||
#[init]
|
#[init]
|
||||||
fn init() {}
|
fn init(_: init::Context) {}
|
||||||
};
|
};
|
||||||
|
|
|
@ -5,16 +5,14 @@ extern crate lm3s6965;
|
||||||
extern crate panic_halt;
|
extern crate panic_halt;
|
||||||
extern crate rtfm;
|
extern crate rtfm;
|
||||||
|
|
||||||
use rtfm::app;
|
#[rtfm::app(device = lm3s6965)]
|
||||||
|
|
||||||
#[app(device = lm3s6965)]
|
|
||||||
const APP: () = {
|
const APP: () = {
|
||||||
#[init]
|
#[init]
|
||||||
fn init() {}
|
fn init(_: init::Context) {}
|
||||||
|
|
||||||
#[task]
|
#[task]
|
||||||
fn foo() -> ! {
|
fn foo(_: foo::Context) -> ! {
|
||||||
//~^ ERROR `task` handlers must have type signature `[unsafe] fn(..)`
|
//~^ ERROR this `task` handler must have type signature `fn(foo::Context, ..)`
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,10 +10,10 @@ use rtfm::app;
|
||||||
#[app(device = lm3s6965)]
|
#[app(device = lm3s6965)]
|
||||||
const APP: () = {
|
const APP: () = {
|
||||||
#[init]
|
#[init]
|
||||||
fn init() {}
|
fn init(_: init::Context) {}
|
||||||
|
|
||||||
#[task]
|
#[task]
|
||||||
fn idle() {
|
fn idle(_: idle::Context) {
|
||||||
//~^ ERROR `task` handlers can NOT be named `idle`, `init` or `resources`
|
//~^ ERROR `task` handlers can NOT be named `idle`, `init` or `resources`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,5 +10,5 @@ use rtfm::app;
|
||||||
#[app(device = lm3s6965)]
|
#[app(device = lm3s6965)]
|
||||||
const APP: () = {
|
const APP: () = {
|
||||||
#[init(spawn = [X])] //~ ERROR this task has NOT been declared
|
#[init(spawn = [X])] //~ ERROR this task has NOT been declared
|
||||||
fn init() {}
|
fn init(_: init::Context) {}
|
||||||
};
|
};
|
||||||
|
|
18
tests/cfail/unsafe-exception.rs
Normal file
18
tests/cfail/unsafe-exception.rs
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
#![no_main]
|
||||||
|
#![no_std]
|
||||||
|
|
||||||
|
extern crate lm3s6965;
|
||||||
|
extern crate panic_halt;
|
||||||
|
extern crate rtfm;
|
||||||
|
|
||||||
|
use rtfm::app;
|
||||||
|
|
||||||
|
#[app(device = lm3s6965)]
|
||||||
|
const APP: () = {
|
||||||
|
#[init]
|
||||||
|
fn init(_: init::Context) {}
|
||||||
|
|
||||||
|
#[exception(binds = SVCall)]
|
||||||
|
unsafe fn foo(_: foo::Context) {}
|
||||||
|
//~^ ERROR this `exception` handler must have type signature `fn(foo::Context)`
|
||||||
|
};
|
20
tests/cfail/unsafe-idle.rs
Normal file
20
tests/cfail/unsafe-idle.rs
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
#![no_main]
|
||||||
|
#![no_std]
|
||||||
|
|
||||||
|
extern crate lm3s6965;
|
||||||
|
extern crate panic_halt;
|
||||||
|
extern crate rtfm;
|
||||||
|
|
||||||
|
use rtfm::app;
|
||||||
|
|
||||||
|
#[app(device = lm3s6965)]
|
||||||
|
const APP: () = {
|
||||||
|
#[init]
|
||||||
|
fn init(_: init::Context) {}
|
||||||
|
|
||||||
|
#[idle]
|
||||||
|
unsafe fn idle(_: idle::Context) -> ! {
|
||||||
|
//~^ ERROR `idle` must have type signature `fn(idle::Context) -> !`
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
};
|
|
@ -1,5 +1,3 @@
|
||||||
// TODO remove in v0.5.x
|
|
||||||
|
|
||||||
#![no_main]
|
#![no_main]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
|
@ -11,8 +9,7 @@ use rtfm::app;
|
||||||
|
|
||||||
#[app(device = lm3s6965)]
|
#[app(device = lm3s6965)]
|
||||||
const APP: () = {
|
const APP: () = {
|
||||||
static mut X: u32 = (); //~ ERROR late resources MUST be initialized at the end of `init`
|
|
||||||
|
|
||||||
#[init]
|
#[init]
|
||||||
fn init() {}
|
unsafe fn init(_: init::Context) {}
|
||||||
|
//~^ ERROR `init` must have type signature `fn(init::Context) [-> init::LateResources]`
|
||||||
};
|
};
|
18
tests/cfail/unsafe-interrupt.rs
Normal file
18
tests/cfail/unsafe-interrupt.rs
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
#![no_main]
|
||||||
|
#![no_std]
|
||||||
|
|
||||||
|
extern crate lm3s6965;
|
||||||
|
extern crate panic_halt;
|
||||||
|
extern crate rtfm;
|
||||||
|
|
||||||
|
use rtfm::app;
|
||||||
|
|
||||||
|
#[app(device = lm3s6965)]
|
||||||
|
const APP: () = {
|
||||||
|
#[init]
|
||||||
|
fn init(_: init::Context) {}
|
||||||
|
|
||||||
|
#[interrupt(binds = UART0)]
|
||||||
|
unsafe fn foo(_: foo::Context) {}
|
||||||
|
//~^ ERROR this `interrupt` handler must have type signature `fn(foo::Context)`
|
||||||
|
};
|
22
tests/cfail/unsafe-task.rs
Normal file
22
tests/cfail/unsafe-task.rs
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
#![no_main]
|
||||||
|
#![no_std]
|
||||||
|
|
||||||
|
extern crate lm3s6965;
|
||||||
|
extern crate panic_halt;
|
||||||
|
extern crate rtfm;
|
||||||
|
|
||||||
|
use rtfm::app;
|
||||||
|
|
||||||
|
#[app(device = lm3s6965)]
|
||||||
|
const APP: () = {
|
||||||
|
#[init]
|
||||||
|
fn init(_: init::Context) {}
|
||||||
|
|
||||||
|
#[task]
|
||||||
|
unsafe fn foo(_: foo::Context) {}
|
||||||
|
//~^ ERROR this `task` handler must have type signature `fn(foo::Context, ..)`
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
fn UART0();
|
||||||
|
}
|
||||||
|
};
|
|
@ -10,10 +10,10 @@ use rtfm::app;
|
||||||
#[app(device = lm3s6965)]
|
#[app(device = lm3s6965)]
|
||||||
const APP: () = {
|
const APP: () = {
|
||||||
#[init]
|
#[init]
|
||||||
fn init() {}
|
fn init(_: init::Context) {}
|
||||||
|
|
||||||
#[interrupt(binds = UART0)] //~ ERROR free interrupts (`extern { .. }`) can't be used as interrupt handlers
|
#[interrupt(binds = UART0)] //~ ERROR free interrupts (`extern { .. }`) can't be used as interrupt handlers
|
||||||
fn foo() {}
|
fn foo(_: foo::Context) {}
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
fn UART0();
|
fn UART0();
|
||||||
|
|
|
@ -10,10 +10,11 @@ use rtfm::app;
|
||||||
#[app(device = lm3s6965)]
|
#[app(device = lm3s6965)]
|
||||||
const APP: () = {
|
const APP: () = {
|
||||||
#[init]
|
#[init]
|
||||||
fn init() {}
|
fn init(_: init::Context) {}
|
||||||
|
|
||||||
#[interrupt]
|
#[interrupt]
|
||||||
fn UART0() {} //~ ERROR free interrupts (`extern { .. }`) can't be used as interrupt handlers
|
fn UART0(_: UART0::Context) {}
|
||||||
|
//~^ ERROR free interrupts (`extern { .. }`) can't be used as interrupt handlers
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
fn UART0();
|
fn UART0();
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
//! Check that `binds` works as advertised
|
//! Check that `binds` works as advertised
|
||||||
|
#![deny(unsafe_code)]
|
||||||
|
#![deny(warnings)]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
|
@ -6,18 +8,20 @@ extern crate lm3s6965;
|
||||||
extern crate panic_halt;
|
extern crate panic_halt;
|
||||||
extern crate rtfm;
|
extern crate rtfm;
|
||||||
|
|
||||||
use rtfm::app;
|
#[rtfm::app(device = lm3s6965)]
|
||||||
|
|
||||||
#[app(device = lm3s6965)]
|
|
||||||
const APP: () = {
|
const APP: () = {
|
||||||
#[init]
|
#[init]
|
||||||
fn init() {}
|
fn init(_: init::Context) {}
|
||||||
|
|
||||||
#[exception(binds = SVCall)]
|
#[exception(binds = SVCall)]
|
||||||
fn foo() {}
|
fn foo(c: foo::Context) {
|
||||||
|
foo_trampoline(c)
|
||||||
|
}
|
||||||
|
|
||||||
#[interrupt(binds = UART0)]
|
#[interrupt(binds = UART0)]
|
||||||
fn bar() {}
|
fn bar(c: bar::Context) {
|
||||||
|
bar_trampoline(c)
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
|
|
|
@ -6,24 +6,22 @@
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
extern crate lm3s6965;
|
extern crate lm3s6965;
|
||||||
extern crate panic_semihosting;
|
extern crate panic_halt;
|
||||||
extern crate rtfm;
|
extern crate rtfm;
|
||||||
|
|
||||||
use rtfm::app;
|
#[rtfm::app(device = lm3s6965)]
|
||||||
|
|
||||||
#[app(device = lm3s6965)]
|
|
||||||
const APP: () = {
|
const APP: () = {
|
||||||
#[cfg(never)]
|
#[cfg(never)]
|
||||||
static mut FOO: u32 = 0;
|
static mut FOO: u32 = 0;
|
||||||
|
|
||||||
#[init]
|
#[init]
|
||||||
fn init() {
|
fn init(_: init::Context) {
|
||||||
#[cfg(never)]
|
#[cfg(never)]
|
||||||
static mut BAR: u32 = 0;
|
static mut BAR: u32 = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[idle]
|
#[idle]
|
||||||
fn idle() -> ! {
|
fn idle(_: idle::Context) -> ! {
|
||||||
#[cfg(never)]
|
#[cfg(never)]
|
||||||
static mut BAR: u32 = 0;
|
static mut BAR: u32 = 0;
|
||||||
|
|
||||||
|
@ -31,20 +29,20 @@ const APP: () = {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[task(resources = [FOO], schedule = [quux], spawn = [quux])]
|
#[task(resources = [FOO], schedule = [quux], spawn = [quux])]
|
||||||
fn foo() {
|
fn foo(_: foo::Context) {
|
||||||
#[cfg(never)]
|
#[cfg(never)]
|
||||||
static mut BAR: u32 = 0;
|
static mut BAR: u32 = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[task(priority = 3, resources = [FOO], schedule = [quux], spawn = [quux])]
|
#[task(priority = 3, resources = [FOO], schedule = [quux], spawn = [quux])]
|
||||||
fn bar() {
|
fn bar(_: bar::Context) {
|
||||||
#[cfg(never)]
|
#[cfg(never)]
|
||||||
static mut BAR: u32 = 0;
|
static mut BAR: u32 = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(never)]
|
#[cfg(never)]
|
||||||
#[task]
|
#[task]
|
||||||
fn quux() {}
|
fn quux(_: quux::Context) {}
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
fn UART0();
|
fn UART0();
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
#![deny(unsafe_code)]
|
||||||
|
#![deny(warnings)]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
|
@ -7,20 +9,18 @@ extern crate rtfm;
|
||||||
|
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
|
|
||||||
use rtfm::app;
|
|
||||||
|
|
||||||
pub struct NotSend {
|
pub struct NotSend {
|
||||||
_0: PhantomData<*const ()>,
|
_0: PhantomData<*const ()>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[app(device = lm3s6965)]
|
#[rtfm::app(device = lm3s6965)]
|
||||||
const APP: () = {
|
const APP: () = {
|
||||||
static mut X: NotSend = ();
|
static mut X: NotSend = ();
|
||||||
static mut Y: Option<NotSend> = None;
|
static mut Y: Option<NotSend> = None;
|
||||||
|
|
||||||
#[init(resources = [Y])]
|
#[init(resources = [Y])]
|
||||||
fn init() -> init::LateResources {
|
fn init(c: init::Context) -> init::LateResources {
|
||||||
*resources.Y = Some(NotSend { _0: PhantomData });
|
*c.resources.Y = Some(NotSend { _0: PhantomData });
|
||||||
|
|
||||||
init::LateResources {
|
init::LateResources {
|
||||||
X: NotSend { _0: PhantomData },
|
X: NotSend { _0: PhantomData },
|
||||||
|
@ -28,7 +28,7 @@ const APP: () = {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[idle(resources = [X, Y])]
|
#[idle(resources = [X, Y])]
|
||||||
fn idle() -> ! {
|
fn idle(_: idle::Context) -> ! {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
//! Runtime initialized resources
|
//! Runtime initialized resources
|
||||||
|
#![deny(unsafe_code)]
|
||||||
|
#![deny(warnings)]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
|
@ -6,15 +8,13 @@ extern crate lm3s6965;
|
||||||
extern crate panic_halt;
|
extern crate panic_halt;
|
||||||
extern crate rtfm;
|
extern crate rtfm;
|
||||||
|
|
||||||
use rtfm::app;
|
#[rtfm::app(device = lm3s6965)]
|
||||||
|
|
||||||
#[app(device = lm3s6965)]
|
|
||||||
const APP: () = {
|
const APP: () = {
|
||||||
static mut X: u32 = ();
|
static mut X: u32 = ();
|
||||||
static Y: u32 = ();
|
static Y: u32 = ();
|
||||||
|
|
||||||
#[init]
|
#[init]
|
||||||
fn init() -> init::LateResources {
|
fn init(_: init::Context) -> init::LateResources {
|
||||||
init::LateResources { X: 0, Y: 1 }
|
init::LateResources { X: 0, Y: 1 }
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
//! Core and device peripherals
|
//! Core and device peripherals
|
||||||
|
#![deny(unsafe_code)]
|
||||||
|
#![deny(warnings)]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
|
@ -6,13 +8,11 @@ extern crate lm3s6965;
|
||||||
extern crate panic_halt;
|
extern crate panic_halt;
|
||||||
extern crate rtfm;
|
extern crate rtfm;
|
||||||
|
|
||||||
use rtfm::app;
|
#[rtfm::app(device = lm3s6965)]
|
||||||
|
|
||||||
#[app(device = lm3s6965)]
|
|
||||||
const APP: () = {
|
const APP: () = {
|
||||||
#[init]
|
#[init]
|
||||||
fn init() {
|
fn init(c: init::Context) {
|
||||||
let _: rtfm::Peripherals = core;
|
let _: rtfm::Peripherals = c.core;
|
||||||
let _: lm3s6965::Peripherals = device;
|
let _: lm3s6965::Peripherals = c.device;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
//! Check code generation of resources
|
//! Check code generation of resources
|
||||||
|
|
||||||
|
#![deny(unsafe_code)]
|
||||||
|
#![deny(warnings)]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
|
@ -7,9 +9,9 @@ extern crate lm3s6965;
|
||||||
extern crate panic_halt;
|
extern crate panic_halt;
|
||||||
extern crate rtfm;
|
extern crate rtfm;
|
||||||
|
|
||||||
use rtfm::{app, Exclusive};
|
use rtfm::Exclusive;
|
||||||
|
|
||||||
#[app(device = lm3s6965)]
|
#[rtfm::app(device = lm3s6965)]
|
||||||
const APP: () = {
|
const APP: () = {
|
||||||
static mut O1: u32 = 0; // init
|
static mut O1: u32 = 0; // init
|
||||||
static mut O2: u32 = 0; // idle
|
static mut O2: u32 = 0; // idle
|
||||||
|
@ -23,57 +25,57 @@ const APP: () = {
|
||||||
static S3: u32 = 0;
|
static S3: u32 = 0;
|
||||||
|
|
||||||
#[init(resources = [O1, O4, O5, O6, S3])]
|
#[init(resources = [O1, O4, O5, O6, S3])]
|
||||||
fn init() {
|
fn init(c: init::Context) {
|
||||||
// owned by `init` == `&'static mut`
|
// owned by `init` == `&'static mut`
|
||||||
let _: &'static mut u32 = resources.O1;
|
let _: &'static mut u32 = c.resources.O1;
|
||||||
|
|
||||||
// owned by `init` == `&'static` if read-only
|
// owned by `init` == `&'static` if read-only
|
||||||
let _: &'static u32 = resources.O6;
|
let _: &'static u32 = c.resources.O6;
|
||||||
|
|
||||||
// `init` has exclusive access to all resources
|
// `init` has exclusive access to all resources
|
||||||
let _: &mut u32 = resources.O4;
|
let _: &mut u32 = c.resources.O4;
|
||||||
let _: &mut u32 = resources.O5;
|
let _: &mut u32 = c.resources.O5;
|
||||||
let _: &mut u32 = resources.S3;
|
let _: &mut u32 = c.resources.S3;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[idle(resources = [O2, O4, S1, S3])]
|
#[idle(resources = [O2, O4, S1, S3])]
|
||||||
fn idle() -> ! {
|
fn idle(mut c: idle::Context) -> ! {
|
||||||
// owned by `idle` == `&'static mut`
|
// owned by `idle` == `&'static mut`
|
||||||
let _: &'static mut u32 = resources.O2;
|
let _: &'static mut u32 = c.resources.O2;
|
||||||
|
|
||||||
// owned by `idle` == `&'static` if read-only
|
// owned by `idle` == `&'static` if read-only
|
||||||
let _: &'static u32 = resources.O4;
|
let _: &'static u32 = c.resources.O4;
|
||||||
|
|
||||||
// shared with `idle` == `Mutex`
|
// shared with `idle` == `Mutex`
|
||||||
resources.S1.lock(|_| {});
|
c.resources.S1.lock(|_| {});
|
||||||
|
|
||||||
// `&` if read-only
|
// `&` if read-only
|
||||||
let _: &u32 = resources.S3;
|
let _: &u32 = c.resources.S3;
|
||||||
|
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[interrupt(resources = [O3, S1, S2, S3])]
|
#[interrupt(resources = [O3, S1, S2, S3])]
|
||||||
fn UART0() {
|
fn UART0(c: UART0::Context) {
|
||||||
// owned by interrupt == `&mut`
|
// owned by interrupt == `&mut`
|
||||||
let _: &mut u32 = resources.O3;
|
let _: &mut u32 = c.resources.O3;
|
||||||
|
|
||||||
// no `Mutex` proxy when access from highest priority task
|
// no `Mutex` proxy when access from highest priority task
|
||||||
let _: Exclusive<u32> = resources.S1;
|
let _: Exclusive<u32> = c.resources.S1;
|
||||||
|
|
||||||
// no `Mutex` proxy when co-owned by cooperative (same priority) tasks
|
// no `Mutex` proxy when co-owned by cooperative (same priority) tasks
|
||||||
let _: Exclusive<u32> = resources.S2;
|
let _: Exclusive<u32> = c.resources.S2;
|
||||||
|
|
||||||
// `&` if read-only
|
// `&` if read-only
|
||||||
let _: &u32 = resources.S3;
|
let _: &u32 = c.resources.S3;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[interrupt(resources = [S2, O5])]
|
#[interrupt(resources = [S2, O5])]
|
||||||
fn UART1() {
|
fn UART1(c: UART1::Context) {
|
||||||
// owned by interrupt == `&` if read-only
|
// owned by interrupt == `&` if read-only
|
||||||
let _: &u32 = resources.O5;
|
let _: &u32 = c.resources.O5;
|
||||||
|
|
||||||
// no `Mutex` proxy when co-owned by cooperative (same priority) tasks
|
// no `Mutex` proxy when co-owned by cooperative (same priority) tasks
|
||||||
let _: Exclusive<u32> = resources.S2;
|
let _: Exclusive<u32> = c.resources.S2;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
#![deny(unsafe_code)]
|
||||||
|
#![deny(warnings)]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
|
@ -5,52 +7,52 @@ extern crate lm3s6965;
|
||||||
extern crate panic_halt;
|
extern crate panic_halt;
|
||||||
extern crate rtfm;
|
extern crate rtfm;
|
||||||
|
|
||||||
use rtfm::{app, Instant};
|
use rtfm::Instant;
|
||||||
|
|
||||||
#[app(device = lm3s6965)]
|
#[rtfm::app(device = lm3s6965)]
|
||||||
const APP: () = {
|
const APP: () = {
|
||||||
#[init(schedule = [foo, bar, baz])]
|
#[init(schedule = [foo, bar, baz])]
|
||||||
fn init() {
|
fn init(c: init::Context) {
|
||||||
let _: Result<(), ()> = schedule.foo(start + 10.cycles());
|
let _: Result<(), ()> = c.schedule.foo(c.start + 10.cycles());
|
||||||
let _: Result<(), u32> = schedule.bar(start + 20.cycles(), 0);
|
let _: Result<(), u32> = c.schedule.bar(c.start + 20.cycles(), 0);
|
||||||
let _: Result<(), (u32, u32)> = schedule.baz(start + 30.cycles(), 0, 1);
|
let _: Result<(), (u32, u32)> = c.schedule.baz(c.start + 30.cycles(), 0, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[idle(schedule = [foo, bar, baz])]
|
#[idle(schedule = [foo, bar, baz])]
|
||||||
fn idle() -> ! {
|
fn idle(c: idle::Context) -> ! {
|
||||||
let _: Result<(), ()> = schedule.foo(Instant::now() + 40.cycles());
|
let _: Result<(), ()> = c.schedule.foo(Instant::now() + 40.cycles());
|
||||||
let _: Result<(), u32> = schedule.bar(Instant::now() + 50.cycles(), 0);
|
let _: Result<(), u32> = c.schedule.bar(Instant::now() + 50.cycles(), 0);
|
||||||
let _: Result<(), (u32, u32)> = schedule.baz(Instant::now() + 60.cycles(), 0, 1);
|
let _: Result<(), (u32, u32)> = c.schedule.baz(Instant::now() + 60.cycles(), 0, 1);
|
||||||
|
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[exception(schedule = [foo, bar, baz])]
|
#[exception(schedule = [foo, bar, baz])]
|
||||||
fn SVCall() {
|
fn SVCall(c: SVCall::Context) {
|
||||||
let _: Result<(), ()> = schedule.foo(start + 70.cycles());
|
let _: Result<(), ()> = c.schedule.foo(c.start + 70.cycles());
|
||||||
let _: Result<(), u32> = schedule.bar(start + 80.cycles(), 0);
|
let _: Result<(), u32> = c.schedule.bar(c.start + 80.cycles(), 0);
|
||||||
let _: Result<(), (u32, u32)> = schedule.baz(start + 90.cycles(), 0, 1);
|
let _: Result<(), (u32, u32)> = c.schedule.baz(c.start + 90.cycles(), 0, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[interrupt(schedule = [foo, bar, baz])]
|
#[interrupt(schedule = [foo, bar, baz])]
|
||||||
fn UART0() {
|
fn UART0(c: UART0::Context) {
|
||||||
let _: Result<(), ()> = schedule.foo(start + 100.cycles());
|
let _: Result<(), ()> = c.schedule.foo(c.start + 100.cycles());
|
||||||
let _: Result<(), u32> = schedule.bar(start + 110.cycles(), 0);
|
let _: Result<(), u32> = c.schedule.bar(c.start + 110.cycles(), 0);
|
||||||
let _: Result<(), (u32, u32)> = schedule.baz(start + 120.cycles(), 0, 1);
|
let _: Result<(), (u32, u32)> = c.schedule.baz(c.start + 120.cycles(), 0, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[task(schedule = [foo, bar, baz])]
|
#[task(schedule = [foo, bar, baz])]
|
||||||
fn foo() {
|
fn foo(c: foo::Context) {
|
||||||
let _: Result<(), ()> = schedule.foo(scheduled + 130.cycles());
|
let _: Result<(), ()> = c.schedule.foo(c.scheduled + 130.cycles());
|
||||||
let _: Result<(), u32> = schedule.bar(scheduled + 140.cycles(), 0);
|
let _: Result<(), u32> = c.schedule.bar(c.scheduled + 140.cycles(), 0);
|
||||||
let _: Result<(), (u32, u32)> = schedule.baz(scheduled + 150.cycles(), 0, 1);
|
let _: Result<(), (u32, u32)> = c.schedule.baz(c.scheduled + 150.cycles(), 0, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[task]
|
#[task]
|
||||||
fn bar(_x: u32) {}
|
fn bar(_: bar::Context, _x: u32) {}
|
||||||
|
|
||||||
#[task]
|
#[task]
|
||||||
fn baz(_x: u32, _y: u32) {}
|
fn baz(_: baz::Context, _x: u32, _y: u32) {}
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
fn UART1();
|
fn UART1();
|
||||||
|
|
|
@ -1,66 +0,0 @@
|
||||||
#![no_main]
|
|
||||||
#![no_std]
|
|
||||||
|
|
||||||
extern crate lm3s6965;
|
|
||||||
extern crate owned_singleton;
|
|
||||||
extern crate panic_halt;
|
|
||||||
extern crate rtfm;
|
|
||||||
|
|
||||||
use rtfm::{app, Exclusive};
|
|
||||||
|
|
||||||
#[app(device = lm3s6965)]
|
|
||||||
const APP: () = {
|
|
||||||
#[Singleton]
|
|
||||||
static mut O1: u32 = 0;
|
|
||||||
#[Singleton]
|
|
||||||
static mut O2: u32 = 0;
|
|
||||||
#[Singleton]
|
|
||||||
static mut O3: u32 = 0;
|
|
||||||
#[Singleton]
|
|
||||||
static O4: u32 = 0;
|
|
||||||
#[Singleton]
|
|
||||||
static O5: u32 = 0;
|
|
||||||
#[Singleton]
|
|
||||||
static O6: u32 = 0;
|
|
||||||
|
|
||||||
#[Singleton]
|
|
||||||
static mut S1: u32 = 0;
|
|
||||||
#[Singleton]
|
|
||||||
static S2: u32 = 0;
|
|
||||||
|
|
||||||
#[init(resources = [O1, O2, O3, O4, O5, O6, S1, S2])]
|
|
||||||
fn init() {
|
|
||||||
let _: O1 = resources.O1;
|
|
||||||
let _: &mut O2 = resources.O2;
|
|
||||||
let _: &mut O3 = resources.O3;
|
|
||||||
let _: O4 = resources.O4;
|
|
||||||
let _: &mut O5 = resources.O5;
|
|
||||||
let _: &mut O6 = resources.O6;
|
|
||||||
|
|
||||||
let _: &mut S1 = resources.S1;
|
|
||||||
let _: &mut S2 = resources.S2;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[idle(resources = [O2, O5])]
|
|
||||||
fn idle() -> ! {
|
|
||||||
let _: O2 = resources.O2;
|
|
||||||
let _: O5 = resources.O5;
|
|
||||||
|
|
||||||
loop {}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[interrupt(resources = [O3, O6, S1, S2])]
|
|
||||||
fn UART0() {
|
|
||||||
let _: &mut O3 = resources.O3;
|
|
||||||
let _: &O6 = resources.O6;
|
|
||||||
|
|
||||||
let _: Exclusive<S1> = resources.S1;
|
|
||||||
let _: &S2 = resources.S2;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[interrupt(resources = [S1, S2])]
|
|
||||||
fn UART1() {
|
|
||||||
let _: Exclusive<S1> = resources.S1;
|
|
||||||
let _: &S2 = resources.S2;
|
|
||||||
}
|
|
||||||
};
|
|
|
@ -1,4 +1,6 @@
|
||||||
//! Check code generation of `spawn`
|
//! Check code generation of `spawn`
|
||||||
|
#![deny(unsafe_code)]
|
||||||
|
#![deny(warnings)]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
|
@ -6,52 +8,50 @@ extern crate lm3s6965;
|
||||||
extern crate panic_halt;
|
extern crate panic_halt;
|
||||||
extern crate rtfm;
|
extern crate rtfm;
|
||||||
|
|
||||||
use rtfm::app;
|
#[rtfm::app(device = lm3s6965)]
|
||||||
|
|
||||||
#[app(device = lm3s6965)]
|
|
||||||
const APP: () = {
|
const APP: () = {
|
||||||
#[init(spawn = [foo, bar, baz])]
|
#[init(spawn = [foo, bar, baz])]
|
||||||
fn init() {
|
fn init(c: init::Context) {
|
||||||
let _: Result<(), ()> = spawn.foo();
|
let _: Result<(), ()> = c.spawn.foo();
|
||||||
let _: Result<(), u32> = spawn.bar(0);
|
let _: Result<(), u32> = c.spawn.bar(0);
|
||||||
let _: Result<(), (u32, u32)> = spawn.baz(0, 1);
|
let _: Result<(), (u32, u32)> = c.spawn.baz(0, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[idle(spawn = [foo, bar, baz])]
|
#[idle(spawn = [foo, bar, baz])]
|
||||||
fn idle() -> ! {
|
fn idle(c: idle::Context) -> ! {
|
||||||
let _: Result<(), ()> = spawn.foo();
|
let _: Result<(), ()> = c.spawn.foo();
|
||||||
let _: Result<(), u32> = spawn.bar(0);
|
let _: Result<(), u32> = c.spawn.bar(0);
|
||||||
let _: Result<(), (u32, u32)> = spawn.baz(0, 1);
|
let _: Result<(), (u32, u32)> = c.spawn.baz(0, 1);
|
||||||
|
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[exception(spawn = [foo, bar, baz])]
|
#[exception(spawn = [foo, bar, baz])]
|
||||||
fn SVCall() {
|
fn SVCall(c: SVCall::Context) {
|
||||||
let _: Result<(), ()> = spawn.foo();
|
let _: Result<(), ()> = c.spawn.foo();
|
||||||
let _: Result<(), u32> = spawn.bar(0);
|
let _: Result<(), u32> = c.spawn.bar(0);
|
||||||
let _: Result<(), (u32, u32)> = spawn.baz(0, 1);
|
let _: Result<(), (u32, u32)> = c.spawn.baz(0, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[interrupt(spawn = [foo, bar, baz])]
|
#[interrupt(spawn = [foo, bar, baz])]
|
||||||
fn UART0() {
|
fn UART0(c: UART0::Context) {
|
||||||
let _: Result<(), ()> = spawn.foo();
|
let _: Result<(), ()> = c.spawn.foo();
|
||||||
let _: Result<(), u32> = spawn.bar(0);
|
let _: Result<(), u32> = c.spawn.bar(0);
|
||||||
let _: Result<(), (u32, u32)> = spawn.baz(0, 1);
|
let _: Result<(), (u32, u32)> = c.spawn.baz(0, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[task(spawn = [foo, bar, baz])]
|
#[task(spawn = [foo, bar, baz])]
|
||||||
fn foo() {
|
fn foo(c: foo::Context) {
|
||||||
let _: Result<(), ()> = spawn.foo();
|
let _: Result<(), ()> = c.spawn.foo();
|
||||||
let _: Result<(), u32> = spawn.bar(0);
|
let _: Result<(), u32> = c.spawn.bar(0);
|
||||||
let _: Result<(), (u32, u32)> = spawn.baz(0, 1);
|
let _: Result<(), (u32, u32)> = c.spawn.baz(0, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[task]
|
#[task]
|
||||||
fn bar(_x: u32) {}
|
fn bar(_: bar::Context, _x: u32) {}
|
||||||
|
|
||||||
#[task]
|
#[task]
|
||||||
fn baz(_x: u32, _y: u32) {}
|
fn baz(_: baz::Context, _x: u32, _y: u32) {}
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
fn UART1();
|
fn UART1();
|
||||||
|
|
|
@ -1,45 +0,0 @@
|
||||||
//! Check code generation of `unsafe` `init` / `idle` / `exception` / `interrupt` / `task`
|
|
||||||
#![no_main]
|
|
||||||
#![no_std]
|
|
||||||
|
|
||||||
extern crate lm3s6965;
|
|
||||||
extern crate panic_halt;
|
|
||||||
extern crate rtfm;
|
|
||||||
|
|
||||||
use rtfm::app;
|
|
||||||
|
|
||||||
unsafe fn foo() {}
|
|
||||||
|
|
||||||
#[app(device = lm3s6965)]
|
|
||||||
const APP: () = {
|
|
||||||
#[init]
|
|
||||||
unsafe fn init() {
|
|
||||||
foo();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[idle]
|
|
||||||
unsafe fn idle() -> ! {
|
|
||||||
foo();
|
|
||||||
|
|
||||||
loop {}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[exception]
|
|
||||||
unsafe fn SVCall() {
|
|
||||||
foo();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[interrupt]
|
|
||||||
unsafe fn UART0() {
|
|
||||||
foo();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[task]
|
|
||||||
unsafe fn bar() {
|
|
||||||
foo();
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" {
|
|
||||||
fn UART1();
|
|
||||||
}
|
|
||||||
};
|
|
Loading…
Reference in a new issue