Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions examples/simple/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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...");
Expand Down
72 changes: 72 additions & 0 deletions macros/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion macros/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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
60 changes: 60 additions & 0 deletions macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
///
/// ```
Expand Down Expand Up @@ -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()
}
10 changes: 10 additions & 0 deletions probe-plotter-common/Cargo.toml
Original file line number Diff line number Diff line change
@@ -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" }
135 changes: 135 additions & 0 deletions probe-plotter-common/src/lib.rs
Original file line number Diff line number Diff line change
@@ -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<Atype, TypeDef>;

pub enum TypeDef {
Struct {
name: Atype,
fields: Vec<symbol::Member>,
},
Enum {
name: Atype,
discriminator_type: PrimitiveType,
variants: Vec<EnumVariant>,
},
}

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<PrimitiveType, Self::Error> {
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<Atype> 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()),
}
}
}
Loading
Loading