功能:
1. 错误,警告, 信息,调试,四个等级输出, 四种颜色区别。 建议使用putty调试
2.标签独立划分等级, 每个标签可单独定义输出等级,控制输出、不输出
3.十进制/十六进制数组输出
4.自定义printf , 标准C库printf输出, 宏切换。
输出效果:
函数说明:
//tag为输出标签, 必须为静态字符或全局字符
//level 为对应标签输出等级
LOG_ADD(tag, level)
LOGE(tag, format, ...) //输出错误日志, 红色
LOGW(tag, format, ...) //输出警告日志,绿色
LOGI(tag, format, ...) //输出信息日志,黄色
LOGD(tag, format, ...) //输出调试日志,白色
//示例
LOG_ADD(TAG, _LOG_DEBUG);
LOGE(TAG, "put string, %s\n", "hello world");
LOGW(TAG, "put string, %s\n", "hello world");
LOGI(TAG, "put string, %s\n", "hello world");
LOGD(TAG, "put string, %s\n", "hello world");
//十六进制输出数组,默认为答谢
//level ,输出等级
//tag 标签
//title 描述
//buffer , 数组指针
//size 长度
LOG_ARRY_HEX(level, tag, tltle, buffer, size)
//十进制输出数组
LOG_ARRY_DEC(level, tag, tltle, buffer, size)
//示例
LOG_ARRY_HEX(_LOG_DEBUG, TAG, "test buffer", buffer, sizeof(buffer));
LOG_ARRY_DEC(_LOG_DEBUG, TAG, "test buffer", buffer, sizeof(buffer));
源码, log.c
#include "log.h"
#include <stdarg.h>
stp_tag_level_t *tag_level = NULL;
static const char log_color[][15] =
{
{0},
{"\033[0;31mE "},
{"\033[0;32mW "},
{"\033[0;33mI "},
{"\033[0;37mD "},
{0},
};
static const char log_binary[][6] =
{
{0},
{"[DEC]"},
{"[HEX]"},
{0},
};
#if (USE_PRINTF == 0)
static const char log_str_cap_num[17] = "0123456789ABCDEF";
static const char log_str_sml_num[17] = "0123456789abcdef";
void stp_put_num(const char *str_num, unsigned long num, int base)
{
if (num == 0)
{
return;
}
stp_put_num(str_num, num / base, base);
putchar(str_num[num % base]);
}
void stp_put_dec(int dec)
{
if (dec < 0)
{
putchar('-');
dec = abs(dec);
}
if (dec == 0)
{
putchar('0');
return;
}
else
{
stp_put_num(log_str_sml_num, dec, 10);
}
}
void stp_put_oct(unsigned oct)
{
if (oct == 0)
{
putchar('0');
return;
}
else
{
stp_put_num(log_str_sml_num, oct, 8);
}
}
void stp_put_hex(unsigned hex, char iscap)
{
if (hex == 0)
{
putchar('0');
return;
}
else
{
if (iscap)
{
stp_put_num(log_str_cap_num, hex, 16);
}
else
{
stp_put_num(log_str_sml_num, hex, 16);
}
}
}
void stp_put_addr(unsigned long addr)
{
putchar('0');
putchar('x');
stp_put_num(log_str_cap_num, addr, 16);
}
void stp_put_str(char *str)
{
int i = 0;
while (str[i] != '\0')
{
putchar(str[i++]);
}
}
void stp_put_float(double f)
{
int temp;
temp = (int)f;
stp_put_num(log_str_sml_num, temp, 10);
putchar('.');
f -= temp;
if (f == 0)
{
for (temp = 0; temp < 6; temp++)
{
putchar('0');
}
return;
}
else
{
temp = (int)(f * 1000000);
stp_put_num(log_str_sml_num, temp, 10);
}
}
void stp_log_print(const char *s, ...)
{
int i = 0;
va_list va_ptr;
va_start(va_ptr, s);
while (s[i] != '\0')
{
if (s[i] != '%')
{
putchar(s[i++]);
continue;
}
switch (s[++i])
{
case 'd':
stp_put_dec(va_arg(va_ptr, int));
break;
case 'o':
stp_put_oct(va_arg(va_ptr, unsigned int));
break;
case 'x':
stp_put_hex(va_arg(va_ptr, unsigned int), false);
break;
case 'X':
stp_put_hex(va_arg(va_ptr, unsigned int), true);
break;
case 'c':
putchar(va_arg(va_ptr, int));
break;
case 'p':
stp_put_addr(va_arg(va_ptr, unsigned long));
break;
case 'f':
stp_put_float(va_arg(va_ptr, double));
break;
case 's':
stp_put_str(va_arg(va_ptr, char *));
break;
default:
break;
}
i++;
}
va_end(va_ptr);
}
#endif
/*
* Tag must be a static string
*/
uint8_t stp_log_add_tag(char *tag, uint8_t level)
{
stp_tag_level_t *priv;
stp_tag_level_t *this;
if (level >= _LOG_MAX)
{
return false;
}
this = malloc(sizeof(stp_tag_level_t));
if (this != NULL)
{
this->tag = tag;
this->level = level;
this->next = NULL;
if (tag_level == NULL)
{
tag_level = this;
}
else
{
priv = tag_level;
while (priv->next != NULL)
{
priv = priv->next;
}
priv->next = this;
}
}
else
{
return false;
}
return (true);
}
stp_tag_level_t *stp_log_find_tag(const char *tag)
{
stp_tag_level_t *priv = tag_level;
while (priv != NULL)
{
if ((strlen(priv->tag) == strlen(tag)) && (strncmp(priv->tag, tag, strlen(tag)) == 0))
{
return priv;
}
priv = priv->next;
}
return NULL;
}
int stp_log_write_str(const char *s, int len)
{
int ret = 0;
while (ret != EOF && len--)
{
ret = putchar(*s++);
}
return ret;
}
/*
* log printf
*/
#if USE_PRINTF
uint8_t stp_log_write(stp_log_level_t level, const char *tag, const char *format, ...)
{
char *log_buf;
stp_tag_level_t *info_tag = NULL;
int ret;
va_list arg;
info_tag = stp_log_find_tag(tag);
if ((info_tag == NULL) || (info_tag->level < level))
{
return false;
}
if (level >= _LOG_MAX)
{
return false;
}
stp_log_write_str(log_color[level], strlen(log_color[level]));
stp_log_write_str(tag, strlen(tag));
stp_log_write_str(" : ", strlen(" : "));
/* compute the length of the formatted message */
va_start(arg, format);
ret = vsnprintf(NULL, 0, format, arg);
va_end(arg);
/* allocated an array for the formatted message */
if (ret < 0 || (log_buf = malloc(ret + 1)) == NULL)
{
stp_log_write_str(LOG_COLOR_END, strlen(LOG_COLOR_END));
return -1;
}
/* construct the formatted message */
va_start(arg, format);
ret = vsnprintf(log_buf, ret + 1, format, arg);
va_end(arg);
ret = stp_log_write_str(log_buf, ret);
stp_log_write_str(LOG_COLOR_END, strlen(LOG_COLOR_END));
free(log_buf);
return true;
}
uint8_t stp_log_write_arry(stp_log_level_t level, char *tag, char *tltle, uint8_t *buffer, int size, stp_log_binary_t binary)
{
stp_tag_level_t *info_tag = NULL;
char *log_buf = NULL;
int len = 0, ret = 0, malloc_size = 0;
info_tag = stp_log_find_tag(tag);
if ((info_tag == NULL) || (info_tag->level < level))
{
return false;
}
if ((level >= _LOG_MAX) || (binary >= _LOG_BINARY_MAX))
{
return false;
}
malloc_size = strlen(log_color[level]) + strlen(tag) + strlen(" : ") + strlen(tltle);
malloc_size += snprintf(NULL, 0, "[%d]", size);
malloc_size += 1; // ‘=’ size
malloc_size += size * 4; //buffer size
malloc_size += strlen(LOG_COLOR_END);
malloc_size += 1; //end
log_buf = malloc(malloc_size);
ret = snprintf(log_buf, malloc_size + 1, "%s%s : %s%s[%d]=", log_color[level], tag, tltle, log_binary[binary], size);
if (ret < 0)
{
goto log_arry_err;
}
while (size--)
{
len += ret;
if (binary == _LOG_BINARY_HEX)
{
ret = snprintf(log_buf + len, 4, "%02X ", *buffer++);
if (ret < 0)
{
goto log_arry_err;
}
}
else if (binary == _LOG_BINARY_DEC)
{
ret = snprintf(log_buf + len, 4, "%02d ", *buffer++);
if (ret < 0)
{
goto log_arry_err;
}
}
}
ret = snprintf(log_buf + len, 15, "%s\n", LOG_COLOR_END);
if (ret < 0)
{
return false;
}
len += ret;
stp_log_write_str(log_buf, len);
free(log_buf);
return true;
log_arry_err:
free(log_buf);
return false;
}
#else
uint8_t stp_log_write(stp_log_level_t level, const char *tag)
{
stp_tag_level_t *info_tag = NULL;
info_tag = stp_log_find_tag(tag);
if ((info_tag == NULL) || (info_tag->level < level))
{
return false;
}
if (level >= _LOG_MAX)
{
return false;
}
stp_log_write_str(log_color[level], strlen(log_color[level]));
stp_log_write_str(tag, strlen(tag));
stp_log_write_str(" : ", strlen(" : "));
return true;
}
uint8_t stp_log_write_arry(stp_log_level_t level, char *tag, char *tltle, uint8_t *buffer, int size, stp_log_binary_t binary)
{
stp_tag_level_t *info_tag = NULL;
info_tag = stp_log_find_tag(tag);
if ((info_tag == NULL) || (info_tag->level < level))
{
return false;
}
if ((level >= _LOG_MAX) || (binary >= _LOG_BINARY_MAX))
{
return false;
}
stp_log_write_str(log_color[level], strlen(log_color[level]));
stp_log_write_str(tag, strlen(tag));
stp_log_write_str(" : ", strlen(" : "));
stp_log_write_str(tltle, strlen(tltle));
stp_log_write_str(log_binary[binary], strlen(log_binary[binary]));
putchar('[');
stp_put_dec(size);
putchar(']');
putchar('=');
while (size--)
{
if (binary == _LOG_BINARY_HEX)
{
stp_put_hex(*buffer++, true);
}
else if (binary == _LOG_BINARY_DEC)
{
stp_put_dec(*buffer++);
}
putchar(' ');
}
stp_log_write_str(LOG_COLOR_END, strlen(LOG_COLOR_END));
putchar('\n');
return true;
}
#endif
log.h
#ifndef __LOG_H__
#define __LOG_H__
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <stddef.h>
/*
*Whether to use the standard C language library, 0 is not used, 1 is used
*/
#define USE_PRINTF (0)
typedef enum
{
_LOG_NONE = 0,
_LOG_ERROR,
_LOG_WARN,
_LOG_INFO,
_LOG_DEBUG,
_LOG_MAX
} stp_log_level_t;
typedef enum
{
_LOG_BINARY_NONE = 0,
_LOG_BINARY_DEC,
_LOG_BINARY_HEX,
_LOG_BINARY_MAX
} stp_log_binary_t;
typedef struct
{
char *tag;
uint8_t level;
void *next;
} stp_tag_level_t;
#define LOG_COLOR_HEAD "\033[0;%dm"
#define LOG_COLOR_E "\033[0;31m"
#define LOG_COLOR_W "\033[0;32m"
#define LOG_COLOR_I "\033[0;33m"
#define LOG_COLOR_D "\033[0;37m"
#define LOG_COLOR_END "\033[0;39m"
uint8_t stp_log_add_tag(char *tag, uint8_t level);
uint8_t stp_log_write_arry(stp_log_level_t level, char *tag, char *tltle, uint8_t *buffer, int size, stp_log_binary_t binary);
#define LOG_ADD(tag, level) stp_log_add_tag(tag, level)
#if USE_PRINTF
uint8_t stp_log_write(stp_log_level_t level, const char *tag, const char *fmt, ...);
#define LOGE(tag, format, ...) stp_log_write(_LOG_ERROR, tag, format, ##__VA_ARGS__)
#define LOGW(tag, format, ...) stp_log_write(_LOG_WARN, tag, format, ##__VA_ARGS__)
#define LOGI(tag, format, ...) stp_log_write(_LOG_INFO, tag, format, ##__VA_ARGS__)
#define LOGD(tag, format, ...) stp_log_write(_LOG_DEBUG, tag, format, ##__VA_ARGS__)
#else
uint8_t stp_log_write(stp_log_level_t level, const char *tag);
int stp_log_write_str(const char *s, int len);
void stp_log_print(const char *s, ...);
#define LOGE(tag, format, ...) \
do \
{ \
if (stp_log_write(_LOG_ERROR, tag) == false) \
{ \
break; \
} \
stp_log_print(format, ##__VA_ARGS__); \
stp_log_write_str(LOG_COLOR_END, strlen(LOG_COLOR_END)); \
} while (0)
#define LOGW(tag, format, ...) \
do \
{ \
if (stp_log_write(_LOG_WARN, tag) == false) \
{ \
break; \
} \
stp_log_print(format, ##__VA_ARGS__); \
stp_log_write_str(LOG_COLOR_END, strlen(LOG_COLOR_END)); \
} while (0)
#define LOGI(tag, format, ...) \
do \
{ \
if (stp_log_write(_LOG_INFO, tag) == false) \
{ \
break; \
} \
stp_log_print(format, ##__VA_ARGS__); \
stp_log_write_str(LOG_COLOR_END, strlen(LOG_COLOR_END)); \
} while (0)
#define LOGD(tag, format, ...) \
do \
{ \
if (stp_log_write(_LOG_DEBUG, tag) == false) \
{ \
break; \
} \
stp_log_print(format, ##__VA_ARGS__); \
stp_log_write_str(LOG_COLOR_END, strlen(LOG_COLOR_END)); \
} while (0)
#endif
#define LOG_ARRY_HEX(level, tag, tltle, buffer, size) \
do \
{ \
stp_log_write_arry(level, tag, tltle, buffer, size, _LOG_BINARY_HEX); \
} while (0)
#define LOG_ARRY_DEC(level, tag, tltle, buffer, size) \
do \
{ \
stp_log_write_arry(level, tag, tltle, buffer, size, _LOG_BINARY_DEC); \
} while (0)
#endif /*end of file*/
工程文件,Github: https://github.com/KarmaStone/stp_coms.git
后续此工程文件会陆续添加其他功能, 比如:基于Freertos的 串口命令(类似shell) , MQTT , protocol buffer, http , mebdTLS(AES, RSA ,MD5, BASE64) , simcom800 , w5500 , BC28 等
下片: 基于串口的调试 , 串口命令解析cmd 类似uboot命令输入