rtic_macros/codegen/
async_dispatchers.rs

1use crate::syntax::ast::App;
2use crate::{
3    analyze::Analysis,
4    codegen::{
5        bindings::{async_entry, handler_config, interrupt_entry, interrupt_exit, interrupt_mod},
6        util,
7    },
8};
9use proc_macro2::TokenStream as TokenStream2;
10use quote::quote;
11
12/// Generates task dispatchers
13pub fn codegen(app: &App, analysis: &Analysis) -> TokenStream2 {
14    let mut items = vec![];
15
16    let interrupts = &analysis.interrupts;
17
18    // Generate executor definition and priority in global scope
19    for (name, _) in app.software_tasks.iter() {
20        let exec_name = util::internal_task_ident(name, "EXEC");
21
22        items.push(quote!(
23            #[allow(non_upper_case_globals)]
24            static #exec_name: rtic::export::executor::AsyncTaskExecutorPtr =
25                rtic::export::executor::AsyncTaskExecutorPtr::new();
26        ));
27    }
28
29    for (&level, channel) in &analysis.channels {
30        let mut stmts = vec![];
31
32        let dispatcher_name = if level > 0 {
33            util::suffixed(&interrupts.get(&level).expect("UNREACHABLE").0.to_string())
34        } else {
35            util::zero_prio_dispatcher_ident()
36        };
37
38        let pend_interrupt = if level > 0 {
39            let int_mod = interrupt_mod(app);
40
41            quote!(rtic::export::pend(#int_mod::#dispatcher_name);)
42        } else {
43            // For 0 priority tasks we don't need to pend anything
44            quote!()
45        };
46
47        for name in channel.tasks.iter() {
48            let exec_name = util::internal_task_ident(name, "EXEC");
49            let from_ptr_n_args =
50                util::from_ptr_n_args_ident(app.software_tasks[name].inputs.len());
51
52            // TODO: Fix cfg
53            // let task = &app.software_tasks[name];
54            // let cfgs = &task.cfgs;
55
56            stmts.push(quote!(
57                let exec = rtic::export::executor::AsyncTaskExecutor::#from_ptr_n_args(#name, &#exec_name);
58                exec.poll(|| {
59                    let exec = rtic::export::executor::AsyncTaskExecutor::#from_ptr_n_args(#name, &#exec_name);
60                    exec.set_pending();
61                    #pend_interrupt
62                });
63            ));
64        }
65
66        if level > 0 {
67            let doc = format!("Interrupt handler to dispatch async tasks at priority {level}");
68            let attribute = &interrupts.get(&level).expect("UNREACHABLE").1.attrs;
69            let entry_stmts = interrupt_entry(app, analysis);
70            let exit_stmts = interrupt_exit(app, analysis);
71            let async_entry_stmts = async_entry(app, analysis, dispatcher_name.clone());
72            let config = handler_config(app, analysis, dispatcher_name.clone());
73            items.push(quote!(
74                #[allow(non_snake_case)]
75                #[doc = #doc]
76                #[no_mangle]
77                #(#attribute)*
78                #(#config)*
79                unsafe fn #dispatcher_name() {
80                    #(#entry_stmts)*
81                    #(#async_entry_stmts)*
82
83                    /// The priority of this interrupt handler
84                    const PRIORITY: u8 = #level;
85
86                    rtic::export::run(PRIORITY, || {
87                        #(#stmts)*
88                    });
89
90                    #(#exit_stmts)*
91                }
92            ));
93        } else {
94            items.push(quote!(
95                #[allow(non_snake_case)]
96                unsafe fn #dispatcher_name() -> ! {
97                    loop {
98                        #(#stmts)*
99                    }
100                }
101            ));
102        }
103    }
104
105    quote!(#(#items)*)
106}