mirror of
https://github.com/rtic-rs/rtic.git
synced 2024-11-25 21:19:35 +01:00
More work
This commit is contained in:
parent
b23bb1192c
commit
97a48983d2
10 changed files with 155 additions and 176 deletions
|
@ -9,10 +9,10 @@ use rtic::app;
|
|||
#[app(device = lm3s6965, dispatchers = [UART])]
|
||||
mod app {
|
||||
#[monotonic(binds = SomeISR1)]
|
||||
type Mono1 = hal::Mono1;
|
||||
type MyMono1 = hal::Mono1;
|
||||
|
||||
#[monotonic(binds = SomeISR2)]
|
||||
type Mono2 = hal::Mono2;
|
||||
#[monotonic(binds = SomeISR2, default = true)]
|
||||
type MyMono2 = hal::Mono2;
|
||||
|
||||
#[init]
|
||||
fn init(cx: init::Context) -> (init::LateResources, init::Monotonics) {
|
||||
|
|
|
@ -27,13 +27,13 @@ pub fn app(app: &App, analysis: &Analysis, extra: &Extra) -> TokenStream2 {
|
|||
let mut user = vec![];
|
||||
|
||||
// Generate the `main` function
|
||||
let assertion_stmts = assertions::codegen(analysis);
|
||||
let assertion_stmts = assertions::codegen(app, analysis);
|
||||
|
||||
let pre_init_stmts = pre_init::codegen(&app, analysis, extra);
|
||||
let pre_init_stmts = pre_init::codegen(app, analysis, extra);
|
||||
|
||||
let (mod_app_init, root_init, user_init, call_init) = init::codegen(app, analysis, extra);
|
||||
|
||||
let post_init_stmts = post_init::codegen(&app, analysis);
|
||||
let post_init_stmts = post_init::codegen(app, analysis);
|
||||
|
||||
let (mod_app_idle, root_idle, user_idle, call_idle) = idle::codegen(app, analysis, extra);
|
||||
|
||||
|
@ -104,12 +104,20 @@ pub fn app(app: &App, analysis: &Analysis, extra: &Extra) -> TokenStream2 {
|
|||
));
|
||||
}
|
||||
|
||||
let monotonic_imports: Vec<_> = app.monotonics.iter().map(|(_, monotonic)| {
|
||||
let name = &monotonic.ident;
|
||||
let ty = &monotonic.ty;
|
||||
quote!(pub type #name = #ty;)
|
||||
}).collect();
|
||||
|
||||
quote!(
|
||||
/// Implementation details
|
||||
pub mod #name {
|
||||
/// Always include the device crate which contains the vector table
|
||||
use #device as you_must_enable_the_rt_feature_for_the_pac_in_your_cargo_toml;
|
||||
|
||||
#(#monotonic_imports)*
|
||||
|
||||
#(#user_imports)*
|
||||
|
||||
/// User code from within the module
|
||||
|
|
|
@ -2,9 +2,10 @@ use proc_macro2::TokenStream as TokenStream2;
|
|||
use quote::quote;
|
||||
|
||||
use crate::analyze::Analysis;
|
||||
use rtic_syntax::ast::App;
|
||||
|
||||
/// Generates compile-time assertions that check that types implement the `Send` / `Sync` traits
|
||||
pub fn codegen(analysis: &Analysis) -> Vec<TokenStream2> {
|
||||
pub fn codegen(app: &App, analysis: &Analysis) -> Vec<TokenStream2> {
|
||||
let mut stmts = vec![];
|
||||
|
||||
for ty in &analysis.send_types {
|
||||
|
@ -15,5 +16,10 @@ pub fn codegen(analysis: &Analysis) -> Vec<TokenStream2> {
|
|||
stmts.push(quote!(rtic::export::assert_sync::<#ty>();));
|
||||
}
|
||||
|
||||
for (_, monotonic) in &app.monotonics {
|
||||
let ty = &monotonic.ty;
|
||||
stmts.push(quote!(rtic::export::assert_monotonic::<#ty>();));
|
||||
}
|
||||
|
||||
stmts
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ use rtic_syntax::ast::App;
|
|||
use crate::{analyze::Analysis, check::Extra, codegen::util};
|
||||
|
||||
/// Generates task dispatchers
|
||||
pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream2> {
|
||||
pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec<TokenStream2> {
|
||||
let mut items = vec![];
|
||||
|
||||
let interrupts = &analysis.interrupts;
|
||||
|
|
|
@ -5,7 +5,7 @@ use rtic_syntax::{ast::App, Context};
|
|||
use crate::{
|
||||
analyze::Analysis,
|
||||
check::Extra,
|
||||
codegen::{locals, module, resources_struct, util},
|
||||
codegen::{locals, module, resources_struct},
|
||||
};
|
||||
|
||||
type CodegenResult = (
|
||||
|
@ -32,50 +32,6 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> CodegenResult {
|
|||
|
||||
let mut root_init = vec![];
|
||||
|
||||
let late_fields = analysis
|
||||
.late_resources
|
||||
.iter()
|
||||
.flat_map(|resources| {
|
||||
resources.iter().map(|name| {
|
||||
let ty = &app.late_resources[name].ty;
|
||||
let cfgs = &app.late_resources[name].cfgs;
|
||||
|
||||
quote!(
|
||||
#(#cfgs)*
|
||||
pub #name: #ty
|
||||
)
|
||||
})
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let late_resources = util::late_resources_ident(&name);
|
||||
|
||||
root_init.push(quote!(
|
||||
/// Resources initialized at runtime
|
||||
#[allow(non_snake_case)]
|
||||
pub struct #late_resources {
|
||||
#(#late_fields),*
|
||||
}
|
||||
));
|
||||
|
||||
let monotonic_types: Vec<_> = app
|
||||
.monotonics
|
||||
.iter()
|
||||
.map(|(_, monotonic)| {
|
||||
let mono = &monotonic.ty;
|
||||
quote! {#mono}
|
||||
})
|
||||
.collect();
|
||||
let monotonics = util::monotonics_ident(&name);
|
||||
|
||||
root_init.push(quote!(
|
||||
/// Monotonics used by the system
|
||||
#[allow(non_snake_case)]
|
||||
pub struct #monotonics(
|
||||
#(#monotonic_types),*
|
||||
);
|
||||
));
|
||||
|
||||
let mut locals_pat = None;
|
||||
let mut locals_new = None;
|
||||
if !init.locals.is_empty() {
|
||||
|
@ -91,15 +47,12 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> CodegenResult {
|
|||
let stmts = &init.stmts;
|
||||
let locals_pat = locals_pat.iter();
|
||||
|
||||
let mut user_init_return = vec![quote! {#name::LateResources}];
|
||||
if !app.monotonics.is_empty() {
|
||||
user_init_return.push(quote! {#name::Monotonics});
|
||||
}
|
||||
let user_init_return = quote! {#name::LateResources, #name::Monotonics};
|
||||
|
||||
let user_init = Some(quote!(
|
||||
#(#attrs)*
|
||||
#[allow(non_snake_case)]
|
||||
fn #name(#(#locals_pat,)* #context: #name::Context) -> (#(#user_init_return,)*) {
|
||||
fn #name(#(#locals_pat,)* #context: #name::Context) -> (#user_init_return) {
|
||||
#(#stmts)*
|
||||
}
|
||||
));
|
||||
|
|
|
@ -19,29 +19,13 @@ pub fn codegen(
|
|||
|
||||
let name = ctxt.ident(app);
|
||||
|
||||
let mut needs_instant = false;
|
||||
let mut lt = None;
|
||||
match ctxt {
|
||||
Context::Init => {
|
||||
// TODO: What fields are needed?
|
||||
// if let Some(m) = &extra.monotonic {
|
||||
// fields.push(quote!(
|
||||
// /// System start time = `Instant(0 /* cycles */)`
|
||||
// pub start: <#m as rtic::Monotonic>::Instant
|
||||
// ));
|
||||
|
||||
// values.push(quote!(start: <#m as rtic::Monotonic>::zero()));
|
||||
|
||||
// fields.push(quote!(
|
||||
// /// Core (Cortex-M) peripherals minus the SysTick
|
||||
// pub core: rtic::Peripherals
|
||||
// ));
|
||||
// } else {
|
||||
// fields.push(quote!(
|
||||
// /// Core (Cortex-M) peripherals
|
||||
// pub core: rtic::export::Peripherals
|
||||
// ));
|
||||
// }
|
||||
fields.push(quote!(
|
||||
/// Core (Cortex-M) peripherals
|
||||
pub core: rtic::export::Peripherals
|
||||
));
|
||||
|
||||
if extra.peripherals {
|
||||
let device = &extra.device;
|
||||
|
@ -68,31 +52,11 @@ pub fn codegen(
|
|||
Context::Idle => {}
|
||||
|
||||
Context::HardwareTask(..) => {
|
||||
// TODO: What fields are needed for monotonic?
|
||||
// if let Some(m) = &extra.monotonic {
|
||||
// fields.push(quote!(
|
||||
// /// Time at which this handler started executing
|
||||
// pub start: <#m as rtic::Monotonic>::Instant
|
||||
// ));
|
||||
|
||||
// values.push(quote!(start: instant));
|
||||
|
||||
// needs_instant = true;
|
||||
// }
|
||||
// None for now.
|
||||
}
|
||||
|
||||
Context::SoftwareTask(..) => {
|
||||
// TODO: What fields are needed for monotonic?
|
||||
// if let Some(m) = &extra.monotonic {
|
||||
// fields.push(quote!(
|
||||
// /// The time at which this task was scheduled to run
|
||||
// pub scheduled: <#m as rtic::Monotonic>::Instant
|
||||
// ));
|
||||
|
||||
// values.push(quote!(scheduled: instant));
|
||||
|
||||
// needs_instant = true;
|
||||
// }
|
||||
// None for now.
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -132,18 +96,45 @@ pub fn codegen(
|
|||
}
|
||||
|
||||
if let Context::Init = ctxt {
|
||||
let init = &app.inits.first().unwrap();
|
||||
let late_resources = util::late_resources_ident(&init.name);
|
||||
let monotonics = util::monotonics_ident(&init.name);
|
||||
let late_fields = analysis
|
||||
.late_resources
|
||||
.iter()
|
||||
.flat_map(|resources| {
|
||||
resources.iter().map(|name| {
|
||||
let ty = &app.late_resources[name].ty;
|
||||
let cfgs = &app.late_resources[name].cfgs;
|
||||
|
||||
quote!(
|
||||
#(#cfgs)*
|
||||
pub #name: #ty
|
||||
)
|
||||
})
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
items.push(quote!(
|
||||
#[doc(inline)]
|
||||
pub use super::#late_resources as LateResources;
|
||||
/// Resources initialized at runtime
|
||||
#[allow(non_snake_case)]
|
||||
pub struct LateResources {
|
||||
#(#late_fields),*
|
||||
}
|
||||
));
|
||||
|
||||
let monotonic_types: Vec<_> = app
|
||||
.monotonics
|
||||
.iter()
|
||||
.map(|(_, monotonic)| {
|
||||
let mono = &monotonic.ident;
|
||||
quote! {#mono}
|
||||
})
|
||||
.collect();
|
||||
|
||||
items.push(quote!(
|
||||
#[doc(inline)]
|
||||
pub use super::#monotonics as Monotonics;
|
||||
/// Monotonics used by the system
|
||||
#[allow(non_snake_case)]
|
||||
pub struct Monotonics(
|
||||
#(#monotonic_types),*
|
||||
);
|
||||
));
|
||||
}
|
||||
|
||||
|
@ -166,16 +157,6 @@ pub fn codegen(
|
|||
Some(quote!(priority: &#lt rtic::export::Priority))
|
||||
};
|
||||
|
||||
// TODO: What is needed for the new monotonic?
|
||||
// let instant = if needs_instant {
|
||||
// let m = extra.monotonic.clone().expect("RTIC-ICE: UNREACHABLE");
|
||||
|
||||
// Some(quote!(, instant: <#m as rtic::Monotonic>::Instant))
|
||||
// } else {
|
||||
// None
|
||||
// };
|
||||
let instant = quote!();
|
||||
|
||||
items.push(quote!(
|
||||
/// Execution context
|
||||
pub struct Context<#lt> {
|
||||
|
@ -184,7 +165,7 @@ pub fn codegen(
|
|||
|
||||
impl<#lt> Context<#lt> {
|
||||
#[inline(always)]
|
||||
pub unsafe fn new(#core #priority #instant) -> Self {
|
||||
pub unsafe fn new(#core #priority) -> Self {
|
||||
Context {
|
||||
#(#values,)*
|
||||
}
|
||||
|
@ -202,7 +183,7 @@ pub fn codegen(
|
|||
let cfgs = &spawnee.cfgs;
|
||||
// Store a copy of the task cfgs
|
||||
task_cfgs = cfgs.clone();
|
||||
let (args, tupled, _untupled, ty) = util::regroup_inputs(&spawnee.inputs);
|
||||
let (args, tupled, untupled, ty) = util::regroup_inputs(&spawnee.inputs);
|
||||
let args = &args;
|
||||
let tupled = &tupled;
|
||||
let fq = util::fq_ident(name);
|
||||
|
@ -251,51 +232,70 @@ pub fn codegen(
|
|||
|
||||
}));
|
||||
|
||||
// TODO: Needs updating for new monotonic.
|
||||
// // Schedule caller
|
||||
// if let Some(m) = &extra.monotonic {
|
||||
// let instants = util::instants_ident(name);
|
||||
// Schedule caller
|
||||
for (_, monotonic) in &app.monotonics {
|
||||
let instants = util::instants_ident(name);
|
||||
|
||||
// let tq = util::tq_ident();
|
||||
// let t = util::schedule_t_ident();
|
||||
let tq = util::tq_ident(&monotonic.ident.to_string());
|
||||
let t = util::schedule_t_ident();
|
||||
let m = &monotonic.ident;
|
||||
|
||||
// items.push(quote!(
|
||||
// #(#cfgs)*
|
||||
// pub fn schedule(
|
||||
// instant: <#m as rtic::Monotonic>::Instant
|
||||
// #(,#args)*
|
||||
// ) -> Result<(), #ty> {
|
||||
// unsafe {
|
||||
// use rtic::Mutex as _;
|
||||
// use rtic::mutex_prelude::*;
|
||||
if monotonic.args.default {
|
||||
items.push(quote!(pub use #m::spawn_after;));
|
||||
items.push(quote!(pub use #m::spawn_at;));
|
||||
}
|
||||
|
||||
// let input = #tupled;
|
||||
// if let Some(index) = rtic::export::interrupt::free(|_| #app_path::#fq.dequeue()) {
|
||||
// #app_path::#inputs
|
||||
// .get_unchecked_mut(usize::from(index))
|
||||
// .as_mut_ptr()
|
||||
// .write(input);
|
||||
items.push(quote!(
|
||||
pub mod #m {
|
||||
#(#cfgs)*
|
||||
pub fn spawn_after(
|
||||
duration: rtic::Duration,
|
||||
#(,#args)*
|
||||
) -> Result<(), #ty> {
|
||||
let instant = <#app_path::#m as rtic::Monotonic>::now();
|
||||
|
||||
// #app_path::#instants
|
||||
// .get_unchecked_mut(usize::from(index))
|
||||
// .as_mut_ptr()
|
||||
// .write(instant);
|
||||
spawn_at(instant + duration, #(,#untupled)*)
|
||||
}
|
||||
|
||||
// let nr = rtic::export::NotReady {
|
||||
// instant,
|
||||
// index,
|
||||
// task: #app_path::#t::#name,
|
||||
// };
|
||||
#(#cfgs)*
|
||||
pub fn spawn_at(
|
||||
instant: Instant<#app_path::#m as rtic::Monotonic>
|
||||
#(,#args)*
|
||||
) -> Result<(), #ty> {
|
||||
unsafe {
|
||||
use rtic::Mutex as _;
|
||||
use rtic::mutex_prelude::*;
|
||||
|
||||
// rtic::export::interrupt::free(|_| #app_path::#tq.enqueue_unchecked(nr));
|
||||
let input = #tupled;
|
||||
if let Some(index) = rtic::export::interrupt::free(|_| #app_path::#fq.dequeue()) {
|
||||
#app_path::#inputs
|
||||
.get_unchecked_mut(usize::from(index))
|
||||
.as_mut_ptr()
|
||||
.write(input);
|
||||
|
||||
// Ok(())
|
||||
// } else {
|
||||
// Err(input)
|
||||
// }
|
||||
// }
|
||||
// }));
|
||||
// }
|
||||
#app_path::#instants
|
||||
.get_unchecked_mut(usize::from(index))
|
||||
.as_mut_ptr()
|
||||
.write(instant);
|
||||
|
||||
let nr = rtic::export::NotReady {
|
||||
instant,
|
||||
index,
|
||||
task: #app_path::#t::#name,
|
||||
};
|
||||
|
||||
rtic::export::interrupt::free(|_| #app_path::#tq.enqueue_unchecked(nr));
|
||||
|
||||
// TODO: After adding the scheduled task, check and setup the timer.
|
||||
|
||||
Ok(())
|
||||
} else {
|
||||
Err(input)
|
||||
}
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
if !items.is_empty() {
|
||||
|
|
|
@ -74,25 +74,26 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream
|
|||
);));
|
||||
}
|
||||
|
||||
// TODO: Update for noew monotonic
|
||||
// // Initialize the SysTick if there exist a TimerQueue
|
||||
// if extra.monotonic.is_some() {
|
||||
// let priority = analysis.channels.keys().max().unwrap();
|
||||
// Initialize monotonic's interrupts
|
||||
for (priority, name) in app
|
||||
.monotonics
|
||||
.iter()
|
||||
.map(|(_, monotonic)| (&monotonic.args.priority, &monotonic.args.binds))
|
||||
{
|
||||
// Compile time assert that this priority is supported by the device
|
||||
stmts.push(quote!(let _ = [(); ((1 << #nvic_prio_bits) - #priority as usize)];));
|
||||
|
||||
// // Compile time assert that this priority is supported by the device
|
||||
// stmts.push(quote!(let _ = [(); ((1 << #nvic_prio_bits) - #priority as usize)];));
|
||||
// NOTE this also checks that the interrupt exists in the `Interrupt` enumeration
|
||||
let interrupt = util::interrupt_ident();
|
||||
stmts.push(quote!(
|
||||
core.NVIC.set_priority(
|
||||
you_must_enable_the_rt_feature_for_the_pac_in_your_cargo_toml::#interrupt::#name,
|
||||
rtic::export::logical2hw(#priority, #nvic_prio_bits),
|
||||
);
|
||||
));
|
||||
|
||||
// stmts.push(quote!(core.SCB.set_priority(
|
||||
// rtic::export::SystemHandler::SysTick,
|
||||
// rtic::export::logical2hw(#priority, #nvic_prio_bits),
|
||||
// );));
|
||||
|
||||
// stmts.push(quote!(
|
||||
// core.SYST.set_clock_source(rtic::export::SystClkSource::Core);
|
||||
// core.SYST.enable_counter();
|
||||
// core.DCB.enable_trace();
|
||||
// ));
|
||||
// }
|
||||
// NOTE we do not unmask the interrupt as this is part of the monotonic to keep track of
|
||||
}
|
||||
|
||||
// If there's no user `#[idle]` then optimize returning from interrupt handlers
|
||||
if app.idles.is_empty() {
|
||||
|
|
|
@ -5,7 +5,7 @@ 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<TokenStream2> {
|
||||
pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec<TokenStream2> {
|
||||
let mut items = vec![];
|
||||
|
||||
if !app.monotonics.is_empty() {
|
||||
|
|
|
@ -16,6 +16,7 @@ pub use cortex_m::{
|
|||
use heapless::spsc::SingleCore;
|
||||
pub use heapless::{consts, i::Queue as iQueue, spsc::Queue};
|
||||
pub use heapless::{i::BinaryHeap as iBinaryHeap, BinaryHeap};
|
||||
pub use rtic_core::monotonic::Monotonic;
|
||||
|
||||
pub type SCFQ<N> = Queue<u8, N, u8, SingleCore>;
|
||||
pub type SCRQ<T, N> = Queue<(T, u8), N, u8, SingleCore>;
|
||||
|
@ -112,6 +113,13 @@ where
|
|||
{
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn assert_monotonic<T>()
|
||||
where
|
||||
T: Monotonic,
|
||||
{
|
||||
}
|
||||
|
||||
/// Lock the resource proxy by setting the BASEPRI
|
||||
/// and running the closure with interrupt::free
|
||||
///
|
||||
|
|
|
@ -39,7 +39,10 @@ use core::ops::Sub;
|
|||
|
||||
use cortex_m::{interrupt::Nr, peripheral::NVIC};
|
||||
pub use cortex_m_rtic_macros::app;
|
||||
pub use rtic_core::{prelude as mutex_prelude, Exclusive, monotonic::Monotonic, Mutex};
|
||||
pub use rtic_core::{
|
||||
monotonic::{Clock, Instant, Monotonic},
|
||||
prelude as mutex_prelude, Exclusive, Mutex,
|
||||
};
|
||||
|
||||
#[doc(hidden)]
|
||||
pub mod export;
|
||||
|
|
Loading…
Reference in a new issue