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