Skip to content

Commit

Permalink
Maps Copperlist indices to named output from tasks. (#121)
Browse files Browse the repository at this point in the history
* Maps Copperlist indices to named output from tasks.

This allows our users to symbolically get the output of a given tasks
without guessing the execution order that can change from Copper.

* Unwrap the CuMsgs tuple

* Unwrap the CuMsgs tuple

* a test snafu
  • Loading branch information
gbin authored Dec 2, 2024
1 parent 5dfa28e commit 5badb69
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 8 deletions.
54 changes: 51 additions & 3 deletions core/cu29_derive/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
extern crate proc_macro;

use proc_macro::TokenStream;
use quote::quote;
use quote::{format_ident, quote};
use std::fs::read_to_string;
use syn::meta::parser;
use syn::Fields::{Named, Unnamed};
Expand Down Expand Up @@ -42,6 +42,13 @@ pub fn gen_cumsgs(config_path_lit: TokenStream) -> TokenStream {
let runtime_plan: CuExecutionLoop =
compute_runtime_plan(&cuconfig).expect("Could not compute runtime plan");

// Give a name compatible with a struct to match the task ids to their output in the CuMsgs tuple.
let all_tasks_member_ids: Vec<String> = cuconfig
.get_all_nodes()
.iter()
.map(|(_, node)| utils::config_id_to_struct_member(node.get_id().as_str()))
.collect();

// All accesses are linear on the culist but the id of the tasks is random (determined by the Ron declaration order).
// This records the task ids in call order.
let taskid_order: Vec<usize> = runtime_plan
Expand All @@ -53,7 +60,16 @@ pub fn gen_cumsgs(config_path_lit: TokenStream) -> TokenStream {
})
.collect();

let support = gen_culist_support(&runtime_plan, &taskid_order);
#[cfg(feature = "macro_debug")]
eprintln!(
"[The CuMsgs matching tasks ids are {:?}]",
taskid_order
.iter()
.map(|i| all_tasks_member_ids[*i].clone())
.collect::<Vec<_>>()
);

let support = gen_culist_support(&runtime_plan, &taskid_order, &all_tasks_member_ids);

let with_uses = quote! {
mod cumsgs {
Expand All @@ -77,6 +93,7 @@ pub fn gen_cumsgs(config_path_lit: TokenStream) -> TokenStream {
fn gen_culist_support(
runtime_plan: &CuExecutionLoop,
taskid_call_order: &[usize],
all_tasks_as_struct_member_name: &Vec<String>,
) -> proc_macro2::TokenStream {
#[cfg(feature = "macro_debug")]
eprintln!("[Extract msgs types]");
Expand Down Expand Up @@ -107,13 +124,38 @@ fn gen_culist_support(
}
};

let methods = itertools::multizip((all_tasks_as_struct_member_name, taskid_call_order)).map(
|(name, output_position)| {
let fn_name = format_ident!("get_{}_output", name);
let payload_type = all_msgs_types_in_culist_order[*output_position].clone();
let index = syn::Index::from(*output_position);
quote! {
pub fn #fn_name(&self) -> &_CuMsg<#payload_type> {
&self.0.#index
}
}
},
);

// This generates a way to get the metadata of every single message of a culist at low cost
quote! {
#collect_metadata_function

pub struct CuMsgs(#msgs_types_tuple);
pub type CuList = _CopperList<CuMsgs>;

impl CuMsgs {
#(#methods)*

fn get_tuple(&self) -> &#msgs_types_tuple {
&self.0
}

fn get_tuple_mut(&mut self) -> &mut #msgs_types_tuple {
&mut self.0
}
}

// Adds the bincode support for the copper list tuple
#msgs_types_tuple_encode
#msgs_types_tuple_decode
Expand Down Expand Up @@ -786,10 +828,16 @@ pub fn copper_runtime(args: TokenStream, input: TokenStream) -> TokenStream {
#[cfg(feature = "macro_debug")]
eprintln!("[Culist access order: {:?}]", taskid_call_order);

// Give a name compatible with a struct to match the task ids to their output in the CuMsgs tuple.
let all_tasks_member_ids: Vec<String> = all_tasks_ids
.iter()
.map(|name| utils::config_id_to_struct_member(name.as_str()))
.collect();

#[cfg(feature = "macro_debug")]
eprintln!("[build the copperlist support]");
let culist_support: proc_macro2::TokenStream =
gen_culist_support(&runtime_plan, &taskid_call_order);
gen_culist_support(&runtime_plan, &taskid_call_order, &all_tasks_member_ids);

#[cfg(feature = "macro_debug")]
eprintln!("[build the sim support]");
Expand Down
37 changes: 37 additions & 0 deletions core/cu29_derive/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,26 @@ pub(crate) fn config_id_to_enum(id: &str) -> String {
candidate
}

/// Same as config_id_to_enum but for a struct member name
pub(crate) fn config_id_to_struct_member(id: &str) -> String {
let mut candidate = id
.chars()
.map(|c| if c.is_alphanumeric() { c } else { '_' })
.collect::<String>();

candidate = candidate.to_case(Case::Snake);

if candidate
.chars()
.next()
.map_or(false, |c| c.is_ascii_digit())
{
candidate.insert(0, '_');
}

candidate
}

// Lifted this HORROR but it works.
pub fn caller_crate_root() -> PathBuf {
let crate_name =
Expand Down Expand Up @@ -106,4 +126,21 @@ mod tests {
);
})
}

#[test]
fn test_identifier_to_struct_member() {
assert_eq!(crate::utils::config_id_to_struct_member("toto"), "toto");
assert_eq!(crate::utils::config_id_to_struct_member("#id"), "id");
assert_eq!(
crate::utils::config_id_to_struct_member("!!something"),
"something"
);
assert_eq!(crate::utils::config_id_to_struct_member("hey?"), "hey");
assert_eq!(crate::utils::config_id_to_struct_member("é"), "é");
assert_eq!(crate::utils::config_id_to_struct_member("T"), "t");
assert_eq!(
crate::utils::config_id_to_struct_member("Test_Dunder"),
"test_dunder"
);
}
}
2 changes: 1 addition & 1 deletion examples/cu_rp_balancebot/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ ignored = ["cu29-log", "cu29-log-runtime", "cu29-unifiedlog", "copper-traits"]
# Core dependencies
cu29 = { workspace = true }
cu29-traits = { workspace = true }
cu29-derive = { workspace = true }
cu29-derive = { workspace = true } #, features = ["macro_debug"] }
cu29-helpers = { workspace = true }
cu29-log = { workspace = true }
cu29-log-runtime = { workspace = true }
Expand Down
16 changes: 12 additions & 4 deletions examples/cu_rp_balancebot/src/resim.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,20 +30,28 @@ fn run_one_copperlist(
copper_list: CopperList<CuMsgs>,
) {
// Sync the copper clock to the simulated physics clock.
let msgs = &copper_list.msgs.0; // TODO: dewrap this.
let msgs = &copper_list.msgs;

// Simulate what the sim is doing here
robot_clock.set_value(msgs.0.metadata.process_time.start.unwrap().0);
// TODO: set that at every step instead of just at the CL level like the sim.
robot_clock.set_value(
msgs.get_balpos_output()
.metadata
.process_time
.start
.unwrap()
.0,
);

let mut sim_callback = move |step: SimStep<'_>| -> SimOverride {
match step {
SimStep::Balpos(CuTaskCallbackState::Process(_, output)) => {
*output = msgs.0.clone(); // TODO: <- that is scheduling dependent.
*output = msgs.get_balpos_output().clone();
SimOverride::ExecutedBySim
}
SimStep::Balpos(_) => SimOverride::ExecutedBySim,
SimStep::Railpos(CuTaskCallbackState::Process(_, output)) => {
*output = msgs.2.clone(); // TODO: <- that is scheduling dependent.
*output = msgs.get_railpos_output().clone();
SimOverride::ExecutedBySim
}
SimStep::Railpos(_) => SimOverride::ExecutedBySim,
Expand Down

0 comments on commit 5badb69

Please sign in to comment.