Skip to main content

osal_rs/
log.rs

1/***************************************************************************
2 *
3 * osal-rs
4 * Copyright (C) 2026 Antonio Salsi <passy.linux@zresa.it>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <https://www.gnu.org/licenses/>.
18 *
19 ***************************************************************************/
20
21//! Logging system for embedded environments.
22//!
23//! Provides a flexible logging system with multiple severity levels and color support.
24//! Designed for no-std environments with UART output support.
25//!
26//! # Features
27//!
28//! - Multiple log levels (DEBUG, INFO, WARNING, ERROR, FATAL)
29//! - Color-coded output support (ANSI colors)
30//! - Timestamp logging with millisecond precision
31//! - Thread-safe logging with busy-wait synchronization
32//! - Configurable log level masking
33//! - Zero-cost when logs are disabled
34//!
35//! # Examples
36//!
37//! ## Basic logging
38//!
39//! ```ignore
40//! use osal_rs::{log_info, log_error, log_debug};
41//! 
42//! log_info!("APP", "Application started");
43//! log_debug!("APP", "Counter value: {}", 42);
44//! log_error!("APP", "Failed to initialize: {}", error_msg);
45//! ```
46//!
47//! ## Configuring log levels
48//!
49//! ```ignore
50//! use osal_rs::log::*;
51//! 
52//! // Set log level to WARNING and above
53//! set_level_log(log_levels::LEVEL_WARNING);
54//! 
55//! // Enable/disable logging
56//! set_enable_log(true);
57//! 
58//! // Enable/disable color output
59//! set_enable_color(true);
60//! ```
61//!
62//! ## Using print macros
63//!
64//! ```ignore
65//! use osal_rs::{print, println};
66//! 
67//! print!("Hello");
68//! println!(" World!");
69//! println!("Value: {}", 123);
70//! ```
71//!
72//! # Thread Safety
73//!
74//! The logging system uses a simple busy-wait lock to ensure thread-safe output:
75//! - Only one thread can log at a time
76//! - Other threads spin-wait until the log is complete
77//! - No heap allocation during the lock
78//! - Suitable for task context only (see ISR Context below)
79//!
80//! # ISR Context
81//!
82//! **WARNING**: Do not use logging macros from interrupt service routines (ISRs).
83//! 
84//! Reasons:
85//! - Busy-wait lock can cause priority inversion
86//! - String formatting allocates memory
87//! - UART operations may block
88//! - Can significantly delay interrupt response
89//!
90//! If you need logging from ISR context, use a queue to defer the log to a task.
91//!
92//! # Performance Considerations
93//!
94//! - Each log call allocates a string (uses RTOS heap)
95//! - UART transmission is synchronous and relatively slow
96//! - Verbose logging (DEBUG level) can impact real-time performance
97//! - Consider using WARNING or ERROR level in production
98//! - Logs are compiled out when the level is disabled (zero cost)
99//!
100//! # Color Output
101//!
102//! When colors are enabled, log levels are color-coded:
103//! - **DEBUG**: Cyan - Detailed debugging information
104//! - **INFO**: Green - Normal operational messages
105//! - **WARNING**: Yellow - Potential issues, non-critical
106//! - **ERROR**: Red - Errors affecting functionality
107//! - **FATAL**: Magenta - Critical errors, system failure
108//!
109//! Disable colors if your terminal doesn't support ANSI escape codes.
110//!
111//! # Best Practices
112//!
113//! 1. **Use appropriate tags**: Use meaningful tags like "NET", "FS", "APP" to identify sources
114//! 2. **Choose correct levels**: DEBUG for development, INFO for milestones, ERROR for failures
115//! 3. **Avoid logging in hot paths**: Logging can significantly slow down tight loops
116//! 4. **Set production levels**: Use WARNING or ERROR level in production builds
117//! 5. **Never log from ISRs**: Defer to task context using queues or notifications
118
119#[cfg(not(feature = "std"))]
120pub mod ffi {
121    //! Foreign Function Interface (FFI) to C UART functions.
122    //!
123    //! This module provides low-level bindings to C functions for UART communication.
124    //! These functions are only available in `no_std` mode.
125    //!
126    //! # Safety
127    //!
128    //! All functions in this module are `unsafe` because they:
129    //! - Call external C code that cannot be verified by Rust
130    //! - Require valid C string pointers (null-terminated)
131    //! - May access hardware registers directly
132    //! - Do not perform bounds checking
133    //!
134    //! # Platform Requirements
135    //!
136    //! The C implementation must provide `printf_on_uart` that:
137    //! - Accepts printf-style format strings
138    //! - Outputs to UART hardware
139    //! - Is thread-safe (or only called from synchronized contexts)
140    //! - Returns number of characters written, or negative on error
141    
142    use core::ffi::{c_char, c_int};
143
144    unsafe extern "C" {
145        /// FFI function to print formatted strings to UART.
146        ///
147        /// This is the low-level C function that interfaces with the hardware UART.
148        /// Typically implemented in the platform-specific porting layer.
149        ///
150        /// # Safety
151        ///
152        /// - `format` must be a valid null-terminated C string
153        /// - Variable arguments must match the format specifiers
154        /// - Must not be called from multiple threads simultaneously (unless C implementation is thread-safe)
155        ///
156        /// # Parameters
157        ///
158        /// * `format` - Printf-style format string (null-terminated)
159        /// * `...` - Variable arguments matching format specifiers
160        ///
161        /// # Returns
162        ///
163        /// Number of characters written, or negative value on error
164        pub fn printf_on_uart(format: *const c_char, ...) -> c_int;
165
166    }
167}
168
169use core::ffi::c_char;
170
171use crate::log::ffi::printf_on_uart;
172use crate::os::{System, SystemFn};
173use crate::utils::Bytes;
174
175pub const LOG_BUFFER_SIZE: usize = 256;
176
177/// ANSI escape code for red text color
178const COLOR_RED: &str = "\x1b[31m";
179/// ANSI escape code for green text color
180const COLOR_GREEN: &str = "\x1b[32m";
181/// ANSI escape code for yellow text color
182const COLOR_YELLOW: &str = "\x1b[33m";
183/// ANSI escape code for blue text color
184const COLOR_BLUE: &str = "\x1b[34m";
185/// ANSI escape code for magenta text color
186const COLOR_MAGENTA: &str = "\x1b[35m";
187/// ANSI escape code for cyan text color
188const COLOR_CYAN: &str = "\x1b[36m";
189/// ANSI escape code to reset all text attributes
190const COLOR_RESET: &str = "\x1b[0m";
191/// Carriage return + line feed for proper terminal output
192pub const RETURN: &str = "\r\n";
193
194/// Log level flags and level configurations.
195///
196/// This module defines bit flags for different log levels and combined
197/// level masks for filtering log messages.
198///
199/// # Flag vs Level
200///
201/// - **FLAGS** (`FLAG_*`): Individual bits for each log level, used internally
202/// - **LEVELS** (`LEVEL_*`): Combined masks that include all levels at or above the specified severity
203///
204/// For example, `LEVEL_WARNING` includes WARNING, ERROR, and FATAL flags.
205///
206/// # Usage
207///
208/// ```ignore
209/// use osal_rs::log::log_levels::*;
210/// use osal_rs::log::set_level_log;
211///
212/// // Set minimum level to WARNING (shows WARNING, ERROR, FATAL)
213/// set_level_log(LEVEL_WARNING);
214///
215/// // Check if specific level is enabled
216/// if is_enabled_log(FLAG_DEBUG) {
217///     // Debug is enabled
218/// }
219/// ```
220pub mod log_levels {
221    /// Flag for DEBUG level messages (bit 0, most verbose).
222    ///
223    /// Use for detailed debugging information during development.
224    pub const FLAG_DEBUG: u8 = 1 << 0;
225    
226    /// Flag for INFO level messages (bit 1).
227    ///
228    /// Use for informational messages about normal operation.
229    pub const FLAG_INFO: u8 = 1 << 1;
230    
231    /// Flag for WARNING level messages (bit 2).
232    ///
233    /// Use for potentially problematic situations that don't prevent operation.
234    pub const FLAG_WARNING: u8 = 1 << 2;
235    
236    /// Flag for ERROR level messages (bit 3).
237    ///
238    /// Use for errors that affect functionality but allow continued operation.
239    pub const FLAG_ERROR: u8 = 1 << 3;
240    
241    /// Flag for FATAL level messages (bit 4, most severe).
242    ///
243    /// Use for critical errors that prevent continued operation.
244    pub const FLAG_FATAL: u8 = 1 << 4;
245    
246    /// Flag to enable color output (bit 6).
247    ///
248    /// When set, log messages are color-coded by severity level.
249    pub const FLAG_COLOR_ON: u8 = 1 << 6;
250    
251    /// Flag to enable/disable logging entirely (bit 7).
252    ///
253    /// When clear, all logging is disabled for zero runtime cost.
254    pub const FLAG_STATE_ON: u8 = 1 << 7;
255
256    /// DEBUG level: Shows all messages (DEBUG, INFO, WARNING, ERROR, FATAL).
257    ///
258    /// Most verbose setting, suitable for development and troubleshooting.
259    pub const LEVEL_DEBUG: u8 = FLAG_DEBUG | FLAG_INFO | FLAG_WARNING | FLAG_ERROR | FLAG_FATAL;
260    
261    /// INFO level: Shows INFO and above (INFO, WARNING, ERROR, FATAL).
262    ///
263    /// Filters out DEBUG messages, suitable for normal operation.
264    pub const LEVEL_INFO: u8 = FLAG_INFO | FLAG_WARNING | FLAG_ERROR | FLAG_FATAL;
265    
266    /// WARNING level: Shows WARNING and above (WARNING, ERROR, FATAL).
267    ///
268    /// Shows only warnings and errors, suitable for production.
269    pub const LEVEL_WARNING: u8 = FLAG_WARNING | FLAG_ERROR | FLAG_FATAL;
270    
271    /// ERROR level: Shows ERROR and FATAL only.
272    ///
273    /// Shows only errors and critical failures.
274    pub const LEVEL_ERROR: u8 = FLAG_ERROR | FLAG_FATAL;
275
276    /// FATAL level: Shows only FATAL messages.
277    ///
278    /// Most restrictive setting, shows only critical failures.
279    pub const LEVEL_FATAL: u8 = FLAG_FATAL;
280}
281
282/// Global log level mask with color and state flags enabled by default.
283///
284/// This mutable static holds the current logging configuration:
285/// - Bits 0-4: Log level flags (DEBUG, INFO, WARNING, ERROR, FATAL)
286/// - Bit 6: Color enable flag
287/// - Bit 7: Logging enable/disable flag
288///
289/// # Default
290///
291/// Initialized to `LEVEL_DEBUG | FLAG_COLOR_ON | FLAG_STATE_ON`:
292/// - All log levels enabled
293/// - Color output enabled
294/// - Logging enabled
295///
296/// # Thread Safety
297///
298/// Modifications are not atomic. Use the provided setter functions
299/// (`set_level_log`, `set_enable_log`, `set_enable_color`) which perform
300/// simple bit operations that are effectively atomic on most platforms.
301/// Race conditions during initialization are unlikely to cause issues
302/// beyond temporarily incorrect filter settings.
303static mut MASK: u8 = log_levels::LEVEL_DEBUG | log_levels::FLAG_COLOR_ON | log_levels::FLAG_STATE_ON;
304
305/// Simple busy flag for thread-safe logging (0 = free, non-zero = busy).
306///
307/// Used as a spinlock to ensure only one thread logs at a time:
308/// - 0 = Lock is free, logging available
309/// - Non-zero = Lock is held, other threads must wait
310///
311/// # Synchronization
312///
313/// Uses a basic busy-wait (spinlock) pattern:
314/// 1. Wait until BUSY == 0
315/// 2. Set BUSY = 1
316/// 3. Perform logging
317/// 4. Set BUSY = 0
318///
319/// # Limitations
320///
321/// - Not a true atomic operation (no memory barriers)
322/// - Priority inversion possible (low-priority task holds lock)
323/// - Wastes CPU cycles during contention
324/// - **Never use from ISR context** - can deadlock
325///
326/// This simple approach is sufficient for most embedded use cases where
327/// logging contention is infrequent.
328static mut BUSY: u8 = 0;
329
330/// Prints formatted text to UART without a newline.
331///
332/// This macro is only available in no-std mode. In std mode, use the standard `print!` macro.
333///
334/// # Examples
335///
336/// ```ignore
337/// use osal_rs::print;
338/// 
339/// print!("Hello");
340/// print!(" World: {}", 42);
341/// ```
342#[cfg(not(feature = "std"))]
343#[macro_export]
344macro_rules! print {
345    ($($arg:tt)*) => {{
346        unsafe {
347            let mut buf = $crate::utils::Bytes::<{$crate::log::LOG_BUFFER_SIZE}>::new();
348            buf.format(format_args!($($arg)*));
349            $crate::log::ffi::printf_on_uart(b"%s\0".as_ptr() as *const core::ffi::c_char, buf.as_cstr().as_ptr());
350        }
351    }};
352}
353
354/// Prints formatted text to UART with a newline (\r\n).
355///
356/// This macro is only available in no-std mode. In std mode, use the standard `println!` macro.
357///
358/// # Examples
359///
360/// ```ignore
361/// use osal_rs::println;
362/// 
363/// println!("Hello World");
364/// println!("Value: {}", 42);
365/// println!();  // Just a newline
366/// ```
367#[cfg(not(feature = "std"))]
368#[macro_export]
369macro_rules! println {
370    () => {
371        $crate::print!("\r\n")
372    };
373    ($fmt:expr) => {{
374        unsafe {
375            let mut buf = $crate::utils::Bytes::<{$crate::log::LOG_BUFFER_SIZE}>::new();
376            buf.format(format_args!(concat!($fmt, "\r\n")));
377            $crate::log::ffi::printf_on_uart(b"%s\0".as_ptr() as *const core::ffi::c_char, buf.as_cstr().as_ptr());
378        }
379    }};
380    ($fmt:expr, $($arg:tt)*) => {{
381        unsafe {
382            let mut buf = $crate::utils::Bytes::<{$crate::log::LOG_BUFFER_SIZE}>::new();
383            buf.format(format_args!(concat!($fmt, "\r\n"), $($arg)*));
384            $crate::log::ffi::printf_on_uart(b"%s\0".as_ptr() as *const core::ffi::c_char, buf.as_cstr().as_ptr());
385        }
386    }};
387}
388
389/// Sets the log level threshold.
390///
391/// Only log messages at or above this level will be displayed.
392///
393/// # Parameters
394///
395/// * `level` - Log level (use constants from `log_levels` module)
396///
397/// # Examples
398///
399/// ```ignore
400/// use osal_rs::log::*;
401/// 
402/// // Show only warnings and errors
403/// set_level_log(log_levels::LEVEL_WARNING);
404/// 
405/// // Show all messages
406/// set_level_log(log_levels::LEVEL_DEBUG);
407/// ```
408pub fn set_level_log(level: u8) {
409    unsafe {
410        MASK =
411            (MASK & log_levels::FLAG_STATE_ON) | (level & !log_levels::FLAG_STATE_ON);
412    }
413}
414
415/// Enables or disables all logging.
416///
417/// When disabled, all log macros become no-ops for zero runtime cost.
418///
419/// # Parameters
420///
421/// * `enabled` - `true` to enable logging, `false` to disable
422///
423/// # Examples
424///
425/// ```ignore
426/// use osal_rs::log::set_enable_log;
427/// 
428/// set_enable_log(false);  // Disable all logging
429/// // ... logs will not be printed ...
430/// set_enable_log(true);   // Re-enable logging
431/// ```
432pub fn set_enable_log(enabled: bool) {
433    unsafe {
434        if enabled {
435            MASK |= log_levels::FLAG_STATE_ON;
436        } else {
437            MASK &= !log_levels::FLAG_STATE_ON;
438        }
439    }
440}
441
442/// Checks if logging is currently enabled.
443///
444/// # Returns
445///
446/// `true` if logging is enabled, `false` otherwise
447///
448/// # Examples
449///
450/// ```ignore
451/// use osal_rs::log::get_enable_log;
452/// 
453/// if get_enable_log() {
454///     println!("Logging is active");
455/// }
456/// ```
457pub fn get_enable_log() -> bool {
458    unsafe { (MASK & log_levels::FLAG_STATE_ON) != 0 }
459}
460
461/// Checks if a specific log level is enabled.
462///
463/// # Parameters
464///
465/// * `log_type` - Log level flag to check
466///
467/// # Returns
468///
469/// `true` if the log level is enabled, `false` otherwise
470///
471/// # Examples
472///
473/// ```ignore
474/// use osal_rs::log::*;
475/// 
476/// if is_enabled_log(log_levels::FLAG_DEBUG) {
477///     // Debug logging is active
478/// }
479/// ```
480pub fn is_enabled_log(log_type: u8) -> bool {
481    unsafe { (MASK & log_levels::FLAG_STATE_ON) != 0 && (MASK & log_type) != 0 }
482}
483
484/// Gets the current log level threshold.
485///
486/// # Returns
487///
488/// Current log level mask (without state and color flags)
489///
490/// # Examples
491///
492/// ```ignore
493/// use osal_rs::log::*;
494/// 
495/// let level = get_level_log();
496/// ```
497pub fn get_level_log() -> u8 {
498    unsafe { MASK & !log_levels::FLAG_STATE_ON & !log_levels::FLAG_COLOR_ON }
499}
500
501/// Enables or disables color output.
502///
503/// When enabled, log messages are color-coded by severity:
504/// - DEBUG: Cyan
505/// - INFO: Green  
506/// - WARNING: Yellow
507/// - ERROR: Red
508/// - FATAL: Magenta
509///
510/// # Parameters
511///
512/// * `enabled` - `true` to enable colors, `false` for plain text
513///
514/// # Examples
515///
516/// ```ignore
517/// use osal_rs::log::set_enable_color;
518/// 
519/// set_enable_color(true);   // Enable colored output
520/// set_enable_color(false);  // Disable colors
521/// ```
522pub fn set_enable_color(enabled: bool) {
523    unsafe {
524        if enabled {
525            MASK |= log_levels::FLAG_COLOR_ON;
526        } else {
527            MASK &= !log_levels::FLAG_COLOR_ON;
528        }
529    }
530}
531
532
533
534/// Core logging function that outputs formatted log messages.
535///
536/// This is the low-level function called by all log macros. It handles:
537/// - Thread-safe output using a busy-wait lock
538/// - Color formatting based on log level
539/// - Timestamp prefixing with millisecond precision
540/// - Tag prefixing for message categorization
541///
542/// # Parameters
543///
544/// * `tag` - Category or module name for the log message (e.g., "APP", "NET", "FS")
545/// * `log_type` - Log level flag (DEBUG, INFO, WARNING, ERROR, FATAL)
546/// * `to_print` - The formatted message string to log
547///
548/// # Thread Safety
549///
550/// Uses a busy-wait lock (BUSY flag) to ensure only one thread logs at a time:
551/// 1. Spins until BUSY == 0
552/// 2. Sets BUSY = 1
553/// 3. Formats and outputs the message
554/// 4. Sets BUSY = 0
555///
556/// Other threads will spin-wait during this time.
557///
558/// # Output Format
559///
560/// In `no_std` mode:
561/// ```text
562/// {color}({timestamp}ms)[{tag}] {message}{color_reset}\r\n
563/// ```
564///
565/// Example:
566/// ```text
567/// \x1b[32m(1234ms)[APP] System initialized\x1b[0m\r\n
568/// ```
569///
570/// # Examples
571///
572/// ```ignore
573/// use osal_rs::log::*;
574/// 
575/// sys_log("APP", log_levels::FLAG_INFO, "Application started");
576/// sys_log("NET", log_levels::FLAG_ERROR, "Connection failed");
577/// ```
578///
579/// # Note
580///
581/// Prefer using the log macros (`log_info!`, `log_error!`, etc.) instead of
582/// calling this function directly. The macros check if the log level is enabled
583/// before formatting the message, avoiding allocation for disabled levels.
584///
585/// # Warning
586///
587/// **Never call from ISR context** - the busy-wait can cause deadlock if a
588/// higher-priority ISR preempts a task that holds the lock.
589pub fn sys_log(tag: &str, log_type: u8, to_print: &str) {
590    unsafe {
591        while BUSY != 0 {}
592        BUSY = 1;
593
594        let mut color_reset = COLOR_RESET;
595        let color = if MASK & log_levels::FLAG_COLOR_ON == log_levels::FLAG_COLOR_ON {
596
597            match log_type {
598                log_levels::FLAG_DEBUG => COLOR_CYAN,
599                log_levels::FLAG_INFO => COLOR_GREEN,
600                log_levels::FLAG_WARNING => COLOR_YELLOW,
601                log_levels::FLAG_ERROR => COLOR_RED,
602                log_levels::FLAG_FATAL => COLOR_MAGENTA,
603                _ => COLOR_RESET,
604            }
605        } else {
606            color_reset = "";
607            ""
608        };
609
610
611        let now = System::get_current_time_us();
612
613
614        #[cfg(not(feature = "std"))]
615        {
616            let mut buf = Bytes::<512>::new();
617            buf.format(format_args!("{color}({millis}ms)[{tag}] {to_print}{color_reset}{RETURN}", millis=now.as_millis()));
618            printf_on_uart(b"%s\0".as_ptr() as *const c_char, buf.as_cstr().as_ptr());
619        }
620
621        #[cfg(feature = "std")]
622        {
623            print!("{}[{}] ", color, tag);
624            core::fmt::write(&mut core::fmt::Formatter::new(), args).unwrap();
625            print!("{}", COLOR_RESET);
626            print!("\r\n");
627        }
628
629        BUSY = 0;
630    }
631}
632
633/// Logs a DEBUG level message.
634///
635/// Debug messages are the most verbose and typically used during development.
636/// Color: Cyan (if colors are enabled)
637///
638/// # Parameters
639///
640/// * `app_tag` - Category or module identifier
641/// * `fmt` - Format string
642/// * `arg` - Optional format arguments
643///
644/// # Examples
645///
646/// ```ignore
647/// use osal_rs::log_debug;
648/// 
649/// log_debug!("APP", "Initializing subsystem");
650/// log_debug!("APP", "Counter: {}, Status: {}", counter, status);
651/// ```
652#[macro_export]
653macro_rules! log_debug {
654    ($app_tag:expr, $fmt:expr $(, $($arg:tt)*)?) => {{
655        if $crate::log::is_enabled_log($crate::log::log_levels::FLAG_DEBUG) {
656            let mut msg = $crate::utils::Bytes::<{$crate::log::LOG_BUFFER_SIZE}>::new();
657            msg.format(format_args!($fmt $(, $($arg)*)?));
658            $crate::log::sys_log($app_tag, $crate::log::log_levels::FLAG_DEBUG, msg.as_str());
659        }
660    }};
661}
662
663/// Logs an INFO level message.
664///
665/// Informational messages about normal application operation.
666/// Color: Green (if colors are enabled)
667///
668/// # Parameters
669///
670/// * `app_tag` - Category or module identifier
671/// * `fmt` - Format string  
672/// * `arg` - Optional format arguments
673///
674/// # Examples
675///
676/// ```ignore
677/// use osal_rs::log_info;
678/// 
679/// log_info!("APP", "System initialized successfully");
680/// log_info!("NET", "Connected to server at {}", ip_addr);
681/// ```
682#[macro_export]
683macro_rules! log_info {
684    ($app_tag:expr, $fmt:expr $(, $($arg:tt)*)?) => {{
685        if $crate::log::is_enabled_log($crate::log::log_levels::FLAG_INFO) {
686            let mut msg = $crate::utils::Bytes::<{$crate::log::LOG_BUFFER_SIZE}>::new();
687            msg.format(format_args!($fmt $(, $($arg)*)?));
688            $crate::log::sys_log($app_tag, $crate::log::log_levels::FLAG_INFO, msg.as_str());
689        }
690    }};
691}
692
693/// Logs a WARNING level message.
694///
695/// Warning messages indicate potential issues that don't prevent operation.
696/// Color: Yellow (if colors are enabled)
697///
698/// # Parameters
699///
700/// * `app_tag` - Category or module identifier
701/// * `fmt` - Format string
702/// * `arg` - Optional format arguments
703///
704/// # Examples
705///
706/// ```ignore
707/// use osal_rs::log_warning;
708/// 
709/// log_warning!("MEM", "Memory usage above 80%");
710/// log_warning!("SENSOR", "Temperature high: {} C", temp);
711/// ```
712#[macro_export]
713macro_rules! log_warning {
714    ($app_tag:expr, $fmt:expr $(, $($arg:tt)*)?) => {{
715        if $crate::log::is_enabled_log($crate::log::log_levels::FLAG_WARNING) {
716            let mut msg = $crate::utils::Bytes::<{$crate::log::LOG_BUFFER_SIZE}>::new();
717            msg.format(format_args!($fmt $(, $($arg)*)?));
718            $crate::log::sys_log($app_tag, $crate::log::log_levels::FLAG_WARNING, msg.as_str());
719        }
720    }};
721}
722
723/// Logs an ERROR level message.
724///
725/// Error messages indicate failures that affect functionality.
726/// Color: Red (if colors are enabled)
727///
728/// # Parameters
729///
730/// * `app_tag` - Category or module identifier
731/// * `fmt` - Format string
732/// * `arg` - Optional format arguments
733///
734/// # Examples
735///
736/// ```ignore
737/// use osal_rs::log_error;
738/// 
739/// log_error!("FS", "Failed to open file");
740/// log_error!("NET", "Connection timeout: {}", error);
741/// ```
742#[macro_export]
743macro_rules! log_error {
744    ($app_tag:expr, $fmt:expr $(, $($arg:tt)*)?) => {{
745        if $crate::log::is_enabled_log($crate::log::log_levels::FLAG_ERROR) {
746            let mut msg = $crate::utils::Bytes::<{$crate::log::LOG_BUFFER_SIZE}>::new();
747            msg.format(format_args!($fmt $(, $($arg)*)?));
748            $crate::log::sys_log($app_tag, $crate::log::log_levels::FLAG_ERROR, msg.as_str());
749        }
750    }};
751}
752
753/// Logs a FATAL level message.
754///
755/// Fatal messages indicate critical errors that prevent continued operation.
756/// Color: Magenta (if colors are enabled)
757///
758/// # Parameters
759///
760/// * `app_tag` - Category or module identifier
761/// * `fmt` - Format string
762/// * `arg` - Optional format arguments
763///
764/// # Examples
765///
766/// ```ignore
767/// use osal_rs::log_fatal;
768/// 
769/// log_fatal!("SYS", "Kernel panic!");
770/// log_fatal!("HW", "Hardware fault detected: {}", fault_code);
771/// ```
772#[macro_export]
773macro_rules! log_fatal {
774    ($app_tag:expr, $fmt:expr $(, $($arg:tt)*)?) => {{
775        if $crate::log::is_enabled_log($crate::log::log_levels::FLAG_FATAL) {
776            let mut msg = $crate::utils::Bytes::<{$crate::log::LOG_BUFFER_SIZE}>::new();
777            msg.format(format_args!($fmt $(, $($arg)*)?));
778            $crate::log::sys_log($app_tag, $crate::log::log_levels::FLAG_FATAL, msg.as_str());
779        }
780    }};
781}