diff --git a/examples/simple/src/main.rs b/examples/simple/src/main.rs index 48401de..2a72e7c 100644 --- a/examples/simple/src/main.rs +++ b/examples/simple/src/main.rs @@ -7,6 +7,11 @@ use defmt_rtt as _; use panic_halt as _; use probe_plotter::{make_metric, make_setting}; +#[derive(probe_plotter::metric::Metricable)] +struct Foo { + x: u8, +} + #[entry] fn main() -> ! { defmt::println!("Running..."); diff --git a/macros/Cargo.lock b/macros/Cargo.lock index 2a83371..90ecf87 100644 --- a/macros/Cargo.lock +++ b/macros/Cargo.lock @@ -2,15 +2,38 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "itoa" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" + [[package]] name = "macros" version = "0.1.0" dependencies = [ + "probe-plotter-common", "proc-macro2", "quote", + "serde", + "serde_json", "syn", ] +[[package]] +name = "memchr" +version = "2.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" + +[[package]] +name = "probe-plotter-common" +version = "0.1.0" +dependencies = [ + "serde", + "serde_json", +] + [[package]] name = "proc-macro2" version = "1.0.95" @@ -29,6 +52,55 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "ryu" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.145" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", + "serde_core", +] + [[package]] name = "syn" version = "2.0.104" diff --git a/macros/Cargo.toml b/macros/Cargo.toml index 708eec7..6dea50e 100644 --- a/macros/Cargo.toml +++ b/macros/Cargo.toml @@ -7,6 +7,9 @@ edition = "2024" proc-macro2 = "1.0.95" quote = "1.0.40" syn = { version = "2", features = ["full"] } +probe-plotter-common = { path = "../probe-plotter-common" } +serde = { version = "1.0.219", features = ["derive"] } +serde_json = "1.0.141" [lib] -proc-macro = true +proc-macro = true \ No newline at end of file diff --git a/macros/src/lib.rs b/macros/src/lib.rs index 8673eeb..aab40ee 100644 --- a/macros/src/lib.rs +++ b/macros/src/lib.rs @@ -64,6 +64,10 @@ pub fn make_metric(args: TokenStream) -> TokenStream { .into() } +/*pub fn make_inplace_thing(args: TokenStream) -> TokenStream { + +}*/ + /// Create a Setting instance that will be shown as a slider in the probe-plotter utility /// /// ``` @@ -128,3 +132,59 @@ fn hash(string: &str) -> u64 { string.hash(&mut hasher); hasher.finish() } + +/// +/// ``` +/// #[derive(Plottable)] +/// struct Foo { +/// #[metric("bar / 33.1")] +/// bar: u8, +/// +/// baz: Baz, +/// +/// #[setting(0..=3, 1)] +/// quix: f32 +/// } +/// +/// #[derive(Plottable)] +/// struct Baz { +/// #[metric("a * 3.0")] +/// a: i16 +/// } +/// ``` +#[proc_macro_derive(Plottable)] +pub fn impl_metricable(input: TokenStream) -> TokenStream { + // TODO: Probably require repr(C)? + // TODO: Require all fields to also impl Metricable + let ast: syn::ItemStruct = syn::parse(input).unwrap(); + let fields = ast.fields; + let name = &ast.ident; + + let fields: Vec<_> = fields + .iter() + .map(|f| { + let ty = &f.ty; + probe_plotter_common::symbol::Member { + name: f.ident.as_ref().unwrap().to_string(), + ty: quote!(#ty).to_string(), + offset: None, + }}) + .collect(); + + // TODO: move the static into some linker section so it does not occupy flash space + // TODO: handle module paths and name spaces + let sym_name = serde_json::to_string(&probe_plotter_common::symbol::Symbol::Type { + name: name.to_string(), + fields, + }) + .unwrap(); + + quote! { + unsafe impl ::probe_plotter::metric::Metricable for #name {} + + #[allow(non_upper_case_globals)] + #[unsafe(export_name = #sym_name)] + static #name: u8 = 0; + } + .into() +} diff --git a/probe-plotter-common/Cargo.toml b/probe-plotter-common/Cargo.toml new file mode 100644 index 0000000..7910c6f --- /dev/null +++ b/probe-plotter-common/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "probe-plotter-common" +version = "0.1.0" +edition = "2024" +publish = ["gitea"] + +[dependencies] +serde = { version = "1.0.219", features = ["derive"] } +serde_json = "1.0.141" +shunting = { git = "https://github.com/usbalbin/tox", branch = "add-ln" } \ No newline at end of file diff --git a/probe-plotter-common/src/lib.rs b/probe-plotter-common/src/lib.rs new file mode 100644 index 0000000..f67c19f --- /dev/null +++ b/probe-plotter-common/src/lib.rs @@ -0,0 +1,135 @@ +use std::{collections::HashMap, fmt::Display}; + +pub mod symbol; + +#[allow(non_camel_case_types)] +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, Copy, PartialEq, Hash, Eq)] +pub enum PrimitiveType { + u8, + u16, + u32, + i8, + i16, + i32, + f32, +} + +#[derive(serde::Serialize, serde::Deserialize, PartialEq, Clone, Hash, Eq)] +pub struct Atype(String); + +impl Display for Atype { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.0.fmt(f) + } +} + +pub type Types = HashMap; + +pub enum TypeDef { + Struct { + name: Atype, + fields: Vec, + }, + Enum { + name: Atype, + discriminator_type: PrimitiveType, + variants: Vec, + }, +} + +impl TypeDef { + fn size_of(&self, types: &Types) -> u64 { + match self { + TypeDef::Struct { name, fields } => fields + .last() + .map(|x| { + x.offset.unwrap().next_multiple_of(x.ty.align_of(&types)) + x.ty.size_of(&types) + }) + .unwrap_or(0), + TypeDef::Enum { + name, + discriminator_type, + variants, + } => todo!(), + } + } + + fn align_of(&self, _types: &Types) -> u64 { + todo!() + } +} + +pub struct EnumVariant { + pub name: String, + pub ty: PrimitiveType, + pub expr: shunting::RPNExpr, +} + +impl Atype { + pub fn is_primitive(&self) -> bool { + ["u8", "u16", "u32", "i8", "i16", "i32", "f32"].contains(&self.0.as_ref()) + } + + pub fn size_of(&self, types: &Types) -> u64 { + match PrimitiveType::try_from(self) { + Ok(p) => p.size_of(), + Err(()) => types.get(self).unwrap().size_of(types), + } + } + + pub fn align_of(&self, types: &Types) -> u64 { + match PrimitiveType::try_from(self) { + Ok(p) => p.align_of(), + Err(()) => types.get(self).unwrap().size_of(types), + } + } +} + +impl TryFrom<&Atype> for PrimitiveType { + type Error = (); + + fn try_from(t: &Atype) -> Result { + match t.0.as_str() { + "u8" => Ok(PrimitiveType::u8), + "u16" => Ok(PrimitiveType::u16), + "u32" => Ok(PrimitiveType::u32), + "i8" => Ok(PrimitiveType::i8), + "i16" => Ok(PrimitiveType::i16), + "i32" => Ok(PrimitiveType::i32), + "f32" => Ok(PrimitiveType::f32), + _ => Err(()), + } + } +} + +impl PrimitiveType { + pub fn size_of(&self) -> u64 { + match self { + PrimitiveType::u8 | PrimitiveType::i8 => 1, + PrimitiveType::u16 | PrimitiveType::i16 => 2, + PrimitiveType::u32 | PrimitiveType::i32 | PrimitiveType::f32 => 4, + } + } + + pub fn align_of(&self) -> u64 { + match self { + PrimitiveType::u8 | PrimitiveType::i8 => 1, + PrimitiveType::u16 | PrimitiveType::i16 => 2, + PrimitiveType::u32 | PrimitiveType::i32 | PrimitiveType::f32 => 4, + } + } +} + +impl Into for &PrimitiveType { + fn into(self) -> Atype { + match self { + PrimitiveType::u8 => Atype("u8".to_string()), + PrimitiveType::u16 => Atype("u16".to_string()), + PrimitiveType::u32 => Atype("u32".to_string()), + PrimitiveType::i8 => Atype("i8".to_string()), + PrimitiveType::i16 => Atype("i16".to_string()), + PrimitiveType::i32 => Atype("i32".to_string()), + PrimitiveType::f32 => Atype("f32".to_string()), + } + } +} diff --git a/probe-plotter-tools/src/symbol.rs b/probe-plotter-common/src/symbol.rs similarity index 57% rename from probe-plotter-tools/src/symbol.rs rename to probe-plotter-common/src/symbol.rs index 618b56c..d462314 100644 --- a/probe-plotter-tools/src/symbol.rs +++ b/probe-plotter-common/src/symbol.rs @@ -1,9 +1,8 @@ -use serde::Deserialize; use std::ops::RangeInclusive; -use crate::Type; +use crate::{Atype, PrimitiveType}; -#[derive(Deserialize, PartialEq)] +#[derive(serde::Serialize, serde::Deserialize, PartialEq)] #[serde(tag = "type")] pub enum Symbol { Metric { @@ -13,13 +12,13 @@ pub enum Symbol { expr: String, /// Type of value, i32, u8 etc. - ty: Type, + ty: Atype, }, Setting { name: String, /// Type of value, i32, u8 etc. - ty: Type, + ty: PrimitiveType, /// Range of valid values range: RangeInclusive, @@ -27,6 +26,12 @@ pub enum Symbol { /// Step size step_size: f64, }, + + // {"type":"Type",""ty":"{name}", fields: [{fields}]} + Type { + name: Atype, + fields: Vec, + }, } impl Symbol { @@ -34,12 +39,14 @@ impl Symbol { match self { Symbol::Metric { name, .. } => name, Symbol::Setting { name, .. } => name, + _ => todo!(), } } - pub fn ty(&self) -> Type { + pub fn ty(&self) -> Atype { match self { - Symbol::Metric { ty, .. } => *ty, - Symbol::Setting { ty, .. } => *ty, + Symbol::Metric { ty, .. } => ty.clone(), + Symbol::Setting { ty, .. } => ty.into(), + Symbol::Type { name, .. } => name.clone(), } } } @@ -52,3 +59,10 @@ impl Symbol { serde_json::from_str(raw).map_err(|_| InvalidSymbolError) } } + +#[derive(serde::Serialize, serde::Deserialize, PartialEq)] +pub struct Member { + pub name: String, + pub ty: Atype, + pub offset: Option, +} diff --git a/probe-plotter-tools/Cargo.toml b/probe-plotter-tools/Cargo.toml index 34c6150..4ec819a 100644 --- a/probe-plotter-tools/Cargo.toml +++ b/probe-plotter-tools/Cargo.toml @@ -22,3 +22,4 @@ mimalloc = "0.1.43" shunting = { git = "https://github.com/usbalbin/tox", branch = "add-ln" } defmt-decoder = "1.0.0" defmt-parser = "1.0.0" +probe-plotter-common = { path = "../probe-plotter-common" } \ No newline at end of file diff --git a/probe-plotter-tools/src/lib.rs b/probe-plotter-tools/src/lib.rs index d8701eb..5136b49 100644 --- a/probe-plotter-tools/src/lib.rs +++ b/probe-plotter-tools/src/lib.rs @@ -1,9 +1,9 @@ pub mod gui; pub mod metric; pub mod setting; -pub mod symbol; -use std::{io::Read, sync::mpsc, time::Duration}; +use probe_plotter_common::{symbol::{self, Member}, Atype, PrimitiveType, TypeDef}; +use std::{collections::HashMap, io::Read, sync::mpsc, time::Duration}; use defmt_decoder::DecodeError; use defmt_parser::Level; @@ -13,37 +13,46 @@ use probe_rs::{ rtt::{self, ChannelMode, Rtt}, }; use rerun::TextLogLevel; -use serde::Deserialize; use shunting::{MathContext, ShuntingParser}; use crate::{metric::Metric, setting::Setting, symbol::Symbol}; -pub fn read_value(core: &mut Core, address: u64, ty: Type) -> Result { + +pub fn read_value(core: &mut Core, address: u64, ty: PrimitiveType) -> Result { let x = match ty { - Type::u8 => core.read_word_8(address)? as f64, - Type::u16 => core.read_word_16(address)? as f64, - Type::u32 => core.read_word_32(address)? as f64, + PrimitiveType::u8 => core.read_word_8(address)? as f64, + PrimitiveType::u16 => core.read_word_16(address)? as f64, + PrimitiveType::u32 => core.read_word_32(address)? as f64, - Type::i8 => core.read_word_8(address)? as i8 as f64, - Type::i16 => core.read_word_16(address)? as i16 as f64, - Type::i32 => core.read_word_32(address)? as i32 as f64, + PrimitiveType::i8 => core.read_word_8(address)? as i8 as f64, + PrimitiveType::i16 => core.read_word_16(address)? as i16 as f64, + PrimitiveType::i32 => core.read_word_32(address)? as i32 as f64, - Type::f32 => f32::from_bits(core.read_word_32(address)?) as f64, + PrimitiveType::f32 => f32::from_bits(core.read_word_32(address)?) as f64, }; Ok(x) } -#[allow(non_camel_case_types)] -#[derive(Deserialize, Debug, Clone, Copy, PartialEq, Hash, Eq)] -pub enum Type { - u8, - u16, - u32, - i8, - i16, - i32, - f32, +pub fn read_from_slice(slice: &[u8], offset: u64, ty: PrimitiveType) -> f64 { + let offset = offset as usize; + match ty { + PrimitiveType::u8 => slice[offset] as f64, + PrimitiveType::u16 => u16::from_le_bytes(slice[offset..(offset + 2)].try_into().unwrap()) as f64, + PrimitiveType::u32 => u32::from_le_bytes(slice[offset..(offset + 4)].try_into().unwrap()) as f64, + + PrimitiveType::i8 => slice[offset] as i8 as f64, + PrimitiveType::i16 => { + u16::from_le_bytes(slice[offset..(offset + 2)].try_into().unwrap()) as i16 as f64 + } + PrimitiveType::i32 => { + u32::from_le_bytes(slice[offset..(offset + 4)].try_into().unwrap()) as i32 as f64 + } + + PrimitiveType::f32 => f32::from_bits(u32::from_le_bytes( + slice[offset..(offset + 4)].try_into().unwrap(), + )) as f64, + } } // Most of this is taken from https://github.com/knurling-rs/defmt/blob/8e517f8d7224237893e39337a61de8ef98b341f2/decoder/src/elf2table/mod.rs and modified @@ -69,6 +78,8 @@ pub fn parse(elf_bytes: &[u8]) -> (Vec, Vec, rtt::ScanRegion) { continue; }; + let mut types = HashMap::new(); + // TODO: Why does this assert not succeed? //assert_eq!(entry.size(), 4); match sym { @@ -79,13 +90,38 @@ pub fn parse(elf_bytes: &[u8]) -> (Vec, Vec, rtt::ScanRegion) { math_ctx .eval(&expr) .expect("Use the metrics name as name for the value in the expression"); - metrics.push(Metric { - name, - expr, - ty, - address: entry.address(), - last_value: f64::NAN, - }); + let address = entry.address(); + + if let Ok(ty) = (&ty).try_into() { + metrics.push(Metric::Primitive { + name, + expr, + ty, + address, + last_value: f64::NAN, + }); + } else { + let x = types + .get(&ty) + .expect(&format!("Undefined type: '{name}'")); + + match x { + TypeDef::Struct { name, fields } => todo!(), + TypeDef::Enum { + name: ty, + discriminator_type, + variants, + } => metrics.push(Metric::Enum { + name, + ty: ty.clone(), + address, + discriminator_type: (), + last_discriminator_value: (), + data_variants: (), + max_size: (), + }), + } + } } Symbol::Setting { name, @@ -102,6 +138,76 @@ pub fn parse(elf_bytes: &[u8]) -> (Vec, Vec, rtt::ScanRegion) { step_size, }); } + Symbol::Type { name, fields } => { + assert!( + types + .insert(name.clone(), TypeDef::Struct { name, fields }) + .is_none(), + "Type '{name}' already defined" + ); + } + } + + enum MetricIn { + Primitive { + name: String, + ty: Type, + address: u32, + + expr: shunting::RPNExpr, + }, + Struct { + name: String, + ty: Type, + address: u32, + + fields: Vec, + }, + Enum { + name: String, + ty: Type, + address: u32, + + discriminator_type: Type, + data_variants: Vec, + }, + } + + fn check_type( + name: String, + ty: Type, + base_address: u32, + metrics: &mut Vec, + types: &HashMap, + ) { + if ty.is_primitive() { + metrics.push(Metric::Primitive { + name, + expr: todo!(), + ty, + address: todo!(), + last_value: todo!(), + }); + return; + } + + let t = types.get(&m.ty).expect("Undefined type"); + + match t { + TypeDef::Struct { name, fields } => { + for f in fields { + let base_address = base_address + f.offset.unwrap(); + check_type(f.name, f.ty, base_address, metrics, types); + } + } + } + } + + for m in &metrics { + //custom { + check_type(m); + + metrics.push(m.ty.clone()); } } diff --git a/probe-plotter-tools/src/metric.rs b/probe-plotter-tools/src/metric.rs index 80e656b..153ab41 100644 --- a/probe-plotter-tools/src/metric.rs +++ b/probe-plotter-tools/src/metric.rs @@ -1,17 +1,11 @@ +use probe_plotter_common::{Atype, PrimitiveType, Types}; +use probe_rs::MemoryInterface; +use rerun::external::egui::ahash::HashMap; use shunting::MathContext; -use std::fmt; -use crate::{Type, read_value}; +use crate::{read_from_slice, read_value}; -pub struct Metric { - pub name: String, - pub expr: shunting::RPNExpr, - pub ty: Type, - pub address: u64, - pub last_value: f64, -} - -impl fmt::Debug for Metric { +/*impl fmt::Debug for Metric { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("Metric") .field("name", &self.name) @@ -20,33 +14,173 @@ impl fmt::Debug for Metric { .field("address", &self.address) .finish() } -} +}*/ pub enum Status { SameAsLast, New, } +pub enum Metric { + Primitive { + name: String, + ty: PrimitiveType, + address: u64, + + last_value: f64, + expr: shunting::RPNExpr, + }, + Enum { + name: String, + ty: Atype, + address: u64, + + discriminator_type: PrimitiveType, + last_discriminator_value: u32, + data_variants: Vec, + max_size: u64, + }, +} + +struct EnumVariant { + name: String, + ty: Atype, + expr: shunting::RPNExpr, + last_value: f64, +} + impl Metric { pub fn read( &mut self, core: &mut probe_rs::Core, math_ctx: &mut MathContext, + types: &Types ) -> Result<(), probe_rs::Error> { - let x = read_value(core, self.address, self.ty)?; - math_ctx.setvar(&self.name, shunting::MathOp::Number(x)); + match self { + Metric::Primitive { + name, + ty, + address, + last_value: _, + expr: _, + } => { + let x = read_value(core, *address, *ty)?; + math_ctx.setvar(&name, shunting::MathOp::Number(x)); + + Ok(()) + } + Metric::Enum { + name, + ty, + address, + discriminator_type, + last_discriminator_value, + data_variants, + max_size, + } => { + let read_first_part = + |core: &mut probe_rs::Core| -> Result, probe_rs::Error> { + Ok(match max_size { + 0 => vec![], + 1 => core.read_word_8(*address)?.to_le_bytes().to_vec(), + 2 => core.read_word_16(*address)?.to_le_bytes().to_vec(), + 3 => core.read_word_32(*address)?.to_le_bytes()[..3].to_vec(), + _ => core.read_word_32(*address)?.to_le_bytes().to_vec(), + }) + }; + + let mut bytes = read_first_part(core)?; + + assert_eq!(*discriminator_type, PrimitiveType::u8); + let discriminator = *bytes.get(0).unwrap_or(&0) as usize; + let size = data_variants[discriminator].ty.size_of(types); + let align = data_variants[discriminator].ty.align_of(types); + let variant_name = &data_variants[discriminator].name; + + let start_of_the_rest = *address + 4; + + let start = start_of_the_rest.next_multiple_of(4); + + if size > 4 { + let mut dst = vec![0; (size / 4 + 1) as usize]; + + assert!(start_of_the_rest % 4 == 0); + assert_eq!(bytes.len(), 4); + assert!(align <= 4); + + core.read_32(start, &mut dst[..(size as usize / 4)])?; + bytes.extend( + dst[..(size as usize / 4)] + .iter() + .flat_map(|w| w.to_le_bytes()), + ); + } + + let bytes = read_first_part(core)?; + assert_eq!(*discriminator_type, PrimitiveType::u8); + let new_discriminator = *bytes.get(0).unwrap_or(&0) as usize; + if new_discriminator != discriminator { + todo!( + "The discriminator changed during the read operation. The data is likely invalid" + ); + } + *last_discriminator_value = new_discriminator as u32; + + let x = read_from_slice(&bytes, start, *discriminator_type); + math_ctx.setvar( + &format!("{name}::{variant_name}"), + shunting::MathOp::Number(x), + ); - Ok(()) + Ok(()) + } + } } - pub fn compute(&mut self, math_ctx: &mut MathContext) -> (f64, Status) { - let new = math_ctx.eval(&self.expr).unwrap(); - let status = if new == self.last_value { - Status::SameAsLast - } else { - Status::New - }; - self.last_value = new; - (new, status) + pub fn compute(&mut self, math_ctx: &mut MathContext) -> Vec<(String, f64, Status)> { + match self { + Metric::Primitive { + name, + ty: _, + address: _, + expr, + last_value, + } => { + let new = math_ctx.eval(&expr).unwrap(); + let status = if new == *last_value { + Status::SameAsLast + } else { + Status::New + }; + *last_value = new; + vec![(name.clone(), new, status)] + } + Metric::Enum { + name, + ty: _, + address: _, + discriminator_type: _, + last_discriminator_value, + data_variants, + max_size: _, + } => data_variants + .iter_mut() + .enumerate() + .map(|(i, x)| { + let new = if i as u32 == *last_discriminator_value { + math_ctx.eval(&x.expr).unwrap() + } else { + f64::NAN + }; + let status = if new == x.last_value { + Status::SameAsLast + } else { + Status::New + }; + let variant = &x.name; + (format!("{name}::{variant}"), new, status) + }) + .collect(), + } } } diff --git a/probe-plotter-tools/src/setting.rs b/probe-plotter-tools/src/setting.rs index ad564d6..7d93221 100644 --- a/probe-plotter-tools/src/setting.rs +++ b/probe-plotter-tools/src/setting.rs @@ -1,13 +1,14 @@ use std::ops::RangeInclusive; +use probe_plotter_common::PrimitiveType; use probe_rs::MemoryInterface; -use crate::{Type, read_value}; +use crate::read_value; #[derive(Clone, Debug)] pub struct Setting { pub name: String, - pub ty: Type, + pub ty: PrimitiveType, pub address: u64, pub value: f64, pub range: RangeInclusive, @@ -22,33 +23,33 @@ impl Setting { pub fn write(&mut self, x: f64, core: &mut probe_rs::Core) -> Result<(), probe_rs::Error> { match self.ty { - Type::u8 => core.write_word_8( + PrimitiveType::u8 => core.write_word_8( self.address, x.round().clamp(u8::MIN as _, u8::MAX as _) as u8, )?, - Type::u16 => core.write_word_16( + PrimitiveType::u16 => core.write_word_16( self.address, x.round().clamp(u16::MIN as _, u16::MAX as _) as u16, )?, - Type::u32 => core.write_word_32( + PrimitiveType::u32 => core.write_word_32( self.address, x.round().clamp(u32::MIN as _, u32::MAX as _) as u32, )?, - Type::i8 => core.write_word_8( + PrimitiveType::i8 => core.write_word_8( self.address, x.round().clamp(i8::MIN as _, i8::MAX as _) as u8, )?, - Type::i16 => core.write_word_16( + PrimitiveType::i16 => core.write_word_16( self.address, x.round().clamp(i16::MIN as _, i16::MAX as _) as u16, )?, - Type::i32 => core.write_word_32( + PrimitiveType::i32 => core.write_word_32( self.address, x.round().clamp(i32::MIN as _, i32::MAX as _) as u32, )?, - Type::f32 => core.write_word_32(self.address, (x as f32).to_bits())?, + PrimitiveType::f32 => core.write_word_32(self.address, (x as f32).to_bits())?, }; Ok(()) diff --git a/probe-plotter/src/metric.rs b/probe-plotter/src/metric.rs index 23fdf8c..ce7f1de 100644 --- a/probe-plotter/src/metric.rs +++ b/probe-plotter/src/metric.rs @@ -1,15 +1,16 @@ // TODO: Adjust size constraints for targets other than 32bit -pub trait Metricable: Sized {} -impl Metricable for i8 {} -impl Metricable for i16 {} -impl Metricable for i32 {} -impl Metricable for u8 {} -impl Metricable for u16 {} -impl Metricable for u32 {} -impl Metricable for f32 {} +pub unsafe trait Metricable: Sized {} +unsafe impl Metricable for i8 {} +unsafe impl Metricable for i16 {} +unsafe impl Metricable for i32 {} +unsafe impl Metricable for u8 {} +unsafe impl Metricable for u16 {} +unsafe impl Metricable for u32 {} +unsafe impl Metricable for f32 {} pub use macros::make_metric; +pub use macros::Metricable; pub struct Metric { x: *mut T,