• 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 
app_log_output(uint8_t level,const char * tag,const char * file,const char * func,const long line,const char * format,...)244 void app_log_output(uint8_t level, const char *tag, const char *file, const char *func, const long line,
245                     const char *format, ...)
246 {
247     uint16_t log_length     = 0;
248     uint8_t  newline_length = strlen(APP_LOG_NEWLINE_SIGN);
249     int      fmt_result     = 0;
250     char     line_num[APP_LOG_LINE_NB_LEN_MAX + 1]  = { 0 };
251     va_list  ap;
252 
253     if (level > s_app_log_env.app_log_init.filter.level && s_app_log_env.is_filter_set) {
254         return;
255     }
256 
257 #if APP_LOG_TAG_ENABLE
258     if (!strstr(tag, s_app_log_env.app_log_init.filter.tag)) {
259         return;
260     }
261 #endif
262 
263     va_start(ap, format);
264 
265     APP_LOG_LOCK();
266 
267 #if APP_LOG_COLOR_ENABLE
268     // Encode CSI start sign and color info.
269     log_length += app_log_strcpy(log_length, s_log_encode_buf, CSI_START);
270     log_length += app_log_strcpy(log_length, s_log_encode_buf, s_log_color_output_info[level]);
271 #endif
272 
273     // Encode level info.
274     if (app_log_is_fmt_set(level, APP_LOG_FMT_LVL)) {
275         log_length += app_log_strcpy(log_length, s_log_encode_buf, s_log_svt_lvl_output_info[level]);
276     }
277 
278 #if APP_LOG_TAG_ENABLE
279     // Encode tag info.
280     if (app_log_is_fmt_set(level, APP_LOG_FMT_TAG)) {
281         log_length += app_log_strcpy(log_length, s_log_encode_buf, tag);
282         log_length += app_log_strcpy(log_length, s_log_encode_buf, " ");
283     }
284 #endif
285 
286     // Encode file directory name , function name and lune number info.
287     if (app_log_is_fmt_set(level, APP_LOG_FMT_DIR | APP_LOG_FMT_FUNC | APP_LOG_FMT_LINE)) {
288         log_length += app_log_strcpy(log_length, s_log_encode_buf, "(");
289 
290         if (app_log_is_fmt_set(level, APP_LOG_FMT_DIR)) {
291             log_length += app_log_strcpy(log_length, s_log_encode_buf, file);
292 
293             if (app_log_is_fmt_set(level, APP_LOG_FMT_FUNC)) {
294                 log_length += app_log_strcpy(log_length, s_log_encode_buf, " ");
295             } else if (app_log_is_fmt_set(level, APP_LOG_FMT_LINE)) {
296                 log_length += app_log_strcpy(log_length, s_log_encode_buf, ":");
297             }
298         }
299 
300         if (app_log_is_fmt_set(level, APP_LOG_FMT_FUNC)) {
301             log_length += app_log_strcpy(log_length, s_log_encode_buf, func);
302 
303             if (app_log_is_fmt_set(level, APP_LOG_FMT_LINE)) {
304                 log_length += app_log_strcpy(log_length, s_log_encode_buf, " Line:");
305             }
306         }
307 
308         if (app_log_is_fmt_set(level, APP_LOG_FMT_LINE)) {
309             snprintf_s(line_num, sizeof (line_num), APP_LOG_LINE_NB_LEN_MAX, "%ld", line);
310             log_length += app_log_strcpy(log_length, s_log_encode_buf, line_num);
311         }
312 
313         log_length += app_log_strcpy(log_length, s_log_encode_buf, ") ");
314     }
315 
316     // Encode other log data to buffer. '\0' must be added in the end by vsnprintf. */
317     fmt_result = vsnprintf_s((char *)s_log_encode_buf + log_length, sizeof (s_log_encode_buf),
318                              APP_LOG_LINE_BUF_SIZE - log_length, format, ap);
319 
320     va_end(ap);
321 
322     //  Calculate log length
323     if ((fmt_result > -1) && (log_length + fmt_result) <= APP_LOG_LINE_BUF_SIZE) {
324         log_length += fmt_result;
325     } else {
326         log_length = APP_LOG_LINE_BUF_SIZE;
327     }
328 
329 #if APP_LOG_COLOR_ENABLE
330     if (log_length + (sizeof(CSI_END) - 1) + newline_length > APP_LOG_LINE_BUF_SIZE) {
331         log_length  = APP_LOG_LINE_BUF_SIZE;
332         // Reserve some space for CSI end sign.
333         log_length -= sizeof(CSI_END) - 1;
334 #else
335     if (log_length + newline_length > APP_LOG_LINE_BUF_SIZE) {
336         log_length = APP_LOG_LINE_BUF_SIZE;
337 #endif
338         log_length -= newline_length;
339     }
340 
341 #if APP_LOG_COLOR_ENABLE
342     // Encode CSI end sign.
343     log_length += app_log_strcpy(log_length, s_log_encode_buf, CSI_END);
344 #endif
345 
346     // Encode newline sign.
347     log_length += app_log_strcpy(log_length, s_log_encode_buf, APP_LOG_NEWLINE_SIGN);
348 
349     app_log_data_trans(s_log_encode_buf, log_length);
350 
351     APP_LOG_UNLOCK();
352 }
353 
354 void app_log_raw_info(const char *format, ...)
355 {
356     int      fmt_result = 0;
357     uint16_t log_length = 0;
358     va_list  ap;
359 
360     va_start(ap, format);
361 
362     APP_LOG_LOCK();
363 
364     fmt_result = vsnprintf_s((char *)s_log_encode_buf, sizeof(s_log_encode_buf), APP_LOG_LINE_BUF_SIZE, format, ap);
365     if ((fmt_result > -1) && (fmt_result) <= APP_LOG_LINE_BUF_SIZE) {
366         log_length = fmt_result;
367     } else {
368         log_length = APP_LOG_LINE_BUF_SIZE;
369     }
370 
371     app_log_data_trans(s_log_encode_buf, log_length);
372 
373     APP_LOG_UNLOCK();
374 }
375 
376 void app_log_hex_dump(uint8_t *p_data, uint16_t length)
377 {
378     uint16_t log_length  = 0;
379     uint16_t convert_idx = 0;
380     char     dump_str[8] = {0};
381 
382     APP_LOG_LOCK();
383 
384     for (convert_idx = 0; convert_idx < length; convert_idx++) {
385         if (log_length >= APP_LOG_LINE_BUF_SIZE) {
386             log_length = APP_LOG_LINE_BUF_SIZE;
387             break;
388         }
389 
390         if (p_data[convert_idx] < ' ') {
391             s_log_encode_buf[log_length] = '.';
392             log_length++;
393         } else {
394             snprintf_s(dump_str, sizeof (dump_str), BIT_8, "%02X ", p_data[convert_idx]);
395             log_length += app_log_strcpy(log_length, s_log_encode_buf, dump_str);
396         }
397     }
398 
399     app_log_data_trans(s_log_encode_buf, log_length);
400 
401     APP_LOG_UNLOCK();
402 }
403 
404 void app_log_flush(void)
405 {
406     if (s_app_log_env.flush_func) {
407         s_app_log_env.flush_func();
408     }
409 }
410 
411 #if IO_REDIRECT == 0
412 #if defined(__CC_ARM)
413 
414 struct __FILE {
415     int handle;
416 };
417 
418 FILE s_stdout;
419 FILE s_stdin;
420 
421 int fputc(int ch, FILE *file)
422 {
423     app_log_data_trans((uint8_t *)&ch, 1);
424 
425     return 1;
426 }
427 
428 #elif defined(__GNUC__)
429 
430 int _write(int file, const char *buf, int len)
431 {
432     int tx_len = 0;
433     char *temp_buf = buf;
434 
435     while (tx_len < len) {
436         app_log_data_trans((uint8_t *)buf, 1);
437         temp_buf++;
438         tx_len++;
439     }
440     return tx_len;
441 }
442 
443 #elif defined(__ICCARM__)
444 
445 size_t s_write(int handle, const unsigned char *buf, size_t size)
446 {
447     size_t len = 0;
448     unsigned char* temp_buf = buf;
449 
450     while (len < size) {
451         app_log_data_trans((uint8_t *)buf, 1);
452         temp_buf++;
453         len++;
454     }
455     return len;
456 }
457 
458 #endif /* defined(__CC_ARM) */
459 #endif
460 
461