Logger library enables you to use unified interface to send out or receive data using one function with different parameters. You leave buffer overflows to this library as it handles it all.

Logger library howto guide.

Below is a simple program that outlines the usage of the logger library, The whole function was head-written so there might be some errors, but it is more for a live representation of usage than anything else. If someone would write a nice example program feel free to link it here.

simple usage of logger library

#include "mbed.h"
#include "logger.h"
#include "errno.h"

Ticker printout;
/**
 * \def STASH_BUFFER_LEN
 * size of stash buffer that can be used to store logged data
 */
#define STASH_BUFFER_LEN 70000
/// stash_buffer size
static char stash_buffer[STASH_BUFFER_LEN];

/**
 * Log_pop_periodic is periodically printing the messages until the buffer is empty. 
 * Once the buffer is empty it detaches and waits for another command.
*/
void log_pop_periodic(void)
{
    if( log_pop(L_BTSERIAL,stash_buffer,STASH_BUFFER_LEN) == 1 )
    {
        printout.detach();
    }
}

static int i=0;
static char read_buffer[20];
/**
 * read data from BT serial
*/
void read_from_BT()
{

    if (BTSerial.readable()) {
        read_buffer[i++] = BTSerial.getc();
        // if we read the desired character
        if (read_buffer[i-1] == 'p')
        {
            // start the printout process which will log_pop logged data
            printout.attach(&log_pop_periodic,0.5);
        }
    }    
}

int main()
{
    log_init(L_SERIAL);
    log_init(L_BTSERIAL);
    BTSerial.attach(&read_from_BT);

    // while loop to fill in loads of stinky data
    while (1) {
            // read something, then stash it
            log_stash(L_INFO,print_buffer,strlen(print_buffer),stash_buffer,STASH_BUFFER_LEN);
    }
}

logger.cpp

Committer:
Letme
Date:
2014-12-31
Revision:
5:f232b826e1f2
Parent:
4:9360fdf3a818

File content as of revision 5:f232b826e1f2:

#include "mbed.h"
#include "logger.h"
#include "errno.h"

/**
 * @defgroup logger_lib Logger library
 * @{
 * @author Crt Lukancic Mori (crt@tech-review.net or crt@the-mori.com)
 * @short Logging library provides more standard re-routing of output.
 * @details While data logger needs an input to define where it output should go, we
 * could also override the output using a global variable, which would be read
 * before the entry into plc switch to override the local output request. Function
 * needs outside buffer definition on which it can stash messages and perform
 * a string buffer. This are then passed into stash and pop functions when
 * such logging is assummed. 
 *
 */ 

Serial logSerial(PA_2, PA_3);
Serial BTSerial(PB_6, PA_10);
char endline[]="\n";

/**
 * Log_init initializes place where messages will be storred
 * @param[in] plc Place id to initialize
 *
 * @retval 1 when succcess
 * @retval -ERR linux errno.h error message
 */
int32_t log_init(uint8_t plc) {
    switch(plc) {
        case L_SERIAL:
            /// initialize baudrate
            logSerial.baud(115700);
            logSerial.printf("Serial port initialized\r\n");
            break;
        case L_FILE:
            break;
        case L_LED:
            // find out what we want here -morse code would be fun ;)
            break;
        case L_BTSERIAL:
            logSerial.printf("BlueTooth initializing\r\n");
            BTSerial.baud(9600);
            logSerial.printf("OK\r\n");
            logSerial.printf("Serial port initialized\r\n");
            break;
        default:
            return -EINVAL;
    }

    return 1;
}

/**
 * Log_msg determines where to save message.
 * @param[in] plc Place id, where to store message(check logger.h for more infos)
 * @param[in] lvl Debug level (ERROR,WARNING,DEBUG)
 * @param[in] msg pointer to message
 * @param[in] length length of message
 *
 * @retval 1 when succcess
 * @retval -ERR linux errno error message
 */
int32_t log_msg(uint8_t plc, uint8_t lvl, char *msg, uint32_t length) {
    if((msg == NULL) || (length == 0))
    {
        return -EINVAL;    
    }
    
    char send_message[length+5]; // add as much as you need to get all chars in (dont forget the \n on end)

    switch(lvl) {
        case L_CRIT_ERROR:
            snprintf(send_message,length+7,"CE: %s %s",msg,endline);
            break;
        case L_ERROR:
            snprintf(send_message,length+6,"E: %s %s",msg,endline);
            break;
        case L_WARNING:
            snprintf(send_message,length+6,"W: %s %s",msg,endline);
            break;
        case L_DEBUG:
            snprintf(send_message,length+6,"D: %s %s",msg,endline);
            break;
        case L_INFO:
            snprintf(send_message,length+3,"%s %s",msg,endline);
            break;
        default:
            return -EINVAL;
    }

    switch(plc) {
        case L_SERIAL:
            if(logSerial.writeable()) {
                logSerial.printf(send_message);
            } else {
                return -EBUSY;
            }
            break;
        case L_FILE:
            break;
        case L_LED:
            // find out what we want here -morse code would be fun ;)
            break;
        case L_BTSERIAL:
            if(BTSerial.writeable()) {
                BTSerial.printf(send_message);
            } else {
                return -EBUSY;
            }
            break;
        default:
            return -EINVAL;

    }

    return 1;
}

