@@ -7,7 +7,7 @@ use proc_macro::{Span, TokenStream};
77use quote:: quote;
88use syn:: parse_macro_input;
99
10- use crate :: symbol:: { MetricsSymbol , SettingSymbol } ;
10+ use crate :: symbol:: { GraphSymbol , MetricsSymbol , SettingSymbol } ;
1111
1212mod args;
1313mod cargo;
@@ -16,26 +16,21 @@ mod symbol;
1616/// Create a Metric instance that will be shown in the probe-plotter utility's graph
1717///
1818/// ```
19- /// make_metric!(NAME_AS_SHOWN_IN_GRAPH: DataType = defalt_value, "expression to convert from raw value (x ) to the value to plot")
19+ /// make_metric!(NAME_AS_SHOWN_IN_GRAPH: DataType = defalt_value, "expression to convert from raw value (NAME_AS_SHOWN_IN_GRAPH ) to the value to plot")
2020/// ```
2121///
2222/// Note that similar to `cortex_m::singleton!`, this should only be called once per metric. The macro will only return Some() the first time, then None.
2323///
2424/// ```
25- /// let mut metric_foo = probe_plotter::make_metric!(FOO: i32 = 0, "x * 3.0").unwrap();
25+ /// let mut metric_foo = probe_plotter::make_metric!(FOO: i32 = 0, "FOO * 3.0").unwrap();
2626///
27- /// metric_foo.set(42); // The value 42 will be available for the host after this call. The value will be plotted as x * 3 = 42 * 3 = 126
27+ /// metric_foo.set(42); // The value 42 will be available for the host after this call. The value will be plotted as FOO * 3 = 42 * 3 = 126
2828/// ```
2929#[ proc_macro]
3030pub fn make_metric ( args : TokenStream ) -> TokenStream {
3131 let args = parse_macro_input ! ( args as args:: MetricArgs ) ;
3232
33- let sym_name = MetricsSymbol :: new (
34- args. ty . to_string ( ) ,
35- args. name . to_string ( ) ,
36- args. expression_string . value ( ) ,
37- )
38- . mangle ( ) ;
33+ let sym_name = MetricsSymbol :: new ( args. ty . to_string ( ) , args. name . to_string ( ) ) . mangle ( ) ;
3934
4035 let name = args. name ;
4136 let ty = args. ty ;
@@ -116,6 +111,68 @@ pub fn make_setting(args: TokenStream) -> TokenStream {
116111 . into ( )
117112}
118113
114+ /// Register a graph for the probe-plotter utility's to plot.
115+ ///
116+ /// This has access to all metrics and settings which may be used in the expression
117+ ///
118+ /// ```
119+ /// make_graph!(GRAPH_TITLE = "expression to convert from raw values to the value to plot, may refer to any metrics or settings")
120+ /// ```
121+ ///
122+ /// ```
123+ /// probe_plotter::make_graph!(FOO_GRAPH = "FOO * 3.0");
124+ ///
125+ ///
126+ /// let mut metric_foo = probe_plotter::make_metric!(FOO: i32 = 0).unwrap();
127+ ///
128+ /// metric_foo.set(42); // The value 42 will be available for the host after this call. The value will be plotted as FOO * 3 = 42 * 3 = 126
129+ /// ```
130+ #[ proc_macro]
131+ pub fn make_graph ( args : TokenStream ) -> TokenStream {
132+ let args = parse_macro_input ! ( args as args:: GraphArgs ) ;
133+
134+ let sym_name = GraphSymbol :: new ( args. name . to_string ( ) , args. expression_string . value ( ) ) . mangle ( ) ;
135+ let section = linker_section ( false , & sym_name) ;
136+ let section_for_macos = linker_section ( true , & sym_name) ;
137+
138+ let name = args. name ;
139+ quote ! (
140+ #[ cfg_attr( target_os = "macos" , unsafe ( link_section = #section_for_macos) ) ]
141+ #[ cfg_attr( not( target_os = "macos" ) , unsafe ( link_section = #section) ) ]
142+ #[ unsafe ( export_name = #sym_name) ]
143+ static mut #name: u8 = 42 ;
144+
145+ #[ allow( unsafe_code) ]
146+ unsafe {
147+ // TODO: Find better way to ensure the compiler considers this static used
148+ // the #[used] attribute does not seem enough
149+ let mut x = & raw const #name as usize ;
150+ core:: arch:: asm!( "mov {0}, {0}" , inout( reg) x) ;
151+ }
152+ )
153+ . into ( )
154+ }
155+ /*
156+ quote!(
157+ #[cfg_attr(target_os = "macos", unsafe(link_section = #section_for_macos))]
158+ #[cfg_attr(not(target_os = "macos"), unsafe(link_section = #section))]
159+ #[used]
160+ #[unsafe(export_name = #sym_name)]
161+ static #name: u8 = 0;
162+ )
163+ .into()
164+
165+
166+ let name = args.name;
167+ quote!(
168+ #[used]
169+ #[unsafe(export_name = #sym_name)]
170+ static mut #name: (i8, bool) =
171+ (0, false);
172+ )
173+ .into()
174+ */
175+
119176pub ( crate ) fn crate_local_disambiguator ( ) -> u64 {
120177 // We want a deterministic, but unique-per-macro-invocation identifier. For that we
121178 // hash the call site `Span`'s debug representation, which contains a counter that
@@ -128,3 +185,17 @@ fn hash(string: &str) -> u64 {
128185 string. hash ( & mut hasher) ;
129186 hasher. finish ( )
130187}
188+
189+ /// work around restrictions on length and allowed characters imposed by macos linker
190+ /// returns (note the comma character for macos):
191+ /// under macos: ".defmt," + 16 character hex digest of symbol's hash
192+ /// otherwise: ".defmt." + prefix + symbol
193+ pub ( crate ) fn linker_section ( for_macos : bool , symbol : & str ) -> String {
194+ let mut sub_section = format ! ( ".{symbol}" ) ;
195+
196+ if for_macos {
197+ sub_section = format ! ( ",{:x}" , hash( & sub_section) ) ;
198+ }
199+
200+ format ! ( ".defmt{sub_section}" )
201+ }
0 commit comments