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
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 11:02:30 by 1.7.2