cortex_m_rtic_macros/codegen/
timer_queue.rs
1use proc_macro2::TokenStream as TokenStream2;
2use quote::quote;
3use rtic_syntax::ast::App;
4
5use crate::{analyze::Analysis, check::Extra, codegen::util};
6
7#[allow(clippy::too_many_lines)]
9pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec<TokenStream2> {
10 let mut items = vec![];
11
12 if !app.monotonics.is_empty() {
13 let tq_marker = util::timer_queue_marker_ident();
15 items.push(quote!(
16 #[doc(hidden)]
17 #[allow(non_camel_case_types)]
18 #[allow(non_upper_case_globals)]
19 static #tq_marker: rtic::RacyCell<u32> = rtic::RacyCell::new(0);
20 ));
21
22 let t = util::schedule_t_ident();
23
24 {
26 let variants = app
27 .software_tasks
28 .iter()
29 .map(|(name, task)| {
30 let cfgs = &task.cfgs;
31
32 quote!(
33 #(#cfgs)*
34 #name
35 )
36 })
37 .collect::<Vec<_>>();
38
39 items.push(quote!(
42 #[doc(hidden)]
44 #[allow(non_camel_case_types)]
45 #[derive(Clone, Copy)]
46 pub enum #t {
47 #(#variants,)*
48 }
49 ));
50 }
51 }
52
53 for (_, monotonic) in &app.monotonics {
54 let monotonic_name = monotonic.ident.to_string();
55 let tq = util::tq_ident(&monotonic_name);
56 let t = util::schedule_t_ident();
57 let mono_type = &monotonic.ty;
58 let cfgs = &monotonic.cfgs;
59 let m_ident = util::monotonic_ident(&monotonic_name);
60
61 {
63 let cap: usize = app
66 .software_tasks
67 .iter()
68 .map(|(_name, task)| task.args.capacity as usize)
69 .sum();
70 let n = util::capacity_literal(cap);
71 let tq_ty = quote!(rtic::export::TimerQueue<#mono_type, #t, #n>);
72
73 items.push(quote!(
76 #[doc(hidden)]
77 #[allow(non_camel_case_types)]
78 #[allow(non_upper_case_globals)]
79 #(#cfgs)*
80 static #tq: rtic::RacyCell<#tq_ty> =
81 rtic::RacyCell::new(rtic::export::TimerQueue(rtic::export::SortedLinkedList::new_u16()));
82 ));
83
84 let mono = util::monotonic_ident(&monotonic_name);
85 items.push(quote!(
89 #[doc(hidden)]
90 #[allow(non_camel_case_types)]
91 #[allow(non_upper_case_globals)]
92 #(#cfgs)*
93 static #mono: rtic::RacyCell<Option<#mono_type>> = rtic::RacyCell::new(None);
94 ));
95 }
96
97 {
99 let enum_ = util::interrupt_ident();
100 let rt_err = util::rt_err_ident();
101
102 let arms = app
103 .software_tasks
104 .iter()
105 .map(|(name, task)| {
106 let cfgs = &task.cfgs;
107 let priority = task.args.priority;
108 let rq = util::rq_ident(priority);
109 let rqt = util::spawn_t_ident(priority);
110
111 let interrupt = &analysis.interrupts.get(&priority).expect("RTIC-ICE: interrupt not found").0;
113
114 let pend = {
115 quote!(
116 rtic::pend(#rt_err::#enum_::#interrupt);
117 )
118 };
119
120 quote!(
121 #(#cfgs)*
122 #t::#name => {
123 rtic::export::interrupt::free(|_| (&mut *#rq.get_mut()).split().0.enqueue_unchecked((#rqt::#name, index)));
124
125 #pend
126 }
127 )
128 })
129 .collect::<Vec<_>>();
130
131 let cfgs = &monotonic.cfgs;
132 let bound_interrupt = &monotonic.args.binds;
133 let disable_isr = if &*bound_interrupt.to_string() == "SysTick" {
134 quote!(core::mem::transmute::<_, rtic::export::SYST>(()).disable_interrupt())
135 } else {
136 quote!(rtic::export::NVIC::mask(#rt_err::#enum_::#bound_interrupt))
137 };
138
139 items.push(quote!(
140 #[no_mangle]
141 #[allow(non_snake_case)]
142 #(#cfgs)*
143 unsafe fn #bound_interrupt() {
144 while let Some((task, index)) = rtic::export::interrupt::free(|_|
145 if let Some(mono) = (&mut *#m_ident.get_mut()).as_mut() {
146 (&mut *#tq.get_mut()).dequeue(|| #disable_isr, mono)
147 } else {
148 core::hint::unreachable_unchecked()
151 })
152 {
153 match task {
154 #(#arms)*
155 }
156 }
157
158 rtic::export::interrupt::free(|_| if let Some(mono) = (&mut *#m_ident.get_mut()).as_mut() {
159 mono.on_interrupt();
160 });
161 }
162 ));
163 }
164 }
165
166 items
167}