From d7d8c0789a174752ade5f1c18db6604952b5146a Mon Sep 17 00:00:00 2001 From: jcweaver997 Date: Mon, 7 Apr 2025 22:32:22 -0500 Subject: [PATCH] changed decom to output json --- Cargo.toml | 4 + README.md | 177 +++++ apps/hs/src/watchdog.rs | 15 +- builds/ground/src/main.rs | 4 +- rfe/Cargo.toml | 7 +- rfe/macros/src/macros.rs | 203 +----- rfe/reflect/Cargo.toml | 12 + rfe/reflect/reflect_macros/Cargo.toml | 14 + .../reflect_macros/src/reflect_macros.rs | 196 ++++++ rfe/reflect/src/reflect.rs | 650 ++++++++++++++++++ rfe/src/lib.rs | 2 +- rfe/src/msg/ds.rs | 19 +- rfe/src/msg/example.rs | 16 +- rfe/src/msg/hs.rs | 15 +- rfe/src/msg/mod.rs | 30 +- rfe/src/msg/to.rs | 20 +- rfe/src/reflect.rs | 649 ----------------- rfe/src/rfe.rs | 18 +- rfe/src/utils.rs | 12 +- tools/decom/Cargo.toml | 4 +- tools/decom/src/decom.rs | 49 +- 21 files changed, 1165 insertions(+), 951 deletions(-) create mode 100644 README.md create mode 100644 rfe/reflect/Cargo.toml create mode 100644 rfe/reflect/reflect_macros/Cargo.toml create mode 100644 rfe/reflect/reflect_macros/src/reflect_macros.rs create mode 100644 rfe/reflect/src/reflect.rs diff --git a/Cargo.toml b/Cargo.toml index cc888d2..3baae2b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,6 +9,9 @@ members = [ "builds/ground", "builds/rp_pico_example", "rfe", + "rfe/macros", + "rfe/reflect", + "rfe/reflect/reflect_macros", "tools/decom", ] resolver = "2" @@ -25,3 +28,4 @@ simple_logger = "5.0.0" rp2040-hal = "0.10.2" rp2040-pac = "0.6.0" mio-serial = "=5.0.5" +reflect = { path = "rfe/reflect" } diff --git a/README.md b/README.md new file mode 100644 index 0000000..eda63b5 --- /dev/null +++ b/README.md @@ -0,0 +1,177 @@ +# Rust Flight Executive (RFE) + +RFE is a framework for building real-time embedded applications in Rust, inspired by concepts from NASA's Core Flight Executive (cFE). Rather than being a direct port of cFE to Rust, RFE is designed as an alternative that embraces Rust's idioms and strengths. Unlike cFE which primarily targets computer systems, RFE extends support to microcontrollers and other resource-constrained embedded devices. It provides a message-passing architecture for inter-application communication, time management, and scheduling at different rates. I/O operations are handled either by the standard library (when the `std` feature is enabled) or by board support packages like `rp2040-hal` for embedded platforms. These board support packages can be used generically through the traits defined in the `embedded-hal` crate, allowing for portable code across different embedded platforms. + +## Overview + +RFE is a framework that enables the development of modular, reusable flight software applications in Rust. While it shares some architectural concepts with NASA's cFE, RFE makes different design choices that are more ergonomic and better aligned with Rust's safety features, performance characteristics, and modern development ecosystem. By supporting both standard computers and microcontrollers, RFE offers greater flexibility for embedded systems development across a wide range of hardware platforms. + +## Features + +- **Message-passing architecture** for inter-application communication +- **Time management** for both system and monotonic time +- **Scheduling of applications** at different rates (1Hz to 100Hz) +- **Platform abstraction** through feature flags: + - `std`: Standard library support (Unix, Windows) + - `rp2040`: Raspberry Pi Pico support + - More platform abstractions planned for future releases + - Support for custom platforms by implementing a few simple traits +- **Runtime reflection**: + - `reflect`: Runtime type information that can be used for dynamic command generation and telemetry processing +- **Connectors**: A trait-based system for communication between instances, with built-in implementations (TCP, UDP, Memory) and support for custom user-defined connectors +- **Core applications**: + - Data Storage (DS): For telemetry storage + - Health & Safety (HS): For system monitoring + - Telemetry Output (TO): For telemetry management + - Example app: Demonstrating application development + +## Architecture + +RFE follows a modular architecture where applications communicate through a message bus. The core components include: + +- **RfeInstance**: The main framework instance that manages applications and scheduling. An instance is intended as a runner for apps - multiple apps can be added to a single instance, but thread/task priority is given to each instance rather than to individual apps. For each app to have its own task priority, you will need a separate instance for each app. +- **App trait**: Interface that all applications must implement +- **Rfe**: Interface for applications to interact with the framework +- **Connectors**: A trait-based interface for communication between different RFE instances, allowing users to implement custom message transport mechanisms. Instances can communicate with each other through these connectors. + +## Getting Started + +### Prerequisites + +- Rust toolchain (latest stable recommended) +- For RP2040 development: `thumbv6m-none-eabi` target + +### Building + +```bash +# For standard desktop build +cargo build --package example_build + +# For Raspberry Pi Pico +cargo build --package rp_pico_example --target thumbv6m-none-eabi +``` + +### Creating an Application + +Applications in RFE must implement the `App` trait: + +```rust +use rfe::*; +use anyhow::Result; + +struct MyApp; + +impl App for MyApp { + fn init(&mut self, rfe: &mut Rfe) -> Result<()> { + // Initialize the application + // Set up message subscriptions + rfe.subscribe(TargetMsg::new(rfe.get_instance(), MsgKind::YourMsgKind)); + Ok(()) + } + + fn run(&mut self, rfe: &mut Rfe) { + // Run the application logic + // Process received messages + while let Some(msg) = rfe.recv() { + // Handle message + } + } + + fn hk(&mut self, rfe: &mut Rfe) { + // Generate housekeeping data + rfe.send(Msg::YourHkMsg(self.your_hk_data.clone())); + } + + fn out_data(&mut self, rfe: &mut Rfe) { + // Generate output data + rfe.send(Msg::YourOutDataMsg(self.your_out_data.clone())); + } + + fn get_app_rate(&self) -> Rate { + // Set the intended rate at which your app runs + Rate::Hz10 // Run at 10Hz + } +} +``` + +### Running an RFE Instance + +```rust +use rfe::*; +use rfe::connector::MemConnector; +use std::thread; +use std::sync::Arc; + +// Create a shared memory connector for inter-instance communication +let (connector1, connector2) = Arc::new(MemConnector::new()); + +// First instance (you can set the priority of the thread you run the instance in) +thread::spawn(move || { + // Create a time driver for the first instance + let time_driver = StdTimeDriver::new(); + + // Create the first RFE instance + let mut instance1 = RfeInstance::new(Instance::Main, &time_driver); + + // Add the memory connector to the instance + instance1.add_connector(connector1); + + // Add applications to the first instance + let mut my_app1 = MyApp::new(); + instance1.add_app("my_app1", &mut my_app1).unwrap(); + + // Run the first instance + instance1.start(); +}); + +// Second instance +let time_driver2 = StdTimeDriver::new(); +let mut instance2 = RfeInstance::new(Instance::Secondary, &time_driver2); + +// Add the memory connector to the second instance +instance2.add_connector(connector_clone); + +// Add applications to the second instance +let mut my_app2 = AnotherApp::new(); +instance2.add_app("my_app2", &mut my_app2).unwrap(); + +// Run the second instance +instance2.start(); +``` + +In this example: +- Two RFE instances are created, each with its own application +- The first instance runs in a separate thread. You can set the priority of this thread +- The second instance runs in the main thread +- A shared `MemConnector` allows the instances to communicate with each other +- Each app can send messages that will be routed to the appropriate instance + +## Project Structure + +- `rfe/`: Core framework implementation +- `apps/`: Application implementations + - `ds/`: Data Storage application + - `hs/`: Health & Safety application + - `to/`: Telemetry Output application + - `example/`: Example application +- `builds/`: Example builds for different platforms + - `example_build/`: Standard desktop build + - `rp_pico_example/`: Raspberry Pi Pico build + - `ground/`: Ground system with GUI +- `tools/`: Development tools + - `decom/`: Telemetry decommutation tool + +## Platform Support + +RFE supports multiple platforms through feature flags: + +- **Standard Desktop** (`std` feature): Unix, Windows +- **Raspberry Pi Pico** (`rp2040` feature): Embedded ARM Cortex-M0+ +- Users can add support for any platform by implementing just a few key traits (primarily the `TimeDriver` trait) +- Board support packages utilize the `embedded-hal` traits for generic, portable hardware abstraction +- Platform-specific functionality can be easily integrated through Rust's trait system +- Additional platform support is planned for future releases + +The `reflect` feature can be enabled on any platform to provide runtime type information. + + diff --git a/apps/hs/src/watchdog.rs b/apps/hs/src/watchdog.rs index 0983b8e..35b84b4 100644 --- a/apps/hs/src/watchdog.rs +++ b/apps/hs/src/watchdog.rs @@ -89,14 +89,16 @@ mod watchdog_rp2040 { pub struct Rp2040Watchdog { wd: Watchdog, - time: u32, + timeout: u32, + enabled: bool, } impl Rp2040Watchdog { pub fn new(wd: Watchdog) -> Self { Self { wd, - time: 3 * 1000000, + timeout: 3 * 1000000, + enabled: false, } } } @@ -105,16 +107,21 @@ mod watchdog_rp2040 { fn enable(&mut self) { self.wd .start(rp2040_hal::fugit::Duration::::from_ticks( - self.time, + self.timeout, )); + self.enabled = true; } fn disable(&mut self) { self.wd.disable(); + self.enabled = false; } fn set_timeout(&mut self, time: i32) { - self.time = time as u32 * 1000000; + self.timeout = time as u32 * 1000000; + if self.enabled { + self.enable(); + } } fn feed(&mut self) { diff --git a/builds/ground/src/main.rs b/builds/ground/src/main.rs index 6fb1532..66d3a89 100644 --- a/builds/ground/src/main.rs +++ b/builds/ground/src/main.rs @@ -12,8 +12,8 @@ use connector::{Connector, UdpConnector}; use egui::{Layout, Ui}; use log::*; use msg::Msg; -use reflect::*; -use rfe::macros::Reflect; + +use rfe::reflect::*; use rfe::*; extern crate alloc; use simple_logger::SimpleLogger; diff --git a/rfe/Cargo.toml b/rfe/Cargo.toml index 6c034ad..d174a90 100644 --- a/rfe/Cargo.toml +++ b/rfe/Cargo.toml @@ -7,7 +7,8 @@ edition = "2021" default = [] std = ["dep:mio", "dep:mio-serial"] rp2040 = ["dep:rp2040-hal", "dep:rp2040-pac"] -reflect = [] +reflect = ["dep:reflect"] +serde = ["dep:serde"] [dependencies] bincode.workspace = true @@ -19,3 +20,7 @@ rp2040-hal = { workspace = true, optional = true } rp2040-pac = { workspace = true, optional = true } macros.path = "macros" mio-serial = { workspace = true, optional = true } +serde = { version = "1.0.219", default-features = false, features = [ + "derive", +], optional = true } +reflect = { workspace = true, optional = true } diff --git a/rfe/macros/src/macros.rs b/rfe/macros/src/macros.rs index 25a79f3..a4e2be9 100644 --- a/rfe/macros/src/macros.rs +++ b/rfe/macros/src/macros.rs @@ -71,7 +71,8 @@ pub fn kind_derive(input: TokenStream) -> TokenStream { let expanded = quote! { #[derive(Debug, Default, Copy, Clone, PartialEq, Eq, Hash, Encode, Decode)] - #[cfg_attr(feature = "reflect", derive(Reflect))] + #[cfg_attr(feature = "reflect", derive(reflect::Reflect))] + #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum #kind_name { #[default] #(#kind_enum_arms)* @@ -103,195 +104,19 @@ pub fn kind_derive(input: TokenStream) -> TokenStream { TokenStream::from(expanded) } - -#[proc_macro_derive(Reflect)] -pub fn reflect_derive(input: TokenStream) -> TokenStream { +#[proc_macro_attribute] +pub fn msg(_attrs: TokenStream, input: TokenStream) -> TokenStream { + // Parse the input tokens into a syntax tree let input = parse_macro_input!(input as DeriveInput); - let name = input.ident; - let name_s = name.to_string(); - - let expanded = match input.data { - Data::Struct(data_struct) => { - let fields = data_struct.fields; - - let field_arms = fields.iter().map(|field| { - let field_ident = field.clone().ident.unwrap(); - let field_name = field_ident.to_string(); - - quote! { { - fields.push((#field_name, &mut self.#field_ident as &mut dyn rfe::reflect::Reflect)); - } } - }); - - quote! { - impl rfe::reflect::Reflect for #name { - fn reflect_type(&self) -> rfe::reflect::ReflectType { - rfe::reflect::ReflectType::Structure - } - - fn type_name(&self) -> &str { - #name_s - } - - fn fields(&mut self) -> alloc::vec::Vec<(&str, &mut dyn rfe::reflect::Reflect)> { - let mut fields = alloc::vec::Vec::new(); - #(#field_arms)* - fields - } - - fn set_value(&mut self, value: rfe::reflect::ReflectValue) { - } - - fn get_value(&self) -> rfe::reflect::ReflectValue { - rfe::reflect::ReflectValue::None - } - - fn variants(&self) -> alloc::vec::Vec<(&'static str, alloc::boxed::Box)> { - alloc::vec::Vec::new() - } - - fn convert_variant(&mut self, _i: usize) {} - - fn unwrap_variant(&mut self) -> Option<(&str, &mut dyn rfe::reflect::Reflect)> { - None - } - - fn as_vec(&mut self) -> Option> { - None - } - } - } - } - - - - Data::Enum(data_enum) => { - let variants = data_enum.variants; - let convert_arms = variants.iter().enumerate().map(|(i, variant)| { - let variant_name = &variant.ident; - - match &variant.fields { - Fields::Unit => { - quote! { - if _i == #i { - *self = Self::#variant_name; - } - } - } - Fields::Unnamed(_) => { - quote! { - if _i == #i { - *self = Self::#variant_name(Default::default()); - } - } - } - Fields::Named(_) => { - panic!("Named fields not supported by Reflect"); - } - } - }); - - let unwrap_arms = variants.iter().enumerate().map(|(_i, variant)| { - let variant_name = &variant.ident; - let variant_name_s = variant_name.to_string(); - - match &variant.fields { - Fields::Unit => { - quote! { - Self::#variant_name => None, - } - } - Fields::Unnamed(_) => { - quote! { - Self::#variant_name(v) => Some((#variant_name_s, v)), - } - } - Fields::Named(_) => { - panic!("Named fields not supported by Reflect"); - } - } - }); - - let variant_arms = variants.iter().map(|variant| { - let variant_name = &variant.ident; - let variant_name_s = variant_name.to_string(); - - match &variant.fields { - Fields::Unit => { - quote! { - { - let name: &'static str = #variant_name_s; - let value: alloc::boxed::Box = alloc::boxed::Box::new(Self::#variant_name); - variants.push((name, value)); - } - } - } - Fields::Unnamed(_) => { - quote! { - { - let name: &'static str = #variant_name_s; - let value: alloc::boxed::Box = alloc::boxed::Box::new(Self::#variant_name(Default::default())); - variants.push((name, value)); - } - } - - } - Fields::Named(_) => { - panic!("Named fields not supported by Reflect"); - } - } - }); - - quote! { - impl rfe::reflect::Reflect for #name { - fn reflect_type(&self) -> rfe::reflect::ReflectType { - rfe::reflect::ReflectType::Enumeration - } - - fn type_name(&self) -> &str { - #name_s - } - - fn fields(&mut self) -> alloc::vec::Vec<(&str, &mut dyn rfe::reflect::Reflect)> { - alloc::vec::Vec::new() - } - - fn set_value(&mut self, value: rfe::reflect::ReflectValue) { - } - - fn get_value(&self) -> rfe::reflect::ReflectValue { - rfe::reflect::ReflectValue::None - } - - fn variants(&self) -> alloc::vec::Vec<(&'static str, alloc::boxed::Box)> { - let mut variants = alloc::vec::Vec::new(); - #(#variant_arms)* - variants - } - - fn convert_variant(&mut self, _i: usize) { - #(#convert_arms)* - } - - fn unwrap_variant(&mut self) -> Option<(&str, &mut dyn rfe::reflect::Reflect)> { - match self { - #(#unwrap_arms)* - } - } - - fn as_vec(&mut self) -> Option> { - None - } - } - } - } - Data::Union(_data_union) => { - return syn::Error::new_spanned(name, "Reflect not implemented for unions") - .to_compile_error() - .into(); - } + // Create a new version of the input with the additional derives + let output = quote! { + #[derive(Debug, Default, Clone, PartialEq, Encode, Decode)] + #[cfg_attr(feature = "reflect", derive(reflect::Reflect))] + #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] + #input }; - TokenStream::from(expanded) -} \ No newline at end of file + // Return the modified token stream + output.into() +} diff --git a/rfe/reflect/Cargo.toml b/rfe/reflect/Cargo.toml new file mode 100644 index 0000000..4a3ee42 --- /dev/null +++ b/rfe/reflect/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "reflect" +version = "0.1.0" +edition = "2024" + +[lib] +path = "src/reflect.rs" +name = "reflect" + +[dependencies] +hashbrown.workspace = true +reflect_macros.path = "reflect_macros" diff --git a/rfe/reflect/reflect_macros/Cargo.toml b/rfe/reflect/reflect_macros/Cargo.toml new file mode 100644 index 0000000..51b5ed5 --- /dev/null +++ b/rfe/reflect/reflect_macros/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "reflect_macros" +version = "0.1.0" +edition = "2024" + +[lib] +path = "src/reflect_macros.rs" +proc-macro = true + + +[dependencies] +proc-macro2 = "1.0.89" +quote = "1.0.37" +syn = { version = "2.0.87", features = ["full"] } diff --git a/rfe/reflect/reflect_macros/src/reflect_macros.rs b/rfe/reflect/reflect_macros/src/reflect_macros.rs new file mode 100644 index 0000000..6c79eea --- /dev/null +++ b/rfe/reflect/reflect_macros/src/reflect_macros.rs @@ -0,0 +1,196 @@ +use proc_macro::TokenStream; +use quote::quote; +use syn::Fields; +use syn::{parse_macro_input, Data, DeriveInput}; + +#[proc_macro_derive(Reflect)] +pub fn reflect_derive(input: TokenStream) -> TokenStream { + let input = parse_macro_input!(input as DeriveInput); + + let name = input.ident; + let name_s = name.to_string(); + + let expanded = match input.data { + Data::Struct(data_struct) => { + let fields = data_struct.fields; + + let field_arms = fields.iter().map(|field| { + let field_ident = field.clone().ident.unwrap(); + let field_name = field_ident.to_string(); + + quote! { { + fields.push((#field_name, &mut self.#field_ident as &mut dyn reflect::Reflect)); + } } + }); + + quote! { + impl reflect::Reflect for #name { + fn reflect_type(&self) -> reflect::ReflectType { + reflect::ReflectType::Structure + } + + fn type_name(&self) -> &str { + #name_s + } + + fn fields(&mut self) -> alloc::vec::Vec<(&str, &mut dyn reflect::Reflect)> { + let mut fields = alloc::vec::Vec::new(); + #(#field_arms)* + fields + } + + fn set_value(&mut self, value: reflect::ReflectValue) { + } + + fn get_value(&self) -> reflect::ReflectValue { + reflect::ReflectValue::None + } + + fn variants(&self) -> alloc::vec::Vec<(&'static str, alloc::boxed::Box)> { + alloc::vec::Vec::new() + } + + fn convert_variant(&mut self, _i: usize) {} + + fn unwrap_variant(&mut self) -> Option<(&str, &mut dyn reflect::Reflect)> { + None + } + + fn as_vec(&mut self) -> Option> { + None + } + } + } + } + + + + Data::Enum(data_enum) => { + let variants = data_enum.variants; + let convert_arms = variants.iter().enumerate().map(|(i, variant)| { + let variant_name = &variant.ident; + + match &variant.fields { + Fields::Unit => { + quote! { + if _i == #i { + *self = Self::#variant_name; + } + } + } + Fields::Unnamed(_) => { + quote! { + if _i == #i { + *self = Self::#variant_name(Default::default()); + } + } + } + Fields::Named(_) => { + panic!("Named fields not supported by Reflect"); + } + } + }); + + let unwrap_arms = variants.iter().enumerate().map(|(_i, variant)| { + let variant_name = &variant.ident; + let variant_name_s = variant_name.to_string(); + + match &variant.fields { + Fields::Unit => { + quote! { + Self::#variant_name => None, + } + } + Fields::Unnamed(_) => { + quote! { + Self::#variant_name(v) => Some((#variant_name_s, v)), + } + } + Fields::Named(_) => { + panic!("Named fields not supported by Reflect"); + } + } + }); + + let variant_arms = variants.iter().map(|variant| { + let variant_name = &variant.ident; + let variant_name_s = variant_name.to_string(); + + match &variant.fields { + Fields::Unit => { + quote! { + { + let name: &'static str = #variant_name_s; + let value: alloc::boxed::Box = alloc::boxed::Box::new(Self::#variant_name); + variants.push((name, value)); + } + } + } + Fields::Unnamed(_) => { + quote! { + { + let name: &'static str = #variant_name_s; + let value: alloc::boxed::Box = alloc::boxed::Box::new(Self::#variant_name(Default::default())); + variants.push((name, value)); + } + } + + } + Fields::Named(_) => { + panic!("Named fields not supported by Reflect"); + } + } + }); + + quote! { + impl reflect::Reflect for #name { + fn reflect_type(&self) -> reflect::ReflectType { + reflect::ReflectType::Enumeration + } + + fn type_name(&self) -> &str { + #name_s + } + + fn fields(&mut self) -> alloc::vec::Vec<(&str, &mut dyn reflect::Reflect)> { + alloc::vec::Vec::new() + } + + fn set_value(&mut self, value: reflect::ReflectValue) { + } + + fn get_value(&self) -> reflect::ReflectValue { + reflect::ReflectValue::None + } + + fn variants(&self) -> alloc::vec::Vec<(&'static str, alloc::boxed::Box)> { + let mut variants = alloc::vec::Vec::new(); + #(#variant_arms)* + variants + } + + fn convert_variant(&mut self, _i: usize) { + #(#convert_arms)* + } + + fn unwrap_variant(&mut self) -> Option<(&str, &mut dyn reflect::Reflect)> { + match self { + #(#unwrap_arms)* + } + } + + fn as_vec(&mut self) -> Option> { + None + } + } + } + } + Data::Union(_data_union) => { + return syn::Error::new_spanned(name, "Reflect not implemented for unions") + .to_compile_error() + .into(); + } + }; + + TokenStream::from(expanded) +} \ No newline at end of file diff --git a/rfe/reflect/src/reflect.rs b/rfe/reflect/src/reflect.rs new file mode 100644 index 0000000..b0bb8bf --- /dev/null +++ b/rfe/reflect/src/reflect.rs @@ -0,0 +1,650 @@ +extern crate alloc; +use core::mem::zeroed; + +use alloc::boxed::Box; +use alloc::string::String; +use alloc::vec::Vec; +use hashbrown::HashMap; + +pub use reflect_macros::Reflect; + +pub trait Reflect: std::fmt::Debug { + fn reflect_type(&self) -> ReflectType; + fn type_name(&self) -> &str; + fn fields(&mut self) -> Vec<(&str, &mut dyn Reflect)>; + fn set_value(&mut self, value: ReflectValue); + fn get_value(&self) -> ReflectValue; + fn variants(&self) -> Vec<(&'static str, Box)>; + fn convert_variant(&mut self, i: usize); + fn unwrap_variant(&mut self) -> Option<(&str, &mut dyn Reflect)>; + fn as_vec(&mut self) -> Option>; + fn vec_add(&mut self) {} + fn vec_remove(&mut self) {} +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum ReflectType { + Value, + Enumeration, + Structure, +} + +pub enum ReflectValue { + None, + U8(u8), + U16(u16), + U32(u32), + U64(u64), + I8(i8), + I16(i16), + I32(i32), + I64(i64), + Vec(Vec), + Str(String), + Bool(bool), +} + +impl ReflectValue { + pub fn signed(&self) -> i64 { + match self { + ReflectValue::None => 0, + ReflectValue::U8(v) => *v as i64, + ReflectValue::U16(v) => *v as i64, + ReflectValue::U32(v) => *v as i64, + ReflectValue::U64(v) => *v as i64, + ReflectValue::I8(v) => *v as i64, + ReflectValue::I16(v) => *v as i64, + ReflectValue::I32(v) => *v as i64, + ReflectValue::I64(v) => *v as i64, + ReflectValue::Vec(_) => 0, + ReflectValue::Str(s) => { + if let Ok(v) = s.parse() { + v + } else { + 0 + } + } + ReflectValue::Bool(b) => { + if *b { + 1 + } else { + 0 + } + } + } + } + + pub fn unsigned(&self) -> u64 { + match self { + ReflectValue::None => 0, + ReflectValue::U8(v) => *v as u64, + ReflectValue::U16(v) => *v as u64, + ReflectValue::U32(v) => *v as u64, + ReflectValue::U64(v) => *v as u64, + ReflectValue::I8(v) => *v as u64, + ReflectValue::I16(v) => *v as u64, + ReflectValue::I32(v) => *v as u64, + ReflectValue::I64(v) => *v as u64, + ReflectValue::Vec(_) => 0, + ReflectValue::Str(s) => { + if let Ok(v) = s.parse() { + v + } else { + 0 + } + } + ReflectValue::Bool(b) => { + if *b { + 1 + } else { + 0 + } + } + } + } + + pub fn str(self) -> String { + match self { + ReflectValue::Str(s) => s, + ReflectValue::None => "".to_string(), + ReflectValue::U8(v) => v.to_string(), + ReflectValue::U16(v) => v.to_string(), + ReflectValue::U32(v) => v.to_string(), + ReflectValue::U64(v) => v.to_string(), + ReflectValue::I8(v) => v.to_string(), + ReflectValue::I16(v) => v.to_string(), + ReflectValue::I32(v) => v.to_string(), + ReflectValue::I64(v) => v.to_string(), + ReflectValue::Vec(_v) => "".to_string(), + ReflectValue::Bool(v) => v.to_string(), + } + } + + pub fn bool(&self) -> bool { + match self { + ReflectValue::None => false, + ReflectValue::U8(v) => *v == 0, + ReflectValue::U16(v) => *v == 0, + ReflectValue::U32(v) => *v == 0, + ReflectValue::U64(v) => *v == 0, + ReflectValue::I8(v) => *v == 0, + ReflectValue::I16(v) => *v == 0, + ReflectValue::I32(v) => *v == 0, + ReflectValue::I64(v) => *v == 0, + ReflectValue::Vec(_) => false, + ReflectValue::Str(_) => false, + ReflectValue::Bool(b) => *b, + } + } + + pub fn vec(self) -> Vec { + if let ReflectValue::Vec(v) = self { + v + } else { + Vec::new() + } + } +} + +pub fn path_set(reflect: &mut dyn Reflect, path: &str, value: ReflectValue) { + let mut next = reflect; + for p in path.split(".") { + let mut index = None; + for (i, f) in next.fields().iter().enumerate() { + if f.0 == p { + index = Some(i); + } + } + if let Some(i) = index { + next = next.fields().remove(i).1; + } else { + return; + } + } + next.set_value(value); +} + +pub fn path_get<'a>(reflect: &'a mut dyn Reflect, path: &str) -> Option<&'a mut dyn Reflect> { + let mut next = reflect; + for p in path.split(".") { + let mut index = None; + for (i, f) in next.fields().iter().enumerate() { + if f.0 == p { + index = Some(i); + } + } + if let Some(i) = index { + next = next.fields().remove(i).1; + } else { + return None; + } + } + Some(next) +} + +fn _flatten<'a>(reflect: &'a mut dyn Reflect) -> HashMap { + let mut list = HashMap::new(); + + match reflect.reflect_type() { + ReflectType::Value => match reflect.get_value() { + ReflectValue::Vec(_) => { + for (i, r) in reflect.as_vec().unwrap().into_iter().enumerate() { + let map = _flatten(r); + for (sn, v) in map { + list.insert(alloc::format!("[{i}].{}", sn), v); + } + } + } + _ => { + list.insert("".to_string(), reflect); + } + }, + ReflectType::Enumeration => { + if let Some((name, r)) = reflect.unwrap_variant() { + let map = _flatten(r); + for (sn, v) in map { + list.insert(alloc::format!("{}.{}", name, sn), v); + } + } + } + ReflectType::Structure => { + for (name, r) in reflect.fields() { + let map = _flatten(r); + for (sn, v) in map { + list.insert(alloc::format!("{}.{}", name, sn), v); + } + } + } + } + + list +} + +pub fn flatten<'a>(reflect: &'a mut dyn Reflect) -> HashMap { + _flatten(reflect) + .into_iter() + .map(|(k, v)| (k[..k.len() - 1].to_string().replace(".[", "["), v)) + .collect() +} + +impl Reflect for u8 { + fn reflect_type(&self) -> ReflectType { + ReflectType::Value + } + + fn type_name(&self) -> &str { + "u8" + } + + fn fields(&mut self) -> Vec<(&str, &mut dyn Reflect)> { + Vec::new() + } + + fn set_value(&mut self, value: ReflectValue) { + *self = value.unsigned() as Self; + } + + fn get_value(&self) -> ReflectValue { + ReflectValue::U8(*self) + } + + fn variants(&self) -> Vec<(&'static str, Box)> { + Vec::new() + } + + fn convert_variant(&mut self, _i: usize) {} + + fn unwrap_variant(&mut self) -> Option<(&str, &mut dyn Reflect)> { + None + } + + fn as_vec(&mut self) -> Option> { + None + } +} + +impl Reflect for u16 { + fn reflect_type(&self) -> ReflectType { + ReflectType::Value + } + + fn type_name(&self) -> &str { + "u16" + } + + fn fields(&mut self) -> Vec<(&str, &mut dyn Reflect)> { + Vec::new() + } + + fn set_value(&mut self, value: ReflectValue) { + *self = value.unsigned() as Self; + } + + fn get_value(&self) -> ReflectValue { + ReflectValue::U16(*self) + } + + fn variants(&self) -> Vec<(&'static str, Box)> { + Vec::new() + } + + fn convert_variant(&mut self, _i: usize) {} + + fn unwrap_variant(&mut self) -> Option<(&str, &mut dyn Reflect)> { + None + } + + fn as_vec(&mut self) -> Option> { + None + } +} + +impl Reflect for u32 { + fn reflect_type(&self) -> ReflectType { + ReflectType::Value + } + + fn type_name(&self) -> &str { + "u32" + } + + fn fields(&mut self) -> Vec<(&str, &mut dyn Reflect)> { + Vec::new() + } + + fn set_value(&mut self, value: ReflectValue) { + *self = value.unsigned() as Self; + } + + fn get_value(&self) -> ReflectValue { + ReflectValue::U32(*self) + } + + fn variants(&self) -> Vec<(&'static str, Box)> { + Vec::new() + } + + fn convert_variant(&mut self, _i: usize) {} + + fn unwrap_variant(&mut self) -> Option<(&str, &mut dyn Reflect)> { + None + } + + fn as_vec(&mut self) -> Option> { + None + } +} + +impl Reflect for u64 { + fn reflect_type(&self) -> ReflectType { + ReflectType::Value + } + + fn type_name(&self) -> &str { + "u64" + } + + fn fields(&mut self) -> Vec<(&str, &mut dyn Reflect)> { + Vec::new() + } + + fn set_value(&mut self, value: ReflectValue) { + *self = value.unsigned() as Self; + } + + fn get_value(&self) -> ReflectValue { + ReflectValue::U64(*self) + } + + fn variants(&self) -> Vec<(&'static str, Box)> { + Vec::new() + } + + fn convert_variant(&mut self, _i: usize) {} + + fn unwrap_variant(&mut self) -> Option<(&str, &mut dyn Reflect)> { + None + } + + fn as_vec(&mut self) -> Option> { + None + } +} + +impl Reflect for i8 { + fn reflect_type(&self) -> ReflectType { + ReflectType::Value + } + + fn type_name(&self) -> &str { + "i8" + } + + fn fields(&mut self) -> Vec<(&str, &mut dyn Reflect)> { + Vec::new() + } + + fn set_value(&mut self, value: ReflectValue) { + *self = value.signed() as Self; + } + + fn get_value(&self) -> ReflectValue { + ReflectValue::I8(*self) + } + + fn variants(&self) -> Vec<(&'static str, Box)> { + Vec::new() + } + + fn convert_variant(&mut self, _i: usize) {} + + fn unwrap_variant(&mut self) -> Option<(&str, &mut dyn Reflect)> { + None + } + + fn as_vec(&mut self) -> Option> { + None + } +} + +impl Reflect for i16 { + fn reflect_type(&self) -> ReflectType { + ReflectType::Value + } + + fn type_name(&self) -> &str { + "i16" + } + + fn fields(&mut self) -> Vec<(&str, &mut dyn Reflect)> { + Vec::new() + } + + fn set_value(&mut self, value: ReflectValue) { + *self = value.signed() as Self; + } + + fn get_value(&self) -> ReflectValue { + ReflectValue::I16(*self) + } + + fn variants(&self) -> Vec<(&'static str, Box)> { + Vec::new() + } + + fn convert_variant(&mut self, _i: usize) {} + + fn unwrap_variant(&mut self) -> Option<(&str, &mut dyn Reflect)> { + None + } + + fn as_vec(&mut self) -> Option> { + None + } +} + +impl Reflect for i32 { + fn reflect_type(&self) -> ReflectType { + ReflectType::Value + } + + fn type_name(&self) -> &str { + "i32" + } + + fn fields(&mut self) -> Vec<(&str, &mut dyn Reflect)> { + Vec::new() + } + + fn set_value(&mut self, value: ReflectValue) { + *self = value.signed() as Self; + } + + fn get_value(&self) -> ReflectValue { + ReflectValue::I32(*self) + } + + fn variants(&self) -> Vec<(&'static str, Box)> { + Vec::new() + } + + fn convert_variant(&mut self, _i: usize) {} + + fn unwrap_variant(&mut self) -> Option<(&str, &mut dyn Reflect)> { + None + } + + fn as_vec(&mut self) -> Option> { + None + } +} + +impl Reflect for i64 { + fn reflect_type(&self) -> ReflectType { + ReflectType::Value + } + + fn type_name(&self) -> &str { + "i64" + } + + fn fields(&mut self) -> Vec<(&str, &mut dyn Reflect)> { + Vec::new() + } + + fn set_value(&mut self, value: ReflectValue) { + *self = value.signed() as Self; + } + + fn get_value(&self) -> ReflectValue { + ReflectValue::I64(*self) + } + + fn variants(&self) -> Vec<(&'static str, Box)> { + Vec::new() + } + + fn convert_variant(&mut self, _i: usize) {} + + fn unwrap_variant(&mut self) -> Option<(&str, &mut dyn Reflect)> { + None + } + + fn as_vec(&mut self) -> Option> { + None + } +} + +impl Reflect for String { + fn reflect_type(&self) -> ReflectType { + ReflectType::Value + } + + fn type_name(&self) -> &str { + "str" + } + + fn fields(&mut self) -> Vec<(&str, &mut dyn Reflect)> { + Vec::new() + } + + fn set_value(&mut self, value: ReflectValue) { + *self = value.str(); + } + + fn get_value(&self) -> ReflectValue { + ReflectValue::Str(self.to_string()) + } + + fn variants(&self) -> Vec<(&'static str, Box)> { + Vec::new() + } + + fn convert_variant(&mut self, _i: usize) {} + + fn unwrap_variant(&mut self) -> Option<(&str, &mut dyn Reflect)> { + None + } + + fn as_vec(&mut self) -> Option> { + None + } +} + +impl Reflect for bool { + fn reflect_type(&self) -> ReflectType { + ReflectType::Value + } + + fn type_name(&self) -> &str { + "bool" + } + + fn fields(&mut self) -> Vec<(&str, &mut dyn Reflect)> { + Vec::new() + } + + fn set_value(&mut self, value: ReflectValue) { + *self = value.bool(); + } + + fn get_value(&self) -> ReflectValue { + ReflectValue::Bool(*self) + } + + fn variants(&self) -> Vec<(&'static str, Box)> { + Vec::new() + } + + fn convert_variant(&mut self, _i: usize) {} + + fn unwrap_variant(&mut self) -> Option<(&str, &mut dyn Reflect)> { + None + } + + fn as_vec(&mut self) -> Option> { + None + } +} + +impl Reflect for Vec { + fn reflect_type(&self) -> ReflectType { + ReflectType::Value + } + + fn type_name(&self) -> &str { + "vec[]" + } + + fn fields(&mut self) -> Vec<(&str, &mut dyn Reflect)> { + Vec::new() + } + + fn set_value(&mut self, value: ReflectValue) { + if let ReflectValue::Vec(v) = value { + *self = v + .into_iter() + .map(|x| { + let mut t: T = unsafe { zeroed() }; + t.set_value(x); + t + }) + .collect(); + } + } + + fn get_value(&self) -> ReflectValue { + ReflectValue::Vec(self.iter().map(|x| x.get_value()).collect()) + } + + fn variants(&self) -> Vec<(&'static str, Box)> { + Vec::new() + } + + fn convert_variant(&mut self, _i: usize) {} + + fn unwrap_variant(&mut self) -> Option<(&str, &mut dyn Reflect)> { + None + } + + fn as_vec<'a>(&'a mut self) -> Option> { + Some( + self.iter_mut() + .map(|x| { + let v: &mut dyn Reflect = x; + v + }) + .collect(), + ) + } + + fn vec_add(&mut self) { + self.push(Default::default()); + } + + fn vec_remove(&mut self) { + if self.len() > 0 { + self.remove(self.len() - 1); + } + } +} diff --git a/rfe/src/lib.rs b/rfe/src/lib.rs index 9035981..da50ee9 100644 --- a/rfe/src/lib.rs +++ b/rfe/src/lib.rs @@ -65,7 +65,7 @@ pub use rfe::*; /// Reflection module for runtime type information #[cfg(feature = "reflect")] -pub mod reflect; +pub use reflect; /// Macros for RFE pub use macros; diff --git a/rfe/src/msg/ds.rs b/rfe/src/msg/ds.rs index 359393b..a12507a 100644 --- a/rfe/src/msg/ds.rs +++ b/rfe/src/msg/ds.rs @@ -3,14 +3,12 @@ use bincode::{Decode, Encode}; extern crate alloc; use alloc::string::String; use alloc::vec::Vec; +use macros::msg; use super::{TlmSetId, TlmSetItem}; -use crate as rfe; -#[cfg(feature = "reflect")] -use crate::macros::Reflect; -#[derive(Debug, Default, Clone, PartialEq, Eq, Hash, Encode, Decode)] -#[cfg_attr(feature = "reflect", derive(Reflect))] +#[msg] +#[derive(Eq, Hash)] pub struct DsTlmSet { pub items: Vec, pub id: TlmSetId, @@ -18,23 +16,22 @@ pub struct DsTlmSet { pub path: String, } -#[derive(Debug, Default, Clone, Copy, PartialEq, Encode, Decode)] -#[cfg_attr(feature = "reflect", derive(Reflect))] +#[msg] +#[derive(Copy, Eq)] pub struct DsHk { pub perf: PerfData, pub counter: u32, } -#[derive(Debug, Default, Clone, Copy, PartialEq, Encode, Decode)] -#[cfg_attr(feature = "reflect", derive(Reflect))] +#[msg] +#[derive(Copy, Eq)] pub struct DsOutData { pub counter: u32, pub bytes_written: u32, pub bytes_written_this_cycle: u32, } -#[derive(Debug, Default, Clone, PartialEq, Encode, Decode)] -#[cfg_attr(feature = "reflect", derive(Reflect))] +#[msg] pub enum DsCmd { #[default] Noop, diff --git a/rfe/src/msg/example.rs b/rfe/src/msg/example.rs index af6dde5..19ab55f 100644 --- a/rfe/src/msg/example.rs +++ b/rfe/src/msg/example.rs @@ -1,25 +1,23 @@ extern crate alloc; -use crate as rfe; -#[cfg(feature = "reflect")] -use crate::macros::Reflect; use crate::utils::PerfData; use bincode::{Decode, Encode}; +use macros::msg; -#[derive(Debug, Default, Clone, Copy, PartialEq, Encode, Decode)] -#[cfg_attr(feature = "reflect", derive(Reflect))] +#[msg] +#[derive(Copy, Eq)] pub struct ExampleHk { pub perf: PerfData, pub counter: u32, } -#[derive(Debug, Default, Clone, Copy, PartialEq, Encode, Decode)] -#[cfg_attr(feature = "reflect", derive(Reflect))] +#[msg] +#[derive(Copy, Eq)] pub struct ExampleOutData { pub counter: u32, } -#[derive(Debug, Default, Clone, PartialEq, Encode, Decode)] -#[cfg_attr(feature = "reflect", derive(Reflect))] +#[msg] +#[derive(Copy, Eq)] pub enum ExampleCmd { #[default] Noop, diff --git a/rfe/src/msg/hs.rs b/rfe/src/msg/hs.rs index 0a7925c..4357c24 100644 --- a/rfe/src/msg/hs.rs +++ b/rfe/src/msg/hs.rs @@ -1,14 +1,11 @@ use crate::utils::PerfData; use bincode::{Decode, Encode}; +use macros::msg; extern crate alloc; -use crate as rfe; -#[cfg(feature = "reflect")] -use crate::macros::Reflect; use alloc::vec::Vec; -#[derive(Debug, Default, Clone, PartialEq, Encode, Decode)] -#[cfg_attr(feature = "reflect", derive(Reflect))] +#[msg] pub struct HsHk { pub perf: PerfData, pub counter: u32, @@ -22,14 +19,14 @@ pub struct HsHk { pub fs_usage_enabled: bool, } -#[derive(Debug, Default, Clone, Copy, PartialEq, Encode, Decode)] -#[cfg_attr(feature = "reflect", derive(Reflect))] +#[msg] +#[derive(Copy, Eq)] pub struct HsOutData { pub counter: u32, } -#[derive(Debug, Default, Clone, PartialEq, Encode, Decode)] -#[cfg_attr(feature = "reflect", derive(Reflect))] +#[msg] +#[derive(Copy, Eq)] pub enum HsCmd { #[default] Noop, diff --git a/rfe/src/msg/mod.rs b/rfe/src/msg/mod.rs index 98f45ad..0084497 100644 --- a/rfe/src/msg/mod.rs +++ b/rfe/src/msg/mod.rs @@ -3,7 +3,7 @@ extern crate alloc; use alloc::string::String; use alloc::vec::Vec; use bincode::{Decode, Encode}; -use macros::Kind; +use macros::{msg, Kind}; mod example; pub use example::*; @@ -14,13 +14,10 @@ pub use to::*; mod ds; pub use ds::*; -use crate as rfe; -#[cfg(feature = "reflect")] -use crate::macros::Reflect; use crate::time::Timestamp; -#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash, Encode, Decode)] -#[cfg_attr(feature = "reflect", derive(Reflect))] +#[msg] +#[derive(Copy, Eq, Hash)] pub struct TargetMsg { // instance is FROM for tlm, is TO for cmds pub instance: Instance, @@ -33,8 +30,8 @@ impl TargetMsg { } } -#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash, Encode, Decode)] -#[cfg_attr(feature = "reflect", derive(Reflect))] +#[msg] +#[derive(Copy, Eq, Hash)] pub enum Instance { #[default] None, @@ -44,8 +41,8 @@ pub enum Instance { Example2, } -#[derive(Debug, Default, Clone, PartialEq, Kind, Encode, Decode)] -#[cfg_attr(feature = "reflect", derive(Reflect))] +#[msg] +#[derive(Kind)] pub enum Msg { #[default] None, @@ -67,8 +64,7 @@ pub enum Msg { ToCmd(ToCmd), } -#[derive(Debug, Clone, PartialEq, Encode, Decode)] -#[cfg_attr(feature = "reflect", derive(Reflect))] +#[msg] pub struct MsgPacket { pub instance: Instance, pub msg: Msg, @@ -93,22 +89,20 @@ impl MsgPacket { } } -#[derive(Debug, Default, Clone, PartialEq, Encode, Decode)] -#[cfg_attr(feature = "reflect", derive(Reflect))] +#[msg] pub struct SubList { pub subs: Vec, } -#[derive(Debug, Default, Clone, PartialEq, Encode, Decode)] -#[cfg_attr(feature = "reflect", derive(Reflect))] +#[msg] pub struct ReinitAppCmd { app_name: String, } pub type TlmSetId = u16; -#[derive(Debug, Default, Clone, PartialEq, Eq, Hash, Encode, Decode)] -#[cfg_attr(feature = "reflect", derive(Reflect))] +#[msg] +#[derive(Copy, Eq, Hash)] pub struct TlmSetItem { pub target: TargetMsg, /// decimation 0 means sends every msg, decimation 1 means sends every other, etc diff --git a/rfe/src/msg/to.rs b/rfe/src/msg/to.rs index 1de42c1..76a1d47 100644 --- a/rfe/src/msg/to.rs +++ b/rfe/src/msg/to.rs @@ -1,36 +1,34 @@ use crate::utils::PerfData; use bincode::{Decode, Encode}; +use macros::msg; extern crate alloc; -use crate as rfe; -#[cfg(feature = "reflect")] -use crate::macros::Reflect; use alloc::vec::Vec; use super::{TlmSetId, TlmSetItem}; -#[derive(Debug, Default, Clone, PartialEq, Eq, Hash, Encode, Decode)] -#[cfg_attr(feature = "reflect", derive(Reflect))] +#[msg] +#[derive(Eq, Hash)] pub struct ToTlmSet { pub items: Vec, pub id: TlmSetId, pub enabled: bool, } -#[derive(Debug, Default, Clone, Copy, PartialEq, Encode, Decode)] -#[cfg_attr(feature = "reflect", derive(Reflect))] +#[msg] +#[derive(Copy, Eq)] pub struct ToHk { pub perf: PerfData, pub counter: u32, } -#[derive(Debug, Default, Clone, Copy, PartialEq, Encode, Decode)] -#[cfg_attr(feature = "reflect", derive(Reflect))] +#[msg] +#[derive(Copy, Eq)] pub struct ToOutData { pub counter: u32, } -#[derive(Debug, Default, Clone, PartialEq, Encode, Decode)] -#[cfg_attr(feature = "reflect", derive(Reflect))] +#[msg] +#[derive(Eq)] pub enum ToCmd { #[default] Noop, diff --git a/rfe/src/reflect.rs b/rfe/src/reflect.rs index 4870b9b..e69de29 100644 --- a/rfe/src/reflect.rs +++ b/rfe/src/reflect.rs @@ -1,649 +0,0 @@ -extern crate alloc; -use core::mem::zeroed; -use std::string::ToString; - -use alloc::boxed::Box; -use alloc::string::String; -use alloc::vec::Vec; -use hashbrown::HashMap; - -pub trait Reflect: std::fmt::Debug { - fn reflect_type(&self) -> ReflectType; - fn type_name(&self) -> &str; - fn fields(&mut self) -> Vec<(&str, &mut dyn Reflect)>; - fn set_value(&mut self, value: ReflectValue); - fn get_value(&self) -> ReflectValue; - fn variants(&self) -> Vec<(&'static str, Box)>; - fn convert_variant(&mut self, i: usize); - fn unwrap_variant(&mut self) -> Option<(&str, &mut dyn Reflect)>; - fn as_vec(&mut self) -> Option>; - fn vec_add(&mut self) {} - fn vec_remove(&mut self) {} -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum ReflectType { - Value, - Enumeration, - Structure, -} - -pub enum ReflectValue { - None, - U8(u8), - U16(u16), - U32(u32), - U64(u64), - I8(i8), - I16(i16), - I32(i32), - I64(i64), - Vec(Vec), - Str(String), - Bool(bool), -} - -impl ReflectValue { - pub fn signed(&self) -> i64 { - match self { - ReflectValue::None => 0, - ReflectValue::U8(v) => *v as i64, - ReflectValue::U16(v) => *v as i64, - ReflectValue::U32(v) => *v as i64, - ReflectValue::U64(v) => *v as i64, - ReflectValue::I8(v) => *v as i64, - ReflectValue::I16(v) => *v as i64, - ReflectValue::I32(v) => *v as i64, - ReflectValue::I64(v) => *v as i64, - ReflectValue::Vec(_) => 0, - ReflectValue::Str(s) => { - if let Ok(v) = s.parse() { - v - } else { - 0 - } - } - ReflectValue::Bool(b) => { - if *b { - 1 - } else { - 0 - } - } - } - } - - pub fn unsigned(&self) -> u64 { - match self { - ReflectValue::None => 0, - ReflectValue::U8(v) => *v as u64, - ReflectValue::U16(v) => *v as u64, - ReflectValue::U32(v) => *v as u64, - ReflectValue::U64(v) => *v as u64, - ReflectValue::I8(v) => *v as u64, - ReflectValue::I16(v) => *v as u64, - ReflectValue::I32(v) => *v as u64, - ReflectValue::I64(v) => *v as u64, - ReflectValue::Vec(_) => 0, - ReflectValue::Str(s) => { - if let Ok(v) = s.parse() { - v - } else { - 0 - } - } - ReflectValue::Bool(b) => { - if *b { - 1 - } else { - 0 - } - } - } - } - - pub fn str(self) -> String { - match self { - ReflectValue::Str(s) => s, - ReflectValue::None => "".to_string(), - ReflectValue::U8(v) => v.to_string(), - ReflectValue::U16(v) => v.to_string(), - ReflectValue::U32(v) => v.to_string(), - ReflectValue::U64(v) => v.to_string(), - ReflectValue::I8(v) => v.to_string(), - ReflectValue::I16(v) => v.to_string(), - ReflectValue::I32(v) => v.to_string(), - ReflectValue::I64(v) => v.to_string(), - ReflectValue::Vec(_v) => "".to_string(), - ReflectValue::Bool(v) => v.to_string(), - } - } - - pub fn bool(&self) -> bool { - match self { - ReflectValue::None => false, - ReflectValue::U8(v) => *v == 0, - ReflectValue::U16(v) => *v == 0, - ReflectValue::U32(v) => *v == 0, - ReflectValue::U64(v) => *v == 0, - ReflectValue::I8(v) => *v == 0, - ReflectValue::I16(v) => *v == 0, - ReflectValue::I32(v) => *v == 0, - ReflectValue::I64(v) => *v == 0, - ReflectValue::Vec(_) => false, - ReflectValue::Str(_) => false, - ReflectValue::Bool(b) => *b, - } - } - - pub fn vec(self) -> Vec { - if let ReflectValue::Vec(v) = self { - v - } else { - Vec::new() - } - } -} - -pub fn path_set(reflect: &mut dyn Reflect, path: &str, value: ReflectValue) { - let mut next = reflect; - for p in path.split(".") { - let mut index = None; - for (i, f) in next.fields().iter().enumerate() { - if f.0 == p { - index = Some(i); - } - } - if let Some(i) = index { - next = next.fields().remove(i).1; - } else { - return; - } - } - next.set_value(value); -} - -pub fn path_get<'a>(reflect: &'a mut dyn Reflect, path: &str) -> Option<&'a mut dyn Reflect> { - let mut next = reflect; - for p in path.split(".") { - let mut index = None; - for (i, f) in next.fields().iter().enumerate() { - if f.0 == p { - index = Some(i); - } - } - if let Some(i) = index { - next = next.fields().remove(i).1; - } else { - return None; - } - } - Some(next) -} - -fn _flatten<'a>(reflect: &'a mut dyn Reflect) -> HashMap { - let mut list = HashMap::new(); - - match reflect.reflect_type() { - ReflectType::Value => match reflect.get_value() { - ReflectValue::Vec(_) => { - for (i, r) in reflect.as_vec().unwrap().into_iter().enumerate() { - let map = _flatten(r); - for (sn, v) in map { - list.insert(alloc::format!("[{i}].{}", sn), v); - } - } - } - _ => { - list.insert("".to_string(), reflect); - } - }, - ReflectType::Enumeration => { - if let Some((name, r)) = reflect.unwrap_variant() { - let map = _flatten(r); - for (sn, v) in map { - list.insert(alloc::format!("{}.{}", name, sn), v); - } - } - } - ReflectType::Structure => { - for (name, r) in reflect.fields() { - let map = _flatten(r); - for (sn, v) in map { - list.insert(alloc::format!("{}.{}", name, sn), v); - } - } - } - } - - list -} - -pub fn flatten<'a>(reflect: &'a mut dyn Reflect) -> HashMap { - _flatten(reflect) - .into_iter() - .map(|(k, v)| (k[..k.len() - 1].to_string().replace(".[", "["), v)) - .collect() -} - -impl Reflect for u8 { - fn reflect_type(&self) -> ReflectType { - ReflectType::Value - } - - fn type_name(&self) -> &str { - "u8" - } - - fn fields(&mut self) -> Vec<(&str, &mut dyn Reflect)> { - Vec::new() - } - - fn set_value(&mut self, value: ReflectValue) { - *self = value.unsigned() as Self; - } - - fn get_value(&self) -> ReflectValue { - ReflectValue::U8(*self) - } - - fn variants(&self) -> Vec<(&'static str, Box)> { - Vec::new() - } - - fn convert_variant(&mut self, _i: usize) {} - - fn unwrap_variant(&mut self) -> Option<(&str, &mut dyn Reflect)> { - None - } - - fn as_vec(&mut self) -> Option> { - None - } -} - -impl Reflect for u16 { - fn reflect_type(&self) -> ReflectType { - ReflectType::Value - } - - fn type_name(&self) -> &str { - "u16" - } - - fn fields(&mut self) -> Vec<(&str, &mut dyn Reflect)> { - Vec::new() - } - - fn set_value(&mut self, value: ReflectValue) { - *self = value.unsigned() as Self; - } - - fn get_value(&self) -> ReflectValue { - ReflectValue::U16(*self) - } - - fn variants(&self) -> Vec<(&'static str, Box)> { - Vec::new() - } - - fn convert_variant(&mut self, _i: usize) {} - - fn unwrap_variant(&mut self) -> Option<(&str, &mut dyn Reflect)> { - None - } - - fn as_vec(&mut self) -> Option> { - None - } -} - -impl Reflect for u32 { - fn reflect_type(&self) -> ReflectType { - ReflectType::Value - } - - fn type_name(&self) -> &str { - "u32" - } - - fn fields(&mut self) -> Vec<(&str, &mut dyn Reflect)> { - Vec::new() - } - - fn set_value(&mut self, value: ReflectValue) { - *self = value.unsigned() as Self; - } - - fn get_value(&self) -> ReflectValue { - ReflectValue::U32(*self) - } - - fn variants(&self) -> Vec<(&'static str, Box)> { - Vec::new() - } - - fn convert_variant(&mut self, _i: usize) {} - - fn unwrap_variant(&mut self) -> Option<(&str, &mut dyn Reflect)> { - None - } - - fn as_vec(&mut self) -> Option> { - None - } -} - -impl Reflect for u64 { - fn reflect_type(&self) -> ReflectType { - ReflectType::Value - } - - fn type_name(&self) -> &str { - "u64" - } - - fn fields(&mut self) -> Vec<(&str, &mut dyn Reflect)> { - Vec::new() - } - - fn set_value(&mut self, value: ReflectValue) { - *self = value.unsigned() as Self; - } - - fn get_value(&self) -> ReflectValue { - ReflectValue::U64(*self) - } - - fn variants(&self) -> Vec<(&'static str, Box)> { - Vec::new() - } - - fn convert_variant(&mut self, _i: usize) {} - - fn unwrap_variant(&mut self) -> Option<(&str, &mut dyn Reflect)> { - None - } - - fn as_vec(&mut self) -> Option> { - None - } -} - -impl Reflect for i8 { - fn reflect_type(&self) -> ReflectType { - ReflectType::Value - } - - fn type_name(&self) -> &str { - "i8" - } - - fn fields(&mut self) -> Vec<(&str, &mut dyn Reflect)> { - Vec::new() - } - - fn set_value(&mut self, value: ReflectValue) { - *self = value.signed() as Self; - } - - fn get_value(&self) -> ReflectValue { - ReflectValue::I8(*self) - } - - fn variants(&self) -> Vec<(&'static str, Box)> { - Vec::new() - } - - fn convert_variant(&mut self, _i: usize) {} - - fn unwrap_variant(&mut self) -> Option<(&str, &mut dyn Reflect)> { - None - } - - fn as_vec(&mut self) -> Option> { - None - } -} - -impl Reflect for i16 { - fn reflect_type(&self) -> ReflectType { - ReflectType::Value - } - - fn type_name(&self) -> &str { - "i16" - } - - fn fields(&mut self) -> Vec<(&str, &mut dyn Reflect)> { - Vec::new() - } - - fn set_value(&mut self, value: ReflectValue) { - *self = value.signed() as Self; - } - - fn get_value(&self) -> ReflectValue { - ReflectValue::I16(*self) - } - - fn variants(&self) -> Vec<(&'static str, Box)> { - Vec::new() - } - - fn convert_variant(&mut self, _i: usize) {} - - fn unwrap_variant(&mut self) -> Option<(&str, &mut dyn Reflect)> { - None - } - - fn as_vec(&mut self) -> Option> { - None - } -} - -impl Reflect for i32 { - fn reflect_type(&self) -> ReflectType { - ReflectType::Value - } - - fn type_name(&self) -> &str { - "i32" - } - - fn fields(&mut self) -> Vec<(&str, &mut dyn Reflect)> { - Vec::new() - } - - fn set_value(&mut self, value: ReflectValue) { - *self = value.signed() as Self; - } - - fn get_value(&self) -> ReflectValue { - ReflectValue::I32(*self) - } - - fn variants(&self) -> Vec<(&'static str, Box)> { - Vec::new() - } - - fn convert_variant(&mut self, _i: usize) {} - - fn unwrap_variant(&mut self) -> Option<(&str, &mut dyn Reflect)> { - None - } - - fn as_vec(&mut self) -> Option> { - None - } -} - -impl Reflect for i64 { - fn reflect_type(&self) -> ReflectType { - ReflectType::Value - } - - fn type_name(&self) -> &str { - "i64" - } - - fn fields(&mut self) -> Vec<(&str, &mut dyn Reflect)> { - Vec::new() - } - - fn set_value(&mut self, value: ReflectValue) { - *self = value.signed() as Self; - } - - fn get_value(&self) -> ReflectValue { - ReflectValue::I64(*self) - } - - fn variants(&self) -> Vec<(&'static str, Box)> { - Vec::new() - } - - fn convert_variant(&mut self, _i: usize) {} - - fn unwrap_variant(&mut self) -> Option<(&str, &mut dyn Reflect)> { - None - } - - fn as_vec(&mut self) -> Option> { - None - } -} - -impl Reflect for String { - fn reflect_type(&self) -> ReflectType { - ReflectType::Value - } - - fn type_name(&self) -> &str { - "str" - } - - fn fields(&mut self) -> Vec<(&str, &mut dyn Reflect)> { - Vec::new() - } - - fn set_value(&mut self, value: ReflectValue) { - *self = value.str(); - } - - fn get_value(&self) -> ReflectValue { - ReflectValue::Str(self.to_string()) - } - - fn variants(&self) -> Vec<(&'static str, Box)> { - Vec::new() - } - - fn convert_variant(&mut self, _i: usize) {} - - fn unwrap_variant(&mut self) -> Option<(&str, &mut dyn Reflect)> { - None - } - - fn as_vec(&mut self) -> Option> { - None - } -} - -impl Reflect for bool { - fn reflect_type(&self) -> ReflectType { - ReflectType::Value - } - - fn type_name(&self) -> &str { - "bool" - } - - fn fields(&mut self) -> Vec<(&str, &mut dyn Reflect)> { - Vec::new() - } - - fn set_value(&mut self, value: ReflectValue) { - *self = value.bool(); - } - - fn get_value(&self) -> ReflectValue { - ReflectValue::Bool(*self) - } - - fn variants(&self) -> Vec<(&'static str, Box)> { - Vec::new() - } - - fn convert_variant(&mut self, _i: usize) {} - - fn unwrap_variant(&mut self) -> Option<(&str, &mut dyn Reflect)> { - None - } - - fn as_vec(&mut self) -> Option> { - None - } -} - -impl Reflect for Vec { - fn reflect_type(&self) -> ReflectType { - ReflectType::Value - } - - fn type_name(&self) -> &str { - "vec[]" - } - - fn fields(&mut self) -> Vec<(&str, &mut dyn Reflect)> { - Vec::new() - } - - fn set_value(&mut self, value: ReflectValue) { - if let ReflectValue::Vec(v) = value { - *self = v - .into_iter() - .map(|x| { - let mut t: T = unsafe { zeroed() }; - t.set_value(x); - t - }) - .collect(); - } - } - - fn get_value(&self) -> ReflectValue { - ReflectValue::Vec(self.iter().map(|x| x.get_value()).collect()) - } - - fn variants(&self) -> Vec<(&'static str, Box)> { - Vec::new() - } - - fn convert_variant(&mut self, _i: usize) {} - - fn unwrap_variant(&mut self) -> Option<(&str, &mut dyn Reflect)> { - None - } - - fn as_vec<'a>(&'a mut self) -> Option> { - Some( - self.iter_mut() - .map(|x| { - let v: &mut dyn Reflect = x; - v - }) - .collect(), - ) - } - - fn vec_add(&mut self) { - self.push(Default::default()); - } - - fn vec_remove(&mut self) { - if self.len() > 0 { - self.remove(self.len() - 1); - } - } -} diff --git a/rfe/src/rfe.rs b/rfe/src/rfe.rs index 4cdf567..c09156d 100644 --- a/rfe/src/rfe.rs +++ b/rfe/src/rfe.rs @@ -415,17 +415,17 @@ impl<'a> RfeInstance<'a> { // Run applications and collect messages for app in self.app_list.values_mut() { // Check if the application should run at this tick - if self.should_run_at_rate(app.app_rate) { + if Self::should_run_at_rate(self.sch_counter, app.app_rate) { app.app.run(&mut app.rfe); } // Check if housekeeping should run at this tick - if self.should_run_at_rate(app.hk_rate) { + if Self::should_run_at_rate(self.sch_counter, app.hk_rate) { app.app.hk(&mut app.rfe); } // Check if output data should run at this tick - if self.should_run_at_rate(app.out_data_rate) { + if Self::should_run_at_rate(self.sch_counter, app.out_data_rate) { app.app.out_data(&mut app.rfe); } @@ -568,14 +568,14 @@ impl<'a> RfeInstance<'a> { /// # Returns /// * `true` - If the task should run at this tick /// * `false` - If the task should not run at this tick - fn should_run_at_rate(&self, rate: Rate) -> bool { + fn should_run_at_rate(sch_counter: u64, rate: Rate) -> bool { match rate { Rate::Hz100 => true, - Rate::Hz50 => self.sch_counter % 2 == 0, - Rate::Hz20 => self.sch_counter % 5 == 0, - Rate::Hz10 => self.sch_counter % 10 == 0, - Rate::Hz5 => self.sch_counter % 20 == 0, - Rate::Hz1 => self.sch_counter % 100 == 0, + Rate::Hz50 => sch_counter % 2 == 0, + Rate::Hz20 => sch_counter % 5 == 0, + Rate::Hz10 => sch_counter % 10 == 0, + Rate::Hz5 => sch_counter % 20 == 0, + Rate::Hz1 => sch_counter % 100 == 0, } } diff --git a/rfe/src/utils.rs b/rfe/src/utils.rs index ddd88ca..715f2a6 100644 --- a/rfe/src/utils.rs +++ b/rfe/src/utils.rs @@ -1,16 +1,12 @@ -use crate::time::Timestamp; use crate::Rfe; +use crate::time::Timestamp; use bincode::{Decode, Encode}; +use macros::msg; extern crate alloc; -use crate as rfe; -#[cfg(feature = "reflect")] -use crate::macros::Reflect; - -#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash, Encode, Decode)] -#[cfg_attr(feature = "reflect", derive(Reflect))] - +#[msg] +#[derive(Copy, Eq, Hash)] pub struct PerfData { enter_time: Timestamp, elapsed: u32, diff --git a/tools/decom/Cargo.toml b/tools/decom/Cargo.toml index fc628ba..53caa7b 100644 --- a/tools/decom/Cargo.toml +++ b/tools/decom/Cargo.toml @@ -11,5 +11,7 @@ path = "src/decom.rs" anyhow.workspace = true log.workspace = true simple_logger.workspace = true -rfe = { path = "../../rfe", features = ["reflect"] } +rfe = { path = "../../rfe", features = ["serde"] } bincode = { workspace = true, features = ["std"] } +serde_json = "1.0.140" +clap = { version = "4.5.35", features = ["derive"] } diff --git a/tools/decom/src/decom.rs b/tools/decom/src/decom.rs index bcf1400..192ae8e 100644 --- a/tools/decom/src/decom.rs +++ b/tools/decom/src/decom.rs @@ -1,7 +1,6 @@ #![feature(bufreader_peek)] use std::{ collections::HashMap, - env::args, fs::{read_dir, OpenOptions}, io::{BufReader, Write}, path::PathBuf, @@ -15,6 +14,17 @@ use log::*; use rfe::{msg::MsgPacket, BINCODE_CONFIG}; use simple_logger::SimpleLogger; +use clap::Parser; + +// Decom DS recorded data files +#[derive(Parser, Debug)] +struct CliArgs { + /// The path to the file or folder containing the DS data + path: String, + /// The path to the folder to output the decommed data + out_dir: String, +} + fn decom_file(file_path: String, out_dir: String) -> Result<()> { info!("decomming {file_path}"); let f = OpenOptions::new().read(true).open(file_path)?; @@ -29,40 +39,25 @@ fn decom_file(file_path: String, out_dir: String) -> Result<()> { }; if !files.contains_key(&msg.msg.kind()) { let path = PathBuf::from_str(&out_dir)? - .join(format!("{:?}.csv", msg.msg.kind()).to_lowercase()); - let exists = path.exists(); - let mut w = OpenOptions::new() + .join(format!("{:?}.json", msg.msg.kind()).to_lowercase()); + let w = OpenOptions::new() .write(true) .create(true) .append(true) .open(path)?; - if !exists { - let values = msg.to_csv_clean(); - let mut line = values - .iter() - .map(|x| x.split_once(" = ").expect("unexpected csv data").0) - .collect::>() - .join(","); - line += "\n"; - w.write(line.as_bytes())?; - } - files.insert(msg.msg.kind(), w); } if let Some(w) = files.get_mut(&msg.msg.kind()) { - let values = msg.to_csv_clean(); - let mut line = values - .iter() - .map(|x| x.split_once(" = ").expect("unexpected csv data").1) - .collect::>() - .join(","); - line += "\n"; - w.write(line.as_bytes())?; + let values = serde_json::to_string(&msg)?; + + w.write(values.as_bytes())?; + w.write("\n".as_bytes())?; } } } + return Ok(()); } @@ -99,13 +94,9 @@ fn decom_task(folder: String, out_dir: String) -> Result<()> { fn main() -> Result<()> { SimpleLogger::new().init().unwrap(); + let args = CliArgs::parse(); info!("started decom"); - - let args = args().skip(1).collect::>(); - let folder = args[0].clone(); - let out_dir = args[1].clone(); - - decom_task(folder, out_dir)?; + decom_task(args.path, args.out_dir)?; info!("finished decom"); return Ok(());