cortex_m_rtic_macros/codegen/
util.rs
1use core::sync::atomic::{AtomicUsize, Ordering};
2
3use proc_macro2::{Span, TokenStream as TokenStream2};
4use quote::quote;
5use rtic_syntax::{ast::App, Context};
6use syn::{Attribute, Ident, LitInt, PatType};
7
8use crate::check::Extra;
9
10const RTIC_INTERNAL: &str = "__rtic_internal";
11
12pub fn capacity_literal(capacity: usize) -> LitInt {
14 LitInt::new(&capacity.to_string(), Span::call_site())
15}
16
17pub fn fq_ident(task: &Ident) -> Ident {
19 mark_internal_name(&format!("{}_FQ", task))
20}
21
22pub fn impl_mutex(
24 extra: &Extra,
25 cfgs: &[Attribute],
26 resources_prefix: bool,
27 name: &Ident,
28 ty: &TokenStream2,
29 ceiling: u8,
30 ptr: &TokenStream2,
31) -> TokenStream2 {
32 let (path, priority) = if resources_prefix {
33 (quote!(shared_resources::#name), quote!(self.priority()))
34 } else {
35 (quote!(#name), quote!(self.priority))
36 };
37
38 let device = &extra.device;
39 let masks_name = priority_masks_ident();
40 quote!(
41 #(#cfgs)*
42 impl<'a> rtic::Mutex for #path<'a> {
43 type T = #ty;
44
45 #[inline(always)]
46 fn lock<RTIC_INTERNAL_R>(&mut self, f: impl FnOnce(&mut #ty) -> RTIC_INTERNAL_R) -> RTIC_INTERNAL_R {
47 const CEILING: u8 = #ceiling;
49
50 unsafe {
51 rtic::export::lock(
52 #ptr,
53 #priority,
54 CEILING,
55 #device::NVIC_PRIO_BITS,
56 &#masks_name,
57 f,
58 )
59 }
60 }
61 }
62 )
63}
64
65pub fn inputs_ident(task: &Ident) -> Ident {
67 mark_internal_name(&format!("{}_INPUTS", task))
68}
69
70pub fn monotonic_instants_ident(task: &Ident, monotonic: &Ident) -> Ident {
72 mark_internal_name(&format!("{}_{}_INSTANTS", task, monotonic))
73}
74
75pub fn interrupt_ident() -> Ident {
76 let span = Span::call_site();
77 Ident::new("interrupt", span)
78}
79
80pub fn timer_queue_marker_ident() -> Ident {
81 mark_internal_name("TIMER_QUEUE_MARKER")
82}
83
84pub fn is_exception(name: &Ident) -> bool {
86 let s = name.to_string();
87
88 matches!(
89 &*s,
90 "MemoryManagement"
91 | "BusFault"
92 | "UsageFault"
93 | "SecureFault"
94 | "SVCall"
95 | "DebugMonitor"
96 | "PendSV"
97 | "SysTick"
98 )
99}
100
101pub fn mark_internal_name(name: &str) -> Ident {
103 Ident::new(&format!("{}_{}", RTIC_INTERNAL, name), Span::call_site())
104}
105
106pub fn internal_monotonics_ident(task: &Ident, monotonic: &Ident, ident_name: &str) -> Ident {
108 mark_internal_name(&format!("{}_{}_{}", task, monotonic, ident_name,))
109}
110
111pub fn internal_task_ident(task: &Ident, ident_name: &str) -> Ident {
113 mark_internal_name(&format!("{}_{}", task, ident_name))
114}
115
116fn link_section_index() -> usize {
117 static INDEX: AtomicUsize = AtomicUsize::new(0);
118
119 INDEX.fetch_add(1, Ordering::Relaxed)
120}
121
122pub fn link_section_uninit() -> TokenStream2 {
124 let section = format!(".uninit.rtic{}", link_section_index());
125
126 quote!(#[link_section = #section])
127}
128
129pub fn regroup_inputs(
133 inputs: &[PatType],
134) -> (
135 Vec<TokenStream2>,
137 TokenStream2,
139 Vec<TokenStream2>,
141 TokenStream2,
143) {
144 if inputs.len() == 1 {
145 let ty = &inputs[0].ty;
146
147 (
148 vec![quote!(_0: #ty)],
149 quote!(_0),
150 vec![quote!(_0)],
151 quote!(#ty),
152 )
153 } else {
154 let mut args = vec![];
155 let mut pats = vec![];
156 let mut tys = vec![];
157
158 for (i, input) in inputs.iter().enumerate() {
159 let i = Ident::new(&format!("_{}", i), Span::call_site());
160 let ty = &input.ty;
161
162 args.push(quote!(#i: #ty));
163
164 pats.push(quote!(#i));
165
166 tys.push(quote!(#ty));
167 }
168
169 let tupled = {
170 let pats = pats.clone();
171 quote!((#(#pats,)*))
172 };
173 let ty = quote!((#(#tys,)*));
174 (args, tupled, pats, ty)
175 }
176}
177
178pub fn get_task_name(ctxt: Context, app: &App) -> Ident {
180 let s = match ctxt {
181 Context::Init => app.init.name.to_string(),
182 Context::Idle => app.idle.as_ref().unwrap().name.to_string(),
183 Context::HardwareTask(ident) | Context::SoftwareTask(ident) => ident.to_string(),
184 };
185
186 Ident::new(&s, Span::call_site())
187}
188
189pub fn shared_resources_ident(ctxt: Context, app: &App) -> Ident {
191 let mut s = match ctxt {
192 Context::Init => app.init.name.to_string(),
193 Context::Idle => app.idle.as_ref().unwrap().name.to_string(),
194 Context::HardwareTask(ident) | Context::SoftwareTask(ident) => ident.to_string(),
195 };
196
197 s.push_str("SharedResources");
198
199 mark_internal_name(&s)
200}
201
202pub fn local_resources_ident(ctxt: Context, app: &App) -> Ident {
204 let mut s = match ctxt {
205 Context::Init => app.init.name.to_string(),
206 Context::Idle => app.idle.as_ref().unwrap().name.to_string(),
207 Context::HardwareTask(ident) | Context::SoftwareTask(ident) => ident.to_string(),
208 };
209
210 s.push_str("LocalResources");
211
212 mark_internal_name(&s)
213}
214
215pub fn rq_ident(priority: u8) -> Ident {
220 mark_internal_name(&format!("P{}_RQ", priority))
221}
222
223pub fn schedule_t_ident() -> Ident {
225 Ident::new("SCHED_T", Span::call_site())
226}
227
228pub fn spawn_t_ident(priority: u8) -> Ident {
233 Ident::new(&format!("P{}_T", priority), Span::call_site())
234}
235
236pub fn suffixed(name: &str) -> Ident {
238 let span = Span::call_site();
239 Ident::new(name, span)
240}
241
242pub fn tq_ident(name: &str) -> Ident {
244 mark_internal_name(&format!("TQ_{}", name))
245}
246
247pub fn monotonic_ident(name: &str) -> Ident {
249 mark_internal_name(&format!("MONOTONIC_STORAGE_{}", name))
250}
251
252pub fn static_shared_resource_ident(name: &Ident) -> Ident {
253 mark_internal_name(&format!("shared_resource_{}", name))
254}
255
256pub fn priority_mask_chunks_ident() -> Ident {
258 mark_internal_name("MASK_CHUNKS")
259}
260
261pub fn priority_masks_ident() -> Ident {
262 mark_internal_name("MASKS")
263}
264
265pub fn static_local_resource_ident(name: &Ident) -> Ident {
266 mark_internal_name(&format!("local_resource_{}", name))
267}
268
269pub fn declared_static_local_resource_ident(name: &Ident, task_name: &Ident) -> Ident {
270 mark_internal_name(&format!("local_{}_{}", task_name, name))
271}
272
273pub fn need_to_lock_ident(name: &Ident) -> Ident {
274 Ident::new(&format!("{}_that_needs_to_be_locked", name), name.span())
275}
276
277pub fn rt_err_ident() -> Ident {
279 Ident::new(
280 "you_must_enable_the_rt_feature_for_the_pac_in_your_cargo_toml",
281 Span::call_site(),
282 )
283}