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.c
1/* =============================================================================
2 ____ ___ ____ ___ _ _ ___ __ __ ___ __ __ TM
3 | _ \ |_ _| / ___| / _ \ | \ | | / _ \ | \/ | |_ _| \ \/ /
4 | |_) | | | | | | | | | | \| | | | | | | |\/| | | | \ /
5 | __/ | | | |___ | |_| | | |\ | | |_| | | | | | | | / \
6 |_| |___| \____| \___/ |_| \_| \___/ |_| |_| |___| /_/\_\
7
8 Copyright (c) 2006 Pieter Conradie <https://piconomix.com>
9
10 License: MIT
11 https://github.com/piconomix/px-fwlib/blob/master/LICENSE.md
12
13 Title: px_log.h : Debug logging module
14 Author(s): Pieter Conradie
15 Creation Date: 2007-03-31
16
17============================================================================= */
18
19/* _____STANDARD INCLUDES____________________________________________________ */
20#include <stdio.h>
21#include <string.h>
22#include <stdarg.h>
23
24/* _____PROJECT INCLUDES_____________________________________________________ */
25#include "px_log.h"
26
27// Only compile functions if PX_LOG = 1
28#if PX_LOG
29
30/* _____LOCAL DEFINITIONS____________________________________________________ */
31/// Number of bytes per row for hex dump
32#define PX_LOG_CFG_TRACE_DATA_BYTES_PER_ROW 16
33
34/* _____MACROS_______________________________________________________________ */
35
36/* _____GLOBAL VARIABLES_____________________________________________________ */
37
38/* _____LOCAL VARIABLES______________________________________________________ */
39/// Allocate internal buffer for log output
40static char px_log_buf[PX_LOG_CFG_BUF_SIZE];
41
42/* _____LOCAL FUNCTION DECLARATIONS__________________________________________ */
43
44/* _____LOCAL FUNCTIONS______________________________________________________ */
45static void inline px_log_putchar(char data)
46{
47#ifdef PX_LOG_CFG_PUTCHAR
48 // Output character using configured function
49 PX_LOG_CFG_PUTCHAR(data);
50#else
51 // Output character to stdout
52 putchar(data);
53#endif
54}
55
56static void px_log_print_str(const char * data)
57{
58 while(*data != '\0')
59 {
60 px_log_putchar(*data++);
61 }
62}
63
64static void inline px_log_print_hex04(uint8_t data)
65{
66 if(data < 10)
67 {
68 data += (uint8_t)'0';
69 }
70 else
71 {
72 data += (uint8_t)'A' - 10;
73 }
74 px_log_putchar((char)data);
75}
76
77static void inline px_log_print_hex08(uint8_t data)
78{
79 px_log_print_hex04(PX_U8_HI4(data));
80 px_log_print_hex04(PX_U8_LO4(data));
81}
82
83#ifdef PX_COMPILER_GCC_AVR
84static void px_log_print_str_P(const char * data)
85{
86 char c;
87
88 while(true)
89 {
90 c = px_pgm_rd_char(data++);
91 if(c == '\0')
92 {
93 return;
94 }
95 px_log_putchar(c);
96 }
97}
98
99static void px_log_printf_vargs_P(const char * format, va_list args)
100{
101 size_t len;
102
103 // Populate buffer with log string
104 vsnprintf_P(px_log_buf, PX_LOG_CFG_BUF_SIZE, format, args);
105 // Append terminating zero in case of buffer overrun
106 px_log_buf[PX_LOG_CFG_BUF_SIZE - 1] = '\0';
107 // Remove tab character ('\t') at the end of user formatted string
108 len = strlen(px_log_buf);
109 if((len != 0) && (px_log_buf[len - 1] == '\t'))
110 {
111 px_log_buf[len - 1] = '\0';
112 }
113 // Output user formatted string
114 px_log_print_str(px_log_buf);
115}
116
117static void px_log_printf_P(const char * format, ...)
118{
119 va_list args;
120
121 va_start(args, format);
122 px_log_printf_vargs_P(format, args);
123 va_end(args);
124}
125
126#else
127
128static void px_log_printf_vargs(const char * format, va_list args)
129{
130 size_t len;
131
132 // Populate buffer with log string
133 vsnprintf(px_log_buf, PX_LOG_CFG_BUF_SIZE, format, args);
134 // Append terminating zero in case of buffer overrun
135 px_log_buf[PX_LOG_CFG_BUF_SIZE - 1] = '\0';
136 // Remove tab character ('\t') at the end of user formatted string
137 len = strlen(px_log_buf);
138 if((len != 0) && (px_log_buf[len - 1] == '\t'))
139 {
140 px_log_buf[len - 1] = '\0';
141 }
142 // Output user formatted string
143 px_log_print_str(px_log_buf);
144}
145
146static void px_log_printf(const char * format, ...)
147{
148 va_list args;
149
150 va_start(args, format);
151 px_log_printf_vargs(format, args);
152 va_end(args);
153}
154#endif
155
156static void px_log_report_log_prefix(px_log_level_t level,
157 const char * name,
158 uint16_t line)
159{
160 switch(level)
161 {
163#if PX_LOG_CFG_COLOR
164 px_log_print_str(PX_LOG_FG_RED "E");
165#else
166 px_log_putchar('E');
167#endif
168 break;
169
171#if PX_LOG_CFG_COLOR
172 px_log_print_str(PX_LOG_FG_YELLOW "W");
173#else
174 px_log_putchar('W');
175#endif
176 break;
177
178 case PX_LOG_LEVEL_INFO:
179#if PX_LOG_CFG_COLOR
180 px_log_print_str(PX_LOG_FG_GREEN "I");
181#else
182 px_log_putchar('I');
183#endif
184 break;
185
187#if PX_LOG_CFG_COLOR
188 px_log_print_str(PX_LOG_FG_BLUE "D");
189#else
190 px_log_putchar('D');
191#endif
192 break;
193
195#if PX_LOG_CFG_COLOR
196 px_log_print_str(PX_LOG_FG_CYAN "V");
197#else
198 px_log_putchar('V');
199#endif
200 break;
201
202 default:
203 px_log_putchar('?');
204 break;
205 }
206 px_log_putchar(' ');
207
208 // Timestamp function provided in 'px_log_cfg.h'?
209#ifdef PX_LOG_CFG_TIMESTAMP
210 // Get user supplied timestamp string
211 PX_LOG_CFG_TIMESTAMP(px_log_buf);
212 // Append terminating zero in case of buffer overrun
213 px_log_buf[PX_LOG_CFG_BUF_SIZE - 1] = '\0';
214 // Output timestamp
215 px_log_print_str(px_log_buf);
216 px_log_putchar(' ');
217#endif
218
219#if PX_LOG_CFG_COLOR
220 // Send VT100 sequence to reset all attributes
221 px_log_print_str(PX_LOG_CR);
222#endif
223
224 // Output file and line
225#ifdef PX_COMPILER_GCC_AVR
226 px_log_print_str_P(name);
227 px_log_printf_P(PX_PGM_STR(" %04u : "), line);
228#else
229 px_log_printf("%s %04u : ", name, line);
230#endif
231}
232
233static void px_log_terminate(const char * format)
234{
235#ifdef PX_COMPILER_GCC_AVR
236 size_t len = strlen_P(format);
237 if((len == 0) || px_pgm_rd_char(format + len - 1) != '\t')
238 {
239 // Append end-of-line
240 px_log_putchar('\n');
241 }
242#else
243 size_t len = strlen(format);
244 if((len == 0) || format[len - 1] != '\t')
245 {
246 // Append end-of-line
247 px_log_putchar('\n');
248 }
249#endif
250}
251
252/* _____GLOBAL FUNCTIONS_____________________________________________________ */
253PX_ATTR_WEAK bool px_log_filter(px_log_level_t level, const char * name)
254{
255 // Allow all log output
256 return false;
257}
258
259void _px_log_log_error(const char * name, uint16_t line, const char * format, ...)
260{
261 va_list args;
262
263#if PX_LOG_CFG_FILTER
264 // Must log be filtered?
266 {
267 // Yes
268 return;
269 }
270#endif
271 // Output log prefix (level, timestamp, name and line)
272 px_log_report_log_prefix(PX_LOG_LEVEL_ERROR, name, line);
273 // Output user formatted string
274 va_start(args, format);
275#ifdef PX_COMPILER_GCC_AVR
276 px_log_printf_vargs_P(format, args);
277#else
278 px_log_printf_vargs(format, args);
279#endif
280 va_end(args);
281 // Append End Of Line ('\n') if format string does not end with a TAB character ('\t')
282 px_log_terminate(format);
283}
284
285void _px_log_log_warning(const char * name, uint16_t line, const char * format, ...)
286{
287 va_list args;
288#if PX_LOG_CFG_FILTER
289 // Must log be filtered?
291 {
292 // Yes
293 return;
294 }
295#endif
296 // Output log prefix (level, timestamp, name and line)
297 px_log_report_log_prefix(PX_LOG_LEVEL_WARNING, name, line);
298 // Output user formatted string
299 va_start(args, format);
300#ifdef PX_COMPILER_GCC_AVR
301 px_log_printf_vargs_P(format, args);
302#else
303 px_log_printf_vargs(format, args);
304#endif
305 va_end(args);
306 // Append End Of Line ('\n') if format string does not end with a TAB character ('\t')
307 px_log_terminate(format);
308}
309
310void _px_log_log_info(const char * name, uint16_t line, const char * format, ...)
311{
312 va_list args;
313
314#if PX_LOG_CFG_FILTER
315 // Must log be filtered?
316 if(px_log_filter(PX_LOG_LEVEL_INFO, name))
317 {
318 // Yes
319 return;
320 }
321#endif
322 // Output log prefix (level, timestamp, name and line)
323 px_log_report_log_prefix(PX_LOG_LEVEL_INFO, name, line);
324 // Output user formatted string
325 va_start(args, format);
326#ifdef PX_COMPILER_GCC_AVR
327 px_log_printf_vargs_P(format, args);
328#else
329 px_log_printf_vargs(format, args);
330#endif
331 va_end(args);
332 // Append End Of Line ('\n') if format string does not end with a TAB character ('\t')
333 px_log_terminate(format);
334}
335
336void _px_log_log_debug(const char * name, uint16_t line, const char * format, ...)
337{
338 va_list args;
339
340#if PX_LOG_CFG_FILTER
341 // Must log be filtered?
343 {
344 // Yes
345 return;
346 }
347#endif
348 // Output log prefix (level, timestamp, name and line)
349 px_log_report_log_prefix(PX_LOG_LEVEL_DEBUG, name, line);
350 // Output user formatted string
351 va_start(args, format);
352#ifdef PX_COMPILER_GCC_AVR
353 px_log_printf_vargs_P(format, args);
354#else
355 px_log_printf_vargs(format, args);
356#endif
357 va_end(args);
358 // Append End Of Line ('\n') if format string does not end with a TAB character ('\t')
359 px_log_terminate(format);
360}
361
362void _px_log_log_verbose(const char * name, uint16_t line, const char * format, ...)
363{
364 va_list args;
365
366#if PX_LOG_CFG_FILTER
367 // Must log be filtered?
369 {
370 // Yes
371 return;
372 }
373#endif
374 // Output log prefix (level, timestamp, name and line)
375 px_log_report_log_prefix(PX_LOG_LEVEL_VERBOSE, name, line);
376 // Output user formatted string
377 va_start(args, format);
378#ifdef PX_COMPILER_GCC_AVR
379 px_log_printf_vargs_P(format, args);
380#else
381 px_log_printf_vargs(format, args);
382#endif
383 va_end(args);
384 // Append End Of Line ('\n') if format string does not end with a TAB character ('\t')
385 px_log_terminate(format);
386}
387
388void _px_log_assert(const char * name,
389 uint16_t line)
390{
391 // Output log prefix (level, timestamp, name and line)
392 px_log_report_log_prefix(PX_LOG_LEVEL_ERROR, name, line);
393#ifdef PX_COMPILER_GCC_AVR
394 px_log_printf_P(PX_PGM_STR("ASSERT"));
395#else
396 px_log_printf("ASSERT");
397#endif
398 // Block forever
399 while(true) {;}
400}
401
402void _px_log_trace(const char * format, ...)
403{
404 va_list args;
405
406 // Output user formatted string
407 va_start(args, format);
408#ifdef PX_COMPILER_GCC_AVR
409 px_log_printf_vargs_P(format, args);
410#else
411 px_log_printf_vargs(format, args);
412#endif
413 va_end(args);
414}
415
417{
418 px_log_putchar(c);
419}
420
421void _px_log_trace_data(const void * data, size_t nr_of_bytes)
422{
423 size_t i;
424 const uint8_t * data_u8 = (const uint8_t *)data;
425
426 for(i = 0; i < nr_of_bytes; i++)
427 {
428 px_log_print_hex08(*data_u8++);
429 px_log_putchar(' ');
430 }
431}
432
433void _px_log_trace_hexdump(const void * data, size_t nr_of_bytes)
434{
435 size_t i, j;
436 const uint8_t * row_data;
437
438 // Split data up into rows
439 for(i = 0; i < nr_of_bytes; i+= PX_LOG_CFG_TRACE_DATA_BYTES_PER_ROW)
440 {
441 // Insert extra empty row?
442 if( (i != 0) && ((i % (PX_LOG_CFG_TRACE_DATA_BYTES_PER_ROW * 4)) == 0) )
443 {
444 // Yes
445 px_log_putchar('\n');
446 }
447 // Select row data
448 row_data = &((const uint8_t *)data)[i];
449 // Display Hexidecimal data
450 for(j = 0; j < PX_LOG_CFG_TRACE_DATA_BYTES_PER_ROW; j++)
451 {
452 // Insert extra space?
453 if((j != 0) && ((j % 4) == 0))
454 {
455 // Yes
456 px_log_putchar(' ');
457 }
458 // End of data?
459 if((i + j) < nr_of_bytes)
460 {
461 // No
462 px_log_print_hex08(row_data[j]);
463 px_log_putchar(' ');
464 }
465 else
466 {
467 // No more data
468#ifdef PX_COMPILER_GCC_AVR
469 px_log_print_str_P(PX_PGM_STR(" "));
470#else
471 px_log_print_str(" ");
472#endif
473 }
474 }
475 // Display ASCII data
476 for(j = 0; j < PX_LOG_CFG_TRACE_DATA_BYTES_PER_ROW; j++)
477 {
478 // End of data?
479 if((i + j) < nr_of_bytes)
480 {
481 // No. Displayable?
482 if( (row_data[j] >= 32) && (row_data[j] <= 127) )
483 {
484 // Yes
485 px_log_putchar(row_data[j]);
486 }
487 else
488 {
489 // No
490 px_log_putchar('.');
491 }
492 }
493 else
494 {
495 // No more data
496 px_log_putchar(' ');
497 }
498 }
499 px_log_putchar('\n');
500 }
501}
502
503#endif // #if PX_LOG
#define PX_U8_LO4(data)
Extract the low 4 bits of a 8-bit value.
Definition: px_defs.h:222
#define PX_U8_HI4(data)
Extract the high 4 bits of a 8-bit value.
Definition: px_defs.h:219
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)
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
#define PX_LOG_CFG_BUF_SIZE
Debug output string buffer size.
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
PX_ATTR_WEAK 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