365 lines
9.9 KiB
C
365 lines
9.9 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;
|
||
|
||
/* 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;
|
||
}
|
||
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");
|
||
}
|
||
LCD_FillByColor(40, 255, 200, 292, UI0902_BG_COLOR);
|
||
LCD_ShowString_AutoAlign(0, 240, 264, (uint8_t *)"50%", LCD_ALIGN_CENTER,
|
||
WHITE, UI0902_BG_COLOR, 0, 24);
|
||
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 */
|