Skip to content
This repository has been archived by the owner on May 23, 2024. It is now read-only.

Commit

Permalink
Add defmt backend (#48)
Browse files Browse the repository at this point in the history
* Add defmt backend

* Add defmt-raw
  • Loading branch information
bugadani committed Aug 29, 2023
1 parent a2f8172 commit c15e85d
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 0 deletions.
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ cargo-args = ["-Z", "build-std=core"]

[dependencies]
log = { version = "0.4.17", optional = true }
defmt = { version = "=0.3.5", optional = true }
critical-section = { version = "1.1.1", optional = true }

[features]
Expand All @@ -40,5 +41,8 @@ jtag_serial = [] # C3, C6, H2, and S3 only!
rtt = []
no-op = []

# Enables a `defmt` backend usable with espflash. We force rzcobs encoding to simplify implementation
defmt = ["dep:defmt", "defmt/encoding-rzcobs"]

# logging sub-features
colors = []
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,17 @@ In this case the following environment variables are used:

If this simple logger implementation isn't sufficient for your needs you can implement your own logger on top of `esp-println` - see https://docs.rs/log/0.4.17/log/#implementing-a-logger

## defmt

Using the `defmt` feature, esp-println will install a defmt global logger. The logger will output
to the same data stream as `println!()`, and adds framing bytes so it can be used even with other,
non-defmt output. Using the `defmt` feature automatically uses the Rzcobs encoding and does not
allow changing the encoding.

You can also use the `defmt-raw` feature that allows using any encoding provided by defmt, but
does not add extra framing. Using this feature requires some care as the defmt output may become
unrecoverably mangled when other data are printed.

## License

Licensed under either of:
Expand Down
79 changes: 79 additions & 0 deletions src/defmt.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
//! defmt global logger implementation.
// Implementation taken from defmt-rtt, with a custom framing prefix

use core::sync::atomic::{AtomicBool, Ordering};

use critical_section::RestoreState;

use super::Printer;

/// Global logger lock.
static TAKEN: AtomicBool = AtomicBool::new(false);
static mut CS_RESTORE: RestoreState = RestoreState::invalid();
static mut ENCODER: defmt::Encoder = defmt::Encoder::new();

#[defmt::global_logger]
pub struct Logger;
unsafe impl defmt::Logger for Logger {
fn acquire() {
// safety: Must be paired with corresponding call to release(), see below
let restore = unsafe { critical_section::acquire() };

// safety: accessing the `static mut` is OK because we have acquired a critical
// section.
if TAKEN.load(Ordering::Relaxed) {
panic!("defmt logger taken reentrantly")
}

// safety: accessing the `static mut` is OK because we have acquired a critical
// section.
TAKEN.store(true, Ordering::Relaxed);

// safety: accessing the `static mut` is OK because we have acquired a critical
// section.
unsafe { CS_RESTORE = restore };

// If not disabled, write a non-UTF8 sequence to indicate the start of a defmt
// frame. We need this to distinguish defmt frames from other data that
// might be written to the printer.
#[cfg(not(feature = "defmt-raw"))]
do_write(&[0xFF, 0x00]);

// safety: accessing the `static mut` is OK because we have acquired a critical
// section.
unsafe { ENCODER.start_frame(do_write) }
}

unsafe fn release() {
// safety: accessing the `static mut` is OK because we have acquired a critical
// section.
ENCODER.end_frame(do_write);

// We don't need to write a custom end-of-frame sequence because:
// - using `defmt`, the rzcobs encoding already includes a terminating zero
// - using `defmt-raw`, we don't add any additional framing data

// safety: accessing the `static mut` is OK because we have acquired a critical
// section.
TAKEN.store(false, Ordering::Relaxed);

// safety: accessing the `static mut` is OK because we have acquired a critical
// section.
let restore = CS_RESTORE;

// safety: Must be paired with corresponding call to acquire(), see above
critical_section::release(restore);
}

unsafe fn flush() {}

unsafe fn write(bytes: &[u8]) {
// safety: accessing the `static mut` is OK because we have acquired a critical
// section.
ENCODER.write(bytes, do_write);
}
}

fn do_write(bytes: &[u8]) {
Printer.write_bytes(bytes)
}
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#![no_std]

#[cfg(any(feature = "defmt", feature = "defmt_raw"))]
pub mod defmt;
#[cfg(feature = "log")]
pub mod logger;
#[cfg(feature = "rtt")]
Expand Down

0 comments on commit c15e85d

Please sign in to comment.