aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2022-02-12 00:30:47 +0000
committerGitHub <[email protected]>2022-02-12 00:30:47 +0000
commite728a32672d9cb108d73ba017a6a153dbc6c2d15 (patch)
tree25cdf290d138929ebf0ff292fc6934e0a266400a
parentd708be7fe5e8fec8f2feea269fcb6964b6c73dcb (diff)
parent1904906b363d2bbe32e95546f53201a3179dcb60 (diff)
Merge #613
613: Rust stable support r=Dirbaio a=Dirbaio This PR adds (limited) stable Rust support! The drawbacks are: - No `#[embassy::task]`, `#[embassy::main]`. (requires `type_alias_impl_trait`). You have to manually allocate the tasks somewhere they'll live forever. See [example](https://github.com/embassy-rs/embassy/blob/master/examples/nrf/src/bin/raw_spawn.rs) - No async trait impls (requires GATs). Note that the full API surface of HALs is still available through inherent methods: #552 #581 - Some stuff is not constructible in const (requires `const_fn_trait_bound`), although there's an (ugly) workaround for the generic `Mutex`. So it's not that bad in the end, it's fully usable for shipping production-ready firmwares. We'll still recommend nightly as the default, until GATs and `type_alias_impl_trait` are stable. Co-authored-by: Dario Nieuwenhuis <[email protected]>
-rw-r--r--.github/workflows/rust.yml26
-rw-r--r--.gitignore1
-rw-r--r--.vscode/settings.json15
-rwxr-xr-xci.sh36
-rwxr-xr-xci_stable.sh30
-rw-r--r--docs/modules/ROOT/examples/basic/Cargo.toml4
-rw-r--r--embassy-macros/src/chip/nrf.rs11
-rw-r--r--embassy-macros/src/chip/rp.rs10
-rw-r--r--embassy-macros/src/chip/stm32.rs11
-rw-r--r--embassy-macros/src/lib.rs534
-rw-r--r--embassy-macros/src/macros/interrupt.rs66
-rw-r--r--embassy-macros/src/macros/interrupt_declare.rs37
-rw-r--r--embassy-macros/src/macros/interrupt_take.rs36
-rw-r--r--embassy-macros/src/macros/main.rs135
-rw-r--r--embassy-macros/src/macros/mod.rs5
-rw-r--r--embassy-macros/src/macros/task.rs90
-rw-r--r--embassy-macros/src/util/ctxt.rs72
-rw-r--r--embassy-macros/src/util/mod.rs2
-rw-r--r--embassy-macros/src/util/path.rs (renamed from embassy-macros/src/path.rs)0
-rw-r--r--embassy-nrf/Cargo.toml8
-rw-r--r--embassy-nrf/src/gpiote.rs7
-rw-r--r--embassy-nrf/src/lib.rs6
-rw-r--r--embassy-nrf/src/spim.rs9
-rw-r--r--embassy-nrf/src/time_driver.rs3
-rw-r--r--embassy-nrf/src/twim.rs85
-rw-r--r--embassy-nrf/src/uarte.rs61
-rw-r--r--embassy-rp/Cargo.toml2
-rw-r--r--embassy-rp/src/timer.rs7
-rw-r--r--embassy-stm32/Cargo.toml2
-rw-r--r--embassy-stm32/src/time_driver.rs8
-rw-r--r--embassy/Cargo.toml6
-rw-r--r--embassy/src/blocking_mutex/kind.rs20
-rw-r--r--embassy/src/blocking_mutex/mod.rs186
-rw-r--r--embassy/src/blocking_mutex/raw.rs112
-rw-r--r--embassy/src/channel/mpsc.rs90
-rw-r--r--embassy/src/channel/signal.rs4
-rw-r--r--embassy/src/executor/raw/mod.rs28
-rw-r--r--embassy/src/lib.rs16
-rw-r--r--embassy/src/time/delay.rs12
-rw-r--r--embassy/src/waitqueue/waker_agnostic.rs7
-rw-r--r--examples/nrf/Cargo.toml3
-rw-r--r--examples/nrf/src/bin/mpsc.rs6
-rw-r--r--examples/nrf/src/bin/uart_split.rs6
-rw-r--r--examples/std/Cargo.toml2
-rw-r--r--examples/stm32f3/src/bin/button_events.rs11
-rw-r--r--examples/wasm/Cargo.toml2
46 files changed, 985 insertions, 845 deletions
diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml
index 767e42243..f1256320d 100644
--- a/.github/workflows/rust.yml
+++ b/.github/workflows/rust.yml
@@ -12,11 +12,11 @@ env:
12jobs: 12jobs:
13 all: 13 all:
14 runs-on: ubuntu-20.04 14 runs-on: ubuntu-20.04
15 needs: [build, test] 15 needs: [build-nightly, build-stable, test]
16 steps: 16 steps:
17 - name: Done 17 - name: Done
18 run: exit 0 18 run: exit 0
19 build: 19 build-nightly:
20 runs-on: ubuntu-latest 20 runs-on: ubuntu-latest
21 permissions: 21 permissions:
22 id-token: write 22 id-token: write
@@ -41,6 +41,28 @@ jobs:
41 chmod +x /usr/local/bin/cargo-batch 41 chmod +x /usr/local/bin/cargo-batch
42 ./ci.sh 42 ./ci.sh
43 rm -rf target_ci/*{,/release}/{build,deps,.fingerprint}/{lib,}{embassy,stm32}* 43 rm -rf target_ci/*{,/release}/{build,deps,.fingerprint}/{lib,}{embassy,stm32}*
44 build-stable:
45 runs-on: ubuntu-latest
46 steps:
47 - uses: actions/checkout@v2
48 with:
49 submodules: true
50 - name: Cache multiple paths
51 uses: actions/cache@v2
52 with:
53 path: |
54 ~/.cargo/bin/
55 ~/.cargo/registry/index/
56 ~/.cargo/registry/cache/
57 ~/.cargo/git/db/
58 target_ci_stable
59 key: rust-stable-${{ runner.os }}-${{ hashFiles('rust-toolchain.toml') }}
60 - name: build
61 run: |
62 curl -L -o /usr/local/bin/cargo-batch https://github.com/embassy-rs/cargo-batch/releases/download/batch-0.1.0/cargo-batch
63 chmod +x /usr/local/bin/cargo-batch
64 ./ci_stable.sh
65 rm -rf target_ci_stable/*{,/release}/{build,deps,.fingerprint}/{lib,}{embassy,stm32}*
44 66
45 test: 67 test:
46 runs-on: ubuntu-latest 68 runs-on: ubuntu-latest
diff --git a/.gitignore b/.gitignore
index 92f9a32b2..144dd703f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,6 @@
1target 1target
2target_ci 2target_ci
3target_ci_stable
3Cargo.lock 4Cargo.lock
4third_party 5third_party
5/Cargo.toml 6/Cargo.toml
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 3defc9077..79433a7c9 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -4,16 +4,19 @@
4 "rust-analyzer.assist.importGranularity": "module", 4 "rust-analyzer.assist.importGranularity": "module",
5 "rust-analyzer.checkOnSave.allFeatures": false, 5 "rust-analyzer.checkOnSave.allFeatures": false,
6 "rust-analyzer.checkOnSave.allTargets": false, 6 "rust-analyzer.checkOnSave.allTargets": false,
7 "rust-analyzer.checkOnSave.command": "clippy", 7 "rust-analyzer.checkOnSave.noDefaultFeatures": true,
8 "rust-analyzer.cargo.allFeatures": false,
8 "rust-analyzer.cargo.noDefaultFeatures": true, 9 "rust-analyzer.cargo.noDefaultFeatures": true,
9 "rust-analyzer.experimental.procAttrMacros": false, 10 "rust-analyzer.experimental.procAttrMacros": false,
10 "rust-analyzer.checkOnSave.noDefaultFeatures": true, 11 "rust-analyzer.procMacro.enable": true,
12 "rust-analyzer.cargo.runBuildScripts": true,
11 "rust-analyzer.cargo.target": "thumbv7em-none-eabi", 13 "rust-analyzer.cargo.target": "thumbv7em-none-eabi",
12 "rust-analyzer.cargo.features": [ 14 "rust-analyzer.cargo.features": [
13 // These are needed to prevent embassy-net from failing to build 15 // These are needed to prevent embassy-net from failing to build
14 //"embassy-net/medium-ethernet", 16 //"embassy-net/medium-ethernet",
15 //"embassy-net/tcp", 17 //"embassy-net/tcp",
16 //"embassy-net/pool-16", 18 //"embassy-net/pool-16",
19 "nightly",
17 ], 20 ],
18 "rust-analyzer.linkedProjects": [ 21 "rust-analyzer.linkedProjects": [
19 // Declare for the target you wish to develop 22 // Declare for the target you wish to develop
@@ -35,12 +38,4 @@
35 // "examples/stm32wl55/Cargo.toml", 38 // "examples/stm32wl55/Cargo.toml",
36 // "examples/wasm/Cargo.toml", 39 // "examples/wasm/Cargo.toml",
37 ], 40 ],
38 "rust-analyzer.procMacro.enable": true,
39 "rust-analyzer.cargo.runBuildScripts": true,
40 "files.watcherExclude": {
41 "**/.git/objects/**": true,
42 "**/.git/subtree-cache/**": true,
43 "**/target/**": true
44 },
45 "git.ignoreLimitWarning": true
46} \ No newline at end of file 41} \ No newline at end of file
diff --git a/ci.sh b/ci.sh
index 452130be2..cd0db286e 100755
--- a/ci.sh
+++ b/ci.sh
@@ -24,24 +24,24 @@ rm -rf stm32-metapac
24mv stm32-metapac-gen/out stm32-metapac 24mv stm32-metapac-gen/out stm32-metapac
25 25
26cargo batch \ 26cargo batch \
27 --- build --release --manifest-path embassy/Cargo.toml --target thumbv7em-none-eabi \ 27 --- build --release --manifest-path embassy/Cargo.toml --target thumbv7em-none-eabi --features nightly \
28 --- build --release --manifest-path embassy/Cargo.toml --target thumbv7em-none-eabi --features log,executor-agnostic \ 28 --- build --release --manifest-path embassy/Cargo.toml --target thumbv7em-none-eabi --features nightly,log,executor-agnostic \
29 --- build --release --manifest-path embassy/Cargo.toml --target thumbv7em-none-eabi --features defmt \ 29 --- build --release --manifest-path embassy/Cargo.toml --target thumbv7em-none-eabi --features nightly,defmt \
30 --- build --release --manifest-path embassy/Cargo.toml --target thumbv6m-none-eabi --features defmt \ 30 --- build --release --manifest-path embassy/Cargo.toml --target thumbv6m-none-eabi --features nightly,defmt \
31 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52805,gpiote,time-driver-rtc1 \ 31 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nightly,nrf52805,gpiote,time-driver-rtc1 \
32 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52810,gpiote,time-driver-rtc1 \ 32 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nightly,nrf52810,gpiote,time-driver-rtc1 \
33 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52811,gpiote,time-driver-rtc1 \ 33 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nightly,nrf52811,gpiote,time-driver-rtc1 \
34 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52820,gpiote,time-driver-rtc1 \ 34 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nightly,nrf52820,gpiote,time-driver-rtc1 \
35 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52832,gpiote,time-driver-rtc1 \ 35 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nightly,nrf52832,gpiote,time-driver-rtc1 \
36 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52833,gpiote,time-driver-rtc1,unstable-traits \ 36 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nightly,nrf52833,gpiote,time-driver-rtc1,unstable-traits \
37 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features nrf9160-s,gpiote,time-driver-rtc1 \ 37 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features nightly,nrf9160-s,gpiote,time-driver-rtc1 \
38 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features nrf9160-ns,gpiote,time-driver-rtc1,unstable-traits \ 38 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features nightly,nrf9160-ns,gpiote,time-driver-rtc1,unstable-traits \
39 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features nrf5340-app-s,gpiote,time-driver-rtc1,unstable-traits \ 39 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features nightly,nrf5340-app-s,gpiote,time-driver-rtc1,unstable-traits \
40 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features nrf5340-app-ns,gpiote,time-driver-rtc1 \ 40 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features nightly,nrf5340-app-ns,gpiote,time-driver-rtc1 \
41 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features nrf5340-net,gpiote,time-driver-rtc1,unstable-traits \ 41 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features nightly,nrf5340-net,gpiote,time-driver-rtc1,unstable-traits \
42 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52840,gpiote,time-driver-rtc1 \ 42 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nightly,nrf52840,gpiote,time-driver-rtc1 \
43 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52840,log,gpiote,time-driver-rtc1 \ 43 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nightly,nrf52840,log,gpiote,time-driver-rtc1 \
44 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52840,defmt,gpiote,time-driver-rtc1,unstable-traits \ 44 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nightly,nrf52840,defmt,gpiote,time-driver-rtc1,unstable-traits \
45 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f411ce,defmt,time-driver-any \ 45 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f411ce,defmt,time-driver-any \
46 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f411ce,defmt,time-driver-any,unstable-traits \ 46 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f411ce,defmt,time-driver-any,unstable-traits \
47 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f429zi,log,time-driver-any \ 47 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f429zi,log,time-driver-any \
diff --git a/ci_stable.sh b/ci_stable.sh
new file mode 100755
index 000000000..c4ec30824
--- /dev/null
+++ b/ci_stable.sh
@@ -0,0 +1,30 @@
1#!/bin/bash
2
3set -euo pipefail
4
5export CARGO_TARGET_DIR=$PWD/target_ci_stable
6export RUSTFLAGS=-Dwarnings
7export DEFMT_LOG=trace
8
9sed -i 's/channel.*/channel = "stable"/g' rust-toolchain.toml
10
11cargo batch \
12 --- build --release --manifest-path embassy/Cargo.toml --target thumbv7em-none-eabi \
13 --- build --release --manifest-path embassy/Cargo.toml --target thumbv7em-none-eabi --features log,executor-agnostic \
14 --- build --release --manifest-path embassy/Cargo.toml --target thumbv7em-none-eabi --features defmt \
15 --- build --release --manifest-path embassy/Cargo.toml --target thumbv6m-none-eabi --features defmt \
16 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52805,gpiote,time-driver-rtc1 \
17 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52810,gpiote,time-driver-rtc1 \
18 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52811,gpiote,time-driver-rtc1 \
19 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52820,gpiote,time-driver-rtc1 \
20 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52832,gpiote,time-driver-rtc1 \
21 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52833,gpiote,time-driver-rtc1,unstable-traits \
22 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features nrf9160-s,gpiote,time-driver-rtc1 \
23 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features nrf9160-ns,gpiote,time-driver-rtc1,unstable-traits \
24 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features nrf5340-app-s,gpiote,time-driver-rtc1,unstable-traits \
25 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features nrf5340-app-ns,gpiote,time-driver-rtc1 \
26 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features nrf5340-net,gpiote,time-driver-rtc1,unstable-traits \
27 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52840,gpiote,time-driver-rtc1 \
28 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52840,log,gpiote,time-driver-rtc1 \
29 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52840,defmt,gpiote,time-driver-rtc1,unstable-traits \
30 --- build --release --manifest-path examples/nrf/Cargo.toml --target thumbv7em-none-eabi --no-default-features --out-dir out/examples/nrf --bin raw_spawn \
diff --git a/docs/modules/ROOT/examples/basic/Cargo.toml b/docs/modules/ROOT/examples/basic/Cargo.toml
index 0f1c30da3..ed1c3cb1c 100644
--- a/docs/modules/ROOT/examples/basic/Cargo.toml
+++ b/docs/modules/ROOT/examples/basic/Cargo.toml
@@ -5,8 +5,8 @@ name = "embassy-basic-example"
5version = "0.1.0" 5version = "0.1.0"
6 6
7[dependencies] 7[dependencies]
8embassy = { version = "0.1.0", path = "../../../../../embassy", features = ["defmt"] } 8embassy = { version = "0.1.0", path = "../../../../../embassy", features = ["defmt", "nightly"] }
9embassy-nrf = { version = "0.1.0", path = "../../../../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote"] } 9embassy-nrf = { version = "0.1.0", path = "../../../../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "nightly"] }
10 10
11defmt = "0.3" 11defmt = "0.3"
12defmt-rtt = "0.3" 12defmt-rtt = "0.3"
diff --git a/embassy-macros/src/chip/nrf.rs b/embassy-macros/src/chip/nrf.rs
deleted file mode 100644
index 3ff6a74cf..000000000
--- a/embassy-macros/src/chip/nrf.rs
+++ /dev/null
@@ -1,11 +0,0 @@
1use crate::path::ModulePrefix;
2use proc_macro2::TokenStream;
3use quote::quote;
4
5pub fn generate(embassy_prefix: &ModulePrefix, config: syn::Expr) -> TokenStream {
6 let embassy_nrf_path = embassy_prefix.append("embassy_nrf").path();
7
8 quote!(
9 let p = #embassy_nrf_path::init(#config);
10 )
11}
diff --git a/embassy-macros/src/chip/rp.rs b/embassy-macros/src/chip/rp.rs
deleted file mode 100644
index ba0a97ada..000000000
--- a/embassy-macros/src/chip/rp.rs
+++ /dev/null
@@ -1,10 +0,0 @@
1use crate::path::ModulePrefix;
2use proc_macro2::TokenStream;
3use quote::quote;
4
5pub fn generate(embassy_prefix: &ModulePrefix, config: syn::Expr) -> TokenStream {
6 let embassy_rp_path = embassy_prefix.append("embassy_rp").path();
7 quote!(
8 let p = #embassy_rp_path::init(#config);
9 )
10}
diff --git a/embassy-macros/src/chip/stm32.rs b/embassy-macros/src/chip/stm32.rs
deleted file mode 100644
index c6938836c..000000000
--- a/embassy-macros/src/chip/stm32.rs
+++ /dev/null
@@ -1,11 +0,0 @@
1use crate::path::ModulePrefix;
2use proc_macro2::TokenStream;
3use quote::quote;
4
5pub fn generate(embassy_prefix: &ModulePrefix, config: syn::Expr) -> TokenStream {
6 let embassy_stm32_path = embassy_prefix.append("embassy_stm32").path();
7
8 quote!(
9 let p = #embassy_stm32_path::init(#config);
10 )
11}
diff --git a/embassy-macros/src/lib.rs b/embassy-macros/src/lib.rs
index 44a8d3b93..085f7889d 100644
--- a/embassy-macros/src/lib.rs
+++ b/embassy-macros/src/lib.rs
@@ -1,228 +1,39 @@
1#![feature(proc_macro_diagnostic)]
2
3extern crate proc_macro; 1extern crate proc_macro;
4 2
5use darling::FromMeta;
6use proc_macro::TokenStream; 3use proc_macro::TokenStream;
7use proc_macro2::Span;
8use quote::{format_ident, quote};
9use std::iter;
10use syn::spanned::Spanned;
11use syn::{parse, Type, Visibility};
12use syn::{ItemFn, ReturnType};
13
14mod path;
15
16use path::ModulePrefix;
17 4
18#[derive(Debug, FromMeta)] 5mod macros;
19struct TaskArgs { 6mod util;
20 #[darling(default)] 7use macros::*;
21 pool_size: Option<usize>,
22 #[darling(default)]
23 send: bool,
24 #[darling(default)]
25 embassy_prefix: ModulePrefix,
26}
27 8
28#[proc_macro_attribute] 9#[proc_macro_attribute]
29pub fn task(args: TokenStream, item: TokenStream) -> TokenStream { 10pub fn task(args: TokenStream, item: TokenStream) -> TokenStream {
30 let macro_args = syn::parse_macro_input!(args as syn::AttributeArgs); 11 let args = syn::parse_macro_input!(args as syn::AttributeArgs);
31 let mut task_fn = syn::parse_macro_input!(item as syn::ItemFn); 12 let f = syn::parse_macro_input!(item as syn::ItemFn);
32
33 let macro_args = match TaskArgs::from_list(&macro_args) {
34 Ok(v) => v,
35 Err(e) => {
36 return TokenStream::from(e.write_errors());
37 }
38 };
39
40 let embassy_prefix = macro_args.embassy_prefix.append("embassy");
41 let embassy_path = embassy_prefix.path();
42
43 let pool_size: usize = macro_args.pool_size.unwrap_or(1);
44
45 let mut fail = false;
46 if task_fn.sig.asyncness.is_none() {
47 task_fn
48 .sig
49 .span()
50 .unwrap()
51 .error("task functions must be async")
52 .emit();
53 fail = true;
54 }
55 if !task_fn.sig.generics.params.is_empty() {
56 task_fn
57 .sig
58 .span()
59 .unwrap()
60 .error("task functions must not be generic")
61 .emit();
62 fail = true;
63 }
64 if pool_size < 1 {
65 return parse::Error::new(Span::call_site(), "pool_size must be 1 or greater")
66 .to_compile_error()
67 .into();
68 }
69
70 let mut arg_names: syn::punctuated::Punctuated<syn::Ident, syn::Token![,]> =
71 syn::punctuated::Punctuated::new();
72 let mut args = task_fn.sig.inputs.clone();
73
74 for arg in args.iter_mut() {
75 match arg {
76 syn::FnArg::Receiver(_) => {
77 arg.span()
78 .unwrap()
79 .error("task functions must not have receiver arguments")
80 .emit();
81 fail = true;
82 }
83 syn::FnArg::Typed(t) => match t.pat.as_mut() {
84 syn::Pat::Ident(i) => {
85 arg_names.push(i.ident.clone());
86 i.mutability = None;
87 }
88 _ => {
89 arg.span()
90 .unwrap()
91 .error("pattern matching in task arguments is not yet supporteds")
92 .emit();
93 fail = true;
94 }
95 },
96 }
97 }
98
99 if fail {
100 return TokenStream::new();
101 }
102 13
103 let name = task_fn.sig.ident.clone(); 14 task::run(args, f).unwrap_or_else(|x| x).into()
104
105 let visibility = &task_fn.vis;
106 task_fn.sig.ident = format_ident!("task");
107 let impl_ty = if macro_args.send {
108 quote!(impl ::core::future::Future + Send + 'static)
109 } else {
110 quote!(impl ::core::future::Future + 'static)
111 };
112
113 let attrs = &task_fn.attrs;
114
115 let result = quote! {
116 #(#attrs)*
117 #visibility fn #name(#args) -> #embassy_path::executor::SpawnToken<#impl_ty> {
118 use #embassy_path::executor::raw::TaskStorage;
119 #task_fn
120 type F = #impl_ty;
121 #[allow(clippy::declare_interior_mutable_const)]
122 const NEW_TASK: TaskStorage<F> = TaskStorage::new();
123 static POOL: [TaskStorage<F>; #pool_size] = [NEW_TASK; #pool_size];
124 unsafe { TaskStorage::spawn_pool(&POOL, move || task(#arg_names)) }
125 }
126 };
127 result.into()
128} 15}
129 16
130#[proc_macro_attribute] 17#[proc_macro_attribute]
131pub fn interrupt(args: TokenStream, input: TokenStream) -> TokenStream { 18pub fn main(args: TokenStream, item: TokenStream) -> TokenStream {
132 let mut f: ItemFn = syn::parse(input).expect("`#[interrupt]` must be applied to a function"); 19 let args = syn::parse_macro_input!(args as syn::AttributeArgs);
133 20 let f = syn::parse_macro_input!(item as syn::ItemFn);
134 if !args.is_empty() { 21 main::run(args, f).unwrap_or_else(|x| x).into()
135 return parse::Error::new(Span::call_site(), "This attribute accepts no arguments") 22}
136 .to_compile_error()
137 .into();
138 }
139
140 let fspan = f.span();
141 let ident = f.sig.ident.clone();
142 let ident_s = ident.to_string();
143
144 // XXX should we blacklist other attributes?
145
146 let valid_signature = f.sig.constness.is_none()
147 && f.vis == Visibility::Inherited
148 && f.sig.abi.is_none()
149 && f.sig.inputs.is_empty()
150 && f.sig.generics.params.is_empty()
151 && f.sig.generics.where_clause.is_none()
152 && f.sig.variadic.is_none()
153 && match f.sig.output {
154 ReturnType::Default => true,
155 ReturnType::Type(_, ref ty) => match **ty {
156 Type::Tuple(ref tuple) => tuple.elems.is_empty(),
157 Type::Never(..) => true,
158 _ => false,
159 },
160 };
161
162 if !valid_signature {
163 return parse::Error::new(
164 fspan,
165 "`#[interrupt]` handlers must have signature `[unsafe] fn() [-> !]`",
166 )
167 .to_compile_error()
168 .into();
169 }
170
171 f.block.stmts = iter::once(
172 syn::parse2(quote! {{
173 // Check that this interrupt actually exists
174 let __irq_exists_check: interrupt::#ident;
175 }})
176 .unwrap(),
177 )
178 .chain(f.block.stmts)
179 .collect();
180 23
181 quote!( 24#[proc_macro_attribute]
182 #[doc(hidden)] 25pub fn interrupt(args: TokenStream, item: TokenStream) -> TokenStream {
183 #[export_name = #ident_s] 26 let args = syn::parse_macro_input!(args as syn::AttributeArgs);
184 #[allow(non_snake_case)] 27 let f = syn::parse_macro_input!(item as syn::ItemFn);
185 #f 28 interrupt::run(args, f).unwrap_or_else(|x| x).into()
186 )
187 .into()
188} 29}
189 30
190#[proc_macro] 31#[proc_macro]
191pub fn interrupt_declare(item: TokenStream) -> TokenStream { 32pub fn interrupt_declare(item: TokenStream) -> TokenStream {
192 let name = syn::parse_macro_input!(item as syn::Ident); 33 let name = syn::parse_macro_input!(item as syn::Ident);
193 let name = format_ident!("{}", name); 34 interrupt_declare::run(name).unwrap_or_else(|x| x).into()
194 let name_interrupt = format_ident!("{}", name);
195 let name_handler = format!("__EMBASSY_{}_HANDLER", name);
196
197 let result = quote! {
198 #[allow(non_camel_case_types)]
199 pub struct #name_interrupt(());
200 unsafe impl ::embassy::interrupt::Interrupt for #name_interrupt {
201 type Priority = crate::interrupt::Priority;
202 fn number(&self) -> u16 {
203 use cortex_m::interrupt::InterruptNumber;
204 let irq = InterruptEnum::#name;
205 irq.number() as u16
206 }
207 unsafe fn steal() -> Self {
208 Self(())
209 }
210 unsafe fn __handler(&self) -> &'static ::embassy::interrupt::Handler {
211 #[export_name = #name_handler]
212 static HANDLER: ::embassy::interrupt::Handler = ::embassy::interrupt::Handler::new();
213 &HANDLER
214 }
215 }
216
217 unsafe impl ::embassy::util::Unborrow for #name_interrupt {
218 type Target = #name_interrupt;
219 unsafe fn unborrow(self) -> #name_interrupt {
220 self
221 }
222 }
223 };
224 result.into()
225} 35}
36
226/// # interrupt_take procedural macro 37/// # interrupt_take procedural macro
227/// 38///
228/// core::panic! is used as a default way to panic in this macro as there is no sensible way of enabling/disabling defmt for macro generation. 39/// core::panic! is used as a default way to panic in this macro as there is no sensible way of enabling/disabling defmt for macro generation.
@@ -231,312 +42,5 @@ pub fn interrupt_declare(item: TokenStream) -> TokenStream {
231#[proc_macro] 42#[proc_macro]
232pub fn interrupt_take(item: TokenStream) -> TokenStream { 43pub fn interrupt_take(item: TokenStream) -> TokenStream {
233 let name = syn::parse_macro_input!(item as syn::Ident); 44 let name = syn::parse_macro_input!(item as syn::Ident);
234 let name = format!("{}", name); 45 interrupt_take::run(name).unwrap_or_else(|x| x).into()
235 let name_interrupt = format_ident!("{}", name);
236 let name_handler = format!("__EMBASSY_{}_HANDLER", name);
237
238 let result = quote! {
239 {
240 #[allow(non_snake_case)]
241 #[export_name = #name]
242 pub unsafe extern "C" fn trampoline() {
243 extern "C" {
244 #[link_name = #name_handler]
245 static HANDLER: ::embassy::interrupt::Handler;
246 }
247
248 let func = HANDLER.func.load(::embassy::export::atomic::Ordering::Relaxed);
249 let ctx = HANDLER.ctx.load(::embassy::export::atomic::Ordering::Relaxed);
250 let func: fn(*mut ()) = ::core::mem::transmute(func);
251 func(ctx)
252 }
253
254 static TAKEN: ::embassy::export::atomic::AtomicBool = ::embassy::export::atomic::AtomicBool::new(false);
255
256 if TAKEN.compare_exchange(false, true, ::embassy::export::atomic::Ordering::AcqRel, ::embassy::export::atomic::Ordering::Acquire).is_err() {
257 core::panic!("IRQ Already taken");
258 }
259
260 let irq: interrupt::#name_interrupt = unsafe { ::core::mem::transmute(()) };
261 irq
262 }
263 };
264 result.into()
265}
266
267#[cfg(feature = "stm32")]
268#[path = "chip/stm32.rs"]
269mod chip;
270
271#[cfg(feature = "nrf")]
272#[path = "chip/nrf.rs"]
273mod chip;
274
275#[cfg(feature = "rp")]
276#[path = "chip/rp.rs"]
277mod chip;
278
279#[cfg(any(
280 feature = "nrf",
281 feature = "rp",
282 feature = "stm32",
283 feature = "wasm",
284 feature = "std"
285))]
286#[derive(Debug, FromMeta)]
287struct MainArgs {
288 #[darling(default)]
289 embassy_prefix: ModulePrefix,
290
291 #[allow(unused)]
292 #[darling(default)]
293 config: Option<syn::LitStr>,
294}
295
296#[cfg(any(feature = "nrf", feature = "rp", feature = "stm32"))]
297#[proc_macro_attribute]
298pub fn main(args: TokenStream, item: TokenStream) -> TokenStream {
299 let macro_args = syn::parse_macro_input!(args as syn::AttributeArgs);
300 let task_fn = syn::parse_macro_input!(item as syn::ItemFn);
301
302 let macro_args = match MainArgs::from_list(&macro_args) {
303 Ok(v) => v,
304 Err(e) => {
305 return TokenStream::from(e.write_errors());
306 }
307 };
308
309 let mut fail = false;
310 if task_fn.sig.asyncness.is_none() {
311 task_fn
312 .sig
313 .span()
314 .unwrap()
315 .error("task functions must be async")
316 .emit();
317 fail = true;
318 }
319 if !task_fn.sig.generics.params.is_empty() {
320 task_fn
321 .sig
322 .span()
323 .unwrap()
324 .error("main function must not be generic")
325 .emit();
326 fail = true;
327 }
328
329 let args = task_fn.sig.inputs.clone();
330
331 if args.len() != 2 {
332 task_fn
333 .sig
334 .span()
335 .unwrap()
336 .error("main function must have 2 arguments")
337 .emit();
338 fail = true;
339 }
340
341 if fail {
342 return TokenStream::new();
343 }
344
345 let embassy_prefix = macro_args.embassy_prefix;
346 let embassy_prefix_lit = embassy_prefix.literal();
347 let embassy_path = embassy_prefix.append("embassy").path();
348 let task_fn_body = task_fn.block;
349
350 let config = macro_args
351 .config
352 .map(|s| s.parse::<syn::Expr>().unwrap())
353 .unwrap_or_else(|| {
354 syn::Expr::Verbatim(quote! {
355 Default::default()
356 })
357 });
358
359 let chip_setup = chip::generate(&embassy_prefix, config);
360
361 let result = quote! {
362 #[#embassy_path::task(embassy_prefix = #embassy_prefix_lit)]
363 async fn __embassy_main(#args) {
364 #task_fn_body
365 }
366
367 #[cortex_m_rt::entry]
368 fn main() -> ! {
369 unsafe fn make_static<T>(t: &mut T) -> &'static mut T {
370 ::core::mem::transmute(t)
371 }
372
373 #chip_setup
374
375 let mut executor = #embassy_path::executor::Executor::new();
376 let executor = unsafe { make_static(&mut executor) };
377
378 executor.run(|spawner| {
379 spawner.must_spawn(__embassy_main(spawner, p));
380 })
381 }
382 };
383 result.into()
384}
385
386#[cfg(feature = "std")]
387#[proc_macro_attribute]
388pub fn main(args: TokenStream, item: TokenStream) -> TokenStream {
389 let macro_args = syn::parse_macro_input!(args as syn::AttributeArgs);
390 let task_fn = syn::parse_macro_input!(item as syn::ItemFn);
391
392 let macro_args = match MainArgs::from_list(&macro_args) {
393 Ok(v) => v,
394 Err(e) => {
395 return TokenStream::from(e.write_errors());
396 }
397 };
398
399 let embassy_path = macro_args.embassy_prefix.append("embassy");
400
401 let mut fail = false;
402 if task_fn.sig.asyncness.is_none() {
403 task_fn
404 .sig
405 .span()
406 .unwrap()
407 .error("task functions must be async")
408 .emit();
409 fail = true;
410 }
411 if !task_fn.sig.generics.params.is_empty() {
412 task_fn
413 .sig
414 .span()
415 .unwrap()
416 .error("main function must not be generic")
417 .emit();
418 fail = true;
419 }
420
421 let args = task_fn.sig.inputs.clone();
422
423 if args.len() != 1 {
424 task_fn
425 .sig
426 .span()
427 .unwrap()
428 .error("main function must have one argument")
429 .emit();
430 fail = true;
431 }
432
433 if fail {
434 return TokenStream::new();
435 }
436
437 let task_fn_body = task_fn.block.clone();
438
439 let embassy_path = embassy_path.path();
440 let embassy_prefix_lit = macro_args.embassy_prefix.literal();
441
442 let result = quote! {
443 #[#embassy_path::task(embassy_prefix = #embassy_prefix_lit)]
444 async fn __embassy_main(#args) {
445 #task_fn_body
446 }
447
448 fn main() -> ! {
449 unsafe fn make_static<T>(t: &mut T) -> &'static mut T {
450 ::core::mem::transmute(t)
451 }
452
453 let mut executor = #embassy_path::executor::Executor::new();
454 let executor = unsafe { make_static(&mut executor) };
455
456 executor.run(|spawner| {
457 spawner.spawn(__embassy_main(spawner)).unwrap();
458 })
459
460 }
461 };
462 result.into()
463}
464
465#[cfg(feature = "wasm")]
466#[proc_macro_attribute]
467pub fn main(args: TokenStream, item: TokenStream) -> TokenStream {
468 let macro_args = syn::parse_macro_input!(args as syn::AttributeArgs);
469 let task_fn = syn::parse_macro_input!(item as syn::ItemFn);
470
471 let macro_args = match MainArgs::from_list(&macro_args) {
472 Ok(v) => v,
473 Err(e) => {
474 return TokenStream::from(e.write_errors());
475 }
476 };
477
478 let embassy_path = macro_args.embassy_prefix.append("embassy");
479
480 let mut fail = false;
481 if task_fn.sig.asyncness.is_none() {
482 task_fn
483 .sig
484 .span()
485 .unwrap()
486 .error("task functions must be async")
487 .emit();
488 fail = true;
489 }
490 if !task_fn.sig.generics.params.is_empty() {
491 task_fn
492 .sig
493 .span()
494 .unwrap()
495 .error("main function must not be generic")
496 .emit();
497 fail = true;
498 }
499
500 let args = task_fn.sig.inputs.clone();
501
502 if args.len() != 1 {
503 task_fn
504 .sig
505 .span()
506 .unwrap()
507 .error("main function must have one argument")
508 .emit();
509 fail = true;
510 }
511
512 if fail {
513 return TokenStream::new();
514 }
515
516 let task_fn_body = task_fn.block.clone();
517
518 let embassy_path = embassy_path.path();
519 let embassy_prefix_lit = macro_args.embassy_prefix.literal();
520
521 let result = quote! {
522 #[#embassy_path::task(embassy_prefix = #embassy_prefix_lit)]
523 async fn __embassy_main(#args) {
524 #task_fn_body
525 }
526
527 use wasm_bindgen::prelude::*;
528
529 #[wasm_bindgen(start)]
530 pub fn main() -> Result<(), JsValue> {
531 static EXECUTOR: #embassy_path::util::Forever<#embassy_path::executor::Executor> = #embassy_path::util::Forever::new();
532 let executor = EXECUTOR.put(#embassy_path::executor::Executor::new());
533
534 executor.start(|spawner| {
535 spawner.spawn(__embassy_main(spawner)).unwrap();
536 });
537
538 Ok(())
539 }
540 };
541 result.into()
542} 46}
diff --git a/embassy-macros/src/macros/interrupt.rs b/embassy-macros/src/macros/interrupt.rs
new file mode 100644
index 000000000..32cc0e010
--- /dev/null
+++ b/embassy-macros/src/macros/interrupt.rs
@@ -0,0 +1,66 @@
1use darling::FromMeta;
2use proc_macro2::TokenStream;
3use quote::quote;
4use std::iter;
5use syn::ReturnType;
6use syn::{Type, Visibility};
7
8use crate::util::ctxt::Ctxt;
9
10#[derive(Debug, FromMeta)]
11struct Args {}
12
13pub fn run(args: syn::AttributeArgs, mut f: syn::ItemFn) -> Result<TokenStream, TokenStream> {
14 let _args = Args::from_list(&args).map_err(|e| e.write_errors())?;
15
16 let ident = f.sig.ident.clone();
17 let ident_s = ident.to_string();
18
19 // XXX should we blacklist other attributes?
20
21 let valid_signature = f.sig.constness.is_none()
22 && f.vis == Visibility::Inherited
23 && f.sig.abi.is_none()
24 && f.sig.inputs.is_empty()
25 && f.sig.generics.params.is_empty()
26 && f.sig.generics.where_clause.is_none()
27 && f.sig.variadic.is_none()
28 && match f.sig.output {
29 ReturnType::Default => true,
30 ReturnType::Type(_, ref ty) => match **ty {
31 Type::Tuple(ref tuple) => tuple.elems.is_empty(),
32 Type::Never(..) => true,
33 _ => false,
34 },
35 };
36
37 let ctxt = Ctxt::new();
38
39 if !valid_signature {
40 ctxt.error_spanned_by(
41 &f.sig,
42 "`#[interrupt]` handlers must have signature `[unsafe] fn() [-> !]`",
43 );
44 }
45
46 ctxt.check()?;
47
48 f.block.stmts = iter::once(
49 syn::parse2(quote! {{
50 // Check that this interrupt actually exists
51 let __irq_exists_check: interrupt::#ident;
52 }})
53 .unwrap(),
54 )
55 .chain(f.block.stmts)
56 .collect();
57
58 let result = quote!(
59 #[doc(hidden)]
60 #[export_name = #ident_s]
61 #[allow(non_snake_case)]
62 #f
63 );
64
65 Ok(result)
66}
diff --git a/embassy-macros/src/macros/interrupt_declare.rs b/embassy-macros/src/macros/interrupt_declare.rs
new file mode 100644
index 000000000..0059936d9
--- /dev/null
+++ b/embassy-macros/src/macros/interrupt_declare.rs
@@ -0,0 +1,37 @@
1use proc_macro2::TokenStream;
2use quote::{format_ident, quote};
3
4pub fn run(name: syn::Ident) -> Result<TokenStream, TokenStream> {
5 let name = format_ident!("{}", name);
6 let name_interrupt = format_ident!("{}", name);
7 let name_handler = format!("__EMBASSY_{}_HANDLER", name);
8
9 let result = quote! {
10 #[allow(non_camel_case_types)]
11 pub struct #name_interrupt(());
12 unsafe impl ::embassy::interrupt::Interrupt for #name_interrupt {
13 type Priority = crate::interrupt::Priority;
14 fn number(&self) -> u16 {
15 use cortex_m::interrupt::InterruptNumber;
16 let irq = InterruptEnum::#name;
17 irq.number() as u16
18 }
19 unsafe fn steal() -> Self {
20 Self(())
21 }
22 unsafe fn __handler(&self) -> &'static ::embassy::interrupt::Handler {
23 #[export_name = #name_handler]
24 static HANDLER: ::embassy::interrupt::Handler = ::embassy::interrupt::Handler::new();
25 &HANDLER
26 }
27 }
28
29 unsafe impl ::embassy::util::Unborrow for #name_interrupt {
30 type Target = #name_interrupt;
31 unsafe fn unborrow(self) -> #name_interrupt {
32 self
33 }
34 }
35 };
36 Ok(result)
37}
diff --git a/embassy-macros/src/macros/interrupt_take.rs b/embassy-macros/src/macros/interrupt_take.rs
new file mode 100644
index 000000000..230b9c741
--- /dev/null
+++ b/embassy-macros/src/macros/interrupt_take.rs
@@ -0,0 +1,36 @@
1use proc_macro2::TokenStream;
2use quote::{format_ident, quote};
3
4pub fn run(name: syn::Ident) -> Result<TokenStream, TokenStream> {
5 let name = format!("{}", name);
6 let name_interrupt = format_ident!("{}", name);
7 let name_handler = format!("__EMBASSY_{}_HANDLER", name);
8
9 let result = quote! {
10 {
11 #[allow(non_snake_case)]
12 #[export_name = #name]
13 pub unsafe extern "C" fn trampoline() {
14 extern "C" {
15 #[link_name = #name_handler]
16 static HANDLER: ::embassy::interrupt::Handler;
17 }
18
19 let func = HANDLER.func.load(::embassy::export::atomic::Ordering::Relaxed);
20 let ctx = HANDLER.ctx.load(::embassy::export::atomic::Ordering::Relaxed);
21 let func: fn(*mut ()) = ::core::mem::transmute(func);
22 func(ctx)
23 }
24
25 static TAKEN: ::embassy::export::atomic::AtomicBool = ::embassy::export::atomic::AtomicBool::new(false);
26
27 if TAKEN.compare_exchange(false, true, ::embassy::export::atomic::Ordering::AcqRel, ::embassy::export::atomic::Ordering::Acquire).is_err() {
28 core::panic!("IRQ Already taken");
29 }
30
31 let irq: interrupt::#name_interrupt = unsafe { ::core::mem::transmute(()) };
32 irq
33 }
34 };
35 Ok(result)
36}
diff --git a/embassy-macros/src/macros/main.rs b/embassy-macros/src/macros/main.rs
new file mode 100644
index 000000000..01e302921
--- /dev/null
+++ b/embassy-macros/src/macros/main.rs
@@ -0,0 +1,135 @@
1use darling::FromMeta;
2use proc_macro2::TokenStream;
3use quote::quote;
4
5use crate::util::ctxt::Ctxt;
6use crate::util::path::ModulePrefix;
7
8#[cfg(feature = "stm32")]
9const HAL: Option<&str> = Some("embassy_stm32");
10#[cfg(feature = "nrf")]
11const HAL: Option<&str> = Some("embassy_nrf");
12#[cfg(feature = "rp")]
13const HAL: Option<&str> = Some("embassy_rp");
14#[cfg(not(any(feature = "stm32", feature = "nrf", feature = "rp")))]
15const HAL: Option<&str> = None;
16
17#[derive(Debug, FromMeta)]
18struct Args {
19 #[darling(default)]
20 embassy_prefix: ModulePrefix,
21
22 #[allow(unused)]
23 #[darling(default)]
24 config: Option<syn::LitStr>,
25}
26
27pub fn run(args: syn::AttributeArgs, f: syn::ItemFn) -> Result<TokenStream, TokenStream> {
28 let args = Args::from_list(&args).map_err(|e| e.write_errors())?;
29
30 let fargs = f.sig.inputs.clone();
31
32 let ctxt = Ctxt::new();
33
34 if f.sig.asyncness.is_none() {
35 ctxt.error_spanned_by(&f.sig, "task functions must be async");
36 }
37 if !f.sig.generics.params.is_empty() {
38 ctxt.error_spanned_by(&f.sig, "task functions must not be generic");
39 }
40
41 if HAL.is_some() && fargs.len() != 2 {
42 ctxt.error_spanned_by(&f.sig, "main function must have 2 arguments");
43 }
44 if HAL.is_none() && fargs.len() != 1 {
45 ctxt.error_spanned_by(&f.sig, "main function must have 2 arguments");
46 }
47
48 ctxt.check()?;
49
50 let embassy_prefix = args.embassy_prefix;
51 let embassy_prefix_lit = embassy_prefix.literal();
52 let embassy_path = embassy_prefix.append("embassy").path();
53 let f_body = f.block;
54
55 #[cfg(feature = "wasm")]
56 let main = quote! {
57 #[wasm_bindgen::prelude::wasm_bindgen(start)]
58 pub fn main() -> Result<(), wasm_bindgen::JsValue> {
59 static EXECUTOR: #embassy_path::util::Forever<#embassy_path::executor::Executor> = #embassy_path::util::Forever::new();
60 let executor = EXECUTOR.put(#embassy_path::executor::Executor::new());
61
62 executor.start(|spawner| {
63 spawner.spawn(__embassy_main(spawner)).unwrap();
64 });
65
66 Ok(())
67 }
68 };
69
70 #[cfg(all(feature = "std", not(feature = "wasm")))]
71 let main = quote! {
72 fn main() -> ! {
73 let mut executor = #embassy_path::executor::Executor::new();
74 let executor = unsafe { __make_static(&mut executor) };
75
76 executor.run(|spawner| {
77 spawner.must_spawn(__embassy_main(spawner));
78 })
79 }
80 };
81
82 #[cfg(all(not(feature = "std"), not(feature = "wasm")))]
83 let main = {
84 let config = args
85 .config
86 .map(|s| s.parse::<syn::Expr>().unwrap())
87 .unwrap_or_else(|| {
88 syn::Expr::Verbatim(quote! {
89 Default::default()
90 })
91 });
92
93 let (hal_setup, peris_arg) = match HAL {
94 Some(hal) => {
95 let embassy_hal_path = embassy_prefix.append(hal).path();
96 (
97 quote!(
98 let p = #embassy_hal_path::init(#config);
99 ),
100 quote!(p),
101 )
102 }
103 None => (quote!(), quote!()),
104 };
105
106 quote! {
107 #[cortex_m_rt::entry]
108 fn main() -> ! {
109 #hal_setup
110
111 let mut executor = #embassy_path::executor::Executor::new();
112 let executor = unsafe { __make_static(&mut executor) };
113
114 executor.run(|spawner| {
115 spawner.must_spawn(__embassy_main(spawner, #peris_arg));
116 })
117 }
118 }
119 };
120
121 let result = quote! {
122 #[#embassy_path::task(embassy_prefix = #embassy_prefix_lit)]
123 async fn __embassy_main(#fargs) {
124 #f_body
125 }
126
127 unsafe fn __make_static<T>(t: &mut T) -> &'static mut T {
128 ::core::mem::transmute(t)
129 }
130
131 #main
132 };
133
134 Ok(result)
135}
diff --git a/embassy-macros/src/macros/mod.rs b/embassy-macros/src/macros/mod.rs
new file mode 100644
index 000000000..4350f229f
--- /dev/null
+++ b/embassy-macros/src/macros/mod.rs
@@ -0,0 +1,5 @@
1pub mod interrupt;
2pub mod interrupt_declare;
3pub mod interrupt_take;
4pub mod main;
5pub mod task;
diff --git a/embassy-macros/src/macros/task.rs b/embassy-macros/src/macros/task.rs
new file mode 100644
index 000000000..f0c78c596
--- /dev/null
+++ b/embassy-macros/src/macros/task.rs
@@ -0,0 +1,90 @@
1use darling::FromMeta;
2use proc_macro2::TokenStream;
3use quote::{format_ident, quote};
4
5use crate::util::ctxt::Ctxt;
6use crate::util::path::ModulePrefix;
7
8#[derive(Debug, FromMeta)]
9struct Args {
10 #[darling(default)]
11 pool_size: Option<usize>,
12 #[darling(default)]
13 send: bool,
14 #[darling(default)]
15 embassy_prefix: ModulePrefix,
16}
17
18pub fn run(args: syn::AttributeArgs, mut f: syn::ItemFn) -> Result<TokenStream, TokenStream> {
19 let args = Args::from_list(&args).map_err(|e| e.write_errors())?;
20
21 let embassy_prefix = args.embassy_prefix.append("embassy");
22 let embassy_path = embassy_prefix.path();
23
24 let pool_size: usize = args.pool_size.unwrap_or(1);
25
26 let ctxt = Ctxt::new();
27
28 if f.sig.asyncness.is_none() {
29 ctxt.error_spanned_by(&f.sig, "task functions must be async");
30 }
31 if !f.sig.generics.params.is_empty() {
32 ctxt.error_spanned_by(&f.sig, "task functions must not be generic");
33 }
34 if pool_size < 1 {
35 ctxt.error_spanned_by(&f.sig, "pool_size must be 1 or greater");
36 }
37
38 let mut arg_names: syn::punctuated::Punctuated<syn::Ident, syn::Token![,]> =
39 syn::punctuated::Punctuated::new();
40 let mut fargs = f.sig.inputs.clone();
41
42 for arg in fargs.iter_mut() {
43 match arg {
44 syn::FnArg::Receiver(_) => {
45 ctxt.error_spanned_by(arg, "task functions must not have receiver arguments");
46 }
47 syn::FnArg::Typed(t) => match t.pat.as_mut() {
48 syn::Pat::Ident(i) => {
49 arg_names.push(i.ident.clone());
50 i.mutability = None;
51 }
52 _ => {
53 ctxt.error_spanned_by(
54 arg,
55 "pattern matching in task arguments is not yet supporteds",
56 );
57 }
58 },
59 }
60 }
61
62 ctxt.check()?;
63
64 let name = f.sig.ident.clone();
65
66 let visibility = &f.vis;
67 f.sig.ident = format_ident!("task");
68 let impl_ty = if args.send {
69 quote!(impl ::core::future::Future + Send + 'static)
70 } else {
71 quote!(impl ::core::future::Future + 'static)
72 };
73
74 let attrs = &f.attrs;
75
76 let result = quote! {
77 #(#attrs)*
78 #visibility fn #name(#fargs) -> #embassy_path::executor::SpawnToken<#impl_ty> {
79 use #embassy_path::executor::raw::TaskStorage;
80 #f
81 type F = #impl_ty;
82 #[allow(clippy::declare_interior_mutable_const)]
83 const NEW_TASK: TaskStorage<F> = TaskStorage::new();
84 static POOL: [TaskStorage<F>; #pool_size] = [NEW_TASK; #pool_size];
85 unsafe { TaskStorage::spawn_pool(&POOL, move || task(#arg_names)) }
86 }
87 };
88
89 Ok(result)
90}
diff --git a/embassy-macros/src/util/ctxt.rs b/embassy-macros/src/util/ctxt.rs
new file mode 100644
index 000000000..d668ae780
--- /dev/null
+++ b/embassy-macros/src/util/ctxt.rs
@@ -0,0 +1,72 @@
1// nifty utility borrowed from serde :)
2// https://github.com/serde-rs/serde/blob/master/serde_derive/src/internals/ctxt.rs
3
4use proc_macro2::TokenStream;
5use quote::{quote, ToTokens};
6use std::cell::RefCell;
7use std::fmt::Display;
8use std::thread;
9use syn;
10
11/// A type to collect errors together and format them.
12///
13/// Dropping this object will cause a panic. It must be consumed using `check`.
14///
15/// References can be shared since this type uses run-time exclusive mut checking.
16#[derive(Default)]
17pub struct Ctxt {
18 // The contents will be set to `None` during checking. This is so that checking can be
19 // enforced.
20 errors: RefCell<Option<Vec<syn::Error>>>,
21}
22
23impl Ctxt {
24 /// Create a new context object.
25 ///
26 /// This object contains no errors, but will still trigger a panic if it is not `check`ed.
27 pub fn new() -> Self {
28 Ctxt {
29 errors: RefCell::new(Some(Vec::new())),
30 }
31 }
32
33 /// Add an error to the context object with a tokenenizable object.
34 ///
35 /// The object is used for spanning in error messages.
36 pub fn error_spanned_by<A: ToTokens, T: Display>(&self, obj: A, msg: T) {
37 self.errors
38 .borrow_mut()
39 .as_mut()
40 .unwrap()
41 // Curb monomorphization from generating too many identical methods.
42 .push(syn::Error::new_spanned(obj.into_token_stream(), msg));
43 }
44
45 /// Add one of Syn's parse errors.
46 #[allow(unused)]
47 pub fn syn_error(&self, err: syn::Error) {
48 self.errors.borrow_mut().as_mut().unwrap().push(err);
49 }
50
51 /// Consume this object, producing a formatted error string if there are errors.
52 pub fn check(self) -> Result<(), TokenStream> {
53 let errors = self.errors.borrow_mut().take().unwrap();
54 match errors.len() {
55 0 => Ok(()),
56 _ => Err(to_compile_errors(errors)),
57 }
58 }
59}
60
61fn to_compile_errors(errors: Vec<syn::Error>) -> proc_macro2::TokenStream {
62 let compile_errors = errors.iter().map(syn::Error::to_compile_error);
63 quote!(#(#compile_errors)*)
64}
65
66impl Drop for Ctxt {
67 fn drop(&mut self) {
68 if !thread::panicking() && self.errors.borrow().is_some() {
69 panic!("forgot to check for errors");
70 }
71 }
72}
diff --git a/embassy-macros/src/util/mod.rs b/embassy-macros/src/util/mod.rs
new file mode 100644
index 000000000..c2f2dfd65
--- /dev/null
+++ b/embassy-macros/src/util/mod.rs
@@ -0,0 +1,2 @@
1pub mod ctxt;
2pub mod path;
diff --git a/embassy-macros/src/path.rs b/embassy-macros/src/util/path.rs
index 00fca7bdb..00fca7bdb 100644
--- a/embassy-macros/src/path.rs
+++ b/embassy-macros/src/util/path.rs
diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml
index 4ed922ba9..5ced9b1b2 100644
--- a/embassy-nrf/Cargo.toml
+++ b/embassy-nrf/Cargo.toml
@@ -6,14 +6,18 @@ edition = "2018"
6 6
7[features] 7[features]
8 8
9# Enable nightly-only features
10nightly = ["embassy/nightly", "embedded-hal-1", "embedded-hal-async"]
11
9# Reexport the PAC for the currently enabled chip at `embassy_nrf::pac`. 12# Reexport the PAC for the currently enabled chip at `embassy_nrf::pac`.
10# This is unstable because semver-minor (non-breaking) releases of embassy-nrf may major-bump (breaking) the PAC version. 13# This is unstable because semver-minor (non-breaking) releases of embassy-nrf may major-bump (breaking) the PAC version.
11# If this is an issue for you, you're encouraged to directly depend on a fixed version of the PAC. 14# If this is an issue for you, you're encouraged to directly depend on a fixed version of the PAC.
12# There are no plans to make this stable. 15# There are no plans to make this stable.
13unstable-pac = [] 16unstable-pac = []
14 17
15# Implement embedded-hal 1.0 alpha and embedded-hal-async traits. 18# Implement embedded-hal 1.0 alpha traits.
16unstable-traits = ["embedded-hal-1", "embedded-hal-async"] 19# Implement embedded-hal-async traits if `nightly` is set as well.
20unstable-traits = ["embedded-hal-1"]
17 21
18nrf52805 = ["nrf52805-pac", "_ppi"] 22nrf52805 = ["nrf52805-pac", "_ppi"]
19nrf52810 = ["nrf52810-pac", "_ppi"] 23nrf52810 = ["nrf52810-pac", "_ppi"]
diff --git a/embassy-nrf/src/gpiote.rs b/embassy-nrf/src/gpiote.rs
index a4c24058c..b856c2dfe 100644
--- a/embassy-nrf/src/gpiote.rs
+++ b/embassy-nrf/src/gpiote.rs
@@ -463,7 +463,6 @@ mod eh02 {
463#[cfg(feature = "unstable-traits")] 463#[cfg(feature = "unstable-traits")]
464mod eh1 { 464mod eh1 {
465 use super::*; 465 use super::*;
466 use futures::FutureExt;
467 466
468 impl<'d, C: Channel, T: GpioPin> embedded_hal_1::digital::ErrorType for InputChannel<'d, C, T> { 467 impl<'d, C: Channel, T: GpioPin> embedded_hal_1::digital::ErrorType for InputChannel<'d, C, T> {
469 type Error = Infallible; 468 type Error = Infallible;
@@ -480,6 +479,12 @@ mod eh1 {
480 self.pin.is_low() 479 self.pin.is_low()
481 } 480 }
482 } 481 }
482}
483
484#[cfg(all(feature = "unstable-traits", feature = "nightly"))]
485mod eh1a {
486 use super::*;
487 use futures::FutureExt;
483 488
484 impl<'d, T: GpioPin> embedded_hal_async::digital::Wait for Input<'d, T> { 489 impl<'d, T: GpioPin> embedded_hal_async::digital::Wait for Input<'d, T> {
485 type WaitForHighFuture<'a> 490 type WaitForHighFuture<'a>
diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs
index 8e05d9b6a..b448f6ab6 100644
--- a/embassy-nrf/src/lib.rs
+++ b/embassy-nrf/src/lib.rs
@@ -1,6 +1,8 @@
1#![no_std] 1#![no_std]
2#![feature(generic_associated_types)] 2#![cfg_attr(
3#![feature(type_alias_impl_trait)] 3 feature = "nightly",
4 feature(generic_associated_types, type_alias_impl_trait)
5)]
4 6
5#[cfg(not(any( 7#[cfg(not(any(
6 feature = "nrf51", 8 feature = "nrf51",
diff --git a/embassy-nrf/src/spim.rs b/embassy-nrf/src/spim.rs
index 976a546ce..a45b9390d 100644
--- a/embassy-nrf/src/spim.rs
+++ b/embassy-nrf/src/spim.rs
@@ -374,7 +374,6 @@ mod eh02 {
374#[cfg(feature = "unstable-traits")] 374#[cfg(feature = "unstable-traits")]
375mod eh1 { 375mod eh1 {
376 use super::*; 376 use super::*;
377 use core::future::Future;
378 377
379 impl embedded_hal_1::spi::Error for Error { 378 impl embedded_hal_1::spi::Error for Error {
380 fn kind(&self) -> embedded_hal_1::spi::ErrorKind { 379 fn kind(&self) -> embedded_hal_1::spi::ErrorKind {
@@ -437,7 +436,7 @@ mod eh1 {
437 436
438 fn transaction<'a>( 437 fn transaction<'a>(
439 &mut self, 438 &mut self,
440 operations: &mut [embedded_hal_async::spi::Operation<'a, u8>], 439 operations: &mut [embedded_hal_1::spi::blocking::Operation<'a, u8>],
441 ) -> Result<(), Self::Error> { 440 ) -> Result<(), Self::Error> {
442 use embedded_hal_1::spi::blocking::Operation; 441 use embedded_hal_1::spi::blocking::Operation;
443 for o in operations { 442 for o in operations {
@@ -451,6 +450,12 @@ mod eh1 {
451 Ok(()) 450 Ok(())
452 } 451 }
453 } 452 }
453}
454
455#[cfg(all(feature = "unstable-traits", feature = "nightly"))]
456mod eh1a {
457 use super::*;
458 use core::future::Future;
454 459
455 impl<'d, T: Instance> embedded_hal_async::spi::Read<u8> for Spim<'d, T> { 460 impl<'d, T: Instance> embedded_hal_async::spi::Read<u8> for Spim<'d, T> {
456 type ReadFuture<'a> 461 type ReadFuture<'a>
diff --git a/embassy-nrf/src/time_driver.rs b/embassy-nrf/src/time_driver.rs
index 19356c2d2..4240b9ac4 100644
--- a/embassy-nrf/src/time_driver.rs
+++ b/embassy-nrf/src/time_driver.rs
@@ -2,6 +2,7 @@ use core::cell::Cell;
2use core::sync::atomic::{compiler_fence, AtomicU32, AtomicU8, Ordering}; 2use core::sync::atomic::{compiler_fence, AtomicU32, AtomicU8, Ordering};
3use core::{mem, ptr}; 3use core::{mem, ptr};
4use critical_section::CriticalSection; 4use critical_section::CriticalSection;
5use embassy::blocking_mutex::raw::CriticalSectionRawMutex;
5use embassy::blocking_mutex::CriticalSectionMutex as Mutex; 6use embassy::blocking_mutex::CriticalSectionMutex as Mutex;
6use embassy::interrupt::{Interrupt, InterruptExt}; 7use embassy::interrupt::{Interrupt, InterruptExt};
7use embassy::time::driver::{AlarmHandle, Driver}; 8use embassy::time::driver::{AlarmHandle, Driver};
@@ -94,7 +95,7 @@ const ALARM_STATE_NEW: AlarmState = AlarmState::new();
94embassy::time_driver_impl!(static DRIVER: RtcDriver = RtcDriver { 95embassy::time_driver_impl!(static DRIVER: RtcDriver = RtcDriver {
95 period: AtomicU32::new(0), 96 period: AtomicU32::new(0),
96 alarm_count: AtomicU8::new(0), 97 alarm_count: AtomicU8::new(0),
97 alarms: Mutex::new([ALARM_STATE_NEW; ALARM_COUNT]), 98 alarms: Mutex::const_new(CriticalSectionRawMutex::new(), [ALARM_STATE_NEW; ALARM_COUNT]),
98}); 99});
99 100
100impl RtcDriver { 101impl RtcDriver {
diff --git a/embassy-nrf/src/twim.rs b/embassy-nrf/src/twim.rs
index 4cd47c897..ed2844f79 100644
--- a/embassy-nrf/src/twim.rs
+++ b/embassy-nrf/src/twim.rs
@@ -679,7 +679,7 @@ mod eh1 {
679 fn transaction<'a>( 679 fn transaction<'a>(
680 &mut self, 680 &mut self,
681 _address: u8, 681 _address: u8,
682 _operations: &mut [embedded_hal_async::i2c::Operation<'a>], 682 _operations: &mut [embedded_hal_1::i2c::blocking::Operation<'a>],
683 ) -> Result<(), Self::Error> { 683 ) -> Result<(), Self::Error> {
684 todo!(); 684 todo!();
685 } 685 }
@@ -690,58 +690,59 @@ mod eh1 {
690 _operations: O, 690 _operations: O,
691 ) -> Result<(), Self::Error> 691 ) -> Result<(), Self::Error>
692 where 692 where
693 O: IntoIterator<Item = embedded_hal_async::i2c::Operation<'a>>, 693 O: IntoIterator<Item = embedded_hal_1::i2c::blocking::Operation<'a>>,
694 { 694 {
695 todo!(); 695 todo!();
696 } 696 }
697 } 697 }
698}
698 699
699 impl<'d, T: Instance> embedded_hal_async::i2c::I2c for Twim<'d, T> { 700#[cfg(all(feature = "unstable-traits", feature = "nightly"))]
700 type ReadFuture<'a> 701impl<'d, T: Instance> embedded_hal_async::i2c::I2c for Twim<'d, T> {
701 where 702 type ReadFuture<'a>
702 Self: 'a, 703 where
703 = impl Future<Output = Result<(), Self::Error>> + 'a; 704 Self: 'a,
705 = impl Future<Output = Result<(), Self::Error>> + 'a;
704 706
705 fn read<'a>(&'a mut self, address: u8, buffer: &'a mut [u8]) -> Self::ReadFuture<'a> { 707 fn read<'a>(&'a mut self, address: u8, buffer: &'a mut [u8]) -> Self::ReadFuture<'a> {
706 self.read(address, buffer) 708 self.read(address, buffer)
707 } 709 }
708 710
709 type WriteFuture<'a> 711 type WriteFuture<'a>
710 where 712 where
711 Self: 'a, 713 Self: 'a,
712 = impl Future<Output = Result<(), Self::Error>> + 'a; 714 = impl Future<Output = Result<(), Self::Error>> + 'a;
713 715
714 fn write<'a>(&'a mut self, address: u8, bytes: &'a [u8]) -> Self::WriteFuture<'a> { 716 fn write<'a>(&'a mut self, address: u8, bytes: &'a [u8]) -> Self::WriteFuture<'a> {
715 self.write(address, bytes) 717 self.write(address, bytes)
716 } 718 }
717 719
718 type WriteReadFuture<'a> 720 type WriteReadFuture<'a>
719 where 721 where
720 Self: 'a, 722 Self: 'a,
721 = impl Future<Output = Result<(), Self::Error>> + 'a; 723 = impl Future<Output = Result<(), Self::Error>> + 'a;
722 724
723 fn write_read<'a>( 725 fn write_read<'a>(
724 &'a mut self, 726 &'a mut self,
725 address: u8, 727 address: u8,
726 wr_buffer: &'a [u8], 728 wr_buffer: &'a [u8],
727 rd_buffer: &'a mut [u8], 729 rd_buffer: &'a mut [u8],
728 ) -> Self::WriteReadFuture<'a> { 730 ) -> Self::WriteReadFuture<'a> {
729 self.write_read(address, wr_buffer, rd_buffer) 731 self.write_read(address, wr_buffer, rd_buffer)
730 } 732 }
731 733
732 type TransactionFuture<'a> 734 type TransactionFuture<'a>
733 where 735 where
734 Self: 'a, 736 Self: 'a,
735 = impl Future<Output = Result<(), Self::Error>> + 'a; 737 = impl Future<Output = Result<(), Self::Error>> + 'a;
736 738
737 fn transaction<'a>( 739 fn transaction<'a>(
738 &'a mut self, 740 &'a mut self,
739 address: u8, 741 address: u8,
740 operations: &mut [embedded_hal_async::i2c::Operation<'a>], 742 operations: &mut [embedded_hal_async::i2c::Operation<'a>],
741 ) -> Self::TransactionFuture<'a> { 743 ) -> Self::TransactionFuture<'a> {
742 let _ = address; 744 let _ = address;
743 let _ = operations; 745 let _ = operations;
744 async move { todo!() } 746 async move { todo!() }
745 }
746 } 747 }
747} 748}
diff --git a/embassy-nrf/src/uarte.rs b/embassy-nrf/src/uarte.rs
index a1c47cff5..119a17981 100644
--- a/embassy-nrf/src/uarte.rs
+++ b/embassy-nrf/src/uarte.rs
@@ -844,7 +844,6 @@ mod eh02 {
844#[cfg(feature = "unstable-traits")] 844#[cfg(feature = "unstable-traits")]
845mod eh1 { 845mod eh1 {
846 use super::*; 846 use super::*;
847 use core::future::Future;
848 847
849 impl embedded_hal_1::serial::Error for Error { 848 impl embedded_hal_1::serial::Error for Error {
850 fn kind(&self) -> embedded_hal_1::serial::ErrorKind { 849 fn kind(&self) -> embedded_hal_1::serial::ErrorKind {
@@ -872,6 +871,36 @@ mod eh1 {
872 } 871 }
873 } 872 }
874 873
874 impl<'d, T: Instance> embedded_hal_1::serial::ErrorType for UarteTx<'d, T> {
875 type Error = Error;
876 }
877
878 impl<'d, T: Instance> embedded_hal_1::serial::blocking::Write for UarteTx<'d, T> {
879 fn write(&mut self, buffer: &[u8]) -> Result<(), Self::Error> {
880 self.blocking_write(buffer)
881 }
882
883 fn flush(&mut self) -> Result<(), Self::Error> {
884 Ok(())
885 }
886 }
887
888 impl<'d, T: Instance> embedded_hal_1::serial::ErrorType for UarteRx<'d, T> {
889 type Error = Error;
890 }
891
892 impl<'d, U: Instance, T: TimerInstance> embedded_hal_1::serial::ErrorType
893 for UarteWithIdle<'d, U, T>
894 {
895 type Error = Error;
896 }
897}
898
899#[cfg(all(feature = "unstable-traits", feature = "nightly"))]
900mod eh1a {
901 use super::*;
902 use core::future::Future;
903
875 impl<'d, T: Instance> embedded_hal_async::serial::Read for Uarte<'d, T> { 904 impl<'d, T: Instance> embedded_hal_async::serial::Read for Uarte<'d, T> {
876 type ReadFuture<'a> 905 type ReadFuture<'a>
877 where 906 where
@@ -903,22 +932,6 @@ mod eh1 {
903 } 932 }
904 } 933 }
905 934
906 // =====================
907
908 impl<'d, T: Instance> embedded_hal_1::serial::ErrorType for UarteTx<'d, T> {
909 type Error = Error;
910 }
911
912 impl<'d, T: Instance> embedded_hal_1::serial::blocking::Write for UarteTx<'d, T> {
913 fn write(&mut self, buffer: &[u8]) -> Result<(), Self::Error> {
914 self.blocking_write(buffer)
915 }
916
917 fn flush(&mut self) -> Result<(), Self::Error> {
918 Ok(())
919 }
920 }
921
922 impl<'d, T: Instance> embedded_hal_async::serial::Write for UarteTx<'d, T> { 935 impl<'d, T: Instance> embedded_hal_async::serial::Write for UarteTx<'d, T> {
923 type WriteFuture<'a> 936 type WriteFuture<'a>
924 where 937 where
@@ -939,12 +952,6 @@ mod eh1 {
939 } 952 }
940 } 953 }
941 954
942 // =====================
943
944 impl<'d, T: Instance> embedded_hal_1::serial::ErrorType for UarteRx<'d, T> {
945 type Error = Error;
946 }
947
948 impl<'d, T: Instance> embedded_hal_async::serial::Read for UarteRx<'d, T> { 955 impl<'d, T: Instance> embedded_hal_async::serial::Read for UarteRx<'d, T> {
949 type ReadFuture<'a> 956 type ReadFuture<'a>
950 where 957 where
@@ -956,14 +963,6 @@ mod eh1 {
956 } 963 }
957 } 964 }
958 965
959 // =====================
960
961 impl<'d, U: Instance, T: TimerInstance> embedded_hal_1::serial::ErrorType
962 for UarteWithIdle<'d, U, T>
963 {
964 type Error = Error;
965 }
966
967 impl<'d, U: Instance, T: TimerInstance> embedded_hal_async::serial::Read 966 impl<'d, U: Instance, T: TimerInstance> embedded_hal_async::serial::Read
968 for UarteWithIdle<'d, U, T> 967 for UarteWithIdle<'d, U, T>
969 { 968 {
diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml
index be41f95eb..cb6544028 100644
--- a/embassy-rp/Cargo.toml
+++ b/embassy-rp/Cargo.toml
@@ -13,7 +13,7 @@ edition = "2018"
13unstable-pac = [] 13unstable-pac = []
14 14
15[dependencies] 15[dependencies]
16embassy = { version = "0.1.0", path = "../embassy", features = [ "time-tick-1mhz" ] } 16embassy = { version = "0.1.0", path = "../embassy", features = [ "time-tick-1mhz", "nightly"] }
17embassy-hal-common = {version = "0.1.0", path = "../embassy-hal-common" } 17embassy-hal-common = {version = "0.1.0", path = "../embassy-hal-common" }
18embassy-macros = { version = "0.1.0", path = "../embassy-macros", features = ["rp"]} 18embassy-macros = { version = "0.1.0", path = "../embassy-macros", features = ["rp"]}
19atomic-polyfill = "0.1.5" 19atomic-polyfill = "0.1.5"
diff --git a/embassy-rp/src/timer.rs b/embassy-rp/src/timer.rs
index b3c047ca4..f449df000 100644
--- a/embassy-rp/src/timer.rs
+++ b/embassy-rp/src/timer.rs
@@ -1,7 +1,8 @@
1use atomic_polyfill::{AtomicU8, Ordering}; 1use atomic_polyfill::{AtomicU8, Ordering};
2use core::cell::Cell; 2use core::cell::Cell;
3use critical_section::CriticalSection; 3use critical_section::CriticalSection;
4use embassy::blocking_mutex::CriticalSectionMutex as Mutex; 4use embassy::blocking_mutex::raw::CriticalSectionRawMutex;
5use embassy::blocking_mutex::Mutex;
5use embassy::interrupt::{Interrupt, InterruptExt}; 6use embassy::interrupt::{Interrupt, InterruptExt};
6use embassy::time::driver::{AlarmHandle, Driver}; 7use embassy::time::driver::{AlarmHandle, Driver};
7 8
@@ -20,12 +21,12 @@ const DUMMY_ALARM: AlarmState = AlarmState {
20}; 21};
21 22
22struct TimerDriver { 23struct TimerDriver {
23 alarms: Mutex<[AlarmState; ALARM_COUNT]>, 24 alarms: Mutex<CriticalSectionRawMutex, [AlarmState; ALARM_COUNT]>,
24 next_alarm: AtomicU8, 25 next_alarm: AtomicU8,
25} 26}
26 27
27embassy::time_driver_impl!(static DRIVER: TimerDriver = TimerDriver{ 28embassy::time_driver_impl!(static DRIVER: TimerDriver = TimerDriver{
28 alarms: Mutex::new([DUMMY_ALARM; ALARM_COUNT]), 29 alarms: Mutex::const_new(CriticalSectionRawMutex::new(), [DUMMY_ALARM; ALARM_COUNT]),
29 next_alarm: AtomicU8::new(0), 30 next_alarm: AtomicU8::new(0),
30}); 31});
31 32
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml
index 386722d47..55a646d4a 100644
--- a/embassy-stm32/Cargo.toml
+++ b/embassy-stm32/Cargo.toml
@@ -6,7 +6,7 @@ edition = "2018"
6resolver = "2" 6resolver = "2"
7 7
8[dependencies] 8[dependencies]
9embassy = { version = "0.1.0", path = "../embassy" } 9embassy = { version = "0.1.0", path = "../embassy", features = ["nightly"]}
10embassy-macros = { version = "0.1.0", path = "../embassy-macros", features = ["stm32"] } 10embassy-macros = { version = "0.1.0", path = "../embassy-macros", features = ["stm32"] }
11embassy-hal-common = {version = "0.1.0", path = "../embassy-hal-common" } 11embassy-hal-common = {version = "0.1.0", path = "../embassy-hal-common" }
12embassy-net = { version = "0.1.0", path = "../embassy-net", default-features = false, optional = true } 12embassy-net = { version = "0.1.0", path = "../embassy-net", default-features = false, optional = true }
diff --git a/embassy-stm32/src/time_driver.rs b/embassy-stm32/src/time_driver.rs
index d1596c5f8..7efe0d3a5 100644
--- a/embassy-stm32/src/time_driver.rs
+++ b/embassy-stm32/src/time_driver.rs
@@ -3,13 +3,15 @@ use core::cell::Cell;
3use core::convert::TryInto; 3use core::convert::TryInto;
4use core::sync::atomic::{compiler_fence, Ordering}; 4use core::sync::atomic::{compiler_fence, Ordering};
5use core::{mem, ptr}; 5use core::{mem, ptr};
6use embassy::blocking_mutex::raw::CriticalSectionRawMutex;
7use embassy::blocking_mutex::Mutex;
6use embassy::interrupt::InterruptExt; 8use embassy::interrupt::InterruptExt;
7use embassy::time::driver::{AlarmHandle, Driver}; 9use embassy::time::driver::{AlarmHandle, Driver};
8use embassy::time::TICKS_PER_SECOND; 10use embassy::time::TICKS_PER_SECOND;
9use stm32_metapac::timer::regs; 11use stm32_metapac::timer::regs;
10 12
11use crate::interrupt; 13use crate::interrupt;
12use crate::interrupt::{CriticalSection, Interrupt, Mutex}; 14use crate::interrupt::{CriticalSection, Interrupt};
13use crate::pac::timer::{vals, TimGp16}; 15use crate::pac::timer::{vals, TimGp16};
14use crate::peripherals; 16use crate::peripherals;
15use crate::rcc::sealed::RccPeripheral; 17use crate::rcc::sealed::RccPeripheral;
@@ -95,7 +97,7 @@ struct RtcDriver {
95 period: AtomicU32, 97 period: AtomicU32,
96 alarm_count: AtomicU8, 98 alarm_count: AtomicU8,
97 /// Timestamp at which to fire alarm. u64::MAX if no alarm is scheduled. 99 /// Timestamp at which to fire alarm. u64::MAX if no alarm is scheduled.
98 alarms: Mutex<[AlarmState; ALARM_COUNT]>, 100 alarms: Mutex<CriticalSectionRawMutex, [AlarmState; ALARM_COUNT]>,
99} 101}
100 102
101const ALARM_STATE_NEW: AlarmState = AlarmState::new(); 103const ALARM_STATE_NEW: AlarmState = AlarmState::new();
@@ -103,7 +105,7 @@ const ALARM_STATE_NEW: AlarmState = AlarmState::new();
103embassy::time_driver_impl!(static DRIVER: RtcDriver = RtcDriver { 105embassy::time_driver_impl!(static DRIVER: RtcDriver = RtcDriver {
104 period: AtomicU32::new(0), 106 period: AtomicU32::new(0),
105 alarm_count: AtomicU8::new(0), 107 alarm_count: AtomicU8::new(0),
106 alarms: Mutex::new([ALARM_STATE_NEW; ALARM_COUNT]), 108 alarms: Mutex::const_new(CriticalSectionRawMutex::new(), [ALARM_STATE_NEW; ALARM_COUNT]),
107}); 109});
108 110
109impl RtcDriver { 111impl RtcDriver {
diff --git a/embassy/Cargo.toml b/embassy/Cargo.toml
index ccb5574d7..d10a8874e 100644
--- a/embassy/Cargo.toml
+++ b/embassy/Cargo.toml
@@ -10,8 +10,12 @@ default = []
10std = ["futures/std", "time", "time-tick-1mhz", "embassy-macros/std"] 10std = ["futures/std", "time", "time-tick-1mhz", "embassy-macros/std"]
11wasm = ["wasm-bindgen", "js-sys", "embassy-macros/wasm", "wasm-timer", "time", "time-tick-1mhz"] 11wasm = ["wasm-bindgen", "js-sys", "embassy-macros/wasm", "wasm-timer", "time", "time-tick-1mhz"]
12 12
13# Enable nightly-only features
14nightly = ["embedded-hal-async"]
15
13# Implement embedded-hal 1.0 alpha and embedded-hal-async traits. 16# Implement embedded-hal 1.0 alpha and embedded-hal-async traits.
14unstable-traits = ["embedded-hal-1", "embedded-hal-async"] 17# Implement embedded-hal-async traits if `nightly` is set as well.
18unstable-traits = ["embedded-hal-1"]
15 19
16# Enable `embassy::time` module. 20# Enable `embassy::time` module.
17# NOTE: This feature is only intended to be enabled by crates providing the time driver implementation. 21# NOTE: This feature is only intended to be enabled by crates providing the time driver implementation.
diff --git a/embassy/src/blocking_mutex/kind.rs b/embassy/src/blocking_mutex/kind.rs
deleted file mode 100644
index a4a45605f..000000000
--- a/embassy/src/blocking_mutex/kind.rs
+++ /dev/null
@@ -1,20 +0,0 @@
1pub trait MutexKind {
2 type Mutex<T>: super::Mutex<Data = T>;
3}
4
5pub enum CriticalSection {}
6impl MutexKind for CriticalSection {
7 type Mutex<T> = super::CriticalSectionMutex<T>;
8}
9
10#[cfg(any(cortex_m, feature = "std"))]
11pub enum ThreadMode {}
12#[cfg(any(cortex_m, feature = "std"))]
13impl MutexKind for ThreadMode {
14 type Mutex<T> = super::ThreadModeMutex<T>;
15}
16
17pub enum Noop {}
18impl MutexKind for Noop {
19 type Mutex<T> = super::NoopMutex<T>;
20}
diff --git a/embassy/src/blocking_mutex/mod.rs b/embassy/src/blocking_mutex/mod.rs
index 949531392..859eca075 100644
--- a/embassy/src/blocking_mutex/mod.rs
+++ b/embassy/src/blocking_mutex/mod.rs
@@ -1,67 +1,107 @@
1//! Blocking mutex (not async) 1//! Blocking mutex (not async)
2 2
3pub mod kind; 3pub mod raw;
4 4
5use self::raw::RawMutex;
5use core::cell::UnsafeCell; 6use core::cell::UnsafeCell;
6use critical_section::CriticalSection;
7 7
8/// Any object implementing this trait guarantees exclusive access to the data contained 8/// Any object implementing this trait guarantees exclusive access to the data contained
9/// within the mutex for the duration of the lock. 9/// within the mutex for the duration of the lock.
10/// Adapted from <https://github.com/rust-embedded/mutex-trait>. 10/// Adapted from <https://github.com/rust-embedded/mutex-trait>.
11pub trait Mutex { 11pub struct Mutex<R, T: ?Sized> {
12 /// Data protected by the mutex. 12 // NOTE: `raw` must be FIRST, so when using ThreadModeMutex the "can't drop in non-thread-mode" gets
13 type Data; 13 // to run BEFORE dropping `data`.
14 raw: R,
15 data: UnsafeCell<T>,
16}
14 17
15 fn new(data: Self::Data) -> Self; 18unsafe impl<R: RawMutex + Send, T: ?Sized + Send> Send for Mutex<R, T> {}
19unsafe impl<R: RawMutex + Sync, T: ?Sized + Send> Sync for Mutex<R, T> {}
20
21impl<R: RawMutex, T> Mutex<R, T> {
22 /// Creates a new mutex in an unlocked state ready for use.
23 #[cfg(feature = "nightly")]
24 #[inline]
25 pub const fn new(val: T) -> Mutex<R, T> {
26 Mutex {
27 raw: R::INIT,
28 data: UnsafeCell::new(val),
29 }
30 }
16 31
17 /// Creates a critical section and grants temporary access to the protected data. 32 /// Creates a new mutex in an unlocked state ready for use.
18 fn lock<R>(&self, f: impl FnOnce(&Self::Data) -> R) -> R; 33 #[cfg(not(feature = "nightly"))]
19} 34 #[inline]
35 pub fn new(val: T) -> Mutex<R, T> {
36 Mutex {
37 raw: R::INIT,
38 data: UnsafeCell::new(val),
39 }
40 }
20 41
21/// A "mutex" based on critical sections 42 /// Creates a critical section and grants temporary access to the protected data.
22/// 43 pub fn lock<U>(&self, f: impl FnOnce(&T) -> U) -> U {
23/// # Safety 44 self.raw.lock(|| {
24/// 45 let ptr = self.data.get() as *const T;
25/// **This Mutex is only safe on single-core systems.** 46 let inner = unsafe { &*ptr };
26/// 47 f(inner)
27/// On multi-core systems, a `CriticalSection` **is not sufficient** to ensure exclusive access. 48 })
28pub struct CriticalSectionMutex<T> { 49 }
29 inner: UnsafeCell<T>,
30} 50}
31 51
32// NOTE: A `CriticalSectionMutex` can be used as a channel so the protected data must be `Send` 52impl<R, T> Mutex<R, T> {
33// to prevent sending non-Sendable stuff (e.g. access tokens) across different 53 /// Creates a new mutex based on a pre-existing raw mutex.
34// execution contexts (e.g. interrupts) 54 ///
35unsafe impl<T> Sync for CriticalSectionMutex<T> where T: Send {} 55 /// This allows creating a mutex in a constant context on stable Rust.
36 56 #[inline]
37impl<T> CriticalSectionMutex<T> { 57 pub const fn const_new(raw_mutex: R, val: T) -> Mutex<R, T> {
38 /// Creates a new mutex 58 Mutex {
39 pub const fn new(value: T) -> Self { 59 raw: raw_mutex,
40 CriticalSectionMutex { 60 data: UnsafeCell::new(val),
41 inner: UnsafeCell::new(value),
42 } 61 }
43 } 62 }
44}
45 63
46impl<T> CriticalSectionMutex<T> { 64 /// Consumes this mutex, returning the underlying data.
47 /// Borrows the data for the duration of the critical section 65 #[inline]
48 pub fn borrow<'cs>(&'cs self, _cs: CriticalSection<'cs>) -> &'cs T { 66 pub fn into_inner(self) -> T {
49 unsafe { &*self.inner.get() } 67 self.data.into_inner()
68 }
69
70 /// Returns a mutable reference to the underlying data.
71 ///
72 /// Since this call borrows the `Mutex` mutably, no actual locking needs to
73 /// take place---the mutable borrow statically guarantees no locks exist.
74 #[inline]
75 pub fn get_mut(&mut self) -> &mut T {
76 unsafe { &mut *self.data.get() }
50 } 77 }
51} 78}
52 79
53impl<T> Mutex for CriticalSectionMutex<T> { 80pub type CriticalSectionMutex<T> = Mutex<raw::CriticalSectionRawMutex, T>;
54 type Data = T; 81pub type NoopMutex<T> = Mutex<raw::NoopRawMutex, T>;
55 82
56 fn new(data: T) -> Self { 83impl<T> Mutex<raw::CriticalSectionRawMutex, T> {
57 Self::new(data) 84 /// Borrows the data for the duration of the critical section
85 pub fn borrow<'cs>(&'cs self, _cs: critical_section::CriticalSection<'cs>) -> &'cs T {
86 let ptr = self.data.get() as *const T;
87 unsafe { &*ptr }
58 } 88 }
89}
59 90
60 fn lock<R>(&self, f: impl FnOnce(&Self::Data) -> R) -> R { 91impl<T> Mutex<raw::NoopRawMutex, T> {
61 critical_section::with(|cs| f(self.borrow(cs))) 92 /// Borrows the data
93 pub fn borrow(&self) -> &T {
94 let ptr = self.data.get() as *const T;
95 unsafe { &*ptr }
62 } 96 }
63} 97}
64 98
99// ThreadModeMutex does NOT use the generic mutex from above because it's special:
100// it's Send+Sync even if T: !Send. There's no way to do that without specialization (I think?).
101//
102// There's still a ThreadModeRawMutex for use with the generic Mutex (handy with Channel, for example),
103// but that will require T: Send even though it shouldn't be needed.
104
65#[cfg(any(cortex_m, feature = "std"))] 105#[cfg(any(cortex_m, feature = "std"))]
66pub use thread_mode_mutex::*; 106pub use thread_mode_mutex::*;
67#[cfg(any(cortex_m, feature = "std"))] 107#[cfg(any(cortex_m, feature = "std"))]
@@ -75,15 +115,15 @@ mod thread_mode_mutex {
75 /// **This Mutex is only safe on single-core systems.** 115 /// **This Mutex is only safe on single-core systems.**
76 /// 116 ///
77 /// On multi-core systems, a `ThreadModeMutex` **is not sufficient** to ensure exclusive access. 117 /// On multi-core systems, a `ThreadModeMutex` **is not sufficient** to ensure exclusive access.
78 pub struct ThreadModeMutex<T> { 118 pub struct ThreadModeMutex<T: ?Sized> {
79 inner: UnsafeCell<T>, 119 inner: UnsafeCell<T>,
80 } 120 }
81 121
82 // NOTE: ThreadModeMutex only allows borrowing from one execution context ever: thread mode. 122 // NOTE: ThreadModeMutex only allows borrowing from one execution context ever: thread mode.
83 // Therefore it cannot be used to send non-sendable stuff between execution contexts, so it can 123 // Therefore it cannot be used to send non-sendable stuff between execution contexts, so it can
84 // be Send+Sync even if T is not Send (unlike CriticalSectionMutex) 124 // be Send+Sync even if T is not Send (unlike CriticalSectionMutex)
85 unsafe impl<T> Sync for ThreadModeMutex<T> {} 125 unsafe impl<T: ?Sized> Sync for ThreadModeMutex<T> {}
86 unsafe impl<T> Send for ThreadModeMutex<T> {} 126 unsafe impl<T: ?Sized> Send for ThreadModeMutex<T> {}
87 127
88 impl<T> ThreadModeMutex<T> { 128 impl<T> ThreadModeMutex<T> {
89 /// Creates a new mutex 129 /// Creates a new mutex
@@ -92,79 +132,35 @@ mod thread_mode_mutex {
92 inner: UnsafeCell::new(value), 132 inner: UnsafeCell::new(value),
93 } 133 }
94 } 134 }
135 }
136
137 impl<T: ?Sized> ThreadModeMutex<T> {
138 pub fn lock<R>(&self, f: impl FnOnce(&T) -> R) -> R {
139 f(self.borrow())
140 }
95 141
96 /// Borrows the data 142 /// Borrows the data
97 pub fn borrow(&self) -> &T { 143 pub fn borrow(&self) -> &T {
98 assert!( 144 assert!(
99 in_thread_mode(), 145 raw::in_thread_mode(),
100 "ThreadModeMutex can only be borrowed from thread mode." 146 "ThreadModeMutex can only be borrowed from thread mode."
101 ); 147 );
102 unsafe { &*self.inner.get() } 148 unsafe { &*self.inner.get() }
103 } 149 }
104 } 150 }
105 151
106 impl<T> Mutex for ThreadModeMutex<T> { 152 impl<T: ?Sized> Drop for ThreadModeMutex<T> {
107 type Data = T;
108
109 fn new(data: T) -> Self {
110 Self::new(data)
111 }
112
113 fn lock<R>(&self, f: impl FnOnce(&Self::Data) -> R) -> R {
114 f(self.borrow())
115 }
116 }
117
118 impl<T> Drop for ThreadModeMutex<T> {
119 fn drop(&mut self) { 153 fn drop(&mut self) {
120 // Only allow dropping from thread mode. Dropping calls drop on the inner `T`, so 154 // Only allow dropping from thread mode. Dropping calls drop on the inner `T`, so
121 // `drop` needs the same guarantees as `lock`. `ThreadModeMutex<T>` is Send even if 155 // `drop` needs the same guarantees as `lock`. `ThreadModeMutex<T>` is Send even if
122 // T isn't, so without this check a user could create a ThreadModeMutex in thread mode, 156 // T isn't, so without this check a user could create a ThreadModeMutex in thread mode,
123 // send it to interrupt context and drop it there, which would "send" a T even if T is not Send. 157 // send it to interrupt context and drop it there, which would "send" a T even if T is not Send.
124 assert!( 158 assert!(
125 in_thread_mode(), 159 raw::in_thread_mode(),
126 "ThreadModeMutex can only be dropped from thread mode." 160 "ThreadModeMutex can only be dropped from thread mode."
127 ); 161 );
128 162
129 // Drop of the inner `T` happens after this. 163 // Drop of the inner `T` happens after this.
130 } 164 }
131 } 165 }
132
133 pub fn in_thread_mode() -> bool {
134 #[cfg(feature = "std")]
135 return Some("main") == std::thread::current().name();
136
137 #[cfg(not(feature = "std"))]
138 return cortex_m::peripheral::SCB::vect_active()
139 == cortex_m::peripheral::scb::VectActive::ThreadMode;
140 }
141}
142
143/// A "mutex" that does nothing and cannot be shared between threads.
144pub struct NoopMutex<T> {
145 inner: T,
146}
147
148impl<T> NoopMutex<T> {
149 pub const fn new(value: T) -> Self {
150 NoopMutex { inner: value }
151 }
152}
153
154impl<T> NoopMutex<T> {
155 pub fn borrow(&self) -> &T {
156 &self.inner
157 }
158}
159
160impl<T> Mutex for NoopMutex<T> {
161 type Data = T;
162
163 fn new(data: T) -> Self {
164 Self::new(data)
165 }
166
167 fn lock<R>(&self, f: impl FnOnce(&Self::Data) -> R) -> R {
168 f(self.borrow())
169 }
170} 166}
diff --git a/embassy/src/blocking_mutex/raw.rs b/embassy/src/blocking_mutex/raw.rs
new file mode 100644
index 000000000..ebeb6dccf
--- /dev/null
+++ b/embassy/src/blocking_mutex/raw.rs
@@ -0,0 +1,112 @@
1use core::marker::PhantomData;
2
3pub trait RawMutex {
4 const INIT: Self;
5
6 fn lock<R>(&self, f: impl FnOnce() -> R) -> R;
7}
8
9pub struct CriticalSectionRawMutex {
10 _phantom: PhantomData<()>,
11}
12unsafe impl Send for CriticalSectionRawMutex {}
13unsafe impl Sync for CriticalSectionRawMutex {}
14
15impl CriticalSectionRawMutex {
16 pub const fn new() -> Self {
17 Self {
18 _phantom: PhantomData,
19 }
20 }
21}
22
23impl RawMutex for CriticalSectionRawMutex {
24 const INIT: Self = Self::new();
25
26 fn lock<R>(&self, f: impl FnOnce() -> R) -> R {
27 critical_section::with(|_| f())
28 }
29}
30
31// ================
32
33pub struct NoopRawMutex {
34 _phantom: PhantomData<*mut ()>,
35}
36
37unsafe impl Send for NoopRawMutex {}
38
39impl NoopRawMutex {
40 pub const fn new() -> Self {
41 Self {
42 _phantom: PhantomData,
43 }
44 }
45}
46
47impl RawMutex for NoopRawMutex {
48 const INIT: Self = Self::new();
49 fn lock<R>(&self, f: impl FnOnce() -> R) -> R {
50 f()
51 }
52}
53
54// ================
55
56#[cfg(any(cortex_m, feature = "std"))]
57mod thread_mode {
58 use super::*;
59
60 pub struct ThreadModeRawMutex {
61 _phantom: PhantomData<()>,
62 }
63
64 unsafe impl Send for ThreadModeRawMutex {}
65 unsafe impl Sync for ThreadModeRawMutex {}
66
67 impl ThreadModeRawMutex {
68 pub const fn new() -> Self {
69 Self {
70 _phantom: PhantomData,
71 }
72 }
73 }
74
75 impl RawMutex for ThreadModeRawMutex {
76 const INIT: Self = Self::new();
77 fn lock<R>(&self, f: impl FnOnce() -> R) -> R {
78 assert!(
79 in_thread_mode(),
80 "ThreadModeMutex can only be locked from thread mode."
81 );
82
83 f()
84 }
85 }
86
87 impl Drop for ThreadModeRawMutex {
88 fn drop(&mut self) {
89 // Only allow dropping from thread mode. Dropping calls drop on the inner `T`, so
90 // `drop` needs the same guarantees as `lock`. `ThreadModeMutex<T>` is Send even if
91 // T isn't, so without this check a user could create a ThreadModeMutex in thread mode,
92 // send it to interrupt context and drop it there, which would "send" a T even if T is not Send.
93 assert!(
94 in_thread_mode(),
95 "ThreadModeMutex can only be dropped from thread mode."
96 );
97
98 // Drop of the inner `T` happens after this.
99 }
100 }
101
102 pub(crate) fn in_thread_mode() -> bool {
103 #[cfg(feature = "std")]
104 return Some("main") == std::thread::current().name();
105
106 #[cfg(not(feature = "std"))]
107 return cortex_m::peripheral::SCB::vect_active()
108 == cortex_m::peripheral::scb::VectActive::ThreadMode;
109 }
110}
111#[cfg(any(cortex_m, feature = "std"))]
112pub use thread_mode::*;
diff --git a/embassy/src/channel/mpsc.rs b/embassy/src/channel/mpsc.rs
index 04709cb90..32787d810 100644
--- a/embassy/src/channel/mpsc.rs
+++ b/embassy/src/channel/mpsc.rs
@@ -47,7 +47,7 @@ use core::task::Waker;
47use futures::Future; 47use futures::Future;
48use heapless::Deque; 48use heapless::Deque;
49 49
50use crate::blocking_mutex::kind::MutexKind; 50use crate::blocking_mutex::raw::RawMutex;
51use crate::blocking_mutex::Mutex; 51use crate::blocking_mutex::Mutex;
52use crate::waitqueue::WakerRegistration; 52use crate::waitqueue::WakerRegistration;
53 53
@@ -56,7 +56,7 @@ use crate::waitqueue::WakerRegistration;
56/// Instances are created by the [`split`](split) function. 56/// Instances are created by the [`split`](split) function.
57pub struct Sender<'ch, M, T, const N: usize> 57pub struct Sender<'ch, M, T, const N: usize>
58where 58where
59 M: MutexKind, 59 M: RawMutex,
60{ 60{
61 channel: &'ch Channel<M, T, N>, 61 channel: &'ch Channel<M, T, N>,
62} 62}
@@ -66,7 +66,7 @@ where
66/// Instances are created by the [`split`](split) function. 66/// Instances are created by the [`split`](split) function.
67pub struct Receiver<'ch, M, T, const N: usize> 67pub struct Receiver<'ch, M, T, const N: usize>
68where 68where
69 M: MutexKind, 69 M: RawMutex,
70{ 70{
71 channel: &'ch Channel<M, T, N>, 71 channel: &'ch Channel<M, T, N>,
72} 72}
@@ -99,7 +99,7 @@ pub fn split<M, T, const N: usize>(
99 channel: &mut Channel<M, T, N>, 99 channel: &mut Channel<M, T, N>,
100) -> (Sender<M, T, N>, Receiver<M, T, N>) 100) -> (Sender<M, T, N>, Receiver<M, T, N>)
101where 101where
102 M: MutexKind, 102 M: RawMutex,
103{ 103{
104 let sender = Sender { channel }; 104 let sender = Sender { channel };
105 let receiver = Receiver { channel }; 105 let receiver = Receiver { channel };
@@ -112,7 +112,7 @@ where
112 112
113impl<'ch, M, T, const N: usize> Receiver<'ch, M, T, N> 113impl<'ch, M, T, const N: usize> Receiver<'ch, M, T, N>
114where 114where
115 M: MutexKind, 115 M: RawMutex,
116{ 116{
117 /// Receives the next value for this receiver. 117 /// Receives the next value for this receiver.
118 /// 118 ///
@@ -161,7 +161,7 @@ where
161 161
162impl<'ch, M, T, const N: usize> Drop for Receiver<'ch, M, T, N> 162impl<'ch, M, T, const N: usize> Drop for Receiver<'ch, M, T, N>
163where 163where
164 M: MutexKind, 164 M: RawMutex,
165{ 165{
166 fn drop(&mut self) { 166 fn drop(&mut self) {
167 self.channel.lock(|c| c.deregister_receiver()) 167 self.channel.lock(|c| c.deregister_receiver())
@@ -170,14 +170,14 @@ where
170 170
171pub struct RecvFuture<'ch, M, T, const N: usize> 171pub struct RecvFuture<'ch, M, T, const N: usize>
172where 172where
173 M: MutexKind, 173 M: RawMutex,
174{ 174{
175 channel: &'ch Channel<M, T, N>, 175 channel: &'ch Channel<M, T, N>,
176} 176}
177 177
178impl<'ch, M, T, const N: usize> Future for RecvFuture<'ch, M, T, N> 178impl<'ch, M, T, const N: usize> Future for RecvFuture<'ch, M, T, N>
179where 179where
180 M: MutexKind, 180 M: RawMutex,
181{ 181{
182 type Output = Option<T>; 182 type Output = Option<T>;
183 183
@@ -193,7 +193,7 @@ where
193 193
194impl<'ch, M, T, const N: usize> Sender<'ch, M, T, N> 194impl<'ch, M, T, const N: usize> Sender<'ch, M, T, N>
195where 195where
196 M: MutexKind, 196 M: RawMutex,
197{ 197{
198 /// Sends a value, waiting until there is capacity. 198 /// Sends a value, waiting until there is capacity.
199 /// 199 ///
@@ -268,7 +268,7 @@ where
268 268
269pub struct SendFuture<'ch, M, T, const N: usize> 269pub struct SendFuture<'ch, M, T, const N: usize>
270where 270where
271 M: MutexKind, 271 M: RawMutex,
272{ 272{
273 channel: &'ch Channel<M, T, N>, 273 channel: &'ch Channel<M, T, N>,
274 message: Option<T>, 274 message: Option<T>,
@@ -276,7 +276,7 @@ where
276 276
277impl<'ch, M, T, const N: usize> Future for SendFuture<'ch, M, T, N> 277impl<'ch, M, T, const N: usize> Future for SendFuture<'ch, M, T, N>
278where 278where
279 M: MutexKind, 279 M: RawMutex,
280{ 280{
281 type Output = Result<(), SendError<T>>; 281 type Output = Result<(), SendError<T>>;
282 282
@@ -295,18 +295,18 @@ where
295 } 295 }
296} 296}
297 297
298impl<'ch, M, T, const N: usize> Unpin for SendFuture<'ch, M, T, N> where M: MutexKind {} 298impl<'ch, M, T, const N: usize> Unpin for SendFuture<'ch, M, T, N> where M: RawMutex {}
299 299
300struct CloseFuture<'ch, M, T, const N: usize> 300struct CloseFuture<'ch, M, T, const N: usize>
301where 301where
302 M: MutexKind, 302 M: RawMutex,
303{ 303{
304 channel: &'ch Channel<M, T, N>, 304 channel: &'ch Channel<M, T, N>,
305} 305}
306 306
307impl<'ch, M, T, const N: usize> Future for CloseFuture<'ch, M, T, N> 307impl<'ch, M, T, const N: usize> Future for CloseFuture<'ch, M, T, N>
308where 308where
309 M: MutexKind, 309 M: RawMutex,
310{ 310{
311 type Output = (); 311 type Output = ();
312 312
@@ -321,7 +321,7 @@ where
321 321
322impl<'ch, M, T, const N: usize> Drop for Sender<'ch, M, T, N> 322impl<'ch, M, T, const N: usize> Drop for Sender<'ch, M, T, N>
323where 323where
324 M: MutexKind, 324 M: RawMutex,
325{ 325{
326 fn drop(&mut self) { 326 fn drop(&mut self) {
327 self.channel.lock(|c| c.deregister_sender()) 327 self.channel.lock(|c| c.deregister_sender())
@@ -330,7 +330,7 @@ where
330 330
331impl<'ch, M, T, const N: usize> Clone for Sender<'ch, M, T, N> 331impl<'ch, M, T, const N: usize> Clone for Sender<'ch, M, T, N>
332where 332where
333 M: MutexKind, 333 M: RawMutex,
334{ 334{
335 fn clone(&self) -> Self { 335 fn clone(&self) -> Self {
336 self.channel.lock(|c| c.register_sender()); 336 self.channel.lock(|c| c.register_sender());
@@ -546,30 +546,50 @@ impl<T, const N: usize> ChannelState<T, N> {
546/// All data sent will become available in the same order as it was sent. 546/// All data sent will become available in the same order as it was sent.
547pub struct Channel<M, T, const N: usize> 547pub struct Channel<M, T, const N: usize>
548where 548where
549 M: MutexKind, 549 M: RawMutex,
550{ 550{
551 inner: M::Mutex<RefCell<ChannelState<T, N>>>, 551 inner: Mutex<M, RefCell<ChannelState<T, N>>>,
552} 552}
553 553
554impl<M, T, const N: usize> Channel<M, T, N> 554impl<M, T, const N: usize> Channel<M, T, N>
555where 555where
556 M: MutexKind, 556 M: RawMutex,
557{ 557{
558 /// Establish a new bounded channel. For example, to create one with a NoopMutex: 558 /// Establish a new bounded channel. For example, to create one with a NoopMutex:
559 /// 559 ///
560 /// ``` 560 /// ```
561 /// use embassy::channel::mpsc; 561 /// use embassy::channel::mpsc;
562 /// use embassy::blocking_mutex::kind::Noop; 562 /// use embassy::blocking_mutex::raw::NoopRawMutex;
563 /// use embassy::channel::mpsc::Channel; 563 /// use embassy::channel::mpsc::Channel;
564 /// 564 ///
565 /// // Declare a bounded channel of 3 u32s. 565 /// // Declare a bounded channel of 3 u32s.
566 /// let mut channel = Channel::<Noop, u32, 3>::new(); 566 /// let mut channel = Channel::<NoopRawMutex, u32, 3>::new();
567 /// // once we have a channel, obtain its sender and receiver 567 /// // once we have a channel, obtain its sender and receiver
568 /// let (sender, receiver) = mpsc::split(&mut channel); 568 /// let (sender, receiver) = mpsc::split(&mut channel);
569 /// ``` 569 /// ```
570 #[cfg(feature = "nightly")]
571 pub const fn new() -> Self {
572 Self {
573 inner: Mutex::new(RefCell::new(ChannelState::new())),
574 }
575 }
576
577 /// Establish a new bounded channel. For example, to create one with a NoopMutex:
578 ///
579 /// ```
580 /// use embassy::channel::mpsc;
581 /// use embassy::blocking_mutex::raw::NoopRawMutex;
582 /// use embassy::channel::mpsc::Channel;
583 ///
584 /// // Declare a bounded channel of 3 u32s.
585 /// let mut channel = Channel::<NoopRawMutex, u32, 3>::new();
586 /// // once we have a channel, obtain its sender and receiver
587 /// let (sender, receiver) = mpsc::split(&mut channel);
588 /// ```
589 #[cfg(not(feature = "nightly"))]
570 pub fn new() -> Self { 590 pub fn new() -> Self {
571 Self { 591 Self {
572 inner: M::Mutex::new(RefCell::new(ChannelState::new())), 592 inner: Mutex::new(RefCell::new(ChannelState::new())),
573 } 593 }
574 } 594 }
575 595
@@ -586,7 +606,7 @@ mod tests {
586 use futures_executor::ThreadPool; 606 use futures_executor::ThreadPool;
587 use futures_timer::Delay; 607 use futures_timer::Delay;
588 608
589 use crate::blocking_mutex::kind::{CriticalSection, Noop}; 609 use crate::blocking_mutex::raw::{CriticalSectionRawMutex, NoopRawMutex};
590 use crate::util::Forever; 610 use crate::util::Forever;
591 611
592 use super::*; 612 use super::*;
@@ -655,7 +675,7 @@ mod tests {
655 675
656 #[test] 676 #[test]
657 fn simple_send_and_receive() { 677 fn simple_send_and_receive() {
658 let mut c = Channel::<Noop, u32, 3>::new(); 678 let mut c = Channel::<NoopRawMutex, u32, 3>::new();
659 let (s, r) = split(&mut c); 679 let (s, r) = split(&mut c);
660 assert!(s.clone().try_send(1).is_ok()); 680 assert!(s.clone().try_send(1).is_ok());
661 assert_eq!(r.try_recv().unwrap(), 1); 681 assert_eq!(r.try_recv().unwrap(), 1);
@@ -663,7 +683,7 @@ mod tests {
663 683
664 #[test] 684 #[test]
665 fn should_close_without_sender() { 685 fn should_close_without_sender() {
666 let mut c = Channel::<Noop, u32, 3>::new(); 686 let mut c = Channel::<NoopRawMutex, u32, 3>::new();
667 let (s, r) = split(&mut c); 687 let (s, r) = split(&mut c);
668 drop(s); 688 drop(s);
669 match r.try_recv() { 689 match r.try_recv() {
@@ -674,7 +694,7 @@ mod tests {
674 694
675 #[test] 695 #[test]
676 fn should_close_once_drained() { 696 fn should_close_once_drained() {
677 let mut c = Channel::<Noop, u32, 3>::new(); 697 let mut c = Channel::<NoopRawMutex, u32, 3>::new();
678 let (s, r) = split(&mut c); 698 let (s, r) = split(&mut c);
679 assert!(s.try_send(1).is_ok()); 699 assert!(s.try_send(1).is_ok());
680 drop(s); 700 drop(s);
@@ -687,7 +707,7 @@ mod tests {
687 707
688 #[test] 708 #[test]
689 fn should_reject_send_when_receiver_dropped() { 709 fn should_reject_send_when_receiver_dropped() {
690 let mut c = Channel::<Noop, u32, 3>::new(); 710 let mut c = Channel::<NoopRawMutex, u32, 3>::new();
691 let (s, r) = split(&mut c); 711 let (s, r) = split(&mut c);
692 drop(r); 712 drop(r);
693 match s.try_send(1) { 713 match s.try_send(1) {
@@ -698,7 +718,7 @@ mod tests {
698 718
699 #[test] 719 #[test]
700 fn should_reject_send_when_channel_closed() { 720 fn should_reject_send_when_channel_closed() {
701 let mut c = Channel::<Noop, u32, 3>::new(); 721 let mut c = Channel::<NoopRawMutex, u32, 3>::new();
702 let (s, mut r) = split(&mut c); 722 let (s, mut r) = split(&mut c);
703 assert!(s.try_send(1).is_ok()); 723 assert!(s.try_send(1).is_ok());
704 r.close(); 724 r.close();
@@ -714,7 +734,7 @@ mod tests {
714 async fn receiver_closes_when_sender_dropped_async() { 734 async fn receiver_closes_when_sender_dropped_async() {
715 let executor = ThreadPool::new().unwrap(); 735 let executor = ThreadPool::new().unwrap();
716 736
717 static CHANNEL: Forever<Channel<CriticalSection, u32, 3>> = Forever::new(); 737 static CHANNEL: Forever<Channel<CriticalSectionRawMutex, u32, 3>> = Forever::new();
718 let c = CHANNEL.put(Channel::new()); 738 let c = CHANNEL.put(Channel::new());
719 let (s, mut r) = split(c); 739 let (s, mut r) = split(c);
720 assert!(executor 740 assert!(executor
@@ -729,7 +749,7 @@ mod tests {
729 async fn receiver_receives_given_try_send_async() { 749 async fn receiver_receives_given_try_send_async() {
730 let executor = ThreadPool::new().unwrap(); 750 let executor = ThreadPool::new().unwrap();
731 751
732 static CHANNEL: Forever<Channel<CriticalSection, u32, 3>> = Forever::new(); 752 static CHANNEL: Forever<Channel<CriticalSectionRawMutex, u32, 3>> = Forever::new();
733 let c = CHANNEL.put(Channel::new()); 753 let c = CHANNEL.put(Channel::new());
734 let (s, mut r) = split(c); 754 let (s, mut r) = split(c);
735 assert!(executor 755 assert!(executor
@@ -742,7 +762,7 @@ mod tests {
742 762
743 #[futures_test::test] 763 #[futures_test::test]
744 async fn sender_send_completes_if_capacity() { 764 async fn sender_send_completes_if_capacity() {
745 let mut c = Channel::<CriticalSection, u32, 1>::new(); 765 let mut c = Channel::<CriticalSectionRawMutex, u32, 1>::new();
746 let (s, mut r) = split(&mut c); 766 let (s, mut r) = split(&mut c);
747 assert!(s.send(1).await.is_ok()); 767 assert!(s.send(1).await.is_ok());
748 assert_eq!(r.recv().await, Some(1)); 768 assert_eq!(r.recv().await, Some(1));
@@ -750,7 +770,7 @@ mod tests {
750 770
751 #[futures_test::test] 771 #[futures_test::test]
752 async fn sender_send_completes_if_closed() { 772 async fn sender_send_completes_if_closed() {
753 static CHANNEL: Forever<Channel<CriticalSection, u32, 1>> = Forever::new(); 773 static CHANNEL: Forever<Channel<CriticalSectionRawMutex, u32, 1>> = Forever::new();
754 let c = CHANNEL.put(Channel::new()); 774 let c = CHANNEL.put(Channel::new());
755 let (s, r) = split(c); 775 let (s, r) = split(c);
756 drop(r); 776 drop(r);
@@ -764,7 +784,7 @@ mod tests {
764 async fn senders_sends_wait_until_capacity() { 784 async fn senders_sends_wait_until_capacity() {
765 let executor = ThreadPool::new().unwrap(); 785 let executor = ThreadPool::new().unwrap();
766 786
767 static CHANNEL: Forever<Channel<CriticalSection, u32, 1>> = Forever::new(); 787 static CHANNEL: Forever<Channel<CriticalSectionRawMutex, u32, 1>> = Forever::new();
768 let c = CHANNEL.put(Channel::new()); 788 let c = CHANNEL.put(Channel::new());
769 let (s0, mut r) = split(c); 789 let (s0, mut r) = split(c);
770 assert!(s0.try_send(1).is_ok()); 790 assert!(s0.try_send(1).is_ok());
@@ -784,7 +804,7 @@ mod tests {
784 804
785 #[futures_test::test] 805 #[futures_test::test]
786 async fn sender_close_completes_if_closing() { 806 async fn sender_close_completes_if_closing() {
787 static CHANNEL: Forever<Channel<CriticalSection, u32, 1>> = Forever::new(); 807 static CHANNEL: Forever<Channel<CriticalSectionRawMutex, u32, 1>> = Forever::new();
788 let c = CHANNEL.put(Channel::new()); 808 let c = CHANNEL.put(Channel::new());
789 let (s, mut r) = split(c); 809 let (s, mut r) = split(c);
790 r.close(); 810 r.close();
@@ -793,7 +813,7 @@ mod tests {
793 813
794 #[futures_test::test] 814 #[futures_test::test]
795 async fn sender_close_completes_if_closed() { 815 async fn sender_close_completes_if_closed() {
796 static CHANNEL: Forever<Channel<CriticalSection, u32, 1>> = Forever::new(); 816 static CHANNEL: Forever<Channel<CriticalSectionRawMutex, u32, 1>> = Forever::new();
797 let c = CHANNEL.put(Channel::new()); 817 let c = CHANNEL.put(Channel::new());
798 let (s, r) = split(c); 818 let (s, r) = split(c);
799 drop(r); 819 drop(r);
diff --git a/embassy/src/channel/signal.rs b/embassy/src/channel/signal.rs
index 87922b2fd..027f4f47c 100644
--- a/embassy/src/channel/signal.rs
+++ b/embassy/src/channel/signal.rs
@@ -32,13 +32,15 @@ enum State<T> {
32unsafe impl<T: Send> Send for Signal<T> {} 32unsafe impl<T: Send> Send for Signal<T> {}
33unsafe impl<T: Send> Sync for Signal<T> {} 33unsafe impl<T: Send> Sync for Signal<T> {}
34 34
35impl<T: Send> Signal<T> { 35impl<T> Signal<T> {
36 pub const fn new() -> Self { 36 pub const fn new() -> Self {
37 Self { 37 Self {
38 state: UnsafeCell::new(State::None), 38 state: UnsafeCell::new(State::None),
39 } 39 }
40 } 40 }
41}
41 42
43impl<T: Send> Signal<T> {
42 /// Mark this Signal as completed. 44 /// Mark this Signal as completed.
43 pub fn signal(&self, val: T) { 45 pub fn signal(&self, val: T) {
44 critical_section::with(|_| unsafe { 46 critical_section::with(|_| unsafe {
diff --git a/embassy/src/executor/raw/mod.rs b/embassy/src/executor/raw/mod.rs
index 5ee38715d..3ae52ae31 100644
--- a/embassy/src/executor/raw/mod.rs
+++ b/embassy/src/executor/raw/mod.rs
@@ -57,6 +57,7 @@ pub struct TaskHeader {
57} 57}
58 58
59impl TaskHeader { 59impl TaskHeader {
60 #[cfg(feature = "nightly")]
60 pub(crate) const fn new() -> Self { 61 pub(crate) const fn new() -> Self {
61 Self { 62 Self {
62 state: AtomicU32::new(0), 63 state: AtomicU32::new(0),
@@ -71,6 +72,21 @@ impl TaskHeader {
71 } 72 }
72 } 73 }
73 74
75 #[cfg(not(feature = "nightly"))]
76 pub(crate) fn new() -> Self {
77 Self {
78 state: AtomicU32::new(0),
79 run_queue_item: RunQueueItem::new(),
80 executor: Cell::new(ptr::null()),
81 poll_fn: UninitCell::uninit(),
82
83 #[cfg(feature = "time")]
84 expires_at: Cell::new(Instant::from_ticks(0)),
85 #[cfg(feature = "time")]
86 timer_queue_item: timer_queue::TimerQueueItem::new(),
87 }
88 }
89
74 pub(crate) unsafe fn enqueue(&self) { 90 pub(crate) unsafe fn enqueue(&self) {
75 critical_section::with(|cs| { 91 critical_section::with(|cs| {
76 let state = self.state.load(Ordering::Relaxed); 92 let state = self.state.load(Ordering::Relaxed);
@@ -113,7 +129,8 @@ pub struct TaskStorage<F: Future + 'static> {
113} 129}
114 130
115impl<F: Future + 'static> TaskStorage<F> { 131impl<F: Future + 'static> TaskStorage<F> {
116 /// Create a new Task, in not-spawned state. 132 /// Create a new TaskStorage, in not-spawned state.
133 #[cfg(feature = "nightly")]
117 pub const fn new() -> Self { 134 pub const fn new() -> Self {
118 Self { 135 Self {
119 raw: TaskHeader::new(), 136 raw: TaskHeader::new(),
@@ -121,6 +138,15 @@ impl<F: Future + 'static> TaskStorage<F> {
121 } 138 }
122 } 139 }
123 140
141 /// Create a new TaskStorage, in not-spawned state.
142 #[cfg(not(feature = "nightly"))]
143 pub fn new() -> Self {
144 Self {
145 raw: TaskHeader::new(),
146 future: UninitCell::uninit(),
147 }
148 }
149
124 /// Try to spawn a task in a pool. 150 /// Try to spawn a task in a pool.
125 /// 151 ///
126 /// See [`Self::spawn()`] for details. 152 /// See [`Self::spawn()`] for details.
diff --git a/embassy/src/lib.rs b/embassy/src/lib.rs
index 2be0e0052..acc71e105 100644
--- a/embassy/src/lib.rs
+++ b/embassy/src/lib.rs
@@ -1,8 +1,13 @@
1#![cfg_attr(not(any(feature = "std", feature = "wasm")), no_std)] 1#![cfg_attr(not(any(feature = "std", feature = "wasm")), no_std)]
2#![feature(generic_associated_types)] 2#![cfg_attr(
3#![feature(const_fn_trait_bound)] 3 feature = "nightly",
4#![feature(const_fn_fn_ptr_basics)] 4 feature(
5#![feature(type_alias_impl_trait)] 5 const_fn_trait_bound,
6 const_fn_fn_ptr_basics,
7 generic_associated_types,
8 type_alias_impl_trait
9 )
10)]
6#![allow(clippy::new_without_default)] 11#![allow(clippy::new_without_default)]
7 12
8// This mod MUST go first, so that the others see its macros. 13// This mod MUST go first, so that the others see its macros.
@@ -20,7 +25,8 @@ pub mod io;
20pub mod time; 25pub mod time;
21pub mod util; 26pub mod util;
22 27
23pub use embassy_macros::*; 28#[cfg(feature = "nightly")]
29pub use embassy_macros::{main, task};
24 30
25#[doc(hidden)] 31#[doc(hidden)]
26/// Implementation details for embassy macros. DO NOT USE. 32/// Implementation details for embassy macros. DO NOT USE.
diff --git a/embassy/src/time/delay.rs b/embassy/src/time/delay.rs
index ff32941ee..27ec61fe6 100644
--- a/embassy/src/time/delay.rs
+++ b/embassy/src/time/delay.rs
@@ -16,11 +16,7 @@ pub struct Delay;
16 16
17#[cfg(feature = "unstable-traits")] 17#[cfg(feature = "unstable-traits")]
18mod eh1 { 18mod eh1 {
19 use core::future::Future;
20 use futures::FutureExt;
21
22 use super::*; 19 use super::*;
23 use crate::time::Timer;
24 20
25 impl embedded_hal_1::delay::blocking::DelayUs for Delay { 21 impl embedded_hal_1::delay::blocking::DelayUs for Delay {
26 type Error = core::convert::Infallible; 22 type Error = core::convert::Infallible;
@@ -33,6 +29,14 @@ mod eh1 {
33 Ok(block_for(Duration::from_millis(ms as u64))) 29 Ok(block_for(Duration::from_millis(ms as u64)))
34 } 30 }
35 } 31 }
32}
33
34#[cfg(all(feature = "unstable-traits", feature = "nightly"))]
35mod eh1a {
36 use super::*;
37 use crate::time::Timer;
38 use core::future::Future;
39 use futures::FutureExt;
36 40
37 impl embedded_hal_async::delay::DelayUs for Delay { 41 impl embedded_hal_async::delay::DelayUs for Delay {
38 type Error = core::convert::Infallible; 42 type Error = core::convert::Infallible;
diff --git a/embassy/src/waitqueue/waker_agnostic.rs b/embassy/src/waitqueue/waker_agnostic.rs
index f583fa6f4..89430aa4c 100644
--- a/embassy/src/waitqueue/waker_agnostic.rs
+++ b/embassy/src/waitqueue/waker_agnostic.rs
@@ -2,7 +2,8 @@ use core::cell::Cell;
2use core::mem; 2use core::mem;
3use core::task::Waker; 3use core::task::Waker;
4 4
5use crate::blocking_mutex::CriticalSectionMutex as Mutex; 5use crate::blocking_mutex::raw::CriticalSectionRawMutex;
6use crate::blocking_mutex::Mutex;
6 7
7/// Utility struct to register and wake a waker. 8/// Utility struct to register and wake a waker.
8#[derive(Debug)] 9#[derive(Debug)]
@@ -50,13 +51,13 @@ impl WakerRegistration {
50 51
51/// Utility struct to register and wake a waker. 52/// Utility struct to register and wake a waker.
52pub struct AtomicWaker { 53pub struct AtomicWaker {
53 waker: Mutex<Cell<Option<Waker>>>, 54 waker: Mutex<CriticalSectionRawMutex, Cell<Option<Waker>>>,
54} 55}
55 56
56impl AtomicWaker { 57impl AtomicWaker {
57 pub const fn new() -> Self { 58 pub const fn new() -> Self {
58 Self { 59 Self {
59 waker: Mutex::new(Cell::new(None)), 60 waker: Mutex::const_new(CriticalSectionRawMutex::new(), Cell::new(None)),
60 } 61 }
61 } 62 }
62 63
diff --git a/examples/nrf/Cargo.toml b/examples/nrf/Cargo.toml
index da16bcbaf..2d9c99530 100644
--- a/examples/nrf/Cargo.toml
+++ b/examples/nrf/Cargo.toml
@@ -4,6 +4,9 @@ edition = "2018"
4name = "embassy-nrf-examples" 4name = "embassy-nrf-examples"
5version = "0.1.0" 5version = "0.1.0"
6 6
7[features]
8default = ["nightly"]
9nightly = ["embassy-nrf/nightly"]
7 10
8[dependencies] 11[dependencies]
9embassy = { version = "0.1.0", path = "../../embassy", features = ["defmt"] } 12embassy = { version = "0.1.0", path = "../../embassy", features = ["defmt"] }
diff --git a/examples/nrf/src/bin/mpsc.rs b/examples/nrf/src/bin/mpsc.rs
index 454fb9541..d50736d82 100644
--- a/examples/nrf/src/bin/mpsc.rs
+++ b/examples/nrf/src/bin/mpsc.rs
@@ -6,7 +6,7 @@
6mod example_common; 6mod example_common;
7 7
8use defmt::unwrap; 8use defmt::unwrap;
9use embassy::blocking_mutex::kind::Noop; 9use embassy::blocking_mutex::raw::NoopRawMutex;
10use embassy::channel::mpsc::{self, Channel, Sender, TryRecvError}; 10use embassy::channel::mpsc::{self, Channel, Sender, TryRecvError};
11use embassy::executor::Spawner; 11use embassy::executor::Spawner;
12use embassy::time::{Duration, Timer}; 12use embassy::time::{Duration, Timer};
@@ -19,10 +19,10 @@ enum LedState {
19 Off, 19 Off,
20} 20}
21 21
22static CHANNEL: Forever<Channel<Noop, LedState, 1>> = Forever::new(); 22static CHANNEL: Forever<Channel<NoopRawMutex, LedState, 1>> = Forever::new();
23 23
24#[embassy::task(pool_size = 1)] 24#[embassy::task(pool_size = 1)]
25async fn my_task(sender: Sender<'static, Noop, LedState, 1>) { 25async fn my_task(sender: Sender<'static, NoopRawMutex, LedState, 1>) {
26 loop { 26 loop {
27 let _ = sender.send(LedState::On).await; 27 let _ = sender.send(LedState::On).await;
28 Timer::after(Duration::from_secs(1)).await; 28 Timer::after(Duration::from_secs(1)).await;
diff --git a/examples/nrf/src/bin/uart_split.rs b/examples/nrf/src/bin/uart_split.rs
index 750798378..19d438c40 100644
--- a/examples/nrf/src/bin/uart_split.rs
+++ b/examples/nrf/src/bin/uart_split.rs
@@ -6,7 +6,7 @@
6mod example_common; 6mod example_common;
7use example_common::*; 7use example_common::*;
8 8
9use embassy::blocking_mutex::kind::Noop; 9use embassy::blocking_mutex::raw::NoopRawMutex;
10use embassy::channel::mpsc::{self, Channel, Sender}; 10use embassy::channel::mpsc::{self, Channel, Sender};
11use embassy::executor::Spawner; 11use embassy::executor::Spawner;
12use embassy::util::Forever; 12use embassy::util::Forever;
@@ -14,7 +14,7 @@ use embassy_nrf::peripherals::UARTE0;
14use embassy_nrf::uarte::UarteRx; 14use embassy_nrf::uarte::UarteRx;
15use embassy_nrf::{interrupt, uarte, Peripherals}; 15use embassy_nrf::{interrupt, uarte, Peripherals};
16 16
17static CHANNEL: Forever<Channel<Noop, [u8; 8], 1>> = Forever::new(); 17static CHANNEL: Forever<Channel<NoopRawMutex, [u8; 8], 1>> = Forever::new();
18 18
19#[embassy::main] 19#[embassy::main]
20async fn main(spawner: Spawner, p: Peripherals) { 20async fn main(spawner: Spawner, p: Peripherals) {
@@ -56,7 +56,7 @@ async fn main(spawner: Spawner, p: Peripherals) {
56} 56}
57 57
58#[embassy::task] 58#[embassy::task]
59async fn reader(mut rx: UarteRx<'static, UARTE0>, s: Sender<'static, Noop, [u8; 8], 1>) { 59async fn reader(mut rx: UarteRx<'static, UARTE0>, s: Sender<'static, NoopRawMutex, [u8; 8], 1>) {
60 let mut buf = [0; 8]; 60 let mut buf = [0; 8];
61 loop { 61 loop {
62 info!("reading..."); 62 info!("reading...");
diff --git a/examples/std/Cargo.toml b/examples/std/Cargo.toml
index 450911fa1..ef60fe992 100644
--- a/examples/std/Cargo.toml
+++ b/examples/std/Cargo.toml
@@ -5,7 +5,7 @@ name = "embassy-std-examples"
5version = "0.1.0" 5version = "0.1.0"
6 6
7[dependencies] 7[dependencies]
8embassy = { version = "0.1.0", path = "../../embassy", features = ["log", "std", "time"] } 8embassy = { version = "0.1.0", path = "../../embassy", features = ["log", "std", "time", "nightly"] }
9embassy-net = { version = "0.1.0", path = "../../embassy-net", features=["std", "log", "medium-ethernet", "tcp", "dhcpv4"] } 9embassy-net = { version = "0.1.0", path = "../../embassy-net", features=["std", "log", "medium-ethernet", "tcp", "dhcpv4"] }
10 10
11async-io = "1.6.0" 11async-io = "1.6.0"
diff --git a/examples/stm32f3/src/bin/button_events.rs b/examples/stm32f3/src/bin/button_events.rs
index 720ed9d11..1218edd2b 100644
--- a/examples/stm32f3/src/bin/button_events.rs
+++ b/examples/stm32f3/src/bin/button_events.rs
@@ -12,7 +12,7 @@
12 12
13#[path = "../example_common.rs"] 13#[path = "../example_common.rs"]
14mod example_common; 14mod example_common;
15use embassy::blocking_mutex::kind::Noop; 15use embassy::blocking_mutex::raw::NoopRawMutex;
16use embassy::channel::mpsc::{self, Channel, Receiver, Sender}; 16use embassy::channel::mpsc::{self, Channel, Receiver, Sender};
17use embassy::executor::Spawner; 17use embassy::executor::Spawner;
18use embassy::time::{with_timeout, Duration, Timer}; 18use embassy::time::{with_timeout, Duration, Timer};
@@ -77,7 +77,7 @@ enum ButtonEvent {
77 Hold, 77 Hold,
78} 78}
79 79
80static BUTTON_EVENTS_QUEUE: Forever<Channel<Noop, ButtonEvent, 4>> = Forever::new(); 80static BUTTON_EVENTS_QUEUE: Forever<Channel<NoopRawMutex, ButtonEvent, 4>> = Forever::new();
81 81
82#[embassy::main] 82#[embassy::main]
83async fn main(spawner: Spawner, p: Peripherals) { 83async fn main(spawner: Spawner, p: Peripherals) {
@@ -103,7 +103,10 @@ async fn main(spawner: Spawner, p: Peripherals) {
103} 103}
104 104
105#[embassy::task] 105#[embassy::task]
106async fn led_blinker(mut leds: Leds<'static>, queue: Receiver<'static, Noop, ButtonEvent, 4>) { 106async fn led_blinker(
107 mut leds: Leds<'static>,
108 queue: Receiver<'static, NoopRawMutex, ButtonEvent, 4>,
109) {
107 loop { 110 loop {
108 leds.blink().await; 111 leds.blink().await;
109 match queue.try_recv() { 112 match queue.try_recv() {
@@ -121,7 +124,7 @@ async fn led_blinker(mut leds: Leds<'static>, queue: Receiver<'static, Noop, But
121#[embassy::task] 124#[embassy::task]
122async fn button_waiter( 125async fn button_waiter(
123 mut button: ExtiInput<'static, PA0>, 126 mut button: ExtiInput<'static, PA0>,
124 queue: Sender<'static, Noop, ButtonEvent, 4>, 127 queue: Sender<'static, NoopRawMutex, ButtonEvent, 4>,
125) { 128) {
126 const DOUBLE_CLICK_DELAY: u64 = 250; 129 const DOUBLE_CLICK_DELAY: u64 = 250;
127 const HOLD_DELAY: u64 = 1000; 130 const HOLD_DELAY: u64 = 1000;
diff --git a/examples/wasm/Cargo.toml b/examples/wasm/Cargo.toml
index c6218a805..6750f6a6c 100644
--- a/examples/wasm/Cargo.toml
+++ b/examples/wasm/Cargo.toml
@@ -8,7 +8,7 @@ version = "0.1.0"
8crate-type = ["cdylib"] 8crate-type = ["cdylib"]
9 9
10[dependencies] 10[dependencies]
11embassy = { version = "0.1.0", path = "../../embassy", features = ["log", "wasm"] } 11embassy = { version = "0.1.0", path = "../../embassy", features = ["log", "wasm", "nightly"] }
12 12
13wasm-logger = "0.2.0" 13wasm-logger = "0.2.0"
14wasm-bindgen = "0.2" 14wasm-bindgen = "0.2"