• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  *****************************************************************************************
3  *
4  * @file app_log.c
5  *
6  * @brief App Log Implementation.
7  *
8  *****************************************************************************************
9  * @attention
10   #####Copyright (c) 2019 GOODIX
11   All rights reserved.
12 
13     Redistribution and use in source and binary forms, with or without
14     modification, are permitted provided that the following conditions are met:
15   * Redistributions of source code must retain the above copyright
16     notice, this list of conditions and the following disclaimer.
17   * Redistributions in binary form must reproduce the above copyright
18     notice, this list of conditions and the following disclaimer in the
19     documentation and/or other materials provided with the distribution.
20   * Neither the name of GOODIX nor the names of its contributors may be used
21     to endorse or promote products derived from this software without
22     specific prior written permission.
23 
24   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
25   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27   ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
28   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
32   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34   POSSIBILITY OF SUCH DAMAGE.
35  *****************************************************************************************
36  */
37 
38 /*
39  * INCLUDE FILES
40  *****************************************************************************************
41  */
42 #include <string.h>
43 #include <stdarg.h>
44 #include <stdio.h>
45 #include "app_log.h"
46 
47 /*
48  * DEFINE
49  *****************************************************************************************
50  */
51 #if APP_LOG_COLOR_ENABLE
52 /**@brief CSI(Control Sequence Introducer/Initiator) sign more information on
53   * https://en.wikipedia.org/wiki/ANSI_escape_code. */
54 #define CSI_START                      "\033["
55 #define CSI_END                        "\033[0m"
56 
57 /**@brief Output log front color */
58 #define F_BLACK                        "30;"
59 #define F_RED                          "31;"
60 #define F_GREEN                        "32;"
61 #define F_YELLOW                       "33;"
62 #define F_BLUE                         "34;"
63 #define F_MAGENTA                      "35;"
64 #define F_CYAN                         "36;"
65 #define F_WHITE                        "37;"
66 
67 /**@brief Output log background color */
68 #define B_NULL
69 #define B_BLACK                        "40;"
70 #define B_RED                          "41;"
71 #define B_GREEN                        "42;"
72 #define B_YELLOW                       "43;"
73 #define B_BLUE                         "44;"
74 #define B_MAGENTA                      "45;"
75 #define B_CYAN                         "46;"
76 #define B_WHITE                        "47;"
77 
78 /**@brief Output log fonts style */
79 #define S_BOLD                         "1m"
80 #define S_UNDERLINE                    "4m"
81 #define S_BLINK                        "5m"
82 #define S_NORMAL                       "22m"
83 
84 /**@brief Output log default color definition: [front color] + [background color] + [show style] */
85 #ifndef APP_LOG_COLOR_ERROR
86 #define APP_LOG_COLOR_ERROR               (F_YELLOW B_NULL S_NORMAL)
87 #endif
88 
89 #ifndef APP_LOG_COLOR_WARNING
90 #define APP_LOG_COLOR_WARNING             (F_CYAN B_NULL S_NORMAL)
91 #endif
92 
93 #ifndef APP_LOG_COLOR_INFO
94 #define APP_LOG_COLOR_INFO                (F_GREEN B_NULL S_NORMAL)
95 #endif
96 
97 #ifndef APP_LOG_COLOR_DEBUG
98 #define APP_LOG_COLOR_DEBUG               (F_WHITE B_NULL S_NORMAL)
99 #endif
100 
101 #endif
102 
103 #define BIT_8                           8
104 
105 /*
106  * STRUCTURES
107  *****************************************************************************************
108  */
109 /**@brief App log environment variable. */
110 struct app_log_env_t {
111     app_log_init_t       app_log_init;  /**< App log initialization variables. */
112     bool                 is_filter_set; /**< App log filter is set or not. */
113     app_log_trans_func_t trans_func;    /**< App log transmit function. */
114     app_log_flush_func_t flush_func;    /**< App log flush function. */
115 };
116 
117 /*
118  * LOCAL VARIABLE DEFINITIONS
119  *****************************************************************************************
120  */
121 static uint8_t     s_log_encode_buf[APP_LOG_LINE_BUF_SIZE];  /**< App log data encode buffer. */
122 
123 static const char *s_log_svt_lvl_output_info[] = {           /**< App log severity level outpout information. */
124     [APP_LOG_LVL_ERROR]   = "APP_E: ",
125     [APP_LOG_LVL_WARNING] = "APP_W: ",
126     [APP_LOG_LVL_INFO]    = "APP_I: ",
127     [APP_LOG_LVL_DEBUG]   = "APP_D: ",
128 };
129 
130 #if APP_LOG_COLOR_ENABLE
131 static const char *s_log_color_output_info[] = {            /**< App log level outpout color information. */
132     [APP_LOG_LVL_ERROR]   = APP_LOG_COLOR_ERROR,
133     [APP_LOG_LVL_WARNING] = APP_LOG_COLOR_WARNING,
134     [APP_LOG_LVL_INFO]    = APP_LOG_COLOR_INFO,
135     [APP_LOG_LVL_DEBUG]   = APP_LOG_COLOR_DEBUG,
136 };
137 #endif
138 
139 static struct app_log_env_t  s_app_log_env;                  /**< App log environment variable. */
140 
141 
142 /*
143  * LOCAL FUNCTION DEFINITIONS
144  *****************************************************************************************
145  */
146 /**
147  *****************************************************************************************
148  * @brief App log string copy.
149  *
150  * @param[in] wr_idx:     Write index of app log buffer.
151  * @param[in] p_log_buff: Pointer to app log cache buffer.
152  * @param[in] p_log_data: Pointer to app log data.
153  *
154  * @return Length of copy.
155  *****************************************************************************************
156  */
app_log_strcpy(uint16_t wr_idx,uint8_t * p_log_buff,const char * p_log_data)157 static uint16_t app_log_strcpy(uint16_t wr_idx, uint8_t *p_log_buff, const char *p_log_data)
158 {
159     uint16_t cpy_length = 0;
160     char *temp_p_log_data = p_log_data;
161 
162     if (!p_log_buff || !temp_p_log_data) {
163         return cpy_length;
164     }
165 
166     while (*temp_p_log_data != 0) {
167         if ((wr_idx + cpy_length) < APP_LOG_LINE_BUF_SIZE) {
168             p_log_buff[wr_idx + cpy_length] = *temp_p_log_data++;
169             cpy_length++;
170         } else {
171             break;
172         }
173     }
174 
175     return cpy_length;
176 }
177 
178 /**
179  *****************************************************************************************
180  * @brief Check app log format is set or not.
181  *
182  * @param[in] level: App log level.
183  * @param[in] fmt:   Format.
184  *
185  * @return Result of check.
186  *****************************************************************************************
187  */
app_log_is_fmt_set(uint8_t level,uint8_t fmt)188 static bool app_log_is_fmt_set(uint8_t level, uint8_t fmt)
189 {
190     if (s_app_log_env.app_log_init.fmt_set[level] & fmt) {
191         return true;
192     } else {
193         return false;
194     }
195 }
196 
197 /**
198  *****************************************************************************************
199  * @brief Transmit app log data.
200  *
201  * @param[in] p_data: Pointer to log data.
202  * @param[in] length: Length of log data.
203  *
204  * @return Result of check.
205  *****************************************************************************************
206  */
app_log_data_trans(uint8_t * p_data,uint16_t length)207 static void app_log_data_trans(uint8_t *p_data, uint16_t length)
208 {
209     if (p_data == NULL || length == 0) {
210         return;
211     }
212 
213     if (s_app_log_env.trans_func) {
214         s_app_log_env.trans_func(p_data, length);
215     }
216 
217 #if APP_LOG_STORE_ENABLE
218     app_log_store_save(p_data, length);
219 #endif
220 }
221 
222 /*
223  * GLOBAL FUNCTION DEFINITIONS
224  *****************************************************************************************
225  */
app_log_init(app_log_init_t * p_log_init,app_log_trans_func_t trans_func,app_log_flush_func_t flush_func)226 sdk_err_t app_log_init(app_log_init_t *p_log_init, app_log_trans_func_t trans_func, app_log_flush_func_t flush_func)
227 {
228     if (NULL == p_log_init) {
229         s_app_log_env.is_filter_set = false;
230         memset_s(&s_app_log_env.app_log_init, sizeof (s_app_log_env.app_log_init), 0, sizeof(app_log_init_t));
231     } else if (p_log_init->filter.level <= APP_LOG_LVL_DEBUG) {
232         s_app_log_env.is_filter_set = true;
233         memset_s(&s_app_log_env.app_log_init, sizeof (s_app_log_env.app_log_init), p_log_init, sizeof(app_log_init_t));
234     } else {
235         return SDK_ERR_INVALID_PARAM;
236     }
237 
238     s_app_log_env.trans_func    = trans_func;
239     s_app_log_env.flush_func    = flush_func;
240 
241     return SDK_SUCCESS;
242 }
243 
encode_name(uint8_t level,const char * file,const char * func,const long line)244 uint16_t encode_name(uint8_t level, const char *file, const char *func, const long line)
245 {
246     uint16_t log_length = 0;
247     char     line_num[APP_LOG_LINE_NB_LEN_MAX + 1]  = { 0 };
248 
249     // Encode file directory name , function name and lune number info.
250     if (app_log_is_fmt_set(level, APP_LOG_FMT_DIR | APP_LOG_FMT_FUNC | APP_LOG_FMT_LINE)) {
251         log_length += app_log_strcpy(log_length, s_log_encode_buf, "(");
252 
253         if (app_log_is_fmt_set(level, APP_LOG_FMT_DIR)) {
254             log_length += app_log_strcpy(log_length, s_log_encode_buf, file);
255 
256             if (app_log_is_fmt_set(level, APP_LOG_FMT_FUNC)) {
257                 log_length += app_log_strcpy(log_length, s_log_encode_buf, " ");
258             } else if (app_log_is_fmt_set(level, APP_LOG_FMT_LINE)) {
259                 log_length += app_log_strcpy(log_length, s_log_encode_buf, ":");
260             }
261         }
262 
263         if (app_log_is_fmt_set(level, APP_LOG_FMT_FUNC)) {
264             log_length += app_log_strcpy(log_length, s_log_encode_buf, func);
265 
266             if (app_log_is_fmt_set(level, APP_LOG_FMT_LINE)) {
267                 log_length += app_log_strcpy(log_length, s_log_encode_buf, " Line:");
268             }
269         }
270 
271         if (app_log_is_fmt_set(level, APP_LOG_FMT_LINE)) {
272             snprintf_s(line_num, sizeof (line_num), APP_LOG_LINE_NB_LEN_MAX, "%ld", line);
273             log_length += app_log_strcpy(log_length, s_log_encode_buf, line_num);
274         }
275 
276         log_length += app_log_strcpy(log_length, s_log_encode_buf, ") ");
277     }
278     return log_length;
279 }
280 
calculate_log_length(uint16_t log_length,int fmt_result)281 uint16_t calculate_log_length(uint16_t log_length, int fmt_result)
282 {
283     uint8_t  newline_length = strlen(APP_LOG_NEWLINE_SIGN);
284     uint16_t log_len     = log_length;
285     //  Calculate log length
286     if ((fmt_result > -1) && (log_len + fmt_result) <= APP_LOG_LINE_BUF_SIZE) {
287         log_len += fmt_result;
288     } else {
289         log_len = APP_LOG_LINE_BUF_SIZE;
290     }
291 
292 #if APP_LOG_COLOR_ENABLE
293     if (log_len + (sizeof(CSI_END) - 1) + newline_length > APP_LOG_LINE_BUF_SIZE) {
294         log_len  = APP_LOG_LINE_BUF_SIZE;
295         // Reserve some space for CSI end sign.
296         log_len -= sizeof(CSI_END) - 1;
297 #else
298     if (log_len + newline_length > APP_LOG_LINE_BUF_SIZE) {
299         log_len = APP_LOG_LINE_BUF_SIZE;
300 #endif
301         log_len -= newline_length;
302     }
303 
304 #if APP_LOG_COLOR_ENABLE
305     // Encode CSI end sign.
306     log_len += app_log_strcpy(log_len, s_log_encode_buf, CSI_END);
307 #endif
308 
309     // Encode newline sign.
310     log_len += app_log_strcpy(log_len, s_log_encode_buf, APP_LOG_NEWLINE_SIGN);
311     return log_len;
312 }
313 
314 void app_log_output(uint8_t level, const char *tag, const char *file, const char *func, const long line,
315                     const char *format, ...)
316 {
317     uint16_t log_length     = 0;
318     int      fmt_result     = 0;
319     va_list  ap;
320 
321     if (level > s_app_log_env.app_log_init.filter.level && s_app_log_env.is_filter_set) {
322         return;
323     }
324 #if APP_LOG_TAG_ENABLE
325     if (!strstr(tag, s_app_log_env.app_log_init.filter.tag)) {
326         return;
327     }
328 #endif
329     va_start(ap, format);
330     APP_LOG_LOCK();
331 
332 #if APP_LOG_COLOR_ENABLE
333     // Encode CSI start sign and color info.
334     log_length += app_log_strcpy(log_length, s_log_encode_buf, CSI_START);
335     log_length += app_log_strcpy(log_length, s_log_encode_buf, s_log_color_output_info[level]);
336 #endif
337 
338     // Encode level info.
339     if (app_log_is_fmt_set(level, APP_LOG_FMT_LVL)) {
340         log_length += app_log_strcpy(log_length, s_log_encode_buf, s_log_svt_lvl_output_info[level]);
341     }
342 
343 #if APP_LOG_TAG_ENABLE
344     // Encode tag info.
345     if (app_log_is_fmt_set(level, APP_LOG_FMT_TAG)) {
346         log_length += app_log_strcpy(log_length, s_log_encode_buf, tag);
347         log_length += app_log_strcpy(log_length, s_log_encode_buf, " ");
348     }
349 #endif
350     log_length = encode_name(level, file, func, line);
351     // Encode other log data to buffer. '\0' must be added in the end by vsnprintf. */
352     fmt_result = vsnprintf_s((char *)s_log_encode_buf + log_length, sizeof (s_log_encode_buf),
353                              APP_LOG_LINE_BUF_SIZE - log_length, format, ap);
354 
355     va_end(ap);
356     log_length = calculate_log_length(log_length, fmt_result);
357     app_log_data_trans(s_log_encode_buf, log_length);
358     APP_LOG_UNLOCK();
359 }
360 
361 void app_log_raw_info(const char *format, ...)
362 {
363     int      fmt_result = 0;
364     uint16_t log_length = 0;
365     va_list  ap;
366 
367     va_start(ap, format);
368 
369     APP_LOG_LOCK();
370 
371     fmt_result = vsnprintf_s((char *)s_log_encode_buf, sizeof(s_log_encode_buf), APP_LOG_LINE_BUF_SIZE, format, ap);
372     if ((fmt_result > -1) && (fmt_result) <= APP_LOG_LINE_BUF_SIZE) {
373         log_length = fmt_result;
374     } else {
375         log_length = APP_LOG_LINE_BUF_SIZE;
376     }
377 
378     app_log_data_trans(s_log_encode_buf, log_length);
379 
380     APP_LOG_UNLOCK();
381 }
382 
383 void app_log_hex_dump(uint8_t *p_data, uint16_t length)
384 {
385     uint16_t log_length  = 0;
386     uint16_t convert_idx = 0;
387     char     dump_str[8] = {0};
388 
389     APP_LOG_LOCK();
390 
391     for (convert_idx = 0; convert_idx < length; convert_idx++) {
392         if (log_length >= APP_LOG_LINE_BUF_SIZE) {
393             log_length = APP_LOG_LINE_BUF_SIZE;
394             break;
395         }
396 
397         if (p_data[convert_idx] < ' ') {
398             s_log_encode_buf[log_length] = '.';
399             log_length++;
400         } else {
401             snprintf_s(dump_str, sizeof (dump_str), BIT_8, "%02X ", p_data[convert_idx]);
402             log_length += app_log_strcpy(log_length, s_log_encode_buf, dump_str);
403         }
404     }
405 
406     app_log_data_trans(s_log_encode_buf, log_length);
407 
408     APP_LOG_UNLOCK();
409 }
410 
411 void app_log_flush(void)
412 {
413     if (s_app_log_env.flush_func) {
414         s_app_log_env.flush_func();
415     }
416 }
417 
418 #if IO_REDIRECT == 0
419 #if defined(__CC_ARM)
420 
421 struct __FILE {
422     int handle;
423 };
424 
425 FILE s_stdout;
426 FILE s_stdin;
427 
428 int fputc(int ch, FILE *file)
429 {
430     app_log_data_trans((uint8_t *)&ch, 1);
431 
432     return 1;
433 }
434 
435 #elif defined(__GNUC__)
436 
437 int _write(int file, const char *buf, int len)
438 {
439     int tx_len = 0;
440     char *temp_buf = buf;
441 
442     while (tx_len < len) {
443         app_log_data_trans((uint8_t *)buf, 1);
444         temp_buf++;
445         tx_len++;
446     }
447     return tx_len;
448 }
449 
450 #elif defined(__ICCARM__)
451 
452 size_t s_write(int handle, const unsigned char *buf, size_t size)
453 {
454     size_t len = 0;
455     unsigned char* temp_buf = buf;
456 
457     while (len < size) {
458         app_log_data_trans((uint8_t *)buf, 1);
459         temp_buf++;
460         len++;
461     }
462     return len;
463 }
464 
465 #endif /* defined(__CC_ARM) */
466 #endif
467 
468