Example
Dependencies: FXAS21002 FXOS8700Q
Diff: simple-mbed-cloud-client/mbed-cloud-client/mbed-trace/source/mbed_trace.c
- Revision:
- 0:11cc2b7889af
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-trace/source/mbed_trace.c Tue Nov 19 09:49:38 2019 +0000 @@ -0,0 +1,595 @@ +/* + * Copyright (c) 2014-2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include <stdio.h> +#include <string.h> +#include <stdarg.h> + +#ifdef MBED_CONF_MBED_TRACE_ENABLE +#undef MBED_CONF_MBED_TRACE_ENABLE +#endif +#define MBED_CONF_MBED_TRACE_ENABLE 1 +#ifndef MBED_CONF_MBED_TRACE_FEA_IPV6 +#define MBED_CONF_MBED_TRACE_FEA_IPV6 1 +#endif + +#include "mbed-trace/mbed_trace.h" +#if MBED_CONF_MBED_TRACE_FEA_IPV6 == 1 +#include "mbed-client-libservice/ip6string.h" +#include "mbed-client-libservice/common_functions.h" +#endif + +#if defined(YOTTA_CFG_MBED_TRACE_MEM) +#define MBED_TRACE_MEM_INCLUDE YOTTA_CFG_MBED_TRACE_MEM_INCLUDE +#define MBED_TRACE_MEM_ALLOC YOTTA_CFG_MBED_TRACE_MEM_ALLOC +#define MBED_TRACE_MEM_FREE YOTTA_CFG_MBED_TRACE_MEM_FREE +#else /* YOTTA_CFG_MEMLIB */ +// Default options +#ifndef MBED_TRACE_MEM_INCLUDE +#define MBED_TRACE_MEM_INCLUDE <stdlib.h> +#endif +#include MBED_TRACE_MEM_INCLUDE +#ifndef MBED_TRACE_MEM_ALLOC +#define MBED_TRACE_MEM_ALLOC malloc +#endif +#ifndef MBED_TRACE_MEM_FREE +#define MBED_TRACE_MEM_FREE free +#endif +#endif /* YOTTA_CFG_MEMLIB */ + +#define VT100_COLOR_ERROR "\x1b[31m" +#define VT100_COLOR_WARN "\x1b[33m" +#define VT100_COLOR_INFO "\x1b[39m" +#define VT100_COLOR_DEBUG "\x1b[90m" + +/** default max trace line size in bytes */ +#ifdef MBED_TRACE_LINE_LENGTH +#define DEFAULT_TRACE_LINE_LENGTH MBED_TRACE_LINE_LENGTH +#elif defined YOTTA_CFG_MBED_TRACE_LINE_LENGTH +#warning YOTTA_CFG_MBED_TRACE_LINE_LENGTH is deprecated and will be removed in the future! Use MBED_TRACE_LINE_LENGTH instead. +#define DEFAULT_TRACE_LINE_LENGTH YOTTA_CFG_MBED_TRACE_LINE_LENGTH +#else +#define DEFAULT_TRACE_LINE_LENGTH 1024 +#endif + +/** default max temporary buffer size in bytes, used in + trace_ipv6, trace_ipv6_prefix and trace_array */ +#ifdef MBED_TRACE_TMP_LINE_LENGTH +#define DEFAULT_TRACE_TMP_LINE_LEN MBED_TRACE_TMP_LINE_LENGTH +#elif defined YOTTA_CFG_MBED_TRACE_TMP_LINE_LEN +#warning The YOTTA_CFG_MBED_TRACE_TMP_LINE_LEN flag is deprecated and will be removed in the future! Use MBED_TRACE_TMP_LINE_LENGTH instead. +#define DEFAULT_TRACE_TMP_LINE_LEN YOTTA_CFG_MBED_TRACE_TMP_LINE_LEN +#elif defined YOTTA_CFG_MTRACE_TMP_LINE_LEN +#warning The YOTTA_CFG_MTRACE_TMP_LINE_LEN flag is deprecated and will be removed in the future! Use MBED_TRACE_TMP_LINE_LENGTH instead. +#define DEFAULT_TRACE_TMP_LINE_LEN YOTTA_CFG_MTRACE_TMP_LINE_LEN +#else +#define DEFAULT_TRACE_TMP_LINE_LEN 128 +#endif + +/** default max filters (include/exclude) length in bytes */ +#ifdef MBED_TRACE_FILTER_LENGTH +#define DEFAULT_TRACE_FILTER_LENGTH MBED_TRACE_FILTER_LENGTH +#else +#define DEFAULT_TRACE_FILTER_LENGTH 24 +#endif + +/** default trace configuration bitmask */ +#ifdef MBED_TRACE_CONFIG +#define DEFAULT_TRACE_CONFIG MBED_TRACE_CONFIG +#else +#define DEFAULT_TRACE_CONFIG TRACE_MODE_COLOR | TRACE_ACTIVE_LEVEL_ALL | TRACE_CARRIAGE_RETURN +#endif + +/** default print function, just redirect str to printf */ +static void mbed_trace_realloc( char **buffer, int *length_ptr, int new_length); +static void mbed_trace_default_print(const char *str); +static void mbed_trace_reset_tmp(void); + +typedef struct trace_s { + /** trace configuration bits */ + uint8_t trace_config; + /** exclude filters list, related group name */ + char *filters_exclude; + /** include filters list, related group name */ + char *filters_include; + /** Filters length */ + int filters_length; + /** trace line */ + char *line; + /** trace line length */ + int line_length; + /** temporary data */ + char *tmp_data; + /** temporary data array length */ + int tmp_data_length; + /** temporary data pointer */ + char *tmp_data_ptr; + + /** prefix function, which can be used to put time to the trace line */ + char *(*prefix_f)(size_t); + /** suffix function, which can be used to some string to the end of trace line */ + char *(*suffix_f)(void); + /** print out function. Can be redirect to flash for example. */ + void (*printf)(const char *); + /** print out function for TRACE_LEVEL_CMD */ + void (*cmd_printf)(const char *); + /** mutex wait function which can be called to lock against a mutex. */ + void (*mutex_wait_f)(void); + /** mutex release function which must be used to release the mutex locked by mutex_wait_f. */ + void (*mutex_release_f)(void); + /** number of times the mutex has been locked */ + int mutex_lock_count; +} trace_t; + +static trace_t m_trace = { + .trace_config = DEFAULT_TRACE_CONFIG, + .filters_exclude = 0, + .filters_include = 0, + .filters_length = DEFAULT_TRACE_FILTER_LENGTH, + .line = 0, + .line_length = DEFAULT_TRACE_LINE_LENGTH, + .tmp_data = 0, + .tmp_data_length = DEFAULT_TRACE_TMP_LINE_LEN, + .prefix_f = 0, + .suffix_f = 0, + .printf = mbed_trace_default_print, + .cmd_printf = 0, + .mutex_wait_f = 0, + .mutex_release_f = 0, + .mutex_lock_count = 0 +}; + +int mbed_trace_init(void) +{ + if (m_trace.line == NULL) { + m_trace.line = MBED_TRACE_MEM_ALLOC(m_trace.line_length); + } + + if (m_trace.tmp_data == NULL) { + m_trace.tmp_data = MBED_TRACE_MEM_ALLOC(m_trace.tmp_data_length); + } + m_trace.tmp_data_ptr = m_trace.tmp_data; + + if (m_trace.filters_exclude == NULL) { + m_trace.filters_exclude = MBED_TRACE_MEM_ALLOC(m_trace.filters_length); + } + if (m_trace.filters_include == NULL) { + m_trace.filters_include = MBED_TRACE_MEM_ALLOC(m_trace.filters_length); + } + + if (m_trace.line == NULL || + m_trace.tmp_data == NULL || + m_trace.filters_exclude == NULL || + m_trace.filters_include == NULL) { + //memory allocation fail + mbed_trace_free(); + return -1; + } + memset(m_trace.tmp_data, 0, m_trace.tmp_data_length); + memset(m_trace.filters_exclude, 0, m_trace.filters_length); + memset(m_trace.filters_include, 0, m_trace.filters_length); + memset(m_trace.line, 0, m_trace.line_length); + + return 0; +} +void mbed_trace_free(void) +{ + // release memory + MBED_TRACE_MEM_FREE(m_trace.line); + MBED_TRACE_MEM_FREE(m_trace.tmp_data); + MBED_TRACE_MEM_FREE(m_trace.filters_exclude); + MBED_TRACE_MEM_FREE(m_trace.filters_include); + + // reset to default values + m_trace.trace_config = DEFAULT_TRACE_CONFIG; + m_trace.filters_exclude = 0; + m_trace.filters_include = 0; + m_trace.filters_length = DEFAULT_TRACE_FILTER_LENGTH; + m_trace.line = 0; + m_trace.line_length = DEFAULT_TRACE_LINE_LENGTH; + m_trace.tmp_data = 0; + m_trace.tmp_data_length = DEFAULT_TRACE_TMP_LINE_LEN; + m_trace.prefix_f = 0; + m_trace.suffix_f = 0; + m_trace.printf = mbed_trace_default_print; + m_trace.cmd_printf = 0; + m_trace.mutex_wait_f = 0; + m_trace.mutex_release_f = 0; + m_trace.mutex_lock_count = 0; +} +static void mbed_trace_realloc( char **buffer, int *length_ptr, int new_length) +{ + MBED_TRACE_MEM_FREE(*buffer); + *buffer = MBED_TRACE_MEM_ALLOC(new_length); + *length_ptr = new_length; +} +void mbed_trace_buffer_sizes(int lineLength, int tmpLength) +{ + if( lineLength > 0 ) { + mbed_trace_realloc( &(m_trace.line), &m_trace.line_length, lineLength ); + } + if( tmpLength > 0 ) { + mbed_trace_realloc( &(m_trace.tmp_data), &m_trace.tmp_data_length, tmpLength); + mbed_trace_reset_tmp(); + } +} +void mbed_trace_config_set(uint8_t config) +{ + m_trace.trace_config = config; +} +uint8_t mbed_trace_config_get(void) +{ + return m_trace.trace_config; +} +void mbed_trace_prefix_function_set(char *(*pref_f)(size_t)) +{ + m_trace.prefix_f = pref_f; +} +void mbed_trace_suffix_function_set(char *(*suffix_f)(void)) +{ + m_trace.suffix_f = suffix_f; +} +void mbed_trace_print_function_set(void (*printf)(const char *)) +{ + m_trace.printf = printf; +} +void mbed_trace_cmdprint_function_set(void (*printf)(const char *)) +{ + m_trace.cmd_printf = printf; +} +void mbed_trace_mutex_wait_function_set(void (*mutex_wait_f)(void)) +{ + m_trace.mutex_wait_f = mutex_wait_f; +} +void mbed_trace_mutex_release_function_set(void (*mutex_release_f)(void)) +{ + m_trace.mutex_release_f = mutex_release_f; +} +void mbed_trace_exclude_filters_set(char *filters) +{ + if (filters) { + (void)strncpy(m_trace.filters_exclude, filters, m_trace.filters_length); + } else { + m_trace.filters_exclude[0] = 0; + } +} +const char *mbed_trace_exclude_filters_get(void) +{ + return m_trace.filters_exclude; +} +const char *mbed_trace_include_filters_get(void) +{ + return m_trace.filters_include; +} +void mbed_trace_include_filters_set(char *filters) +{ + if (filters) { + (void)strncpy(m_trace.filters_include, filters, m_trace.filters_length); + } else { + m_trace.filters_include[0] = 0; + } +} +static int8_t mbed_trace_skip(int8_t dlevel, const char *grp) +{ + if (dlevel >= 0 && grp != 0) { + // filter debug prints only when dlevel is >0 and grp is given + + /// @TODO this could be much better.. + if (m_trace.filters_exclude[0] != '\0' && + strstr(m_trace.filters_exclude, grp) != 0) { + //grp was in exclude list + return 1; + } + if (m_trace.filters_include[0] != '\0' && + strstr(m_trace.filters_include, grp) == 0) { + //grp was in include list + return 1; + } + } + return 0; +} +static void mbed_trace_default_print(const char *str) +{ + puts(str); +} +void mbed_tracef(uint8_t dlevel, const char *grp, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + mbed_vtracef(dlevel, grp, fmt, ap); + va_end(ap); +} +void mbed_vtracef(uint8_t dlevel, const char* grp, const char *fmt, va_list ap) +{ + if ( m_trace.mutex_wait_f ) { + m_trace.mutex_wait_f(); + m_trace.mutex_lock_count++; + } + + if (NULL == m_trace.line) { + goto end; + } + + m_trace.line[0] = 0; //by default trace is empty + + if (mbed_trace_skip(dlevel, grp) || fmt == 0 || grp == 0 || !m_trace.printf) { + //return tmp data pointer back to the beginning + mbed_trace_reset_tmp(); + goto end; + } + if ((m_trace.trace_config & TRACE_MASK_LEVEL) & dlevel) { + bool color = (m_trace.trace_config & TRACE_MODE_COLOR) != 0; + bool plain = (m_trace.trace_config & TRACE_MODE_PLAIN) != 0; + bool cr = (m_trace.trace_config & TRACE_CARRIAGE_RETURN) != 0; + + int retval = 0, bLeft = m_trace.line_length; + char *ptr = m_trace.line; + if (plain == true || dlevel == TRACE_LEVEL_CMD) { + //add trace data + retval = vsnprintf(ptr, bLeft, fmt, ap); + if (dlevel == TRACE_LEVEL_CMD && m_trace.cmd_printf) { + m_trace.cmd_printf(m_trace.line); + m_trace.cmd_printf("\n"); + } else { + //print out whole data + m_trace.printf(m_trace.line); + } + } else { + if (color) { + if (cr) { + retval = snprintf(ptr, bLeft, "\r\x1b[2K"); + if (retval >= bLeft) { + retval = 0; + } + if (retval > 0) { + ptr += retval; + bLeft -= retval; + } + } + if (bLeft > 0) { + //include color in ANSI/VT100 escape code + switch (dlevel) { + case (TRACE_LEVEL_ERROR): + retval = snprintf(ptr, bLeft, "%s", VT100_COLOR_ERROR); + break; + case (TRACE_LEVEL_WARN): + retval = snprintf(ptr, bLeft, "%s", VT100_COLOR_WARN); + break; + case (TRACE_LEVEL_INFO): + retval = snprintf(ptr, bLeft, "%s", VT100_COLOR_INFO); + break; + case (TRACE_LEVEL_DEBUG): + retval = snprintf(ptr, bLeft, "%s", VT100_COLOR_DEBUG); + break; + default: + color = 0; //avoid unneeded color-terminate code + retval = 0; + break; + } + if (retval >= bLeft) { + retval = 0; + } + if (retval > 0 && color) { + ptr += retval; + bLeft -= retval; + } + } + + } + if (bLeft > 0 && m_trace.prefix_f) { + //find out length of body + size_t sz = 0; + va_list ap2; + va_copy(ap2, ap); + sz = vsnprintf(NULL, 0, fmt, ap2) + retval + (retval ? 4 : 0); + va_end(ap2); + //add prefix string + retval = snprintf(ptr, bLeft, "%s", m_trace.prefix_f(sz)); + if (retval >= bLeft) { + retval = 0; + } + if (retval > 0) { + ptr += retval; + bLeft -= retval; + } + } + if (bLeft > 0) { + //add group tag + switch (dlevel) { + case (TRACE_LEVEL_ERROR): + retval = snprintf(ptr, bLeft, "[ERR ][%-4s]: ", grp); + break; + case (TRACE_LEVEL_WARN): + retval = snprintf(ptr, bLeft, "[WARN][%-4s]: ", grp); + break; + case (TRACE_LEVEL_INFO): + retval = snprintf(ptr, bLeft, "[INFO][%-4s]: ", grp); + break; + case (TRACE_LEVEL_DEBUG): + retval = snprintf(ptr, bLeft, "[DBG ][%-4s]: ", grp); + break; + default: + retval = snprintf(ptr, bLeft, " "); + break; + } + if (retval >= bLeft) { + retval = 0; + } + if (retval > 0) { + ptr += retval; + bLeft -= retval; + } + } + if (retval > 0 && bLeft > 0) { + //add trace text + retval = vsnprintf(ptr, bLeft, fmt, ap); + if (retval >= bLeft) { + retval = 0; + } + if (retval > 0) { + ptr += retval; + bLeft -= retval; + } + } + + if (retval > 0 && bLeft > 0 && m_trace.suffix_f) { + //add suffix string + retval = snprintf(ptr, bLeft, "%s", m_trace.suffix_f()); + if (retval >= bLeft) { + retval = 0; + } + if (retval > 0) { + ptr += retval; + bLeft -= retval; + } + } + + if (retval > 0 && bLeft > 0 && color) { + //add zero color VT100 when color mode + retval = snprintf(ptr, bLeft, "\x1b[0m"); + if (retval >= bLeft) { + retval = 0; + } + if (retval > 0) { + // not used anymore + //ptr += retval; + //bLeft -= retval; + } + } + //print out whole data + m_trace.printf(m_trace.line); + } + //return tmp data pointer back to the beginning + mbed_trace_reset_tmp(); + } + +end: + if ( m_trace.mutex_release_f ) { + // Store the mutex lock count to temp variable so that it won't get + // clobbered during last loop iteration when mutex gets released + int count = m_trace.mutex_lock_count; + m_trace.mutex_lock_count = 0; + // Since the helper functions (eg. mbed_trace_array) are used like this: + // mbed_tracef(TRACE_LEVEL_INFO, "grp", "%s", mbed_trace_array(some_array)) + // The helper function MUST acquire the mutex if it modifies any buffers. However + // it CANNOT unlock the mutex because that would allow another thread to acquire + // the mutex after helper function unlocks it and before mbed_tracef acquires it + // for itself. This means that here we have to unlock the mutex as many times + // as it was acquired by trace function and any possible helper functions. + do { + m_trace.mutex_release_f(); + } while (--count > 0); + } +} +static void mbed_trace_reset_tmp(void) +{ + m_trace.tmp_data_ptr = m_trace.tmp_data; +} +const char *mbed_trace_last(void) +{ + return m_trace.line; +} +/* Helping functions */ +#define tmp_data_left() m_trace.tmp_data_length-(m_trace.tmp_data_ptr-m_trace.tmp_data) +#if MBED_CONF_MBED_TRACE_FEA_IPV6 == 1 +char *mbed_trace_ipv6(const void *addr_ptr) +{ + /** Acquire mutex. It is released before returning from mbed_vtracef. */ + if ( m_trace.mutex_wait_f ) { + m_trace.mutex_wait_f(); + m_trace.mutex_lock_count++; + } + char *str = m_trace.tmp_data_ptr; + if (str == NULL) { + return ""; + } + if (tmp_data_left() < 41) { + return ""; + } + if (addr_ptr == NULL) { + return "<null>"; + } + str[0] = 0; + m_trace.tmp_data_ptr += ip6tos(addr_ptr, str) + 1; + return str; +} +char *mbed_trace_ipv6_prefix(const uint8_t *prefix, uint8_t prefix_len) +{ + /** Acquire mutex. It is released before returning from mbed_vtracef. */ + if ( m_trace.mutex_wait_f ) { + m_trace.mutex_wait_f(); + m_trace.mutex_lock_count++; + } + char *str = m_trace.tmp_data_ptr; + if (str == NULL) { + return ""; + } + if (tmp_data_left() < 45) { + return ""; + } + + if ((prefix_len != 0 && prefix == NULL) || prefix_len > 128) { + return "<err>"; + } + + m_trace.tmp_data_ptr += ip6_prefix_tos(prefix, prefix_len, str) + 1; + return str; +} +#endif //MBED_CONF_MBED_TRACE_FEA_IPV6 +char *mbed_trace_array(const uint8_t *buf, uint16_t len) +{ + /** Acquire mutex. It is released before returning from mbed_vtracef. */ + if ( m_trace.mutex_wait_f ) { + m_trace.mutex_wait_f(); + m_trace.mutex_lock_count++; + } + int i, bLeft = tmp_data_left(); + char *str, *wptr; + str = m_trace.tmp_data_ptr; + if (len == 0 || str == NULL || bLeft == 0) { + return ""; + } + if (buf == NULL) { + return "<null>"; + } + wptr = str; + wptr[0] = 0; + const uint8_t *ptr = buf; + char overflow = 0; + for (i = 0; i < len; i++) { + if (bLeft <= 3) { + overflow = 1; + break; + } + int retval = snprintf(wptr, bLeft, "%02x:", *ptr++); + if (retval <= 0 || retval > bLeft) { + break; + } + bLeft -= retval; + wptr += retval; + } + if (wptr > str) { + if( overflow ) { + // replace last character as 'star', + // which indicate buffer len is not enough + *(wptr - 1) = '*'; + } else { + //null to replace last ':' character + *(wptr - 1) = 0; + } + } + m_trace.tmp_data_ptr = wptr; + return str; +}