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