mbed-os for GR-LYCHEE

Dependents:   mbed-os-example-blinky-gr-lychee GR-Boads_Camera_sample GR-Boards_Audio_Recoder GR-Boads_Camera_DisplayApp ... more

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers ns_trace.c Source File

ns_trace.c

00001 /*
00002  * Copyright (c) 2014-2015 ARM Limited. All rights reserved.
00003  * SPDX-License-Identifier: Apache-2.0
00004  * Licensed under the Apache License, Version 2.0 (the License); you may
00005  * not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  * http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an AS IS BASIS, WITHOUT
00012  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
00015  */
00016 #include <stdio.h>
00017 #include <string.h>
00018 #include <stdarg.h>
00019 #include <stdlib.h>
00020 
00021 #define HAVE_DEBUG 1
00022 
00023 #include "ns_trace.h"
00024 #include "ip6string.h"
00025 #include "common_functions.h"
00026 
00027 #if defined(_WIN32) || defined(__unix__) || defined(__unix) || defined(unix) || (defined(YOTTA_CFG) && !defined(NDEBUG))
00028 //NOTE! It is not allowed to use this MEM_ALLOC/MEM_FREE from interrupt context.
00029 #ifndef MEM_ALLOC
00030 #define MEM_ALLOC malloc
00031 #endif
00032 #ifndef MEM_FREE
00033 #define MEM_FREE free
00034 #endif
00035 #else
00036 #include "nsdynmemLIB.h"
00037 #ifndef MEM_ALLOC
00038 #define MEM_ALLOC ns_dyn_mem_alloc
00039 #endif
00040 #ifndef MEM_FREE
00041 #define MEM_FREE ns_dyn_mem_free
00042 #endif
00043 #endif
00044 
00045 #ifndef NS_TRACE_USE_MBED_TRACE
00046 
00047 #define VT100_COLOR_ERROR "\x1b[31m"
00048 #define VT100_COLOR_WARN  "\x1b[33m"
00049 #define VT100_COLOR_INFO  "\x1b[39m"
00050 #define VT100_COLOR_DEBUG "\x1b[90m"
00051 
00052 /** default max trace line size in bytes */
00053 #define DEFAULT_TRACE_LINE_LENGTH     1024
00054 /** default max temporary buffer size in bytes, used in
00055     trace_ipv6, trace_array and trace_strn */
00056 #define DEFAULT_TRACE_TMP_LINE_LEN        512
00057 /** default max filters (include/exclude) length in bytes */
00058 #define DEFAULT_TRACE_FILTER_LENGTH       24
00059 
00060 /** default print function, just redirect str to printf */
00061 static void default_print(const char *str);
00062 
00063 typedef struct {
00064     /** trace configuration bits */
00065     uint8_t trace_config;
00066     /** exclude filters list, related group name */
00067     char *filters_exclude;
00068     /** include filters list, related group name */
00069     char *filters_include;
00070     /** Filters length */
00071     int filters_length;
00072     /** trace line */
00073     char *line;
00074     /** trace line length */
00075     int line_length;
00076     /** temporary data */
00077     char *tmp_data;
00078     /** temporary data array length */
00079     int tmp_data_length;
00080     /** temporary data pointer */
00081     char *tmp_data_ptr;
00082 
00083     /** prefix function, which can be used to put time to the trace line */
00084     char *(*prefix_f)(size_t);
00085     /** suffix function, which can be used to some string to the end of trace line */
00086     char *(*suffix_f)(void);
00087     /** print out function. Can be redirect to flash for example. */
00088     void (*printf)(const char *);
00089     /** print out function for TRACE_LEVEL_CMD */
00090     void (*cmd_printf)(const char *);
00091 } trace_s;
00092 
00093 static trace_s m_trace = {
00094     .filters_exclude = 0,
00095     .filters_include = 0,
00096     .line = 0,
00097     .tmp_data = 0,
00098     .prefix_f = 0,
00099     .suffix_f = 0,
00100     .printf  = 0,
00101     .cmd_printf = 0
00102 };
00103 
00104 int trace_init(void)
00105 {
00106     m_trace.trace_config = TRACE_MODE_COLOR | TRACE_ACTIVE_LEVEL_ALL | TRACE_CARRIAGE_RETURN;
00107     m_trace.line_length = DEFAULT_TRACE_LINE_LENGTH;
00108     if (m_trace.line == NULL) {
00109         m_trace.line = MEM_ALLOC(m_trace.line_length);
00110     }
00111     m_trace.tmp_data_length = DEFAULT_TRACE_TMP_LINE_LEN;
00112     if (m_trace.tmp_data == NULL) {
00113         m_trace.tmp_data = MEM_ALLOC(m_trace.tmp_data_length);
00114     }
00115     m_trace.tmp_data_ptr = m_trace.tmp_data;
00116     m_trace.filters_length = DEFAULT_TRACE_FILTER_LENGTH;
00117     if (m_trace.filters_exclude == NULL) {
00118         m_trace.filters_exclude = MEM_ALLOC(m_trace.filters_length);
00119     }
00120     if (m_trace.filters_include == NULL) {
00121         m_trace.filters_include = MEM_ALLOC(m_trace.filters_length);
00122     }
00123 
00124     if (m_trace.line == NULL ||
00125             m_trace.tmp_data == NULL ||
00126             m_trace.filters_exclude == NULL  ||
00127             m_trace.filters_include == NULL) {
00128         //memory allocation fail
00129         trace_free();
00130         return -1;
00131     }
00132     memset(m_trace.tmp_data, 0, m_trace.tmp_data_length);
00133     memset(m_trace.filters_exclude, 0, m_trace.filters_length);
00134     memset(m_trace.filters_include, 0, m_trace.filters_length);
00135     memset(m_trace.line, 0, m_trace.line_length);
00136 
00137     m_trace.prefix_f = 0;
00138     m_trace.suffix_f = 0;
00139     m_trace.printf = default_print;
00140     m_trace.cmd_printf = 0;
00141 
00142     return 0;
00143 }
00144 void trace_free(void)
00145 {
00146     MEM_FREE(m_trace.line);
00147     m_trace.line_length = 0;
00148     m_trace.line = 0;
00149     MEM_FREE(m_trace.tmp_data);
00150     m_trace.tmp_data = 0;
00151     m_trace.tmp_data_ptr = 0;
00152     MEM_FREE(m_trace.filters_exclude);
00153     m_trace.filters_exclude = 0;
00154     MEM_FREE(m_trace.filters_include);
00155     m_trace.filters_include = 0;
00156     m_trace.filters_length = 0;
00157 }
00158 /** @TODO do we need dynamically change trace buffer sizes ?
00159 // reconfigure trace buffer sizes
00160 void set_trace_buffer_sizes(int lineLength, int tmpLength)
00161 {
00162   REALLOC( m_trace.line, dataLength );
00163   REALLOC( m_trace.tmp_data, tmpLength);
00164   m_trace.tmp_data_length = tmpLength;
00165 }
00166 */
00167 void set_trace_config(uint8_t config)
00168 {
00169     m_trace.trace_config = config;
00170 }
00171 uint8_t get_trace_config(void)
00172 {
00173     return m_trace.trace_config;
00174 }
00175 void set_trace_prefix_function(char *(*pref_f)(size_t))
00176 {
00177     m_trace.prefix_f = pref_f;
00178 }
00179 void set_trace_suffix_function(char *(*suffix_f)(void))
00180 {
00181     m_trace.suffix_f = suffix_f;
00182 }
00183 void set_trace_print_function(void (*printf)(const char *))
00184 {
00185     m_trace.printf = printf;
00186 }
00187 void set_trace_cmdprint_function(void (*printf)(const char *))
00188 {
00189     m_trace.cmd_printf = printf;
00190 }
00191 void set_trace_exclude_filters(char *filters)
00192 {
00193     if (filters) {
00194         (void)strncpy(m_trace.filters_exclude, filters, m_trace.filters_length);
00195     } else {
00196         m_trace.filters_exclude[0] = 0;
00197     }
00198 }
00199 const char *get_trace_exclude_filters(void)
00200 {
00201     return m_trace.filters_exclude;
00202 }
00203 const char *get_trace_include_filters(void)
00204 {
00205     return m_trace.filters_include;
00206 }
00207 void set_trace_include_filters(char *filters)
00208 {
00209     if (filters) {
00210         (void)strncpy(m_trace.filters_include, filters, m_trace.filters_length);
00211     } else {
00212         m_trace.filters_include[0] = 0;
00213     }
00214 }
00215 static int8_t trace_skip(int8_t dlevel, const char *grp)
00216 {
00217     if (dlevel >= 0 && grp != 0) {
00218         // filter debug prints only when dlevel is >0 and grp is given
00219 
00220         /// @TODO this could be much better..
00221         if (m_trace.filters_exclude[0] != '\0' &&
00222                 strstr(m_trace.filters_exclude, grp) != 0) {
00223             //grp was in exclude list
00224             return 1;
00225         }
00226         if (m_trace.filters_include[0] != '\0' &&
00227                 strstr(m_trace.filters_include, grp) == 0) {
00228             //grp was in include list
00229             return 1;
00230         }
00231     }
00232     return 0;
00233 }
00234 static void default_print(const char *str)
00235 {
00236     puts(str);
00237 }
00238 void tracef(uint8_t dlevel, const char *grp, const char *fmt, ...)
00239 {
00240     if (m_trace.line == NULL) {
00241         // Quite likely the trace_init() has not been called yet,
00242         // but it is better to just shut up instead of crashing with
00243         // null pointer dereference. 
00244         m_trace.tmp_data_ptr = m_trace.tmp_data;
00245         return;
00246     }
00247     
00248     m_trace.line[0] = 0; //by default trace is empty
00249     if (trace_skip(dlevel, grp) || fmt == 0 || grp == 0) {
00250         m_trace.tmp_data_ptr = m_trace.tmp_data;
00251         return;
00252     }
00253     if ((m_trace.trace_config & TRACE_MASK_LEVEL) &  dlevel) {
00254         bool color = (m_trace.trace_config & TRACE_MODE_COLOR) != 0;
00255         bool plain = (m_trace.trace_config & TRACE_MODE_PLAIN) != 0;
00256         bool cr    = (m_trace.trace_config & TRACE_CARRIAGE_RETURN) != 0;
00257         //printf("CFG: 0x%02x, plain: %i, color: %i, cr: %i\n", m_trace.trace_config, plain, color, cr);
00258 
00259         int retval = 0, bLeft = m_trace.line_length;
00260         char *ptr = m_trace.line;
00261         if (plain == true || dlevel == TRACE_LEVEL_CMD) {
00262             va_list ap;
00263             va_start(ap, fmt);
00264             //add trace data
00265             retval = vsnprintf(ptr, bLeft, fmt, ap);
00266             va_end(ap);
00267             if (dlevel == TRACE_LEVEL_CMD && m_trace.cmd_printf) {
00268                 m_trace.cmd_printf(m_trace.line);
00269                 m_trace.cmd_printf("\n");
00270             } else {
00271                 //print out whole data
00272                 m_trace.printf(m_trace.line);
00273             }
00274         } else {
00275             if (color) {
00276                 if (cr) {
00277                     retval = snprintf(ptr, bLeft, "\r\x1b[2K");
00278                     if (retval >= bLeft) {
00279                         retval = 0;
00280                     }
00281                     if (retval > 0) {
00282                         ptr += retval;
00283                         bLeft -= retval;
00284                     }
00285                 }
00286                 if (bLeft > 0) {
00287                     //include color in ANSI/VT100 escape code
00288                     switch (dlevel) {
00289                         case (TRACE_LEVEL_ERROR):
00290                             retval = snprintf(ptr, bLeft, "%s", VT100_COLOR_ERROR);
00291                             break;
00292                         case (TRACE_LEVEL_WARN):
00293                             retval = snprintf(ptr, bLeft, "%s", VT100_COLOR_WARN);
00294                             break;
00295                         case (TRACE_LEVEL_INFO):
00296                             retval = snprintf(ptr, bLeft, "%s", VT100_COLOR_INFO);
00297                             break;
00298                         case (TRACE_LEVEL_DEBUG):
00299                             retval = snprintf(ptr, bLeft, "%s", VT100_COLOR_DEBUG);
00300                             break;
00301                         default:
00302                             color = 0; //avoid unneeded color-terminate code
00303                             retval = 0;
00304                             break;
00305                     }
00306                     if (retval >= bLeft) {
00307                         retval = 0;
00308                     }
00309                     if (retval > 0 && color) {
00310                         ptr += retval;
00311                         bLeft -= retval;
00312                     }
00313                 }
00314 
00315             }
00316             if (bLeft > 0 && m_trace.prefix_f) {
00317                 va_list ap;
00318                 va_start(ap, fmt);
00319                 //find out length of body
00320                 size_t sz = 0;
00321                 sz = vsnprintf(NULL, 0, fmt, ap) + retval + (retval ? 4 : 0);
00322                 //add prefix string
00323                 retval = snprintf(ptr, bLeft, "%s", m_trace.prefix_f(sz));
00324                 if (retval >= bLeft) {
00325                     retval = 0;
00326                 }
00327                 if (retval > 0) {
00328                     ptr += retval;
00329                     bLeft -= retval;
00330                 }
00331                 va_end(ap);
00332             }
00333             if (bLeft > 0) {
00334                 //add group tag
00335                 switch (dlevel) {
00336                     case (TRACE_LEVEL_ERROR):
00337                         retval = snprintf(ptr, bLeft, "[ERR ][%-4s]: ", grp);
00338                         break;
00339                     case (TRACE_LEVEL_WARN):
00340                         retval = snprintf(ptr, bLeft, "[WARN][%-4s]: ", grp);
00341                         break;
00342                     case (TRACE_LEVEL_INFO):
00343                         retval = snprintf(ptr, bLeft, "[INFO][%-4s]: ", grp);
00344                         break;
00345                     case (TRACE_LEVEL_DEBUG):
00346                         retval = snprintf(ptr, bLeft, "[DBG ][%-4s]: ", grp);
00347                         break;
00348                     default:
00349                         retval = snprintf(ptr, bLeft, "              ");
00350                         break;
00351                 }
00352                 if (retval >= bLeft) {
00353                     retval = 0;
00354                 }
00355                 if (retval > 0) {
00356                     ptr += retval;
00357                     bLeft -= retval;
00358                 }
00359             }
00360             if (retval > 0 && bLeft > 0) {
00361                 va_list ap;
00362                 va_start(ap, fmt);
00363                 //add trace text
00364                 retval = vsnprintf(ptr, bLeft, fmt, ap);
00365                 if (retval >= bLeft) {
00366                     retval = 0;
00367                 }
00368                 if (retval > 0) {
00369                     ptr += retval;
00370                     bLeft -= retval;
00371                 }
00372                 va_end(ap);
00373             }
00374 
00375             if (retval > 0 && bLeft > 0  && m_trace.suffix_f) {
00376                 //add suffix string
00377                 retval = snprintf(ptr, bLeft, "%s", m_trace.suffix_f());
00378                 if (retval >= bLeft) {
00379                     retval = 0;
00380                 }
00381                 if (retval > 0) {
00382                     ptr += retval;
00383                     bLeft -= retval;
00384                 }
00385             }
00386 
00387             if (retval > 0 && bLeft > 0  && color) {
00388                 //add zero color VT100 when color mode
00389                 retval = snprintf(ptr, bLeft, "\x1b[0m");
00390                 if (retval >= bLeft) {
00391                     retval = 0;
00392                 }
00393                 if (retval > 0) {
00394                     ptr += retval;
00395                     bLeft -= retval;
00396                 }
00397             }
00398             //print out whole data
00399             m_trace.printf(m_trace.line);
00400         }
00401         //return tmp data pointer back to the beginning
00402     }
00403     m_trace.tmp_data_ptr = m_trace.tmp_data;
00404 }
00405 const char *trace_last(void)
00406 {
00407     return m_trace.line;
00408 }
00409 /* Helping functions */
00410 #define tmp_data_left()  m_trace.tmp_data_length-(m_trace.tmp_data_ptr-m_trace.tmp_data)
00411 char *trace_ipv6(const void *addr_ptr)
00412 {
00413     char *str = m_trace.tmp_data_ptr;
00414     if (str == NULL) {
00415         return "";
00416     }
00417     if (tmp_data_left() < 41) {
00418         return "";
00419     }
00420     if (addr_ptr == NULL) {
00421         return "<null>";
00422     }
00423     str[0] = 0;
00424     ip6tos(addr_ptr, str);
00425     m_trace.tmp_data_ptr += strlen(str) + 1;
00426     return str;
00427 }
00428 char *trace_ipv6_prefix(const uint8_t *prefix, uint8_t prefix_len)
00429 {
00430     char *str = m_trace.tmp_data_ptr;
00431     int retval, bLeft = tmp_data_left();
00432     char tmp[40];
00433     uint8_t addr[16] = {0};
00434 
00435     if (str == NULL) {
00436         return "";
00437     }
00438     if (bLeft < 40 + 1 + 3 + 1) {// "ipv6 addr" + "/" + "128" + nul
00439         return "";
00440     }
00441 
00442     if (prefix_len != 0) {
00443         if (prefix == NULL || prefix_len > 128) {
00444             return "<err>";
00445         }
00446         bitcopy(addr, prefix, prefix_len);
00447     }
00448 
00449     ip6tos(addr, tmp);
00450     retval = snprintf(str, bLeft, "%s/%u", tmp, prefix_len);
00451     if (retval <= 0 || retval > bLeft) {
00452         return "";
00453     }
00454 
00455     m_trace.tmp_data_ptr += retval + 1;
00456     return str;
00457 }
00458 char *trace_array(const uint8_t *buf, uint16_t len)
00459 {
00460     int i, retval, bLeft = tmp_data_left();
00461     char *str, *wptr;
00462     str = m_trace.tmp_data_ptr;
00463     if (str == NULL || bLeft == 0) {
00464         return "";
00465     }
00466     if (buf == NULL) {
00467         return "<null>";
00468     }
00469     if (!bLeft) {
00470         return "";
00471     }
00472     wptr = str;
00473     wptr[0] = 0;
00474     const uint8_t *ptr = buf;
00475     char overflow = 0;
00476     for (i = 0; i < len; i++) {
00477         if (bLeft <= 3) {
00478             overflow = 1;
00479             break;
00480         }
00481         retval = snprintf(wptr, bLeft, "%02x:", *ptr++);
00482         if (retval <= 0 || retval > bLeft) {
00483             break;
00484         }
00485         bLeft -= retval;
00486         wptr += retval;
00487     }
00488     if (wptr > str) {
00489         if( overflow ) {
00490             // replace last character as 'star',
00491             // which indicate buffer len is not enough
00492             *(wptr - 1) = '*';
00493         } else {
00494             //null to replace last ':' character
00495             *(wptr - 1) = 0;
00496         }
00497     }
00498     m_trace.tmp_data_ptr = wptr;
00499     return str;
00500 }
00501 #endif /* NS_TRACE_USE_MBED_TRACE */
00502 
00503 // rest of debug print functions will be obsolete and will be overridden with new trace interface..
00504 void debugf(const char *fmt, ...)
00505 {
00506     va_list ap;
00507     va_start(ap, fmt);
00508     vprintf(fmt, ap);
00509     va_end(ap);
00510 }
00511 
00512 void debug(const char *s)
00513 {
00514     fputs(s, stdout);
00515 }
00516 
00517 void debug_put(char c)
00518 {
00519     putchar(c);
00520 }
00521 
00522 void debug_hex(uint8_t x)
00523 {
00524     printf("%02x", x);
00525 }
00526 void debug_int(int i)
00527 {
00528     printf("%d", i);
00529 }
00530 void printf_array(const void *buf , uint16_t len)
00531 {
00532     int i;
00533     const uint8_t *ptr = buf;
00534     for (i = 0; i < len; i++) {
00535         if (i && (0 == i % 16)) {
00536             putchar('\n');
00537         }
00538         printf("%02x:", *ptr++);
00539 
00540     }
00541     putchar('\n');
00542 }
00543 void printf_ipv6_address(const void *addr_ptr)
00544 {
00545     char buf[40] = {0};
00546     ip6tos(addr_ptr, buf);
00547     printf("%s\n", buf);
00548 }
00549 void printf_string(const void *ptr, uint16_t len)
00550 {
00551     printf("%.*s\n", len, (const char *)ptr);
00552 }