mbed client lightswitch demo
Dependencies: mbed Socket lwip-eth lwip-sys lwip
Fork of mbed-client-classic-example-lwip by
Diff: nanostack-libservice/source/libTrace/ns_trace.c
- Revision:
- 11:cada08fc8a70
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nanostack-libservice/source/libTrace/ns_trace.c Thu Jun 09 17:08:36 2016 +0000
@@ -0,0 +1,535 @@
+/*
+ * 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>
+#include <stdlib.h>
+
+#define HAVE_DEBUG 1
+
+#include "ns_trace.h"
+#include "ip6string.h"
+#include "common_functions.h"
+
+#if defined(_WIN32) || defined(__unix__) || defined(__unix) || defined(unix) || (defined(YOTTA_CFG) && !defined(NDEBUG))
+//NOTE! It is not allowed to use this MEM_ALLOC/MEM_FREE from interrupt context.
+#ifndef MEM_ALLOC
+#define MEM_ALLOC malloc
+#endif
+#ifndef MEM_FREE
+#define MEM_FREE free
+#endif
+#else
+#include "nsdynmemLIB.h"
+#ifndef MEM_ALLOC
+#define MEM_ALLOC ns_dyn_mem_alloc
+#endif
+#ifndef MEM_FREE
+#define MEM_FREE ns_dyn_mem_free
+#endif
+#endif
+
+#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 */
+#define DEFAULT_TRACE_LINE_LENGTH 1024
+/** default max temporary buffer size in bytes, used in
+ trace_ipv6, trace_array and trace_strn */
+#define DEFAULT_TRACE_TMP_LINE_LEN 128
+/** default max filters (include/exclude) length in bytes */
+#define DEFAULT_TRACE_FILTER_LENGTH 24
+
+/** default print function, just redirect str to printf */
+static void default_print(const char *str);
+
+typedef struct {
+ /** 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 *);
+} trace_s;
+
+static trace_s m_trace = {
+ .filters_exclude = 0,
+ .filters_include = 0,
+ .line = 0,
+ .tmp_data = 0,
+ .prefix_f = 0,
+ .suffix_f = 0,
+ .printf = 0,
+ .cmd_printf = 0
+};
+
+int trace_init(void)
+{
+ m_trace.trace_config = TRACE_MODE_COLOR | TRACE_ACTIVE_LEVEL_ALL | TRACE_CARRIAGE_RETURN;
+ m_trace.line_length = DEFAULT_TRACE_LINE_LENGTH;
+ if (m_trace.line == NULL) {
+ m_trace.line = MEM_ALLOC(m_trace.line_length);
+ }
+ m_trace.tmp_data_length = DEFAULT_TRACE_TMP_LINE_LEN;
+ if (m_trace.tmp_data == NULL) {
+ m_trace.tmp_data = MEM_ALLOC(m_trace.tmp_data_length);
+ }
+ m_trace.tmp_data_ptr = m_trace.tmp_data;
+ m_trace.filters_length = DEFAULT_TRACE_FILTER_LENGTH;
+ if (m_trace.filters_exclude == NULL) {
+ m_trace.filters_exclude = MEM_ALLOC(m_trace.filters_length);
+ }
+ if (m_trace.filters_include == NULL) {
+ m_trace.filters_include = 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
+ 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);
+
+ m_trace.prefix_f = 0;
+ m_trace.suffix_f = 0;
+ m_trace.printf = default_print;
+ m_trace.cmd_printf = 0;
+
+ return 0;
+}
+void trace_free(void)
+{
+ MEM_FREE(m_trace.line);
+ m_trace.line_length = 0;
+ m_trace.line = 0;
+ MEM_FREE(m_trace.tmp_data);
+ m_trace.tmp_data = 0;
+ m_trace.tmp_data_ptr = 0;
+ MEM_FREE(m_trace.filters_exclude);
+ m_trace.filters_exclude = 0;
+ MEM_FREE(m_trace.filters_include);
+ m_trace.filters_include = 0;
+ m_trace.filters_length = 0;
+}
+/** @TODO do we need dynamically change trace buffer sizes ?
+// reconfigure trace buffer sizes
+void set_trace_buffer_sizes(int lineLength, int tmpLength)
+{
+ REALLOC( m_trace.line, dataLength );
+ REALLOC( m_trace.tmp_data, tmpLength);
+ m_trace.tmp_data_length = tmpLength;
+}
+*/
+void set_trace_config(uint8_t config)
+{
+ m_trace.trace_config = config;
+}
+uint8_t get_trace_config(void)
+{
+ return m_trace.trace_config;
+}
+void set_trace_prefix_function(char *(*pref_f)(size_t))
+{
+ m_trace.prefix_f = pref_f;
+}
+void set_trace_suffix_function(char *(*suffix_f)(void))
+{
+ m_trace.suffix_f = suffix_f;
+}
+void set_trace_print_function(void (*printf)(const char *))
+{
+ m_trace.printf = printf;
+}
+void set_trace_cmdprint_function(void (*printf)(const char *))
+{
+ m_trace.cmd_printf = printf;
+}
+void set_trace_exclude_filters(char *filters)
+{
+ if (filters) {
+ (void)strncpy(m_trace.filters_exclude, filters, m_trace.filters_length);
+ } else {
+ m_trace.filters_exclude[0] = 0;
+ }
+}
+const char *get_trace_exclude_filters(void)
+{
+ return m_trace.filters_exclude;
+}
+const char *get_trace_include_filters(void)
+{
+ return m_trace.filters_include;
+}
+void set_trace_include_filters(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 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 default_print(const char *str)
+{
+ puts(str);
+}
+void tracef(uint8_t dlevel, const char *grp, const char *fmt, ...)
+{
+ if (m_trace.line == NULL) {
+ // Quite likely the trace_init() has not been called yet,
+ // but it is better to just shut up instead of crashing with
+ // null pointer dereference.
+ return;
+ }
+
+ m_trace.line[0] = 0; //by default trace is empty
+ if (trace_skip(dlevel, grp) || fmt == 0 || grp == 0) {
+ return;
+ }
+ 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;
+ //printf("CFG: 0x%02x, plain: %i, color: %i, cr: %i\n", m_trace.trace_config, plain, color, cr);
+
+ int retval = 0, bLeft = m_trace.line_length;
+ char *ptr = m_trace.line;
+ if (plain == true || dlevel == TRACE_LEVEL_CMD) {
+ va_list ap;
+ va_start(ap, fmt);
+ //add trace data
+ retval = vsnprintf(ptr, bLeft, fmt, ap);
+ va_end(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) {
+ va_list ap;
+ va_start(ap, fmt);
+ //find out length of body
+ size_t sz = 0;
+ sz = vsnprintf(NULL, 0, fmt, ap) + retval + (retval ? 4 : 0);
+ //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;
+ }
+ va_end(ap);
+ }
+ 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) {
+ va_list ap;
+ va_start(ap, fmt);
+ //add trace text
+ retval = vsnprintf(ptr, bLeft, fmt, ap);
+ if (retval >= bLeft) {
+ retval = 0;
+ }
+ if (retval > 0) {
+ ptr += retval;
+ bLeft -= retval;
+ }
+ va_end(ap);
+ }
+
+ 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) {
+ ptr += retval;
+ bLeft -= retval;
+ }
+ }
+ //print out whole data
+ m_trace.printf(m_trace.line);
+ }
+ //return tmp data pointer back to the beginning
+ m_trace.tmp_data_ptr = m_trace.tmp_data;
+ }
+}
+const char *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)
+char *trace_ipv6(const void *addr_ptr)
+{
+ 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;
+ ip6tos(addr_ptr, str);
+ m_trace.tmp_data_ptr += strlen(str) + 1;
+ return str;
+}
+char *trace_ipv6_prefix(const uint8_t *prefix, uint8_t prefix_len)
+{
+ char *str = m_trace.tmp_data_ptr;
+ int retval, bLeft = tmp_data_left();
+ char tmp[40];
+ uint8_t addr[16] = {0};
+
+ if (str == NULL) {
+ return "";
+ }
+ if (bLeft < 43) {
+ return "";
+ }
+
+ if (prefix_len != 0) {
+ if (prefix == NULL || prefix_len > 128) {
+ return "<err>";
+ }
+ bitcopy(addr, prefix, prefix_len);
+ }
+
+ ip6tos(addr, tmp);
+ retval = snprintf(str, bLeft, "%s/%u", tmp, prefix_len);
+ if (retval <= 0 || retval > bLeft) {
+ return "";
+ }
+
+ m_trace.tmp_data_ptr += retval + 1;
+ return str;
+}
+char *trace_array(const uint8_t *buf, uint16_t len)
+{
+ int i, retval, bLeft = tmp_data_left();
+ char *str, *wptr;
+ str = m_trace.tmp_data_ptr;
+ if (str == NULL) {
+ return "";
+ }
+ if (buf == NULL) {
+ return "<null>";
+ }
+ wptr = str;
+ wptr[0] = 0;
+ const uint8_t *ptr = buf;
+ for (i = 0; i < len; i++) {
+ if (bLeft <= 0) {
+ break;
+ }
+ retval = snprintf(wptr, bLeft, "%02x:", *ptr++);
+ if (retval <= 0 || retval > bLeft) {
+ break;
+ }
+ bLeft -= retval;
+ wptr += retval;
+ }
+ if (wptr > str) {
+ *(wptr - 1) = 0; //null to replace last ':' character
+ }
+ m_trace.tmp_data_ptr = wptr;
+ return str;
+}
+
+// rest of debug print functions will be obsolete and will be overridden with new trace interface..
+void debugf(const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ vprintf(fmt, ap);
+ va_end(ap);
+}
+
+void debug(const char *s)
+{
+ fputs(s, stdout);
+}
+
+void debug_put(char c)
+{
+ putchar(c);
+}
+
+void debug_hex(uint8_t x)
+{
+ printf("%02x", x);
+}
+void debug_int(int i)
+{
+ printf("%d", i);
+}
+void printf_array(const void *buf , uint16_t len)
+{
+ int i;
+ const uint8_t *ptr = buf;
+ for (i = 0; i < len; i++) {
+ if (i && (0 == i % 16)) {
+ putchar('\n');
+ }
+ printf("%02x:", *ptr++);
+
+ }
+ putchar('\n');
+}
+void printf_ipv6_address(const void *addr_ptr)
+{
+ char buf[40] = {0};
+ ip6tos(addr_ptr, buf);
+ printf("%s\n", buf);
+}
+void printf_string(const void *ptr, uint16_t len)
+{
+ printf("%.*s\n", len, (const char *)ptr);
+}
Austin Blackstone