/**
 * Log_stash is meant to stash logs until they are ready to be sent, using log_pop function
 * Remember that this function can return also buffer full as result, which means you have to keep
 * deciding what you want to do - it just stashes files, but it keeps them in in case of buffer overflow.
 * Stash buffer is defined outside library and passed in as memoryspace.
 *
 * @param[in] lvl Debug level (ERROR,WARNING,DEBUG)
 * @param[in] msg pointer to message
 * @param[in] length length of message
 * @param[in] *stash_buffer Place where stashed messages were saved
 * @param[in] stash_buffer_len how many characters can be saved on stashed message buffer
 *
 * @retval 1 success
 * @retval -ERR linux errno error message - also includes buffer full!
 *
 */
int32_t log_stash(uint8_t lvl, char *msg, uint32_t length, char *stash_buffer,size_t stash_buffer_len) {
    if((msg == NULL) || (length == 0) || (stash_buffer == NULL) || (stash_buffer_len == 0))
    {
        return -EINVAL;    
    }
    
    char stash_buffer_tmp[length+8];
    
    // check if buffer is full and set starting point
    if((strlen(stash_buffer) > (stash_buffer_len-5)) || (stash_buffer_len < length)) {
        return -EFBIG;
    }

    // now fill it
    switch(lvl) {
        case L_CRIT_ERROR:
            snprintf(stash_buffer_tmp,length+7,"CE: %s %s",msg,endline);
            break;
        case L_ERROR:
            snprintf(stash_buffer_tmp,length+6,"E: %s %s",msg,endline);
            break;
        case L_WARNING:
            snprintf(stash_buffer_tmp,length+6,"W: %s %s",msg,endline);
            break;
        case L_DEBUG:
            snprintf(stash_buffer_tmp,length+6,"D: %s %s",msg,endline);
            break;
        case L_INFO:
            snprintf(stash_buffer_tmp,length+3,"%s %s",msg,endline);
            break;
        default:
            return -EINVAL;
    }
    strcat(stash_buffer,stash_buffer_tmp);
    return 1;
}

/**
 * Log_pop function sends everything log_stash stashed. Stash buffer is defined outside of function
 * and pointer to memory space is passed into it. Make sure you have a string buffer on
 * passed location, as there is still not enough checks against that
 *
 * @param[in] plc Place to where you pop stashed messages
 * @param[in] *stash_buffer Place where stashed messages were saved
 * @param[in] stash_buffer_len how many characters can be saved on stashed message buffer
 *
 * @retval 1 for success
 * @retval 2 for partial printout - did not send everything. You need to recall the function within timer so that you do not flood the serial port. So far it is only on BTSerial.
 * @retval -ERR errno.h error message
 *
 */
int32_t log_pop(uint8_t plc,char *stash_buffer,size_t stash_buffer_len) {
    if((stash_buffer == NULL) || (stash_buffer_len == 0))
    {
        return -EINVAL;    
    }
    
    char *tmp_needle;
    size_t tmp_len;
    
    switch(plc) {
        case L_SERIAL:
            if(logSerial.writeable()) {
                logSerial.printf("%s",stash_buffer);
                
                //clear stash buffer
                int i;
                for(i=0;i<stash_buffer_len;++i) {
                    stash_buffer[i]=0;    
                }
            } else {
                return -EBUSY;
            }
            break;
        case L_FILE:
            break;
        case L_LED:
            // find out what we want here -morse code would be fun ;)
            break;
        case L_BTSERIAL:
            if(BTSerial.writeable()) {
                // big chunk of text is not OK - add some delay between it
                tmp_needle=strstr(stash_buffer,endline);
                if(tmp_needle != NULL)
                {
                    // we have found a end line - now print out up to this end line
                    tmp_len = (tmp_needle+strlen(endline))-stash_buffer;
                    // we pray for complete printf definition
                    BTSerial.printf("%.*s", tmp_len,stash_buffer);
                    // move whole array to remove out the line needle is increased before tmp_len to include the endline string
                    memmove(stash_buffer,tmp_needle+strlen(endline),stash_buffer_len-tmp_len);
                    return 2;
                }
            } else {
                return -EBUSY;
            }
            break;
        default:
            return -EINVAL;

    }
    
    return 1;
}
/**
 * @}
 */