Skip to main content

mpfs_hal/
logger.rs

1use super::println;
2use alloc::string::String;
3use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
4use embassy_sync::channel::Channel;
5
6extern crate alloc;
7
8// Structure to hold log messages
9struct LogMessage {
10    level: log::Level,
11    args: String,
12    timestamp: u64,
13}
14
15// Static channel for log messages
16static LOG_CHANNEL: Channel<CriticalSectionRawMutex, LogMessage, 1024> = Channel::new();
17static mut LOGGER: MpfsLogger = MpfsLogger {
18    level: log::LevelFilter::Error,
19};
20
21/// Initialize the logger with the given maximum log level.
22pub fn init_logger(level: log::LevelFilter) {
23    unsafe {
24        LOGGER.level = level;
25        #[allow(static_mut_refs)]
26        log::set_logger_racy(&LOGGER).unwrap();
27        log::set_max_level_racy(level);
28    }
29}
30
31pub async fn log_task() -> ! {
32    let receiver = LOG_CHANNEL.receiver();
33    loop {
34        // Try to receive a message from the channel
35        if let Ok(message) = receiver.try_receive() {
36            const RESET: &str = "\u{001B}[0m";
37            const RED: &str = "\u{001B}[31m";
38            const GREEN: &str = "\u{001B}[32m";
39            const YELLOW: &str = "\u{001B}[33m";
40            const BLUE: &str = "\u{001B}[34m";
41            const CYAN: &str = "\u{001B}[35m";
42
43            #[cfg(feature = "log-colors")]
44            let color = match message.level {
45                log::Level::Error => RED,
46                log::Level::Warn => YELLOW,
47                log::Level::Info => GREEN,
48                log::Level::Debug => BLUE,
49                log::Level::Trace => CYAN,
50            };
51            #[cfg(feature = "log-colors")]
52            let reset = RESET;
53
54            #[cfg(not(feature = "log-colors"))]
55            let color = "";
56            #[cfg(not(feature = "log-colors"))]
57            let reset = "";
58
59            println!(
60                "{}{} [{:?}] - {}{}",
61                color, message.level, message.timestamp, message.args, reset
62            );
63        }
64        yield_now().await;
65    }
66}
67
68struct MpfsLogger {
69    level: log::LevelFilter,
70}
71
72impl log::Log for MpfsLogger {
73    fn enabled(&self, metadata: &log::Metadata) -> bool {
74        metadata.level() <= self.level
75    }
76
77    #[allow(unused)]
78    fn log(&self, record: &log::Record) {
79        if !self.enabled(&record.metadata()) {
80            return;
81        }
82
83        let mut args = String::new();
84        let _ = core::fmt::write(&mut args, *record.args());
85
86        // Create the log message with timestamp
87        let message = LogMessage {
88            level: record.level(),
89            args,
90            timestamp: unsafe { crate::pac::readmcycle() / 600 }, // Convert to microseconds
91        };
92
93        let _ = LOG_CHANNEL.try_send(message);
94    }
95
96    fn flush(&self) {}
97}
98
99//----------------------------------------------------------
100// Yield now
101use core::future::Future;
102use core::pin::Pin;
103use core::task::{Context, Poll};
104
105fn yield_now() -> impl Future<Output = ()> {
106    YieldNowFuture { yielded: false }
107}
108
109#[must_use = "futures do nothing unless you `.await` or poll them"]
110struct YieldNowFuture {
111    yielded: bool,
112}
113
114impl Future for YieldNowFuture {
115    type Output = ();
116    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
117        if self.yielded {
118            Poll::Ready(())
119        } else {
120            self.yielded = true;
121            cx.waker().wake_by_ref();
122            Poll::Pending
123        }
124    }
125}