#![no_std]
use core::ptr::addr_of_mut;
use core::sync::atomic::Ordering;
use portable_atomic::AtomicBool;
use defmt::global_logger;
use embedded_io::Write;
static mut ENCODER: defmt::Encoder = defmt::Encoder::new();
static TAKEN: AtomicBool = AtomicBool::new(false);
static mut CS_RESTORE: critical_section::RestoreState = critical_section::RestoreState::invalid();
pub trait EraseWrite {
fn write(&mut self, buf: &[u8]);
fn flush(&mut self);
}
impl<T: Write> EraseWrite for T {
fn write(&mut self, buf: &[u8]) {
self.write_all(buf).ok();
}
fn flush(&mut self) {
self.flush().ok();
}
}
static mut ERASEDWRITE: Option<&mut dyn EraseWrite> = None;
pub fn defmt_serial<T: EraseWrite>(serial: &'static mut T) {
unsafe {
critical_section::with(|_| {
assert!(
(&raw mut ERASEDWRITE).as_ref().unwrap().is_none(),
"Tried to assign serial port when one was already assigned."
);
ERASEDWRITE = Some(serial);
});
}
}
pub fn release() {
unsafe {
critical_section::with(|_| {
if TAKEN.load(Ordering::Relaxed) {
panic!("defmt logger taken reentrantly"); }
ERASEDWRITE = None;
});
}
}
#[global_logger]
struct GlobalSerialLogger;
unsafe impl defmt::Logger for GlobalSerialLogger {
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;
}
#[cfg(feature = "espflash")]
write_serial(&[0xFF, 0x00]);
unsafe { (&raw mut ENCODER).as_mut().unwrap().start_frame(write_serial) }
}
unsafe fn release() {
unsafe { (&raw mut ENCODER).as_mut().unwrap().end_frame(write_serial); }
TAKEN.store(false, Ordering::Relaxed);
let restore = (&raw mut CS_RESTORE);
unsafe { critical_section::release(*restore); }
}
unsafe fn write(bytes: &[u8]) {
unsafe { (&raw mut ENCODER).as_mut().unwrap().write(bytes, write_serial); }
}
unsafe fn flush() {
unsafe {
if let Some(writer) = &mut *addr_of_mut!(ERASEDWRITE) {
(*writer).flush();
}
}
}
}
fn write_serial(remaining: &[u8]) {
unsafe {
if let Some(writer) = &mut *addr_of_mut!(ERASEDWRITE) {
(*writer).write(remaining);
}
}
}