#include "includes.h" #include "SEGGER_RTT.h" #include #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 */