193 lines
3.8 KiB
C
193 lines
3.8 KiB
C
#include "mx_log.h"
|
|
|
|
#include <stdio.h>
|
|
|
|
#if MX_LOG_BACKEND_RTT
|
|
#include "SEGGER_RTT.h"
|
|
#endif
|
|
|
|
#ifndef MX_LOG_LINE_BUF_SIZE
|
|
#define MX_LOG_LINE_BUF_SIZE 256U
|
|
#endif
|
|
|
|
#ifndef MX_LOG_DEFAULT_LEVEL
|
|
#define MX_LOG_DEFAULT_LEVEL MX_LOG_LEVEL_DEBUG
|
|
#endif
|
|
|
|
static volatile mx_log_level_t s_log_level = MX_LOG_DEFAULT_LEVEL;
|
|
static mx_log_writer_t s_log_writer = 0;
|
|
static uint8_t s_log_inited = 0U;
|
|
|
|
static const char *mx_log_level_to_str(mx_log_level_t level)
|
|
{
|
|
switch (level) {
|
|
case MX_LOG_LEVEL_ERROR:
|
|
return "E";
|
|
case MX_LOG_LEVEL_WARN:
|
|
return "W";
|
|
case MX_LOG_LEVEL_INFO:
|
|
return "I";
|
|
case MX_LOG_LEVEL_DEBUG:
|
|
default:
|
|
return "D";
|
|
}
|
|
}
|
|
|
|
static size_t mx_log_strnlen(const char *s, size_t maxlen)
|
|
{
|
|
size_t len = 0U;
|
|
if (s == 0) {
|
|
return 0U;
|
|
}
|
|
while ((len < maxlen) && (s[len] != '\0')) {
|
|
len++;
|
|
}
|
|
return len;
|
|
}
|
|
|
|
static void mx_log_output_line(const char *line)
|
|
{
|
|
if (line == 0) {
|
|
return;
|
|
}
|
|
|
|
if (s_log_writer != 0) {
|
|
s_log_writer(line);
|
|
return;
|
|
}
|
|
|
|
#if MX_LOG_BACKEND_RTT
|
|
SEGGER_RTT_WriteString(0, line);
|
|
#elif MX_LOG_BACKEND_STDIO
|
|
(void)fputs(line, stdout);
|
|
#else
|
|
(void)line;
|
|
#endif
|
|
}
|
|
|
|
void mx_log_init(void)
|
|
{
|
|
if (s_log_inited) {
|
|
return;
|
|
}
|
|
|
|
#if MX_LOG_BACKEND_RTT
|
|
SEGGER_RTT_Init();
|
|
SEGGER_RTT_SetTerminal(0);
|
|
#endif
|
|
|
|
s_log_inited = 1U;
|
|
}
|
|
|
|
void mx_log_set_level(mx_log_level_t level)
|
|
{
|
|
s_log_level = level;
|
|
}
|
|
|
|
mx_log_level_t mx_log_get_level(void)
|
|
{
|
|
return s_log_level;
|
|
}
|
|
|
|
void mx_log_set_writer(mx_log_writer_t writer)
|
|
{
|
|
s_log_writer = writer;
|
|
}
|
|
|
|
void mx_log_vprintf(mx_log_level_t level, const char *tag, const char *fmt, va_list ap)
|
|
{
|
|
char line[MX_LOG_LINE_BUF_SIZE];
|
|
int prefix_len;
|
|
int payload_len;
|
|
size_t line_len;
|
|
|
|
if ((fmt == 0) || (level > s_log_level)) {
|
|
return;
|
|
}
|
|
|
|
if (!MX_LOG_ENABLE) {
|
|
return;
|
|
}
|
|
|
|
if (!s_log_inited) {
|
|
mx_log_init();
|
|
}
|
|
|
|
prefix_len = snprintf(line,
|
|
sizeof(line),
|
|
"[%s][%s] ",
|
|
mx_log_level_to_str(level),
|
|
(tag != 0) ? tag : "");
|
|
if (prefix_len < 0) {
|
|
return;
|
|
}
|
|
if ((size_t)prefix_len >= sizeof(line)) {
|
|
line[sizeof(line) - 1U] = '\0';
|
|
mx_log_output_line(line);
|
|
return;
|
|
}
|
|
|
|
payload_len = vsnprintf(line + prefix_len, sizeof(line) - (size_t)prefix_len, fmt, ap);
|
|
(void)payload_len;
|
|
|
|
line_len = mx_log_strnlen(line, sizeof(line));
|
|
if ((line_len + 2U) < sizeof(line)) {
|
|
line[line_len++] = '\r';
|
|
line[line_len++] = '\n';
|
|
line[line_len] = '\0';
|
|
} else {
|
|
line[sizeof(line) - 1U] = '\0';
|
|
}
|
|
|
|
mx_log_output_line(line);
|
|
}
|
|
|
|
void mx_log_printf(mx_log_level_t level, const char *tag, const char *fmt, ...)
|
|
{
|
|
va_list ap;
|
|
va_start(ap, fmt);
|
|
mx_log_vprintf(level, tag, fmt, ap);
|
|
va_end(ap);
|
|
}
|
|
|
|
void mx_log_hex_frame(const char *tag, const uint8_t *data, uint16_t len)
|
|
{
|
|
static const char hex[] = "0123456789ABCDEF";
|
|
char line[(32U * 3U) + 1U];
|
|
uint16_t i = 0U;
|
|
|
|
if ((data == 0) || (len == 0U)) {
|
|
return;
|
|
}
|
|
|
|
while (i < len) {
|
|
uint16_t chunk = (uint16_t)(len - i);
|
|
uint16_t pos = 0U;
|
|
uint16_t j;
|
|
|
|
if (chunk > 32U) {
|
|
chunk = 32U;
|
|
}
|
|
|
|
for (j = 0U; j < chunk; j++) {
|
|
uint8_t v = data[(uint16_t)(i + j)];
|
|
line[pos++] = hex[(v >> 4) & 0x0FU];
|
|
line[pos++] = hex[v & 0x0FU];
|
|
line[pos++] = ' ';
|
|
}
|
|
|
|
if (pos > 0U) {
|
|
line[pos - 1U] = '\0';
|
|
} else {
|
|
line[0] = '\0';
|
|
}
|
|
|
|
MX_LOGD((tag != 0) ? tag : "HEX", "%s", line);
|
|
i = (uint16_t)(i + chunk);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|