osal_rs/
log.rs

1/***************************************************************************
2 *
3 * osal-rs
4 * Copyright (C) 2023/2026 Antonio Salsi <passy.linux@zresa.it>
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 *
18 ***************************************************************************/
19
20#[cfg(not(feature = "std"))]
21pub mod ffi {
22    use core::ffi::{c_char, c_int};
23
24    unsafe extern "C" {
25        pub fn printf_on_uart(format: *const c_char, ...) -> c_int;
26
27    }
28}
29
30use core::ffi::c_char;
31
32use alloc::{ffi::CString, format};
33
34use crate::log::ffi::printf_on_uart;
35use crate::os::{System, SystemFn};
36
37
38const COLOR_RED: &str = "\x1b[31m";
39const COLOR_GREEN: &str = "\x1b[32m";
40const COLOR_YELLOW: &str = "\x1b[33m";
41const COLOR_BLUE: &str = "\x1b[34m";
42const COLOR_MAGENTA: &str = "\x1b[35m";
43const COLOR_CYAN: &str = "\x1b[36m";
44const COLOR_RESET: &str = "\x1b[0m";
45pub const RETURN: &str = "\r\n";
46
47pub mod log_levels {
48    pub const FLAG_DEBUG: u8 = 1 << 0;
49    pub const FLAG_INFO: u8 = 1 << 1;
50    pub const FLAG_WARNING: u8 = 1 << 2;
51    pub const FLAG_ERROR: u8 = 1 << 3;
52    pub const FLAG_FATAL: u8 = 1 << 4;
53    pub const FLAG_COLOR_ON: u8 = 1 << 6;
54    pub const FLAG_STATE_ON: u8 = 1 << 7;
55
56    pub const LEVEL_DEBUG: u8 = FLAG_DEBUG | FLAG_INFO | FLAG_WARNING | FLAG_ERROR | FLAG_FATAL;
57    pub const LEVEL_INFO: u8 = FLAG_INFO | FLAG_WARNING | FLAG_ERROR | FLAG_FATAL;
58    pub const LEVEL_WARNING: u8 = FLAG_WARNING | FLAG_ERROR | FLAG_FATAL;
59    pub const LEVEL_ERROR: u8 = FLAG_ERROR | FLAG_FATAL;
60
61    pub const LEVEL_FATAL: u8 = FLAG_FATAL;
62}
63
64static mut MASK: u8 = log_levels::LEVEL_DEBUG | log_levels::FLAG_COLOR_ON | log_levels::FLAG_STATE_ON;
65static mut BUSY: u8 = 0;
66
67#[cfg(not(feature = "std"))]
68#[macro_export]
69macro_rules! print {
70    ($($arg:tt)*) => {{
71        unsafe {
72            use alloc::string::ToString;
73            let formatted = alloc::format!($($arg)*);
74            if let Ok(c_str) = alloc::ffi::CString::new(formatted) {
75                $crate::log::ffi::printf_on_uart(b"%s\0".as_ptr() as *const core::ffi::c_char, c_str.as_ptr());
76            }
77        }
78    }};
79}
80
81#[cfg(not(feature = "std"))]
82#[macro_export]
83macro_rules! println {
84    () => {
85        $crate::print!("\r\n")
86    };
87    ($fmt:expr) => {{
88        unsafe {
89            use alloc::string::ToString;
90            let formatted = alloc::format!(concat!($fmt, "\r\n"));
91            if let Ok(c_str) = alloc::ffi::CString::new(formatted) {
92                $crate::log::ffi::printf_on_uart(b"%s\0".as_ptr() as *const core::ffi::c_char, c_str.as_ptr());
93            }
94        }
95    }};
96    ($fmt:expr, $($arg:tt)*) => {{
97        unsafe {
98            use alloc::string::ToString;
99            let formatted = alloc::format!(concat!($fmt, "\r\n"), $($arg)*);
100            if let Ok(c_str) = alloc::ffi::CString::new(formatted) {
101                $crate::log::ffi::printf_on_uart(b"%s\0".as_ptr() as *const core::ffi::c_char, c_str.as_ptr());
102            }
103        }
104    }};
105}
106
107pub fn set_level_log(level: u8) {
108    unsafe {
109        MASK =
110            (MASK & log_levels::FLAG_STATE_ON) | (level & !log_levels::FLAG_STATE_ON);
111    }
112}
113
114pub fn set_enable_log(enabled: bool) {
115    unsafe {
116        if enabled {
117            MASK |= log_levels::FLAG_STATE_ON;
118        } else {
119            MASK &= !log_levels::FLAG_STATE_ON;
120        }
121    }
122}
123
124pub fn get_enable_log() -> bool {
125    unsafe { (MASK & log_levels::FLAG_STATE_ON) != 0 }
126}
127
128pub fn is_enabled_log(log_type: u8) -> bool {
129    unsafe { (MASK & log_levels::FLAG_STATE_ON) != 0 && (MASK & log_type) != 0 }
130}
131
132pub fn get_level_log() -> u8 {
133    unsafe { MASK & !log_levels::FLAG_STATE_ON & !log_levels::FLAG_COLOR_ON }
134}
135
136pub fn set_enable_color(enabled: bool) {
137    unsafe {
138        if enabled {
139            MASK |= log_levels::FLAG_COLOR_ON;
140        } else {
141            MASK &= !log_levels::FLAG_COLOR_ON;
142        }
143    }
144}
145
146
147
148pub fn sys_log(tag: &str, log_type: u8, to_print: &str) {
149    unsafe {
150        while BUSY != 0 {}
151        BUSY = 1;
152
153        let mut color_reset = COLOR_RESET;
154        let color = if MASK & log_levels::FLAG_COLOR_ON == log_levels::FLAG_COLOR_ON {
155
156            match log_type {
157                log_levels::FLAG_DEBUG => COLOR_CYAN,
158                log_levels::FLAG_INFO => COLOR_GREEN,
159                log_levels::FLAG_WARNING => COLOR_YELLOW,
160                log_levels::FLAG_ERROR => COLOR_RED,
161                log_levels::FLAG_FATAL => COLOR_MAGENTA,
162                _ => COLOR_RESET,
163            }
164        } else {
165            color_reset = "";
166            ""
167        };
168
169
170        let now = System::get_current_time_us();
171
172
173        #[cfg(not(feature = "std"))]
174        {
175            let formatted = format!("{color}({millis}ms)[{tag}] {to_print}{color_reset}{RETURN}", millis=now.as_millis());
176            if let Ok(c_str) = CString::new(formatted) {
177                printf_on_uart(b"%s\0".as_ptr() as *const c_char, c_str.as_ptr());
178            }
179        }
180
181        #[cfg(feature = "std")]
182        {
183            print!("{}[{}] ", color, tag);
184            core::fmt::write(&mut core::fmt::Formatter::new(), args).unwrap();
185            print!("{}", COLOR_RESET);
186            print!("\r\n");
187        }
188
189        BUSY = 0;
190    }
191}
192
193#[macro_export]
194macro_rules! log_debug {
195    ($app_tag:expr, $fmt:expr $(, $($arg:tt)*)?) => {{
196        if $crate::log::is_enabled_log($crate::log::log_levels::FLAG_DEBUG) {
197            let msg = alloc::format!($fmt $(, $($arg)*)?);
198            $crate::log::sys_log($app_tag, $crate::log::log_levels::FLAG_DEBUG, &msg);
199        }
200    }};
201}
202
203#[macro_export]
204macro_rules! log_info {
205    ($app_tag:expr, $fmt:expr $(, $($arg:tt)*)?) => {{
206        if $crate::log::is_enabled_log($crate::log::log_levels::FLAG_INFO) {
207            let msg = alloc::format!($fmt $(, $($arg)*)?);
208            $crate::log::sys_log($app_tag, $crate::log::log_levels::FLAG_INFO, &msg);
209        }
210    }};
211}
212
213#[macro_export]
214macro_rules! log_warning {
215    ($app_tag:expr, $fmt:expr $(, $($arg:tt)*)?) => {{
216        if $crate::log::is_enabled_log($crate::log::log_levels::FLAG_WARNING) {
217            let msg = alloc::format!($fmt $(, $($arg)*)?);
218            $crate::log::sys_log($app_tag, $crate::log::log_levels::FLAG_WARNING, &msg);
219        }
220    }};
221}
222
223#[macro_export]
224macro_rules! log_error {
225    ($app_tag:expr, $fmt:expr $(, $($arg:tt)*)?) => {{
226        if $crate::log::is_enabled_log($crate::log::log_levels::FLAG_ERROR) {
227            let msg = alloc::format!($fmt $(, $($arg)*)?);
228            $crate::log::sys_log($app_tag, $crate::log::log_levels::FLAG_ERROR, &msg);
229        }
230    }};
231}
232
233#[macro_export]
234macro_rules! log_fatal {
235    ($app_tag:expr, $fmt:expr $(, $($arg:tt)*)?) => {{
236        if $crate::log::is_enabled_log($crate::log::log_levels::FLAG_FATAL) {
237            let msg = alloc::format!($fmt $(, $($arg)*)?);
238            $crate::log::sys_log($app_tag, $crate::log::log_levels::FLAG_FATAL, &msg);
239        }
240    }};
241}