ti_lp55231/
debug.rs

1/// Macros for low level debugging when developing against I2C devices.
2
3/// Create a debugging scope on the provided context.
4///
5/// A debugging scope causes any subsequent [`text!`] or [`byte!`] calls to be
6/// printed with additional padding and automatically ends once the current code
7/// scope ends.
8///
9/// Scopes can be nested, where the inner scope will further pad any output.
10///
11/// The provided context (`ctx`) can be any struct that has two fields
12/// accessible to these macros:
13/// 1. `debug_enabled: bool`
14/// 2. `debug_depth: Rc<Cell<usize>>`
15///
16/// Example:
17/// ```
18/// debug::scope!(ctx, "entering scope 1");
19/// debug::text!(ctx, "message 1")
20/// debug::scope!(ctx, "entering scope 2");
21/// debug::text!(ctx, "message 2")
22/// {
23///   debug::scope!(ctx, "entering scope 3");
24///   debug::text!(ctx, "message 3")
25/// } // scope 3 ends
26/// debug::text!("message 4")
27/// ```
28/// Prints:
29/// ```text
30/// entering scope 1
31///   message 1
32///   entering scope 2
33///     message 2
34///     entering scope 3
35///       message 3
36///     message 4
37/// ```
38///
39/// The nesting ability of scopes becomes really useful when composing I2C
40/// operations; example:
41/// ```
42/// fn start() {
43///   debug::scope!("start()");
44///   let byte = 1;
45///   debug::byte!(byte, "write start byte", byte)
46///   device.write(byte);
47/// }
48///
49/// fn stop() {
50///   debug::scope!("stop()");
51///   let byte = 0;
52///   debug::byte!(byte, "write stop byte", byte)
53///   device.write(byte);
54/// }
55///
56/// fn restart() {
57///   debug::scope!("restart()");
58///   stop();
59///   start();
60/// }
61///
62/// restart();
63/// // ...
64/// stop();
65/// ```
66///
67/// Would result in the output:
68/// ```text
69/// restart()
70///   stop()
71///     00000000 write stop byte
72///   start()
73///     00000001 write start byte
74/// stop()
75///   00000000 write stop byte
76/// ```
77#[macro_export]
78macro_rules! scope {
79  ($ctx:ident, $fmt:expr $(, $arg:expr)* $(,)?) => {
80    // _unused is dropped at end of scope where this macro is called, which
81    // decrements debug depth.
82    let _unused = if $ctx.debug_enabled {
83      let mut cur_depth = $ctx.debug_depth.lock().unwrap();
84      let padding = "  ".repeat(*cur_depth);
85      println!("{}{} {{", padding, format!($fmt $(, $arg)*));
86      *cur_depth += 1;
87      // lock releases after return
88
89      // debug_depth ArcMutex needs to be cloned since guard() takes ownership
90      // of the arg. Code in block below is executed at the end of the code
91      // scope where the `scope` macro is called.
92      Some(scopeguard::guard($ctx.debug_depth.clone(), |depth| {
93        let mut cur_depth = depth.lock().unwrap();
94        if *cur_depth > 0 {
95          *cur_depth -= 1;
96        }
97        println!("{}}}", "  ".repeat(*cur_depth));
98      }))
99    } else {
100      None
101    };
102  };
103}
104pub use scope;
105
106/// Print a formated message at current debug depth.
107///
108/// Example:
109/// ```
110/// debug::text!(ctx, "1. top-level debug text");
111/// debug::scope!(ctx, "2. in-scope");
112/// debug::text!(ctx, "2a. in-scope debug text");
113/// ```
114///
115/// Prints:
116/// ```text
117/// 1. top-level debug text
118/// 2. in-scope
119///   2a. in-scope debug text
120/// ```
121#[macro_export]
122macro_rules! text {
123  ($ctx:expr, $fmt:expr $(, $arg:expr)* $(,)?) => {
124    if $ctx.debug_enabled {
125      let padding = "  ".repeat(*$ctx.debug_depth.lock().unwrap());
126      println!("{}{}", padding, format!($fmt $(, $arg)*));
127    };
128  };
129}
130pub use text;
131
132/// Print the binary representation for the given byte, along with a formatted
133/// description at the current debug depth.
134///
135/// Example:
136/// ```
137/// let value = 0b0010_1010;
138/// debug::byte(value, "is binary for {}", value);
139/// ```
140/// Prints:
141/// ```text
142/// 00101010 is binary for 42
143/// ```
144#[macro_export]
145macro_rules! byte {
146  ($ctx:expr, $value:expr, $($description:tt)*) => {
147    if $ctx.debug_enabled {
148      let value: u8 = $value;
149      let formatted_string = format!($($description)*);
150      debug::text!(
151        $ctx,
152        "{:08b} {}",
153        value,
154        formatted_string,
155      );
156    }
157  };
158}
159pub use byte;