cortex_m_rtic_macros/codegen/
hardware_tasks.rs

1use proc_macro2::TokenStream as TokenStream2;
2use quote::quote;
3use rtic_syntax::{ast::App, Context};
4
5use crate::{
6    analyze::Analysis,
7    check::Extra,
8    codegen::{local_resources_struct, module, shared_resources_struct},
9};
10
11/// Generate support code for hardware tasks (`#[exception]`s and `#[interrupt]`s)
12pub fn codegen(
13    app: &App,
14    analysis: &Analysis,
15    extra: &Extra,
16) -> (
17    // mod_app_hardware_tasks -- interrupt handlers and `${task}Resources` constructors
18    Vec<TokenStream2>,
19    // root_hardware_tasks -- items that must be placed in the root of the crate:
20    // - `${task}Locals` structs
21    // - `${task}Resources` structs
22    // - `${task}` modules
23    Vec<TokenStream2>,
24    // user_hardware_tasks -- the `#[task]` functions written by the user
25    Vec<TokenStream2>,
26) {
27    let mut mod_app = vec![];
28    let mut root = vec![];
29    let mut user_tasks = vec![];
30
31    for (name, task) in &app.hardware_tasks {
32        let symbol = task.args.binds.clone();
33        let priority = task.args.priority;
34        let cfgs = &task.cfgs;
35        let attrs = &task.attrs;
36        let user_hardware_task_isr_doc = &format!(" User HW task ISR trampoline for {name}");
37
38        mod_app.push(quote!(
39            #[allow(non_snake_case)]
40            #[no_mangle]
41            #[doc = #user_hardware_task_isr_doc]
42            #(#attrs)*
43            #(#cfgs)*
44            unsafe fn #symbol() {
45                const PRIORITY: u8 = #priority;
46
47                rtic::export::run(PRIORITY, || {
48                    #name(
49                        #name::Context::new(&rtic::export::Priority::new(PRIORITY))
50                    )
51                });
52            }
53        ));
54
55        let mut shared_needs_lt = false;
56        let mut local_needs_lt = false;
57
58        // `${task}Locals`
59        if !task.args.local_resources.is_empty() {
60            let (item, constructor) = local_resources_struct::codegen(
61                Context::HardwareTask(name),
62                &mut local_needs_lt,
63                app,
64            );
65
66            root.push(item);
67
68            mod_app.push(constructor);
69        }
70
71        // `${task}Resources`
72        if !task.args.shared_resources.is_empty() {
73            let (item, constructor) = shared_resources_struct::codegen(
74                Context::HardwareTask(name),
75                &mut shared_needs_lt,
76                app,
77            );
78
79            root.push(item);
80
81            mod_app.push(constructor);
82        }
83
84        root.push(module::codegen(
85            Context::HardwareTask(name),
86            shared_needs_lt,
87            local_needs_lt,
88            app,
89            analysis,
90            extra,
91        ));
92
93        let user_hardware_task_doc = &format!(" User HW task: {name}");
94        if !task.is_extern {
95            let attrs = &task.attrs;
96            let cfgs = &task.cfgs;
97            let context = &task.context;
98            let stmts = &task.stmts;
99            user_tasks.push(quote!(
100                #[doc = #user_hardware_task_doc]
101                #(#attrs)*
102                #(#cfgs)*
103                #[allow(non_snake_case)]
104                fn #name(#context: #name::Context) {
105                    use rtic::Mutex as _;
106                    use rtic::mutex::prelude::*;
107
108                    #(#stmts)*
109                }
110            ));
111        }
112    }
113
114    (mod_app, root, user_tasks)
115}