test(host): 断言字面量统一纯 ASCII,30 文件 1535 行
用户裁定「统一」。口径就是 AGENTS 铁律:字符串字面量必须纯 ASCII (无 BOM 文件里奇数个汉字会吞掉结束引号,偶数才侥幸通过),中文只写注释。 四名队友按目录分四组并行、写范围互斥:net_socket 418 行(6 文件)、 console_log/sys_log_mcu/soe_store/cfg_file_store_mcu 268 行(4 文件)、 11 个存量套件 404 行 + adc_input 89 行、iec104 与 lftpd 与 NET 四套等 356 行 (9 文件)。runner 的 .py 文档串不在口径内(Python 源不经 ARMCC 代码页)。 两套口径必须分清:粗口径(按行切引号)普查 = 34 文件 / 1,552 行;严格口径 (状态机剥掉块/行注释与字符常量后再取字符串字面量)= 30 文件 / 1,535 行。 差值那 4 个文件的命中全在注释里(ns_peers.c、net_socket/stub/ns_rtos.h、 common/ch395f_fake.h、common/fatfs_fake.c)——按口径一处都不该改,改了等于 把中文从注释里搬走、正好违背口径。粗口径绝不能当交付判据,否则要么白改 注释、要么留下「这行为什么没改」的悬案。 Lead 独立终检(不采信自报)五条硬判据,结果 30 文件漂移 0:① 每文件 TC 号 集合与 HEAD 逐字相同 ② 断言宏调用点数不变 ③ 行数与 HEAD 完全相等(专抓 整文件回写把尾部含 main() 吃掉的截断,第 1 轮真发生过两次)④ 剥注释后代码区 非 ASCII 字符 = 0 ⑤ 字节卫生(BOM 与 HEAD 一致、无 CR、无 U+FFFD、单尾换行)。 另用「逐行把字面量整体替换成空串后与 HEAD 必须逐行相等」机械证明只改了字面量; 各套 --module 覆盖率与断言数逐字不变(net_socket 887/889·53/53、console_log 199/200·16/16、sys_log_mcu 324/326·13/13、adc_input 103/103、sys_clock 100/100) → 生产码零改动,基线不需重登。 闸拦下一处真实回归(我的验收器没抓到):ns_s6_edges.c 翻译时把一个上一轮 已整改成平实描述的编号又写回了 CHECK 标签。原因很清楚:「只改字面量」并不 等于「只改无害内容」,标签里完全可以带进未登记族的编号形态;而 Lead 的自动 验收器只比对了 TC 形 id 集合,未覆盖 L/E/N/S/TRAP 等族。教训:批量改标签的 守卫必须加一条「新串不得出现任何已登记前缀族之外的编号形态」,且结构不变式 只覆盖自己想到的维度时不能替代真闸。 Lead 自查另清掉 126 处写坏的反斜杠(JS→Python 转义层数翻倍,把 markdown 反引号写成反斜杠+反引号),恰好发生在记录这条教训的那一节里。 文档:docs/测试说明/主机单测覆盖率口径.md §9 新增「第 2 轮」小节(两套口径对照 表、五条终检判据、六条手法含「转换说明符序列必须逐位相同」取代「禁止裸 %」、 三条协作纪律含先改板再派工与临时文件带组前缀、后续项 3 条)+ 变更记录一行。 后续项(本轮不做):把剥注释词法扫描器收进 scripts 当门禁(需用户点头并先定 test/ 是否纳入 coding-standard);iec104 的简写编号归族(牵 id_registry, 不能顺手做);替换器加「编号形态白名单」校验。 gate: pre-commit run --all-files -> 39 hooks, 37 Passed; failed = mem-numbers + mem-budget(受管快照与本树 .map 的漂移,属第 1 轮生产码改动的遗留,非本批 增量)。本批只碰 test/host/**,不进 Keil 编译面也不进模拟器 CMake,**RAM/Flash 增量 = 0**;实测水位 RW_IRAM1 57.4%、RW_CCM 87.9%,均低于 92% 红线。 id-check 0 台账外新账(可判定 84.63% > 基线 82.6%);test-coverage 33/33 全绿; cppcheck / coding-standard / bsp-err / layer-deps / doc-links 全 Passed。 按仓内分支约定 --no-verify 提交,台账 --write 回填留待主工作树合并后。
This commit is contained in:
@@ -493,27 +493,27 @@ static void tc_params(void)
|
||||
{
|
||||
char buf[DBG_CON_LINE_MAX + 128U];
|
||||
|
||||
printf("-- TC-CONLOG-000..006 参数校验与截断 --\n");
|
||||
printf("-- TC-CONLOG-000..006 argument checks and truncation --\n");
|
||||
reset_all();
|
||||
printf("(probe) 这行走宿主 CRT\n");
|
||||
printf("(probe) this line goes through the host CRT\n");
|
||||
fflush(stdout);
|
||||
CHECK(con_uart_tx_n == 0U && used_now() == 0U,
|
||||
"TC-CONLOG-000 宿主 printf 不经过本模块 fputc(否则测试输出会被吞进环)");
|
||||
"TC-CONLOG-000 host printf does not pass through this module fputc (else test output would be swallowed into the ring)");
|
||||
|
||||
reset_all();
|
||||
con_uart_txe_stuck = 1; /* 通道卡死:任何字节都不该上线 */
|
||||
CHECK(dbg_console_write_line(0, 5U) == -1, "TC-CONLOG-001 write_line(NULL) 返回 -1");
|
||||
CHECK(dbg_console_write_line("abc", 0U) == -1, "TC-CONLOG-002 write_line(len=0) 返回 -1");
|
||||
CHECK(dbg_console_write_line(0, 5U) == -1, "TC-CONLOG-001 write_line(NULL) returns -1");
|
||||
CHECK(dbg_console_write_line("abc", 0U) == -1, "TC-CONLOG-002 write_line(len=0) returns -1");
|
||||
dbg_console_write_raw(0, 5U);
|
||||
dbg_console_write_raw("abc", 0U);
|
||||
CHECK(con_uart_tx_n == 0U, "TC-CONLOG-003 两路 NULL/0 都不碰 UART");
|
||||
CHECK(dbg_console_dropped() == 0U, "TC-CONLOG-004 参数非法不计入丢弃");
|
||||
CHECK(con_uart_tx_n == 0U, "TC-CONLOG-003 both NULL and len=0 never touch the UART");
|
||||
CHECK(dbg_console_dropped() == 0U, "TC-CONLOG-004 invalid arguments are not counted as drops");
|
||||
|
||||
reset_all();
|
||||
memset(buf, 'A', sizeof(buf));
|
||||
CHECK(dbg_console_write_line(buf, sizeof(buf)) == (int)DBG_CON_LINE_MAX,
|
||||
"TC-CONLOG-005 超过 DBG_CON_LINE_MAX 的行按 192 截断(返回值即交付字节数)");
|
||||
CHECK(con_uart_tx_n == DBG_CON_LINE_MAX, "TC-CONLOG-006 截断后恰好上线 192 字节");
|
||||
"TC-CONLOG-005 a line longer than DBG_CON_LINE_MAX is truncated to 192 (return value is the delivered byte count)");
|
||||
CHECK(con_uart_tx_n == DBG_CON_LINE_MAX, "TC-CONLOG-006 after truncation exactly 192 bytes reach the wire");
|
||||
}
|
||||
|
||||
/* ============ TC-CONLOG-010..018 写者未注册 = 无锁直发 ============ */
|
||||
@@ -521,26 +521,26 @@ static void tc_unattached(void)
|
||||
{
|
||||
char big[DBG_CON_CHUNK_MAX + 64U];
|
||||
|
||||
printf("-- TC-CONLOG-010..018 写者未注册:无锁直发 --\n");
|
||||
printf("-- TC-CONLOG-010..018 writer not attached: lock-free direct send --\n");
|
||||
reset_all();
|
||||
CHECK(dbg_console_writer_ready() == 0U, "TC-CONLOG-010 attach 之前 writer_ready() == 0");
|
||||
CHECK(dbg_console_write_line("hello", 5U) == 5, "TC-CONLOG-011 未注册时整行直发,返回行长");
|
||||
CHECK(tx_is(0U, "hello"), "TC-CONLOG-012 直发内容原样上线(没经过环形缓冲)");
|
||||
CHECK(used_now() == 0U, "TC-CONLOG-013 直发不入环(head == tail)");
|
||||
CHECK(con_evt_sets == 0U, "TC-CONLOG-014 直发不置 SYS_EVT_CONSOLE_TX(还没写者可唤醒)");
|
||||
CHECK(dbg_console_writer_ready() == 0U, "TC-CONLOG-010 writer_ready() == 0 before attach");
|
||||
CHECK(dbg_console_write_line("hello", 5U) == 5, "TC-CONLOG-011 before attach the whole line is sent directly, returning its length");
|
||||
CHECK(tx_is(0U, "hello"), "TC-CONLOG-012 direct send reaches the wire verbatim (never went through the ring)");
|
||||
CHECK(used_now() == 0U, "TC-CONLOG-013 direct send does not enter the ring (head == tail)");
|
||||
CHECK(con_evt_sets == 0U, "TC-CONLOG-014 direct send does not set SYS_EVT_CONSOLE_TX (no writer to wake yet)");
|
||||
CHECK(con_crit_enter == 0U,
|
||||
"TC-CONLOG-015 直发零临界区 = 2026-10-10 逐字节交错的根因(不是丢整行)");
|
||||
"TC-CONLOG-015 direct send uses zero critical sections = the 2026-10-10 byte-interleaving root cause (not whole-line loss)");
|
||||
|
||||
reset_all();
|
||||
memset(big, 'B', sizeof(big));
|
||||
dbg_console_write_raw(big, sizeof(big));
|
||||
CHECK(con_uart_tx_n == DBG_CON_CHUNK_MAX, "TC-CONLOG-016 write_raw 有界:只发 256 字节");
|
||||
CHECK(con_uart_tx_n == DBG_CON_CHUNK_MAX, "TC-CONLOG-016 write_raw is bounded: only 256 bytes are sent");
|
||||
|
||||
reset_all();
|
||||
con_uart_txe_after = 3; /* 前 3 次不就绪(TXE 抖动,未超上界) */
|
||||
CHECK(dbg_console_write_line("CD", 2U) == 2, "TC-CONLOG-017 TXE 抖动后仍发全");
|
||||
CHECK(dbg_console_write_line("CD", 2U) == 2, "TC-CONLOG-017 after TXE jitter the whole line still goes out");
|
||||
CHECK(tx_is(0U, "CD") && con_delay_calls == 0U,
|
||||
"TC-CONLOG-018 直发既不等 tick 也不入环(ISR/崩溃钩子可用的前提)");
|
||||
"TC-CONLOG-018 direct send neither waits on tick nor enters the ring (premise for ISR and crash hooks)");
|
||||
}
|
||||
|
||||
/* ============ TC-CONLOG-020..037 注册后走环形缓冲 ============ */
|
||||
@@ -550,24 +550,24 @@ static void tc_ring(void)
|
||||
static char oversize[3000]; /* 超长入环的源(>= 钳位后的 2048B) */
|
||||
uint32_t i;
|
||||
|
||||
printf("-- TC-CONLOG-020..027 注册后:生产者入环、写者发送 --\n");
|
||||
printf("-- TC-CONLOG-020..027 after attach: producers enter the ring, writer sends --\n");
|
||||
reset_all();
|
||||
attach_writer();
|
||||
CHECK(dbg_console_writer_ready() == 1U, "TC-CONLOG-020 attach 之后 writer_ready() == 1");
|
||||
CHECK(dbg_console_writer_ready() == 1U, "TC-CONLOG-020 writer_ready() == 1 after attach");
|
||||
CHECK(s_con_writer_task == (TaskHandle_t)&s_task_writer,
|
||||
"TC-CONLOG-021 attach 记下的正是调用方的任务句柄(自等保护的依据)");
|
||||
CHECK(dbg_console_write_line("netTask up\r\n", 12U) == 12, "TC-CONLOG-022 入环成功返回行长");
|
||||
CHECK(con_uart_tx_n == 0U, "TC-CONLOG-023 生产者绝不碰 UART");
|
||||
CHECK(used_now() == 12U, "TC-CONLOG-024 整行一次入环(used = 12)");
|
||||
"TC-CONLOG-021 attach records exactly the caller task handle (basis of the self-wait guard)");
|
||||
CHECK(dbg_console_write_line("netTask up\r\n", 12U) == 12, "TC-CONLOG-022 a successful ring entry returns the line length");
|
||||
CHECK(con_uart_tx_n == 0U, "TC-CONLOG-023 producers never touch the UART");
|
||||
CHECK(used_now() == 12U, "TC-CONLOG-024 the whole line enters the ring at once (used = 12)");
|
||||
CHECK(con_evt_sets == 1U && con_evt_flags == SYS_EVT_CONSOLE_TX,
|
||||
"TC-CONLOG-025 入环后置真实事件位 SYS_EVT_CONSOLE_TX(bit6)唤醒写者");
|
||||
"TC-CONLOG-025 after entering the ring the real event bit SYS_EVT_CONSOLE_TX (bit6) wakes the writer");
|
||||
CHECK(con_crit_enter == 1U && con_crit_exit == 1U && con_crit_max_depth == 1U,
|
||||
"TC-CONLOG-026 整行入环恰好一层临界区(行级原子的实现依据)");
|
||||
"TC-CONLOG-026 one line takes exactly one critical-section level (implementation basis of line atomicity)");
|
||||
|
||||
writer_drain();
|
||||
CHECK(tx_is(0U, "netTask up\r\n"), "TC-CONLOG-027 写者排空:上线字节与入环内容逐字节相同");
|
||||
CHECK(tx_is(0U, "netTask up\r\n"), "TC-CONLOG-027 writer drain: wire bytes are byte-identical to what entered the ring");
|
||||
|
||||
printf("-- TC-CONLOG-028..032 分块 256B 与多生产者不交错 --\n");
|
||||
printf("-- TC-CONLOG-028..032 256B chunking and no interleaving between producers --\n");
|
||||
reset_all();
|
||||
attach_writer();
|
||||
memset(line, 'C', sizeof(line));
|
||||
@@ -575,12 +575,12 @@ static void tc_ring(void)
|
||||
(void)dbg_console_write_line(line, sizeof(line));
|
||||
}
|
||||
writer_drain();
|
||||
CHECK(con_uart_block_n == 4U, "TC-CONLOG-028 960B 按 DBG_CON_CHUNK_MAX 切成 4 块");
|
||||
CHECK(con_uart_block_n == 4U, "TC-CONLOG-028 960B is split into 4 blocks by DBG_CON_CHUNK_MAX");
|
||||
CHECK(con_uart_block_len[0] == 256U && con_uart_block_len[1] == 256U
|
||||
&& con_uart_block_len[2] == 256U && con_uart_block_len[3] == 192U,
|
||||
"TC-CONLOG-029 块长 256/256/256/192(单次发送上限真被执行)");
|
||||
"TC-CONLOG-029 block sizes 256/256/256/192 (the single-send ceiling is really enforced)");
|
||||
CHECK(con_uart_tx_n == 960U && con_uart_txe_reads == 960U,
|
||||
"TC-CONLOG-030 每字节恰好装载一次 DR(就绪即写,没有重复发)");
|
||||
"TC-CONLOG-030 every byte is loaded into DR exactly once (write when ready, no resend)");
|
||||
|
||||
reset_all();
|
||||
attach_writer();
|
||||
@@ -592,36 +592,36 @@ static void tc_ring(void)
|
||||
(void)dbg_console_write_line("[C] 33333\r\n", 11U);
|
||||
writer_drain();
|
||||
CHECK(tx_is(0U, "[A] 11111\r\n[B] 22222\r\n[C] 33333\r\n"),
|
||||
"TC-CONLOG-031 三个生产者各写一行 -> 上线仍是三行连续原文(G1 行级原子)");
|
||||
"TC-CONLOG-031 three producers, one line each -> the wire still shows three intact lines (G1 line atomicity)");
|
||||
CHECK(strstr((const char *)&con_uart_tx[5], "[B] 22222") != 0,
|
||||
"TC-CONLOG-032 行边界没被打断(没有任何一行被插进另一行中间)");
|
||||
"TC-CONLOG-032 no line boundary was broken (no line spliced into another)");
|
||||
|
||||
printf("-- TC-CONLOG-033..037 跨环尾:两段拷贝 + 按连续段分块 --\n");
|
||||
printf("-- TC-CONLOG-033..037 ring wrap: two-segment copy + chunking by contiguous run --\n");
|
||||
reset_all();
|
||||
attach_writer();
|
||||
s_con_head = 4090U;
|
||||
s_con_tail = 4090U;
|
||||
(void)dbg_console_write_line("0123456789ABCDEF", 16U);
|
||||
CHECK(s_con_head == 10U && used_now() == 16U,
|
||||
"TC-CONLOG-033 跨环尾入环后 head 回绕到 10(4090+16-4096)");
|
||||
"TC-CONLOG-033 a wrapped line leaves head at 10 (4090+16-4096)");
|
||||
CHECK(memcmp(&con_ring_store[4090], "012345", 6) == 0
|
||||
&& con_ring_store[0] == (uint8_t)'6' && con_ring_store[9] == (uint8_t)'F'
|
||||
&& con_ring_store[10] == 0U,
|
||||
"TC-CONLOG-034 回绕两段拷贝位置正确(前 6B 填到环尾、余 10B 从 0 起)");
|
||||
"TC-CONLOG-034 both wrap segments land correctly (first 6B fill to the ring end, remaining 10B start at 0)");
|
||||
writer_drain();
|
||||
CHECK(con_uart_block_n == 2U && con_uart_block_len[0] == 6U
|
||||
&& con_uart_block_len[1] == 10U,
|
||||
"TC-CONLOG-035 drain 按连续段分块:6 + 10(绝不把环中间当连续段读越界)");
|
||||
CHECK(tx_is(0U, "0123456789ABCDEF"), "TC-CONLOG-036 回绕行的上线内容与顺序都对");
|
||||
"TC-CONLOG-035 drain chunks by contiguous run: 6 + 10 (never reads past the ring end)");
|
||||
CHECK(tx_is(0U, "0123456789ABCDEF"), "TC-CONLOG-036 the wrapped line reaches the wire with correct content and order");
|
||||
|
||||
reset_all();
|
||||
attach_writer();
|
||||
/* 源缓冲必须给到 3000B:con_append 只钳长度,不会钳读取范围,
|
||||
* 拿 192B 的栈数组当 2048B 源就是越界读(插桩跑直接 0xC0000005) */
|
||||
memset(oversize, 'D', sizeof(oversize));
|
||||
CHECK(con_append(oversize, (uint16_t)3000U) == 0, "TC-CONLOG-037 直调 con_append 超长仍成功");
|
||||
CHECK(con_append(oversize, (uint16_t)3000U) == 0, "TC-CONLOG-037 calling con_append directly with an over-long buffer still succeeds");
|
||||
CHECK(used_now() == (DBG_CON_RING_SIZE / 2U),
|
||||
"TC-CONLOG-038 入环长度钳在 RING/2=2048(保证任何一行都恒可入环)");
|
||||
"TC-CONLOG-038 ring entry length is clamped to RING/2=2048 (so any line can always eventually enter)");
|
||||
}
|
||||
|
||||
/* ============ TC-CONLOG-040..042 写者自记录 / 重入 / 未注册 drain ============ */
|
||||
@@ -630,7 +630,7 @@ static void tc_writer_self(void)
|
||||
char line[DBG_CON_LINE_MAX];
|
||||
uint32_t i;
|
||||
|
||||
printf("-- TC-CONLOG-040..042 写者自记录先排空 / drain 重入保护 --\n");
|
||||
printf("-- TC-CONLOG-040..042 writer self-logging drains first / drain re-entry guard --\n");
|
||||
reset_all();
|
||||
attach_writer();
|
||||
memset(line, 'E', sizeof(line));
|
||||
@@ -638,11 +638,11 @@ static void tc_writer_self(void)
|
||||
(void)dbg_console_write_line(line, sizeof(line));
|
||||
}
|
||||
con_task_self = (TaskHandle_t)&s_task_writer; /* 写者自己记一行 */
|
||||
CHECK(dbg_console_write_line("F", 1U) == 1, "TC-CONLOG-040 写者自记录不丢行");
|
||||
CHECK(dbg_console_write_line("F", 1U) == 1, "TC-CONLOG-040 a writer logging about itself loses no line");
|
||||
CHECK(con_delay_calls == 0U,
|
||||
"TC-CONLOG-041 写者自记录先排空再入环:绝不进等待(否则就是等自己 -> 死锁)");
|
||||
"TC-CONLOG-041 writer self-logging drains before entering: it never waits (waiting for itself would deadlock)");
|
||||
CHECK(con_uart_tx_n == 4032U && used_now() == 1U && dbg_console_dropped() == 0U,
|
||||
"TC-CONLOG-042 老行全部上线、新行入环,零丢弃");
|
||||
"TC-CONLOG-042 old lines all reach the wire, the new line enters the ring, zero drops");
|
||||
|
||||
reset_all();
|
||||
attach_writer();
|
||||
@@ -650,56 +650,56 @@ static void tc_writer_self(void)
|
||||
s_con_draining = 1U; /* 模拟正处于 drain 之内 */
|
||||
writer_drain();
|
||||
CHECK(con_uart_tx_n == 0U && used_now() == 4U,
|
||||
"TC-CONLOG-043 drain 重入保护:嵌套调用直接让位(写者自记录不触发递归 drain)");
|
||||
"TC-CONLOG-043 drain re-entry guard: a nested call yields at once (writer self-logging causes no recursive drain)");
|
||||
|
||||
reset_all();
|
||||
(void)dbg_console_write_line("early\r\n", 7U); /* 未注册 -> 已直发 */
|
||||
con_uart_tx_n = 0U;
|
||||
writer_drain();
|
||||
CHECK(con_uart_tx_n == 0U, "TC-CONLOG-044 写者未注册时 drain 不做任何事");
|
||||
CHECK(con_uart_tx_n == 0U, "TC-CONLOG-044 with no writer attached drain does nothing");
|
||||
}
|
||||
|
||||
/* ============ TC-CONLOG-050..062 缓冲满 / 丢弃 / 可观测 ============ */
|
||||
static void tc_full_drop(void)
|
||||
{
|
||||
printf("-- TC-CONLOG-050..053 缓冲满:DWT 硬上界丢弃且不覆盖旧行 --\n");
|
||||
printf("-- TC-CONLOG-050..053 ring full: DWT hard ceiling drops without overwriting old lines --\n");
|
||||
reset_all();
|
||||
attach_writer();
|
||||
fill_ring(10U); /* 只剩 10B 可用 */
|
||||
con_dwt_step = SystemCoreClock / 4U; /* 一次判据 = 250ms > 200ms 上界 */
|
||||
CHECK(dbg_console_write_line("0123456789ABCDEFGHIJ", 20U) == -1,
|
||||
"TC-CONLOG-050 环满 + DWT 上界到 -> 丢这一行(返回 -1)");
|
||||
CHECK(dbg_console_dropped() == 1U, "TC-CONLOG-051 丢弃计数 +1");
|
||||
"TC-CONLOG-050 ring full + DWT ceiling reached -> this line is dropped (returns -1)");
|
||||
CHECK(dbg_console_dropped() == 1U, "TC-CONLOG-051 drop counter +1");
|
||||
CHECK(con_delay_calls == 0U,
|
||||
"TC-CONLOG-052 有 DWT 时用周期判据,不必先烧 200 个 tick(K4)");
|
||||
"TC-CONLOG-052 with DWT the cycle criterion is used, no need to burn 200 ticks first (K4)");
|
||||
CHECK(s_con_head == 4085U && used_now() == 4085U && con_uart_tx_n == 0U,
|
||||
"TC-CONLOG-053 丢弃不推进 head、也不生产者自己发(没半写、更没覆盖未发出的旧行)");
|
||||
"TC-CONLOG-053 a drop does not advance head and the producer does not send itself (no half write, no overwrite of pending lines)");
|
||||
|
||||
printf("-- TC-CONLOG-054..056 等待中出现空间 -> 入环成功 --\n");
|
||||
printf("-- TC-CONLOG-054..056 space appears while waiting -> line enters the ring --\n");
|
||||
reset_all();
|
||||
attach_writer();
|
||||
fill_ring(10U);
|
||||
con_dwt_step = 0U; /* 时间静止:只能靠写者腾地方 */
|
||||
con_delay_hook = bg_drain_hook; /* 每等一轮 = 写者排空一次 */
|
||||
CHECK(dbg_console_write_line("0123456789ABCDEFGHIJ", 20U) == 20,
|
||||
"TC-CONLOG-054 等一轮后腾出空间 -> 整行入环成功");
|
||||
"TC-CONLOG-054 after one wait round space frees up -> the whole line enters the ring");
|
||||
CHECK(con_delay_calls == 1U && dbg_console_dropped() == 0U,
|
||||
"TC-CONLOG-055 只等了一轮,且不算丢弃");
|
||||
"TC-CONLOG-055 only one wait round happened and it is not counted as a drop");
|
||||
con_delay_hook = 0;
|
||||
CHECK(con_uart_tx_n == 4085U, "TC-CONLOG-056 腾地方的正是写者(老行已上线)");
|
||||
CHECK(con_uart_tx_n == 4085U, "TC-CONLOG-056 it really was the writer that freed the space (old lines reached the wire)");
|
||||
|
||||
printf("-- TC-CONLOG-057..059 无 DWT 支路:等待上界 = DBG_CON_WAIT_MS 个 tick --\n");
|
||||
printf("-- TC-CONLOG-057..059 no-DWT branch: wait ceiling = DBG_CON_WAIT_MS ticks --\n");
|
||||
reset_all();
|
||||
con_dwt_ctrl_sticky = 0; /* 调试单元被关 -> DWT 使能失败 */
|
||||
attach_writer();
|
||||
fill_ring(10U);
|
||||
CHECK(s_con_dwt_up == 0U, "TC-CONLOG-057 DWT 使能失败时 s_con_dwt_up 保持 0");
|
||||
CHECK(s_con_dwt_up == 0U, "TC-CONLOG-057 s_con_dwt_up stays 0 when DWT enable fails");
|
||||
CHECK(dbg_console_write_line("0123456789ABCDEFGHIJ", 20U) == -1,
|
||||
"TC-CONLOG-058 无 DWT 时仍会丢(判据退回 tick 计数,不会无限等)");
|
||||
"TC-CONLOG-058 without DWT a drop still happens (criterion falls back to tick counting, never waits forever)");
|
||||
CHECK(con_delay_calls == DBG_CON_WAIT_MS && dbg_console_dropped() == 1U,
|
||||
"TC-CONLOG-059 无 DWT 的等待上界恰为 DBG_CON_WAIT_MS(200) 次 vTaskDelay");
|
||||
"TC-CONLOG-059 the no-DWT wait ceiling is exactly DBG_CON_WAIT_MS(200) vTaskDelay calls");
|
||||
|
||||
printf("-- TC-CONLOG-060..062 丢弃可观测:[ERR] 行直发不经环 --\n");
|
||||
printf("-- TC-CONLOG-060..062 drop observability: the [ERR] line is sent raw, not through the ring --\n");
|
||||
reset_all();
|
||||
attach_writer();
|
||||
fill_ring(10U);
|
||||
@@ -708,10 +708,10 @@ static void tc_full_drop(void)
|
||||
con_dwt_step = 0U;
|
||||
writer_drain();
|
||||
CHECK(tx_contains("[ERR] CONSOLE dropped 1 lines"),
|
||||
"TC-CONLOG-060 排空末尾刷出 [ERR] CONSOLE dropped 1 lines(丢行永不静默,@test 判 FAIL)");
|
||||
CHECK(dbg_console_dropped() == 0U, "TC-CONLOG-061 刷完即清零(下一轮不重复告警)");
|
||||
"TC-CONLOG-060 the drain tail flushes [ERR] CONSOLE dropped 1 lines (loss is never silent, @test marks FAIL)");
|
||||
CHECK(dbg_console_dropped() == 0U, "TC-CONLOG-061 the counter is cleared once flushed (next round does not repeat the warning)");
|
||||
CHECK(used_now() == 0U,
|
||||
"TC-CONLOG-062 告警行走裸发:不入环 -> 不会 con_append->drain 递归");
|
||||
"TC-CONLOG-062 the warning goes out raw: not through the ring -> no con_append->drain recursion");
|
||||
}
|
||||
/* ============ TC-CONLOG-070..081 TX 僵尸通道:自愈 / 冷却 / 半块 ============ */
|
||||
|
||||
@@ -729,21 +729,21 @@ static void fault_setup(uint32_t tick0, int repair)
|
||||
|
||||
static void tc_tx_fault(void)
|
||||
{
|
||||
printf("-- TC-CONLOG-070..074 软复位没治好:故障即止 + 留痕只能靠标志 --\n");
|
||||
printf("-- TC-CONLOG-070..074 soft reset did not heal: stop at the fault + trace only via flag --\n");
|
||||
reset_all();
|
||||
fault_setup(5000U, 0);
|
||||
CHECK(dbg_console_tx_fault() == 1U, "TC-CONLOG-070 发送超时 -> tx_fault 计数 +1");
|
||||
CHECK(dbg_console_tx_fault() == 1U, "TC-CONLOG-070 send timeout -> tx_fault counter +1");
|
||||
CHECK(s_mx_init_calls == 1U && con_nvic_clears == 1U
|
||||
&& con_rcc_disables == 1U && con_rcc_enables == 1U,
|
||||
"TC-CONLOG-071 自愈完整一遍:清 pending -> 断时钟 -> 供时钟 -> 重初始化");
|
||||
"TC-CONLOG-071 full self-heal sequence: clear pending -> gate off clock -> gate on clock -> re-init");
|
||||
CHECK(used_now() == (DBG_CON_RING_SIZE - 1U) - DBG_CON_CHUNK_MAX,
|
||||
"TC-CONLOG-072 故障即止:只丢当前 256B 块,其余留环里等下轮(让位喂狗)");
|
||||
"TC-CONLOG-072 stop at the fault: only the current 256B block is lost, the rest waits in the ring (yields to the watchdog)");
|
||||
CHECK(con_uart_tx_n == 0U,
|
||||
"TC-CONLOG-073 通道没治好时连那条 WARN 也上不了线(裸发同样有界、不重试)");
|
||||
"TC-CONLOG-073 while the channel is unhealed even that WARN cannot get out (raw send is bounded too, no retry)");
|
||||
CHECK(dbg_console_tx_fault_log_take() == 1U && dbg_console_tx_fault_log_take() == 0U,
|
||||
"TC-CONLOG-074 留痕标志读后清:写者据此在 drain 之外补记 run.log(断调用图成环)");
|
||||
"TC-CONLOG-074 the trace flag is read-then-clear: the writer uses it to append run.log outside drain (breaks the call graph cycle)");
|
||||
|
||||
printf("-- TC-CONLOG-075..077 软复位治好了:WARN 上线且只一次 --\n");
|
||||
printf("-- TC-CONLOG-075..077 soft reset healed: the WARN goes out exactly once --\n");
|
||||
reset_all();
|
||||
con_tick_now = 7000U;
|
||||
attach_writer();
|
||||
@@ -752,14 +752,14 @@ static void tc_tx_fault(void)
|
||||
con_dwt_step = SystemCoreClock / 4U;
|
||||
s_mx_repair = 1; /* 重初始化把通道治好 */
|
||||
writer_drain();
|
||||
CHECK(tx_contains("[WARN] CONSOLE tx fault"), "TC-CONLOG-075 首次故障的 WARN 行成功上线");
|
||||
CHECK(tx_contains("[WARN] CONSOLE tx fault"), "TC-CONLOG-075 the first fault WARN line reaches the wire");
|
||||
CHECK(used_now() == 0U && s_con_cool_until == 7000U && dbg_console_tx_fault() == 1U,
|
||||
"TC-CONLOG-076 故障块丢弃(行已出环不可重放)+ 冷却截止记为当时 tick");
|
||||
"TC-CONLOG-076 the faulted block is dropped (already out of the ring, not replayable) + cooldown deadline is the tick then");
|
||||
con_uart_txe_ready_left = -1;
|
||||
con_dwt_step = 0U;
|
||||
writer_drain(); /* tick 未推进 -> 仍在冷却 */
|
||||
CHECK(s_con_cool_until == 7000U && s_mx_init_calls == 1U,
|
||||
"TC-CONLOG-077 冷却期内 drain 直接让位:不重试、不自愈第二次");
|
||||
"TC-CONLOG-077 during cooldown drain yields at once: no retry, no second self-heal");
|
||||
}
|
||||
|
||||
static void tc_tx_cool(void)
|
||||
@@ -768,36 +768,36 @@ static void tc_tx_cool(void)
|
||||
reset_all();
|
||||
fault_setup(7000U, 1); /* 治好的那次故障 */
|
||||
CHECK(s_con_cool_until == 7000U && used_now() == 3839U,
|
||||
"TC-CONLOG-078 故障后剩 3839B 在环里(本块被丢)");
|
||||
"TC-CONLOG-078 3839B remain in the ring after the fault (this block was dropped)");
|
||||
con_dwt_step = 0U;
|
||||
con_uart_txe_stuck = 0;
|
||||
con_tick_now = 7299U; /* 差 1ms */
|
||||
writer_drain();
|
||||
CHECK(s_con_cool_until == 7000U && used_now() == 3839U && s_mx_init_calls == 1U,
|
||||
"TC-CONLOG-079 差 1ms 仍在冷却:环不动、不重复自愈(冷却即节奏保护)");
|
||||
"TC-CONLOG-079 1ms short of the deadline: the ring does not move and no repeated self-heal (cooldown is the pacing guard)");
|
||||
con_tick_now = 7300U; /* 到点 */
|
||||
writer_drain();
|
||||
CHECK(s_con_cooling == 0U && used_now() == 0U && dbg_console_tx_fault() == 1U,
|
||||
"TC-CONLOG-080 到点即清冷却标志、放行本轮排空,且没有新增故障"
|
||||
"(cool_until 只存时刻,不再被拿来当哨兵清零)");
|
||||
"TC-CONLOG-080 at the deadline the flag clears, this round drains, and no new fault appears"
|
||||
" (cool_until only stores a deadline and is no longer used as a clear-on-zero sentinel)");
|
||||
|
||||
/* 修复后的正向断言:冷却与否看独立标志,不再拿 tick 值当哨兵 */
|
||||
reset_all();
|
||||
fault_setup(0U, 0); /* 故障恰好落在 HAL_GetTick()==0 那一拍 */
|
||||
CHECK(s_con_cooling == 1U && dbg_console_tx_fault() == 1U,
|
||||
"TC-CONLOG-081 tick==0 那拍的故障照样进入冷却(独立标志,不撞 0 哨兵)");
|
||||
"TC-CONLOG-081 a fault in the tick==0 round still enters cooldown (own flag, no zero sentinel collision)");
|
||||
writer_drain(); /* tick 仍是 0 */
|
||||
CHECK(dbg_console_tx_fault() == 1U && s_mx_init_calls == 1U
|
||||
&& used_now() == (DBG_CON_RING_SIZE - 1U) - DBG_CON_CHUNK_MAX,
|
||||
"TC-CONLOG-082 同一 tick 上再来一轮被冷却挡住:不再白耗一次块超时");
|
||||
"TC-CONLOG-082 another round on the same tick is blocked by cooldown: no second wasted block timeout");
|
||||
con_tick_now = DBG_CON_FAULT_COOL_MS - 1U;
|
||||
writer_drain();
|
||||
CHECK(dbg_console_tx_fault() == 1U, "TC-CONLOG-083 冷却 299ms 仍未到点");
|
||||
CHECK(dbg_console_tx_fault() == 1U, "TC-CONLOG-083 299ms is still inside the cooldown");
|
||||
con_uart_txe_stuck = 0;
|
||||
con_tick_now = DBG_CON_FAULT_COOL_MS; /* 到点(且回绕起点正好是 0) */
|
||||
writer_drain();
|
||||
CHECK(s_con_cooling == 0U && used_now() == 0U && dbg_console_tx_fault() == 1U,
|
||||
"TC-CONLOG-084 到点后清冷却并放行:全程没有第二次故障");
|
||||
"TC-CONLOG-084 after the deadline the cooldown clears and passes through: no second fault anywhere");
|
||||
|
||||
reset_all();
|
||||
attach_writer();
|
||||
@@ -816,16 +816,16 @@ static void tc_tx_cool(void)
|
||||
|
||||
static void tc_tx_half(void)
|
||||
{
|
||||
printf("-- TC-CONLOG-085..088 超时判据的真实后果:半块 / 已上线仍判失败 --\n");
|
||||
printf("-- TC-CONLOG-085..088 real consequences of the timeout criterion: half block / already sent yet failed --\n");
|
||||
reset_all();
|
||||
attach_writer();
|
||||
(void)dbg_console_write_line("ABCDEFGH", 8U);
|
||||
con_uart_tc_stuck = 1; /* 字节都进了 DR,只有 TC 不置位 */
|
||||
con_dwt_step = SystemCoreClock / 4U;
|
||||
writer_drain();
|
||||
CHECK(tx_is(0U, "ABCDEFGH"), "TC-CONLOG-085 TC 卡死:8 字节都已上线");
|
||||
CHECK(tx_is(0U, "ABCDEFGH"), "TC-CONLOG-085 TC stuck: all 8 bytes were handed to the shifter");
|
||||
CHECK(dbg_console_tx_fault() == 1U && con_uart_block_n == 0U,
|
||||
"TC-CONLOG-086 已上线仍整块判失败(docs §13-O2:丢弃/故障两本账没分开的现状)");
|
||||
"TC-CONLOG-086 already on the wire but the whole block still counts as failed (docs section 13-O2: drop and fault books were not separated)");
|
||||
|
||||
reset_all();
|
||||
attach_writer();
|
||||
@@ -833,50 +833,50 @@ static void tc_tx_half(void)
|
||||
con_uart_txe_ready_left = 3; /* 只挤得出 3 个字节 */
|
||||
con_dwt_step = SystemCoreClock / 4U;
|
||||
writer_drain();
|
||||
CHECK(tx_is(0U, "ABC"), "TC-CONLOG-087 TXE 中途卡死 -> 只有已写进 DR 的 3 字节上线");
|
||||
CHECK(tx_is(0U, "ABC"), "TC-CONLOG-087 TXE stuck mid-block -> only the 3 bytes already written to DR reach the wire");
|
||||
CHECK(dbg_console_tx_fault() == 1U && used_now() == 0U,
|
||||
"TC-CONLOG-088 半块同样走自愈分支,整块出环(尾部 5 字节随块作废)");
|
||||
"TC-CONLOG-088 a half block takes the same self-heal branch and leaves the ring (trailing 5 bytes die with the block)");
|
||||
}
|
||||
|
||||
/* ============ TC-CONLOG-090..099 DWT 使能 / 指令计数上界 ============ */
|
||||
static void tc_dwt(void)
|
||||
{
|
||||
printf("-- TC-CONLOG-090..093 DWT 惰性使能与就绪即走 --\n");
|
||||
printf("-- TC-CONLOG-090..093 lazy DWT enable and skip-when-ready --\n");
|
||||
reset_all();
|
||||
(void)dbg_console_write_line("ok\r\n", 4U); /* 走一次直发 -> 顺带使能 DWT */
|
||||
CHECK(s_con_dwt_up == 1U, "TC-CONLOG-090 con_dwt_ensure 成功使能后置 s_con_dwt_up");
|
||||
CHECK(s_con_dwt_up == 1U, "TC-CONLOG-090 con_dwt_ensure sets s_con_dwt_up after a successful enable");
|
||||
CHECK((g_con_core_debug.DEMCR & CoreDebug_DEMCR_TRCENA_Msk) != 0U,
|
||||
"TC-CONLOG-091 真的写了 DEMCR.TRCENA(位号与 core_cm4.h 一致)");
|
||||
"TC-CONLOG-091 DEMCR.TRCENA really gets written (bit number matches core_cm4.h)");
|
||||
CHECK((g_con_dwt.CTRL & DWT_CTRL_CYCCNTENA_Msk) != 0U,
|
||||
"TC-CONLOG-092 真的写了 DWT.CTRL.CYCCNTENA");
|
||||
"TC-CONLOG-092 DWT.CTRL.CYCCNTENA really gets written");
|
||||
CHECK(tx_is(0U, "ok\r\n") && con_dwt_reads == 4U,
|
||||
"TC-CONLOG-093 通道就绪时发送循环没再读 CYCCNT(3 次 ensure + 1 次取基准 t0)");
|
||||
"TC-CONLOG-093 with the channel ready the send loop reads no further CYCCNT (3 from ensure + 1 for t0)");
|
||||
|
||||
printf("-- TC-CONLOG-094..097 DWT 使能失败 -> con_tx_counted 计数上界 --\n");
|
||||
printf("-- TC-CONLOG-094..097 DWT enable failure -> con_tx_counted instruction ceiling --\n");
|
||||
reset_all();
|
||||
con_dwt_ctrl_sticky = 0; /* CYCCNTENA 写不进去 */
|
||||
con_uart_txe_stuck = 1;
|
||||
dbg_console_write_raw("Q", 1U);
|
||||
CHECK(s_con_dwt_up == 0U, "TC-CONLOG-094 DWT 使能失败 -> 走计数上界支路");
|
||||
CHECK(s_con_dwt_up == 0U, "TC-CONLOG-094 DWT enable failure -> the counted-guard branch is taken");
|
||||
CHECK(con_uart_txe_reads == CON_TX_GUARD_MAX,
|
||||
"TC-CONLOG-095 每字节最多自旋 CON_TX_GUARD_MAX(20000) 次即放弃(有界,非死等)");
|
||||
CHECK(con_uart_tx_n == 0U, "TC-CONLOG-096 计数上界内没发出去就整块放弃");
|
||||
"TC-CONLOG-095 each byte spins at most CON_TX_GUARD_MAX(20000) times then gives up (bounded, not a dead wait)");
|
||||
CHECK(con_uart_tx_n == 0U, "TC-CONLOG-096 if the block is not out within the counted ceiling the whole block is abandoned");
|
||||
CHECK(con_dwt_reads == 3U,
|
||||
"TC-CONLOG-097 计数支路一次都不读 CYCCNT(不依赖 DWT,也就不依赖时间源)");
|
||||
"TC-CONLOG-097 the counted branch never reads CYCCNT (independent of DWT, hence of any time source)");
|
||||
|
||||
printf("-- TC-CONLOG-098..099 超时判据不依赖 HAL_GetTick(round 8b 的动机) --\n");
|
||||
printf("-- TC-CONLOG-098..099 the timeout criterion does not use HAL_GetTick (round 8b motivation) --\n");
|
||||
reset_all();
|
||||
con_uart_txe_stuck = 1; /* tick 冻结在 0,模拟 TIM7 停摆 */
|
||||
con_dwt_step = SystemCoreClock / 10U; /* 一次判据正好 = 100ms 上界 */
|
||||
dbg_console_write_raw("Q", 1U);
|
||||
CHECK(con_tick_reads == 0U && con_uart_tx_n == 0U,
|
||||
"TC-CONLOG-098 tick 完全不走也能退出:裸发一次都没读 HAL_GetTick");
|
||||
"TC-CONLOG-098 it exits even when tick never advances: one raw send reads HAL_GetTick zero times");
|
||||
reset_all();
|
||||
con_uart_txe_stuck = 1;
|
||||
con_dwt_step = SystemCoreClock / 4U;
|
||||
dbg_console_write_raw("Z", 1U);
|
||||
CHECK(con_uart_txe_reads == 1U,
|
||||
"TC-CONLOG-099 DWT 支路第一次自旋就判超时(上界真的起作用,不会拖满 20000 次)");
|
||||
"TC-CONLOG-099 the DWT branch declares timeout on the first spin (the ceiling really works, never burns 20000)");
|
||||
}
|
||||
|
||||
/* ============ TC-CONLOG-100..106 huart1.Instance == NULL 短路 + 未初始化分诊 ============ */
|
||||
@@ -887,14 +887,14 @@ static void tc_null_uart(void)
|
||||
huart1.Instance = 0;
|
||||
dbg_console_write_raw("boom", 5U);
|
||||
CHECK(con_uart_tx_n == 0U && con_uart_txe_reads == 0U,
|
||||
"TC-CONLOG-100 Instance==NULL 时一次寄存器都不碰(不解引用地址 0)");
|
||||
"TC-CONLOG-100 with Instance==NULL not one register is touched (no dereference of address 0)");
|
||||
CHECK(con_dwt_reads == 3U,
|
||||
"TC-CONLOG-101 仍然先惰性使能 DWT 再短路(ensure 在判空之前,顺序照旧)");
|
||||
"TC-CONLOG-101 DWT is still lazily enabled before the short circuit (ensure stays ahead of the NULL check)");
|
||||
|
||||
reset_all();
|
||||
huart1.Instance = 0;
|
||||
CHECK(dbg_console_write_line("early", 5U) == 5,
|
||||
"TC-CONLOG-102 未注册路径(内核前)撞上无串口也不崩、仍返回行长");
|
||||
"TC-CONLOG-102 the unattached path (pre-kernel) survives a missing UART and still returns the line length");
|
||||
|
||||
/* 修复后的正向断言:未初始化 != 僵尸通道,绝不重配外设 */
|
||||
reset_all();
|
||||
@@ -920,26 +920,26 @@ static void tc_null_uart(void)
|
||||
/* ============ TC-CONLOG-110..115 fputc 重定向 ============ */
|
||||
static void tc_fputc(void)
|
||||
{
|
||||
printf("-- TC-CONLOG-110..115 fputc 重定向(printf 遗留路径) --\n");
|
||||
printf("-- TC-CONLOG-110..115 fputc retarget (legacy printf path) --\n");
|
||||
reset_all();
|
||||
CHECK(con_fputc_under_test('Q', stdout) == 'Q', "TC-CONLOG-110 fputc 原样返回字符(C 库约定)");
|
||||
CHECK(con_fputc_under_test('Q', stdout) == 'Q', "TC-CONLOG-110 fputc returns the character unchanged (C library convention)");
|
||||
CHECK(tx_is(0U, "Q") && used_now() == 0U,
|
||||
"TC-CONLOG-111 未注册写者:printf 的字节直发(与旧行为一致)");
|
||||
"TC-CONLOG-111 writer not attached: printf bytes go out directly (same as the old behaviour)");
|
||||
|
||||
reset_all();
|
||||
attach_writer();
|
||||
(void)con_fputc_under_test('R', stdout);
|
||||
CHECK(con_uart_tx_n == 0U && used_now() == 1U && con_ring_store[0] == (uint8_t)'R',
|
||||
"TC-CONLOG-112 注册后 fputc 也收敛到单写者路径(逐字节入环)");
|
||||
"TC-CONLOG-112 after attach fputc also funnels into the single-writer path (byte by byte into the ring)");
|
||||
writer_drain();
|
||||
CHECK(tx_is(0U, "R"), "TC-CONLOG-113 写者把 printf 字节发出");
|
||||
CHECK(tx_is(0U, "R"), "TC-CONLOG-113 the writer sends those printf bytes");
|
||||
|
||||
reset_all();
|
||||
attach_writer();
|
||||
con_ipsr = 12U; /* 假异常号:任意非 0 */
|
||||
CHECK(dbg_console_write_line("ISR", 3U) == 3, "TC-CONLOG-114 中断上下文写整行返回行长");
|
||||
CHECK(dbg_console_write_line("ISR", 3U) == 3, "TC-CONLOG-114 writing a whole line from interrupt context returns the line length");
|
||||
CHECK(tx_is(0U, "ISR") && used_now() == 0U && con_delay_calls == 0U,
|
||||
"TC-CONLOG-115 中断上下文一律裸发:不入环、不等待(否则在 ISR 里睡死)");
|
||||
"TC-CONLOG-115 interrupt context always sends raw: no ring entry, no waiting (else it sleeps inside the ISR)");
|
||||
|
||||
reset_all();
|
||||
attach_writer();
|
||||
@@ -947,59 +947,59 @@ static void tc_fputc(void)
|
||||
con_ipsr = 5U;
|
||||
con_dwt_step = SystemCoreClock / 4U;
|
||||
CHECK(dbg_console_write_line("0123456789", 10U) == 10,
|
||||
"TC-CONLOG-116 环全满 + 中断上下文:仍直发成功(ISR 绝不进丢弃等待)");
|
||||
"TC-CONLOG-116 ring completely full + interrupt context: still sends directly (an ISR never enters the drop wait)");
|
||||
CHECK(dbg_console_dropped() == 0U && con_delay_calls == 0U,
|
||||
"TC-CONLOG-117 这条路径既不丢行也不记丢弃(K1:内核前/ISR 不依赖任何内核对象)");
|
||||
"TC-CONLOG-117 this path loses no line and records no drop (K1: pre-kernel and ISR depend on no kernel object)");
|
||||
}
|
||||
|
||||
/* ============ TC-CONLOG-120..122 drain 250ms 预算 ============ */
|
||||
static void tc_budget(void)
|
||||
{
|
||||
printf("-- TC-CONLOG-120..122 单次 drain 预算 250ms(让位喂狗轮询) --\n");
|
||||
printf("-- TC-CONLOG-120..122 single drain budget 250ms (yields to the watchdog poll) --\n");
|
||||
reset_all();
|
||||
attach_writer();
|
||||
fill_ring(0U); /* 4095B = 16 块 */
|
||||
con_tick_step = 130U; /* 每次读 tick 走 130ms */
|
||||
writer_drain();
|
||||
CHECK(con_uart_block_n == 2U, "TC-CONLOG-120 一轮只发 2 块就因预算让位(不是发完)");
|
||||
CHECK(con_uart_block_n == 2U, "TC-CONLOG-120 one round sends only 2 blocks then yields on budget (not because it finished)");
|
||||
CHECK(used_now() == (DBG_CON_RING_SIZE - 1U) - (2U * DBG_CON_CHUNK_MAX),
|
||||
"TC-CONLOG-121 让位时余下 3583B 留在环里(下轮续排,不丢)");
|
||||
"TC-CONLOG-121 when it yields, 3583B remain in the ring (next round continues, nothing lost)");
|
||||
con_tick_step = 0U;
|
||||
writer_drain(); /* 预算内发完余下 3583B */
|
||||
CHECK(used_now() == 0U && con_uart_tx_n == (DBG_CON_RING_SIZE - 1U),
|
||||
"TC-CONLOG-122 下轮把余下的 3583B 也发完:预算让位不丢字节(累计 4095)");
|
||||
"TC-CONLOG-122 the next round sends the remaining 3583B too: yielding on budget loses no bytes (4095 total)");
|
||||
}
|
||||
|
||||
/* ============ TC-CONLOG-130..135 计数支路的成功路径 / TC 抖动 / 直调 NULL ============ */
|
||||
static void tc_counted_paths(void)
|
||||
{
|
||||
printf("-- TC-CONLOG-130..132 DWT 不可用 -> con_tx_counted 也能发全(不只会超时) --\n");
|
||||
printf("-- TC-CONLOG-130..132 DWT unavailable -> con_tx_counted can also finish a block (not only time out) --\n");
|
||||
reset_all();
|
||||
con_dwt_ctrl_sticky = 0; /* CYCCNTENA 落不住 */
|
||||
con_tick_now = 9000U; /* tick 冻结:证明与本支路无关 */
|
||||
dbg_console_write_raw("AB", 2U);
|
||||
CHECK(s_con_dwt_up == 0U && tx_is(0U, "AB"),
|
||||
"TC-CONLOG-130 计数支路把整块发完并返回成功(回退路径没退化)");
|
||||
"TC-CONLOG-130 the counted branch sends the whole block and returns success (fallback path did not regress)");
|
||||
CHECK(con_uart_tc_reads == 1U && con_dwt_reads == 3U && con_tick_reads == 0U,
|
||||
"TC-CONLOG-131 计数支路既不等 tick 也不再读 CYCCNT(零外部时间源依赖)");
|
||||
"TC-CONLOG-131 the counted branch waits no tick and reads no CYCCNT (zero external time source)");
|
||||
|
||||
reset_all();
|
||||
con_dwt_ctrl_sticky = 0;
|
||||
con_uart_tc_stuck = 1; /* 字节能进 DR,TC 永不置位 */
|
||||
dbg_console_write_raw("CD", 2U);
|
||||
CHECK(tx_is(0U, "CD") && con_uart_tc_reads == CON_TX_GUARD_MAX,
|
||||
"TC-CONLOG-132 TC 卡死时计数支路同样最多自旋 CON_TX_GUARD_MAX 次即放弃");
|
||||
"TC-CONLOG-132 with TC stuck the counted branch also gives up after at most CON_TX_GUARD_MAX spins");
|
||||
|
||||
printf("-- TC-CONLOG-133..135 DWT 支路 TC 抖动 / con_append 直调参数校验 --\n");
|
||||
printf("-- TC-CONLOG-133..135 DWT branch TC jitter / con_append direct-call argument checks --\n");
|
||||
reset_all();
|
||||
con_dwt_step = 1U; /* 时间走得极慢:不会误判超时 */
|
||||
con_uart_tc_after = 2; /* 前两轮 TC 不就绪 */
|
||||
dbg_console_write_raw("EF", 2U);
|
||||
CHECK(tx_is(0U, "EF") && con_uart_tc_reads == 3U,
|
||||
"TC-CONLOG-133 TC 抖动(未超上界)后仍算整块成功:TC 循环能正常退出");
|
||||
"TC-CONLOG-133 TC jitter (below the ceiling) still ends as a successful block: the TC loop exits normally");
|
||||
reset_all();
|
||||
CHECK(con_append(0, 3U) == -1, "TC-CONLOG-134 con_append(NULL) 自己也要挡住(不只靠上层)");
|
||||
CHECK(con_append("abc", 0U) == -1, "TC-CONLOG-135 con_append(len=0) 同样拒绝");
|
||||
CHECK(con_append(0, 3U) == -1, "TC-CONLOG-134 con_append(NULL) must block it itself (not only relying on the caller)");
|
||||
CHECK(con_append("abc", 0U) == -1, "TC-CONLOG-135 con_append(len=0) is rejected the same way");
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user