diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c687115389..8da98678e1 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -45,7 +45,6 @@ jobs: - x86_64-unknown-linux-gnu toolchain: - stable - - 1.36.0 steps: - name: Checkout uses: actions/checkout@v2 @@ -79,10 +78,6 @@ jobs: target: ${{ matrix.target }} override: true - - name: Disable optimisation profiles - if: matrix.toolchain == '1.36.0' - run: sed -i '/^\[profile.*build-override]$/,/^$/{/^#/!{/^$/!d}}' Cargo.toml - - name: cargo check uses: actions-rs/cargo@v1 with: @@ -90,7 +85,7 @@ jobs: command: check args: --target=${{ matrix.target }} - # Verify all examples + # Verify all examples, checks checkexamples: name: checkexamples runs-on: ubuntu-20.04 @@ -145,6 +140,51 @@ jobs: command: check args: --examples --target=${{ matrix.target }} --features __min_r1_43,${{ env.V7 }} + # Verify the example output with run-pass tests + testexamples: + name: testexamples + runs-on: ubuntu-20.04 + strategy: + matrix: + target: + - thumbv7m-none-eabi + - thumbv6m-none-eabi + toolchain: + - stable + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Cache cargo dependencies + uses: actions/cache@v2 + with: + path: | + - ~/.cargo/bin/ + - ~/.cargo/registry/index/ + - ~/.cargo/registry/cache/ + - ~/.cargo/git/db/ + key: ${{ runner.OS }}-cargo-${{ hashFiles('**/Cargo.lock') }} + restore-keys: | + ${{ runner.OS }}-cargo-${{ hashFiles('**/Cargo.lock') }} + ${{ runner.OS }}-cargo- + + - name: Cache build output dependencies + uses: actions/cache@v2 + with: + path: target + key: ${{ runner.OS }}-build-${{ hashFiles('**/Cargo.lock') }} + restore-keys: | + ${{ runner.OS }}-build-${{ hashFiles('**/Cargo.lock') }} + ${{ runner.OS }}-build- + + - name: Install Rust ${{ matrix.toolchain }} with target (${{ matrix.target }}) + uses: actions-rs/toolchain@v1 + with: + toolchain: ${{ matrix.toolchain }} + target: ${{ matrix.target }} + override: true + components: llvm-tools-preview + # Use precompiled binutils - name: cargo install cargo-binutils uses: actions-rs/install@v0.1 @@ -306,7 +346,6 @@ jobs: - x86_64-unknown-linux-gnu toolchain: - stable - - 1.36.0 steps: - name: Checkout uses: actions/checkout@v2 @@ -340,10 +379,6 @@ jobs: target: ${{ matrix.target }} override: true - - name: Disable optimisation profiles - if: matrix.toolchain == '1.36.0' - run: sed -i '/^\[profile.*build-override]$/,/^$/{/^#/!{/^$/!d}}' Cargo.toml - - name: cargo check uses: actions-rs/cargo@v1 with: @@ -351,6 +386,56 @@ jobs: command: check args: --manifest-path macros/Cargo.toml --target=${{ matrix.target }} + # Run the macros test-suite + testmacros: + name: testmacros + runs-on: ubuntu-20.04 + strategy: + matrix: + target: + - x86_64-unknown-linux-gnu + toolchain: + - stable + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Cache cargo dependencies + uses: actions/cache@v2 + with: + path: | + - ~/.cargo/bin/ + - ~/.cargo/registry/index/ + - ~/.cargo/registry/cache/ + - ~/.cargo/git/db/ + key: ${{ runner.OS }}-cargo-${{ hashFiles('**/Cargo.lock') }} + restore-keys: | + ${{ runner.OS }}-cargo-${{ hashFiles('**/Cargo.lock') }} + ${{ runner.OS }}-cargo- + + - name: Cache build output dependencies + uses: actions/cache@v2 + with: + path: target + key: ${{ runner.OS }}-build-${{ hashFiles('**/Cargo.lock') }} + restore-keys: | + ${{ runner.OS }}-build-${{ hashFiles('**/Cargo.lock') }} + ${{ runner.OS }}-build- + + - name: Install Rust ${{ matrix.toolchain }} with target (${{ matrix.target }}) + uses: actions-rs/toolchain@v1 + with: + toolchain: ${{ matrix.toolchain }} + target: ${{ matrix.target }} + override: true + + - name: cargo check + uses: actions-rs/cargo@v1 + with: + use-cross: false + command: test + args: --manifest-path macros/Cargo.toml --target=${{ matrix.target }} + # Run test suite for thumbv7m testv7: name: testv7 @@ -382,13 +467,10 @@ jobs: - name: Install Rust uses: actions-rs/toolchain@v1 with: - toolchain: 1.36.0 + toolchain: stable target: thumbv7m-none-eabi override: true - - name: Disable optimisation profiles - run: sed -i '/^\[profile.*build-override]$/,/^$/{/^#/!{/^$/!d}}' Cargo.toml - - uses: actions-rs/cargo@v1 with: use-cross: false @@ -426,13 +508,10 @@ jobs: - name: Install Rust uses: actions-rs/toolchain@v1 with: - toolchain: 1.36.0 + toolchain: stable target: thumbv6m-none-eabi override: true - - name: Disable optimisation profiles - run: sed -i '/^\[profile.*build-override]$/,/^$/{/^#/!{/^$/!d}}' Cargo.toml - - uses: actions-rs/cargo@v1 with: use-cross: false @@ -529,7 +608,7 @@ jobs: - name: mdBook Action uses: peaceiris/actions-mdbook@v1.1.11 with: - mdbook-version: '0.3.1' + mdbook-version: 'latest' - name: Build book in English run: cd book/en && mdbook build @@ -557,7 +636,9 @@ jobs: - style - check - checkexamples + - testexamples - checkmacros + - testmacros - testv7 - testv6 - docs @@ -582,8 +663,7 @@ jobs: - name: mdBook Action uses: peaceiris/actions-mdbook@v1.1.11 with: - mdbook-version: '0.3.1' - # mdbook-version: 'latest' + mdbook-version: 'latest' - name: Remove cargo-config run: rm -f .cargo/config @@ -594,27 +674,37 @@ jobs: - name: Build books run: | langs=( en ru ) - latest=0.5 - vers=( 0.4.x ) + devver=( dev ) + # The latest stable must be the first element in the array + vers=( 0.5.x 0.4.x ) + + # All releases start with "v" + # followed by MAJOR.MINOR.PATCH, see semver.org + # Retain MAJOR.MINOR as $stable + stable=${vers%.*} + + echo "Stable version: $stable" # Create directories td=$(mktemp -d) - mkdir -p $td/$latest/book/ - cp -r target/doc $td/$latest/api + mkdir -p $td/$devver/book/ + cp -r target/doc $td/$devver/api - # sed fixes - sed 's|URL|rtic/index.html|g' redirect.html > $td/$latest/api/index.html - sed 's|URL|0.5|g' redirect.html > $td/index.html - sed 's|URL|book/en|g' redirect.html > $td/$latest/index.html + # Redirect the main site to the stable release + sed "s|URL|$stable|g" redirect.html > $td/index.html + + # Create the redirects for dev-version + sed 's|URL|rtic/index.html|g' redirect.html > $td/$devver/api/index.html + sed 's|URL|book/en|g' redirect.html > $td/$devver/index.html # Build books for lang in ${langs[@]}; do ( cd book/$lang && mdbook build ) - cp -r book/$lang/book $td/$latest/book/$lang - cp LICENSE-* $td/$latest/book/$lang/ + cp -r book/$lang/book $td/$devver/book/$lang + cp LICENSE-* $td/$devver/book/$lang/ done - # Build older versions + # Build older versions, including stable root=$(pwd) for ver in ${vers[@]}; do prefix=${ver%.*} @@ -639,6 +729,9 @@ jobs: rm -rf $src done + # Copy the stable book to the stable alias + cp -r $td/$stable $td/stable + # Forward CNAME file cp CNAME $td/ mv $td/ bookstodeploy @@ -660,7 +753,9 @@ jobs: - style - check - checkexamples + - testexamples - checkmacros + - testmacros - testv7 - testv6 - docs @@ -676,7 +771,9 @@ jobs: - style - check - checkexamples + - testexamples - checkmacros + - testmacros - testv7 - testv6 - docs diff --git a/Cargo.toml b/Cargo.toml index d4ad4ef05e..6fe5fce38f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -60,6 +60,7 @@ cortex-m-rtic-macros = { path = "macros", version = "0.5.2" } rtic-core = "0.3.0" cortex-m-rt = "0.6.9" heapless = "0.5.0" +bare-metal = "1.0.0" [build-dependencies] version_check = "0.9" diff --git a/README.md b/README.md index 45bb9de840..18f968dbb2 100644 --- a/README.md +++ b/README.md @@ -4,9 +4,9 @@ A concurrency framework for building real-time systems. Formerly known as Real-Time For the Masses. -![crates.io](https://img.shields.io/crates/v/cortex-m-rtic) -![docs.rs](https://docs.rs/cortex-m-rtic/badge.svg) -![book](https://img.shields.io/badge/web-rtic.rs-red.svg?style=flat&label=book&colorB=d33847) +[![crates.io](https://img.shields.io/crates/v/cortex-m-rtic)](https://crates.io/crates/cortex-m-rtic) +[![docs.rs](https://docs.rs/cortex-m-rtic/badge.svg)](https://docs.rs/cortex-m-rtic) +[![book](https://img.shields.io/badge/web-rtic.rs-red.svg?style=flat&label=book&colorB=d33847)](https://rtic.rs/) ![rustc](https://img.shields.io/badge/rustc-1.36+-lightgray.svg) ## Features diff --git a/book/en/src/SUMMARY.md b/book/en/src/SUMMARY.md index 25aef811b9..e1a4a330c7 100644 --- a/book/en/src/SUMMARY.md +++ b/book/en/src/SUMMARY.md @@ -10,8 +10,10 @@ - [Types, Send and Sync](./by-example/types-send-sync.md) - [Starting a new project](./by-example/new.md) - [Tips & tricks](./by-example/tips.md) -- [Migrating from v0.4.x to v0.5.0](./migration.md) -- [Migrating from RTFM to RTIC](./migration_rtic.md) +- [Migration Guides](./migration.md) + - [v0.5.x to v0.6.x](./migration/migration_v5.md) + - [v0.4.x to v0.5.x](./migration/migration_v4.md) + - [RTFM to RTIC](./migration/migration_rtic.md) - [Under the hood](./internals.md) - [Interrupt configuration](./internals/interrupt-configuration.md) - [Non-reentrancy](./internals/non-reentrancy.md) @@ -21,5 +23,3 @@ - [Ceiling analysis](./internals/ceilings.md) - [Software tasks](./internals/tasks.md) - [Timer queue](./internals/timer-queue.md) -- [Homogeneous multi-core support](./homogeneous.md) -- [Heterogeneous multi-core support](./heterogeneous.md) diff --git a/book/en/src/by-example.md b/book/en/src/by-example.md index d4527223e4..e4441fd962 100644 --- a/book/en/src/by-example.md +++ b/book/en/src/by-example.md @@ -9,8 +9,16 @@ is required to follow along. [repository]: https://github.com/rtic-rs/cortex-m-rtic -To run the examples on your laptop / PC you'll need the `qemu-system-arm` +To run the examples on your computer you'll need the `qemu-system-arm` program. Check [the embedded Rust book] for instructions on how to set up an embedded development environment that includes QEMU. [the embedded Rust book]: https://rust-embedded.github.io/book/intro/install.html + +## Real World Examples + +The following are examples of RTFM being used in real world projects. + +### RTFM V0.4.2 + +- [etrombly/sandbox](https://github.com/etrombly/sandbox/tree/41d423bcdd0d8e42fd46b79771400a8ca349af55). A hardware zen garden that draws patterns in sand. Patterns are sent over serial using G-code. diff --git a/book/en/src/by-example/app.md b/book/en/src/by-example/app.md index 344cefc7aa..ab6f45240f 100644 --- a/book/en/src/by-example/app.md +++ b/book/en/src/by-example/app.md @@ -7,7 +7,7 @@ This is the smallest possible RTIC application: ``` All RTIC applications use the [`app`] attribute (`#[app(..)]`). This attribute -must be applied to a `const` item that contains items. The `app` attribute has +must be applied to a `mod`-item. The `app` attribute has a mandatory `device` argument that takes a *path* as a value. This path must point to a *peripheral access crate* (PAC) generated using [`svd2rust`] **v0.14.x** or newer. The `app` attribute will expand into a suitable entry @@ -17,31 +17,25 @@ point so it's not required to use the [`cortex_m_rt::entry`] attribute. [`svd2rust`]: https://crates.io/crates/svd2rust [`cortex_m_rt::entry`]: ../../../api/cortex_m_rt_macros/attr.entry.html -> **ASIDE**: Some of you may be wondering why we are using a `const` item as a -> module and not a proper `mod` item. The reason is that using attributes on -> modules requires a feature gate, which requires a nightly toolchain. To make -> RTIC work on stable we use the `const` item instead. When more parts of macros -> 1.2 are stabilized we'll move from a `const` item to a `mod` item and -> eventually to a crate level attribute (`#![app]`). - ## `init` -Within the pseudo-module the `app` attribute expects to find an initialization +Within the `app` module the attribute expects to find an initialization function marked with the `init` attribute. This function must have signature `fn(init::Context) [-> init::LateResources]` (the return type is not always required). This initialization function will be the first part of the application to run. The `init` function will run *with interrupts disabled* and has exclusive access -to Cortex-M and, optionally, device specific peripherals through the `core` and -`device` fields of `init::Context`. +to Cortex-M where the `bare_metal::CriticalSection` token is available as `cs`. +And optionally, device specific peripherals through the `core` and `device` fields +of `init::Context`. `static mut` variables declared at the beginning of `init` will be transformed into `&'static mut` references that are safe to access. [`rtic::Peripherals`]: ../../api/rtic/struct.Peripherals.html -The example below shows the types of the `core` and `device` fields and +The example below shows the types of the `core`, `device` and `cs` fields, and showcases safe access to a `static mut` variable. The `device` field is only available when the `peripherals` argument is set to `true` (it defaults to `false`). @@ -61,7 +55,7 @@ $ cargo run --example init ## `idle` A function marked with the `idle` attribute can optionally appear in the -pseudo-module. This function is used as the special *idle task* and must have +module. This function is used as the special *idle task* and must have signature `fn(idle::Context) - > !`. When present, the runtime will execute the `idle` task after `init`. Unlike diff --git a/book/en/src/by-example/resources.md b/book/en/src/by-example/resources.md index 9b6e5a809f..9d90fbe366 100644 --- a/book/en/src/by-example/resources.md +++ b/book/en/src/by-example/resources.md @@ -4,11 +4,13 @@ The framework provides an abstraction to share data between any of the contexts we saw in the previous section (task handlers, `init` and `idle`): resources. Resources are data visible only to functions declared within the `#[app]` -pseudo-module. The framework gives the user complete control over which context +module. The framework gives the user complete control over which context can access which resource. All resources are declared as a single `struct` within the `#[app]` -pseudo-module. Each field in the structure corresponds to a different resource. +module. Each field in the structure corresponds to a different resource. +The `struct` must be annotated with the following attribute: `#[resources]`. + Resources can optionally be given an initial value using the `#[init]` attribute. Resources that are not given an initial value are referred to as *late* resources and are covered in more detail in a follow-up section in this diff --git a/book/en/src/by-example/tasks.md b/book/en/src/by-example/tasks.md index 345e224e16..ba16404841 100644 --- a/book/en/src/by-example/tasks.md +++ b/book/en/src/by-example/tasks.md @@ -95,7 +95,7 @@ following snippet: ``` rust #[rtic::app(..)] -const APP: () = { +mod app { #[init(spawn = [foo, bar])] fn init(cx: init::Context) { cx.spawn.foo().unwrap(); @@ -116,5 +116,5 @@ const APP: () = { fn bar(cx: bar::Context, payload: i32) { // .. } -}; +} ``` diff --git a/book/en/src/by-example/tips.md b/book/en/src/by-example/tips.md index 98c1abbf1e..090b30ad35 100644 --- a/book/en/src/by-example/tips.md +++ b/book/en/src/by-example/tips.md @@ -144,7 +144,7 @@ $ tail target/rtic-expansion.rs ``` rust #[doc = r" Implementation details"] -const APP: () = { +mod app { #[doc = r" Always include the device crate which contains the vector table"] use lm3s6965 as _; #[no_mangle] @@ -157,7 +157,7 @@ const APP: () = { rtic::export::wfi() } } -}; +} ``` Or, you can use the [`cargo-expand`] sub-command. This sub-command will expand diff --git a/book/en/src/by-example/types-send-sync.md b/book/en/src/by-example/types-send-sync.md index 41cd9ba92c..9cdb88945f 100644 --- a/book/en/src/by-example/types-send-sync.md +++ b/book/en/src/by-example/types-send-sync.md @@ -1,6 +1,6 @@ # Types, Send and Sync -Every function within the `APP` pseudo-module has a `Context` structure as its +Every function within the `app` module has a `Context` structure as its first parameter. All the fields of these structures have predictable, non-anonymous types so you can write plain functions that take them as arguments. diff --git a/book/en/src/heterogeneous.md b/book/en/src/heterogeneous.md deleted file mode 100644 index d2c3d6c548..0000000000 --- a/book/en/src/heterogeneous.md +++ /dev/null @@ -1,6 +0,0 @@ -# Heterogeneous multi-core support - -This section covers the *experimental* heterogeneous multi-core support provided -by RTIC behind the `heterogeneous` Cargo feature. - -**Content coming soon** diff --git a/book/en/src/homogeneous.md b/book/en/src/homogeneous.md deleted file mode 100644 index bcf6d2bef9..0000000000 --- a/book/en/src/homogeneous.md +++ /dev/null @@ -1,6 +0,0 @@ -# Homogeneous multi-core support - -This section covers the *experimental* homogeneous multi-core support provided -by RTIC behind the `homogeneous` Cargo feature. - -**Content coming soon** diff --git a/book/en/src/internals/access.md b/book/en/src/internals/access.md index 6433707ea1..3894470c09 100644 --- a/book/en/src/internals/access.md +++ b/book/en/src/internals/access.md @@ -15,7 +15,7 @@ To achieve the fine-grained access control where tasks can only access the static variables (resources) that they have specified in their RTIC attribute the RTIC framework performs a source code level transformation. This transformation consists of placing the resources (static variables) specified by -the user *inside* a `const` item and the user code *outside* the `const` item. +the user *inside* a module and the user code *outside* the module. This makes it impossible for the user code to refer to these static variables. Access to the resources is then given to each task using a `Resources` struct @@ -29,7 +29,7 @@ happens behind the scenes: ``` rust #[rtic::app(device = ..)] -const APP: () = { +mod app { static mut X: u64: 0; static mut Y: bool: 0; @@ -49,7 +49,7 @@ const APP: () = { } // .. -}; +} ``` The framework produces codes like this: @@ -103,8 +103,8 @@ pub mod bar { } /// Implementation details -const APP: () = { - // everything inside this `const` item is hidden from user code +mod app { + // everything inside this module is hidden from user code static mut X: u64 = 0; static mut Y: bool = 0; @@ -154,5 +154,5 @@ const APP: () = { // .. }); } -}; +} ``` diff --git a/book/en/src/internals/ceilings.md b/book/en/src/internals/ceilings.md index 49d248adf3..07bd0adda0 100644 --- a/book/en/src/internals/ceilings.md +++ b/book/en/src/internals/ceilings.md @@ -28,7 +28,7 @@ An example to illustrate the ceiling analysis: ``` rust #[rtic::app(device = ..)] -const APP: () = { +mod app { struct Resources { // accessed by `foo` (prio = 1) and `bar` (prio = 2) // -> CEILING = 2 @@ -80,5 +80,5 @@ const APP: () = { } // .. -}; +} ``` diff --git a/book/en/src/internals/critical-sections.md b/book/en/src/internals/critical-sections.md index f95a5a7a3b..a064ad09a8 100644 --- a/book/en/src/internals/critical-sections.md +++ b/book/en/src/internals/critical-sections.md @@ -32,7 +32,7 @@ The example below shows the different types handed out to each task: ``` rust #[rtic::app(device = ..)] -const APP: () = { +mut app { struct Resources { #[init(0)] x: u64, @@ -57,7 +57,7 @@ const APP: () = { } // .. -}; +} ``` Now let's see how these types are created by the framework. @@ -99,7 +99,7 @@ pub mod bar { } } -const APP: () = { +mod app { static mut x: u64 = 0; impl rtic::Mutex for resources::x { @@ -129,7 +129,7 @@ const APP: () = { // .. }) } -}; +} ``` ## `lock` @@ -225,7 +225,7 @@ Consider this program: ``` rust #[rtic::app(device = ..)] -const APP: () = { +mod app { struct Resources { #[init(0)] x: u64, @@ -277,7 +277,7 @@ const APP: () = { } // .. -}; +} ``` The code generated by the framework looks like this: @@ -315,7 +315,7 @@ pub mod foo { } } -const APP: () = { +mod app { use cortex_m::register::basepri; #[no_mangle] @@ -368,7 +368,7 @@ const APP: () = { } // repeat for resource `y` -}; +} ``` At the end the compiler will optimize the function `foo` into something like @@ -430,7 +430,7 @@ handler through preemption. This is best observed in the following example: ``` rust #[rtic::app(device = ..)] -const APP: () = { +mod app { struct Resources { #[init(0)] x: u64, @@ -484,7 +484,7 @@ const APP: () = { // .. } -}; +} ``` IMPORTANT: let's say we *forget* to roll back `BASEPRI` in `UART1` -- this would @@ -493,7 +493,7 @@ be a bug in the RTIC code generator. ``` rust // code generated by RTIC -const APP: () = { +mod app { // .. #[no_mangle] @@ -513,7 +513,7 @@ const APP: () = { // BUG: FORGOT to roll back the BASEPRI to the snapshot value we took before basepri::write(initial); } -}; +} ``` The consequence is that `idle` will run at a dynamic priority of `2` and in fact diff --git a/book/en/src/internals/interrupt-configuration.md b/book/en/src/internals/interrupt-configuration.md index 278707c0ad..7aec9c9f4d 100644 --- a/book/en/src/internals/interrupt-configuration.md +++ b/book/en/src/internals/interrupt-configuration.md @@ -13,7 +13,7 @@ This example gives you an idea of the code that the RTIC framework runs: ``` rust #[rtic::app(device = lm3s6965)] -const APP: () = { +mod app { #[init] fn init(c: init::Context) { // .. user code .. @@ -28,7 +28,7 @@ const APP: () = { fn foo(c: foo::Context) { // .. user code .. } -}; +} ``` The framework generates an entry point that looks like this: diff --git a/book/en/src/internals/late-resources.md b/book/en/src/internals/late-resources.md index ad2a5e51ed..f3a0b0ae2a 100644 --- a/book/en/src/internals/late-resources.md +++ b/book/en/src/internals/late-resources.md @@ -10,7 +10,7 @@ initialize late resources. ``` rust #[rtic::app(device = ..)] -const APP: () = { +mod app { struct Resources { x: Thing, } @@ -34,7 +34,7 @@ const APP: () = { } // .. -}; +} ``` The code generated by the framework looks like this: @@ -69,7 +69,7 @@ pub mod foo { } /// Implementation details -const APP: () = { +mod app { // uninitialized static static mut x: MaybeUninit = MaybeUninit::uninit(); @@ -101,7 +101,7 @@ const APP: () = { // .. }) } -}; +} ``` An important detail here is that `interrupt::enable` behaves like a *compiler diff --git a/book/en/src/internals/non-reentrancy.md b/book/en/src/internals/non-reentrancy.md index 0b0e4a7342..17b34d0ca9 100644 --- a/book/en/src/internals/non-reentrancy.md +++ b/book/en/src/internals/non-reentrancy.md @@ -12,7 +12,7 @@ are discouraged from directly invoking an interrupt handler. ``` rust #[rtic::app(device = ..)] -const APP: () = { +mod app { #[init] fn init(c: init::Context) { .. } @@ -39,7 +39,7 @@ const APP: () = { // in aliasing of the static variable `X` unsafe { UART0() } } -}; +} ``` The RTIC framework must generate the interrupt handler code that calls the user @@ -57,7 +57,7 @@ fn bar(c: bar::Context) { // .. user code .. } -const APP: () = { +mod app { // everything in this block is not visible to user code #[no_mangle] @@ -69,7 +69,7 @@ const APP: () = { unsafe fn USART1() { bar(..); } -}; +} ``` ## By hardware diff --git a/book/en/src/internals/tasks.md b/book/en/src/internals/tasks.md index 995a88577b..a533dc0c26 100644 --- a/book/en/src/internals/tasks.md +++ b/book/en/src/internals/tasks.md @@ -28,7 +28,7 @@ Consider this example: ``` rust #[rtic::app(device = ..)] -const APP: () = { +mod app { // .. #[interrupt(binds = UART0, priority = 2, spawn = [bar, baz])] @@ -51,7 +51,7 @@ const APP: () = { extern "C" { fn UART1(); } -}; +} ``` The framework produces the following task dispatcher which consists of an @@ -62,7 +62,7 @@ fn bar(c: bar::Context) { // .. user code .. } -const APP: () = { +mod app { use heapless::spsc::Queue; use cortex_m::register::basepri; @@ -110,7 +110,7 @@ const APP: () = { // BASEPRI invariant basepri::write(snapshot); } -}; +} ``` ## Spawning a task @@ -144,7 +144,7 @@ mod foo { } } -const APP: () = { +mod app { // .. // Priority ceiling for the producer endpoint of the `RQ1` @@ -194,7 +194,7 @@ const APP: () = { } } } -}; +} ``` Using `bar_FQ` to limit the number of `bar` tasks that can be spawned may seem @@ -211,7 +211,7 @@ fn baz(c: baz::Context, input: u64) { // .. user code .. } -const APP: () = { +mod app { // .. // Now we show the full contents of the `Ready` struct @@ -263,13 +263,13 @@ const APP: () = { } } } -}; +} ``` And now let's look at the real implementation of the task dispatcher: ``` rust -const APP: () = { +mod app { // .. #[no_mangle] @@ -304,7 +304,7 @@ const APP: () = { // BASEPRI invariant basepri::write(snapshot); } -}; +} ``` `INPUTS` plus `FQ`, the free queue, is effectively a memory pool. However, @@ -357,7 +357,7 @@ Consider the following example: ``` rust #[rtic::app(device = ..)] -const APP: () = { +mod app { #[idle(spawn = [foo, bar])] fn idle(c: idle::Context) -> ! { // .. @@ -382,7 +382,7 @@ const APP: () = { fn quux(c: quux::Context) { // .. } -}; +} ``` This is how the ceiling analysis would go: diff --git a/book/en/src/internals/timer-queue.md b/book/en/src/internals/timer-queue.md index 0eba106904..fcd345c51a 100644 --- a/book/en/src/internals/timer-queue.md +++ b/book/en/src/internals/timer-queue.md @@ -12,7 +12,7 @@ Let's see how this in implemented in code. Consider the following program: ``` rust #[rtic::app(device = ..)] -const APP: () = { +mod app { // .. #[task(capacity = 2, schedule = [foo])] @@ -24,7 +24,7 @@ const APP: () = { extern "C" { fn UART0(); } -}; +} ``` ## `schedule` @@ -46,7 +46,7 @@ mod foo { } } -const APP: () = { +mod app { type Instant = ::Instant; // all tasks that can be `schedule`-d @@ -100,7 +100,7 @@ const APP: () = { } } } -}; +} ``` This looks very similar to the `Spawn` implementation. In fact, the same @@ -123,7 +123,7 @@ is up. Let's see the associated code. ``` rust -const APP: () = { +mod app { #[no_mangle] fn SysTick() { const PRIORITY: u8 = 1; @@ -146,7 +146,7 @@ const APP: () = { } } } -}; +} ``` This looks similar to a task dispatcher except that instead of running the @@ -197,7 +197,7 @@ able to insert the task in the timer queue; this lets us omit runtime checks. ## System timer priority -The priority of the system timer can't set by the user; it is chosen by the +The priority of the system timer can't be set by the user; it is chosen by the framework. To ensure that lower priority tasks don't prevent higher priority tasks from running we choose the priority of the system timer to be the maximum of all the `schedule`-able tasks. @@ -222,7 +222,7 @@ To illustrate, consider the following example: ``` rust #[rtic::app(device = ..)] -const APP: () = { +mod app { #[task(priority = 3, spawn = [baz])] fn foo(c: foo::Context) { // .. @@ -237,7 +237,7 @@ const APP: () = { fn baz(c: baz::Context) { // .. } -}; +} ``` The ceiling analysis would go like this: @@ -246,7 +246,7 @@ The ceiling analysis would go like this: `SysTick` must run at the highest priority between these two, that is `3`. - `foo::Spawn` (prio = 3) and `bar::Schedule` (prio = 2) contend over the - consumer endpoind of `baz_FQ`; this leads to a priority ceiling of `3`. + consumer endpoint of `baz_FQ`; this leads to a priority ceiling of `3`. - `bar::Schedule` (prio = 2) has exclusive access over the consumer endpoint of `foo_FQ`; thus the priority ceiling of `foo_FQ` is effectively `2`. @@ -270,7 +270,7 @@ run; this `Instant` is read in the task dispatcher and passed to the user code as part of the task context. ``` rust -const APP: () = { +mod app { // .. #[no_mangle] @@ -303,7 +303,7 @@ const APP: () = { // BASEPRI invariant basepri::write(snapshot); } -}; +} ``` Conversely, the `spawn` implementation needs to write a value to the `INSTANTS` @@ -333,7 +333,7 @@ mod foo { } } -const APP: () = { +mod app { impl<'a> foo::Spawn<'a> { /// Spawns the `baz` task pub fn baz(&self, message: u64) -> Result<(), u64> { @@ -364,5 +364,5 @@ const APP: () = { } } } -}; +} ``` diff --git a/book/en/src/migration.md b/book/en/src/migration.md index d382db1724..08feb81e1e 100644 --- a/book/en/src/migration.md +++ b/book/en/src/migration.md @@ -1,232 +1,4 @@ -# Migrating from v0.4.x to v0.5.0 +# Migration Guides -This section covers how to upgrade an application written against RTIC v0.4.x to -the version v0.5.0 of the framework. - -## `Cargo.toml` - -First, the version of the `cortex-m-rtic` dependency needs to be updated to -`"0.5.0"`. The `timer-queue` feature needs to be removed. - -``` toml -[dependencies.cortex-m-rtic] -# change this -version = "0.4.3" - -# into this -version = "0.5.0" - -# and remove this Cargo feature -features = ["timer-queue"] -# ^^^^^^^^^^^^^ -``` - -## `Context` argument - -All functions inside the `#[rtic::app]` item need to take as first argument a -`Context` structure. This `Context` type will contain the variables that were -magically injected into the scope of the function by version v0.4.x of the -framework: `resources`, `spawn`, `schedule` -- these variables will become -fields of the `Context` structure. Each function within the `#[rtic::app]` item -gets a different `Context` type. - -``` rust -#[rtic::app(/* .. */)] -const APP: () = { - // change this - #[task(resources = [x], spawn = [a], schedule = [b])] - fn foo() { - resources.x.lock(|x| /* .. */); - spawn.a(message); - schedule.b(baseline); - } - - // into this - #[task(resources = [x], spawn = [a], schedule = [b])] - fn foo(mut cx: foo::Context) { - // ^^^^^^^^^^^^^^^^^^^^ - - cx.resources.x.lock(|x| /* .. */); - // ^^^ - - cx.spawn.a(message); - // ^^^ - - cx.schedule.b(message, baseline); - // ^^^ - } - - // change this - #[init] - fn init() { - // .. - } - - // into this - #[init] - fn init(cx: init::Context) { - // ^^^^^^^^^^^^^^^^^ - // .. - } - - // .. -}; -``` - -## Resources - -The syntax used to declare resources has been changed from `static mut` -variables to a `struct Resources`. - -``` rust -#[rtic::app(/* .. */)] -const APP: () = { - // change this - static mut X: u32 = 0; - static mut Y: u32 = (); // late resource - - // into this - struct Resources { - #[init(0)] // <- initial value - X: u32, // NOTE: we suggest changing the naming style to `snake_case` - - Y: u32, // late resource - } - - // .. -}; -``` - -## Device peripherals - -If your application was accessing the device peripherals in `#[init]` through -the `device` variable then you'll need to add `peripherals = true` to the -`#[rtic::app]` attribute to continue to access the device peripherals through -the `device` field of the `init::Context` structure. - -Change this: - -``` rust -#[rtic::app(/* .. */)] -const APP: () = { - #[init] - fn init() { - device.SOME_PERIPHERAL.write(something); - } - - // .. -}; -``` - -Into this: - -``` rust -#[rtic::app(/* .. */, peripherals = true)] -// ^^^^^^^^^^^^^^^^^^ -const APP: () = { - #[init] - fn init(cx: init::Context) { - // ^^^^^^^^^^^^^^^^^ - cx.device.SOME_PERIPHERAL.write(something); - // ^^^ - } - - // .. -}; -``` - -## `#[interrupt]` and `#[exception]` - -The `#[interrupt]` and `#[exception]` attributes have been removed. To declare -hardware tasks in v0.5.x use the `#[task]` attribute with the `binds` argument. - -Change this: - -``` rust -#[rtic::app(/* .. */)] -const APP: () = { - // hardware tasks - #[exception] - fn SVCall() { /* .. */ } - - #[interrupt] - fn UART0() { /* .. */ } - - // software task - #[task] - fn foo() { /* .. */ } - - // .. -}; -``` - -Into this: - -``` rust -#[rtic::app(/* .. */)] -const APP: () = { - #[task(binds = SVCall)] - // ^^^^^^^^^^^^^^ - fn svcall(cx: svcall::Context) { /* .. */ } - // ^^^^^^ we suggest you use a `snake_case` name here - - #[task(binds = UART0)] - // ^^^^^^^^^^^^^ - fn uart0(cx: uart0::Context) { /* .. */ } - - #[task] - fn foo(cx: foo::Context) { /* .. */ } - - // .. -}; -``` - -## `schedule` - -The `timer-queue` feature has been removed. To use the `schedule` API one must -first define the monotonic timer the runtime will use using the `monotonic` -argument of the `#[rtic::app]` attribute. To continue using the cycle counter -(CYCCNT) as the monotonic timer, and match the behavior of version v0.4.x, add -the `monotonic = rtic::cyccnt::CYCCNT` argument to the `#[rtic::app]` attribute. - -Also, the `Duration` and `Instant` types and the `U32Ext` trait have been moved -into the `rtic::cyccnt` module. This module is only available on ARMv7-M+ -devices. The removal of the `timer-queue` also brings back the `DWT` peripheral -inside the core peripherals struct, this will need to be enabled by the application -inside `init`. - -Change this: - -``` rust -use rtic::{Duration, Instant, U32Ext}; - -#[rtic::app(/* .. */)] -const APP: () = { - #[task(schedule = [b])] - fn a() { - // .. - } -}; -``` - -Into this: - -``` rust -use rtic::cyccnt::{Duration, Instant, U32Ext}; -// ^^^^^^^^ - -#[rtic::app(/* .. */, monotonic = rtic::cyccnt::CYCCNT)] -// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -const APP: () = { - #[init] - fn init(cx: init::Context) { - cx.core.DWT.enable_cycle_counter(); - // optional, configure the DWT run without a debugger connected - cx.core.DCB.enable_trace(); - } - #[task(schedule = [b])] - fn a(cx: a::Context) { - // .. - } -}; -``` +This section describes how to migrate between different version of RTIC. +It also acts as a comparing reference between versions. diff --git a/book/en/src/migration_rtic.md b/book/en/src/migration/migration_rtic.md similarity index 100% rename from book/en/src/migration_rtic.md rename to book/en/src/migration/migration_rtic.md diff --git a/book/en/src/migration/migration_v4.md b/book/en/src/migration/migration_v4.md new file mode 100644 index 0000000000..2c4e3ade6f --- /dev/null +++ b/book/en/src/migration/migration_v4.md @@ -0,0 +1,232 @@ +# Migrating from v0.4.x to v0.5.0 + +This section covers how to upgrade an application written against RTIC v0.4.x to +the version v0.5.0 of the framework. + +### `Cargo.toml` + +First, the version of the `cortex-m-rtic` dependency needs to be updated to +`"0.5.0"`. The `timer-queue` feature needs to be removed. + +``` toml +[dependencies.cortex-m-rtic] +# change this +version = "0.4.3" + +# into this +version = "0.5.0" + +# and remove this Cargo feature +features = ["timer-queue"] +# ^^^^^^^^^^^^^ +``` + +### `Context` argument + +All functions inside the `#[rtic::app]` item need to take as first argument a +`Context` structure. This `Context` type will contain the variables that were +magically injected into the scope of the function by version v0.4.x of the +framework: `resources`, `spawn`, `schedule` -- these variables will become +fields of the `Context` structure. Each function within the `#[rtic::app]` item +gets a different `Context` type. + +``` rust +#[rtic::app(/* .. */)] +const APP: () = { + // change this + #[task(resources = [x], spawn = [a], schedule = [b])] + fn foo() { + resources.x.lock(|x| /* .. */); + spawn.a(message); + schedule.b(baseline); + } + + // into this + #[task(resources = [x], spawn = [a], schedule = [b])] + fn foo(mut cx: foo::Context) { + // ^^^^^^^^^^^^^^^^^^^^ + + cx.resources.x.lock(|x| /* .. */); + // ^^^ + + cx.spawn.a(message); + // ^^^ + + cx.schedule.b(message, baseline); + // ^^^ + } + + // change this + #[init] + fn init() { + // .. + } + + // into this + #[init] + fn init(cx: init::Context) { + // ^^^^^^^^^^^^^^^^^ + // .. + } + + // .. +}; +``` + +### Resources + +The syntax used to declare resources has been changed from `static mut` +variables to a `struct Resources`. + +``` rust +#[rtic::app(/* .. */)] +const APP: () = { + // change this + static mut X: u32 = 0; + static mut Y: u32 = (); // late resource + + // into this + struct Resources { + #[init(0)] // <- initial value + X: u32, // NOTE: we suggest changing the naming style to `snake_case` + + Y: u32, // late resource + } + + // .. +}; +``` + +### Device peripherals + +If your application was accessing the device peripherals in `#[init]` through +the `device` variable then you'll need to add `peripherals = true` to the +`#[rtic::app]` attribute to continue to access the device peripherals through +the `device` field of the `init::Context` structure. + +Change this: + +``` rust +#[rtic::app(/* .. */)] +const APP: () = { + #[init] + fn init() { + device.SOME_PERIPHERAL.write(something); + } + + // .. +}; +``` + +Into this: + +``` rust +#[rtic::app(/* .. */, peripherals = true)] +// ^^^^^^^^^^^^^^^^^^ +const APP: () = { + #[init] + fn init(cx: init::Context) { + // ^^^^^^^^^^^^^^^^^ + cx.device.SOME_PERIPHERAL.write(something); + // ^^^ + } + + // .. +}; +``` + +### `#[interrupt]` and `#[exception]` + +The `#[interrupt]` and `#[exception]` attributes have been removed. To declare +hardware tasks in v0.5.x use the `#[task]` attribute with the `binds` argument. + +Change this: + +``` rust +#[rtic::app(/* .. */)] +const APP: () = { + // hardware tasks + #[exception] + fn SVCall() { /* .. */ } + + #[interrupt] + fn UART0() { /* .. */ } + + // software task + #[task] + fn foo() { /* .. */ } + + // .. +}; +``` + +Into this: + +``` rust +#[rtic::app(/* .. */)] +const APP: () = { + #[task(binds = SVCall)] + // ^^^^^^^^^^^^^^ + fn svcall(cx: svcall::Context) { /* .. */ } + // ^^^^^^ we suggest you use a `snake_case` name here + + #[task(binds = UART0)] + // ^^^^^^^^^^^^^ + fn uart0(cx: uart0::Context) { /* .. */ } + + #[task] + fn foo(cx: foo::Context) { /* .. */ } + + // .. +}; +``` + +### `schedule` + +The `timer-queue` feature has been removed. To use the `schedule` API one must +first define the monotonic timer the runtime will use using the `monotonic` +argument of the `#[rtic::app]` attribute. To continue using the cycle counter +(CYCCNT) as the monotonic timer, and match the behavior of version v0.4.x, add +the `monotonic = rtic::cyccnt::CYCCNT` argument to the `#[rtic::app]` attribute. + +Also, the `Duration` and `Instant` types and the `U32Ext` trait have been moved +into the `rtic::cyccnt` module. This module is only available on ARMv7-M+ +devices. The removal of the `timer-queue` also brings back the `DWT` peripheral +inside the core peripherals struct, this will need to be enabled by the application +inside `init`. + +Change this: + +``` rust +use rtic::{Duration, Instant, U32Ext}; + +#[rtic::app(/* .. */)] +const APP: () = { + #[task(schedule = [b])] + fn a() { + // .. + } +}; +``` + +Into this: + +``` rust +use rtic::cyccnt::{Duration, Instant, U32Ext}; +// ^^^^^^^^ + +#[rtic::app(/* .. */, monotonic = rtic::cyccnt::CYCCNT)] +// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +const APP: () = { + #[init] + fn init(cx: init::Context) { + cx.core.DWT.enable_cycle_counter(); + // optional, configure the DWT run without a debugger connected + cx.core.DCB.enable_trace(); + } + #[task(schedule = [b])] + fn a(cx: a::Context) { + // .. + } +}; +``` diff --git a/book/en/src/migration/migration_v5.md b/book/en/src/migration/migration_v5.md new file mode 100644 index 0000000000..749ddecdba --- /dev/null +++ b/book/en/src/migration/migration_v5.md @@ -0,0 +1,96 @@ +# Migrating from v0.5.x to v0.6.0 + +This section describes how to upgrade from v0.5.x to v0.6.0 of the RTIC framework. + +### `Cargo.toml` - version bump + +Change the version of `cortex-m-rtic` to `"0.6.0"`. + +### Module instead of Const + +With the support of attributes on modules the `const APP` workaround is not needed. + +Change + +``` rust +#[rtic::app(/* .. */)] +const APP: () = { + [code here] +}; +``` + +into + +``` rust +#[rtic::app(/* .. */)] +mod app { + [code here] +} +``` + +Now that a regular Rust module is used it means it is possible to have custom +user code within that module. +Additionally, it means that `use`-statements for resources etc may be required. + +### Init always returns late resources + +In order to make the API more symmetric the #[init]-task always returns a late resource. + +From this: + +``` rust +#[rtic::app(device = lm3s6965)] +mod app { + #[init] + fn init(_: init::Context) { + rtic::pend(Interrupt::UART0); + } + [more code] +} +``` + +to this: + +``` rust +#[rtic::app(device = lm3s6965)] +mod app { + #[init] + fn init(_: init::Context) -> init::LateResources { + rtic::pend(Interrupt::UART0); + + init::LateResources {} + } + [more code] +} +``` + +### Resources struct - #[resources] + +Previously the RTIC resources had to be in in a struct named exactly "Resources": + +``` rust +struct Resources { + // Resources defined in here +} +``` + +With RTIC v0.6.0 the resources struct is annotated similarly like +`#[task]`, `#[init]`, `#[idle]`: with an attribute `#[resources]` + +``` rust +#[resources] +struct Resources { + // Resources defined in here +} +``` + +In fact, the name of the struct is now up to the developer: + +``` rust +#[resources] +struct whateveryouwant { + // Resources defined in here +} +``` + +would work equally well. diff --git a/book/en/src/preface.md b/book/en/src/preface.md index 419f067e1f..041b3bd480 100644 --- a/book/en/src/preface.md +++ b/book/en/src/preface.md @@ -13,8 +13,10 @@ There is a translation of this book in [Russian]. [Russian]: ../ru/index.html -This is the documentation of v0.5.x of RTIC; for the documentation of version -v0.4.x go [here](/0.4). +This is the documentation of v0.6.x of RTIC; for the documentation of version + +* v0.5.x go [here](/0.5). +* v0.4.x go [here](/0.4). {{#include ../../../README.md:7:46}} diff --git a/examples/baseline.rs b/examples/baseline.rs index f46b273d4b..3ab40dbb32 100644 --- a/examples/baseline.rs +++ b/examples/baseline.rs @@ -11,15 +11,17 @@ use panic_semihosting as _; // NOTE: does NOT properly work on QEMU #[rtic::app(device = lm3s6965, monotonic = rtic::cyccnt::CYCCNT)] -const APP: () = { +mod app { #[init(spawn = [foo])] - fn init(cx: init::Context) { + fn init(cx: init::Context) -> init::LateResources { // omitted: initialization of `CYCCNT` hprintln!("init(baseline = {:?})", cx.start).unwrap(); // `foo` inherits the baseline of `init`: `Instant(0)` cx.spawn.foo().unwrap(); + + init::LateResources {} } #[task(schedule = [foo])] @@ -51,4 +53,4 @@ const APP: () = { extern "C" { fn SSI0(); } -}; +} diff --git a/examples/binds.rs b/examples/binds.rs index 82bf89640f..42010ae243 100644 --- a/examples/binds.rs +++ b/examples/binds.rs @@ -11,12 +11,14 @@ use panic_semihosting as _; // `examples/interrupt.rs` rewritten to use `binds` #[rtic::app(device = lm3s6965)] -const APP: () = { +mod app { #[init] - fn init(_: init::Context) { + fn init(_: init::Context) -> init::LateResources { rtic::pend(Interrupt::UART0); hprintln!("init").unwrap(); + + init::LateResources {} } #[idle] @@ -45,4 +47,4 @@ const APP: () = { ) .unwrap(); } -}; +} diff --git a/examples/capacity.rs b/examples/capacity.rs index 00cec34459..ba8b15b087 100644 --- a/examples/capacity.rs +++ b/examples/capacity.rs @@ -10,10 +10,12 @@ use lm3s6965::Interrupt; use panic_semihosting as _; #[rtic::app(device = lm3s6965)] -const APP: () = { +mod app { #[init] - fn init(_: init::Context) { + fn init(_: init::Context) -> init::LateResources { rtic::pend(Interrupt::UART0); + + init::LateResources {} } #[task(binds = UART0, spawn = [foo, bar])] @@ -44,4 +46,4 @@ const APP: () = { extern "C" { fn SSI0(); } -}; +} diff --git a/examples/cfg.rs b/examples/cfg.rs index 8eeeb2a93a..d49f54c7ef 100644 --- a/examples/cfg.rs +++ b/examples/cfg.rs @@ -11,7 +11,8 @@ use cortex_m_semihosting::hprintln; use panic_semihosting as _; #[rtic::app(device = lm3s6965)] -const APP: () = { +mod app { + #[resources] struct Resources { #[cfg(debug_assertions)] // <- `true` when using the `dev` profile #[init(0)] @@ -19,9 +20,11 @@ const APP: () = { } #[init(spawn = [foo])] - fn init(cx: init::Context) { + fn init(cx: init::Context) -> init::LateResources { cx.spawn.foo().unwrap(); cx.spawn.foo().unwrap(); + + init::LateResources {} } #[idle] @@ -66,4 +69,4 @@ const APP: () = { fn SSI0(); fn QEI0(); } -}; +} diff --git a/examples/destructure.rs b/examples/destructure.rs index 1756bd9e75..e7c53237d3 100644 --- a/examples/destructure.rs +++ b/examples/destructure.rs @@ -10,7 +10,8 @@ use lm3s6965::Interrupt; use panic_semihosting as _; #[rtic::app(device = lm3s6965)] -const APP: () = { +mod app { + #[resources] struct Resources { // Some resources to work with #[init(0)] @@ -22,9 +23,11 @@ const APP: () = { } #[init] - fn init(_: init::Context) { + fn init(_: init::Context) -> init::LateResources { rtic::pend(Interrupt::UART0); rtic::pend(Interrupt::UART1); + + init::LateResources {} } // Direct destructure @@ -44,4 +47,4 @@ const APP: () = { hprintln!("UART0: a = {}, b = {}, c = {}", a, b, c).unwrap(); } -}; +} diff --git a/examples/double_schedule.rs b/examples/double_schedule.rs index 6b3aec8fcd..b1b78b80f6 100644 --- a/examples/double_schedule.rs +++ b/examples/double_schedule.rs @@ -9,7 +9,9 @@ use panic_semihosting as _; use rtic::cyccnt::U32Ext; #[rtic::app(device = lm3s6965, monotonic = rtic::cyccnt::CYCCNT)] -const APP: () = { +mod app { + + #[resources] struct Resources { nothing: (), } @@ -34,4 +36,4 @@ const APP: () = { extern "C" { fn SSI0(); } -}; +} diff --git a/examples/generics.rs b/examples/generics.rs index 40ab81ac75..3107dd1175 100644 --- a/examples/generics.rs +++ b/examples/generics.rs @@ -11,16 +11,19 @@ use panic_semihosting as _; use rtic::{Exclusive, Mutex}; #[rtic::app(device = lm3s6965)] -const APP: () = { +mod app { + #[resources] struct Resources { #[init(0)] shared: u32, } #[init] - fn init(_: init::Context) { + fn init(_: init::Context) -> init::LateResources { rtic::pend(Interrupt::UART0); rtic::pend(Interrupt::UART1); + + init::LateResources {} } #[task(binds = UART0, resources = [shared])] @@ -49,7 +52,7 @@ const APP: () = { // second argument has type `Exclusive` advance(STATE, Exclusive(c.resources.shared)); } -}; +} // the second parameter is generic: it can be any type that implements the `Mutex` trait fn advance(state: &mut u32, mut shared: impl Mutex) { diff --git a/examples/hardware.rs b/examples/hardware.rs index 8105a7420d..f6a2d3758e 100644 --- a/examples/hardware.rs +++ b/examples/hardware.rs @@ -10,14 +10,16 @@ use lm3s6965::Interrupt; use panic_semihosting as _; #[rtic::app(device = lm3s6965)] -const APP: () = { +mod app { #[init] - fn init(_: init::Context) { + fn init(_: init::Context) -> init::LateResources { // Pends the UART0 interrupt but its handler won't run until *after* // `init` returns because interrupts are disabled rtic::pend(Interrupt::UART0); // equivalent to NVIC::pend hprintln!("init").unwrap(); + + init::LateResources {} } #[idle] @@ -49,4 +51,4 @@ const APP: () = { ) .unwrap(); } -}; +} diff --git a/examples/idle.rs b/examples/idle.rs index 3d28dac8a7..58c3c87d75 100644 --- a/examples/idle.rs +++ b/examples/idle.rs @@ -9,10 +9,12 @@ use cortex_m_semihosting::{debug, hprintln}; use panic_semihosting as _; #[rtic::app(device = lm3s6965)] -const APP: () = { +mod app { #[init] - fn init(_: init::Context) { + fn init(_: init::Context) -> init::LateResources { hprintln!("init").unwrap(); + + init::LateResources {} } #[idle] @@ -30,4 +32,4 @@ const APP: () = { cortex_m::asm::nop(); } } -}; +} diff --git a/examples/init.rs b/examples/init.rs index 315969f045..6ac284a16a 100644 --- a/examples/init.rs +++ b/examples/init.rs @@ -9,9 +9,9 @@ use cortex_m_semihosting::{debug, hprintln}; use panic_semihosting as _; #[rtic::app(device = lm3s6965, peripherals = true)] -const APP: () = { +mod app { #[init] - fn init(cx: init::Context) { + fn init(cx: init::Context) -> init::LateResources { static mut X: u32 = 0; // Cortex-M peripherals @@ -23,8 +23,14 @@ const APP: () = { // Safe access to local `static mut` variable let _x: &'static mut u32 = X; + // Access to the critical section token, + // to indicate that this is a critical seciton + let _cs_token: bare_metal::CriticalSection = cx.cs; + hprintln!("init").unwrap(); debug::exit(debug::EXIT_SUCCESS); + + init::LateResources {} } -}; +} diff --git a/examples/late.rs b/examples/late.rs index 60b9be0046..761c68f5be 100644 --- a/examples/late.rs +++ b/examples/late.rs @@ -15,8 +15,13 @@ use lm3s6965::Interrupt; use panic_semihosting as _; #[rtic::app(device = lm3s6965)] -const APP: () = { +mod app { + use heapless::{ + consts::*, + spsc::{Consumer, Producer}, + }; // Late resources + #[resources] struct Resources { p: Producer<'static, u32, U4>, c: Consumer<'static, u32, U4>, @@ -49,4 +54,4 @@ const APP: () = { fn uart0(c: uart0::Context) { c.resources.p.enqueue(42).unwrap(); } -}; +} diff --git a/examples/lock.rs b/examples/lock.rs index 5e3bce2500..669b1aedd8 100644 --- a/examples/lock.rs +++ b/examples/lock.rs @@ -10,15 +10,18 @@ use lm3s6965::Interrupt; use panic_semihosting as _; #[rtic::app(device = lm3s6965)] -const APP: () = { +mod app { + #[resources] struct Resources { #[init(0)] shared: u32, } #[init] - fn init(_: init::Context) { + fn init(_: init::Context) -> init::LateResources { rtic::pend(Interrupt::GPIOA); + + init::LateResources {} } // when omitted priority is assumed to be `1` @@ -59,4 +62,4 @@ const APP: () = { fn gpioc(_: gpioc::Context) { hprintln!("C").unwrap(); } -}; +} diff --git a/examples/message.rs b/examples/message.rs index 596f244904..f9736728fa 100644 --- a/examples/message.rs +++ b/examples/message.rs @@ -9,10 +9,12 @@ use cortex_m_semihosting::{debug, hprintln}; use panic_semihosting as _; #[rtic::app(device = lm3s6965)] -const APP: () = { +mod app { #[init(spawn = [foo])] - fn init(c: init::Context) { + fn init(c: init::Context) -> init::LateResources { c.spawn.foo(/* no message */).unwrap(); + + init::LateResources {} } #[task(spawn = [bar])] @@ -49,4 +51,4 @@ const APP: () = { extern "C" { fn SSI0(); } -}; +} diff --git a/examples/not-send.rs b/examples/not-send.rs index 16a874dc0f..18071fc514 100644 --- a/examples/not-send.rs +++ b/examples/not-send.rs @@ -16,16 +16,21 @@ pub struct NotSend { } #[app(device = lm3s6965)] -const APP: () = { +mod app { + use super::NotSend; + + #[resources] struct Resources { #[init(None)] shared: Option, } #[init(spawn = [baz, quux])] - fn init(c: init::Context) { + fn init(c: init::Context) -> init::LateResources { c.spawn.baz().unwrap(); c.spawn.quux().unwrap(); + + init::LateResources {} } #[task(spawn = [bar])] @@ -60,4 +65,4 @@ const APP: () = { fn SSI0(); fn QEI0(); } -}; +} diff --git a/examples/not-sync.rs b/examples/not-sync.rs index a7eaac8e7f..75412e6343 100644 --- a/examples/not-sync.rs +++ b/examples/not-sync.rs @@ -15,15 +15,21 @@ pub struct NotSync { } #[rtic::app(device = lm3s6965)] -const APP: () = { +mod app { + use super::NotSync; + use core::marker::PhantomData; + + #[resources] struct Resources { #[init(NotSync { _0: PhantomData })] shared: NotSync, } #[init] - fn init(_: init::Context) { + fn init(_: init::Context) -> init::LateResources { debug::exit(debug::EXIT_SUCCESS); + + init::LateResources {} } #[task(resources = [&shared])] @@ -42,4 +48,4 @@ const APP: () = { extern "C" { fn SSI0(); } -}; +} diff --git a/examples/only-shared-access.rs b/examples/only-shared-access.rs index c022b037d2..91d0b7adca 100644 --- a/examples/only-shared-access.rs +++ b/examples/only-shared-access.rs @@ -10,7 +10,8 @@ use lm3s6965::Interrupt; use panic_semihosting as _; #[rtic::app(device = lm3s6965)] -const APP: () = { +mod app { + #[resources] struct Resources { key: u32, } @@ -35,4 +36,4 @@ const APP: () = { fn uart1(cx: uart1::Context) { hprintln!("UART1(key = {:#x})", cx.resources.key).unwrap(); } -}; +} diff --git a/examples/periodic.rs b/examples/periodic.rs index 405346e390..d3aedd3207 100644 --- a/examples/periodic.rs +++ b/examples/periodic.rs @@ -13,12 +13,15 @@ const PERIOD: u32 = 8_000_000; // NOTE: does NOT work on QEMU! #[rtic::app(device = lm3s6965, monotonic = rtic::cyccnt::CYCCNT)] -const APP: () = { +mod app { + #[init(schedule = [foo])] - fn init(cx: init::Context) { + fn init(cx: init::Context) -> init::LateResources { // omitted: initialization of `CYCCNT` cx.schedule.foo(cx.start + PERIOD.cycles()).unwrap(); + + init::LateResources {} } #[task(schedule = [foo])] @@ -35,4 +38,4 @@ const APP: () = { extern "C" { fn SSI0(); } -}; +} diff --git a/examples/peripherals-taken.rs b/examples/peripherals-taken.rs index cd4ba0f0ed..09f92427f5 100644 --- a/examples/peripherals-taken.rs +++ b/examples/peripherals-taken.rs @@ -7,10 +7,12 @@ use cortex_m_semihosting::debug; use panic_semihosting as _; #[rtic::app(device = lm3s6965)] -const APP: () = { +mod app { #[init] - fn main(_: main::Context) { + fn init(_: init::Context) -> init::LateResources { assert!(cortex_m::Peripherals::take().is_none()); debug::exit(debug::EXIT_SUCCESS); + + init::LateResources {} } -}; +} diff --git a/examples/pool.rs b/examples/pool.rs index 824d5bd86b..cdbabca7b3 100644 --- a/examples/pool.rs +++ b/examples/pool.rs @@ -18,15 +18,22 @@ use rtic::app; pool!(P: [u8; 128]); #[app(device = lm3s6965)] -const APP: () = { +mod app { + use crate::Box; + + // Import the memory pool into scope + use super::P; + #[init] - fn init(_: init::Context) { + fn init(_: init::Context) -> init::LateResources { static mut MEMORY: [u8; 512] = [0; 512]; // Increase the capacity of the memory pool by ~4 P::grow(MEMORY); rtic::pend(Interrupt::I2C0); + + init::LateResources {} } #[task(binds = I2C0, priority = 2, spawn = [foo, bar])] @@ -66,4 +73,4 @@ const APP: () = { fn SSI0(); fn QEI0(); } -}; +} diff --git a/examples/preempt.rs b/examples/preempt.rs index 3cb11029b4..f6fc4b052e 100644 --- a/examples/preempt.rs +++ b/examples/preempt.rs @@ -9,10 +9,12 @@ use panic_semihosting as _; use rtic::app; #[app(device = lm3s6965)] -const APP: () = { +mod app { #[init] - fn init(_: init::Context) { + fn init(_: init::Context) -> init::LateResources { rtic::pend(Interrupt::GPIOA); + + init::LateResources {} } #[task(binds = GPIOA, priority = 1)] @@ -34,4 +36,4 @@ const APP: () = { rtic::pend(Interrupt::GPIOB); hprintln!(" GPIOC - end").unwrap(); } -}; +} diff --git a/examples/ramfunc.rs b/examples/ramfunc.rs index 1f95d496ef..5ff167a32f 100644 --- a/examples/ramfunc.rs +++ b/examples/ramfunc.rs @@ -9,10 +9,12 @@ use cortex_m_semihosting::{debug, hprintln}; use panic_semihosting as _; #[rtic::app(device = lm3s6965)] -const APP: () = { +mod app { #[init(spawn = [bar])] - fn init(c: init::Context) { + fn init(c: init::Context) -> init::LateResources { c.spawn.bar().unwrap(); + + init::LateResources {} } #[inline(never)] @@ -38,4 +40,4 @@ const APP: () = { #[link_section = ".data.UART1"] fn UART1(); } -}; +} diff --git a/examples/resource-user-struct.rs b/examples/resource-user-struct.rs new file mode 100644 index 0000000000..a5bd0ddf5e --- /dev/null +++ b/examples/resource-user-struct.rs @@ -0,0 +1,63 @@ +//! examples/resource.rs + +#![deny(unsafe_code)] +#![deny(warnings)] +#![no_main] +#![no_std] + +use cortex_m_semihosting::{debug, hprintln}; +use lm3s6965::Interrupt; +use panic_semihosting as _; + +#[rtic::app(device = lm3s6965)] +mod app { + #[resources] + struct Resources { + // A resource + #[init(0)] + shared: u32, + } + + // Should not collide with the struct above + #[allow(dead_code)] + struct Resources2 { + // A resource + shared: u32, + } + + #[init] + fn init(_: init::Context) -> init::LateResources { + rtic::pend(Interrupt::UART0); + rtic::pend(Interrupt::UART1); + + init::LateResources {} + } + + // `shared` cannot be accessed from this context + #[idle] + fn idle(_cx: idle::Context) -> ! { + debug::exit(debug::EXIT_SUCCESS); + + // error: no `resources` field in `idle::Context` + // _cx.resources.shared += 1; + + loop {} + } + + // `shared` can be accessed from this context + #[task(binds = UART0, resources = [shared])] + fn uart0(cx: uart0::Context) { + let shared: &mut u32 = cx.resources.shared; + *shared += 1; + + hprintln!("UART0: shared = {}", shared).unwrap(); + } + + // `shared` can be accessed from this context + #[task(binds = UART1, resources = [shared])] + fn uart1(cx: uart1::Context) { + *cx.resources.shared += 1; + + hprintln!("UART1: shared = {}", cx.resources.shared).unwrap(); + } +} diff --git a/examples/resource.rs b/examples/resource.rs index 2361fd0033..273af26a0e 100644 --- a/examples/resource.rs +++ b/examples/resource.rs @@ -10,7 +10,8 @@ use lm3s6965::Interrupt; use panic_semihosting as _; #[rtic::app(device = lm3s6965)] -const APP: () = { +mod app { + #[resources] struct Resources { // A resource #[init(0)] @@ -18,9 +19,11 @@ const APP: () = { } #[init] - fn init(_: init::Context) { + fn init(_: init::Context) -> init::LateResources { rtic::pend(Interrupt::UART0); rtic::pend(Interrupt::UART1); + + init::LateResources {} } // `shared` cannot be accessed from this context @@ -52,4 +55,4 @@ const APP: () = { hprintln!("UART1: shared = {}", cx.resources.shared).unwrap(); } -}; +} diff --git a/examples/schedule.rs b/examples/schedule.rs index 70a7a5e328..7e6adc1aa7 100644 --- a/examples/schedule.rs +++ b/examples/schedule.rs @@ -12,9 +12,9 @@ use rtic::cyccnt::{Instant, U32Ext as _}; // NOTE: does NOT work on QEMU! #[rtic::app(device = lm3s6965, monotonic = rtic::cyccnt::CYCCNT)] -const APP: () = { +mod app { #[init(schedule = [foo, bar])] - fn init(mut cx: init::Context) { + fn init(mut cx: init::Context) -> init::LateResources { // Initialize (enable) the monotonic timer (CYCCNT) cx.core.DCB.enable_trace(); // required on Cortex-M7 devices that software lock the DWT (e.g. STM32F7) @@ -32,6 +32,8 @@ const APP: () = { // Schedule `bar` to run 4e6 cycles in the future cx.schedule.bar(now + 4_000_000.cycles()).unwrap(); + + init::LateResources {} } #[task] @@ -50,4 +52,4 @@ const APP: () = { extern "C" { fn SSI0(); } -}; +} diff --git a/examples/shared-with-init.rs b/examples/shared-with-init.rs index bd55f7efd5..85c72761bc 100644 --- a/examples/shared-with-init.rs +++ b/examples/shared-with-init.rs @@ -13,19 +13,24 @@ use rtic::app; pub struct MustBeSend; #[app(device = lm3s6965)] -const APP: () = { +mod app { + use super::MustBeSend; + + #[resources] struct Resources { #[init(None)] shared: Option, } #[init(resources = [shared])] - fn init(c: init::Context) { + fn init(c: init::Context) -> init::LateResources { // this `message` will be sent to task `UART0` let message = MustBeSend; *c.resources.shared = Some(message); rtic::pend(Interrupt::UART0); + + init::LateResources {} } #[task(binds = UART0, resources = [shared])] @@ -37,4 +42,4 @@ const APP: () = { debug::exit(debug::EXIT_SUCCESS); } } -}; +} diff --git a/examples/smallest.rs b/examples/smallest.rs index ec3fa970d7..b8cbf87ed5 100644 --- a/examples/smallest.rs +++ b/examples/smallest.rs @@ -7,4 +7,4 @@ use panic_semihosting as _; // panic handler use rtic::app; #[app(device = lm3s6965)] -const APP: () = {}; +mod app {} diff --git a/examples/t-binds.rs b/examples/t-binds.rs index 588ac46fa6..3ca4c66ec5 100644 --- a/examples/t-binds.rs +++ b/examples/t-binds.rs @@ -8,9 +8,11 @@ use panic_halt as _; #[rtic::app(device = lm3s6965)] -const APP: () = { +mod app { #[init] - fn init(_: init::Context) {} + fn init(_: init::Context) -> init::LateResources { + init::LateResources {} + } // Cortex-M exception #[task(binds = SVCall)] @@ -23,7 +25,7 @@ const APP: () = { fn bar(c: bar::Context) { bar_trampoline(c) } -}; +} #[allow(dead_code)] fn foo_trampoline(_: foo::Context) {} diff --git a/examples/t-cfg-resources.rs b/examples/t-cfg-resources.rs index 4f7fd635a7..61eb4c7b10 100644 --- a/examples/t-cfg-resources.rs +++ b/examples/t-cfg-resources.rs @@ -6,19 +6,17 @@ use panic_halt as _; #[rtic::app(device = lm3s6965)] -const APP: () = { +mod app { + #[resources] struct Resources { // A resource #[init(0)] shared: u32, - // A conditionally compiled resource behind feature_x #[cfg(feature = "feature_x")] x: u32, - - dummy: (), + dummy: (), // dummy such that we have at least one late resource } - #[init] fn init(_: init::Context) -> init::LateResources { init::LateResources { @@ -35,4 +33,4 @@ const APP: () = { cortex_m::asm::nop(); } } -}; +} diff --git a/examples/t-cfg.rs b/examples/t-cfg.rs index b6c9e47207..3da20d4ee1 100644 --- a/examples/t-cfg.rs +++ b/examples/t-cfg.rs @@ -6,7 +6,8 @@ use panic_halt as _; #[rtic::app(device = lm3s6965, monotonic = rtic::cyccnt::CYCCNT)] -const APP: () = { +mod app { + #[resources] struct Resources { #[cfg(never)] #[init(0)] @@ -14,9 +15,11 @@ const APP: () = { } #[init] - fn init(_: init::Context) { + fn init(_: init::Context) -> init::LateResources { #[cfg(never)] static mut BAR: u32 = 0; + + init::LateResources {} } #[idle] @@ -52,4 +55,4 @@ const APP: () = { fn SSI0(); fn QEI0(); } -}; +} diff --git a/examples/t-htask-main.rs b/examples/t-htask-main.rs index c4bebf94dc..1e38e317c4 100644 --- a/examples/t-htask-main.rs +++ b/examples/t-htask-main.rs @@ -7,14 +7,16 @@ use cortex_m_semihosting::debug; use panic_semihosting as _; #[rtic::app(device = lm3s6965)] -const APP: () = { +mod app { #[init] - fn init(_: init::Context) { - rtic::pend(lm3s6965::Interrupt::UART0) + fn init(_: init::Context) -> init::LateResources { + rtic::pend(lm3s6965::Interrupt::UART0); + + init::LateResources {} } #[task(binds = UART0)] - fn main(_: main::Context) { + fn taskmain(_: taskmain::Context) { debug::exit(debug::EXIT_SUCCESS); } -}; +} diff --git a/examples/t-idle-main.rs b/examples/t-idle-main.rs index 051a9ee812..9078628ecd 100644 --- a/examples/t-idle-main.rs +++ b/examples/t-idle-main.rs @@ -7,15 +7,17 @@ use cortex_m_semihosting::debug; use panic_semihosting as _; #[rtic::app(device = lm3s6965)] -const APP: () = { +mod app { #[init] - fn init(_: init::Context) {} + fn init(_: init::Context) -> init::LateResources { + init::LateResources {} + } #[idle] - fn main(_: main::Context) -> ! { + fn taskmain(_: taskmain::Context) -> ! { debug::exit(debug::EXIT_SUCCESS); loop { cortex_m::asm::nop(); } } -}; +} diff --git a/examples/t-init-main.rs b/examples/t-init-main.rs index 6a6cd99164..7c23cc8307 100644 --- a/examples/t-init-main.rs +++ b/examples/t-init-main.rs @@ -7,9 +7,11 @@ use cortex_m_semihosting::debug; use panic_semihosting as _; #[rtic::app(device = lm3s6965)] -const APP: () = { +mod app { #[init] - fn main(_: main::Context) { + fn init(_: init::Context) -> init::LateResources { debug::exit(debug::EXIT_SUCCESS); + + init::LateResources {} } -}; +} diff --git a/examples/t-late-not-send.rs b/examples/t-late-not-send.rs index d2a9b63ce9..345d9aefa1 100644 --- a/examples/t-late-not-send.rs +++ b/examples/t-late-not-send.rs @@ -12,7 +12,10 @@ pub struct NotSend { } #[rtic::app(device = lm3s6965)] -const APP: () = { +mod app { + use super::NotSend; + + #[resources] struct Resources { x: NotSend, #[init(None)] @@ -35,4 +38,4 @@ const APP: () = { cortex_m::asm::nop(); } } -}; +} diff --git a/examples/t-resource.rs b/examples/t-resource.rs index 81ba18563f..91950d3e00 100644 --- a/examples/t-resource.rs +++ b/examples/t-resource.rs @@ -8,7 +8,8 @@ use panic_halt as _; #[rtic::app(device = lm3s6965)] -const APP: () = { +mod app { + #[resources] struct Resources { #[init(0)] o1: u32, // init @@ -31,7 +32,7 @@ const APP: () = { } #[init(resources = [o1, o4, o5, o6, s3])] - fn init(c: init::Context) { + fn init(c: init::Context) -> init::LateResources { // owned by `init` == `&'static mut` let _: &'static mut u32 = c.resources.o1; @@ -42,6 +43,8 @@ const APP: () = { let _: &mut u32 = c.resources.o4; let _: &mut u32 = c.resources.o5; let _: &mut u32 = c.resources.s3; + + init::LateResources {} } #[idle(resources = [o2, &o4, s1, &s3])] @@ -86,4 +89,4 @@ const APP: () = { // no `Mutex` proxy when co-owned by cooperative (same priority) tasks let _: &mut u32 = c.resources.s2; } -}; +} diff --git a/examples/t-schedule.rs b/examples/t-schedule.rs index 3854aad36b..d5a6d3ff32 100644 --- a/examples/t-schedule.rs +++ b/examples/t-schedule.rs @@ -9,12 +9,14 @@ use panic_halt as _; use rtic::cyccnt::{Instant, U32Ext as _}; #[rtic::app(device = lm3s6965, monotonic = rtic::cyccnt::CYCCNT)] -const APP: () = { +mod app { #[init(schedule = [foo, bar, baz])] - fn init(c: init::Context) { + fn init(c: init::Context) -> init::LateResources { let _: Result<(), ()> = c.schedule.foo(c.start + 10.cycles()); let _: Result<(), u32> = c.schedule.bar(c.start + 20.cycles(), 0); let _: Result<(), (u32, u32)> = c.schedule.baz(c.start + 30.cycles(), 0, 1); + + init::LateResources {} } #[idle(schedule = [foo, bar, baz])] @@ -61,4 +63,4 @@ const APP: () = { extern "C" { fn SSI0(); } -}; +} diff --git a/examples/t-spawn.rs b/examples/t-spawn.rs index 35831ccf9d..efb748bc14 100644 --- a/examples/t-spawn.rs +++ b/examples/t-spawn.rs @@ -8,12 +8,14 @@ use panic_halt as _; #[rtic::app(device = lm3s6965)] -const APP: () = { +mod app { #[init(spawn = [foo, bar, baz])] - fn init(c: init::Context) { + fn init(c: init::Context) -> init::LateResources { let _: Result<(), ()> = c.spawn.foo(); let _: Result<(), u32> = c.spawn.bar(0); let _: Result<(), (u32, u32)> = c.spawn.baz(0, 1); + + init::LateResources {} } #[idle(spawn = [foo, bar, baz])] @@ -60,4 +62,4 @@ const APP: () = { extern "C" { fn SSI0(); } -}; +} diff --git a/examples/t-stask-main.rs b/examples/t-stask-main.rs index f270940454..74335c18a9 100644 --- a/examples/t-stask-main.rs +++ b/examples/t-stask-main.rs @@ -7,14 +7,16 @@ use cortex_m_semihosting::debug; use panic_semihosting as _; #[rtic::app(device = lm3s6965)] -const APP: () = { - #[init(spawn = [main])] - fn init(cx: init::Context) { - cx.spawn.main().ok(); +mod app { + #[init(spawn = [taskmain])] + fn init(cx: init::Context) -> init::LateResources { + cx.spawn.taskmain().ok(); + + init::LateResources {} } #[task] - fn main(_: main::Context) { + fn taskmain(_: taskmain::Context) { debug::exit(debug::EXIT_SUCCESS); } @@ -24,4 +26,4 @@ const APP: () = { extern "C" { fn SSI0(); } -}; +} diff --git a/examples/task.rs b/examples/task.rs index 12c4ac8355..80a9c4316d 100644 --- a/examples/task.rs +++ b/examples/task.rs @@ -9,10 +9,12 @@ use cortex_m_semihosting::{debug, hprintln}; use panic_semihosting as _; #[rtic::app(device = lm3s6965)] -const APP: () = { +mod app { #[init(spawn = [foo])] - fn init(c: init::Context) { + fn init(c: init::Context) -> init::LateResources { c.spawn.foo().unwrap(); + + init::LateResources {} } #[task(spawn = [bar, baz])] @@ -52,4 +54,4 @@ const APP: () = { fn SSI0(); fn QEI0(); } -}; +} diff --git a/examples/types.rs b/examples/types.rs index 5233f868b1..251d004c4a 100644 --- a/examples/types.rs +++ b/examples/types.rs @@ -10,14 +10,15 @@ use panic_semihosting as _; use rtic::cyccnt; #[rtic::app(device = lm3s6965, peripherals = true, monotonic = rtic::cyccnt::CYCCNT)] -const APP: () = { +mod app { + #[resources] struct Resources { #[init(0)] shared: u32, } #[init(schedule = [foo], spawn = [foo])] - fn init(cx: init::Context) { + fn init(cx: init::Context) -> init::LateResources { let _: cyccnt::Instant = cx.start; let _: rtic::Peripherals = cx.core; let _: lm3s6965::Peripherals = cx.device; @@ -25,6 +26,8 @@ const APP: () = { let _: init::Spawn = cx.spawn; debug::exit(debug::EXIT_SUCCESS); + + init::LateResources {} } #[idle(schedule = [foo], spawn = [foo])] @@ -60,4 +63,4 @@ const APP: () = { extern "C" { fn SSI0(); } -}; +} diff --git a/macros/src/codegen.rs b/macros/src/codegen.rs index fe4d59a6b7..f230d3956d 100644 --- a/macros/src/codegen.rs +++ b/macros/src/codegen.rs @@ -25,21 +25,36 @@ mod util; // TODO document the syntax here or in `rtic-syntax` pub fn app(app: &App, analysis: &Analysis, extra: &Extra) -> TokenStream2 { - let mut const_app = vec![]; + let mut mod_app = vec![]; + let mut mod_app_imports = vec![]; let mut mains = vec![]; let mut root = vec![]; let mut user = vec![]; + let mut imports = vec![]; // Generate the `main` function let assertion_stmts = assertions::codegen(analysis); let pre_init_stmts = pre_init::codegen(&app, analysis, extra); - let (const_app_init, root_init, user_init, call_init) = init::codegen(app, analysis, extra); + let (mod_app_init, root_init, user_init, user_init_imports, call_init) = + init::codegen(app, analysis, extra); let post_init_stmts = post_init::codegen(&app, analysis); - let (const_app_idle, root_idle, user_idle, call_idle) = idle::codegen(app, analysis, extra); + let (mod_app_idle, root_idle, user_idle, user_idle_imports, call_idle) = + idle::codegen(app, analysis, extra); + + if user_init.is_some() { + mod_app_imports.push(quote!( + use super::init; + )) + } + if user_idle.is_some() { + mod_app_imports.push(quote!( + use super::idle; + )) + } user.push(quote!( #user_init @@ -47,16 +62,21 @@ pub fn app(app: &App, analysis: &Analysis, extra: &Extra) -> TokenStream2 { #user_idle )); + imports.push(quote!( + #(#user_init_imports)* + #(#user_idle_imports)* + )); + root.push(quote!( #(#root_init)* #(#root_idle)* )); - const_app.push(quote!( - #const_app_init + mod_app.push(quote!( + #mod_app_init - #const_app_idle + #mod_app_idle )); let main = util::suffixed("main"); @@ -77,22 +97,33 @@ pub fn app(app: &App, analysis: &Analysis, extra: &Extra) -> TokenStream2 { } )); - let (const_app_resources, mod_resources) = resources::codegen(app, analysis, extra); + let (mod_app_resources, mod_resources, mod_resources_imports) = + resources::codegen(app, analysis, extra); - let (const_app_hardware_tasks, root_hardware_tasks, user_hardware_tasks) = - hardware_tasks::codegen(app, analysis, extra); + let ( + mod_app_hardware_tasks, + root_hardware_tasks, + user_hardware_tasks, + user_hardware_tasks_imports, + ) = hardware_tasks::codegen(app, analysis, extra); - let (const_app_software_tasks, root_software_tasks, user_software_tasks) = - software_tasks::codegen(app, analysis, extra); + let ( + mod_app_software_tasks, + root_software_tasks, + user_software_tasks, + user_software_tasks_imports, + ) = software_tasks::codegen(app, analysis, extra); - let const_app_dispatchers = dispatchers::codegen(app, analysis, extra); + let mod_app_dispatchers = dispatchers::codegen(app, analysis, extra); - let const_app_spawn = spawn::codegen(app, analysis, extra); + let mod_app_spawn = spawn::codegen(app, analysis, extra); - let const_app_timer_queue = timer_queue::codegen(app, analysis, extra); + let mod_app_timer_queue = timer_queue::codegen(app, analysis, extra); - let const_app_schedule = schedule::codegen(app, extra); + let mod_app_schedule = schedule::codegen(app, extra); + let user_imports = app.user_imports.clone(); + let user_code = app.user_code.clone(); let name = &app.name; let device = extra.device; quote!( @@ -111,28 +142,41 @@ pub fn app(app: &App, analysis: &Analysis, extra: &Extra) -> TokenStream2 { #(#root_software_tasks)* /// Implementation details - // The user can't access the items within this `const` item - const #name: () = { + mod #name { /// Always include the device crate which contains the vector table use #device as _; + #(#imports)* + #(#user_imports)* - #(#const_app)* + /// User code from within the module + #(#user_code)* + /// User code end - #(#const_app_resources)* - #(#const_app_hardware_tasks)* + #(#user_hardware_tasks_imports)* - #(#const_app_software_tasks)* + #(#user_software_tasks_imports)* - #(#const_app_dispatchers)* + #(#mod_resources_imports)* - #(#const_app_spawn)* + /// app module + #(#mod_app)* - #(#const_app_timer_queue)* + #(#mod_app_resources)* - #(#const_app_schedule)* + #(#mod_app_hardware_tasks)* + + #(#mod_app_software_tasks)* + + #(#mod_app_dispatchers)* + + #(#mod_app_spawn)* + + #(#mod_app_timer_queue)* + + #(#mod_app_schedule)* #(#mains)* - }; + } ) } diff --git a/macros/src/codegen/hardware_tasks.rs b/macros/src/codegen/hardware_tasks.rs index 7f14b5e17c..25f1df416f 100644 --- a/macros/src/codegen/hardware_tasks.rs +++ b/macros/src/codegen/hardware_tasks.rs @@ -1,5 +1,5 @@ use proc_macro2::TokenStream as TokenStream2; -use quote::quote; +use quote::{format_ident, quote}; use rtic_syntax::{ast::App, Context}; use crate::{ @@ -14,7 +14,7 @@ pub fn codegen( analysis: &Analysis, extra: &Extra, ) -> ( - // const_app_hardware_tasks -- interrupt handlers and `${task}Resources` constructors + // mod_app_hardware_tasks -- interrupt handlers and `${task}Resources` constructors Vec, // root_hardware_tasks -- items that must be placed in the root of the crate: // - `${task}Locals` structs @@ -23,10 +23,13 @@ pub fn codegen( Vec, // user_hardware_tasks -- the `#[task]` functions written by the user Vec, + // user_hardware_tasks_imports -- the imports for `#[task]` functions written by the user + Vec, ) { - let mut const_app = vec![]; + let mut mod_app = vec![]; let mut root = vec![]; let mut user_tasks = vec![]; + let mut hardware_tasks_imports = vec![]; for (name, task) in &app.hardware_tasks { let (let_instant, instant) = if app.uses_schedule() { @@ -49,7 +52,7 @@ pub fn codegen( let symbol = task.args.binds.clone(); let priority = task.args.priority; - const_app.push(quote!( + mod_app.push(quote!( #[allow(non_snake_case)] #[no_mangle] unsafe fn #symbol() { @@ -78,9 +81,16 @@ pub fn codegen( analysis, ); + // Add resources to imports + let name_res = format_ident!("{}Resources", name); + hardware_tasks_imports.push(quote!( + #[allow(non_snake_case)] + use super::#name_res; + )); + root.push(item); - const_app.push(constructor); + mod_app.push(constructor); } root.push(module::codegen( @@ -112,7 +122,13 @@ pub fn codegen( #(#stmts)* } )); + + hardware_tasks_imports.push(quote!( + #(#attrs)* + #[allow(non_snake_case)] + use super::#name; + )); } - (const_app, root, user_tasks) + (mod_app, root, user_tasks, hardware_tasks_imports) } diff --git a/macros/src/codegen/idle.rs b/macros/src/codegen/idle.rs index d0bff3e76b..2e2932d751 100644 --- a/macros/src/codegen/idle.rs +++ b/macros/src/codegen/idle.rs @@ -1,5 +1,5 @@ use proc_macro2::TokenStream as TokenStream2; -use quote::quote; +use quote::{format_ident, quote}; use rtic_syntax::{ast::App, Context}; use crate::{ @@ -14,7 +14,7 @@ pub fn codegen( analysis: &Analysis, extra: &Extra, ) -> ( - // const_app_idle -- the `${idle}Resources` constructor + // mod_app_idle -- the `${idle}Resources` constructor Option, // root_idle -- items that must be placed in the root of the crate: // - the `${idle}Locals` struct @@ -23,26 +23,37 @@ pub fn codegen( Vec, // user_idle Option, + // user_idle_imports + Vec, // call_idle TokenStream2, ) { if app.idles.len() > 0 { let idle = &app.idles.first().unwrap(); let mut needs_lt = false; - let mut const_app = None; + let mut mod_app = None; let mut root_idle = vec![]; let mut locals_pat = None; let mut locals_new = None; + let mut user_idle_imports = vec![]; + + let name = &idle.name; + if !idle.args.resources.is_empty() { let (item, constructor) = resources_struct::codegen(Context::Idle, 0, &mut needs_lt, app, analysis); root_idle.push(item); - const_app = Some(constructor); + mod_app = Some(constructor); + + let name_resource = format_ident!("{}Resources", name); + user_idle_imports.push(quote!( + #[allow(non_snake_case)] + use super::#name_resource; + )); } - let name = &idle.name; if !idle.locals.is_empty() { let (locals, pat) = locals::codegen(Context::Idle, &idle.locals, app); @@ -66,6 +77,11 @@ pub fn codegen( #(#stmts)* } )); + user_idle_imports.push(quote!( + #(#attrs)* + #[allow(non_snake_case)] + use super::#name; + )); let locals_new = locals_new.iter(); let call_idle = quote!(crate::#name( @@ -73,12 +89,13 @@ pub fn codegen( #name::Context::new(&rtic::export::Priority::new(0)) )); - (const_app, root_idle, user_idle, call_idle) + (mod_app, root_idle, user_idle, user_idle_imports, call_idle) } else { ( None, vec![], None, + vec![], quote!(loop { rtic::export::wfi() }), diff --git a/macros/src/codegen/init.rs b/macros/src/codegen/init.rs index e0b7d69972..8942439bd7 100644 --- a/macros/src/codegen/init.rs +++ b/macros/src/codegen/init.rs @@ -1,5 +1,5 @@ use proc_macro2::TokenStream as TokenStream2; -use quote::quote; +use quote::{format_ident, quote}; use rtic_syntax::{ast::App, Context}; use crate::{ @@ -14,7 +14,7 @@ pub fn codegen( analysis: &Analysis, extra: &Extra, ) -> ( - // const_app_idle -- the `${init}Resources` constructor + // mod_app_idle -- the `${init}Resources` constructor Option, // root_init -- items that must be placed in the root of the crate: // - the `${init}Locals` struct @@ -24,6 +24,8 @@ pub fn codegen( Vec, // user_init -- the `#[init]` function written by the user Option, + // user_init_imports -- the imports for `#[init]` functio written by the user + Vec, // call_init -- the call to the user `#[init]` if there's one Option, ) { @@ -34,39 +36,38 @@ pub fn codegen( let mut root_init = vec![]; - let ret = { - let late_fields = analysis - .late_resources - .iter() - .flat_map(|resources| { - resources.iter().map(|name| { - let ty = &app.late_resources[name].ty; - let cfgs = &app.late_resources[name].cfgs; + let late_fields = analysis + .late_resources + .iter() + .flat_map(|resources| { + resources.iter().map(|name| { + let ty = &app.late_resources[name].ty; + let cfgs = &app.late_resources[name].cfgs; - quote!( + quote!( #(#cfgs)* pub #name: #ty - ) - }) + ) }) - .collect::>(); + }) + .collect::>(); - if !late_fields.is_empty() { - let late_resources = util::late_resources_ident(&name); + let mut user_init_imports = vec![]; + let late_resources = util::late_resources_ident(&name); - root_init.push(quote!( - /// Resources initialized at runtime - #[allow(non_snake_case)] - pub struct #late_resources { - #(#late_fields),* - } - )); - - Some(quote!(-> #name::LateResources)) - } else { - None + root_init.push(quote!( + /// Resources initialized at runtime + #[allow(non_snake_case)] + pub struct #late_resources { + #(#late_fields),* } - }; + )); + + let name_late = format_ident!("{}LateResources", name); + user_init_imports.push(quote!( + #[allow(non_snake_case)] + use super::#name_late; + )); let mut locals_pat = None; let mut locals_new = None; @@ -85,18 +86,29 @@ pub fn codegen( let user_init = Some(quote!( #(#attrs)* #[allow(non_snake_case)] - fn #name(#(#locals_pat,)* #context: #name::Context) #ret { + fn #name(#(#locals_pat,)* #context: #name::Context) -> #name::LateResources { #(#stmts)* } )); + user_init_imports.push(quote!( + #(#attrs)* + #[allow(non_snake_case)] + use super::#name; + )); - let mut const_app = None; + let mut mod_app = None; if !init.args.resources.is_empty() { let (item, constructor) = resources_struct::codegen(Context::Init, 0, &mut needs_lt, app, analysis); root_init.push(item); - const_app = Some(constructor); + mod_app = Some(constructor); + + let name_late = format_ident!("{}Resources", name); + user_init_imports.push(quote!( + #[allow(non_snake_case)] + use super::#name_late; + )); } let locals_new = locals_new.iter(); @@ -106,8 +118,8 @@ pub fn codegen( root_init.push(module::codegen(Context::Init, needs_lt, app, extra)); - (const_app, root_init, user_init, call_init) + (mod_app, root_init, user_init, user_init_imports, call_init) } else { - (None, vec![], None, None) + (None, vec![], None, vec![], None) } } diff --git a/macros/src/codegen/module.rs b/macros/src/codegen/module.rs index 863f6c5b73..2e51e7db6e 100644 --- a/macros/src/codegen/module.rs +++ b/macros/src/codegen/module.rs @@ -47,6 +47,14 @@ pub fn codegen(ctxt: Context, resources_tick: bool, app: &App, extra: &Extra) -> values.push(quote!(device: #device::Peripherals::steal())); } + lt = Some(quote!('a)); + fields.push(quote!( + /// Critical section token for init + pub cs: rtic::export::CriticalSection<#lt> + )); + + values.push(quote!(cs: rtic::export::CriticalSection::new())); + values.push(quote!(core)); } @@ -253,14 +261,12 @@ pub fn codegen(ctxt: Context, resources_tick: bool, app: &App, extra: &Extra) -> if let Context::Init = ctxt { let init = &app.inits.first().unwrap(); - if init.returns_late_resources { - let late_resources = util::late_resources_ident(&init.name); + let late_resources = util::late_resources_ident(&init.name); - items.push(quote!( - #[doc(inline)] - pub use super::#late_resources as LateResources; - )); - } + items.push(quote!( + #[doc(inline)] + pub use super::#late_resources as LateResources; + )); } let doc = match ctxt { diff --git a/macros/src/codegen/resources.rs b/macros/src/codegen/resources.rs index 4196ee7aad..38ea52459e 100644 --- a/macros/src/codegen/resources.rs +++ b/macros/src/codegen/resources.rs @@ -10,13 +10,16 @@ pub fn codegen( analysis: &Analysis, extra: &Extra, ) -> ( - // const_app -- the `static [mut]` variables behind the proxies + // mod_app -- the `static [mut]` variables behind the proxies Vec, // mod_resources -- the `resources` module TokenStream2, + // mod_resources_imports -- the `resources` module imports + Vec, ) { - let mut const_app = vec![]; + let mut mod_app = vec![]; let mut mod_resources = vec![]; + let mut mod_resources_imports = vec![]; for (name, res, expr, _) in app.resources(analysis) { let cfgs = &res.cfgs; @@ -39,7 +42,7 @@ pub fn codegen( }; let attrs = &res.attrs; - const_app.push(quote!( + mod_app.push(quote!( #[allow(non_upper_case_globals)] #(#attrs)* #(#cfgs)* @@ -82,7 +85,13 @@ pub fn codegen( ) }; - const_app.push(util::impl_mutex( + mod_resources_imports.push(quote!( + #[allow(non_camel_case_types)] + #(#cfgs)* + use super::resources::#name; + )); + + mod_app.push(util::impl_mutex( extra, cfgs, true, @@ -97,6 +106,11 @@ pub fn codegen( let mod_resources = if mod_resources.is_empty() { quote!() } else { + // Also import the resource module + mod_resources_imports.push(quote!( + use super::resources; + )); + quote!(mod resources { use rtic::export::Priority; @@ -104,5 +118,5 @@ pub fn codegen( }) }; - (const_app, mod_resources) + (mod_app, mod_resources, mod_resources_imports) } diff --git a/macros/src/codegen/resources_struct.rs b/macros/src/codegen/resources_struct.rs index dbbba30e0f..92d5b66633 100644 --- a/macros/src/codegen/resources_struct.rs +++ b/macros/src/codegen/resources_struct.rs @@ -165,7 +165,7 @@ pub fn codegen( let constructor = quote!( impl<#lt> #ident<#lt> { #[inline(always)] - unsafe fn new(#arg) -> Self { + pub unsafe fn new(#arg) -> Self { #ident { #(#values,)* } diff --git a/macros/src/codegen/schedule.rs b/macros/src/codegen/schedule.rs index 46b0f38494..5a887496b7 100644 --- a/macros/src/codegen/schedule.rs +++ b/macros/src/codegen/schedule.rs @@ -34,7 +34,7 @@ pub fn codegen(app: &App, extra: &Extra) -> Vec { methods.push(quote!( #(#cfgs)* - fn #name(&self, instant: #instant #(,#args)*) -> Result<(), #ty> { + pub fn #name(&self, instant: #instant #(,#args)*) -> Result<(), #ty> { #body } )); @@ -49,7 +49,7 @@ pub fn codegen(app: &App, extra: &Extra) -> Vec { items.push(quote!( #(#cfgs)* - unsafe fn #schedule( + pub unsafe fn #schedule( priority: &rtic::export::Priority, instant: #instant #(,#args)* @@ -62,7 +62,7 @@ pub fn codegen(app: &App, extra: &Extra) -> Vec { methods.push(quote!( #(#cfgs)* #[inline(always)] - fn #name(&self, instant: #instant #(,#args)*) -> Result<(), #ty> { + pub fn #name(&self, instant: #instant #(,#args)*) -> Result<(), #ty> { unsafe { #schedule(self.priority(), instant #(,#untupled)*) } diff --git a/macros/src/codegen/software_tasks.rs b/macros/src/codegen/software_tasks.rs index b56db4199d..4ae37e4e9b 100644 --- a/macros/src/codegen/software_tasks.rs +++ b/macros/src/codegen/software_tasks.rs @@ -1,5 +1,5 @@ use proc_macro2::TokenStream as TokenStream2; -use quote::quote; +use quote::{format_ident, quote}; use rtic_syntax::{ast::App, Context}; use crate::{ @@ -13,7 +13,7 @@ pub fn codegen( analysis: &Analysis, extra: &Extra, ) -> ( - // const_app_software_tasks -- free queues, buffers and `${task}Resources` constructors + // mod_app_software_tasks -- free queues, buffers and `${task}Resources` constructors Vec, // root_software_tasks -- items that must be placed in the root of the crate: // - `${task}Locals` structs @@ -22,10 +22,13 @@ pub fn codegen( Vec, // user_software_tasks -- the `#[task]` functions written by the user Vec, + // user_software_tasks_imports -- the imports for `#[task]` functions written by the user + Vec, ) { - let mut const_app = vec![]; + let mut mod_app = vec![]; let mut root = vec![]; let mut user_tasks = vec![]; + let mut software_tasks_imports = vec![]; for (name, task) in &app.software_tasks { let inputs = &task.inputs; @@ -48,7 +51,7 @@ pub fn codegen( Box::new(|| util::link_section_uninit(true)), ) }; - const_app.push(quote!( + mod_app.push(quote!( /// Queue version of a free-list that keeps track of empty slots in /// the following buffers static mut #fq: #fq_ty = #fq_expr; @@ -56,13 +59,13 @@ pub fn codegen( // Generate a resource proxy if needed if let Some(ceiling) = ceiling { - const_app.push(quote!( + mod_app.push(quote!( struct #fq<'a> { priority: &'a rtic::export::Priority, } )); - const_app.push(util::impl_mutex( + mod_app.push(util::impl_mutex( extra, &[], false, @@ -82,7 +85,7 @@ pub fn codegen( let instants = util::instants_ident(name); let uninit = mk_uninit(); - const_app.push(quote!( + mod_app.push(quote!( #uninit /// Buffer that holds the instants associated to the inputs of a task static mut #instants: @@ -93,7 +96,7 @@ pub fn codegen( let uninit = mk_uninit(); let inputs = util::inputs_ident(name); - const_app.push(quote!( + mod_app.push(quote!( #uninit /// Buffer that holds the inputs of a task static mut #inputs: [core::mem::MaybeUninit<#input_ty>; #cap_lit] = @@ -112,9 +115,16 @@ pub fn codegen( analysis, ); + // Add resources to imports + let name_res = format_ident!("{}Resources", name); + software_tasks_imports.push(quote!( + #[allow(non_snake_case)] + use super::#name_res; + )); + root.push(item); - const_app.push(constructor); + mod_app.push(constructor); } // `${task}Locals` @@ -135,12 +145,17 @@ pub fn codegen( #(#attrs)* #(#cfgs)* #[allow(non_snake_case)] - fn #name(#(#locals_pat,)* #context: #name::Context #(,#inputs)*) { + pub fn #name(#(#locals_pat,)* #context: #name::Context #(,#inputs)*) { use rtic::Mutex as _; #(#stmts)* } )); + software_tasks_imports.push(quote!( + #(#cfgs)* + #[allow(non_snake_case)] + use super::#name; + )); root.push(module::codegen( Context::SoftwareTask(name), @@ -150,5 +165,5 @@ pub fn codegen( )); } - (const_app, root, user_tasks) + (mod_app, root, user_tasks, software_tasks_imports) } diff --git a/macros/src/codegen/spawn.rs b/macros/src/codegen/spawn.rs index 4b824f56ab..da2815160b 100644 --- a/macros/src/codegen/spawn.rs +++ b/macros/src/codegen/spawn.rs @@ -40,7 +40,7 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec Result<(), #ty> { + pub fn #name(&self #(,#args)*) -> Result<(), #ty> { #let_instant #body } @@ -92,7 +92,7 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec Result<(), #ty> { + pub fn #name(&self #(,#args)*) -> Result<(), #ty> { unsafe { #let_instant #spawn(self.priority() #instant #(,#untupled)*) diff --git a/macros/src/lib.rs b/macros/src/lib.rs index 7b72c7fb13..e659559e9b 100644 --- a/macros/src/lib.rs +++ b/macros/src/lib.rs @@ -15,8 +15,7 @@ mod tests; /// Attribute used to declare a RTIC application /// -/// This attribute must be applied to a `const` item of type `()`. The `const` item is effectively -/// used as a `mod` item: its value must be a block that contains items commonly found in modules, +/// This attribute must be applied to a module block that contains items commonly found in modules, /// like functions and `static` variables. /// /// The `app` attribute has one mandatory argument: @@ -34,9 +33,9 @@ mod tests; /// - `monotonic = `. This is a path to a zero-sized structure (e.g. `struct Foo;`) that /// implements the `Monotonic` trait. This argument must be provided to use the `schedule` API. /// -/// The items allowed in the block value of the `const` item are specified below: +/// The items allowed in the module block are specified below: /// -/// # 1. `struct Resources` +/// # 1. `#[resources] struct ` /// /// This structure contains the declaration of all the resources used by the application. Each field /// in this structure corresponds to a different resource. Each resource may optionally be given an diff --git a/macros/src/tests/single.rs b/macros/src/tests/single.rs index d6693882a3..97cbbb3f3a 100644 --- a/macros/src/tests/single.rs +++ b/macros/src/tests/single.rs @@ -8,7 +8,7 @@ fn analyze() { let (app, analysis) = rtic_syntax::parse2( quote!(device = pac), quote!( - const APP: () = { + mod app { #[task(priority = 1)] fn a(_: a::Context) {} @@ -20,7 +20,7 @@ fn analyze() { fn B(); fn A(); } - }; + } ), settings, ) diff --git a/src/export.rs b/src/export.rs index 8a5d4e3e56..27f7f5fbf8 100644 --- a/src/export.rs +++ b/src/export.rs @@ -4,6 +4,7 @@ use core::{ }; pub use crate::tq::{NotReady, TimerQueue}; +pub use bare_metal::CriticalSection; #[cfg(armv7m)] pub use cortex_m::register::basepri; pub use cortex_m::{ @@ -15,8 +16,6 @@ pub use cortex_m::{ use heapless::spsc::SingleCore; pub use heapless::{consts, i::Queue as iQueue, spsc::Queue}; pub use heapless::{i::BinaryHeap as iBinaryHeap, BinaryHeap}; -#[cfg(feature = "heterogeneous")] -pub use microamp::shared; pub type SCFQ = Queue; pub type SCRQ = Queue<(T, u8), N, u8, SingleCore>; diff --git a/ui/single/exception-invalid.rs b/ui/single/exception-invalid.rs index efe0621243..04d9bc75f0 100644 --- a/ui/single/exception-invalid.rs +++ b/ui/single/exception-invalid.rs @@ -1,7 +1,7 @@ #![no_main] #[rtic::app(device = lm3s6965)] -const APP: () = { +mod app { #[task(binds = NonMaskableInt)] fn nmi(_: nmi::Context) {} -}; +} diff --git a/ui/single/exception-systick-used.rs b/ui/single/exception-systick-used.rs index 36ed1744b1..1c30b7004b 100644 --- a/ui/single/exception-systick-used.rs +++ b/ui/single/exception-systick-used.rs @@ -1,10 +1,10 @@ #![no_main] #[rtic::app(device = lm3s6965)] -const APP: () = { +mod app { #[task(binds = SysTick)] fn sys_tick(_: sys_tick::Context) {} #[task(schedule = [foo])] fn foo(_: foo::Context) {} -}; +} diff --git a/ui/single/extern-interrupt-not-enough.rs b/ui/single/extern-interrupt-not-enough.rs index 53820b52ae..f262403640 100644 --- a/ui/single/extern-interrupt-not-enough.rs +++ b/ui/single/extern-interrupt-not-enough.rs @@ -1,7 +1,7 @@ #![no_main] #[rtic::app(device = lm3s6965)] -const APP: () = { +mod app { #[task] fn a(_: a::Context) {} -}; +} diff --git a/ui/single/extern-interrupt-used.rs b/ui/single/extern-interrupt-used.rs index 82f1bdd22a..89c2378460 100644 --- a/ui/single/extern-interrupt-used.rs +++ b/ui/single/extern-interrupt-used.rs @@ -1,11 +1,11 @@ #![no_main] #[rtic::app(device = lm3s6965)] -const APP: () = { +mod app { #[task(binds = UART0)] fn a(_: a::Context) {} extern "C" { fn UART0(); } -}; +} diff --git a/ui/single/locals-cfg.rs b/ui/single/locals-cfg.rs index 54bba8aefd..45a7a9116a 100644 --- a/ui/single/locals-cfg.rs +++ b/ui/single/locals-cfg.rs @@ -1,13 +1,16 @@ #![no_main] +use panic_halt as _; #[rtic::app(device = lm3s6965)] -const APP: () = { +mod app { #[init] - fn init(_: init::Context) { + fn init(_: init::Context) -> init::LateResources { #[cfg(never)] static mut FOO: u32 = 0; FOO; + + init::LateResources {} } #[idle] @@ -47,4 +50,4 @@ const APP: () = { extern "C" { fn UART1(); } -}; +} diff --git a/ui/single/locals-cfg.stderr b/ui/single/locals-cfg.stderr index bb558fa60e..e58bd935e3 100644 --- a/ui/single/locals-cfg.stderr +++ b/ui/single/locals-cfg.stderr @@ -1,37 +1,41 @@ error[E0425]: cannot find value `FOO` in this scope - --> $DIR/locals-cfg.rs:10:9 + --> $DIR/locals-cfg.rs:11:9 | -10 | FOO; +11 | FOO; | ^^^ not found in this scope error[E0425]: cannot find value `FOO` in this scope - --> $DIR/locals-cfg.rs:18:9 + --> $DIR/locals-cfg.rs:21:9 | -18 | FOO; +21 | FOO; | ^^^ not found in this scope error[E0425]: cannot find value `FOO` in this scope - --> $DIR/locals-cfg.rs:28:9 + --> $DIR/locals-cfg.rs:31:9 | -28 | FOO; +31 | FOO; | ^^^ not found in this scope error[E0425]: cannot find value `FOO` in this scope - --> $DIR/locals-cfg.rs:36:9 + --> $DIR/locals-cfg.rs:39:9 | -36 | FOO; +39 | FOO; | ^^^ not found in this scope error[E0425]: cannot find value `FOO` in this scope - --> $DIR/locals-cfg.rs:44:9 + --> $DIR/locals-cfg.rs:47:9 | -44 | FOO; +47 | FOO; | ^^^ not found in this scope -error: duplicate lang item in crate `panic_halt`: `panic_impl`. +error: duplicate lang item in crate `panic_halt` (which `$CRATE` depends on): `panic_impl`. | - = note: first defined in crate `std`. + = note: the lang item is first defined in crate `std` (which `$CRATE` depends on) + = note: first definition in `std` loaded from /usr/share/rust/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libstd-cf0f33af3a901778.rlib + = note: second definition in `panic_halt` loaded from $DIR/target/tests/target/x86_64-unknown-linux-gnu/debug/deps/libpanic_halt-ba6f0ab3439cbc7e.rmeta error: duplicate lang item in crate `panic_semihosting`: `panic_impl`. | - = note: first defined in crate `panic_halt`. + = note: the lang item is first defined in crate `panic_halt` (which `$CRATE` depends on) + = note: first definition in `panic_halt` loaded from $DIR/target/tests/target/x86_64-unknown-linux-gnu/debug/deps/libpanic_halt-ba6f0ab3439cbc7e.rmeta + = note: second definition in `panic_semihosting` loaded from $DIR/target/tests/target/x86_64-unknown-linux-gnu/debug/deps/libpanic_semihosting-805015f4a2d05965.rmeta diff --git a/ui/single/resources-cfg.rs b/ui/single/resources-cfg.rs index df7ac80605..2ba65a048a 100644 --- a/ui/single/resources-cfg.rs +++ b/ui/single/resources-cfg.rs @@ -1,7 +1,9 @@ #![no_main] +use panic_halt as _; #[rtic::app(device = lm3s6965)] -const APP: () = { +mod app { + #[resources] struct Resources { #[cfg(never)] #[init(0)] @@ -41,12 +43,14 @@ const APP: () = { } #[init(resources = [o1, o4, o5, o6, s3])] - fn init(c: init::Context) { + fn init(c: init::Context) -> init::LateResources { c.resources.o1; c.resources.o4; c.resources.o5; c.resources.o6; c.resources.s3; + + init::LateResources {} } #[idle(resources = [o2, &o4, s1, &s3])] @@ -72,4 +76,4 @@ const APP: () = { c.resources.s2; c.resources.o5; } -}; +} diff --git a/ui/single/resources-cfg.stderr b/ui/single/resources-cfg.stderr index c47b95d4b9..17f08d8133 100644 --- a/ui/single/resources-cfg.stderr +++ b/ui/single/resources-cfg.stderr @@ -1,119 +1,125 @@ +error: duplicate lang item in crate `panic_halt` (which `$CRATE` depends on): `panic_impl`. + | + = note: the lang item is first defined in crate `std` (which `$CRATE` depends on) + = note: first definition in `std` loaded from /usr/share/rust/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libstd-cf0f33af3a901778.rlib + = note: second definition in `panic_halt` loaded from $DIR/target/tests/target/x86_64-unknown-linux-gnu/debug/deps/libpanic_halt-ba6f0ab3439cbc7e.rmeta + error[E0609]: no field `o1` on type `initResources<'_>` - --> $DIR/resources-cfg.rs:45:21 + --> $DIR/resources-cfg.rs:47:21 | -45 | c.resources.o1; +47 | c.resources.o1; | ^^ unknown field | = note: available fields are: `__marker__` error[E0609]: no field `o4` on type `initResources<'_>` - --> $DIR/resources-cfg.rs:46:21 + --> $DIR/resources-cfg.rs:48:21 | -46 | c.resources.o4; +48 | c.resources.o4; | ^^ unknown field | = note: available fields are: `__marker__` error[E0609]: no field `o5` on type `initResources<'_>` - --> $DIR/resources-cfg.rs:47:21 + --> $DIR/resources-cfg.rs:49:21 | -47 | c.resources.o5; +49 | c.resources.o5; | ^^ unknown field | = note: available fields are: `__marker__` error[E0609]: no field `o6` on type `initResources<'_>` - --> $DIR/resources-cfg.rs:48:21 + --> $DIR/resources-cfg.rs:50:21 | -48 | c.resources.o6; +50 | c.resources.o6; | ^^ unknown field | = note: available fields are: `__marker__` error[E0609]: no field `s3` on type `initResources<'_>` - --> $DIR/resources-cfg.rs:49:21 + --> $DIR/resources-cfg.rs:51:21 | -49 | c.resources.s3; +51 | c.resources.s3; | ^^ unknown field | = note: available fields are: `__marker__` error[E0609]: no field `o2` on type `idleResources<'_>` - --> $DIR/resources-cfg.rs:54:21 + --> $DIR/resources-cfg.rs:58:21 | -54 | c.resources.o2; +58 | c.resources.o2; | ^^ unknown field | = note: available fields are: `__marker__` error[E0609]: no field `o4` on type `idleResources<'_>` - --> $DIR/resources-cfg.rs:55:21 + --> $DIR/resources-cfg.rs:59:21 | -55 | c.resources.o4; +59 | c.resources.o4; | ^^ unknown field | = note: available fields are: `__marker__` error[E0609]: no field `s1` on type `idleResources<'_>` - --> $DIR/resources-cfg.rs:56:21 + --> $DIR/resources-cfg.rs:60:21 | -56 | c.resources.s1; +60 | c.resources.s1; | ^^ unknown field | = note: available fields are: `__marker__` error[E0609]: no field `s3` on type `idleResources<'_>` - --> $DIR/resources-cfg.rs:57:21 + --> $DIR/resources-cfg.rs:61:21 | -57 | c.resources.s3; +61 | c.resources.s3; | ^^ unknown field | = note: available fields are: `__marker__` error[E0609]: no field `o3` on type `uart0Resources<'_>` - --> $DIR/resources-cfg.rs:64:21 + --> $DIR/resources-cfg.rs:68:21 | -64 | c.resources.o3; +68 | c.resources.o3; | ^^ unknown field | = note: available fields are: `__marker__` error[E0609]: no field `s1` on type `uart0Resources<'_>` - --> $DIR/resources-cfg.rs:65:21 + --> $DIR/resources-cfg.rs:69:21 | -65 | c.resources.s1; +69 | c.resources.s1; | ^^ unknown field | = note: available fields are: `__marker__` error[E0609]: no field `s2` on type `uart0Resources<'_>` - --> $DIR/resources-cfg.rs:66:21 + --> $DIR/resources-cfg.rs:70:21 | -66 | c.resources.s2; +70 | c.resources.s2; | ^^ unknown field | = note: available fields are: `__marker__` error[E0609]: no field `s3` on type `uart0Resources<'_>` - --> $DIR/resources-cfg.rs:67:21 + --> $DIR/resources-cfg.rs:71:21 | -67 | c.resources.s3; +71 | c.resources.s3; | ^^ unknown field | = note: available fields are: `__marker__` error[E0609]: no field `s2` on type `uart1Resources<'_>` - --> $DIR/resources-cfg.rs:72:21 + --> $DIR/resources-cfg.rs:76:21 | -72 | c.resources.s2; +76 | c.resources.s2; | ^^ unknown field | = note: available fields are: `__marker__` error[E0609]: no field `o5` on type `uart1Resources<'_>` - --> $DIR/resources-cfg.rs:73:21 + --> $DIR/resources-cfg.rs:77:21 | -73 | c.resources.o5; +77 | c.resources.o5; | ^^ unknown field | = note: available fields are: `__marker__` diff --git a/ui/single/task-priority-too-high.rs b/ui/single/task-priority-too-high.rs index 539c3f5d0e..caa7b8ee24 100644 --- a/ui/single/task-priority-too-high.rs +++ b/ui/single/task-priority-too-high.rs @@ -1,11 +1,11 @@ #![no_main] -use rtic::app; - #[rtic::app(device = lm3s6965)] -const APP: () = { +mod app { #[init] - fn init(_: init::Context) {} + fn init(_: init::Context) -> init::LateResources { + init::LateResources {} + } #[task(binds = GPIOA, priority = 1)] fn gpioa(_: gpioa::Context) {} @@ -35,4 +35,4 @@ const APP: () = { // this value is too high! #[task(binds = I2C0, priority = 9)] fn i2c0(_: i2c0::Context) {} -}; +} diff --git a/ui/single/task-priority-too-high.stderr b/ui/single/task-priority-too-high.stderr index eae6074df9..e84ddd3cd4 100644 --- a/ui/single/task-priority-too-high.stderr +++ b/ui/single/task-priority-too-high.stderr @@ -1,13 +1,7 @@ -warning: unused import: `rtic::app` - --> $DIR/task-priority-too-high.rs:3:5 - | -3 | use rtic::app; - | ^^^^^^^^^ - | - = note: #[warn(unused_imports)] on by default - error[E0080]: evaluation of constant value failed - --> $DIR/task-priority-too-high.rs:5:1 + --> $DIR/task-priority-too-high.rs:3:1 | -5 | #[rtic::app(device = lm3s6965)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to subtract with overflow +3 | #[rtic::app(device = lm3s6965)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to compute `8_usize - 9_usize` which would overflow + | + = note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info)