A traditional embedded systems trick is to log messages to a circular buffer in core. This has the following benefits:
Used to define buffer variables, it is similar to ‘FILE*’ type in ‘stdio.h’. To create an instance use ‘L_buffer_create’.
These are used to create or delete a buffer which can contain size characters.
L_BUFFER *lbuffer; lbuffer = L_buffer_create(32*1024); /* create a 32K buffer */ ...; L_buffer_delete(lbuffer); /* and delete it after use */
A buffer created by ‘L_buffer_create’ is set up so that the new messages will overwrite the older messages in the buffer. If you wish to disable this overwriting, e.g. to keep the first 32K bytes of your system startup messages you should use ‘L_buffer_wraparound’. For example:
L_BUFFER *lb = L_buffer_create(32*1024); L_buffer_wraparound(lb, 0); /* disable wraparound */
These are the routines which do that actual printing to the buffer.
L_buffer_printf(lbuffer, "U: user input %c\n", c); L_buffer_puts(lbuffer, "warning: its too hot"); L_buffer_putchar(lbuffer, '*');Note: a null pointer passed to the ‘L_buffer_puts’ function prints as ‘(null)’. 1
Clear the log, i.e. remove all messages and start again.
Dump the contents of the log *b to the file descriptor *fp. Typically *fp would be ‘stderr’.
Note that this does not change the contents of the buffer. This is important since we may have a hardware or software problem part of the way through the dump operation and you don't want to loose anything.
To reset the buffer after a successful dump use ‘L_buffer_clear’.
The output of ‘L_buffer_dump’ consists of a starting message followed by the contents of the log. If a character in the log is not printable we print it out in hex on a line by itself.
* L_buffer_dump = log message and another * non-printable character 0x1 more log messages * end of dump
You also need to be able to integrate these functions into your design. See ‘examples/ott.c’ for a complicated example. Here we will provide a simplified version which implements a new logging macro called ‘LFAST’ which does a ‘printf’ to the ‘log_buffer’. If you want to have all messages going to a ‘L_BUFFER’ then you can redefine ‘L_DEFAULT_HANDLER’.
/* project.h - the project wide include file */ #include <nana.h> #include <L_buffer.h> /* LFAST(char *, ...) - log a message to the log_buffer */ /* ##f translates as the rest of the arguments to LFAST */ #define LFAST(f...) LHP(L_buffer_printf,log_buffer,##f) extern L_BUFFER *log_buffer; /* the log buffer */
The main program merely creates the log_buffer and eventually calls ‘L_buffer_dump’ to print out the buffer when the system dies.
/* main.c - initialise the system and start things */ #include <project.h> L_BUFFER *log_buffer; main() { log_buffer = L_buffer_create(16000); if(log_buffer == NULL) { /* not enough store */ ... } LFAST("system starting at %f\n", now()); ...; } void fatal_error() { /* called on fatal errors */ FILE *f = fopen("project.errors","w"); L_buffer_dump(b, stderr); /* print log to stderr */ L_buffer_dump(b, f); /* print log to file */ }