diff --git a/lib_logging/.cproject b/lib_logging/.cproject index ccd82c8..cdd6361 100644 --- a/lib_logging/.cproject +++ b/lib_logging/.cproject @@ -48,6 +48,7 @@ + @@ -309,12 +386,167 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -469,6 +701,160 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib_logging/.project b/lib_logging/.project index 406b939..905e77d 100644 --- a/lib_logging/.project +++ b/lib_logging/.project @@ -1,10 +1,15 @@ - lib_logging + lib_logging + + com.xmos.cdt.core.LegacyProjectCheckerBuilder + + + com.xmos.cdt.core.BuildMarkersBuilder diff --git a/lib_logging/api/debug_print.h b/lib_logging/api/debug_print.h index 56aee4b..5657b9d 100644 --- a/lib_logging/api/debug_print.h +++ b/lib_logging/api/debug_print.h @@ -73,7 +73,10 @@ enabled/disabled per debug unit. #if defined(__cplusplus) extern "C" { #endif -void debug_printf(char fmt[], ...); +#include +size_t debug_snprintf(char *str, size_t size, const char *fmt, ...); +size_t debug_sprintf(char *str, const char *fmt, ...); +void debug_printf(const char fmt[], ...); #if defined(__cplusplus) } #endif diff --git a/lib_logging/src/debug_printf.c b/lib_logging/src/debug_printf.c index 8a84c75..fa34fff 100644 --- a/lib_logging/src/debug_printf.c +++ b/lib_logging/src/debug_printf.c @@ -1,140 +1,480 @@ -// Copyright (c) 2014-2016, XMOS Ltd, All rights reserved +// Copyright (c) 2014-2019, XMOS Ltd, All rights reserved + +/*---------------------------------------------------*/ +/* Modified from : */ +/* Public Domain version of printf */ +/* Rud Merriam, Compsult, Inc. Houston, Tx. */ +/* For Embedded Systems Programming, 1991 */ +/* */ +/*---------------------------------------------------*/ + #include -#include #include #include #include -#include #include +#include #include #undef debug_printf -static void reverse_array(char buf[], unsigned size) +#define LONG64 (LONG_MAX == 9223372036854775807L) +#define POINTER64 (INTPTR_MAX == 9223372036854775807L) + +typedef struct { + size_t size; + size_t pos; + char *str; + int writeout; + int32_t len; + int32_t num1; + int32_t num2; + int32_t do_padding; + int32_t left_flag; + int32_t unsigned_flag; + char pad_character; +} params_t; + +void outbyte(char b, params_t *par) { - int begin = 0; - int end = size - 1; - int tmp; - for (;begin < end; begin++,end--) { - tmp = buf[begin]; - buf[begin] = buf[end]; - buf[end] = tmp; - } + if (par->pos < par->size) { + par->str[par->pos] = b; + } + par->pos++; + + if (par->writeout && par->pos >= par->size) { + _write(FD_STDOUT, par->str, par->size); + par->pos = 0; + } } -static int itoa(unsigned n, char *buf, unsigned base, int fill) +/*---------------------------------------------------*/ +/* The purpose of this routine is to output data the */ +/* same as the standard printf function without the */ +/* overhead most run-time libraries involve. Usually */ +/* the printf brings in many kilobytes of code and */ +/* that is unacceptable in most embedded systems. */ +/*---------------------------------------------------*/ + + +/*---------------------------------------------------*/ +/* */ +/* This routine puts pad characters into the output */ +/* buffer. */ +/* */ +static void padding(const int32_t l_flag, params_t *par) { - static const char digits[] = "0123456789ABCDEF"; - unsigned i = 0; - - if (n == 0) - fill += 1; - - while (n > 0) { - unsigned next = n / base; - unsigned cur = n % base; - buf[i] = digits[cur]; - i += 1; - fill--; - n = next; - } - for (;fill > 0; fill--) { - buf[i] = '0'; - i++; - } - reverse_array(buf, i); - return i; + int32_t i; + + if ((par->do_padding != 0) && (l_flag != 0) && (par->len < par->num1)) { + i=(par->len); + for (; i<(par->num1); i++) { + outbyte(par->pad_character, par); + } + } } -#define MAX_INT_STRING_SIZE 10 +/*---------------------------------------------------*/ +/* */ +/* This routine moves a string to the output buffer */ +/* as directed by the padding and positioning flags. */ +/* */ +static void outs(const char *lp, params_t *par) +{ + /* pad on left if needed */ + if(lp != NULL) { + par->len = (int32_t) strlen(lp); + } + padding(!(par->left_flag), par); -#ifndef DEBUG_PRINTF_BUFSIZE -#define DEBUG_PRINTF_BUFSIZE 130 + /* Move string to the buffer */ + while (((*lp) != (char)0) && ((par->num2) != 0)) { + (par->num2)--; + outbyte(*lp, par); + lp += 1; + } + + padding(par->left_flag, par); +} + +/*---------------------------------------------------*/ +/* */ +/* This routine moves a number to the output buffer */ +/* as directed by the padding and positioning flags. */ +/* */ + +static void outnum(const int32_t n, const int32_t base, params_t *par) +{ + int32_t negative; + int32_t i; + char outbuf[32]; + const char digits[] = "0123456789ABCDEF"; + uint32_t num; + for(i = 0; i<32; i++) { + outbuf[i] = '0'; + } + + /* Check if number is negative */ + if ((par->unsigned_flag == 0) && (base == 10) && (n < 0L)) { + negative = 1; + num =(-(n)); + } + else{ + num = n; + negative = 0; + } + + /* Build number (backwards) in outbuf */ + i = 0; + do { + outbuf[i] = digits[(num % base)]; + i++; + num /= base; + } while (num > 0); + + if (negative != 0) { + outbuf[i] = '-'; + i++; + } + + outbuf[i] = '\0'; + i--; + + /* Move the converted number to the buffer and */ + /* add in the padding where needed. */ + par->len = (int32_t)strlen(outbuf); + padding(!(par->left_flag), par); + while (&outbuf[i] >= outbuf) { + outbyte(outbuf[i], par); + i--; + } + padding(par->left_flag, par); +} +/*---------------------------------------------------*/ +/* */ +/* This routine moves a 64-bit number to the output */ +/* buffer as directed by the padding and positioning */ +/* flags. */ +/* */ +#if LONG64 +static void outnum1(const int64_t n, const int32_t base, params_t *par) +{ + int32_t negative; + int32_t i; + char outbuf[64]; + const char digits[] = "0123456789ABCDEF"; + uint64_t num; + for(i = 0; i<64; i++) { + outbuf[i] = '0'; + } + + /* Check if number is negative */ + if ((par->unsigned_flag == 0) && (base == 10) && (n < 0L)) { + negative = 1; + num =(-(n)); + } + else{ + num = (n); + negative = 0; + } + + /* Build number (backwards) in outbuf */ + i = 0; + do { + outbuf[i] = digits[(num % base)]; + i++; + num /= base; + } while (num > 0); + + if (negative != 0) { + outbuf[i] = '-'; + i++; + } + + outbuf[i] = '\0'; + i--; + + /* Move the converted number to the buffer and */ + /* add in the padding where needed. */ + par->len = (int32_t)strlen(outbuf); + padding(!(par->left_flag), par); + while (&outbuf[i] >= outbuf) { + outbyte(outbuf[i], par); + i--; + } + padding(par->left_flag, par); +} #endif +/*---------------------------------------------------*/ +/* */ +/* This routine gets a number from the format */ +/* string. */ +/* */ +static int32_t getnum(char **linep) +{ + int32_t n; + int32_t ResultIsDigit = 0; + char *cptr; + n = 0; + cptr = *linep; + if(cptr != NULL){ + ResultIsDigit = isdigit(((int32_t)*cptr)); + } + while (ResultIsDigit != 0) { + if(cptr != NULL){ + n = ((n*10) + (((int32_t)*cptr) - (int32_t)'0')); + cptr += 1; + if(cptr != NULL){ + ResultIsDigit = isdigit(((int32_t)*cptr)); + } + } + ResultIsDigit = isdigit(((int32_t)*cptr)); + } + *linep = ((char *)(cptr)); + return(n); +} +/*---------------------------------------------------*/ +/* */ +/* This routine operates just like a printf/sprintf */ +/* routine. It outputs a set of data under the */ +/* control of a formatting string. Not all of the */ +/* standard C format control are supported. The ones */ +/* provided are primarily those needed for embedded */ +/* systems work. Primarily the floating point */ +/* routines are omitted. Other formats could be */ +/* added easily by following the examples shown for */ +/* the supported formats. */ +/* */ -void debug_printf(char * fmt, ...) +static size_t debug_vsnwprintf(char *str, size_t size, int writeout, const char *fmt, va_list ap) { - char * marker; - int intArg; - unsigned int uintArg; - char * strArg; - - char buf[DEBUG_PRINTF_BUFSIZE]; - char *end = &buf[DEBUG_PRINTF_BUFSIZE - 1 - MAX_INT_STRING_SIZE]; - - va_list args; - - va_start(args,fmt); - marker = fmt; - char *p = buf; - while (*fmt) { - if (p > end) { - // flush - _write(FD_STDOUT, buf, p - buf); - p = buf; - } - switch (*fmt) { - case '%': - fmt++; - if (*(fmt) == '-' || *(fmt) == '+' || *(fmt) == '#' || *(fmt) == ' ') { - // Ignore flags - fmt++; - } - while (*(fmt) && *(fmt) >= '0' && *(fmt) <= '9') { - // Ignore width - fmt++; - } - // Use 'tolower' to ensure both %x/%X do something sensible - switch (tolower(*(fmt))) { - case 'd': - intArg = va_arg(args, int); - if (intArg < 0) { - *p++ = '-'; - intArg = -intArg; + int32_t Check; +#if LONG64 + int32_t long_flag; +#endif + int32_t dot_flag; + + params_t par; + + char ch; + char *ctrl = (char *)fmt; + + par.size = size; + par.pos = 0; + par.str = str; + par.writeout = writeout; + + while ((ctrl != NULL) && (*ctrl != (char)0)) { + + /* move format string chars to buffer until a */ + /* format control is found. */ + if (*ctrl != '%') { + outbyte(*ctrl, &par); + ctrl += 1; + continue; } - p += itoa(intArg, p, 10, 0); - break; - case 'u': - uintArg = va_arg(args, int); - p += itoa(uintArg, p, 10, 0); - break; - case 'p': - case 'x': - uintArg = va_arg(args, int); - p += itoa(uintArg, p, 16, 0); - break; - case 'c': - intArg = va_arg(args, int); - *p++ = intArg; - break; - case 's': - strArg = va_arg(args, char *); - int len = strlen(strArg); - if (len > (end - buf)) { - // flush - _write(FD_STDOUT, buf, p - buf); - p = buf; + + /* initialize all the flags for this format. */ + dot_flag = 0; +#if LONG64 + long_flag = 0; +#endif + par.unsigned_flag = 0; + par.left_flag = 0; + par.do_padding = 0; + par.pad_character = ' '; + par.num2=32767; + par.num1=0; + par.len=0; + + try_next: + if(ctrl != NULL) { + ctrl += 1; } - if (len > (end - buf)) - len = end - buf; - memcpy(p, strArg, len); - p += len; - break; - default: + if(ctrl != NULL) { + ch = *ctrl; + } + else { + ch = *ctrl; + } + + if (isdigit((int32_t)ch) != 0) { + if (dot_flag != 0) { + par.num2 = getnum(&ctrl); + } + else { + if (ch == '0') { + par.pad_character = '0'; + } + if(ctrl != NULL) { + par.num1 = getnum(&ctrl); + } + par.do_padding = 1; + } + if(ctrl != NULL) { + ctrl -= 1; + } + goto try_next; + } + + switch (tolower((int32_t)ch)) { + case '%': + outbyte('%', &par); + Check = 1; + break; + + case '-': + par.left_flag = 1; + Check = 0; + break; + + case '.': + dot_flag = 1; + Check = 0; + break; + + case 'l': + #if LONG64 + long_flag = 1; + #endif + Check = 0; + break; + + case 'u': + par.unsigned_flag = 1; + /* fall through */ + case 'i': + case 'd': + #if LONG64 + if (long_flag != 0){ + outnum1((int64_t)va_arg(ap, int64_t), 10L, &par); + } + else { + outnum(va_arg(ap, int32_t), 10L, &par); + } + #else + outnum(va_arg(ap, int32_t), 10L, &par); + #endif + Check = 1; + break; + case 'p': + #if POINTER64 + par.unsigned_flag = 1; + outnum1((int64_t)va_arg(ap, int64_t), 16L, &par); + Check = 1; + break; + #endif + case 'X': + case 'x': + par.unsigned_flag = 1; + #if LONG64 + if (long_flag != 0) { + outnum1((int64_t)va_arg(ap, int64_t), 16L, &par); + } + else { + outnum((int32_t)va_arg(ap, int32_t), 16L, &par); + } + #else + outnum((int32_t)va_arg(ap, int32_t), 16L, &par); + #endif + Check = 1; + break; + + case 's': + outs(va_arg(ap, char *), &par); + Check = 1; + break; + + case 'c': + outbyte(va_arg(ap, int32_t), &par); + Check = 1; + break; + + case '\\': + switch (*ctrl) { + case 'a': + outbyte((char)0x07, &par); + break; + case 'h': + outbyte((char)0x08, &par); + break; + case 'r': + outbyte((char)0x0D, &par); + break; + case 'n': + outbyte((char)0x0D, &par); + outbyte((char)0x0A, &par); + break; + default: + outbyte(*ctrl, &par); + break; + } + ctrl += 1; + Check = 0; + break; + + default: + Check = 1; break; - } - break; + } + if(Check == 1) { + if(ctrl != NULL) { + ctrl += 1; + } + continue; + } + goto try_next; + } - default: - *p++ = *fmt; + if (par.pos < par.size) { + par.str[par.pos] = '\0'; } - fmt++; - } - _write(FD_STDOUT, buf, p - buf); - va_end(args); - return; + return par.pos; } +/*---------------------------------------------------*/ + +size_t debug_snprintf(char *str, size_t size, const char *fmt, ...) +{ + size_t len; + va_list ap; + + va_start(ap, fmt); + len = debug_vsnwprintf(str, size, 0, fmt, ap); + va_end(ap); + + return len; +} + +size_t debug_sprintf(char *str, const char *fmt, ...) +{ + size_t len; + va_list ap; + + va_start(ap, fmt); + len = debug_vsnwprintf(str, SIZE_MAX, 0, fmt, ap); + va_end(ap); + + return len; +} + +#ifndef DEBUG_PRINTF_BUFSIZE +#define DEBUG_PRINTF_BUFSIZE 130 +#endif + +void debug_printf(const char *fmt, ...) +{ + size_t len; + va_list ap; + char buf[DEBUG_PRINTF_BUFSIZE]; + + va_start(ap, fmt); + len = debug_vsnwprintf(buf, DEBUG_PRINTF_BUFSIZE, 1, fmt, ap); + va_end(ap); + + _write(FD_STDOUT, buf, len); +} +