208 lines
5.1 KiB
C
208 lines
5.1 KiB
C
#include "includes.h"
|
|
#include "SEGGER_RTT.h"
|
|
#include <stdarg.h>
|
|
|
|
#if APP_LOG_ENABLE
|
|
|
|
static char s_slots[APP_LOG_SLOT_COUNT][APP_LOG_SLOT_SIZE];
|
|
static uint16_t s_head;
|
|
static uint16_t s_count;
|
|
static uint32_t s_overflow;
|
|
static uint32_t s_boot_count;
|
|
static char s_ui_page[16] = "boot";
|
|
static char s_debug_level = 'D';
|
|
static char s_cmd_buf[48];
|
|
static uint8_t s_cmd_len;
|
|
|
|
static uint32_t app_log_ms(void)
|
|
{
|
|
return (uint32_t)(rt_tick_get() * 1000U / RT_TICK_PER_SECOND);
|
|
}
|
|
|
|
static void app_log_slot_store(const char *line)
|
|
{
|
|
uint16_t idx = s_head;
|
|
|
|
strncpy(s_slots[idx], line, APP_LOG_SLOT_SIZE - 1U);
|
|
s_slots[idx][APP_LOG_SLOT_SIZE - 1U] = '\0';
|
|
s_head = (uint16_t)((s_head + 1U) % APP_LOG_SLOT_COUNT);
|
|
if (s_count < APP_LOG_SLOT_COUNT) {
|
|
s_count++;
|
|
} else {
|
|
s_overflow++;
|
|
}
|
|
}
|
|
|
|
void app_log_set_ui_page(const char *name)
|
|
{
|
|
if (name == NULL) {
|
|
return;
|
|
}
|
|
strncpy(s_ui_page, name, sizeof(s_ui_page) - 1U);
|
|
s_ui_page[sizeof(s_ui_page) - 1U] = '\0';
|
|
}
|
|
|
|
void app_log_write(char level, const char *cat, const char *fmt, ...)
|
|
{
|
|
char line[APP_LOG_SLOT_SIZE];
|
|
va_list ap;
|
|
int n;
|
|
|
|
if (level == 'D' && s_debug_level != 'D') {
|
|
return;
|
|
}
|
|
|
|
n = snprintf(line, sizeof(line), "[%05u][%c][%-4s] ",
|
|
(unsigned)app_log_ms(), level, cat);
|
|
if (n < 0) {
|
|
return;
|
|
}
|
|
if ((size_t)n >= sizeof(line)) {
|
|
n = (int)sizeof(line) - 1;
|
|
}
|
|
|
|
va_start(ap, fmt);
|
|
vsnprintf(line + n, sizeof(line) - (size_t)n, fmt, ap);
|
|
va_end(ap);
|
|
|
|
app_log_slot_store(line);
|
|
SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, line);
|
|
SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, "\n");
|
|
}
|
|
|
|
static void app_log_dump_ram(void)
|
|
{
|
|
uint16_t start;
|
|
uint16_t i;
|
|
|
|
SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, "LOG_DUMP_BEGIN\n");
|
|
{
|
|
char meta[APP_LOG_SLOT_SIZE];
|
|
snprintf(meta, sizeof(meta),
|
|
"meta boot=%u lines=%u overflow=%u ui=%s",
|
|
(unsigned)s_boot_count,
|
|
(unsigned)s_count,
|
|
(unsigned)s_overflow,
|
|
s_ui_page);
|
|
SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, meta);
|
|
SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, "\n");
|
|
}
|
|
|
|
if (s_count == 0U) {
|
|
SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, "LOG_DUMP_END\n");
|
|
return;
|
|
}
|
|
|
|
start = (s_count < APP_LOG_SLOT_COUNT)
|
|
? 0U
|
|
: s_head;
|
|
for (i = 0; i < s_count; i++) {
|
|
uint16_t idx = (uint16_t)((start + i) % APP_LOG_SLOT_COUNT);
|
|
SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, s_slots[idx]);
|
|
SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, "\n");
|
|
}
|
|
SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, "LOG_DUMP_END\n");
|
|
}
|
|
|
|
static void app_log_clear_ram(void)
|
|
{
|
|
s_head = 0U;
|
|
s_count = 0U;
|
|
s_overflow = 0U;
|
|
memset(s_slots, 0, sizeof(s_slots));
|
|
LOG_I("LOG", "ram cleared");
|
|
}
|
|
|
|
static void app_log_print_status(void)
|
|
{
|
|
char line[APP_LOG_SLOT_SIZE];
|
|
|
|
snprintf(line, sizeof(line),
|
|
"LOG_STATUS boot=%u lines=%u overflow=%u level=%c ui=%s tick=%u",
|
|
(unsigned)s_boot_count,
|
|
(unsigned)s_count,
|
|
(unsigned)s_overflow,
|
|
s_debug_level,
|
|
s_ui_page,
|
|
(unsigned)app_log_ms());
|
|
SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, line);
|
|
SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, "\n");
|
|
}
|
|
|
|
uint8_t app_log_try_command(const char *cmd)
|
|
{
|
|
if (cmd == NULL || cmd[0] == '\0') {
|
|
return 0U;
|
|
}
|
|
|
|
if (strncmp(cmd, "log dump", 8) == 0) {
|
|
app_log_dump_ram();
|
|
return 1U;
|
|
}
|
|
if (strncmp(cmd, "log clear", 9) == 0) {
|
|
app_log_clear_ram();
|
|
return 1U;
|
|
}
|
|
if (strncmp(cmd, "log status", 10) == 0) {
|
|
app_log_print_status();
|
|
return 1U;
|
|
}
|
|
if (strncmp(cmd, "log level ", 10) == 0 && cmd[10] != '\0') {
|
|
s_debug_level = cmd[10];
|
|
LOG_I("LOG", "level set %c", s_debug_level);
|
|
return 1U;
|
|
}
|
|
return 0U;
|
|
}
|
|
|
|
static void app_log_feed_char(char c)
|
|
{
|
|
if (c == '\r' || c == '\n' || c == '\0') {
|
|
if (s_cmd_len > 0U) {
|
|
s_cmd_buf[s_cmd_len] = '\0';
|
|
(void)app_log_try_command(s_cmd_buf);
|
|
}
|
|
s_cmd_len = 0U;
|
|
s_cmd_buf[0] = '\0';
|
|
return;
|
|
}
|
|
|
|
if (s_cmd_len + 1U >= sizeof(s_cmd_buf)) {
|
|
s_cmd_len = 0U;
|
|
}
|
|
s_cmd_buf[s_cmd_len++] = c;
|
|
s_cmd_buf[s_cmd_len] = '\0';
|
|
}
|
|
|
|
void app_log_poll(void)
|
|
{
|
|
char rx[16];
|
|
unsigned read_len;
|
|
unsigned i;
|
|
|
|
read_len = SEGGER_RTT_Read(APP_LOG_RTT_CHANNEL, rx, sizeof(rx));
|
|
if (read_len == 0U) {
|
|
return;
|
|
}
|
|
|
|
for (i = 0; i < read_len; i++) {
|
|
app_log_feed_char(rx[i]);
|
|
}
|
|
}
|
|
|
|
void app_log_init(void)
|
|
{
|
|
s_boot_count++;
|
|
LOG_I("BOOT", "app_log init boot=%u", (unsigned)s_boot_count);
|
|
}
|
|
|
|
#else
|
|
|
|
void app_log_init(void) {}
|
|
void app_log_write(char level, const char *cat, const char *fmt, ...) { (void)level; (void)cat; (void)fmt; }
|
|
void app_log_poll(void) {}
|
|
uint8_t app_log_try_command(const char *cmd) { (void)cmd; return 0U; }
|
|
void app_log_set_ui_page(const char *name) { (void)name; }
|
|
|
|
#endif /* APP_LOG_ENABLE */
|