use crate::UpChannel;
use portable_atomic::{AtomicBool, Ordering};
static mut CHANNEL: Option<UpChannel> = None;
#[defmt::global_logger]
struct Logger;
pub fn set_defmt_channel(channel: UpChannel) {
unsafe { CHANNEL = Some(channel) }
}
static TAKEN: AtomicBool = AtomicBool::new(false);
static mut CS_RESTORE: critical_section::RestoreState = critical_section::RestoreState::invalid();
static mut ENCODER: defmt::Encoder = defmt::Encoder::new();
unsafe impl defmt::Logger for Logger {
fn acquire() {
let restore = unsafe { critical_section::acquire() };
if TAKEN.load(Ordering::Relaxed) {
panic!("defmt logger taken reentrantly")
}
TAKEN.store(true, Ordering::Relaxed);
unsafe { CS_RESTORE = restore };
unsafe {
let encoder = &mut *core::ptr::addr_of_mut!(ENCODER);
encoder.start_frame(do_write)
}
}
unsafe fn flush() {}
unsafe fn release() {
let encoder = &mut *core::ptr::addr_of_mut!(ENCODER);
encoder.end_frame(do_write);
TAKEN.store(false, Ordering::Relaxed);
let restore = CS_RESTORE;
critical_section::release(restore);
}
unsafe fn write(bytes: &[u8]) {
let encoder = &mut *core::ptr::addr_of_mut!(ENCODER);
encoder.write(bytes, do_write);
}
}
fn do_write(bytes: &[u8]) {
unsafe {
let channel = core::ptr::addr_of_mut!(CHANNEL);
if let Some(Some(c)) = channel.as_mut() {
c.write(bytes);
}
}
}
#[macro_export]
macro_rules! rtt_init_defmt {
($mode:path, $size:expr) => {{
let channels = $crate::rtt_init! {
up: {
0: {
size: $size,
mode: $mode,
name: "defmt"
}
}
};
$crate::set_defmt_channel(channels.up.0);
}};
($mode:path) => {
$crate::rtt_init_defmt!($mode, 1024);
};
() => {{
use $crate::ChannelMode::NoBlockSkip;
$crate::rtt_init_defmt!(NoBlockSkip, 1024);
}};
}