acid/firmware/acid-firmware/src/logging.rs

215 lines
5.8 KiB
Rust
Raw Normal View History

2026-02-13 03:00:46 +01:00
use core::fmt::Arguments;
2026-02-13 03:00:46 +01:00
use log::LevelFilter;
pub const LOG_LEVEL_FILTER: LevelFilter = {
if let Some(string) = option_env!("ESP_LOG") {
if string.eq_ignore_ascii_case("ERROR") {
LevelFilter::Error
} else if string.eq_ignore_ascii_case("WARN") {
LevelFilter::Warn
} else if string.eq_ignore_ascii_case("INFO") {
LevelFilter::Info
} else if string.eq_ignore_ascii_case("DEBUG") {
LevelFilter::Debug
} else if string.eq_ignore_ascii_case("TRACE") {
LevelFilter::Trace
} else {
2026-01-31 20:21:40 +01:00
panic!(
"Unknown `ESP_LOG` value. Only `ERROR`, `WARN`, `INFO`, `DEBUG`, `TRACE`, or `OFF` may be used."
);
}
} else {
LevelFilter::Off
}
};
2025-12-31 00:54:48 +01:00
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";
2026-01-31 20:21:40 +01:00
fn with_formatted_log_record<R>(
record: &log::Record,
callback: impl FnOnce(Arguments<'_>) -> R,
) -> R {
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,
};
2026-01-06 22:52:41 +01:00
let args = format_args!(
"{}{:>5} - {}{}\n",
color,
record.level(),
record.args(),
2026-01-31 20:21:40 +01:00
RESET
2026-01-06 22:52:41 +01:00
);
2026-01-31 20:21:40 +01:00
(callback)(args)
}
2026-01-31 20:21:40 +01:00
/// The default USB logger.
#[cfg(feature = "usb-log")]
pub mod usb {
use super::*;
2026-01-05 04:16:05 +01:00
2026-02-22 00:59:01 +01:00
pub fn setup_logging() {
2026-01-31 20:21:40 +01:00
esp_println::logger::init_logger(LOG_LEVEL_FILTER);
log::info!("Logger initialized!");
}
}
/// Alternative logger via UART.
2026-01-05 04:16:05 +01:00
#[cfg(feature = "alt-log")]
2026-02-04 03:14:21 +01:00
#[macro_use]
2026-01-31 20:21:40 +01:00
pub mod uart {
use super::*;
use crate::console;
use core::{cell::RefCell, fmt::Write};
use critical_section::{CriticalSection, Mutex};
use esp_hal::{
Blocking,
gpio::interconnect::{PeripheralInput, PeripheralOutput},
uart::{Uart, UartTx},
};
use log::{Log, info};
2026-01-31 20:21:40 +01:00
static ALT_LOGGER_UART: Mutex<RefCell<Option<UartTx<'static, Blocking>>>> =
Mutex::new(RefCell::new(None));
2026-01-31 20:21:40 +01:00
pub fn with_uart_tx<R>(
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();
2026-01-31 20:21:40 +01:00
(f)(cs, uart)
})
}
#[allow(unused)]
macro_rules! println {
2026-02-04 03:14:21 +01:00
() => {{
do_print(Default::default());
}};
2026-01-31 20:21:40 +01:00
($($arg:tt)*) => {{
do_print(::core::format_args!($($arg)*));
}};
}
#[allow(unused)]
fn do_print(args: core::fmt::Arguments<'_>) {
with_uart_tx(|_, uart| {
uart.write_fmt(format_args!("{}\n", args)).unwrap();
uart.flush().unwrap();
})
}
struct UartLogger;
impl Log for UartLogger {
#[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| {
with_formatted_log_record(record, |args| uart.write_fmt(args)).unwrap();
uart.flush().unwrap();
})
}
fn flush(&self) {}
}
#[panic_handler]
fn panic_handler(info: &core::panic::PanicInfo) -> ! {
use super::{RED, RESET};
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 {}
}
2026-02-22 00:59:01 +01:00
pub fn setup_logging(uart_tx: UartTx<'static, Blocking>) {
2026-01-31 20:21:40 +01:00
critical_section::with(|cs| {
*ALT_LOGGER_UART.borrow(cs).borrow_mut() = Some(uart_tx);
});
unsafe {
log::set_logger_racy(&UartLogger).unwrap();
log::set_max_level_racy(LOG_LEVEL_FILTER);
}
info!("Logger initialized!");
}
}
2026-01-31 20:21:40 +01:00
/// Logging via RTT for probe-rs.
#[cfg(feature = "rtt-log")]
pub mod rtt {
use super::*;
#[allow(unused)]
2026-02-04 03:14:21 +01:00
pub use ::rtt_target::{rprint as print, rprintln as println};
2026-01-31 20:21:40 +01:00
use panic_rtt_target as _; // Use the RTT panic handler.
use rtt_target::ChannelMode;
2026-02-22 00:59:01 +01:00
pub fn setup_logging() {
2026-01-31 20:21:40 +01:00
rtt_target::rtt_init_log!(LOG_LEVEL_FILTER, ChannelMode::BlockIfFull);
log::info!("Logger initialized!");
}
}
2026-02-04 03:14:21 +01:00
// #[macro_export]
// macro_rules! dbg {
// () => {
// $crate::logging::implementation::println!("[{}:{}:{}]", $crate::file!(), $crate::line!(), $crate::column!())
// };
// ($val:expr $(,)?) => {
// match $val {
// tmp => {
// $crate::logging::uart::println!("[{}:{}:{}] {} = {:#?}",
// file!(),
// line!(),
// column!(),
// stringify!($val),
// // The `&T: Debug` check happens here (not in the format literal desugaring)
// // to avoid format literal related messages and suggestions.
// &&tmp as &dyn ::core::fmt::Debug,
// );
// tmp
// }
// }
// };
// ($($val:expr),+ $(,)?) => {
// ($($crate::dbg!($val)),+,)
// };
// }
// #[cfg(feature = "alt-log")]
// pub use uart as implementation;
// #[cfg(feature = "rtt-log")]
// pub use rtt as implementation;