Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers mbed_trace.c Source File

mbed_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 
00020 #ifdef MBED_CONF_MBED_TRACE_ENABLE
00021 #undef MBED_CONF_MBED_TRACE_ENABLE
00022 #endif
00023 #define MBED_CONF_MBED_TRACE_ENABLE 1
00024 #ifndef MBED_CONF_MBED_TRACE_FEA_IPV6
00025 #define MBED_CONF_MBED_TRACE_FEA_IPV6 1
00026 #endif
00027 
00028 #include "mbed-trace/mbed_trace.h"
00029 #if MBED_CONF_MBED_TRACE_FEA_IPV6 == 1
00030 #include "mbed-client-libservice/ip6string.h"
00031 #include "mbed-client-libservice/common_functions.h"
00032 #endif
00033 
00034 #if defined(YOTTA_CFG_MBED_TRACE_MEM)
00035 #define MBED_TRACE_MEM_INCLUDE      YOTTA_CFG_MBED_TRACE_MEM_INCLUDE
00036 #define MBED_TRACE_MEM_ALLOC        YOTTA_CFG_MBED_TRACE_MEM_ALLOC
00037 #define MBED_TRACE_MEM_FREE         YOTTA_CFG_MBED_TRACE_MEM_FREE
00038 #else /* YOTTA_CFG_MEMLIB */
00039 // Default options
00040 #ifndef MBED_TRACE_MEM_INCLUDE
00041 #define MBED_TRACE_MEM_INCLUDE   <stdlib.h>
00042 #endif
00043 #include MBED_TRACE_MEM_INCLUDE
00044 #ifndef MBED_TRACE_MEM_ALLOC
00045 #define MBED_TRACE_MEM_ALLOC malloc
00046 #endif
00047 #ifndef MBED_TRACE_MEM_FREE
00048 #define MBED_TRACE_MEM_FREE  free
00049 #endif
00050 #endif /* YOTTA_CFG_MEMLIB */
00051 
00052 #define VT100_COLOR_ERROR "\x1b[31m"
00053 #define VT100_COLOR_WARN  "\x1b[33m"
00054 #define VT100_COLOR_INFO  "\x1b[39m"
00055 #define VT100_COLOR_DEBUG "\x1b[90m"
00056 
00057 /** default max trace line size in bytes */
00058 #ifdef MBED_TRACE_LINE_LENGTH
00059 #define DEFAULT_TRACE_LINE_LENGTH         MBED_TRACE_LINE_LENGTH
00060 #elif defined YOTTA_CFG_MBED_TRACE_LINE_LENGTH
00061 #warning YOTTA_CFG_MBED_TRACE_LINE_LENGTH is deprecated and will be removed in the future! Use MBED_TRACE_LINE_LENGTH instead.
00062 #define DEFAULT_TRACE_LINE_LENGTH         YOTTA_CFG_MBED_TRACE_LINE_LENGTH
00063 #else
00064 #define DEFAULT_TRACE_LINE_LENGTH         1024
00065 #endif
00066 
00067 /** default max temporary buffer size in bytes, used in
00068     trace_ipv6, trace_ipv6_prefix and trace_array */
00069 #ifdef MBED_TRACE_TMP_LINE_LENGTH
00070 #define DEFAULT_TRACE_TMP_LINE_LEN        MBED_TRACE_TMP_LINE_LENGTH
00071 #elif defined YOTTA_CFG_MBED_TRACE_TMP_LINE_LEN
00072 #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.
00073 #define DEFAULT_TRACE_TMP_LINE_LEN        YOTTA_CFG_MBED_TRACE_TMP_LINE_LEN
00074 #elif defined YOTTA_CFG_MTRACE_TMP_LINE_LEN
00075 #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.
00076 #define DEFAULT_TRACE_TMP_LINE_LEN        YOTTA_CFG_MTRACE_TMP_LINE_LEN
00077 #else
00078 #define DEFAULT_TRACE_TMP_LINE_LEN        128
00079 #endif
00080 
00081 /** default max filters (include/exclude) length in bytes */
00082 #ifdef MBED_TRACE_FILTER_LENGTH
00083 #define DEFAULT_TRACE_FILTER_LENGTH       MBED_TRACE_FILTER_LENGTH
00084 #else
00085 #define DEFAULT_TRACE_FILTER_LENGTH       24
00086 #endif
00087 
00088 /** default trace configuration bitmask */
00089 #ifdef MBED_TRACE_CONFIG
00090 #define DEFAULT_TRACE_CONFIG              MBED_TRACE_CONFIG
00091 #else
00092 #define DEFAULT_TRACE_CONFIG              TRACE_MODE_COLOR | TRACE_ACTIVE_LEVEL_ALL | TRACE_CARRIAGE_RETURN
00093 #endif
00094 
00095 /** default print function, just redirect str to printf */
00096 static void mbed_trace_realloc(char **buffer, int *length_ptr, int new_length);
00097 static void mbed_trace_default_print(const char *str);
00098 static void mbed_trace_reset_tmp(void);
00099 
00100 typedef struct trace_s {
00101     /** trace configuration bits */
00102     uint8_t trace_config;
00103     /** exclude filters list, related group name */
00104     char *filters_exclude;
00105     /** include filters list, related group name */
00106     char *filters_include;
00107     /** Filters length */
00108     int filters_length;
00109     /** trace line */
00110     char *line;
00111     /** trace line length */
00112     int line_length;
00113     /** temporary data */
00114     char *tmp_data;
00115     /** temporary data array length */
00116     int tmp_data_length;
00117     /** temporary data pointer */
00118     char *tmp_data_ptr;
00119 
00120     /** prefix function, which can be used to put time to the trace line */
00121     char *(*prefix_f)(size_t);
00122     /** suffix function, which can be used to some string to the end of trace line */
00123     char *(*suffix_f)(void);
00124     /** print out function. Can be redirect to flash for example. */
00125     void (*printf)(const char *);
00126     /** print out function for TRACE_LEVEL_CMD */
00127     void (*cmd_printf)(const char *);
00128     /** mutex wait function which can be called to lock against a mutex. */
00129     void (*mutex_wait_f)(void);
00130     /** mutex release function which must be used to release the mutex locked by mutex_wait_f. */
00131     void (*mutex_release_f)(void);
00132     /** number of times the mutex has been locked */
00133     int mutex_lock_count;
00134 } trace_t;
00135 
00136 static trace_t m_trace = {
00137     .trace_config = DEFAULT_TRACE_CONFIG,
00138     .filters_exclude = 0,
00139     .filters_include = 0,
00140     .filters_length = DEFAULT_TRACE_FILTER_LENGTH,
00141     .line = 0,
00142     .line_length = DEFAULT_TRACE_LINE_LENGTH,
00143     .tmp_data = 0,
00144     .tmp_data_length = DEFAULT_TRACE_TMP_LINE_LEN,
00145     .tmp_data_ptr = 0,
00146     .prefix_f = 0,
00147     .suffix_f = 0,
00148     .printf  = mbed_trace_default_print,
00149     .cmd_printf = 0,
00150     .mutex_wait_f = 0,
00151     .mutex_release_f = 0,
00152     .mutex_lock_count = 0
00153 };
00154 
00155 int mbed_trace_init(void)
00156 {
00157     if (m_trace.line == NULL) {
00158         m_trace.line = MBED_TRACE_MEM_ALLOC(m_trace.line_length);
00159     }
00160 
00161     if (m_trace.tmp_data == NULL) {
00162         m_trace.tmp_data = MBED_TRACE_MEM_ALLOC(m_trace.tmp_data_length);
00163     }
00164     m_trace.tmp_data_ptr = m_trace.tmp_data;
00165 
00166     if (m_trace.filters_exclude == NULL) {
00167         m_trace.filters_exclude = MBED_TRACE_MEM_ALLOC(m_trace.filters_length);
00168     }
00169     if (m_trace.filters_include == NULL) {
00170         m_trace.filters_include = MBED_TRACE_MEM_ALLOC(m_trace.filters_length);
00171     }
00172 
00173     if (m_trace.line == NULL ||
00174             m_trace.tmp_data == NULL ||
00175             m_trace.filters_exclude == NULL  ||
00176             m_trace.filters_include == NULL) {
00177         //memory allocation fail
00178         mbed_trace_free();
00179         return -1;
00180     }
00181     memset(m_trace.tmp_data, 0, m_trace.tmp_data_length);
00182     memset(m_trace.filters_exclude, 0, m_trace.filters_length);
00183     memset(m_trace.filters_include, 0, m_trace.filters_length);
00184     memset(m_trace.line, 0, m_trace.line_length);
00185 
00186     return 0;
00187 }
00188 void mbed_trace_free(void)
00189 {
00190     // release memory
00191     MBED_TRACE_MEM_FREE(m_trace.line);
00192     MBED_TRACE_MEM_FREE(m_trace.tmp_data);
00193     MBED_TRACE_MEM_FREE(m_trace.filters_exclude);
00194     MBED_TRACE_MEM_FREE(m_trace.filters_include);
00195 
00196     // reset to default values
00197     m_trace.trace_config = DEFAULT_TRACE_CONFIG;
00198     m_trace.filters_exclude = 0;
00199     m_trace.filters_include = 0;
00200     m_trace.filters_length = DEFAULT_TRACE_FILTER_LENGTH;
00201     m_trace.line = 0;
00202     m_trace.line_length = DEFAULT_TRACE_LINE_LENGTH;
00203     m_trace.tmp_data = 0;
00204     m_trace.tmp_data_length = DEFAULT_TRACE_TMP_LINE_LEN;
00205     m_trace.prefix_f = 0;
00206     m_trace.suffix_f = 0;
00207     m_trace.printf  = mbed_trace_default_print;
00208     m_trace.cmd_printf = 0;
00209     m_trace.mutex_wait_f = 0;
00210     m_trace.mutex_release_f = 0;
00211     m_trace.mutex_lock_count = 0;
00212 }
00213 static void mbed_trace_realloc(char **buffer, int *length_ptr, int new_length)
00214 {
00215     MBED_TRACE_MEM_FREE(*buffer);
00216     *buffer  = MBED_TRACE_MEM_ALLOC(new_length);
00217     *length_ptr = new_length;
00218 }
00219 void mbed_trace_buffer_sizes(int lineLength, int tmpLength)
00220 {
00221     if (lineLength > 0) {
00222         mbed_trace_realloc(&(m_trace.line), &m_trace.line_length, lineLength);
00223     }
00224     if (tmpLength > 0) {
00225         mbed_trace_realloc(&(m_trace.tmp_data), &m_trace.tmp_data_length, tmpLength);
00226         mbed_trace_reset_tmp();
00227     }
00228 }
00229 void mbed_trace_config_set(uint8_t config)
00230 {
00231     m_trace.trace_config = config;
00232 }
00233 uint8_t mbed_trace_config_get(void)
00234 {
00235     return m_trace.trace_config;
00236 }
00237 void mbed_trace_prefix_function_set(char *(*pref_f)(size_t))
00238 {
00239     m_trace.prefix_f = pref_f;
00240 }
00241 void mbed_trace_suffix_function_set(char *(*suffix_f)(void))
00242 {
00243     m_trace.suffix_f = suffix_f;
00244 }
00245 void mbed_trace_print_function_set(void (*printf)(const char *))
00246 {
00247     m_trace.printf = printf;
00248 }
00249 void mbed_trace_cmdprint_function_set(void (*printf)(const char *))
00250 {
00251     m_trace.cmd_printf = printf;
00252 }
00253 void mbed_trace_mutex_wait_function_set(void (*mutex_wait_f)(void))
00254 {
00255     m_trace.mutex_wait_f = mutex_wait_f;
00256 }
00257 void mbed_trace_mutex_release_function_set(void (*mutex_release_f)(void))
00258 {
00259     m_trace.mutex_release_f = mutex_release_f;
00260 }
00261 void mbed_trace_exclude_filters_set(char *filters)
00262 {
00263     if (filters) {
00264         (void)strncpy(m_trace.filters_exclude, filters, m_trace.filters_length);
00265     } else {
00266         m_trace.filters_exclude[0] = 0;
00267     }
00268 }
00269 const char *mbed_trace_exclude_filters_get(void)
00270 {
00271     return m_trace.filters_exclude;
00272 }
00273 const char *mbed_trace_include_filters_get(void)
00274 {
00275     return m_trace.filters_include;
00276 }
00277 void mbed_trace_include_filters_set(char *filters)
00278 {
00279     if (filters) {
00280         (void)strncpy(m_trace.filters_include, filters, m_trace.filters_length);
00281     } else {
00282         m_trace.filters_include[0] = 0;
00283     }
00284 }
00285 static int8_t mbed_trace_skip(int8_t dlevel, const char *grp)
00286 {
00287     if (dlevel >= 0 && grp != 0) {
00288         // filter debug prints only when dlevel is >0 and grp is given
00289 
00290         /// @TODO this could be much better..
00291         if (m_trace.filters_exclude[0] != '\0' &&
00292                 strstr(m_trace.filters_exclude, grp) != 0) {
00293             //grp was in exclude list
00294             return 1;
00295         }
00296         if (m_trace.filters_include[0] != '\0' &&
00297                 strstr(m_trace.filters_include, grp) == 0) {
00298             //grp was in include list
00299             return 1;
00300         }
00301     }
00302     return 0;
00303 }
00304 static void mbed_trace_default_print(const char *str)
00305 {
00306     puts(str);
00307 }
00308 void mbed_tracef(uint8_t dlevel, const char *grp, const char *fmt, ...)
00309 {
00310     va_list ap;
00311     va_start(ap, fmt);
00312     mbed_vtracef(dlevel, grp, fmt, ap);
00313     va_end(ap);
00314 }
00315 void mbed_vtracef(uint8_t dlevel, const char *grp, const char *fmt, va_list ap)
00316 {
00317     if (m_trace.mutex_wait_f) {
00318         m_trace.mutex_wait_f();
00319         m_trace.mutex_lock_count++;
00320     }
00321 
00322     if (NULL == m_trace.line) {
00323         goto end;
00324     }
00325 
00326     m_trace.line[0] = 0; //by default trace is empty
00327 
00328     if (mbed_trace_skip(dlevel, grp) || fmt == 0 || grp == 0 || !m_trace.printf) {
00329         //return tmp data pointer back to the beginning
00330         mbed_trace_reset_tmp();
00331         goto end;
00332     }
00333     if ((m_trace.trace_config & TRACE_MASK_LEVEL) &  dlevel) {
00334         bool color = (m_trace.trace_config & TRACE_MODE_COLOR) != 0;
00335         bool plain = (m_trace.trace_config & TRACE_MODE_PLAIN) != 0;
00336         bool cr    = (m_trace.trace_config & TRACE_CARRIAGE_RETURN) != 0;
00337 
00338         int retval = 0, bLeft = m_trace.line_length;
00339         char *ptr = m_trace.line;
00340         if (plain == true || dlevel == TRACE_LEVEL_CMD) {
00341             //add trace data
00342             retval = vsnprintf(ptr, bLeft, fmt, ap);
00343             if (dlevel == TRACE_LEVEL_CMD && m_trace.cmd_printf) {
00344                 m_trace.cmd_printf(m_trace.line);
00345                 m_trace.cmd_printf("\n");
00346             } else {
00347                 //print out whole data
00348                 m_trace.printf(m_trace.line);
00349             }
00350         } else {
00351             if (color) {
00352                 if (cr) {
00353                     retval = snprintf(ptr, bLeft, "\r\x1b[2K");
00354                     if (retval >= bLeft) {
00355                         retval = 0;
00356                     }
00357                     if (retval > 0) {
00358                         ptr += retval;
00359                         bLeft -= retval;
00360                     }
00361                 }
00362                 if (bLeft > 0) {
00363                     //include color in ANSI/VT100 escape code
00364                     switch (dlevel) {
00365                         case (TRACE_LEVEL_ERROR):
00366                             retval = snprintf(ptr, bLeft, "%s", VT100_COLOR_ERROR);
00367                             break;
00368                         case (TRACE_LEVEL_WARN):
00369                             retval = snprintf(ptr, bLeft, "%s", VT100_COLOR_WARN);
00370                             break;
00371                         case (TRACE_LEVEL_INFO):
00372                             retval = snprintf(ptr, bLeft, "%s", VT100_COLOR_INFO);
00373                             break;
00374                         case (TRACE_LEVEL_DEBUG):
00375                             retval = snprintf(ptr, bLeft, "%s", VT100_COLOR_DEBUG);
00376                             break;
00377                         default:
00378                             color = 0; //avoid unneeded color-terminate code
00379                             retval = 0;
00380                             break;
00381                     }
00382                     if (retval >= bLeft) {
00383                         retval = 0;
00384                     }
00385                     if (retval > 0 && color) {
00386                         ptr += retval;
00387                         bLeft -= retval;
00388                     }
00389                 }
00390 
00391             }
00392             if (bLeft > 0 && m_trace.prefix_f) {
00393                 //find out length of body
00394                 size_t sz = 0;
00395                 va_list ap2;
00396                 va_copy(ap2, ap);
00397                 sz = vsnprintf(NULL, 0, fmt, ap2) + retval + (retval ? 4 : 0);
00398                 va_end(ap2);
00399                 //add prefix string
00400                 retval = snprintf(ptr, bLeft, "%s", m_trace.prefix_f(sz));
00401                 if (retval >= bLeft) {
00402                     retval = 0;
00403                 }
00404                 if (retval > 0) {
00405                     ptr += retval;
00406                     bLeft -= retval;
00407                 }
00408             }
00409             if (bLeft > 0) {
00410                 //add group tag
00411                 switch (dlevel) {
00412                     case (TRACE_LEVEL_ERROR):
00413                         retval = snprintf(ptr, bLeft, "[ERR ][%-4s]: ", grp);
00414                         break;
00415                     case (TRACE_LEVEL_WARN):
00416                         retval = snprintf(ptr, bLeft, "[WARN][%-4s]: ", grp);
00417                         break;
00418                     case (TRACE_LEVEL_INFO):
00419                         retval = snprintf(ptr, bLeft, "[INFO][%-4s]: ", grp);
00420                         break;
00421                     case (TRACE_LEVEL_DEBUG):
00422                         retval = snprintf(ptr, bLeft, "[DBG ][%-4s]: ", grp);
00423                         break;
00424                     default:
00425                         retval = snprintf(ptr, bLeft, "              ");
00426                         break;
00427                 }
00428                 if (retval >= bLeft) {
00429                     retval = 0;
00430                 }
00431                 if (retval > 0) {
00432                     ptr += retval;
00433                     bLeft -= retval;
00434                 }
00435             }
00436             if (retval > 0 && bLeft > 0) {
00437                 //add trace text
00438                 retval = vsnprintf(ptr, bLeft, fmt, ap);
00439                 if (retval >= bLeft) {
00440                     retval = 0;
00441                 }
00442                 if (retval > 0) {
00443                     ptr += retval;
00444                     bLeft -= retval;
00445                 }
00446             }
00447 
00448             if (retval > 0 && bLeft > 0  && m_trace.suffix_f) {
00449                 //add suffix string
00450                 retval = snprintf(ptr, bLeft, "%s", m_trace.suffix_f());
00451                 if (retval >= bLeft) {
00452                     retval = 0;
00453                 }
00454                 if (retval > 0) {
00455                     ptr += retval;
00456                     bLeft -= retval;
00457                 }
00458             }
00459 
00460             if (retval > 0 && bLeft > 0  && color) {
00461                 //add zero color VT100 when color mode
00462                 retval = snprintf(ptr, bLeft, "\x1b[0m");
00463                 if (retval >= bLeft) {
00464                     retval = 0;
00465                 }
00466                 if (retval > 0) {
00467                     // not used anymore
00468                     //ptr += retval;
00469                     //bLeft -= retval;
00470                 }
00471             }
00472             //print out whole data
00473             m_trace.printf(m_trace.line);
00474         }
00475         //return tmp data pointer back to the beginning
00476         mbed_trace_reset_tmp();
00477     }
00478 
00479 end:
00480     if (m_trace.mutex_release_f) {
00481         // Store the mutex lock count to temp variable so that it won't get
00482         // clobbered during last loop iteration when mutex gets released
00483         int count = m_trace.mutex_lock_count;
00484         m_trace.mutex_lock_count = 0;
00485         // Since the helper functions (eg. mbed_trace_array) are used like this:
00486         //   mbed_tracef(TRACE_LEVEL_INFO, "grp", "%s", mbed_trace_array(some_array))
00487         // The helper function MUST acquire the mutex if it modifies any buffers. However
00488         // it CANNOT unlock the mutex because that would allow another thread to acquire
00489         // the mutex after helper function unlocks it and before mbed_tracef acquires it
00490         // for itself. This means that here we have to unlock the mutex as many times
00491         // as it was acquired by trace function and any possible helper functions.
00492         do {
00493             m_trace.mutex_release_f();
00494         } while (--count > 0);
00495     }
00496 }
00497 static void mbed_trace_reset_tmp(void)
00498 {
00499     m_trace.tmp_data_ptr = m_trace.tmp_data;
00500 }
00501 const char *mbed_trace_last(void)
00502 {
00503     return m_trace.line;
00504 }
00505 /* Helping functions */
00506 #define tmp_data_left()  m_trace.tmp_data_length-(m_trace.tmp_data_ptr-m_trace.tmp_data)
00507 #if MBED_CONF_MBED_TRACE_FEA_IPV6 == 1
00508 char *mbed_trace_ipv6(const void *addr_ptr)
00509 {
00510     /** Acquire mutex. It is released before returning from mbed_vtracef. */
00511     if (m_trace.mutex_wait_f) {
00512         m_trace.mutex_wait_f();
00513         m_trace.mutex_lock_count++;
00514     }
00515     char *str = m_trace.tmp_data_ptr;
00516     if (str == NULL) {
00517         return "";
00518     }
00519     if (tmp_data_left() < 41) {
00520         return "";
00521     }
00522     if (addr_ptr == NULL) {
00523         return "<null>";
00524     }
00525     str[0] = 0;
00526     m_trace.tmp_data_ptr += ip6tos(addr_ptr, str) + 1;
00527     return str;
00528 }
00529 char *mbed_trace_ipv6_prefix(const uint8_t *prefix, uint8_t prefix_len)
00530 {
00531     /** Acquire mutex. It is released before returning from mbed_vtracef. */
00532     if (m_trace.mutex_wait_f) {
00533         m_trace.mutex_wait_f();
00534         m_trace.mutex_lock_count++;
00535     }
00536     char *str = m_trace.tmp_data_ptr;
00537     if (str == NULL) {
00538         return "";
00539     }
00540     if (tmp_data_left() < 45) {
00541         return "";
00542     }
00543 
00544     if ((prefix_len != 0 && prefix == NULL) || prefix_len > 128) {
00545         return "<err>";
00546     }
00547 
00548     m_trace.tmp_data_ptr += ip6_prefix_tos(prefix, prefix_len, str) + 1;
00549     return str;
00550 }
00551 #endif //MBED_CONF_MBED_TRACE_FEA_IPV6
00552 char *mbed_trace_array(const uint8_t *buf, uint16_t len)
00553 {
00554     /** Acquire mutex. It is released before returning from mbed_vtracef. */
00555     if (m_trace.mutex_wait_f) {
00556         m_trace.mutex_wait_f();
00557         m_trace.mutex_lock_count++;
00558     }
00559     int i, bLeft = tmp_data_left();
00560     char *str, *wptr;
00561     str = m_trace.tmp_data_ptr;
00562     if (len == 0 || str == NULL || bLeft == 0) {
00563         return "";
00564     }
00565     if (buf == NULL) {
00566         return "<null>";
00567     }
00568     wptr = str;
00569     wptr[0] = 0;
00570     const uint8_t *ptr = buf;
00571     char overflow = 0;
00572     for (i = 0; i < len; i++) {
00573         if (bLeft <= 3) {
00574             overflow = 1;
00575             break;
00576         }
00577         int retval = snprintf(wptr, bLeft, "%02x:", *ptr++);
00578         if (retval <= 0 || retval > bLeft) {
00579             break;
00580         }
00581         bLeft -= retval;
00582         wptr += retval;
00583     }
00584     if (wptr > str) {
00585         if (overflow) {
00586             // replace last character as 'star',
00587             // which indicate buffer len is not enough
00588             *(wptr - 1) = '*';
00589         } else {
00590             //null to replace last ':' character
00591             *(wptr - 1) = 0;
00592         }
00593     }
00594     m_trace.tmp_data_ptr = wptr;
00595     return str;
00596 }