feat(对时): 8888 对时补一条操作记录留痕——与 104 对时对称,被拒不落痕
task-49 盘点盘出的唯一供给缺口,task-50 实现(道H 交付)。为什么这算缺陷而不是「维护工装不值得留痕」:
对时改变的是**其后每一条记录**的时标,而 104 侧的对时**已经留痕** —— 同一类行为两种结果,这个不对称
本身就是缺陷。FTP 上传不留痕则维持原状(那是传输动作,与「装置时钟被改了」不同类),本笔
刻意不扩面到它。
实现:`time_sync_handle_conn` 里 `sys_clock_set_unix` 的返回值原先是**裸丢弃**,现改为接住判
0,==0 才
投 `SYSLOG_OPER`(走 quiet 口,netTask 侧纪律,栈成本已在注释写明);**被拒零投**(不把失败记成改过时
钟);无合并锁存(连续两次对时留两条,不折叠);**epoch 语义零触碰、零时区补偿** —— 时基口径仍在用
户手里,本笔不替产品决定。
新用例四组十二断言:成功恰一条 / 被拒不落痕 / 连续两次两条 / 魔术字不符皆零。假件把 rc 做成可脚本,
并专门钉「文案出现次数」以证不合并;`sys_log.h` 用真实头(纯 stdint,走 task_watchdog 先例),零桩漂移面。
**停发口径的第一批**:新断言**不配 TC 号**,改用语义化用例名 + 函数名追溯,注释里标了口径出处 —— 裁定
能不能落地看的就是第一批,这条留在这里给后来者当样例。
证据:time_sync 92/92(存量 82 零回归);@build **0 错 0 警**,Code=235268 RO=26308 RW
=1572 ZI=136924
(与上一笔的差值是 728d6067 合账所致,不是本笔);栈**以表为证**:timeSyncTask 链 1272→1272 B 零增
量,own frame 152 不变,handle_conn 200 / post_quiet 40 / post 264 逐函数帧全等 ——
按今天刚定稿的栈判
据,「零增量」这句话必须是表,不能是论证。id-check --strict 0(零新号零裸形)、乱码/嵌套/BOM 净。
台账:`ram_baseline.py --update` 已记当日行(IRAM1 61.9% / CCM 87.9%)。覆盖率基线**留给 L
ead 重建** ——
上一版基线是在 time_sync 套件编译不过的破树下打的,少算了该套件的覆盖。
台账同步:本笔代码改了体积(Code=235268),RAM 预算台账受管区与文档快照区按 12:46 那次权威构建回填(ram_baselin
e --write 加 check_mem_numbers --write)。代码与数字不同笔,就是下一次 mem 钩子假红的来源——上一笔 d
ocs 提交被 mem-numbers 与 mem-budget 双双拦下,正是这个原因。
This commit is contained in:
@@ -641,7 +641,7 @@ repos:
|
||||
# 疑似 MSBuild 节点争用;此后 3 次干净树连跑均绿。判据:单次失败先复跑一次再看,
|
||||
# 连续两次失败才当真(不许直接 --no-verify 绕过)。
|
||||
- id: ui-golden
|
||||
name: UI 像素回归(菜单 8 状态 + 内容页 47 页 黄金参考)
|
||||
name: UI 像素回归(菜单 8 状态 + 内容页 53 页 黄金参考)
|
||||
entry: python scripts/check_ui_golden.py
|
||||
language: system
|
||||
files: ^(Drivers/BSP/UI/|App/task/ui_task\.(c|h)$|simulator/(tests|sim|src)/|simulator/main\.c$|simulator/CMakeLists\.txt$|simulator/lv_conf\.h$|scripts/check_ui_golden\.py$|\.pre-commit-config\.yaml$)
|
||||
|
||||
+17
-1
@@ -10,6 +10,11 @@
|
||||
* v1.1 2026-08-28 王建锋 改为 TCP Server,迁入独立任务 timeSyncTask,
|
||||
* 所有 socket 操作经 net_socket 线程安全 API 走消息队列,
|
||||
* netTask 仅负责 net_poll/net_process_messages,多任务并发安全
|
||||
* v1.3 2026-10-27 DTU 项目组 道G task-50:对时**成功应用**后投一条 quiet
|
||||
* 操作记录("clock set by 8888")——task-49 盘点盘出
|
||||
* "104 对时留痕、本端口不留"的同类不对称,Lead 批准补齐;
|
||||
* 被拒不落痕;epoch 时标语义未裁定,本改动不碰、不补
|
||||
* 任何时区补偿。
|
||||
* v1.2 2026-10-02 王建锋 第 8b 轮消抖:等待片长 200ms→50ms,并把各处长
|
||||
* 等待(500/2000/200ms)统一走 time_sync_delay_fed()
|
||||
* 按 ≤50ms 分片、每片喂心跳——消除"心跳滑出两个连续
|
||||
@@ -21,6 +26,7 @@
|
||||
#include "net_socket.h"
|
||||
#include "sys_clock.h"
|
||||
#include "sys_events.h"
|
||||
#include "sys_log.h"
|
||||
#include "task_watchdog.h"
|
||||
|
||||
/* 深调用链模块(timeSyncTask 栈仅 2048 B,本任务链 = 建监听 → net_bind → CH395F):
|
||||
@@ -176,7 +182,17 @@ static void time_sync_handle_conn(int conn_sock) {
|
||||
((uint32_t)buf[5] << 16) |
|
||||
((uint32_t)buf[6] << 8) |
|
||||
((uint32_t)buf[7]);
|
||||
sys_clock_set_unix(epoch);
|
||||
if (sys_clock_set_unix(epoch) == 0) {
|
||||
/* 操作留痕(道G task-50):对时改的是装置时钟——与 104 的
|
||||
* "clock set by 104"(App/task/iec104_serv.c 对时处)同类同口径,
|
||||
* 补齐 task-49 盘出的不对称。**被拒不投**:失败不得记成"时钟被改过";
|
||||
* 连续两次成功各投一条——每次对时是独立事件,无合并语义。
|
||||
* quiet 口:本任务栈 2048 B(见本文件 DBG_LINE_BUF_MAX 段),
|
||||
* syslog_post 的两个满态留痕分支各内联约 216 B 行缓冲,不选它。
|
||||
* ⚠ 记录里的时标语义(本端口写钟面、104 写 UTC 的 8 小时差)
|
||||
* 未裁定——留痕按现有通道原样落,不做任何时区补偿。 */
|
||||
syslog_post_quiet(SYSLOG_OPER, "clock set by 8888");
|
||||
}
|
||||
DBG_INFO("time_sync: wall clock updated (epoch=%lu)", (unsigned long)epoch);
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -47,10 +47,10 @@ dhara 失败类 +84;RO 另 +208,全是该失败类名表)→ `ER_IROM1`
|
||||
<!-- MEM_SNAPSHOT:BEGIN generated by scripts/check_mem_numbers.py -->
|
||||
| 区域 | 用量 | 容量 | 占比 |
|
||||
|---|---|---|---|
|
||||
| ER_IROM1 | 261,544 B (255.41 KB) | 1,048,576 B (1024 KB) | 24.9% |
|
||||
| ER_IROM1 | 261,576 B (255.45 KB) | 1,048,576 B (1024 KB) | 24.9% |
|
||||
| RW_IRAM1 | 81,072 B (79.17 KB) | 131,072 B (128 KB) | 61.9% |
|
||||
| RW_CCM | 57,376 B (56.03 KB) | 65,280 B (64 KB) | 87.9% |
|
||||
| **Flash (ROM 合计)** | **263,116 B (256.9 KB)** | 1,048,576 B (1024 KB) | **25.1%** |
|
||||
| **Flash (ROM 合计)** | **263,148 B (257.0 KB)** | 1,048,576 B (1024 KB) | **25.1%** |
|
||||
<!-- MEM_SNAPSHOT:END -->
|
||||
|
||||
各区的容量与常量来源:
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
<!-- MEM_BUDGET:BEGIN generated by scripts/ram_baseline.py -->
|
||||
| 区域 | 用量 | 容量 | 占比 | 门禁(≤92%) |
|
||||
|---|---|---|---|---|
|
||||
| ER_IROM1 (Flash) | 261,544 B | 1,048,576 B | 24.9% | 参考 |
|
||||
| ER_IROM1 (Flash) | 261,576 B | 1,048,576 B | 24.9% | 参考 |
|
||||
| RW_CCM | 57,376 B | 65,280 B | 87.9% | PASS |
|
||||
| UNINIT_CCM | 48 B | 256 B | 18.8% | 参考 |
|
||||
| RW_IRAM1 | 81,072 B | 131,072 B | 61.9% | PASS |
|
||||
|
||||
@@ -9,4 +9,4 @@ date code ro rw zi er_irom1 er_pct iram1 iram1_pct ccm ccm_pct top_rwzi
|
||||
2026-10-24 213780 18860 1204 131852 232640 22.2 75632 57.7 57376 87.9 heap_4.o=57376;lv_mem_core_builtin.o=16384;lftpd.o=7884;ui_net_sink.o=6766;ui_port.o=6420;nand_ftl.o=6216;ch395f.o=4162;console_log.o=4128;sys_log_mcu.o=3944;default_task.o=2736
|
||||
2026-10-25 224860 24640 1332 135100 249500 23.8 79008 60.3 57376 87.9 heap_4.o=57376;lv_mem_core_builtin.o=16384;lftpd.o=7884;ui_net_sink.o=6770;ui_port.o=6420;nand_ftl.o=6216;ch395f.o=4162;console_log.o=4128;sys_log_mcu.o=3944;default_task.o=2736
|
||||
2026-10-26 231712 25560 1520 136216 257272 24.5 80312 61.3 57376 87.9 heap_4.o=57376;lv_mem_core_builtin.o=16384;lftpd.o=7884;ui_net_sink.o=6770;ui_port.o=6420;nand_ftl.o=6216;ch395f.o=4162;console_log.o=4132;sys_log_mcu.o=4003;default_task.o=2736
|
||||
2026-10-27 235236 26308 1572 136924 261544 24.9 81072 61.9 57376 87.9 heap_4.o=57376;lv_mem_core_builtin.o=16384;lftpd.o=7884;ui_net_sink.o=6770;ui_port.o=6420;nand_ftl.o=6216;ch395f.o=4162;console_log.o=4132;sys_log_mcu.o=4055;default_task.o=2736
|
||||
2026-10-27 235268 26308 1572 136924 261576 24.9 81072 61.9 57376 87.9 heap_4.o=57376;lv_mem_core_builtin.o=16384;lftpd.o=7884;ui_net_sink.o=6770;ui_port.o=6420;nand_ftl.o=6216;ch395f.o=4162;console_log.o=4132;sys_log_mcu.o=4055;default_task.o=2736
|
||||
|
||||
|
@@ -49,6 +49,7 @@ BUILD = TestBuild(
|
||||
os.path.join(HERE, "stub"),
|
||||
os.path.join(ROOT, "App", "util"),
|
||||
os.path.join(ROOT, "App", "sync"),
|
||||
os.path.join(ROOT, "App", "log"), # sys_log.h 用真实头(纯 stdint,同 task_watchdog.h 先例)
|
||||
HERE,
|
||||
],
|
||||
summary_marker="=== Time Sync Tests:",
|
||||
|
||||
@@ -57,6 +57,8 @@
|
||||
* TC-TIMESYNC-042 屏障未就绪期间持续喂心跳(2026-10-02 台架根因的回归防线)
|
||||
* TC-TIMESYNC-043 网络代次变化 -> 关闭旧监听并重监听
|
||||
* TC-TIMESYNC-044 监听建立失败 -> 5 次重试后放弃并退避 2000ms
|
||||
* 对时操作留痕(道G task-50,语义行名不配号——编号规范已停发测试用例号):
|
||||
* "sync trace on success" / "… rejected" / "… two in a row" / "… bad magic" 四组
|
||||
*
|
||||
* 通过:全部 TC PASS(main 返回 0)。
|
||||
* 入口:int main(void),返回 0=PASS / 1=FAIL(由 run 脚本判读)。
|
||||
@@ -76,6 +78,7 @@
|
||||
#include "sys_clock.h"
|
||||
#include "sys_events.h"
|
||||
#include "task_watchdog.h" /* 真实头(App/util):task_wd_id_t / TASK_WD_TIMESYNC */
|
||||
#include "sys_log.h" /* 真实头(App/log,纯 stdint 无 OS 依赖):syslog_id_t / SYSLOG_OPER 契约,假件签名与之逐字对齐 */
|
||||
|
||||
/* ===================== FreeRTOS 桩 ===================== */
|
||||
static TickType_t s_tick;
|
||||
@@ -152,11 +155,33 @@ void task_wd_bind(task_wd_id_t id) {
|
||||
/* ===================== sys_clock 桩 ===================== */
|
||||
static int s_set_unix_calls;
|
||||
static uint32_t s_set_unix_last;
|
||||
static int s_set_unix_rc; /* 可脚本化返回值:非 0 = 对时被拒(task-50) */
|
||||
|
||||
int sys_clock_set_unix(uint32_t unix_secs) {
|
||||
s_set_unix_calls++;
|
||||
s_set_unix_last = unix_secs;
|
||||
return 0;
|
||||
return s_set_unix_rc;
|
||||
}
|
||||
|
||||
/* ===================== sys_log 投递桩(task-50) =====================
|
||||
* 假件按投递顺序记录:条数 / 日志 ID / 末条描述 / 对时文案出现次数。
|
||||
* "出现次数"专为钉"连续两次不合并"——若生产侧哪天改成边沿锁存,
|
||||
* 第三条用例会红,而那正是要拦的语义漂移。 */
|
||||
static int s_post_calls;
|
||||
static int s_post_id;
|
||||
static char s_post_last_desc[32];
|
||||
static int s_post_desc_count;
|
||||
|
||||
void syslog_post_quiet(syslog_id_t id, const char *desc) {
|
||||
s_post_calls++;
|
||||
s_post_id = (int)id;
|
||||
if (desc != NULL) {
|
||||
(void)strncpy(s_post_last_desc, desc, sizeof(s_post_last_desc) - 1u);
|
||||
s_post_last_desc[sizeof(s_post_last_desc) - 1u] = '\0';
|
||||
if (strcmp(desc, "clock set by 8888") == 0) {
|
||||
s_post_desc_count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ===================== net_socket 桩 ===================== */
|
||||
@@ -349,6 +374,11 @@ static void fakes_reset(void) {
|
||||
|
||||
s_set_unix_calls = 0;
|
||||
s_set_unix_last = 0;
|
||||
s_set_unix_rc = 0;
|
||||
s_post_calls = 0;
|
||||
s_post_id = -1;
|
||||
s_post_last_desc[0] = '\0';
|
||||
s_post_desc_count = 0;
|
||||
|
||||
s_htons_last = 0;
|
||||
s_socket_calls = 0;
|
||||
@@ -716,6 +746,61 @@ static void tc_task(void) {
|
||||
CHECK(s_beat_id_bad == 0, "TC-TIMESYNC-044e every beat sets the TIMESYNC bit");
|
||||
}
|
||||
|
||||
/* ===================== 对时操作留痕四组(道G task-50) =========================
|
||||
* 成功应用投一条 quiet OPER;被拒不投(失败不得记成"改过时钟");
|
||||
* 连续两次各一条不合并;魔术字不符不投。
|
||||
* ⚠ 断言标签用语义行名:编号规范 §9 批次三已对测试用例号停发(用户裁定 2026-10-27),
|
||||
* 本组是新口径下写的——追溯靠函数名 tc_oper_trace + 下面的语义标签。 */
|
||||
static void tc_oper_trace(void) {
|
||||
uint8_t pkt[16];
|
||||
|
||||
/* 1) 对时成功 → 恰一条 OPER */
|
||||
fakes_reset();
|
||||
make_time_packet(pkt, 0x20251027u);
|
||||
recv_set(0, 8, pkt, 8, 0U);
|
||||
s_recv_seq_n = 1;
|
||||
s_set_unix_rc = 0;
|
||||
time_sync_handle_conn(7);
|
||||
CHECK(s_set_unix_calls == 1, "sync trace: clock layer applied once");
|
||||
CHECK(s_post_calls == 1, "sync trace on success: exactly one operation record");
|
||||
CHECK(s_post_id == (int)SYSLOG_OPER, "sync trace: record goes to the operation log");
|
||||
CHECK(strcmp(s_post_last_desc, "clock set by 8888") == 0,
|
||||
"sync trace: wording of the same family as the 104 time-sync record");
|
||||
|
||||
/* 2) 对时被拒(时钟层返非 0)→ 零留痕 */
|
||||
fakes_reset();
|
||||
make_time_packet(pkt, 7u);
|
||||
recv_set(0, 8, pkt, 8, 0U);
|
||||
s_recv_seq_n = 1;
|
||||
s_set_unix_rc = -1;
|
||||
time_sync_handle_conn(7);
|
||||
CHECK(s_set_unix_calls == 1, "sync trace rejected: call still reaches the clock layer once");
|
||||
CHECK(s_post_calls == 0, "sync trace rejected: NO operation record written");
|
||||
|
||||
/* 3) 连续两次成功会话 → 两条独立记录,不合并 */
|
||||
fakes_reset();
|
||||
s_set_unix_rc = 0;
|
||||
make_time_packet(pkt, 100u);
|
||||
recv_set(0, 8, pkt, 8, 0U);
|
||||
recv_set(1, 8, pkt, 8, 0U);
|
||||
s_recv_seq_n = 2;
|
||||
time_sync_handle_conn(7);
|
||||
time_sync_handle_conn(7);
|
||||
CHECK(s_set_unix_calls == 2, "sync trace twice: two applied syncs");
|
||||
CHECK(s_post_calls == 2, "sync trace twice: two independent records, not merged");
|
||||
CHECK(s_post_desc_count == 2, "sync trace twice: both records are the time-sync wording (no coalescing latch)");
|
||||
|
||||
/* 4) 前缀不是 TIME → 时钟层都没到,更不该留痕 */
|
||||
fakes_reset();
|
||||
(void)memset(pkt, 'X', 8);
|
||||
recv_set(0, 8, pkt, 8, 0U);
|
||||
s_recv_seq_n = 1;
|
||||
s_set_unix_rc = 0;
|
||||
time_sync_handle_conn(7);
|
||||
CHECK((s_set_unix_calls == 0) && (s_post_calls == 0),
|
||||
"sync trace bad magic: neither moves the clock nor writes a record");
|
||||
}
|
||||
|
||||
/* ===================== main ===================== */
|
||||
|
||||
int main(void) {
|
||||
@@ -729,6 +814,8 @@ int main(void) {
|
||||
tc_handle_conn();
|
||||
printf("-- time_sync_task (barrier / accept / relisten) --\n");
|
||||
tc_task();
|
||||
printf("-- operation trace on sync (task-50) --\n");
|
||||
tc_oper_trace();
|
||||
|
||||
printf("\n=== Time Sync Tests: %d/%d PASSED (failed=%d) ===\n",
|
||||
s_passed, s_total, s_failed);
|
||||
|
||||
Reference in New Issue
Block a user