use proc_macro2::TokenStream as TokenStream2; use quote::quote; use rtic_syntax::ast::App; use crate::{analyze::Analysis, check::Extra, codegen::util}; /// Generates timer queues and timer queue handlers pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec { let mut items = vec![]; if extra.monotonic.is_some() { let t = util::schedule_t_ident(); // Enumeration of `schedule`-able tasks { let variants = app .software_tasks .iter() .map(|(name, task)| { let cfgs = &task.cfgs; quote!( #(#cfgs)* #name ) }) .collect::>(); let doc = format!("Tasks that can be scheduled"); items.push(quote!( #[doc = #doc] #[allow(non_camel_case_types)] #[derive(Clone, Copy)] pub enum #t { #(#variants,)* } )); } let tq = util::tq_ident(); // Static variable and resource proxy { let doc = format!("Timer queue"); let m = extra.monotonic(); let cap = app .software_tasks .iter() .map(|(_name, task)| task.args.capacity) .sum(); let n = util::capacity_typenum(cap, false); let tq_ty = quote!(rtic::export::TimerQueue<#m, #t, #n>); items.push(quote!( #[doc = #doc] pub static mut #tq: #tq_ty = rtic::export::TimerQueue( rtic::export::BinaryHeap( rtic::export::iBinaryHeap::new() ) ); )); } // Timer queue handler { let device = extra.device; let arms = app .software_tasks .iter() .map(|(name, task)| { let cfgs = &task.cfgs; let priority = task.args.priority; let rq = util::rq_ident(priority); let rqt = util::spawn_t_ident(priority); let enum_ = util::interrupt_ident(); let interrupt = &analysis.interrupts.get(&priority); let pend = { quote!( rtic::pend(#device::#enum_::#interrupt); ) }; quote!( #(#cfgs)* #t::#name => { rtic::export::interrupt::free(|_| #rq.split().0.enqueue_unchecked((#rqt::#name, index))); #pend } ) }) .collect::>(); let sys_tick = util::suffixed("SysTick"); items.push(quote!( #[no_mangle] unsafe fn #sys_tick() { use rtic::Mutex as _; while let Some((task, index)) = rtic::export::interrupt::free(|_| #tq.dequeue()) { match task { #(#arms)* } } } )); } } items }