aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-executor/Cargo.toml5
-rw-r--r--embassy-executor/src/lib.rs10
-rw-r--r--embassy-macros/Cargo.toml4
-rw-r--r--embassy-macros/src/lib.rs81
-rw-r--r--embassy-macros/src/macros/main.rs98
5 files changed, 140 insertions, 58 deletions
diff --git a/embassy-executor/Cargo.toml b/embassy-executor/Cargo.toml
index 45b0955bf..6fa1dd7fb 100644
--- a/embassy-executor/Cargo.toml
+++ b/embassy-executor/Cargo.toml
@@ -29,9 +29,8 @@ flavors = [
29 29
30[features] 30[features]
31default = [] 31default = []
32std = ["embassy-macros/std", "critical-section/std"] 32std = ["critical-section/std"]
33wasm = ["dep:wasm-bindgen", "dep:js-sys", "embassy-macros/wasm"] 33wasm = ["dep:wasm-bindgen", "dep:js-sys"]
34riscv = ["embassy-macros/riscv"]
35 34
36# Enable nightly-only features 35# Enable nightly-only features
37nightly = [] 36nightly = []
diff --git a/embassy-executor/src/lib.rs b/embassy-executor/src/lib.rs
index e4cbd04b9..4c7e2f4cd 100644
--- a/embassy-executor/src/lib.rs
+++ b/embassy-executor/src/lib.rs
@@ -8,18 +8,22 @@
8pub(crate) mod fmt; 8pub(crate) mod fmt;
9 9
10#[cfg(feature = "nightly")] 10#[cfg(feature = "nightly")]
11pub use embassy_macros::{main, task}; 11pub use embassy_macros::task;
12 12
13cfg_if::cfg_if! { 13cfg_if::cfg_if! {
14 if #[cfg(cortex_m)] { 14 if #[cfg(cortex_m)] {
15 #[path="arch/cortex_m.rs"] 15 #[path="arch/cortex_m.rs"]
16 mod arch; 16 mod arch;
17 pub use arch::*; 17 pub use arch::*;
18 #[cfg(feature = "nightly")]
19 pub use embassy_macros::main_cortex_m as main;
18 } 20 }
19 else if #[cfg(target_arch="riscv32")] { 21 else if #[cfg(target_arch="riscv32")] {
20 #[path="arch/riscv32.rs"] 22 #[path="arch/riscv32.rs"]
21 mod arch; 23 mod arch;
22 pub use arch::*; 24 pub use arch::*;
25 #[cfg(feature = "nightly")]
26 pub use embassy_macros::main_riscv as main;
23 } 27 }
24 else if #[cfg(all(target_arch="xtensa", feature = "nightly"))] { 28 else if #[cfg(all(target_arch="xtensa", feature = "nightly"))] {
25 #[path="arch/xtensa.rs"] 29 #[path="arch/xtensa.rs"]
@@ -30,11 +34,15 @@ cfg_if::cfg_if! {
30 #[path="arch/wasm.rs"] 34 #[path="arch/wasm.rs"]
31 mod arch; 35 mod arch;
32 pub use arch::*; 36 pub use arch::*;
37 #[cfg(feature = "nightly")]
38 pub use embassy_macros::main_wasm as main;
33 } 39 }
34 else if #[cfg(feature="std")] { 40 else if #[cfg(feature="std")] {
35 #[path="arch/std.rs"] 41 #[path="arch/std.rs"]
36 mod arch; 42 mod arch;
37 pub use arch::*; 43 pub use arch::*;
44 #[cfg(feature = "nightly")]
45 pub use embassy_macros::main_std as main;
38 } 46 }
39} 47}
40 48
diff --git a/embassy-macros/Cargo.toml b/embassy-macros/Cargo.toml
index 9b83771c8..5c612c997 100644
--- a/embassy-macros/Cargo.toml
+++ b/embassy-macros/Cargo.toml
@@ -21,9 +21,5 @@ proc-macro2 = "1.0.29"
21proc-macro = true 21proc-macro = true
22 22
23[features] 23[features]
24std = []
25wasm = []
26riscv = []
27
28# Enabling this cause interrupt::take! to require embassy-executor 24# Enabling this cause interrupt::take! to require embassy-executor
29rtos-trace-interrupt = [] 25rtos-trace-interrupt = []
diff --git a/embassy-macros/src/lib.rs b/embassy-macros/src/lib.rs
index f5df2a269..d2c696c72 100644
--- a/embassy-macros/src/lib.rs
+++ b/embassy-macros/src/lib.rs
@@ -45,7 +45,7 @@ pub fn task(args: TokenStream, item: TokenStream) -> TokenStream {
45 task::run(args, f).unwrap_or_else(|x| x).into() 45 task::run(args, f).unwrap_or_else(|x| x).into()
46} 46}
47 47
48/// Creates a new `executor` instance and declares an application entry point spawning the corresponding function body as an async task. 48/// Creates a new `executor` instance and declares an application entry point for Cortex-M spawning the corresponding function body as an async task.
49/// 49///
50/// The following restrictions apply: 50/// The following restrictions apply:
51/// 51///
@@ -64,10 +64,85 @@ pub fn task(args: TokenStream, item: TokenStream) -> TokenStream {
64/// } 64/// }
65/// ``` 65/// ```
66#[proc_macro_attribute] 66#[proc_macro_attribute]
67pub fn main(args: TokenStream, item: TokenStream) -> TokenStream { 67pub fn main_cortex_m(args: TokenStream, item: TokenStream) -> TokenStream {
68 let args = syn::parse_macro_input!(args as syn::AttributeArgs); 68 let args = syn::parse_macro_input!(args as syn::AttributeArgs);
69 let f = syn::parse_macro_input!(item as syn::ItemFn); 69 let f = syn::parse_macro_input!(item as syn::ItemFn);
70 main::run(args, f).unwrap_or_else(|x| x).into() 70 main::run(args, f, main::cortex_m()).unwrap_or_else(|x| x).into()
71}
72
73/// Creates a new `executor` instance and declares an application entry point for RISC-V spawning the corresponding function body as an async task.
74///
75/// The following restrictions apply:
76///
77/// * The function must accept exactly 1 parameter, an `embassy_executor::Spawner` handle that it can use to spawn additional tasks.
78/// * The function must be declared `async`.
79/// * The function must not use generics.
80/// * Only a single `main` task may be declared.
81///
82/// ## Examples
83/// Spawning a task:
84///
85/// ``` rust
86/// #[embassy_executor::main]
87/// async fn main(_s: embassy_executor::Spawner) {
88/// // Function body
89/// }
90/// ```
91#[proc_macro_attribute]
92pub fn main_riscv(args: TokenStream, item: TokenStream) -> TokenStream {
93 let args = syn::parse_macro_input!(args as syn::AttributeArgs);
94 let f = syn::parse_macro_input!(item as syn::ItemFn);
95 main::run(args, f, main::riscv()).unwrap_or_else(|x| x).into()
96}
97
98/// Creates a new `executor` instance and declares an application entry point for STD spawning the corresponding function body as an async task.
99///
100/// The following restrictions apply:
101///
102/// * The function must accept exactly 1 parameter, an `embassy_executor::Spawner` handle that it can use to spawn additional tasks.
103/// * The function must be declared `async`.
104/// * The function must not use generics.
105/// * Only a single `main` task may be declared.
106///
107/// ## Examples
108/// Spawning a task:
109///
110/// ``` rust
111/// #[embassy_executor::main]
112/// async fn main(_s: embassy_executor::Spawner) {
113/// // Function body
114/// }
115/// ```
116#[proc_macro_attribute]
117pub fn main_std(args: TokenStream, item: TokenStream) -> TokenStream {
118 let args = syn::parse_macro_input!(args as syn::AttributeArgs);
119 let f = syn::parse_macro_input!(item as syn::ItemFn);
120 main::run(args, f, main::std()).unwrap_or_else(|x| x).into()
121}
122
123/// Creates a new `executor` instance and declares an application entry point for WASM spawning the corresponding function body as an async task.
124///
125/// The following restrictions apply:
126///
127/// * The function must accept exactly 1 parameter, an `embassy_executor::Spawner` handle that it can use to spawn additional tasks.
128/// * The function must be declared `async`.
129/// * The function must not use generics.
130/// * Only a single `main` task may be declared.
131///
132/// ## Examples
133/// Spawning a task:
134///
135/// ``` rust
136/// #[embassy_executor::main]
137/// async fn main(_s: embassy_executor::Spawner) {
138/// // Function body
139/// }
140/// ```
141#[proc_macro_attribute]
142pub fn main_wasm(args: TokenStream, item: TokenStream) -> TokenStream {
143 let args = syn::parse_macro_input!(args as syn::AttributeArgs);
144 let f = syn::parse_macro_input!(item as syn::ItemFn);
145 main::run(args, f, main::wasm()).unwrap_or_else(|x| x).into()
71} 146}
72 147
73#[proc_macro_attribute] 148#[proc_macro_attribute]
diff --git a/embassy-macros/src/macros/main.rs b/embassy-macros/src/macros/main.rs
index 54806847c..18f7c36c4 100644
--- a/embassy-macros/src/macros/main.rs
+++ b/embassy-macros/src/macros/main.rs
@@ -7,31 +7,34 @@ use crate::util::ctxt::Ctxt;
7#[derive(Debug, FromMeta)] 7#[derive(Debug, FromMeta)]
8struct Args {} 8struct Args {}
9 9
10pub fn run(args: syn::AttributeArgs, f: syn::ItemFn) -> Result<TokenStream, TokenStream> { 10pub fn riscv() -> TokenStream {
11 #[allow(unused_variables)] 11 quote! {
12 let args = Args::from_list(&args).map_err(|e| e.write_errors())?; 12 #[riscv_rt::entry]
13 13 fn main() -> ! {
14 let fargs = f.sig.inputs.clone(); 14 let mut executor = ::embassy_executor::Executor::new();
15 15 let executor = unsafe { __make_static(&mut executor) };
16 let ctxt = Ctxt::new(); 16 executor.run(|spawner| {
17 17 spawner.must_spawn(__embassy_main(spawner));
18 if f.sig.asyncness.is_none() { 18 })
19 ctxt.error_spanned_by(&f.sig, "main function must be async"); 19 }
20 }
21 if !f.sig.generics.params.is_empty() {
22 ctxt.error_spanned_by(&f.sig, "main function must not be generic");
23 } 20 }
21}
24 22
25 if fargs.len() != 1 { 23pub fn cortex_m() -> TokenStream {
26 ctxt.error_spanned_by(&f.sig, "main function must have 1 argument: the spawner."); 24 quote! {
25 #[cortex_m_rt::entry]
26 fn main() -> ! {
27 let mut executor = ::embassy_executor::Executor::new();
28 let executor = unsafe { __make_static(&mut executor) };
29 executor.run(|spawner| {
30 spawner.must_spawn(__embassy_main(spawner));
31 })
32 }
27 } 33 }
34}
28 35
29 ctxt.check()?; 36pub fn wasm() -> TokenStream {
30 37 quote! {
31 let f_body = f.block;
32
33 #[cfg(feature = "wasm")]
34 let main = quote! {
35 #[wasm_bindgen::prelude::wasm_bindgen(start)] 38 #[wasm_bindgen::prelude::wasm_bindgen(start)]
36 pub fn main() -> Result<(), wasm_bindgen::JsValue> { 39 pub fn main() -> Result<(), wasm_bindgen::JsValue> {
37 static EXECUTOR: ::embassy_executor::_export::StaticCell<::embassy_executor::Executor> = ::embassy_executor::_export::StaticCell::new(); 40 static EXECUTOR: ::embassy_executor::_export::StaticCell<::embassy_executor::Executor> = ::embassy_executor::_export::StaticCell::new();
@@ -43,10 +46,11 @@ pub fn run(args: syn::AttributeArgs, f: syn::ItemFn) -> Result<TokenStream, Toke
43 46
44 Ok(()) 47 Ok(())
45 } 48 }
46 }; 49 }
50}
47 51
48 #[cfg(all(feature = "std", not(feature = "wasm"), not(feature = "riscv")))] 52pub fn std() -> TokenStream {
49 let main = quote! { 53 quote! {
50 fn main() -> ! { 54 fn main() -> ! {
51 let mut executor = ::embassy_executor::Executor::new(); 55 let mut executor = ::embassy_executor::Executor::new();
52 let executor = unsafe { __make_static(&mut executor) }; 56 let executor = unsafe { __make_static(&mut executor) };
@@ -55,31 +59,31 @@ pub fn run(args: syn::AttributeArgs, f: syn::ItemFn) -> Result<TokenStream, Toke
55 spawner.must_spawn(__embassy_main(spawner)); 59 spawner.must_spawn(__embassy_main(spawner));
56 }) 60 })
57 } 61 }
58 }; 62 }
63}
59 64
60 #[cfg(all(not(feature = "std"), not(feature = "wasm"), not(feature = "riscv")))] 65pub fn run(args: syn::AttributeArgs, f: syn::ItemFn, main: TokenStream) -> Result<TokenStream, TokenStream> {
61 let main = quote! { 66 #[allow(unused_variables)]
62 #[cortex_m_rt::entry] 67 let args = Args::from_list(&args).map_err(|e| e.write_errors())?;
63 fn main() -> ! {
64 let mut executor = ::embassy_executor::Executor::new();
65 let executor = unsafe { __make_static(&mut executor) };
66 executor.run(|spawner| {
67 spawner.must_spawn(__embassy_main(spawner));
68 })
69 }
70 };
71 68
72 #[cfg(all(not(feature = "std"), not(feature = "wasm"), feature = "riscv"))] 69 let fargs = f.sig.inputs.clone();
73 let main = quote! { 70
74 #[riscv_rt::entry] 71 let ctxt = Ctxt::new();
75 fn main() -> ! { 72
76 let mut executor = ::embassy_executor::Executor::new(); 73 if f.sig.asyncness.is_none() {
77 let executor = unsafe { __make_static(&mut executor) }; 74 ctxt.error_spanned_by(&f.sig, "main function must be async");
78 executor.run(|spawner| { 75 }
79 spawner.must_spawn(__embassy_main(spawner)); 76 if !f.sig.generics.params.is_empty() {
80 }) 77 ctxt.error_spanned_by(&f.sig, "main function must not be generic");
81 } 78 }
82 }; 79
80 if fargs.len() != 1 {
81 ctxt.error_spanned_by(&f.sig, "main function must have 1 argument: the spawner.");
82 }
83
84 ctxt.check()?;
85
86 let f_body = f.block;
83 87
84 let result = quote! { 88 let result = quote! {
85 #[::embassy_executor::task()] 89 #[::embassy_executor::task()]