2025-12-29 19:36:00 +01:00
|
|
|
use core::fmt::Write;
|
2026-01-31 20:21:40 +01:00
|
|
|
use core::{cell::RefCell, fmt::Arguments};
|
2025-12-29 19:36:00 +01:00
|
|
|
|
2025-12-31 00:54:48 +01:00
|
|
|
use critical_section::{CriticalSection, Mutex};
|
2025-12-31 01:08:12 +01:00
|
|
|
use esp_hal::Blocking;
|
2026-01-31 20:21:40 +01:00
|
|
|
use esp_hal::clock::CpuClock;
|
|
|
|
|
use esp_hal::psram::{FlashFreq, PsramConfig, PsramSize, SpiRamFreq, SpiTimingConfigCoreClock};
|
2026-01-06 22:52:41 +01:00
|
|
|
use esp_hal::uart::UartTx;
|
2026-01-11 00:53:08 +01:00
|
|
|
use log::{LevelFilter, Log};
|
|
|
|
|
|
|
|
|
|
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."
|
|
|
|
|
);
|
2026-01-11 00:53:08 +01:00
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
LevelFilter::Off
|
|
|
|
|
}
|
|
|
|
|
};
|
2025-12-29 19:36:00 +01:00
|
|
|
|
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";
|
2025-12-29 19:36:00 +01:00
|
|
|
|
2026-01-31 20:21:40 +01:00
|
|
|
fn with_formatted_log_record<R>(
|
|
|
|
|
record: &log::Record,
|
|
|
|
|
callback: impl FnOnce(Arguments<'_>) -> R,
|
|
|
|
|
) -> R {
|
2025-12-29 19:36:00 +01:00
|
|
|
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)
|
2025-12-29 19:36:00 +01:00
|
|
|
}
|
|
|
|
|
|
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-01-31 20:21:40 +01:00
|
|
|
pub fn setup_logging() -> impl Future<Output = ()> {
|
|
|
|
|
esp_println::logger::init_logger(LOG_LEVEL_FILTER);
|
|
|
|
|
log::info!("Logger initialized!");
|
|
|
|
|
async {}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Alternative logger via UART.
|
2026-01-05 04:16:05 +01:00
|
|
|
#[cfg(feature = "alt-log")]
|
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},
|
|
|
|
|
peripherals::UART2,
|
|
|
|
|
uart::{Uart, UartTx},
|
|
|
|
|
};
|
|
|
|
|
use log::{Log, info};
|
2025-12-29 19:36:00 +01:00
|
|
|
|
2026-01-31 20:21:40 +01:00
|
|
|
static ALT_LOGGER_UART: Mutex<RefCell<Option<UartTx<'static, Blocking>>>> =
|
|
|
|
|
Mutex::new(RefCell::new(None));
|
2025-12-29 19:36:00 +01:00
|
|
|
|
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();
|
2025-12-29 19:36:00 +01:00
|
|
|
|
2026-01-31 20:21:40 +01:00
|
|
|
(f)(cs, uart)
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[allow(unused)]
|
|
|
|
|
macro_rules! println {
|
|
|
|
|
// TODO: I don't think this is necessary. Consider removing.
|
|
|
|
|
// () => {{
|
|
|
|
|
// 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(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 {}
|
2025-12-29 19:36:00 +01:00
|
|
|
}
|
|
|
|
|
|
2026-01-31 20:21:40 +01:00
|
|
|
pub fn setup_logging(
|
|
|
|
|
uart: impl esp_hal::uart::Instance + 'static,
|
|
|
|
|
tx: impl PeripheralOutput<'static>,
|
|
|
|
|
rx: impl PeripheralInput<'static>,
|
|
|
|
|
) -> impl Future<Output = ()> {
|
|
|
|
|
let (uart_rx, uart_tx) = Uart::new(uart, Default::default())
|
|
|
|
|
.unwrap()
|
|
|
|
|
.with_tx(tx)
|
|
|
|
|
.with_rx(rx)
|
|
|
|
|
.split();
|
|
|
|
|
|
|
|
|
|
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!");
|
|
|
|
|
console::run_console(uart_rx.into_async())
|
|
|
|
|
}
|
2025-12-29 19:36:00 +01:00
|
|
|
}
|
|
|
|
|
|
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)]
|
|
|
|
|
use ::rtt_target::{rprint as print, rprintln as println};
|
|
|
|
|
use panic_rtt_target as _; // Use the RTT panic handler.
|
|
|
|
|
use rtt_target::ChannelMode;
|
|
|
|
|
|
|
|
|
|
pub fn setup_logging() -> impl Future<Output = ()> {
|
|
|
|
|
rtt_target::rtt_init_log!(LOG_LEVEL_FILTER, ChannelMode::BlockIfFull);
|
|
|
|
|
log::info!("Logger initialized!");
|
|
|
|
|
async {}
|
2025-12-29 19:36:00 +01:00
|
|
|
}
|
|
|
|
|
}
|