Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of mbed-os by
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 }
Generated on Tue Jul 12 2022 13:16:02 by
