use core::cell::RefCell; use core::fmt::Write; use critical_section::{CriticalSection, Mutex}; use esp_hal::uart::UartTx; use esp_hal::Blocking; use log::{LevelFilter, Log}; static ALT_LOGGER_UART: Mutex>>> = Mutex::new(RefCell::new(None)); pub fn with_uart_tx(f: impl FnOnce(CriticalSection<'_>, &'_ mut UartTx<'static, Blocking>) -> R) -> R { critical_section::with(|cs| { let mut uart = ALT_LOGGER_UART.borrow(cs).borrow_mut(); let uart = uart.as_mut().unwrap(); (f)(cs, uart) }) } struct AlternativeLogger; impl Log for AlternativeLogger { #[allow(unused)] fn enabled(&self, _: &log::Metadata) -> bool { // Filtered by `log` already true } #[allow(unused)] fn log(&self, record: &log::Record) { with_uart_tx(|cs, uart| { print_log_record(uart, record); }) } fn flush(&self) {} } const RESET: &str = "\u{001B}[0m"; const RED: &str = "\u{001B}[31m"; const GREEN: &str = "\u{001B}[32m"; const YELLOW: &str = "\u{001B}[33m"; const BLUE: &str = "\u{001B}[34m"; const CYAN: &str = "\u{001B}[35m"; #[cfg(feature = "rtt-log")] #[allow(unused)] use ::rtt_target::{rprint as print, rprintln as println}; #[cfg(feature = "alt-log")] #[allow(unused)] macro_rules! println { () => {{ do_print(Default::default()); }}; ($($arg:tt)*) => {{ do_print(::core::format_args!($($arg)*)); }}; } #[allow(unused)] fn do_print(args: core::fmt::Arguments<'_>) { with_uart_tx(|_, uart| { uart.write_fmt(args).unwrap(); uart.write_str("\n").unwrap(); uart.flush().unwrap(); }) } fn print_log_record(uart: &mut UartTx<'_, Blocking>, record: &log::Record) { let color = match record.level() { log::Level::Error => RED, log::Level::Warn => YELLOW, log::Level::Info => GREEN, log::Level::Debug => BLUE, log::Level::Trace => CYAN, }; let reset = RESET; let args = format_args!("{}{:>5} - {}{}\n", color, record.level(), record.args(), reset); uart.write_fmt(args).unwrap(); uart.flush().unwrap(); } #[cfg(feature = "rtt-log")] use panic_rtt_target as _; #[cfg(feature = "alt-log")] #[panic_handler] fn panic_handler(info: &core::panic::PanicInfo) -> ! { use esp_backtrace::Backtrace; println!("{RED}"); println!("=============== CUSTOM PANIC HANDLER =============="); println!("{info}{RESET}"); println!(""); println!("Backtrace:"); println!(""); let backtrace = Backtrace::capture(); for frame in backtrace.frames() { println!("0x{:x}", frame.program_counter()); } loop {} } pub fn setup_alternative_logging(alt_uart: UartTx<'static, Blocking>, level_filter: LevelFilter) { critical_section::with(|cs| { *ALT_LOGGER_UART.borrow(cs).borrow_mut() = Some(alt_uart); }); unsafe { log::set_logger_racy(&AlternativeLogger).unwrap(); log::set_max_level_racy(level_filter); } }