模拟器迁移 P5:2s 配置轮询 + --cfgtest 无头自检;修复 MSVC rename 覆盖与外科保存截断缺陷
This commit is contained in:
@@ -17,6 +17,12 @@
|
||||
* lvgl_sim.exe --keys <seq> shot.bin
|
||||
* seq 字符:u=↑ d=↓ l=← r=→ e=Enter s=Esc(其余字符忽略)
|
||||
* 每键经 lv_group_send_data 注入(与 keypad 输入设备同路径),驱动 5 帧后取快照
|
||||
*
|
||||
* 配置轮询自检模式(无窗口、进程内闭环、退出码 0=PASS / 非0=FAIL):
|
||||
* lvgl_sim.exe --cfgtest
|
||||
* 验证链:net_cfg_load(含旧档迁移)→ poll 建基线 → 伪造外部编辑
|
||||
* (原子写新文档,等价 FTP 上传/文本编辑器)→ poll 两次(4s 沉降)
|
||||
* → 断言 RAM 副本已按新文件重载
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
@@ -38,6 +44,8 @@
|
||||
#include "ui_menu.h"
|
||||
#include "ui_net_sink.h"
|
||||
#include "net_cfg.h"
|
||||
#include "cfg_file.h"
|
||||
#include "cfg_file_store.h"
|
||||
|
||||
/* 屏幕尺寸(与 MCU 端一致) */
|
||||
#define SIM_SCREEN_W 160
|
||||
@@ -168,6 +176,89 @@ static int run_headless(const char * keys, const char * path)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 伪造"外部编辑"文档(绕过引擎原子写 = 等价 FTP 上传/文本编辑器);
|
||||
* 刻意短于出厂模板,保证 (size, mtime) 变更令牌必变 */
|
||||
static const char s_cfgtest_doc[] =
|
||||
"; cfgtest forged external edit\r\n"
|
||||
"\r\n"
|
||||
"[network]\r\n"
|
||||
"ip=10.0.0.1\r\n"
|
||||
"mask=255.255.255.0\r\n"
|
||||
"gw=10.0.0.254\r\n"
|
||||
"mac=00:00:00:00:00:00\r\n";
|
||||
|
||||
/* 伪造编辑后 RAM 副本应呈现的 IP */
|
||||
static const uint8_t s_cfgtest_ip[4] = { 10u, 0u, 0u, 1u };
|
||||
|
||||
/*
|
||||
* @brief 配置轮询自检(无窗口、无需 LVGL/SDL,进程内闭环)
|
||||
* @note 验证链:net_cfg_load(含旧档迁移)→ poll 建基线 → 伪造外部编辑
|
||||
* → poll 两次(沉降去抖)→ 重载并更新 RAM 副本
|
||||
* @return 0 PASS,非 0 FAIL
|
||||
*/
|
||||
static int run_cfgtest(void)
|
||||
{
|
||||
int i;
|
||||
const net_cfg_t *p_cfg;
|
||||
|
||||
setvbuf(stdout, NULL, _IONBF, 0);
|
||||
|
||||
(void)net_cfg_load(); /* 加载 / 旧档迁移(含 [network] 段注册) */
|
||||
|
||||
cfg_file_poll(); /* 第 1 次 poll:建立变更基线 */
|
||||
|
||||
/* 伪造外部编辑(原子写,与 P4 后 FTP STOR 同路径) */
|
||||
if (cfg_store_write_atomic(cfg_store_config_path(),
|
||||
(const uint8_t *)s_cfgtest_doc,
|
||||
strlen(s_cfgtest_doc)) != 0) {
|
||||
fprintf(stderr, "[cfgtest] forge write failed\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
cfg_file_poll(); /* 第 2 次 poll:检出变更,沉降计数 1 */
|
||||
cfg_file_poll(); /* 第 3 次 poll:沉降完成 → 重载 + 变更回调 */
|
||||
|
||||
p_cfg = net_cfg_get();
|
||||
for (i = 0; i < 4; i++) {
|
||||
if (p_cfg->ip[i] != s_cfgtest_ip[i]) {
|
||||
printf("[cfgtest] FAIL ip after reload = %u.%u.%u.%u (expect 10.0.0.1)\n",
|
||||
(unsigned)p_cfg->ip[0], (unsigned)p_cfg->ip[1],
|
||||
(unsigned)p_cfg->ip[2], (unsigned)p_cfg->ip[3]);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
printf("[cfgtest] OK ip after reload = 10.0.0.1\n");
|
||||
|
||||
/* 保存回环:外科手术式保存(目标文件已存在)→ 回读校验注释保留与值一致 */
|
||||
if (net_cfg_save() != 0) {
|
||||
printf("[cfgtest] FAIL net_cfg_save (existing file)\n");
|
||||
return 1;
|
||||
}
|
||||
{
|
||||
uint8_t buf[CFG_FILE_MAX_LEN + 1u];
|
||||
char *p_doc;
|
||||
size_t n = 0u;
|
||||
|
||||
if (cfg_store_read(cfg_store_config_path(), buf, sizeof(buf), &n) != 0) {
|
||||
printf("[cfgtest] FAIL readback open\n");
|
||||
return 1;
|
||||
}
|
||||
buf[n] = '\0';
|
||||
p_doc = (char *)buf;
|
||||
if (strstr(p_doc, "; cfgtest forged external edit") == NULL) {
|
||||
printf("[cfgtest] FAIL comment lost after surgical save\n");
|
||||
return 1;
|
||||
}
|
||||
if (strstr(p_doc, "ip=10.0.0.1") == NULL) {
|
||||
printf("[cfgtest] FAIL value lost after surgical save\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
printf("[cfgtest] OK surgical save (comment kept, value intact)\n");
|
||||
printf("[cfgtest] PASS\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 程序入口
|
||||
*/
|
||||
@@ -181,6 +272,9 @@ int main(int argc, char **argv)
|
||||
if (strcmp(argv[i], "--keys") == 0 && (i + 2) < argc) {
|
||||
return run_headless(argv[i + 1], argv[i + 2]);
|
||||
}
|
||||
if (strcmp(argv[i], "--cfgtest") == 0) {
|
||||
return run_cfgtest();
|
||||
}
|
||||
}
|
||||
|
||||
/* 初始化 Winsock(供 ui_net_sink 使用) */
|
||||
@@ -233,6 +327,9 @@ int main(int argc, char **argv)
|
||||
printf("Keyboard: ↑↓←→ navigate, Enter confirm, Escape back\n");
|
||||
printf("Press Ctrl+C or close window to exit\n\n");
|
||||
|
||||
/* 配置文件轮询起点(2s 周期,与 MCU netTask 一致) */
|
||||
uint32_t cfg_last_poll = (uint32_t)SDL_GetTicks();
|
||||
|
||||
/* 主循环:驱动 LVGL 定时器与刷新
|
||||
* 注意:SDL 事件(键盘/窗口/退出)由 LVGL SDL 驱动内部 5ms 定时器
|
||||
* (lv_sdl_window.c 的 sdl_event_handler)统一轮询分发,
|
||||
@@ -242,6 +339,13 @@ int main(int argc, char **argv)
|
||||
/* 轮询 RemoDispBus 协议(非阻塞收发) */
|
||||
ui_net_sink_poll();
|
||||
|
||||
/* 配置文件轮询(2s 周期:外部文件变更 4s 沉降后自动重载) */
|
||||
uint32_t now_ms = (uint32_t)SDL_GetTicks();
|
||||
if ((uint32_t)(now_ms - cfg_last_poll) >= 2000u) {
|
||||
cfg_last_poll = now_ms;
|
||||
cfg_file_poll();
|
||||
}
|
||||
|
||||
/* 驱动 LVGL 定时器与刷新 */
|
||||
uint32_t sleep_ms = lv_timer_handler();
|
||||
if (sleep_ms == LV_NO_TIMER_READY) {
|
||||
|
||||
Reference in New Issue
Block a user