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
184#[allow(dead_code)]
185const COLOR_BLUE: &str = "\x1b[34m";
186/// ANSI escape code for magenta text color
187const COLOR_MAGENTA: &str = "\x1b[35m";
188/// ANSI escape code for cyan text color
189const COLOR_CYAN: &str = "\x1b[36m";
190/// ANSI escape code to reset all text attributes
191const COLOR_RESET: &str = "\x1b[0m";
192/// Carriage return + line feed for proper terminal output
193pub const RETURN: &str = "\r\n";
194
195/// Log level flags and level configurations.
196///
197/// This module defines bit flags for different log levels and combined
198/// level masks for filtering log messages.
199///
200/// # Flag vs Level
201///
202/// - **FLAGS** (`FLAG_*`): Individual bits for each log level, used internally
203/// - **LEVELS** (`LEVEL_*`): Combined masks that include all levels at or above the specified severity
204///
205/// For example, `LEVEL_WARNING` includes WARNING, ERROR, and FATAL flags.
206///
207/// # Usage
208///
209/// ```ignore
210/// use osal_rs::log::log_levels::*;
211/// use osal_rs::log::set_level_log;
212///
213/// // Set minimum level to WARNING (shows WARNING, ERROR, FATAL)
214/// set_level_log(LEVEL_WARNING);
215///
216/// // Check if specific level is enabled
217/// if is_enabled_log(FLAG_DEBUG) {
218/// // Debug is enabled
219/// }
220/// ```
221pub mod log_levels {
222 /// Flag for DEBUG level messages (bit 0, most verbose).
223 ///
224 /// Use for detailed debugging information during development.
225 pub const FLAG_DEBUG: u8 = 1 << 0;
226
227 /// Flag for INFO level messages (bit 1).
228 ///
229 /// Use for informational messages about normal operation.
230 pub const FLAG_INFO: u8 = 1 << 1;
231
232 /// Flag for WARNING level messages (bit 2).
233 ///
234 /// Use for potentially problematic situations that don't prevent operation.
235 pub const FLAG_WARNING: u8 = 1 << 2;
236
237 /// Flag for ERROR level messages (bit 3).
238 ///
239 /// Use for errors that affect functionality but allow continued operation.
240 pub const FLAG_ERROR: u8 = 1 << 3;
241
242 /// Flag for FATAL level messages (bit 4, most severe).
243 ///
244 /// Use for critical errors that prevent continued operation.
245 pub const FLAG_FATAL: u8 = 1 << 4;
246
247 /// Flag to enable color output (bit 6).
248 ///
249 /// When set, log messages are color-coded by severity level.
250 pub const FLAG_COLOR_ON: u8 = 1 << 6;
251
252 /// Flag to enable/disable logging entirely (bit 7).
253 ///
254 /// When clear, all logging is disabled for zero runtime cost.
255 pub const FLAG_STATE_ON: u8 = 1 << 7;
256
257 /// DEBUG level: Shows all messages (DEBUG, INFO, WARNING, ERROR, FATAL).
258 ///
259 /// Most verbose setting, suitable for development and troubleshooting.
260 pub const LEVEL_DEBUG: u8 = FLAG_DEBUG | FLAG_INFO | FLAG_WARNING | FLAG_ERROR | FLAG_FATAL;
261
262 /// INFO level: Shows INFO and above (INFO, WARNING, ERROR, FATAL).
263 ///
264 /// Filters out DEBUG messages, suitable for normal operation.
265 pub const LEVEL_INFO: u8 = FLAG_INFO | FLAG_WARNING | FLAG_ERROR | FLAG_FATAL;
266
267 /// WARNING level: Shows WARNING and above (WARNING, ERROR, FATAL).
268 ///
269 /// Shows only warnings and errors, suitable for production.
270 pub const LEVEL_WARNING: u8 = FLAG_WARNING | FLAG_ERROR | FLAG_FATAL;
271
272 /// ERROR level: Shows ERROR and FATAL only.
273 ///
274 /// Shows only errors and critical failures.
275 pub const LEVEL_ERROR: u8 = FLAG_ERROR | FLAG_FATAL;
276
277 /// FATAL level: Shows only FATAL messages.
278 ///
279 /// Most restrictive setting, shows only critical failures.
280 pub const LEVEL_FATAL: u8 = FLAG_FATAL;
281}
282
283/// Global log level mask with color and state flags enabled by default.
284///
285/// This mutable static holds the current logging configuration:
286/// - Bits 0-4: Log level flags (DEBUG, INFO, WARNING, ERROR, FATAL)
287/// - Bit 6: Color enable flag
288/// - Bit 7: Logging enable/disable flag
289///
290/// # Default
291///
292/// Initialized to `LEVEL_DEBUG | FLAG_COLOR_ON | FLAG_STATE_ON`:
293/// - All log levels enabled
294/// - Color output enabled
295/// - Logging enabled
296///
297/// # Thread Safety
298///
299/// Modifications are not atomic. Use the provided setter functions
300/// (`set_level_log`, `set_enable_log`, `set_enable_color`) which perform
301/// simple bit operations that are effectively atomic on most platforms.
302/// Race conditions during initialization are unlikely to cause issues
303/// beyond temporarily incorrect filter settings.
304static mut MASK: u8 = log_levels::LEVEL_DEBUG | log_levels::FLAG_COLOR_ON | log_levels::FLAG_STATE_ON;
305
306/// Simple busy flag for thread-safe logging (0 = free, non-zero = busy).
307///
308/// Used as a spinlock to ensure only one thread logs at a time:
309/// - 0 = Lock is free, logging available
310/// - Non-zero = Lock is held, other threads must wait
311///
312/// # Synchronization
313///
314/// Uses a basic busy-wait (spinlock) pattern:
315/// 1. Wait until BUSY == 0
316/// 2. Set BUSY = 1
317/// 3. Perform logging
318/// 4. Set BUSY = 0
319///
320/// # Limitations
321///
322/// - Not a true atomic operation (no memory barriers)
323/// - Priority inversion possible (low-priority task holds lock)
324/// - Wastes CPU cycles during contention
325/// - **Never use from ISR context** - can deadlock
326///
327/// This simple approach is sufficient for most embedded use cases where
328/// logging contention is infrequent.
329static mut BUSY: u8 = 0;
330
331/// Prints formatted text to UART without a newline.
332///
333/// This macro is only available in no-std mode. In std mode, use the standard `print!` macro.
334///
335/// # Examples
336///
337/// ```ignore
338/// use osal_rs::print;
339///
340/// print!("Hello");
341/// print!(" World: {}", 42);
342/// ```
343#[cfg(not(feature = "std"))]
344#[macro_export]
345macro_rules! print {
346 ($($arg:tt)*) => {{
347 unsafe {
348 let mut buf = $crate::utils::Bytes::<{$crate::log::LOG_BUFFER_SIZE}>::new();
349 buf.format(format_args!($($arg)*));
350 $crate::log::ffi::printf_on_uart(b"%s\0".as_ptr() as *const core::ffi::c_char, buf.as_cstr().as_ptr());
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 mut buf = $crate::utils::Bytes::<{$crate::log::LOG_BUFFER_SIZE}>::new();
377 buf.format(format_args!(concat!($fmt, "\r\n")));
378 $crate::log::ffi::printf_on_uart(b"%s\0".as_ptr() as *const core::ffi::c_char, buf.as_cstr().as_ptr());
379 }
380 }};
381 ($fmt:expr, $($arg:tt)*) => {{
382 unsafe {
383 let mut buf = $crate::utils::Bytes::<{$crate::log::LOG_BUFFER_SIZE}>::new();
384 buf.format(format_args!(concat!($fmt, "\r\n"), $($arg)*));
385 $crate::log::ffi::printf_on_uart(b"%s\0".as_ptr() as *const core::ffi::c_char, buf.as_cstr().as_ptr());
386 }
387 }};
388}
389
390/// Sets the log level threshold.
391///
392/// Only log messages at or above this level will be displayed.
393///
394/// # Parameters
395///
396/// * `level` - Log level (use constants from `log_levels` module)
397///
398/// # Examples
399///
400/// ```ignore
401/// use osal_rs::log::*;
402///
403/// // Show only warnings and errors
404/// set_level_log(log_levels::LEVEL_WARNING);
405///
406/// // Show all messages
407/// set_level_log(log_levels::LEVEL_DEBUG);
408/// ```
409pub fn set_level_log(level: u8) {
410 unsafe {
411 MASK =
412 (MASK & log_levels::FLAG_STATE_ON) | (level & !log_levels::FLAG_STATE_ON);
413 }
414}
415
416/// Enables or disables all logging.
417///
418/// When disabled, all log macros become no-ops for zero runtime cost.
419///
420/// # Parameters
421///
422/// * `enabled` - `true` to enable logging, `false` to disable
423///
424/// # Examples
425///
426/// ```ignore
427/// use osal_rs::log::set_enable_log;
428///
429/// set_enable_log(false); // Disable all logging
430/// // ... logs will not be printed ...
431/// set_enable_log(true); // Re-enable logging
432/// ```
433pub fn set_enable_log(enabled: bool) {
434 unsafe {
435 if enabled {
436 MASK |= log_levels::FLAG_STATE_ON;
437 } else {
438 MASK &= !log_levels::FLAG_STATE_ON;
439 }
440 }
441}
442
443/// Checks if logging is currently enabled.
444///
445/// # Returns
446///
447/// `true` if logging is enabled, `false` otherwise
448///
449/// # Examples
450///
451/// ```ignore
452/// use osal_rs::log::get_enable_log;
453///
454/// if get_enable_log() {
455/// println!("Logging is active");
456/// }
457/// ```
458pub fn get_enable_log() -> bool {
459 unsafe { (MASK & log_levels::FLAG_STATE_ON) != 0 }
460}
461
462/// Checks if a specific log level is enabled.
463///
464/// # Parameters
465///
466/// * `log_type` - Log level flag to check
467///
468/// # Returns
469///
470/// `true` if the log level is enabled, `false` otherwise
471///
472/// # Examples
473///
474/// ```ignore
475/// use osal_rs::log::*;
476///
477/// if is_enabled_log(log_levels::FLAG_DEBUG) {
478/// // Debug logging is active
479/// }
480/// ```
481pub fn is_enabled_log(log_type: u8) -> bool {
482 unsafe { (MASK & log_levels::FLAG_STATE_ON) != 0 && (MASK & log_type) != 0 }
483}
484
485/// Gets the current log level threshold.
486///
487/// # Returns
488///
489/// Current log level mask (without state and color flags)
490///
491/// # Examples
492///
493/// ```ignore
494/// use osal_rs::log::*;
495///
496/// let level = get_level_log();
497/// ```
498pub fn get_level_log() -> u8 {
499 unsafe { MASK & !log_levels::FLAG_STATE_ON & !log_levels::FLAG_COLOR_ON }
500}
501
502/// Enables or disables color output.
503///
504/// When enabled, log messages are color-coded by severity:
505/// - DEBUG: Cyan
506/// - INFO: Green
507/// - WARNING: Yellow
508/// - ERROR: Red
509/// - FATAL: Magenta
510///
511/// # Parameters
512///
513/// * `enabled` - `true` to enable colors, `false` for plain text
514///
515/// # Examples
516///
517/// ```ignore
518/// use osal_rs::log::set_enable_color;
519///
520/// set_enable_color(true); // Enable colored output
521/// set_enable_color(false); // Disable colors
522/// ```
523pub fn set_enable_color(enabled: bool) {
524 unsafe {
525 if enabled {
526 MASK |= log_levels::FLAG_COLOR_ON;
527 } else {
528 MASK &= !log_levels::FLAG_COLOR_ON;
529 }
530 }
531}
532
533
534
535/// Core logging function that outputs formatted log messages.
536///
537/// This is the low-level function called by all log macros. It handles:
538/// - Thread-safe output using a busy-wait lock
539/// - Color formatting based on log level
540/// - Timestamp prefixing with millisecond precision
541/// - Tag prefixing for message categorization
542///
543/// # Parameters
544///
545/// * `tag` - Category or module name for the log message (e.g., "APP", "NET", "FS")
546/// * `log_type` - Log level flag (DEBUG, INFO, WARNING, ERROR, FATAL)
547/// * `to_print` - The formatted message string to log
548///
549/// # Thread Safety
550///
551/// Uses a busy-wait lock (BUSY flag) to ensure only one thread logs at a time:
552/// 1. Spins until BUSY == 0
553/// 2. Sets BUSY = 1
554/// 3. Formats and outputs the message
555/// 4. Sets BUSY = 0
556///
557/// Other threads will spin-wait during this time.
558///
559/// # Output Format
560///
561/// In `no_std` mode:
562/// ```text
563/// {color}({timestamp}ms)[{tag}] {message}{color_reset}\r\n
564/// ```
565///
566/// Example:
567/// ```text
568/// \x1b[32m(1234ms)[APP] System initialized\x1b[0m\r\n
569/// ```
570///
571/// # Examples
572///
573/// ```ignore
574/// use osal_rs::log::*;
575///
576/// sys_log("APP", log_levels::FLAG_INFO, "Application started");
577/// sys_log("NET", log_levels::FLAG_ERROR, "Connection failed");
578/// ```
579///
580/// # Note
581///
582/// Prefer using the log macros (`log_info!`, `log_error!`, etc.) instead of
583/// calling this function directly. The macros check if the log level is enabled
584/// before formatting the message, avoiding allocation for disabled levels.
585///
586/// # Warning
587///
588/// **Never call from ISR context** - the busy-wait can cause deadlock if a
589/// higher-priority ISR preempts a task that holds the lock.
590pub fn sys_log(tag: &str, log_type: u8, to_print: &str) {
591 unsafe {
592 while BUSY != 0 {}
593 BUSY = 1;
594
595 let mut color_reset = COLOR_RESET;
596 let color = if MASK & log_levels::FLAG_COLOR_ON == log_levels::FLAG_COLOR_ON {
597
598 match log_type {
599 log_levels::FLAG_DEBUG => COLOR_CYAN,
600 log_levels::FLAG_INFO => COLOR_GREEN,
601 log_levels::FLAG_WARNING => COLOR_YELLOW,
602 log_levels::FLAG_ERROR => COLOR_RED,
603 log_levels::FLAG_FATAL => COLOR_MAGENTA,
604 _ => COLOR_RESET,
605 }
606 } else {
607 color_reset = "";
608 ""
609 };
610
611
612 let now = System::get_current_time_us();
613
614
615 #[cfg(not(feature = "std"))]
616 {
617 let mut buf = Bytes::<512>::new();
618 buf.format(format_args!("{color}({millis}ms)[{tag}] {to_print}{color_reset}{RETURN}", millis=now.as_millis()));
619 printf_on_uart(b"%s\0".as_ptr() as *const c_char, buf.as_cstr().as_ptr());
620 }
621
622 #[cfg(feature = "std")]
623 {
624 print!("{}[{}] ", color, tag);
625 core::fmt::write(&mut core::fmt::Formatter::new(), args).unwrap();
626 print!("{}", COLOR_RESET);
627 print!("\r\n");
628 }
629
630 BUSY = 0;
631 }
632}
633
634/// Logs a DEBUG level message.
635///
636/// Debug messages are the most verbose and typically used during development.
637/// Color: Cyan (if colors are enabled)
638///
639/// # Parameters
640///
641/// * `app_tag` - Category or module identifier
642/// * `fmt` - Format string
643/// * `arg` - Optional format arguments
644///
645/// # Examples
646///
647/// ```ignore
648/// use osal_rs::log_debug;
649///
650/// log_debug!("APP", "Initializing subsystem");
651/// log_debug!("APP", "Counter: {}, Status: {}", counter, status);
652/// ```
653#[macro_export]
654macro_rules! log_debug {
655 ($app_tag:expr, $fmt:expr $(, $($arg:tt)*)?) => {{
656 if $crate::log::is_enabled_log($crate::log::log_levels::FLAG_DEBUG) {
657 let mut msg = $crate::utils::Bytes::<{$crate::log::LOG_BUFFER_SIZE}>::new();
658 msg.format(format_args!($fmt $(, $($arg)*)?));
659 $crate::log::sys_log($app_tag, $crate::log::log_levels::FLAG_DEBUG, msg.as_str());
660 }
661 }};
662}
663
664/// Logs an INFO level message.
665///
666/// Informational messages about normal application operation.
667/// Color: Green (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/// ```ignore
678/// use osal_rs::log_info;
679///
680/// log_info!("APP", "System initialized successfully");
681/// log_info!("NET", "Connected to server at {}", ip_addr);
682/// ```
683#[macro_export]
684macro_rules! log_info {
685 ($app_tag:expr, $fmt:expr $(, $($arg:tt)*)?) => {{
686 if $crate::log::is_enabled_log($crate::log::log_levels::FLAG_INFO) {
687 let mut msg = $crate::utils::Bytes::<{$crate::log::LOG_BUFFER_SIZE}>::new();
688 msg.format(format_args!($fmt $(, $($arg)*)?));
689 $crate::log::sys_log($app_tag, $crate::log::log_levels::FLAG_INFO, msg.as_str());
690 }
691 }};
692}
693
694/// Logs a WARNING level message.
695///
696/// Warning messages indicate potential issues that don't prevent operation.
697/// Color: Yellow (if colors are enabled)
698///
699/// # Parameters
700///
701/// * `app_tag` - Category or module identifier
702/// * `fmt` - Format string
703/// * `arg` - Optional format arguments
704///
705/// # Examples
706///
707/// ```ignore
708/// use osal_rs::log_warning;
709///
710/// log_warning!("MEM", "Memory usage above 80%");
711/// log_warning!("SENSOR", "Temperature high: {} C", temp);
712/// ```
713#[macro_export]
714macro_rules! log_warning {
715 ($app_tag:expr, $fmt:expr $(, $($arg:tt)*)?) => {{
716 if $crate::log::is_enabled_log($crate::log::log_levels::FLAG_WARNING) {
717 let mut msg = $crate::utils::Bytes::<{$crate::log::LOG_BUFFER_SIZE}>::new();
718 msg.format(format_args!($fmt $(, $($arg)*)?));
719 $crate::log::sys_log($app_tag, $crate::log::log_levels::FLAG_WARNING, msg.as_str());
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 mut msg = $crate::utils::Bytes::<{$crate::log::LOG_BUFFER_SIZE}>::new();
748 msg.format(format_args!($fmt $(, $($arg)*)?));
749 $crate::log::sys_log($app_tag, $crate::log::log_levels::FLAG_ERROR, msg.as_str());
750 }
751 }};
752}
753
754/// Logs a FATAL level message.
755///
756/// Fatal messages indicate critical errors that prevent continued operation.
757/// Color: Magenta (if colors are enabled)
758///
759/// # Parameters
760///
761/// * `app_tag` - Category or module identifier
762/// * `fmt` - Format string
763/// * `arg` - Optional format arguments
764///
765/// # Examples
766///
767/// ```ignore
768/// use osal_rs::log_fatal;
769///
770/// log_fatal!("SYS", "Kernel panic!");
771/// log_fatal!("HW", "Hardware fault detected: {}", fault_code);
772/// ```
773#[macro_export]
774macro_rules! log_fatal {
775 ($app_tag:expr, $fmt:expr $(, $($arg:tt)*)?) => {{
776 if $crate::log::is_enabled_log($crate::log::log_levels::FLAG_FATAL) {
777 let mut msg = $crate::utils::Bytes::<{$crate::log::LOG_BUFFER_SIZE}>::new();
778 msg.format(format_args!($fmt $(, $($arg)*)?));
779 $crate::log::sys_log($app_tag, $crate::log::log_levels::FLAG_FATAL, msg.as_str());
780 }
781 }};
782}