运行/自检记录与待机屏:sys_log定长64B日志引擎(/log/*.log,FTP可直下)+记录页x2+待机屏+密码错误提示;字体122字/217字形
This commit is contained in:
@@ -53,6 +53,7 @@ include_directories(
|
||||
${NET_DIR} # net_socket.h / net_types.h(net_* API 双端共享核心)
|
||||
${NETCFG_DIR} # net_cfg.h(网络配置,双端共享核心)
|
||||
${PROJECT_ROOT}/App # cfg_file.h / cfg_file_store.h(通用配置文件引擎,双端共享核心)
|
||||
${PROJECT_ROOT}/App/log # sys_log.h(运行/自检记录引擎,双端共享核心)
|
||||
${PROJECT_ROOT}/Drivers/BSP # dbg_log.h(使用 simulator 的 dbg_cfg.h 配置)
|
||||
${SDL2_DIR}/include # SDL2 头文件
|
||||
)
|
||||
@@ -82,11 +83,19 @@ set(UI_SOURCES
|
||||
${UI_DIR}/ui_page_dc.c
|
||||
${UI_DIR}/ui_page_password.c
|
||||
${UI_DIR}/ui_page_net_cfg.c
|
||||
${UI_DIR}/ui_page_runlog.c
|
||||
${UI_DIR}/ui_page_selftest.c
|
||||
${UI_DIR}/ui_standby.c
|
||||
${UI_DIR}/ui_menu_tab.c
|
||||
${UI_DIR}/ui_font_cn_12.c
|
||||
${UI_DIR}/ui_net_sink.c
|
||||
)
|
||||
|
||||
# 运行/自检记录引擎(双端共享核心 + 平台存储后端;MCU 端编 sys_log_mcu.c,见 Keil 工程)
|
||||
set(SYSLOG_SOURCES
|
||||
sim/sim_syslog.c
|
||||
)
|
||||
|
||||
# 网络配置(双端共享核心 + cfg_file 引擎 + 平台存储后端;MCU 端编 cfg_file_store_mcu.c,见 Keil 工程)
|
||||
set(NETCFG_SOURCES
|
||||
${NETCFG_DIR}/net_cfg.c
|
||||
@@ -104,7 +113,7 @@ set(NET_SOURCES
|
||||
#=============================================================================
|
||||
# 构建可执行文件
|
||||
#=============================================================================
|
||||
add_executable(lvgl_sim WIN32 ${SIM_SOURCES} ${UI_SOURCES} ${NETCFG_SOURCES} ${NET_SOURCES})
|
||||
add_executable(lvgl_sim WIN32 ${SIM_SOURCES} ${UI_SOURCES} ${NETCFG_SOURCES} ${SYSLOG_SOURCES} ${NET_SOURCES})
|
||||
|
||||
target_compile_definitions(lvgl_sim PRIVATE
|
||||
LV_CONF_INCLUDE_SIMPLE # 让 lvgl.h 找到 lv_conf.h
|
||||
|
||||
+1
-1
@@ -258,7 +258,7 @@ UI 改动的自动化门禁脚本(完整流程见 `docs/UI 设计/UI_自动化
|
||||
- `LV_USE_THEME_MONO = 1` 且 `sim_port_init` 中调用了 `lv_theme_mono_init`
|
||||
- 主循环调用了 `lv_refr_now(NULL)`(PARTIAL 模式保证首帧)
|
||||
- 没有重复设置 tick(SDL 驱动内部已 `lv_tick_set_cb`,**不要**再 `SDL_AddTimer` + `lv_tick_inc`)
|
||||
4. **中文显示空白**:字体 `ui_font_cn_12` 是子集字体(当前 111 汉字/符号 + ASCII,共 208 字形),缺字渲染为空白。
|
||||
4. **中文显示空白**:字体 `ui_font_cn_12` 是子集字体(当前 122 汉字/符号 + ASCII,共 217 字形),缺字渲染为空白。
|
||||
补字流程见 `docs/UI 设计/UI_中文字体生成与配置.md`(`tools/font_gen/` 两步脚本)。
|
||||
5. **改了 UI 代码但模拟器没变化**:确认改的是 `Drivers/BSP/UI/ui_menu.c`(共享原件)而非本目录副本(本目录无副本),然后重新 `cmake --build`。
|
||||
6. **编码**:UI 源码为 UTF-8(带 BOM),MSVC 已加 `/utf-8`。**不要**用 PowerShell `Set-Content` 等重写含中文的文件(编码铁律,见根目录 `AGENTS.md`)。
|
||||
|
||||
+166
-4
@@ -23,11 +23,22 @@
|
||||
* 验证链:net_cfg_load(含旧档迁移)→ poll 建基线 → 伪造外部编辑
|
||||
* (原子写新文档,等价 FTP 上传/文本编辑器)→ poll 两次(4s 沉降)
|
||||
* → 断言 RAM 副本已按新文件重载
|
||||
*
|
||||
* 日志引擎自检模式(无窗口、进程内闭环、退出码 0=PASS / 非0=FAIL):
|
||||
* lvgl_sim.exe --logtest
|
||||
* 验证链:post N 条 → count/get 回读断言 + 宿主文件字节级校验
|
||||
* (64B 定长、ISO 时间戳、epoch 字段、NUL 填充)
|
||||
*
|
||||
* 待机屏截图模式(无窗口,强制进入待机后截图):
|
||||
* lvgl_sim.exe --standby shot.bin
|
||||
*
|
||||
* 窗口模式空闲超时覆盖:lvgl_sim.exe --idle <秒>(默认 60s)
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <Windows.h>
|
||||
@@ -42,10 +53,12 @@
|
||||
#include "lvgl.h"
|
||||
#include "sim_port.h"
|
||||
#include "ui_menu.h"
|
||||
#include "ui_standby.h"
|
||||
#include "ui_net_sink.h"
|
||||
#include "net_cfg.h"
|
||||
#include "cfg_file.h"
|
||||
#include "cfg_file_store.h"
|
||||
#include "sys_log.h"
|
||||
|
||||
/* 屏幕尺寸(与 MCU 端一致) */
|
||||
#define SIM_SCREEN_W 160
|
||||
@@ -90,13 +103,32 @@ static uint32_t sim_map_key_char(char c)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief 待机屏底部时钟提供回调(平台差异:模拟器 = 宿主 time())
|
||||
*/
|
||||
static void sim_time_cb(char *buf, size_t len)
|
||||
{
|
||||
time_t t = time(NULL);
|
||||
struct tm tmv;
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
localtime_s(&tmv, &t);
|
||||
#else
|
||||
localtime_r(&t, &tmv);
|
||||
#endif
|
||||
(void)snprintf(buf, len, "%04d-%02d-%02d %02d:%02d:%02d",
|
||||
tmv.tm_year + 1900, tmv.tm_mon + 1, tmv.tm_mday,
|
||||
tmv.tm_hour, tmv.tm_min, tmv.tm_sec);
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief 无窗口离屏渲染(可注入键序列)并导出末帧像素
|
||||
* @param keys 键序列(u=上 d=下 l=左 r=右 e=确认 s=返回;空 = 不注键)
|
||||
* @param path 输出文件(写入 160x160 I1 原始像素)
|
||||
* @param standby 非 0 = 注键后强制进入待机屏再截图(--standby 模式)
|
||||
* @return 0 成功,非 0 失败
|
||||
*/
|
||||
static int run_headless(const char * keys, const char * path)
|
||||
static int run_headless(const char * keys, const char * path, int standby)
|
||||
{
|
||||
setvbuf(stdout, NULL, _IONBF, 0);
|
||||
lv_init();
|
||||
@@ -133,6 +165,10 @@ static int run_headless(const char * keys, const char * path)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* 待机模块(无头模式不驱动 lv_timer_handler,空闲定时器不会触发;
|
||||
* --standby 经 force_enter 测试钩子直接切入) */
|
||||
(void)ui_standby_init(60000u, sim_time_cb);
|
||||
|
||||
/* 键注入:与 keypad 输入设备同路径(向焦点对象发 LV_EVENT_KEY)。
|
||||
* 键处理是同步的(状态变更 + 场景更新当场完成),无需驱动帧;
|
||||
* 无头模式严禁调 lv_timer_handler()/lv_refr_now()——I1+FULL 全屏刷新会进渲染死循环 */
|
||||
@@ -144,6 +180,11 @@ static int run_headless(const char * keys, const char * path)
|
||||
lv_group_send_data(g, key);
|
||||
}
|
||||
|
||||
/* --standby:注键后强制进入待机屏(截图前) */
|
||||
if (standby != 0) {
|
||||
ui_standby_force_enter();
|
||||
}
|
||||
|
||||
/* 注键后 LVGL 池占用(无头模式;内存回归用,对照 ui_menu_init 基线) */
|
||||
lv_mem_monitor_t mon;
|
||||
lv_mem_monitor(&mon);
|
||||
@@ -259,22 +300,136 @@ static int run_cfgtest(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief 日志引擎自检(无窗口、进程内闭环)
|
||||
* @note 验证链:清理旧档 → post N 条 → count/get 回读断言 + 宿主文件字节级校验
|
||||
* (64B 定长、ISO 时间戳格式、epoch 字段 ≈ now、NUL 填充)
|
||||
* @return 0 PASS,非 0 FAIL
|
||||
*/
|
||||
static int run_logtest(void)
|
||||
{
|
||||
uint32_t ep;
|
||||
char ts[SYSLOG_TS_LEN + 1u];
|
||||
char desc[SYSLOG_DESC_MAX + 1u];
|
||||
|
||||
setvbuf(stdout, NULL, _IONBF, 0);
|
||||
|
||||
/* 确定性起点:清理旧档 */
|
||||
(void)remove("sim_run.log");
|
||||
(void)remove("sim_selftest.log");
|
||||
|
||||
syslog_post(SYSLOG_RUN, "装置上电记录");
|
||||
syslog_post(SYSLOG_SELFTEST, "时钟芯片异常");
|
||||
syslog_post(SYSLOG_SELFTEST, "NAND异常");
|
||||
|
||||
if (syslog_count(SYSLOG_RUN) != 1u) {
|
||||
printf("[logtest] FAIL run count = %u (expect 1)\n", (unsigned)syslog_count(SYSLOG_RUN));
|
||||
return 1;
|
||||
}
|
||||
if (syslog_count(SYSLOG_SELFTEST) != 2u) {
|
||||
printf("[logtest] FAIL selftest count = %u (expect 2)\n", (unsigned)syslog_count(SYSLOG_SELFTEST));
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* 回读断言:时间戳格式 + 描述内容 */
|
||||
if (syslog_get_record(SYSLOG_RUN, 0u, ts, sizeof(ts), desc, sizeof(desc)) != 0) {
|
||||
printf("[logtest] FAIL get_record(run, 0)\n");
|
||||
return 1;
|
||||
}
|
||||
if (strlen(ts) != SYSLOG_TS_LEN || ts[4] != '-' || ts[7] != '-' || ts[10] != ' ') {
|
||||
printf("[logtest] FAIL ts format = \"%s\"\n", ts);
|
||||
return 1;
|
||||
}
|
||||
if (strcmp(desc, "装置上电记录") != 0) {
|
||||
printf("[logtest] FAIL desc = \"%s\"\n", desc);
|
||||
return 1;
|
||||
}
|
||||
if (syslog_get_record(SYSLOG_SELFTEST, 1u, ts, sizeof(ts), desc, sizeof(desc)) != 0) {
|
||||
printf("[logtest] FAIL get_record(selftest, 1)\n");
|
||||
return 1;
|
||||
}
|
||||
if (strcmp(desc, "NAND异常") != 0) {
|
||||
printf("[logtest] FAIL desc[1] = \"%s\"\n", desc);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* epoch 字段 ≈ now(±5s) */
|
||||
if (syslog_last_epoch(SYSLOG_RUN, &ep) != 0) {
|
||||
printf("[logtest] FAIL last_epoch(run)\n");
|
||||
return 1;
|
||||
}
|
||||
if ((uint32_t)abs((int)(ep - (uint32_t)time(NULL))) > 5u) {
|
||||
printf("[logtest] FAIL epoch = %u (now = %lu)\n", (unsigned)ep, (unsigned long)time(NULL));
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* 宿主文件字节级校验:64B 定长 + 字段布局 + NUL 填充 */
|
||||
{
|
||||
FILE *fp = fopen("sim_run.log", "rb");
|
||||
uint8_t rec[SYSLOG_REC_SIZE];
|
||||
|
||||
if (fp == NULL) {
|
||||
printf("[logtest] FAIL open sim_run.log\n");
|
||||
return 1;
|
||||
}
|
||||
if (fread(rec, 1u, sizeof(rec), fp) != sizeof(rec)) {
|
||||
fclose(fp);
|
||||
printf("[logtest] FAIL record size != %u\n", (unsigned)SYSLOG_REC_SIZE);
|
||||
return 1;
|
||||
}
|
||||
fclose(fp);
|
||||
|
||||
if (rec[SYSLOG_TS_LEN] != ' ' || rec[SYSLOG_DESC_OFFS - 1u] != ' ') {
|
||||
printf("[logtest] FAIL field separators at [%u]/[%u]\n",
|
||||
(unsigned)SYSLOG_TS_LEN, (unsigned)(SYSLOG_DESC_OFFS - 1u));
|
||||
return 1;
|
||||
}
|
||||
for (uint32_t i = SYSLOG_DESC_OFFS + strlen("装置上电记录"); i < SYSLOG_REC_SIZE; i++) {
|
||||
if (rec[i] != '\0') {
|
||||
printf("[logtest] FAIL NUL padding at [%u]\n", (unsigned)i);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
printf("[logtest] OK count/get/epoch/bytes\n");
|
||||
printf("[logtest] PASS\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 程序入口
|
||||
*/
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
/* 截图模式:lvgl_sim.exe --screenshot <path> */
|
||||
/* 截图/自检模式:--screenshot / --keys / --standby / --cfgtest / --logtest */
|
||||
for (int i = 1; i < argc; i++) {
|
||||
if (strcmp(argv[i], "--screenshot") == 0 && (i + 1) < argc) {
|
||||
return run_headless("", argv[i + 1]);
|
||||
return run_headless("", argv[i + 1], 0);
|
||||
}
|
||||
if (strcmp(argv[i], "--keys") == 0 && (i + 2) < argc) {
|
||||
return run_headless(argv[i + 1], argv[i + 2]);
|
||||
return run_headless(argv[i + 1], argv[i + 2], 0);
|
||||
}
|
||||
if (strcmp(argv[i], "--standby") == 0 && (i + 1) < argc) {
|
||||
return run_headless("", argv[i + 1], 1);
|
||||
}
|
||||
if (strcmp(argv[i], "--cfgtest") == 0) {
|
||||
return run_cfgtest();
|
||||
}
|
||||
if (strcmp(argv[i], "--logtest") == 0) {
|
||||
return run_logtest();
|
||||
}
|
||||
}
|
||||
|
||||
/* 窗口模式空闲超时覆盖(--idle <秒>,默认 60) */
|
||||
uint32_t idle_s = 60u;
|
||||
for (int i = 1; i < argc; i++) {
|
||||
if (strcmp(argv[i], "--idle") == 0 && (i + 1) < argc) {
|
||||
int v = atoi(argv[i + 1]);
|
||||
if (v > 0) {
|
||||
idle_s = (uint32_t)v;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 初始化 Winsock(供 ui_net_sink 使用) */
|
||||
@@ -315,6 +470,13 @@ int main(int argc, char **argv)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* 待机显示页(空闲超时 --idle <秒>,默认 60s;ENTER 返回) */
|
||||
if (ui_standby_init(idle_s * 1000u, sim_time_cb) != 0) {
|
||||
fprintf(stderr, "ui_standby_init failed\n");
|
||||
} else {
|
||||
printf("Standby: ready (idle=%us)\n", (unsigned)idle_s);
|
||||
}
|
||||
|
||||
/* 启动 RemoDispBus TCP 监听(端口 7003,与 MCU 端一致) */
|
||||
if (ui_net_sink_start(7003) == 0) {
|
||||
printf("RemoDispBus server listening on port 7003\n");
|
||||
|
||||
@@ -0,0 +1,204 @@
|
||||
/*
|
||||
* 模块名称:System Log (模拟器后端) — 运行/自检记录落盘
|
||||
* 模块功能:宿主文件 sim_run.log / sim_selftest.log(工作目录),与 MCU 端同格式
|
||||
* (定长 64B 记录);单线程直写,无队列
|
||||
* 适用平台:PC 模拟器
|
||||
* 作者:王建锋
|
||||
* 创建日期:2026-09-14
|
||||
* 修改记录:
|
||||
* v1.0 2026-09-14 王建锋 创建初始版本(设计见 docs/运行与自检记录设计说明.md §4)
|
||||
*/
|
||||
|
||||
/* 头文件包含区 */
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "sys_log.h"
|
||||
|
||||
/* 静态变量定义区 */
|
||||
|
||||
static const char s_paths[SYSLOG_COUNT][16] = { "sim_run.log", "sim_selftest.log" };
|
||||
static const uint32_t s_caps[SYSLOG_COUNT] = { SYSLOG_RUN_MAX, SYSLOG_SELFTEST_MAX };
|
||||
|
||||
/* 函数定义区 */
|
||||
|
||||
/*
|
||||
* 函数功能:取当前宿主本地时间(ISO 8601 空格变体 + epoch)
|
||||
* 入口参数:p_ts - 输出缓冲(≥SYSLOG_TS_LEN+1 字节,不可为 NULL) char *
|
||||
* p_epoch- 输出 epoch 秒(不可为 NULL) uint32_t *
|
||||
* 返回值:无
|
||||
*/
|
||||
static void s_now(char *p_ts, uint32_t *p_epoch) {
|
||||
time_t t = time(NULL);
|
||||
struct tm tmv;
|
||||
|
||||
#if defined(_WIN32)
|
||||
localtime_s(&tmv, &t);
|
||||
#else
|
||||
localtime_r(&t, &tmv);
|
||||
#endif
|
||||
(void)sprintf(p_ts, "%04d-%02d-%02d %02d:%02d:%02d",
|
||||
tmv.tm_year + 1900, tmv.tm_mon + 1, tmv.tm_mday,
|
||||
tmv.tm_hour, tmv.tm_min, tmv.tm_sec);
|
||||
*p_epoch = (uint32_t)t;
|
||||
}
|
||||
|
||||
/*
|
||||
* 函数功能:追加一条记录(格式化 64B;容量满先删除重建)
|
||||
* 入口参数:id - 日志 ID syslog_id_t
|
||||
* desc - 描述串(UTF-8,超长截断至 SYSLOG_DESC_MAX) const char *
|
||||
* 返回值:0 - 成功;-1 - 写失败 int
|
||||
*/
|
||||
static int s_append(syslog_id_t id, const char *desc) {
|
||||
FILE *fp;
|
||||
uint8_t rec[SYSLOG_REC_SIZE];
|
||||
char ts[SYSLOG_TS_LEN + 1u];
|
||||
uint32_t epoch = 0u;
|
||||
size_t dl;
|
||||
|
||||
if ((uint32_t)id >= (uint32_t)SYSLOG_COUNT || desc == NULL) {
|
||||
return -1;
|
||||
}
|
||||
if (syslog_count(id) >= s_caps[id]) {
|
||||
(void)remove(s_paths[id]);
|
||||
}
|
||||
memset(rec, 0u, sizeof(rec));
|
||||
s_now(ts, &epoch);
|
||||
memcpy(rec, ts, SYSLOG_TS_LEN);
|
||||
rec[SYSLOG_TS_LEN] = ' ';
|
||||
(void)sprintf((char *)(rec + SYSLOG_EPOCH_OFFS), "%010u", (unsigned int)epoch);
|
||||
rec[SYSLOG_DESC_OFFS - 1u] = ' ';
|
||||
dl = strlen(desc);
|
||||
if (dl > SYSLOG_DESC_MAX) {
|
||||
dl = SYSLOG_DESC_MAX;
|
||||
}
|
||||
memcpy(rec + SYSLOG_DESC_OFFS, desc, dl);
|
||||
|
||||
fp = fopen(s_paths[id], "ab");
|
||||
if (fp == NULL) {
|
||||
return -1;
|
||||
}
|
||||
if (fwrite(rec, 1u, sizeof(rec), fp) != sizeof(rec)) {
|
||||
(void)fclose(fp);
|
||||
return -1;
|
||||
}
|
||||
(void)fclose(fp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* 函数功能:读取第 idx 条原始记录(64B)
|
||||
* 入口参数:id - 日志 ID syslog_id_t
|
||||
* idx - 记录序号(0 起) uint32_t
|
||||
* p_rec- 输出缓冲(SYSLOG_REC_SIZE 字节,不可为 NULL) uint8_t *
|
||||
* 返回值:0 - 成功;-1 - 越界/读失败 int
|
||||
*/
|
||||
static int s_read_raw(syslog_id_t id, uint32_t idx, uint8_t *p_rec) {
|
||||
FILE *fp;
|
||||
|
||||
if (p_rec == NULL || idx >= syslog_count(id)) {
|
||||
return -1;
|
||||
}
|
||||
fp = fopen(s_paths[id], "rb");
|
||||
if (fp == NULL) {
|
||||
return -1;
|
||||
}
|
||||
if (fseek(fp, (long)idx * SYSLOG_REC_SIZE, SEEK_SET) != 0 ||
|
||||
fread(p_rec, 1u, sizeof(uint8_t) * SYSLOG_REC_SIZE, fp) != SYSLOG_REC_SIZE) {
|
||||
(void)fclose(fp);
|
||||
return -1;
|
||||
}
|
||||
(void)fclose(fp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* 函数功能:投递一条日志(单线程直写宿主文件)
|
||||
* 入口参数:id - 日志 ID syslog_id_t
|
||||
* desc - 描述串(UTF-8,超长截断) const char *
|
||||
* 返回值:无
|
||||
*/
|
||||
void syslog_post(syslog_id_t id, const char *desc) {
|
||||
(void)s_append(id, desc);
|
||||
}
|
||||
|
||||
/*
|
||||
* 函数功能:获取记录条数(= filesize / SYSLOG_REC_SIZE,O(1))
|
||||
* 入口参数:id - 日志 ID syslog_id_t
|
||||
* 返回值:条数;文件缺失返回 0 uint32_t
|
||||
*/
|
||||
uint32_t syslog_count(syslog_id_t id) {
|
||||
struct stat st;
|
||||
|
||||
if ((uint32_t)id >= (uint32_t)SYSLOG_COUNT) {
|
||||
return 0u;
|
||||
}
|
||||
if (stat(s_paths[id], &st) != 0) {
|
||||
return 0u;
|
||||
}
|
||||
return (uint32_t)st.st_size / SYSLOG_REC_SIZE;
|
||||
}
|
||||
|
||||
/*
|
||||
* 函数功能:读取第 idx 条记录(时间戳 + 描述,均 NUL 结尾)
|
||||
* 入口参数:id - 日志 ID syslog_id_t
|
||||
* idx - 记录序号(0 起) uint32_t
|
||||
* p_ts - 时间戳输出缓冲(≥SYSLOG_TS_LEN+1 字节,不可为 NULL) char *
|
||||
* ts_len - p_ts 容量 size_t
|
||||
* p_desc - 描述输出缓冲(≥SYSLOG_DESC_MAX+1 字节,不可为 NULL) char *
|
||||
* desc_len - p_desc 容量 size_t
|
||||
* 返回值:0 - 成功;-1 - 越界/读失败 int
|
||||
*/
|
||||
int syslog_get_record(syslog_id_t id, uint32_t idx, char *p_ts, size_t ts_len, char *p_desc, size_t desc_len) {
|
||||
uint8_t rec[SYSLOG_REC_SIZE];
|
||||
size_t dl = 0u;
|
||||
|
||||
if (p_ts == NULL || p_desc == NULL || ts_len <= SYSLOG_TS_LEN || desc_len <= SYSLOG_DESC_MAX) {
|
||||
return -1;
|
||||
}
|
||||
if (s_read_raw(id, idx, rec) != 0) {
|
||||
return -1;
|
||||
}
|
||||
memcpy(p_ts, rec, SYSLOG_TS_LEN);
|
||||
p_ts[SYSLOG_TS_LEN] = '\0';
|
||||
while (dl < SYSLOG_DESC_MAX && rec[SYSLOG_DESC_OFFS + dl] != '\0') {
|
||||
dl++;
|
||||
}
|
||||
if (dl >= desc_len) {
|
||||
dl = desc_len - 1u;
|
||||
}
|
||||
memcpy(p_desc, rec + SYSLOG_DESC_OFFS, dl);
|
||||
p_desc[dl] = '\0';
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* 函数功能:读取末条记录的 epoch 秒(上电/重启分类用)
|
||||
* 入口参数:id - 日志 ID syslog_id_t
|
||||
* p_epoch- 输出缓冲(不可为 NULL;无记录时置 0) uint32_t *
|
||||
* 返回值:0 - 成功读到末条;-1 - 文件缺失/空 int
|
||||
*/
|
||||
int syslog_last_epoch(syslog_id_t id, uint32_t *p_epoch) {
|
||||
uint8_t rec[SYSLOG_REC_SIZE];
|
||||
uint32_t v = 0u;
|
||||
uint32_t i;
|
||||
|
||||
if (p_epoch == NULL || syslog_count(id) == 0u) {
|
||||
*p_epoch = 0u;
|
||||
return -1;
|
||||
}
|
||||
if (s_read_raw(id, syslog_count(id) - 1u, rec) != 0) {
|
||||
*p_epoch = 0u;
|
||||
return -1;
|
||||
}
|
||||
for (i = 0u; i < SYSLOG_EPOCH_LEN; i++) {
|
||||
char c = (char)rec[SYSLOG_EPOCH_OFFS + i];
|
||||
if (c >= '0' && c <= '9') {
|
||||
v = v * 10u + (uint32_t)(c - '0');
|
||||
}
|
||||
}
|
||||
*p_epoch = v;
|
||||
return 0;
|
||||
}
|
||||
@@ -104,7 +104,9 @@ STRIDE = W // 8 # I1:20 字节/行
|
||||
|
||||
# 开页-关页往返后的 LVGL 池水位(x64 模拟器)= 菜单基线 + 一次性残留 80 B。
|
||||
# 页面结构变更导致漂移时,先确认新值合理再更新此常量(内存回归门禁)。
|
||||
POOL_AFTER_ROUNDTRIP = 4864
|
||||
# 2026-09-14: 4864 → 5520(+656B)= run_headless 新增 ui_standby_init():待机模块
|
||||
# 常驻屏 s_scr + 容器 s_cont 两个 lv_obj,随菜单基线同移(见 check_menu_rows.py)。
|
||||
POOL_AFTER_ROUNDTRIP = 5520
|
||||
|
||||
|
||||
def run_sim(seq, out):
|
||||
|
||||
@@ -55,7 +55,9 @@ ROOT_X0, ROOT_Y0, ROOT_W, ROOT_H = 0, 44, 66, 107
|
||||
|
||||
# LVGL 池基线水位(menu build done,x64 模拟器):菜单结构/样式变更导致漂移时,
|
||||
# 先确认新值合理再更新此常量(内存回归门禁,见 docs/UI 设计/UI_自动化测试流程.md)
|
||||
MENU_POOL_BASELINE = 4784
|
||||
# 2026-09-14: 4784 → 5440(+656B)= run_headless 新增 ui_standby_init():待机模块
|
||||
# 常驻屏 s_scr + 容器 s_cont 两个 lv_obj(先于池测量创建),属有意结构变更。
|
||||
MENU_POOL_BASELINE = 5440
|
||||
|
||||
|
||||
def load(path):
|
||||
|
||||
Reference in New Issue
Block a user