#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; /* RTT 二进制烧录:将 ui0902_res.bin 写到 W25Q128 @ UI0902_RES_BASE */ static uint8_t s_flash_mode; static uint32_t s_flash_addr; static uint32_t s_flash_remain; static uint32_t s_flash_last_sector; static uint16_t s_flash_page_len; static uint8_t s_flash_page[256]; uint8_t app_log_flash_busy(void) { return s_flash_mode; } static uint32_t app_log_ms(void) { return (uint32_t)(rt_tick_get() * 1000U / RT_TICK_PER_SECOND); } static void app_log_flash_flush_page(void) { uint32_t sector; char ack[40]; if (s_flash_page_len == 0U) { return; } sector = s_flash_addr & ~0xFFFU; if (sector != s_flash_last_sector) { W25Q128_Erase_Sector(sector); s_flash_last_sector = sector; } W25Q128_Write(s_flash_page, s_flash_addr, s_flash_page_len); s_flash_addr += s_flash_page_len; s_flash_remain -= s_flash_page_len; s_flash_page_len = 0U; /* 每页 ACK,避免主机打爆 RTT 下行缓冲 */ snprintf(ack, sizeof(ack), "FLASH_ACK %lu\n", (unsigned long)s_flash_addr); SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, ack); } static void app_log_flash_feed(const uint8_t *data, unsigned len) { unsigned i; for (i = 0; i < len && s_flash_remain > 0U; i++) { if (s_flash_page_len == 0U && s_flash_addr == UI0902_RES_BASE && i == 0U) { SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, "FLASH_RX\n"); } s_flash_page[s_flash_page_len++] = data[i]; if (s_flash_page_len >= sizeof(s_flash_page) || s_flash_page_len >= s_flash_remain) { app_log_flash_flush_page(); } } if (s_flash_remain == 0U && s_flash_mode) { s_flash_mode = 0U; SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, "FLASH_UI0902_OK\n"); UI_DrawModeSelectScreen(); } } static void app_log_flash_start(uint32_t size) { char msg[64]; if (size == 0U || size > (2U * 1024U * 1024U)) { SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, "FLASH_UI0902_ERR size\n"); return; } s_flash_mode = 1U; s_flash_addr = UI0902_RES_BASE; s_flash_remain = size; s_flash_last_sector = 0xFFFFFFFFUL; s_flash_page_len = 0U; s_cmd_len = 0U; s_cmd_buf[0] = '\0'; snprintf(msg, sizeof(msg), "FLASH_UI0902_GO base=0x%08lX size=%lu\n", (unsigned long)UI0902_RES_BASE, (unsigned long)size); SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, msg); } 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"); } static void app_log_sys_reset(void) { LOG_I("SYS", "reset via RTT"); SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, "SYS_RESET_OK\n"); rt_thread_mdelay(20); __disable_irq(); nvic_system_reset(); } 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; } if (strncmp(cmd, "tp status", 9) == 0) { TP_LogStatus(); return 1U; } if (strncmp(cmd, "tp live off", 11) == 0) { TP_SetLiveMode(0); return 1U; } if (strncmp(cmd, "tp live", 7) == 0) { TP_SetLiveMode(1); return 1U; } if (strncmp(cmd, "sys reset", 9) == 0) { app_log_sys_reset(); return 1U; } if (strncmp(cmd, "flash ui0902 ", 13) == 0) { uint32_t size = (uint32_t)strtoul(cmd + 13, NULL, 10); app_log_flash_start(size); return 1U; } if (strncmp(cmd, "flash erase chip", 16) == 0) { SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, "FLASH_ERASE_BEGIN\n"); LOG_I("FLASH", "W25Q128 chip erase start"); W25Q128_Erase_Chip(); LOG_I("FLASH", "W25Q128 chip erase done"); SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, "FLASH_ERASE_OK\n"); return 1U; } if (strncmp(cmd, "ui boot", 7) == 0) { LCD_BLK_Set(); LCD_WR_PIC_FROM_FLASH(0, 0, UI0902_BOOT_LOGO_W, UI0902_BOOT_LOGO_H, UI0902_BOOT_LOGO_ADDR); SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, "UI_BOOT_OK\n"); 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'; if (strstr(s_cmd_buf, "sys reset") != NULL) { s_cmd_len = 0U; s_cmd_buf[0] = '\0'; (void)app_log_try_command("sys reset"); } } void app_log_poll(void) { uint8_t rx[64]; unsigned read_len; unsigned i; read_len = SEGGER_RTT_Read(APP_LOG_RTT_CHANNEL, rx, sizeof(rx)); if (read_len == 0U) { return; } if (s_flash_mode) { app_log_flash_feed(rx, read_len); return; } for (i = 0; i < read_len; i++) { app_log_feed_char((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; } uint8_t app_log_flash_busy(void) { return 0U; } #endif /* APP_LOG_ENABLE */