K1Guitar/APP/app_log.c

489 lines
15 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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;
/* RTT 二进制烧录:写到 W25Q128ui0902 或本地曲目) */
static uint8_t s_flash_mode;
static uint32_t s_flash_base;
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];
static char s_flash_ok_tag[24];
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 == s_flash_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, s_flash_ok_tag);
UI_DrawModeSelectScreen();
}
}
static void app_log_flash_start_at(uint32_t base, uint32_t size, const char *go_tag, const char *ok_tag)
{
char msg[80];
if (size == 0U || size > (2U * 1024U * 1024U)) {
SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, "FLASH_ERR size\n");
return;
}
s_flash_mode = 1U;
s_flash_base = base;
s_flash_addr = base;
s_flash_remain = size;
s_flash_last_sector = 0xFFFFFFFFUL;
s_flash_page_len = 0U;
s_cmd_len = 0U;
s_cmd_buf[0] = '\0';
strncpy(s_flash_ok_tag, ok_tag, sizeof(s_flash_ok_tag) - 1U);
s_flash_ok_tag[sizeof(s_flash_ok_tag) - 1U] = '\0';
snprintf(msg, sizeof(msg),
"%s base=0x%08lX size=%lu\n",
go_tag, (unsigned long)base, (unsigned long)size);
SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, msg);
}
static void app_log_flash_start(uint32_t size)
{
app_log_flash_start_at(UI0902_RES_BASE, size, "FLASH_UI0902_GO", "FLASH_UI0902_OK\n");
}
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 haitian ", 14) == 0) {
uint32_t size = (uint32_t)strtoul(cmd + 14, NULL, 10);
app_log_flash_start_at(FLASH_ADDR_SONG_HAITIAN, size,
"FLASH_HAITIAN_GO", "FLASH_HAITIAN_OK\n");
return 1U;
}
if (strncmp(cmd, "tone status", 11) == 0) {
uint8_t hdr[16];
uint8_t name[40];
uint8_t cur_hdr[16];
char *pname;
char line[192];
const char *map;
W25Q128_Read(hdr, FLASH_ADDR_SONG_HAITIAN, 16);
W25Q128_Read(name, FLASH_ADDR_SONG_HAITIAN + 1280 + 4, 32);
name[32] = 0;
W25Q128_Read(cur_hdr, (uint32_t)ADDRESS, 16);
pname = AutoBandTop1_GetPresetName();
if (ADDRESS == EXTFLASH_BIN1_RHYTHM_ADDR)
map = "BIN1_RHYTHM";
else if (ADDRESS == EXTFLASH_BIN2_SONG_HAITIAN_ADDR)
map = "BIN2_SONG_HAITIAN";
else if (ADDRESS == EXTFLASH_BIN3_UNIVERSAL_ADDR)
map = "BIN3_UNIVERSAL";
else
map = "UNKNOWN";
snprintf(line, sizeof(line),
"TONE tab=%u sw=%u addr=0x%08lX map=%s songidx=%u rhyt=%u\n",
(unsigned)mGuiData[GUI_TAB_INDEX].Current,
(unsigned)mGuiData[GUI_AUTOBAND_SW].Current,
(unsigned long)ADDRESS, map,
(unsigned)ParamGuiData[EXPRESS_MODE_PARAM].Current,
(unsigned)ParamGuiData[SONG_MODE_PARAM].Current);
SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, line);
snprintf(line, sizeof(line),
"TONE map BIN1=0x%08lX BIN2=0x%08lX BIN3=0x%08lX\n",
(unsigned long)EXTFLASH_BIN1_RHYTHM_ADDR,
(unsigned long)EXTFLASH_BIN2_SONG_HAITIAN_ADDR,
(unsigned long)EXTFLASH_BIN3_UNIVERSAL_ADDR);
SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, line);
snprintf(line, sizeof(line),
"TONE @ADDRESS magic=%02X%02X%02X%02X cnt=%lu\n",
cur_hdr[0], cur_hdr[1], cur_hdr[2], cur_hdr[3],
(unsigned long)(cur_hdr[12] | (cur_hdr[13] << 8) |
(cur_hdr[14] << 16) | (cur_hdr[15] << 24)));
SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, line);
snprintf(line, sizeof(line),
"TONE @BIN2 magic=%02X%02X%02X%02X max=%lu cnt=%lu name=%.16s\n",
hdr[0], hdr[1], hdr[2], hdr[3],
(unsigned long)(hdr[8] | (hdr[9] << 8) | (hdr[10] << 16) | (hdr[11] << 24)),
(unsigned long)(hdr[12] | (hdr[13] << 8) | (hdr[14] << 16) | (hdr[15] << 24)),
(char *)name);
SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, line);
snprintf(line, sizeof(line),
"TONE loaded name=%s count=%d\n",
pname ? pname : "(null)",
AutoBandTop1_GetPresetItemCount());
SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, line);
return 1U;
}
if (strncmp(cmd, "tone reload", 11) == 0) {
char line[96];
UI_ReloadTonePreset();
snprintf(line, sizeof(line),
"TONE_RELOAD addr=0x%08lX name=%s\n",
(unsigned long)ADDRESS,
AutoBandTop1_GetPresetName() ? AutoBandTop1_GetPresetName() : "(null)");
SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, line);
return 1U;
}
if (strncmp(cmd, "tone local", 10) == 0) {
char line[128];
int ret;
mGuiData[GUI_TAB_INDEX].Current = 1; /* 专业 */
mGuiData[GUI_AUTOBAND_SW].Current = 1; /* 本地曲目 */
ParamGuiData[EXPRESS_MODE_PARAM].Current = 0;
UI_ApplyToneAddress();
AutoBandTop1_Stop();
StartFlag = 0;
ret = AutoBandTop1_LoadPresetItemFromFlash(0);
snprintf(line, sizeof(line),
"TONE_LOCAL ret=%d addr=0x%08lX map=BIN2@0x%08lX name=%s count=%d %s\n",
ret, (unsigned long)ADDRESS,
(unsigned long)EXTFLASH_BIN2_SONG_HAITIAN_ADDR,
AutoBandTop1_GetPresetName() ? AutoBandTop1_GetPresetName() : "(null)",
AutoBandTop1_GetPresetItemCount(),
(ADDRESS == EXTFLASH_BIN2_SONG_HAITIAN_ADDR) ? "OK" : "MISMATCH");
SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, line);
return 1U;
}
if (strncmp(cmd, "tone pick", 9) == 0) {
/* 模拟专业+本地曲目拨片(无和弦板) */
mGuiData[GUI_TAB_INDEX].Current = 1;
mGuiData[GUI_AUTOBAND_SW].Current = 1;
KEY_ID_1629 = 0; /* 走默认和弦兜底 */
StartFlag = 0;
Pick_Handle();
SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, "TONE_PICK_DONE\n");
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;
}
if (strncmp(cmd, "ui charge", 9) == 0) {
uint8_t peek[4];
LCD_BLK_Set();
LCD_FillByColor(0, 0, 240, 320, UI0902_BG_COLOR);
W25Q128_Read(peek, UI0902_CHARGE_SCREEN_ADDR, 4);
if (peek[0] != 0xFF || peek[1] != 0xFF) {
LCD_WR_PIC_FROM_FLASH(0, 0, UI0902_CHARGE_SCREEN_W, UI0902_CHARGE_SCREEN_H,
UI0902_CHARGE_SCREEN_ADDR);
SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, "UI_CHARGE_OK\n");
} else {
Draw_Charging_Icon(120, 150, 2, 0x3D7F);
SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, "UI_CHARGE_EMPTY\n");
}
{
const char *s = "50";
uint16_t tw = g_ChargePctPercent.w;
uint16_t x, y = 266;
uint8_t i;
for (i = 0; s[i]; i++)
tw = (uint16_t)(tw + g_ChargePctDigits[s[i] - '0'].w);
LCD_FillByColor(40, 262, 200, 290, UI0902_BG_COLOR);
x = (uint16_t)((240 - tw) / 2);
for (i = 0; s[i]; i++) {
const ChargePctGlyph *g = &g_ChargePctDigits[s[i] - '0'];
LCD_WR_PIC_Trans(x, y, g->w, g->h, g->data, BLACK);
x = (uint16_t)(x + g->w);
}
LCD_WR_PIC_Trans(x, y, g_ChargePctPercent.w, g_ChargePctPercent.h,
g_ChargePctPercent.data, BLACK);
}
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 */