px-fwlib 0.10.0
Cross-platform embedded library and documentation for 8/16/32-bit microcontrollers generated with Doxygen 1.9.2
px_log.h
1#ifndef __PX_LOG_H__
2#define __PX_LOG_H__
3/* =============================================================================
4 ____ ___ ____ ___ _ _ ___ __ __ ___ __ __ TM
5 | _ \ |_ _| / ___| / _ \ | \ | | / _ \ | \/ | |_ _| \ \/ /
6 | |_) | | | | | | | | | | \| | | | | | | |\/| | | | \ /
7 | __/ | | | |___ | |_| | | |\ | | |_| | | | | | | | / \
8 |_| |___| \____| \___/ |_| \_| \___/ |_| |_| |___| /_/\_\
9
10 Copyright (c) 2007 Pieter Conradie <https://piconomix.com>
11
12 License: MIT
13 https://github.com/piconomix/px-fwlib/blob/master/LICENSE.md
14
15 Title: px_log.h : Debug log module
16 Author(s): Pieter Conradie
17 Creation Date: 2007-03-31
18
19============================================================================= */
20/**
21 * @ingroup UTILS
22 * @defgroup PX_LOG px_log.h : Debug log module
23 *
24 * Output human readable debug info to a serial console.
25 *
26 * File(s):
27 * - utils/inc/px_log.h
28 * - utils/inc/px_log_cfg_template.h
29 * - utils/inc/px_log_color.h
30 * - utils/src/px_log.c
31 *
32 * An old school debugging technique which still works well is to add debug
33 * print statements in the source code to track program flow and check for
34 * coding mistakes during development. Afterwards the debug print statements
35 * are removed from the final release build to avoid the significant code and
36 * delay overhead.
37 *
38 * This module allows one to easily add formatted debug print macros to the
39 * source code and enable them by defining PX_LOG=1 or remove them from the
40 * build by defining PX_LOG=0 in the Makefile. There is no need to manually
41 * edit the source code afterwards for the release build.
42 *
43 * ![Debug output on Tera Term](px_log_test.png)
44 *
45 * The following macros can be used:
46 * - PX_LOG_E() to report an ERROR message (RED)
47 * - PX_LOG_W() to report a WARNING message (YELLOW)
48 * - PX_LOG_I() to report an INFO message (GREEN)
49 * - PX_LOG_D() to report a DEBUG message (BLUE)
50 * - PX_LOG_V() to report a VERBOSE message (CYAN)
51 * - PX_LOG_ASSERT() to test an expression and halt if it is false, for example
52 * to make sure that a pointer is not NULL before using it.
53 * - PX_LOG_TRACE() to output a formatted string
54 *
55 * #PX_LOG_CFG_LEVEL is used to specify which log messages are compiled into
56 * the source code. For example if #PX_LOG_CFG_LEVEL is set to PX_LOG_LEVEL_INFO
57 * then all ERROR, WARNING and INFO messages will be included in the code but
58 * VERBOSE and DEBUG message will not. It does not affect PX_LOG_TRACE() or
59 * PX_LOG_ASSERT() macros.
60 *
61 * Set #PX_LOG_CFG_COLOR to 1 to indicate log message level with color on
62 * an ANSI/VT100 terminal emulator (for example
63 * [Tera Term](http://en.sourceforge.jp/projects/ttssh2)).
64 *
65 * Example usage:
66 *
67 * @code{.c}
68 * PX_LOG_I("This word is " PX_LOG_FG_GREEN "green" PX_LOG_CR);
69 * @endcode
70 *
71 * @tip_s
72 * Observe that the compiler will automatically concatenate adjacent strings.
73 * @tip_e
74 *
75 * The log messages will report the file / module name and line number as
76 * well as the user format string. To save code space, the name must be
77 * declared at the top of the C file using PX_LOG_NAME(). This is the correct
78 * way to declare the name:
79 *
80 * @code{.c}
81 * #include "px_log.h"
82 * PX_LOG_NAME("module / file name"); // Or PX_LOG_NAME(__FILE__);
83 * @endcode
84 *
85 * @warn_s
86 * If PX_LOG_NAME() is not used, then the compiler will output the
87 * following error when log output is enabled (PX_LOG=1):
88 * @warn_e
89 *
90 * error: '_px_log_name' undeclared (first use in this function)
91 *
92 * The log output can be redirected by using the PX_LOG_CFG_PUTCHAR macro,
93 * for example to stderr stream, a different uart or to a log file on an SD
94 * card.
95 *
96 * Example:
97 *
98 * @include utils/test/px_log_test.c
99 *
100 * The project wide #PX_LOG_CFG_LEVEL setting in the Makefile or
101 * "px_log_cfg.h" can be overriden for a specific C file as follows:
102 *
103 * @code{.c}
104 * // PX_LOG_CFG_LEVEL defined in Makefile?
105 * #ifdef PX_LOG_CFG_LEVEL
106 * #undef PX_LOG_CFG_LEVEL
107 * #endif
108 * // Set output level to DEBUG (ERROR, WARN, INFO and DEBUG messages)
109 * #define PX_LOG_CFG_LEVEL PX_LOG_LEVEL_DEBUG
110 * #include "px_log.h"
111 * PX_LOG_NAME("buggy_module");
112 * @endcode
113 *
114 * The #PX_LOG_CFG_LEVEL can easily be tested with the the
115 * #PX_LOG_LEVEL_IS_E(), #PX_LOG_LEVEL_IS_W(), #PX_LOG_LEVEL_IS_I(),
116 * #PX_LOG_LEVEL_IS_V() or #PX_LOG_LEVEL_IS_D() macro to conditionally add
117 * code, for example:
118 *
119 * @code{.c}
120 * void tx_data(void * data, size_t nr_of_bytes)
121 * {
122 * // PX_LOG=1 and PX_LOG_CFG_LEVEL includes VERBOSE messages?
123 * if(PX_LOG_LEVEL_IS_V())
124 * {
125 * // Report content of buffer
126 * PX_LOG_TRACE_HEXDUMP(data, nr_of_bytes);
127 * }
128 * // Rest of function...
129 * }
130 * @endcode
131 *
132 * @tip_s
133 * A naming convention is used to start a function, variable or macro name with
134 * an underscore ('_') to indicate that it is used internally by this C module
135 * and should not be used directly, for example _px_log_log_error() or
136 * _px_log_name[].
137 * @tip_e
138 *
139 * @{
140 */
141
142/* _____STANDARD INCLUDES____________________________________________________ */
143
144/* _____PROJECT INCLUDES_____________________________________________________ */
145#include "px_defs.h"
146#include "px_compiler.h"
147#include "px_pgm_P.h"
148
149// Define PX_LOG for the benefit of Doxygen references
150#ifdef __DOX__
151 /// Set flag to disable (PX_LOG=0) or enable (PX_LOG=1) log output.
152 #define PX_LOG 1
153#endif
154
155// PX_LOG symbol defined in Makefile?
156#if defined(PX_LOG)
157 // Yes. Include project specific configuration. See "px_log_cfg_template.h"
158 #include "px_log_cfg.h"
159#else
160 // No: Remove all log code.
161 #define PX_LOG 0
162 #define PX_LOG_CFG_LEVEL PX_LOG_LEVEL_NONE
163 #define PX_LOG_CFG_FILTER 0
164 #define PX_LOG_CFG_BUF_SIZE 64
165 #define PX_LOG_CFG_COLOR 0
166#endif
167
168// Check that all project specific options have been specified in "px_log_cfg.h"
169#if ( !defined(PX_LOG ) \
170 || !defined(PX_LOG_CFG_LEVEL ) \
171 || !defined(PX_LOG_CFG_FILTER ) \
172 || !defined(PX_LOG_CFG_COLOR ) \
173 || !defined(PX_LOG_CFG_BUF_SIZE) )
174#error "One or more options not defined in 'px_log_cfg.h'"
175#endif
176
177// Include log color definitions *AFTER* PX_LOG_CFG_COLOR has been defined
178#include "px_log_color.h"
179
180#ifdef __cplusplus
181extern "C" {
182#endif
183/* _____DEFINITIONS _________________________________________________________ */
184/// Log message level ordered in increasing verbosity
185typedef enum
186{
187 PX_LOG_LEVEL_NONE = 0, ///< No log output
188 PX_LOG_LEVEL_ERROR = 1, ///< Critical errors
189 PX_LOG_LEVEL_WARNING = 2, ///< Warnings
190 PX_LOG_LEVEL_INFO = 3, ///< Concise info messages to track the normal flow of events
191 PX_LOG_LEVEL_DEBUG = 4, ///< Extra info for debugging that's not required for normal use
192 PX_LOG_LEVEL_VERBOSE = 5, ///< Extra details for debugging which can flood normal output
194
195/* _____TYPE DEFINITIONS_____________________________________________________ */
196
197/* _____GLOBAL VARIABLES_____________________________________________________ */
198
199/* _____GLOBAL FUNCTION DECLARATIONS_________________________________________ */
200/**
201 * Run time log filter.
202 *
203 * A customised version of this function can be declared to filter log output
204 * based on the level and / or name. Define PX_LOG_CFG_FILTER=1 to enable.
205 *
206 * A weak version is declared in px_log.c that always returns `false` meaning
207 * that all log output is allowed (none is filtered).
208 *
209 * @param level Log level
210 * @param name Module / file name
211 *
212 * @retval true Log must be filtered
213 * @retval false Log must be outputted
214 */
215bool px_log_filter(px_log_level_t level, const char * name);
216
217/**
218 * Output error info: module name, line and variable argument user format string.
219 *
220 * The line is automatically appended with a new line character ('\\n'), except
221 * if the format string ends with a tab character ('\\t'). The tab character at
222 * the end of the string is discarded.
223 *
224 * @param name Module / file name
225 * @param line Line number
226 * @param format User format string
227 * @param ... Variable number of arguments
228 */
229void _px_log_log_error(const char * name,
230 uint16_t line,
231 const char * format, ...);
232
233/**
234 * Output warning info: module name, line and variable argument user format string.
235 *
236 * The line is automatically appended with a new line character ('\\n'), except
237 * if the format string ends with a tab character ('\\t'). The tab character at
238 * the end of the string is discarded.
239 *
240 * @param name Module / file name
241 * @param line Line number
242 * @param format User format string
243 * @param ... Variable number of arguments
244 */
245void _px_log_log_warning(const char * name,
246 uint16_t line,
247 const char * format, ...);
248
249/**
250 * Output info info: module name, line and variable argument user format string.
251 *
252 * The line is automatically appended with a new line character ('\\n'), except
253 * if the format string ends with a tab character ('\\t'). The tab character at
254 * the end of the string is discarded.
255 *
256 *
257 * @param name Module / file name
258 * @param line Line number
259 * @param format User format string
260 * @param ... Variable number of arguments
261 */
262void _px_log_log_info(const char * name,
263 uint16_t line,
264 const char * format, ...);
265
266/**
267 * Output debug info: module name, line and variable argument user format string.
268 *
269 * The line is automatically appended with a new line character ('\\n'), except
270 * if the format string ends with a tab character ('\\t'). The tab character at
271 * the end of the string is discarded.
272 *
273 *
274 * @param name Module / file name
275 * @param line Line number
276 * @param format User format string
277 * @param ... Variable number of arguments
278 */
279void _px_log_log_debug(const char * name,
280 uint16_t line,
281 const char * format, ...);
282
283/**
284 * Output verbose info: module name, line and variable argument user format string.
285 *
286 * The line is automatically appended with a new line character ('\\n'), except
287 * if the format string ends with a tab character ('\\t'). The tab character at
288 * the end of the string is discarded.
289 *
290 *
291 * @param name Module / file name
292 * @param line Line number
293 * @param format User format string
294 * @param ... Variable number of arguments
295 */
296void _px_log_log_verbose(const char * name,
297 uint16_t line,
298 const char * format, ...);
299
300/**
301 * Report that an assertion has failed and block indefinitely.
302 *
303 * @param name Module / file name
304 * @param line Line number
305 */
306void _px_log_assert(const char * name,
307 uint16_t line) PX_ATTR_NORETURN;
308
309/**
310 * Output a user format string.
311 *
312 * This function does not automatically append a new line character ('\\n') so
313 * that multiple strings can be sent on the same line.
314 *
315 * @param format User format string
316 * @param ... Variable number of arguments
317 */
318void _px_log_trace(const char * format, ...);
319
320/**
321 * Output a character.
322 *
323 * @param c Character to output
324 */
325void _px_log_trace_char(char c);
326
327/**
328 * Output the content of a buffer as an array of HEX values.
329 *
330 * @param data Pointer to buffer containing data to display
331 * @param nr_of_bytes Number of bytes in buffer to display
332 */
333void _px_log_trace_data(const void * data, size_t nr_of_bytes);
334
335/**
336 * Output the content of a buffer as a spaced table of HEX values and ASCII
337 * characters.
338 *
339 * @param data Pointer to buffer containing data to display
340 * @param nr_of_bytes Number of bytes in buffer to display
341 */
342void _px_log_trace_hexdump(const void * data, size_t nr_of_bytes);
343
344/* _____MACROS_______________________________________________________________ */
345// PX_LOG enabled?
346#if PX_LOG
347
348/// Macro to declare a log name string once for each file to reduce code size.
349#define PX_LOG_NAME(name) PX_ATTR_UNUSED static const char _px_log_name[] PX_ATTR_PGM = name;
350
351// Run time filter enabled?
352#if PX_LOG_CFG_FILTER
353 /// Error level enabled?
354 #define PX_LOG_LEVEL_IS_E() ((PX_LOG_CFG_LEVEL >= PX_LOG_LEVEL_ERROR) && !px_log_filter(PX_LOG_LEVEL_ERROR, _px_log_name))
355 /// Warning level enabled?
356 #define PX_LOG_LEVEL_IS_W() ((PX_LOG_CFG_LEVEL >= PX_LOG_LEVEL_WARNING) && !px_log_filter(PX_LOG_LEVEL_WARNING, _px_log_name))
357 /// Info level enabled?
358 #define PX_LOG_LEVEL_IS_I() ((PX_LOG_CFG_LEVEL >= PX_LOG_LEVEL_INFO) && !px_log_filter(PX_LOG_LEVEL_INFO, _px_log_name))
359 /// Debug level enabled?
360 #define PX_LOG_LEVEL_IS_D() ((PX_LOG_CFG_LEVEL >= PX_LOG_LEVEL_DEBUG) && !px_log_filter(PX_LOG_LEVEL_DEBUG, _px_log_name))
361 /// Verbose level enabled?
362 #define PX_LOG_LEVEL_IS_V() ((PX_LOG_CFG_LEVEL >= PX_LOG_LEVEL_VERBOSE) && !px_log_filter(PX_LOG_LEVEL_VERBOSE, _px_log_name))
363#else
364 /// Error level enabled?
365 #define PX_LOG_LEVEL_IS_E() (PX_LOG_CFG_LEVEL >= PX_LOG_LEVEL_ERROR)
366 /// Warning level enabled?
367 #define PX_LOG_LEVEL_IS_W() (PX_LOG_CFG_LEVEL >= PX_LOG_LEVEL_WARNING)
368 /// Info level enabled?
369 #define PX_LOG_LEVEL_IS_I() (PX_LOG_CFG_LEVEL >= PX_LOG_LEVEL_INFO)
370 /// Debug level enabled?
371 #define PX_LOG_LEVEL_IS_D() (PX_LOG_CFG_LEVEL >= PX_LOG_LEVEL_DEBUG)
372 /// Verbose level enabled?
373 #define PX_LOG_LEVEL_IS_V() (PX_LOG_CFG_LEVEL >= PX_LOG_LEVEL_VERBOSE)
374#endif
375
376/// Macro to display a formatted ERROR message
377#define PX_LOG_E(format, ...) \
378 do \
379 { \
380 if(PX_LOG_CFG_LEVEL >= PX_LOG_LEVEL_ERROR) \
381 { \
382 _px_log_log_error(_px_log_name, (uint16_t)__LINE__, PX_PGM_STR(format), ## __VA_ARGS__); \
383 } \
384 } \
385 while(0)
386
387/// Macro to display a formatted WARNING message
388#define PX_LOG_W(format, ...) \
389 do \
390 { \
391 if(PX_LOG_CFG_LEVEL >= PX_LOG_LEVEL_WARNING) \
392 { \
393 _px_log_log_warning(_px_log_name, (uint16_t)__LINE__, PX_PGM_STR(format), ## __VA_ARGS__); \
394 } \
395 } \
396 while(0)
397
398/// Macro to display a formatted INFO message
399#define PX_LOG_I(format, ...) \
400 do \
401 { \
402 if(PX_LOG_CFG_LEVEL >= PX_LOG_LEVEL_INFO) \
403 { \
404 _px_log_log_info(_px_log_name, (uint16_t)__LINE__, PX_PGM_STR(format), ## __VA_ARGS__); \
405 } \
406 } \
407 while(0)
408
409/// Macro to display a formatted DEBUG message
410#define PX_LOG_D(format, ...) \
411 do \
412 { \
413 if(PX_LOG_CFG_LEVEL >= PX_LOG_LEVEL_DEBUG) \
414 { \
415 _px_log_log_debug(_px_log_name, (uint16_t)__LINE__, PX_PGM_STR(format), ## __VA_ARGS__); \
416 } \
417 } \
418 while(0)
419
420/// Macro to display a formatted VERBOSE message
421#define PX_LOG_V(format, ...) \
422 do \
423 { \
424 if(PX_LOG_CFG_LEVEL >= PX_LOG_LEVEL_VERBOSE) \
425 { \
426 _px_log_log_verbose(_px_log_name, (uint16_t)__LINE__, PX_PGM_STR(format), ## __VA_ARGS__); \
427 } \
428 } \
429 while(0)
430
431/**
432 * Macro that will test an expression, and block indefinitely if false.
433 *
434 * This macro will perform the test and if false, will output the filename and
435 * line number. The macro will then block indefinitely.
436 *
437 * @param[in] expression Expression that evaluates to a boolean value
438 * (true or false)
439 */
440#define PX_LOG_ASSERT(expression) \
441 do \
442 { \
443 if(!(expression)) \
444 { \
445 _px_log_assert(_px_log_name, (uint16_t)__LINE__); \
446 } \
447 } while(0)
448
449/**
450 * Macro to output a user format string if #PX_LOG=1
451 *
452 * This macro does not append a new line character ('\\n') so that multiple
453 * strings can be sent on the same line.
454 *
455 * @param[in] format Format string following by a variable list of arguments.
456 *
457 */
458#define PX_LOG_TRACE(format, ...) _px_log_trace(PX_PGM_STR(format), ## __VA_ARGS__)
459
460/**
461 * Macro to output a char if #PX_LOG=1
462 *
463 * @param c Character to output
464 */
465#define PX_LOG_TRACE_CHAR(c) _px_log_trace_char(c)
466
467/**
468 * Macro to output the content of a buffer if #PX_LOG=1
469 *
470 * The data is displayed as an array of HEX values.
471 *
472 * @param data Pointer to buffer containing data to display
473 * @param nr_of_bytes Size of buffer (in bytes)
474 *
475 */
476#define PX_LOG_TRACE_DATA(data, nr_of_bytes) _px_log_trace_data(data, nr_of_bytes)
477
478/**
479 * Macro to output the content of a buffer if #PX_LOG=1
480 *
481 * The data is displayed as a spaced table of HEX values and ASCII characters.
482 *
483 * @param data Pointer to buffer containing data to display
484 * @param nr_of_bytes Size of buffer (in bytes)
485 *
486 */
487#define PX_LOG_TRACE_HEXDUMP(data, nr_of_bytes) _px_log_trace_hexdump(data, nr_of_bytes)
488
489#else
490 // PX_LOG = 0; Remove log code
491 #define PX_LOG_NAME(name)
492 #define PX_LOG_LEVEL_IS_E() 0
493 #define PX_LOG_LEVEL_IS_W() 0
494 #define PX_LOG_LEVEL_IS_I() 0
495 #define PX_LOG_LEVEL_IS_D() 0
496 #define PX_LOG_LEVEL_IS_V() 0
497 #define PX_LOG_E(format, ...) ((void)0)
498 #define PX_LOG_W(format, ...) ((void)0)
499 #define PX_LOG_I(format, ...) ((void)0)
500 #define PX_LOG_D(format, ...) ((void)0)
501 #define PX_LOG_V(format, ...) ((void)0)
502 #define PX_LOG_ASSERT(expression) ((void)0)
503 #define PX_LOG_TRACE(format, ...) ((void)0)
504 #define PX_LOG_TRACE_CHAR(c) ((void)0)
505 #define PX_LOG_TRACE_DATA(data, nr_of_bytes) ((void)0)
506 #define PX_LOG_TRACE_HEXDUMP(data, nr_of_bytes) ((void)0)
507#endif
508
509#ifdef __cplusplus
510}
511#endif
512
513/// @}
514#endif
void _px_log_log_info(const char *name, uint16_t line, const char *format,...)
Output info info: module name, line and variable argument user format string.
Definition: px_log.c:310
void _px_log_assert(const char *name, uint16_t line) PX_ATTR_NORETURN
Report that an assertion has failed and block indefinitely.
Definition: px_log.c:388
void _px_log_trace(const char *format,...)
Output a user format string.
Definition: px_log.c:402
void _px_log_log_warning(const char *name, uint16_t line, const char *format,...)
Output warning info: module name, line and variable argument user format string.
Definition: px_log.c:285
bool px_log_filter(px_log_level_t level, const char *name)
Run time log filter.
Definition: px_log.c:253
void _px_log_log_verbose(const char *name, uint16_t line, const char *format,...)
Output verbose info: module name, line and variable argument user format string.
Definition: px_log.c:362
void _px_log_trace_hexdump(const void *data, size_t nr_of_bytes)
Output the content of a buffer as a spaced table of HEX values and ASCII characters.
Definition: px_log.c:433
px_log_level_t
Log message level ordered in increasing verbosity.
Definition: px_log.h:186
void _px_log_log_error(const char *name, uint16_t line, const char *format,...)
Output error info: module name, line and variable argument user format string.
Definition: px_log.c:259
void _px_log_trace_char(char c)
Output a character.
Definition: px_log.c:416
void _px_log_log_debug(const char *name, uint16_t line, const char *format,...)
Output debug info: module name, line and variable argument user format string.
Definition: px_log.c:336
void _px_log_trace_data(const void *data, size_t nr_of_bytes)
Output the content of a buffer as an array of HEX values.
Definition: px_log.c:421
@ PX_LOG_LEVEL_ERROR
Critical errors.
Definition: px_log.h:188
@ PX_LOG_LEVEL_WARNING
Warnings.
Definition: px_log.h:189
@ PX_LOG_LEVEL_VERBOSE
Extra details for debugging which can flood normal output.
Definition: px_log.h:192
@ PX_LOG_LEVEL_DEBUG
Extra info for debugging that's not required for normal use.
Definition: px_log.h:191
@ PX_LOG_LEVEL_NONE
No log output.
Definition: px_log.h:187