Skip to content

Commit 90fbd01

Browse files
Add the defmt-log crate.
This is a work in progress, but it shows how, with the new `no-interning` feature, a crate can capture defmt log data, including the actual format string, and render locally. TODO: Actually parse the format string.
1 parent 64d4fc7 commit 90fbd01

File tree

3 files changed

+84
-0
lines changed

3 files changed

+84
-0
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ members = [
44
"decoder",
55
"decoder/defmt-json-schema",
66
"defmt",
7+
"defmt-log",
78
"macros",
89
"parser",
910
"print",

defmt-log/Cargo.toml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
[package]
2+
name = "defmt-log"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
[dependencies]
7+
defmt = { version = "0.3", path = "../defmt", features = ["no-interning"] }
8+
critical-section = "1.1"
9+
log = "0.4.22"

defmt-log/src/lib.rs

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
//! An implementation of the defmt logging traits, but using the `log` crate for output
2+
3+
use std::sync::{Condvar, Mutex};
4+
5+
#[defmt::global_logger]
6+
struct FakeLogger;
7+
8+
#[derive(PartialEq, Eq)]
9+
enum State {
10+
Waiting,
11+
AcquiredNeedAddr,
12+
WantArgs,
13+
}
14+
15+
struct Context {
16+
state: State
17+
}
18+
19+
impl Context {
20+
const fn new() -> Context {
21+
Context {
22+
state: State::Waiting
23+
}
24+
}
25+
}
26+
27+
static CONTEXT: (Mutex<Context>, Condvar) = (Mutex::new(Context::new()), Condvar::new());
28+
29+
unsafe impl defmt::Logger for FakeLogger {
30+
fn acquire() {
31+
log::info!("Acquiring {:?}", std::thread::current().id());
32+
let mut ctx = CONTEXT.0.lock().unwrap();
33+
while ctx.state != State::Waiting {
34+
// sit on the condvar because only one thread can grab the lock
35+
ctx = CONTEXT.1.wait(ctx).unwrap();
36+
}
37+
// cool, we can take it
38+
ctx.state = State::AcquiredNeedAddr;
39+
}
40+
41+
unsafe fn flush() {
42+
log::info!("Flushing {:?}", std::thread::current().id());
43+
}
44+
45+
unsafe fn release() {
46+
log::info!("Releasing {:?}", std::thread::current().id());
47+
let mut ctx = CONTEXT.0.lock().unwrap();
48+
ctx.state = State::Waiting;
49+
CONTEXT.1.notify_one();
50+
}
51+
52+
unsafe fn write(bytes: &[u8]) {
53+
use std::convert::TryInto;
54+
log::info!("Bytes {:?} {:02x?}", std::thread::current().id(), bytes);
55+
let mut ctx = CONTEXT.0.lock().unwrap();
56+
match ctx.state {
57+
State::Waiting => panic!("Unlocked write!!"),
58+
State::AcquiredNeedAddr => {
59+
let addr = &bytes[0..std::mem::size_of::<usize>()];
60+
let addr: usize = usize::from_le_bytes(addr.try_into().unwrap());
61+
let ptr = addr as *const &'static str;
62+
let format_str: &'static str = unsafe { ptr.read() };
63+
log::info!("Format string: {}", format_str);
64+
ctx.state = State::WantArgs;
65+
},
66+
State::WantArgs => {
67+
log::info!("Arg: {:02x?}", bytes);
68+
},
69+
}
70+
}
71+
}
72+
73+
#[export_name = "_defmt_timestamp"]
74+
fn defmt_timestamp(_: defmt::Formatter<'_>) {}

0 commit comments

Comments
 (0)