refactor(编号): 16 个测试模块码单词化 + 门禁识别面连带放宽
批 2(用户授权改名 + 「新名要一眼看懂」裁定)
- 16 个有歧义模块码单词化,共 1,146 处随 scripts/rename_ids.py 改写:
AI→ADCIN、AH→ADCHEALTH、PS→PROTSET、PE→PROTELEM、PH→PHASOR、
TS→TIMESYNC、VL→VOLLOCK、NP→NANDPORT、CFG→CONFIG、CLK→SYSCLK、
WD→WATCHDOG、STO→STORAGE、SH→SHA256、FA→FTPAUTH、FR→FREQ、104→IEC104
- 不动 NET/GD5F/RTC/SOE/UI/ADC/LOG/RS485/TOOL(已是单词、芯片名或业界通用词,
改了纯属 churn)
- 别名按全局登记:这批字面量已完全限定(TC-<码>-<nnn>),不存在裸形多义
- 映射表存档 scripts/rename_maps/batch2.json 作审计轨迹;§6 模块码表同步
连带修门禁(关键教训)
- 模块码涨到 9 位(ADCHEALTH/WATCHDOG)后,候选正则与族正则的 {0,4} 上界
会让改名后的号**整批从门禁眼里消失**:实测编号字面量从 8271 掉到 7315、
悬空假降 490 处。已放宽到 {0,9} 并写进 §6 注记
- 结论:改名批次必须连带复核识别面,只改数据不改判据 = 静默放行;
这次是靠「可判定比例跌破基线即失败」那条线拦下来的
现状与遗留
- 校验 1 未登记前缀 0 处;可判定比例 82.71%(基线 82.6%,只涨不跌成立)
- 遗留:7 个模块的「单元测试说明.md」仍缺(PROTSET 116、NANDPORT 109、
PROTELEM 65、FREQ 48、FTPAUTH 45、SHA256 25、SOE 14 处悬空)——改名不解决
缺文档,处置方式待议
- 遗留:T-2/T-3/T-4/T-6 历史任务号悬空(别名表未收全,属本工具批次漏项)
- 未改任何 C/H 可编译语义(仅注释与宏名内的编号),故不需 @build
This commit is contained in:
@@ -14,17 +14,17 @@
|
||||
* 3. 不占 MCU 的 RAM,毫秒级完成。
|
||||
*
|
||||
* 覆盖点(对应 docs/算法/继电保护功能复现规划.md §3.1 L1-6):
|
||||
* TC-AH-001 init + 首拍只建基线(不误报)
|
||||
* TC-AH-002 正常 1 kHz 推进 2000 拍:零故障零事件(健康不误报)
|
||||
* TC-AH-003 TPAFE 静默:99ms 不报 / 100ms 报 / 恢复清除电平位、锁存位留痕
|
||||
* TC-AH-004 STM32 静默:TPAFE 正常时只报 STM32 侧
|
||||
* TC-AH-005 TPAFE 丢帧:d=3 → tgap+=2、事件仅当拍(边沿语义)
|
||||
* TC-AH-006 STM32 gap 计数增量 → 事件(不入锁存:超拍非故障)
|
||||
* TC-AH-007 序号倒退 → SEQ_BACKWARD 锁存(前进后仍留痕)
|
||||
* TC-AH-008 FRSTDATA / STM32_ERR / HW_ERR 增量 → 事件位与锁存位编号一致
|
||||
* TC-AH-009 tick 回绕:跨 0xFFFFFFFF 的正常推进不误报静默;回绕后冻结仍报
|
||||
* TC-AH-010 NULL 守卫:in=NULL 跳过;out=NULL 只更新内部状态
|
||||
* TC-AH-011 init 幂等:故障后 re-init 全清
|
||||
* TC-ADCHEALTH-001 init + 首拍只建基线(不误报)
|
||||
* TC-ADCHEALTH-002 正常 1 kHz 推进 2000 拍:零故障零事件(健康不误报)
|
||||
* TC-ADCHEALTH-003 TPAFE 静默:99ms 不报 / 100ms 报 / 恢复清除电平位、锁存位留痕
|
||||
* TC-ADCHEALTH-004 STM32 静默:TPAFE 正常时只报 STM32 侧
|
||||
* TC-ADCHEALTH-005 TPAFE 丢帧:d=3 → tgap+=2、事件仅当拍(边沿语义)
|
||||
* TC-ADCHEALTH-006 STM32 gap 计数增量 → 事件(不入锁存:超拍非故障)
|
||||
* TC-ADCHEALTH-007 序号倒退 → SEQ_BACKWARD 锁存(前进后仍留痕)
|
||||
* TC-ADCHEALTH-008 FRSTDATA / STM32_ERR / HW_ERR 增量 → 事件位与锁存位编号一致
|
||||
* TC-ADCHEALTH-009 tick 回绕:跨 0xFFFFFFFF 的正常推进不误报静默;回绕后冻结仍报
|
||||
* TC-ADCHEALTH-010 NULL 守卫:in=NULL 跳过;out=NULL 只更新内部状态
|
||||
* TC-ADCHEALTH-011 init 幂等:故障后 re-init 全清
|
||||
*
|
||||
* 通过:全部 TC PASS(main 返回 0)。
|
||||
* 入口:int main(void),返回 0=PASS / 1=FAIL(由 run 脚本判读)。
|
||||
@@ -66,7 +66,7 @@ static adc_health_in_t mk_in(uint32_t seq, uint32_t now_ms) {
|
||||
|
||||
/* ===================== TC ===================== */
|
||||
|
||||
/* TC-AH-001:init + 首拍只建基线 */
|
||||
/* TC-ADCHEALTH-001:init + 首拍只建基线 */
|
||||
static void tc_prime(void) {
|
||||
adc_health_in_t in;
|
||||
adc_health_status_t st;
|
||||
@@ -76,14 +76,14 @@ static void tc_prime(void) {
|
||||
adc_health_check(&in, &st);
|
||||
CHECK((st.flags == 0u) && (st.events == 0u) && (st.sticky == 0u) &&
|
||||
(st.tpafe_gaps == 0u),
|
||||
"TC-AH-001 first check only primes: no flags/events/sticky");
|
||||
"TC-ADCHEALTH-001 first check only primes: no flags/events/sticky");
|
||||
/* 第二拍序号未动但仅 1ms(< 门限)→ 仍不报 */
|
||||
in.now_ms = 1001u;
|
||||
adc_health_check(&in, &st);
|
||||
CHECK(st.flags == 0u, "TC-AH-001 1ms without advance is not a stall");
|
||||
CHECK(st.flags == 0u, "TC-ADCHEALTH-001 1ms without advance is not a stall");
|
||||
}
|
||||
|
||||
/* TC-AH-002:正常 1 kHz 推进 2000 拍零误报 */
|
||||
/* TC-ADCHEALTH-002:正常 1 kHz 推进 2000 拍零误报 */
|
||||
static void tc_healthy(void) {
|
||||
adc_health_status_t st;
|
||||
adc_health_in_t in;
|
||||
@@ -100,10 +100,10 @@ static void tc_healthy(void) {
|
||||
seq++;
|
||||
now++;
|
||||
}
|
||||
CHECK(ok, "TC-AH-002 healthy 1kHz sweep 2000 beats: zero flags/events");
|
||||
CHECK(ok, "TC-ADCHEALTH-002 healthy 1kHz sweep 2000 beats: zero flags/events");
|
||||
}
|
||||
|
||||
/* TC-AH-003:TPAFE 静默 99/100ms 门限 + 恢复留痕 */
|
||||
/* TC-ADCHEALTH-003:TPAFE 静默 99/100ms 门限 + 恢复留痕 */
|
||||
static void tc_tpafe_stall(void) {
|
||||
adc_health_status_t st;
|
||||
adc_health_in_t in;
|
||||
@@ -127,28 +127,28 @@ static void tc_tpafe_stall(void) {
|
||||
now++;
|
||||
}
|
||||
CHECK((st.flags & ADC_HF_TPAFE_STALL) == 0u,
|
||||
"TC-AH-003 no TPAFE stall before 100ms");
|
||||
"TC-ADCHEALTH-003 no TPAFE stall before 100ms");
|
||||
/* 第 100ms:报 */
|
||||
in = mk_in(seq, now);
|
||||
in.stm32_seq = seq + 100u;
|
||||
adc_health_check(&in, &st);
|
||||
CHECK((st.flags & ADC_HF_TPAFE_STALL) != 0u,
|
||||
"TC-AH-003 TPAFE stall at 100ms");
|
||||
"TC-ADCHEALTH-003 TPAFE stall at 100ms");
|
||||
CHECK((st.sticky & ADC_HF_TPAFE_STALL) != 0u,
|
||||
"TC-AH-003 stall latched into sticky");
|
||||
"TC-ADCHEALTH-003 stall latched into sticky");
|
||||
CHECK(st.tpafe_stall_ms >= ADC_HEALTH_STALL_MS,
|
||||
"TC-AH-003 stall_ms reported >= threshold");
|
||||
"TC-ADCHEALTH-003 stall_ms reported >= threshold");
|
||||
/* 恢复:TPAFE 序号重新前进 → 电平位清除、sticky 留痕 */
|
||||
in = mk_in(seq + 1u, now + 1u);
|
||||
in.stm32_seq = seq + 101u;
|
||||
adc_health_check(&in, &st);
|
||||
CHECK((st.flags & ADC_HF_TPAFE_STALL) == 0u,
|
||||
"TC-AH-003 stall level clears on recovery");
|
||||
"TC-ADCHEALTH-003 stall level clears on recovery");
|
||||
CHECK((adc_health_sticky() & ADC_HF_TPAFE_STALL) != 0u,
|
||||
"TC-AH-003 sticky keeps the fault trace after recovery");
|
||||
"TC-ADCHEALTH-003 sticky keeps the fault trace after recovery");
|
||||
}
|
||||
|
||||
/* TC-AH-004:STM32 静默(TPAFE 正常) */
|
||||
/* TC-ADCHEALTH-004:STM32 静默(TPAFE 正常) */
|
||||
static void tc_stm32_stall(void) {
|
||||
adc_health_status_t st;
|
||||
adc_health_in_t in;
|
||||
@@ -169,12 +169,12 @@ static void tc_stm32_stall(void) {
|
||||
adc_health_check(&in, &st);
|
||||
}
|
||||
CHECK((st.flags & ADC_HF_STM32_STALL) != 0u,
|
||||
"TC-AH-004 STM32 stall at 100ms");
|
||||
"TC-ADCHEALTH-004 STM32 stall at 100ms");
|
||||
CHECK((st.flags & ADC_HF_TPAFE_STALL) == 0u,
|
||||
"TC-AH-004 healthy TPAFE not falsely stalled");
|
||||
"TC-ADCHEALTH-004 healthy TPAFE not falsely stalled");
|
||||
}
|
||||
|
||||
/* TC-AH-005:TPAFE 丢帧计数 + 边沿语义 */
|
||||
/* TC-ADCHEALTH-005:TPAFE 丢帧计数 + 边沿语义 */
|
||||
static void tc_tpafe_gap(void) {
|
||||
adc_health_status_t st;
|
||||
adc_health_in_t in;
|
||||
@@ -185,15 +185,15 @@ static void tc_tpafe_gap(void) {
|
||||
in.tpafe_seq = 13u; in.stm32_seq = 11u; in.now_ms = 11u; /* TPAFE d=3 */
|
||||
adc_health_check(&in, &st);
|
||||
CHECK((st.events & ADC_HE_TPAFE_GAP) != 0u,
|
||||
"TC-AH-005 gap event on d>1");
|
||||
CHECK(st.tpafe_gaps == 2u, "TC-AH-005 d=3 accumulates 2 lost points");
|
||||
"TC-ADCHEALTH-005 gap event on d>1");
|
||||
CHECK(st.tpafe_gaps == 2u, "TC-ADCHEALTH-005 d=3 accumulates 2 lost points");
|
||||
in.tpafe_seq = 14u; in.stm32_seq = 12u; in.now_ms = 12u; /* 恢复正常 d=1 */
|
||||
adc_health_check(&in, &st);
|
||||
CHECK(st.events == 0u, "TC-AH-005 gap event is edge-only (next beat clean)");
|
||||
CHECK(st.tpafe_gaps == 2u, "TC-AH-005 gap counter is cumulative");
|
||||
CHECK(st.events == 0u, "TC-ADCHEALTH-005 gap event is edge-only (next beat clean)");
|
||||
CHECK(st.tpafe_gaps == 2u, "TC-ADCHEALTH-005 gap counter is cumulative");
|
||||
}
|
||||
|
||||
/* TC-AH-006:STM32 gap 计数增量 → 事件、不入锁存 */
|
||||
/* TC-ADCHEALTH-006:STM32 gap 计数增量 → 事件、不入锁存 */
|
||||
static void tc_stm32_gap(void) {
|
||||
adc_health_status_t st;
|
||||
adc_health_in_t in;
|
||||
@@ -204,13 +204,13 @@ static void tc_stm32_gap(void) {
|
||||
in.stm32_gaps = 1u; in.tpafe_seq = 2u; in.stm32_seq = 2u; in.now_ms = 2u;
|
||||
adc_health_check(&in, &st);
|
||||
CHECK((st.events & ADC_HE_STM32_GAP) != 0u,
|
||||
"TC-AH-006 STM32 gap increment raises event");
|
||||
"TC-ADCHEALTH-006 STM32 gap increment raises event");
|
||||
CHECK((st.sticky & (ADC_HF_FRSTDATA | ADC_HF_STM32_ERR |
|
||||
ADC_HF_HW_ERR)) == 0u,
|
||||
"TC-AH-006 gap does NOT latch sticky (overrun is not a fault)");
|
||||
"TC-ADCHEALTH-006 gap does NOT latch sticky (overrun is not a fault)");
|
||||
}
|
||||
|
||||
/* TC-AH-007:序号倒退 → 锁存 */
|
||||
/* TC-ADCHEALTH-007:序号倒退 → 锁存 */
|
||||
static void tc_backward(void) {
|
||||
adc_health_status_t st;
|
||||
adc_health_in_t in;
|
||||
@@ -223,9 +223,9 @@ static void tc_backward(void) {
|
||||
in.tpafe_seq = 995u; in.stm32_seq = 995u; in.now_ms = 101u; /* 倒退 */
|
||||
adc_health_check(&in, &st);
|
||||
CHECK((st.flags & ADC_HF_SEQ_BACKWARD) != 0u,
|
||||
"TC-AH-007 backward seq raises latched flag");
|
||||
"TC-ADCHEALTH-007 backward seq raises latched flag");
|
||||
CHECK((st.sticky & ADC_HF_SEQ_BACKWARD) != 0u,
|
||||
"TC-AH-007 backward latched into sticky");
|
||||
"TC-ADCHEALTH-007 backward latched into sticky");
|
||||
/* 恢复正常推进 50 拍:SEQ_BACKWARD 不清(锁存语义) */
|
||||
s = 996u; t = 102u;
|
||||
for (i = 0; i < 50; i++) {
|
||||
@@ -234,10 +234,10 @@ static void tc_backward(void) {
|
||||
s++; t++;
|
||||
}
|
||||
CHECK((adc_health_flags() & ADC_HF_SEQ_BACKWARD) != 0u,
|
||||
"TC-AH-007 SEQ_BACKWARD persists after normal advance");
|
||||
"TC-ADCHEALTH-007 SEQ_BACKWARD persists after normal advance");
|
||||
}
|
||||
|
||||
/* TC-AH-008:三类错误计数增量 → 事件位与锁存位编号一致 */
|
||||
/* TC-ADCHEALTH-008:三类错误计数增量 → 事件位与锁存位编号一致 */
|
||||
static void tc_err_counters(void) {
|
||||
adc_health_status_t st;
|
||||
adc_health_in_t in;
|
||||
@@ -251,29 +251,29 @@ static void tc_err_counters(void) {
|
||||
adc_health_check(&in, &st);
|
||||
CHECK(((st.events & ADC_HE_FRSTDATA) != 0u) &&
|
||||
((st.sticky & ADC_HF_FRSTDATA) != 0u),
|
||||
"TC-AH-008 FRSTDATA increment: event + sticky (same bit number)");
|
||||
"TC-ADCHEALTH-008 FRSTDATA increment: event + sticky (same bit number)");
|
||||
|
||||
in.tpafe_seq = 3u; in.stm32_seq = 3u; in.now_ms = 3u;
|
||||
in.stm32_errs = 1u;
|
||||
adc_health_check(&in, &st);
|
||||
CHECK(((st.events & ADC_HE_STM32_ERR) != 0u) &&
|
||||
((st.sticky & ADC_HF_STM32_ERR) != 0u),
|
||||
"TC-AH-008 STM32 err increment: event + sticky (same bit number)");
|
||||
"TC-ADCHEALTH-008 STM32 err increment: event + sticky (same bit number)");
|
||||
|
||||
in.tpafe_seq = 4u; in.stm32_seq = 4u; in.now_ms = 4u;
|
||||
in.stm32_hw_errs = 1u;
|
||||
adc_health_check(&in, &st);
|
||||
CHECK(((st.events & ADC_HE_HW_ERR) != 0u) &&
|
||||
((st.sticky & ADC_HF_HW_ERR) != 0u),
|
||||
"TC-AH-008 HAL err increment: event + sticky (same bit number)");
|
||||
"TC-ADCHEALTH-008 HAL err increment: event + sticky (same bit number)");
|
||||
|
||||
/* 计数不再变化 → 事件不再重复触发 */
|
||||
in.tpafe_seq = 5u; in.stm32_seq = 5u; in.now_ms = 5u;
|
||||
adc_health_check(&in, &st);
|
||||
CHECK(st.events == 0u, "TC-AH-008 steady error counters raise no repeat events");
|
||||
CHECK(st.events == 0u, "TC-ADCHEALTH-008 steady error counters raise no repeat events");
|
||||
}
|
||||
|
||||
/* TC-AH-009:tick 回绕安全 */
|
||||
/* TC-ADCHEALTH-009:tick 回绕安全 */
|
||||
static void tc_tick_wrap(void) {
|
||||
adc_health_status_t st;
|
||||
adc_health_in_t in;
|
||||
@@ -290,7 +290,7 @@ static void tc_tick_wrap(void) {
|
||||
}
|
||||
seq++; now++; /* uint32 自然回绕 */
|
||||
}
|
||||
CHECK(ok, "TC-AH-009 tick wrap sweep: no false stall");
|
||||
CHECK(ok, "TC-ADCHEALTH-009 tick wrap sweep: no false stall");
|
||||
/* 回绕后两侧同时冻结。⚠ 第 1 拍消费 sweep 末尾的"未消费 +1"并重置计时起点
|
||||
* → 第 i 拍 elapsed = i,需 101 拍才到 100ms */
|
||||
for (i = 0; i < 101; i++) {
|
||||
@@ -300,10 +300,10 @@ static void tc_tick_wrap(void) {
|
||||
}
|
||||
CHECK(((st.flags & ADC_HF_TPAFE_STALL) != 0u) &&
|
||||
((st.flags & ADC_HF_STM32_STALL) != 0u),
|
||||
"TC-AH-009 stall still detected after tick wrap");
|
||||
"TC-ADCHEALTH-009 stall still detected after tick wrap");
|
||||
}
|
||||
|
||||
/* TC-AH-010:NULL 守卫 */
|
||||
/* TC-ADCHEALTH-010:NULL 守卫 */
|
||||
static void tc_null_guard(void) {
|
||||
adc_health_status_t st;
|
||||
adc_health_in_t in;
|
||||
@@ -314,7 +314,7 @@ static void tc_null_guard(void) {
|
||||
adc_health_check(&in, &st);
|
||||
st.flags = 0xA5A5A5A5u;
|
||||
adc_health_check(NULL, &st);
|
||||
CHECK(st.flags == 0xA5A5A5A5u, "TC-AH-010 in=NULL leaves out untouched");
|
||||
CHECK(st.flags == 0xA5A5A5A5u, "TC-ADCHEALTH-010 in=NULL leaves out untouched");
|
||||
|
||||
/* out=NULL:内部状态照常更新(两侧冻结 101 拍 → 静默位应出现) */
|
||||
for (i = 0; i < 101; i++) {
|
||||
@@ -322,10 +322,10 @@ static void tc_null_guard(void) {
|
||||
adc_health_check(&in, NULL);
|
||||
}
|
||||
CHECK((adc_health_flags() & ADC_HF_TPAFE_STALL) != 0u,
|
||||
"TC-AH-010 out=NULL still updates internal state");
|
||||
"TC-ADCHEALTH-010 out=NULL still updates internal state");
|
||||
}
|
||||
|
||||
/* TC-AH-011:init 幂等 / 故障后全清 */
|
||||
/* TC-ADCHEALTH-011:init 幂等 / 故障后全清 */
|
||||
static void tc_reinit(void) {
|
||||
adc_health_status_t st;
|
||||
adc_health_in_t in;
|
||||
@@ -338,15 +338,15 @@ static void tc_reinit(void) {
|
||||
in = mk_in(1u, (uint32_t)(2 + i));
|
||||
adc_health_check(&in, &st);
|
||||
}
|
||||
CHECK(st.sticky != 0u, "TC-AH-011 pre: sticky non-zero before re-init");
|
||||
CHECK(st.sticky != 0u, "TC-ADCHEALTH-011 pre: sticky non-zero before re-init");
|
||||
adc_health_init();
|
||||
CHECK((adc_health_flags() == 0u) && (adc_health_sticky() == 0u) &&
|
||||
(adc_health_tpafe_gaps() == 0u),
|
||||
"TC-AH-011 re-init clears flags/sticky/gaps");
|
||||
"TC-ADCHEALTH-011 re-init clears flags/sticky/gaps");
|
||||
in = mk_in(9u, 9u); /* 序号跳变也无妨:首拍只建基线 */
|
||||
adc_health_check(&in, &st);
|
||||
CHECK((st.flags == 0u) && (st.events == 0u),
|
||||
"TC-AH-011 re-prime after re-init is clean");
|
||||
"TC-ADCHEALTH-011 re-prime after re-init is clean");
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
|
||||
@@ -18,51 +18,51 @@
|
||||
* 3. 不占 MCU 的 RAM,毫秒级完成。
|
||||
*
|
||||
* 覆盖点(对应 docs/算法/继电保护功能复现规划.md §2.1 的 L1-3 / L1-4):
|
||||
* —— adc_input_init(TC-AI-001..006)——
|
||||
* TC-AI-001 poll 失败后失败计数可见(前置状态构造)
|
||||
* TC-AI-002 poll 成功后 TPAFE 侧可取数(前置状态构造)
|
||||
* TC-AI-003 init 返回 0(映射表自检通过)
|
||||
* TC-AI-004 init 后 STM32 状态码 = NOT_RUN
|
||||
* TC-AI-005 init 后失败计数归零
|
||||
* TC-AI-006 init 后 TPAFE / STM32 两侧均无有效数据(有效标志被清)
|
||||
* —— adc_input_desc(TC-AI-010..01A)——
|
||||
* TC-AI-010..018 九个语义通道 -> (来源, 下标) 与权威映射表逐项一致
|
||||
* TC-AI-019/01A 越界(ADC_SEM_COUNT)与负数语义 -> NULL
|
||||
* —— map_check(TC-AI-020)——
|
||||
* TC-AI-020 真实映射表自洽(反向路径结构上不可达,见文件末说明)
|
||||
* —— stm32_take(TC-AI-021..078,v2.0 DMA 模型)——
|
||||
* TC-AI-021..025 取到新帧:返回 0 / 状态码 / 不计失败 / DMA 只挂一次 / seq=1
|
||||
* TC-AI-026..02B **Rank -> 通道号映射**:UB->CH14(rank9) / UC->CH3(rank4) /
|
||||
* —— adc_input_init(TC-ADCIN-001..006)——
|
||||
* TC-ADCIN-001 poll 失败后失败计数可见(前置状态构造)
|
||||
* TC-ADCIN-002 poll 成功后 TPAFE 侧可取数(前置状态构造)
|
||||
* TC-ADCIN-003 init 返回 0(映射表自检通过)
|
||||
* TC-ADCIN-004 init 后 STM32 状态码 = NOT_RUN
|
||||
* TC-ADCIN-005 init 后失败计数归零
|
||||
* TC-ADCIN-006 init 后 TPAFE / STM32 两侧均无有效数据(有效标志被清)
|
||||
* —— adc_input_desc(TC-ADCIN-010..01A)——
|
||||
* TC-ADCIN-010..018 九个语义通道 -> (来源, 下标) 与权威映射表逐项一致
|
||||
* TC-ADCIN-019/01A 越界(ADC_SEM_COUNT)与负数语义 -> NULL
|
||||
* —— map_check(TC-ADCIN-020)——
|
||||
* TC-ADCIN-020 真实映射表自洽(反向路径结构上不可达,见文件末说明)
|
||||
* —— stm32_take(TC-ADCIN-021..078,v2.0 DMA 模型)——
|
||||
* TC-ADCIN-021..025 取到新帧:返回 0 / 状态码 / 不计失败 / DMA 只挂一次 / seq=1
|
||||
* TC-ADCIN-026..02B **Rank -> 通道号映射**:UB->CH14(rank9) / UC->CH3(rank4) /
|
||||
* IB->CH6(rank7) / IC->CH1(rank2) / IN->CH2(rank3) / TEMP->CH5(rank6)
|
||||
* TC-AI-02C stm32_take 不置 TPAFE 有效标志(两来源独立)
|
||||
* TC-AI-080..089 **乒乓双缓冲**:消费侧读"刚完成的半区",即使另一半正被 DMA
|
||||
* TC-ADCIN-02C stm32_take 不置 TPAFE 有效标志(两来源独立)
|
||||
* TC-ADCIN-080..089 **乒乓双缓冲**:消费侧读"刚完成的半区",即使另一半正被 DMA
|
||||
* 改写也不得读到(撕裂帧防线);两拍交替半区、seq 推进;
|
||||
* 超拍未消费 -> 记一次丢帧(gap),与停摆(err)分开计数
|
||||
* TC-AI-090..09A HAL 错误回调计数 + 三个回调的 `hadc == &hadc1` 句柄守卫
|
||||
* TC-ADCIN-090..09A HAL 错误回调计数 + 三个回调的 `hadc == &hadc1` 句柄守卫
|
||||
* (别的句柄不得污染本层 seq / hw_errs)
|
||||
* TC-AI-030..034 HAL_ADC_Start_DMA 失败:init 返回 -2 / 状态码 RC_START / 计数 +1
|
||||
* TC-AI-035..039 本拍无新帧:返回 RC_STALL / **单拍不计故障**(相位伪影)/ seq 不前进
|
||||
* TC-AI-03A..03E 连续两拍无新帧才计停摆;停摆与丢帧分开计数;恢复拍自愈
|
||||
* TC-AI-070..078 **停摆拍不得沿用上一拍旧值**(2026-10-10 补,真机实测发现的
|
||||
* TC-ADCIN-030..034 HAL_ADC_Start_DMA 失败:init 返回 -2 / 状态码 RC_START / 计数 +1
|
||||
* TC-ADCIN-035..039 本拍无新帧:返回 RC_STALL / **单拍不计故障**(相位伪影)/ seq 不前进
|
||||
* TC-ADCIN-03A..03E 连续两拍无新帧才计停摆;停摆与丢帧分开计数;恢复拍自愈
|
||||
* TC-ADCIN-070..078 **停摆拍不得沿用上一拍旧值**(2026-10-10 补,真机实测发现的
|
||||
* 正确性缺陷;DMA 版改由"无新帧"触发同一路径):先成功一拍让
|
||||
* STM32 侧进入有效态,再注入无新帧拍 -> adc_input_raw() 必须返 -2;
|
||||
* 恢复拍重新置有效。TC-AI-034 只覆盖"挂载失败即无数据",
|
||||
* 恢复拍重新置有效。TC-ADCIN-034 只覆盖"挂载失败即无数据",
|
||||
* 照不出"成功过之后停摆 → 静默沿用旧值",故单独立一组。
|
||||
* —— adc_input_raw(TC-AI-040..04B)——
|
||||
* TC-AI-040..043 参数守卫:out=NULL / 越界 / 负数 -> -1,且不写 out
|
||||
* TC-AI-044/045 无有效数据 -> -2(两来源分别)
|
||||
* TC-AI-046..048 poll 快照契约:返回码透传 / 请求 8 通道 / 目的缓冲非空
|
||||
* TC-AI-049..04B TPAFE 按**下标**取数(UA=6 / UN=5 / IA=2)且补码负值原样保留
|
||||
* —— adc_input_poll(TC-AI-050..058)——
|
||||
* TC-AI-050..052 无新帧(0):返回 0 / TPAFE 无效 / STM32 侧照常扫描
|
||||
* TC-AI-053/054 参数错(-1):返回 -1 / TPAFE 无效
|
||||
* TC-AI-055 已有有效帧后再"无新帧"**不清零**(保持上次有效值)
|
||||
* TC-AI-056..058 STM32 失败**不阻断** TPAFE、**不影响** poll 返回值,另由状态码暴露
|
||||
* —— adc_input_stm32_rc / _errs(TC-AI-060..066)——
|
||||
* TC-AI-060/061 init 后 = NOT_RUN / 计数 0
|
||||
* TC-AI-062 成功: rc=OK 且 errs 不变
|
||||
* TC-AI-063/064 两次失败累计 = 2,rc = 最近一次(TIMEOUT)
|
||||
* TC-AI-065/066 恢复成功 rc=OK,errs 单调不回退
|
||||
* —— adc_input_raw(TC-ADCIN-040..04B)——
|
||||
* TC-ADCIN-040..043 参数守卫:out=NULL / 越界 / 负数 -> -1,且不写 out
|
||||
* TC-ADCIN-044/045 无有效数据 -> -2(两来源分别)
|
||||
* TC-ADCIN-046..048 poll 快照契约:返回码透传 / 请求 8 通道 / 目的缓冲非空
|
||||
* TC-ADCIN-049..04B TPAFE 按**下标**取数(UA=6 / UN=5 / IA=2)且补码负值原样保留
|
||||
* —— adc_input_poll(TC-ADCIN-050..058)——
|
||||
* TC-ADCIN-050..052 无新帧(0):返回 0 / TPAFE 无效 / STM32 侧照常扫描
|
||||
* TC-ADCIN-053/054 参数错(-1):返回 -1 / TPAFE 无效
|
||||
* TC-ADCIN-055 已有有效帧后再"无新帧"**不清零**(保持上次有效值)
|
||||
* TC-ADCIN-056..058 STM32 失败**不阻断** TPAFE、**不影响** poll 返回值,另由状态码暴露
|
||||
* —— adc_input_stm32_rc / _errs(TC-ADCIN-060..066)——
|
||||
* TC-ADCIN-060/061 init 后 = NOT_RUN / 计数 0
|
||||
* TC-ADCIN-062 成功: rc=OK 且 errs 不变
|
||||
* TC-ADCIN-063/064 两次失败累计 = 2,rc = 最近一次(TIMEOUT)
|
||||
* TC-ADCIN-065/066 恢复成功 rc=OK,errs 单调不回退
|
||||
*
|
||||
* 通过:全部 TC PASS(main 返回 0)。
|
||||
* 入口:int main(void),返回 0=PASS / 1=FAIL(由 run 脚本判读)。
|
||||
@@ -201,7 +201,7 @@ static void dma_beat(uint16_t base) {
|
||||
}
|
||||
}
|
||||
|
||||
/* ===================== TC-AI-001..006:init ===================== */
|
||||
/* ===================== TC-ADCIN-001..006:init ===================== */
|
||||
|
||||
static void tc_init(void) {
|
||||
int32_t v = -999;
|
||||
@@ -213,69 +213,69 @@ static void tc_init(void) {
|
||||
(void)adc_input_poll(); /* 单拍无新帧 = 相位伪影,不计故障 */
|
||||
(void)adc_input_poll(); /* 连续第二拍无新帧 = 真停摆 */
|
||||
|
||||
CHECK(adc_input_stm32_errs() == 1u, "TC-AI-001 连续两拍无新帧 -> 停摆计数 = 1");
|
||||
CHECK(adc_input_stm32_errs() == 1u, "TC-ADCIN-001 连续两拍无新帧 -> 停摆计数 = 1");
|
||||
CHECK((adc_input_raw(ADC_SEM_UA, &v) == 0) && (v == 4321),
|
||||
"TC-AI-002 poll 后 UA 可取数且值正确");
|
||||
"TC-ADCIN-002 poll 后 UA 可取数且值正确");
|
||||
|
||||
CHECK(adc_input_init() == 0, "TC-AI-003 adc_input_init 返回 0(映射自检通过)");
|
||||
CHECK(adc_input_init() == 0, "TC-ADCIN-003 adc_input_init 返回 0(映射自检通过)");
|
||||
CHECK(adc_input_stm32_rc() == ADC_INPUT_RC_NOT_RUN,
|
||||
"TC-AI-004 init 后 STM32 状态码 = NOT_RUN");
|
||||
CHECK(s_start_dma_calls == 1, "TC-AI-003B init 挂载 DMA 恰好一次");
|
||||
CHECK(s_dma_len == (2u * ADC_INPUT_STM32_CH_NUM), "TC-AI-003C DMA 长度 = 2 x 9(乒乓双缓冲)");
|
||||
CHECK(s_dma_buf != NULL, "TC-AI-003D DMA 目的缓冲地址已交下来");
|
||||
CHECK(adc_input_stm32_seq() == 0u, "TC-AI-005B init 后 DMA 完成计数 = 0");
|
||||
CHECK(adc_input_stm32_errs() == 0u, "TC-AI-005 init 后 STM32 失败计数归零");
|
||||
"TC-ADCIN-004 init 后 STM32 状态码 = NOT_RUN");
|
||||
CHECK(s_start_dma_calls == 1, "TC-ADCIN-003B init 挂载 DMA 恰好一次");
|
||||
CHECK(s_dma_len == (2u * ADC_INPUT_STM32_CH_NUM), "TC-ADCIN-003C DMA 长度 = 2 x 9(乒乓双缓冲)");
|
||||
CHECK(s_dma_buf != NULL, "TC-ADCIN-003D DMA 目的缓冲地址已交下来");
|
||||
CHECK(adc_input_stm32_seq() == 0u, "TC-ADCIN-005B init 后 DMA 完成计数 = 0");
|
||||
CHECK(adc_input_stm32_errs() == 0u, "TC-ADCIN-005 init 后 STM32 失败计数归零");
|
||||
CHECK((adc_input_raw(ADC_SEM_UA, &v) == -2) && (adc_input_raw(ADC_SEM_UB, &v) == -2),
|
||||
"TC-AI-006 init 后 TPAFE / STM32 两侧均无有效数据");
|
||||
"TC-ADCIN-006 init 后 TPAFE / STM32 两侧均无有效数据");
|
||||
}
|
||||
|
||||
/* ===================== TC-AI-010..01A:desc 映射表 ===================== */
|
||||
/* ===================== TC-ADCIN-010..01A:desc 映射表 ===================== */
|
||||
|
||||
static void tc_desc(void) {
|
||||
const adc_channel_desc_t *d;
|
||||
|
||||
d = adc_input_desc(ADC_SEM_UA);
|
||||
CHECK((d != NULL) && (d->source == ADC_SRC_TPAFE) && (d->index == 6u),
|
||||
"TC-AI-010 UA -> TPAFE buf[6]");
|
||||
"TC-ADCIN-010 UA -> TPAFE buf[6]");
|
||||
d = adc_input_desc(ADC_SEM_UB);
|
||||
CHECK((d != NULL) && (d->source == ADC_SRC_STM32) && (d->index == 14u),
|
||||
"TC-AI-011 UB -> STM32 CH14");
|
||||
"TC-ADCIN-011 UB -> STM32 CH14");
|
||||
d = adc_input_desc(ADC_SEM_UC);
|
||||
CHECK((d != NULL) && (d->source == ADC_SRC_STM32) && (d->index == 3u),
|
||||
"TC-AI-012 UC -> STM32 CH3");
|
||||
"TC-ADCIN-012 UC -> STM32 CH3");
|
||||
d = adc_input_desc(ADC_SEM_UN);
|
||||
CHECK((d != NULL) && (d->source == ADC_SRC_TPAFE) && (d->index == 5u),
|
||||
"TC-AI-013 UN -> TPAFE buf[5]");
|
||||
"TC-ADCIN-013 UN -> TPAFE buf[5]");
|
||||
d = adc_input_desc(ADC_SEM_IA);
|
||||
CHECK((d != NULL) && (d->source == ADC_SRC_TPAFE) && (d->index == 2u),
|
||||
"TC-AI-014 IA -> TPAFE buf[2]");
|
||||
"TC-ADCIN-014 IA -> TPAFE buf[2]");
|
||||
d = adc_input_desc(ADC_SEM_IB);
|
||||
CHECK((d != NULL) && (d->source == ADC_SRC_STM32) && (d->index == 6u),
|
||||
"TC-AI-015 IB -> STM32 CH6");
|
||||
"TC-ADCIN-015 IB -> STM32 CH6");
|
||||
d = adc_input_desc(ADC_SEM_IC);
|
||||
CHECK((d != NULL) && (d->source == ADC_SRC_STM32) && (d->index == 1u),
|
||||
"TC-AI-016 IC -> STM32 CH1");
|
||||
"TC-ADCIN-016 IC -> STM32 CH1");
|
||||
d = adc_input_desc(ADC_SEM_IN);
|
||||
CHECK((d != NULL) && (d->source == ADC_SRC_STM32) && (d->index == 2u),
|
||||
"TC-AI-017 IN -> STM32 CH2");
|
||||
"TC-ADCIN-017 IN -> STM32 CH2");
|
||||
d = adc_input_desc(ADC_SEM_TEMP);
|
||||
CHECK((d != NULL) && (d->source == ADC_SRC_STM32) && (d->index == 5u),
|
||||
"TC-AI-018 TEMP -> STM32 CH5");
|
||||
"TC-ADCIN-018 TEMP -> STM32 CH5");
|
||||
|
||||
CHECK(adc_input_desc(ADC_SEM_COUNT) == NULL, "TC-AI-019 越界(ADC_SEM_COUNT) -> NULL");
|
||||
CHECK(adc_input_desc((adc_semantic_t)(-1)) == NULL, "TC-AI-01A 负数语义 -> NULL");
|
||||
CHECK(adc_input_desc(ADC_SEM_COUNT) == NULL, "TC-ADCIN-019 越界(ADC_SEM_COUNT) -> NULL");
|
||||
CHECK(adc_input_desc((adc_semantic_t)(-1)) == NULL, "TC-ADCIN-01A 负数语义 -> NULL");
|
||||
}
|
||||
|
||||
/* ===================== TC-AI-020:map_check ===================== */
|
||||
/* ===================== TC-ADCIN-020:map_check ===================== */
|
||||
|
||||
static void tc_map_check(void) {
|
||||
/* 真实映射表自洽:TPAFE 下标 < 8 且每个 STM32 通道号都出现在扫描 Rank 内。
|
||||
* 反向路径(表不自洽 -> -1)需在运行时改表,而 k_adc_map / k_stm32_rank_ch 均为
|
||||
* 编译期 static const、无运行时输入可使其不自洽 -> 结构上不可达(见文件末说明)。 */
|
||||
CHECK(map_check() == 0, "TC-AI-020 映射表自洽(TPAFE 下标与 STM32 Rank 均在范围内)");
|
||||
CHECK(map_check() == 0, "TC-ADCIN-020 映射表自洽(TPAFE 下标与 STM32 Rank 均在范围内)");
|
||||
}
|
||||
|
||||
/* ===================== TC-AI-021..02C:stm32_scan 成功路径 ===================== */
|
||||
/* ===================== TC-ADCIN-021..02C:stm32_scan 成功路径 ===================== */
|
||||
|
||||
static void tc_take_ok(void) {
|
||||
int32_t v = 0;
|
||||
@@ -284,25 +284,25 @@ static void tc_take_ok(void) {
|
||||
(void)adc_input_init();
|
||||
dma_beat(100); /* 前半区一帧:Rank i -> 100+i */
|
||||
|
||||
CHECK(stm32_take() == ADC_INPUT_RC_OK, "TC-AI-021 stm32_take 取到新帧 -> 0");
|
||||
CHECK(adc_input_stm32_rc() == ADC_INPUT_RC_OK, "TC-AI-022 状态码 = RC_OK");
|
||||
CHECK(adc_input_stm32_errs() == 0u, "TC-AI-023 成功不计入失败");
|
||||
CHECK(s_start_dma_calls == 1, "TC-AI-024 DMA 只在 init 挂一次(每拍不重启)");
|
||||
CHECK(adc_input_stm32_seq() == 1u, "TC-AI-025 DMA 完成计数 = 1");
|
||||
CHECK(stm32_take() == ADC_INPUT_RC_OK, "TC-ADCIN-021 stm32_take 取到新帧 -> 0");
|
||||
CHECK(adc_input_stm32_rc() == ADC_INPUT_RC_OK, "TC-ADCIN-022 状态码 = RC_OK");
|
||||
CHECK(adc_input_stm32_errs() == 0u, "TC-ADCIN-023 成功不计入失败");
|
||||
CHECK(s_start_dma_calls == 1, "TC-ADCIN-024 DMA 只在 init 挂一次(每拍不重启)");
|
||||
CHECK(adc_input_stm32_seq() == 1u, "TC-ADCIN-025 DMA 完成计数 = 1");
|
||||
|
||||
/* Rank -> 通道号映射:第 i 个 Rank = 100+i。
|
||||
* k_stm32_rank_ch = [CH0..CH7, CH14],故 CH3->103 / CH5->105 / CH6->106 / CH14->108。 */
|
||||
CHECK((adc_input_raw(ADC_SEM_UB, &v) == 0) && (v == 108), "TC-AI-026 UB 取到 CH14(rank9)=108");
|
||||
CHECK((adc_input_raw(ADC_SEM_UC, &v) == 0) && (v == 103), "TC-AI-027 UC 取到 CH3(rank4)=103");
|
||||
CHECK((adc_input_raw(ADC_SEM_IB, &v) == 0) && (v == 106), "TC-AI-028 IB 取到 CH6(rank7)=106");
|
||||
CHECK((adc_input_raw(ADC_SEM_IC, &v) == 0) && (v == 101), "TC-AI-029 IC 取到 CH1(rank2)=101");
|
||||
CHECK((adc_input_raw(ADC_SEM_IN, &v) == 0) && (v == 102), "TC-AI-02A IN 取到 CH2(rank3)=102");
|
||||
CHECK((adc_input_raw(ADC_SEM_TEMP, &v) == 0) && (v == 105), "TC-AI-02B TEMP 取到 CH5(rank6)=105");
|
||||
CHECK((adc_input_raw(ADC_SEM_UB, &v) == 0) && (v == 108), "TC-ADCIN-026 UB 取到 CH14(rank9)=108");
|
||||
CHECK((adc_input_raw(ADC_SEM_UC, &v) == 0) && (v == 103), "TC-ADCIN-027 UC 取到 CH3(rank4)=103");
|
||||
CHECK((adc_input_raw(ADC_SEM_IB, &v) == 0) && (v == 106), "TC-ADCIN-028 IB 取到 CH6(rank7)=106");
|
||||
CHECK((adc_input_raw(ADC_SEM_IC, &v) == 0) && (v == 101), "TC-ADCIN-029 IC 取到 CH1(rank2)=101");
|
||||
CHECK((adc_input_raw(ADC_SEM_IN, &v) == 0) && (v == 102), "TC-ADCIN-02A IN 取到 CH2(rank3)=102");
|
||||
CHECK((adc_input_raw(ADC_SEM_TEMP, &v) == 0) && (v == 105), "TC-ADCIN-02B TEMP 取到 CH5(rank6)=105");
|
||||
|
||||
CHECK(adc_input_raw(ADC_SEM_UA, &v) == -2, "TC-AI-02C stm32_take 不置 TPAFE 有效标志");
|
||||
CHECK(adc_input_raw(ADC_SEM_UA, &v) == -2, "TC-ADCIN-02C stm32_take 不置 TPAFE 有效标志");
|
||||
}
|
||||
|
||||
/* ============ TC-AI-080..085:乒乓双缓冲(读刚完成半区,不读正在写的半区) ============
|
||||
/* ============ TC-ADCIN-080..085:乒乓双缓冲(读刚完成半区,不读正在写的半区) ============
|
||||
* 这是 DMA 方案最关键的一条:消费侧必须读"上一拍刚完成的那一半",而 DMA 此刻正在
|
||||
* 写另一半。若读错半区,取到的是**正在被改写**的数据 → 半新半旧的撕裂帧。 */
|
||||
|
||||
@@ -314,30 +314,30 @@ static void tc_dma_pingpong(void) {
|
||||
|
||||
dma_beat(100); /* 第 1 帧 -> 前半区(半传输回调) */
|
||||
dma_fill(1u, 900u); /* 模拟 DMA 正在写后半区(值 900 系) */
|
||||
CHECK(stm32_take() == ADC_INPUT_RC_OK, "TC-AI-080 第一拍取帧成功");
|
||||
CHECK(stm32_take() == ADC_INPUT_RC_OK, "TC-ADCIN-080 第一拍取帧成功");
|
||||
CHECK((adc_input_raw(ADC_SEM_UB, &v) == 0) && (v == 108),
|
||||
"TC-AI-081 读的是刚完成的前半区(108),不是正在写的后半区");
|
||||
"TC-ADCIN-081 读的是刚完成的前半区(108),不是正在写的后半区");
|
||||
|
||||
dma_beat(200); /* 第 2 帧 -> 后半区(传输完成回调) */
|
||||
dma_fill(0u, 800u); /* 模拟 DMA 正在写前半区(值 800 系) */
|
||||
CHECK(stm32_take() == ADC_INPUT_RC_OK, "TC-AI-082 第二拍取帧成功");
|
||||
CHECK(stm32_take() == ADC_INPUT_RC_OK, "TC-ADCIN-082 第二拍取帧成功");
|
||||
CHECK((adc_input_raw(ADC_SEM_UB, &v) == 0) && (v == 208),
|
||||
"TC-AI-083 第二拍读到后半区(208)");
|
||||
CHECK(adc_input_stm32_seq() == 2u, "TC-AI-084 DMA 完成计数 = 2");
|
||||
"TC-ADCIN-083 第二拍读到后半区(208)");
|
||||
CHECK(adc_input_stm32_seq() == 2u, "TC-ADCIN-084 DMA 完成计数 = 2");
|
||||
|
||||
/* 半区奇偶口径:seq=1 -> 前半区,seq=2 -> 后半区(与 dma_beat 独立推导,互相证伪) */
|
||||
CHECK(((adc_input_raw(ADC_SEM_UC, &v) == 0) && (v == 203)), "TC-AI-085 UC 同帧内一致(203)");
|
||||
CHECK(((adc_input_raw(ADC_SEM_UC, &v) == 0) && (v == 203)), "TC-ADCIN-085 UC 同帧内一致(203)");
|
||||
|
||||
/* 消费者超拍:两拍都没取 -> 中间那帧已被乒乓缓冲覆盖 -> 记一次丢帧 */
|
||||
dma_beat(300);
|
||||
dma_beat(400);
|
||||
CHECK(stm32_take() == ADC_INPUT_RC_OK, "TC-AI-086 超拍后仍取到最新帧");
|
||||
CHECK(adc_input_stm32_gaps() == 1u, "TC-AI-087 seq 前进 2 -> 记一次丢帧");
|
||||
CHECK((adc_input_raw(ADC_SEM_UB, &v) == 0) && (v == 408), "TC-AI-088 取到的是最新帧(408)");
|
||||
CHECK(adc_input_stm32_errs() == 0u, "TC-AI-089 丢帧不计入停摆(两类故障分开)");
|
||||
CHECK(stm32_take() == ADC_INPUT_RC_OK, "TC-ADCIN-086 超拍后仍取到最新帧");
|
||||
CHECK(adc_input_stm32_gaps() == 1u, "TC-ADCIN-087 seq 前进 2 -> 记一次丢帧");
|
||||
CHECK((adc_input_raw(ADC_SEM_UB, &v) == 0) && (v == 408), "TC-ADCIN-088 取到的是最新帧(408)");
|
||||
CHECK(adc_input_stm32_errs() == 0u, "TC-ADCIN-089 丢帧不计入停摆(两类故障分开)");
|
||||
}
|
||||
|
||||
/* ============ TC-AI-090..093:HAL 错误回调与句柄守卫 ============ */
|
||||
/* ============ TC-ADCIN-090..093:HAL 错误回调与句柄守卫 ============ */
|
||||
|
||||
static void tc_hw_errs(void) {
|
||||
fakes_reset();
|
||||
@@ -345,21 +345,21 @@ static void tc_hw_errs(void) {
|
||||
|
||||
HAL_ADC_ErrorCallback(&hadc1);
|
||||
HAL_ADC_ErrorCallback(&hadc1);
|
||||
CHECK(adc_input_stm32_hw_errs() == 2u, "TC-AI-090 错误回调累计 = 2");
|
||||
CHECK(adc_input_stm32_hw_errs() == 2u, "TC-ADCIN-090 错误回调累计 = 2");
|
||||
|
||||
HAL_ADC_ErrorCallback(&hadc_other);
|
||||
CHECK(adc_input_stm32_hw_errs() == 2u, "TC-AI-091 别的 ADC 句柄不得计入(hadc 守卫)");
|
||||
CHECK(adc_input_stm32_hw_errs() == 2u, "TC-ADCIN-091 别的 ADC 句柄不得计入(hadc 守卫)");
|
||||
|
||||
HAL_ADC_ConvHalfCpltCallback(&hadc_other);
|
||||
HAL_ADC_ConvCpltCallback(&hadc_other);
|
||||
CHECK(adc_input_stm32_seq() == 0u, "TC-AI-092 别的句柄的完成回调不得推进 seq");
|
||||
CHECK(adc_input_stm32_seq() == 0u, "TC-ADCIN-092 别的句柄的完成回调不得推进 seq");
|
||||
|
||||
HAL_ADC_ErrorCallback(&hadc1);
|
||||
CHECK(adc_input_stm32_hw_errs() == 3u, "TC-AI-093 hw_errs 与 errs 分开计数、互不干扰");
|
||||
CHECK(adc_input_stm32_errs() == 0u, "TC-AI-09A hw_errs 不污染 errs");
|
||||
CHECK(adc_input_stm32_hw_errs() == 3u, "TC-ADCIN-093 hw_errs 与 errs 分开计数、互不干扰");
|
||||
CHECK(adc_input_stm32_errs() == 0u, "TC-ADCIN-09A hw_errs 不污染 errs");
|
||||
}
|
||||
|
||||
/* ===================== TC-AI-030..034:DMA 挂载失败 ===================== */
|
||||
/* ===================== TC-ADCIN-030..034:DMA 挂载失败 ===================== */
|
||||
|
||||
static void tc_init_dma_fail(void) {
|
||||
int32_t v = 0;
|
||||
@@ -367,13 +367,13 @@ static void tc_init_dma_fail(void) {
|
||||
fakes_reset();
|
||||
s_start_dma_rc = HAL_ERROR;
|
||||
|
||||
CHECK(adc_input_init() == -2, "TC-AI-030 HAL_ADC_Start_DMA 失败 -> init 返回 -2");
|
||||
CHECK(adc_input_stm32_rc() == ADC_INPUT_RC_START, "TC-AI-031 状态码 = RC_START");
|
||||
CHECK(adc_input_stm32_errs() == 1u, "TC-AI-032 失败计数 +1");
|
||||
CHECK(adc_input_raw(ADC_SEM_UB, &v) == -2, "TC-AI-034 挂载失败后 STM32 侧无有效数据");
|
||||
CHECK(adc_input_init() == -2, "TC-ADCIN-030 HAL_ADC_Start_DMA 失败 -> init 返回 -2");
|
||||
CHECK(adc_input_stm32_rc() == ADC_INPUT_RC_START, "TC-ADCIN-031 状态码 = RC_START");
|
||||
CHECK(adc_input_stm32_errs() == 1u, "TC-ADCIN-032 失败计数 +1");
|
||||
CHECK(adc_input_raw(ADC_SEM_UB, &v) == -2, "TC-ADCIN-034 挂载失败后 STM32 侧无有效数据");
|
||||
}
|
||||
|
||||
/* ===================== TC-AI-035..03A:本拍无新帧(停摆) ===================== */
|
||||
/* ===================== TC-ADCIN-035..03A:本拍无新帧(停摆) ===================== */
|
||||
|
||||
static void tc_take_stall(void) {
|
||||
int32_t v = 0;
|
||||
@@ -382,29 +382,29 @@ static void tc_take_stall(void) {
|
||||
(void)adc_input_init();
|
||||
/* 没有任何 DMA 完成回调 = TIM3 未启动 / ADC 停摆 / DMA 出错 */
|
||||
|
||||
CHECK(stm32_take() == ADC_INPUT_RC_STALL, "TC-AI-035 无新帧 -> RC_STALL(-2)");
|
||||
CHECK(adc_input_stm32_rc() == ADC_INPUT_RC_STALL, "TC-AI-036 状态码 = RC_STALL");
|
||||
CHECK(adc_input_stm32_errs() == 0u, "TC-AI-037 单拍无新帧不计故障(相位伪影)");
|
||||
CHECK(adc_input_stm32_seq() == 0u, "TC-AI-038 停摆期间 seq 不前进");
|
||||
CHECK(adc_input_raw(ADC_SEM_UB, &v) == -2, "TC-AI-039 停摆拍 STM32 侧无有效数据");
|
||||
CHECK(stm32_take() == ADC_INPUT_RC_STALL, "TC-ADCIN-035 无新帧 -> RC_STALL(-2)");
|
||||
CHECK(adc_input_stm32_rc() == ADC_INPUT_RC_STALL, "TC-ADCIN-036 状态码 = RC_STALL");
|
||||
CHECK(adc_input_stm32_errs() == 0u, "TC-ADCIN-037 单拍无新帧不计故障(相位伪影)");
|
||||
CHECK(adc_input_stm32_seq() == 0u, "TC-ADCIN-038 停摆期间 seq 不前进");
|
||||
CHECK(adc_input_raw(ADC_SEM_UB, &v) == -2, "TC-ADCIN-039 停摆拍 STM32 侧无有效数据");
|
||||
|
||||
(void)stm32_take(); /* 连续第二拍无新帧 = 真停摆 */
|
||||
CHECK(adc_input_stm32_errs() == 1u, "TC-AI-03A 连续两拍无新帧 -> 停摆计数 = 1");
|
||||
CHECK(adc_input_stm32_errs() == 1u, "TC-ADCIN-03A 连续两拍无新帧 -> 停摆计数 = 1");
|
||||
(void)stm32_take(); /* 第三拍仍无新帧 */
|
||||
CHECK(adc_input_stm32_errs() == 2u, "TC-AI-03B 停摆持续 -> 每拍累计 = 2");
|
||||
CHECK(adc_input_stm32_gaps() == 0u, "TC-AI-03C 停摆不计入丢帧(两类故障分开)");
|
||||
CHECK(adc_input_stm32_errs() == 2u, "TC-ADCIN-03B 停摆持续 -> 每拍累计 = 2");
|
||||
CHECK(adc_input_stm32_gaps() == 0u, "TC-ADCIN-03C 停摆不计入丢帧(两类故障分开)");
|
||||
|
||||
dma_beat(100); /* 恢复 */
|
||||
CHECK(stm32_take() == ADC_INPUT_RC_OK, "TC-AI-03D 恢复后取帧成功");
|
||||
CHECK(adc_input_stm32_gaps() == 0u, "TC-AI-03E 恢复拍前进 1 -> 不算丢帧");
|
||||
CHECK(stm32_take() == ADC_INPUT_RC_OK, "TC-ADCIN-03D 恢复后取帧成功");
|
||||
CHECK(adc_input_stm32_gaps() == 0u, "TC-ADCIN-03E 恢复拍前进 1 -> 不算丢帧");
|
||||
}
|
||||
|
||||
/* ============ TC-AI-070..078:停摆拍不得沿用上一拍旧值(陈旧帧) ============
|
||||
/* ============ TC-ADCIN-070..078:停摆拍不得沿用上一拍旧值(陈旧帧) ============
|
||||
* 背景(2026-10-10 真机实测发现):本层只有一份 s_stm32_raw[],而 s_stm32_valid
|
||||
* 此前只在成功时置 1、失败时**从不清零** → 消费侧照样取数、照样压入采样环,
|
||||
* s_frames_skip 抓不到。轮询版的触发路径是"超时拍半新半旧",DMA 版(v2.0)改成
|
||||
* "本拍无新帧仍沿用上一拍"——**同一条缺陷、同一个防线**,故本组用例保留。
|
||||
* TC-AI-034 是"挂载失败后本就无数据"(valid 一直是 0),照不出这条路径——
|
||||
* TC-ADCIN-034 是"挂载失败后本就无数据"(valid 一直是 0),照不出这条路径——
|
||||
* 必须先成功一拍。 */
|
||||
|
||||
static void tc_take_stale(void) {
|
||||
@@ -414,27 +414,27 @@ static void tc_take_stale(void) {
|
||||
fakes_reset();
|
||||
(void)adc_input_init();
|
||||
dma_beat(100);
|
||||
CHECK(stm32_take() == ADC_INPUT_RC_OK, "TC-AI-070 前置:首拍成功");
|
||||
CHECK((adc_input_raw(ADC_SEM_UB, &v) == 0) && (v == 108), "TC-AI-071 前置:UB 取到 108(有效态)");
|
||||
CHECK(stm32_take() == ADC_INPUT_RC_OK, "TC-ADCIN-070 前置:首拍成功");
|
||||
CHECK((adc_input_raw(ADC_SEM_UB, &v) == 0) && (v == 108), "TC-ADCIN-071 前置:UB 取到 108(有效态)");
|
||||
|
||||
/* 第二拍没有任何 DMA 完成(TIM3 停 / ADC 停摆 / DMA 出错) */
|
||||
CHECK(stm32_take() == ADC_INPUT_RC_STALL, "TC-AI-072 第二拍无新帧");
|
||||
CHECK(adc_input_raw(ADC_SEM_UB, &v) == -2, "TC-AI-073 停摆拍不得沿用上一拍值 -> -2");
|
||||
CHECK(adc_input_raw(ADC_SEM_UC, &v) == -2, "TC-AI-074 停摆拍连其它 STM32 通道也不得出数");
|
||||
CHECK(adc_input_raw(ADC_SEM_TEMP, &v) == -2, "TC-AI-074B 同上(TEMP 亦 -2)");
|
||||
CHECK(stm32_take() == ADC_INPUT_RC_STALL, "TC-ADCIN-072 第二拍无新帧");
|
||||
CHECK(adc_input_raw(ADC_SEM_UB, &v) == -2, "TC-ADCIN-073 停摆拍不得沿用上一拍值 -> -2");
|
||||
CHECK(adc_input_raw(ADC_SEM_UC, &v) == -2, "TC-ADCIN-074 停摆拍连其它 STM32 通道也不得出数");
|
||||
CHECK(adc_input_raw(ADC_SEM_TEMP, &v) == -2, "TC-ADCIN-074B 同上(TEMP 亦 -2)");
|
||||
|
||||
dma_beat(200);
|
||||
CHECK(stm32_take() == ADC_INPUT_RC_OK, "TC-AI-075 第三拍恢复成功");
|
||||
CHECK((adc_input_raw(ADC_SEM_UB, &v) == 0) && (v == 208), "TC-AI-076 恢复拍重新可取数(自愈)");
|
||||
CHECK(stm32_take() == ADC_INPUT_RC_OK, "TC-ADCIN-075 第三拍恢复成功");
|
||||
CHECK((adc_input_raw(ADC_SEM_UB, &v) == 0) && (v == 208), "TC-ADCIN-076 恢复拍重新可取数(自愈)");
|
||||
|
||||
/* --- 挂载失败支路:同样不得沿用(init 失败后整层无有效数据) --- */
|
||||
fakes_reset();
|
||||
s_start_dma_rc = HAL_ERROR;
|
||||
(void)adc_input_init();
|
||||
CHECK(adc_input_raw(ADC_SEM_UB, &v) == -2, "TC-AI-078 挂载失败后不得取到任何值 -> -2");
|
||||
CHECK(adc_input_raw(ADC_SEM_UB, &v) == -2, "TC-ADCIN-078 挂载失败后不得取到任何值 -> -2");
|
||||
}
|
||||
|
||||
/* ===================== TC-AI-040..045:raw 参数守卫与无数据 ===================== */
|
||||
/* ===================== TC-ADCIN-040..045:raw 参数守卫与无数据 ===================== */
|
||||
|
||||
static void tc_raw_guards(void) {
|
||||
int32_t v = 0;
|
||||
@@ -442,15 +442,15 @@ static void tc_raw_guards(void) {
|
||||
fakes_reset();
|
||||
(void)adc_input_init();
|
||||
|
||||
CHECK(adc_input_raw(ADC_SEM_UA, NULL) == -1, "TC-AI-040 out=NULL -> -1");
|
||||
CHECK(adc_input_raw(ADC_SEM_COUNT, &v) == -1, "TC-AI-041 ch 越界 -> -1");
|
||||
CHECK(adc_input_raw((adc_semantic_t)(-1), &v) == -1, "TC-AI-042 ch 负数 -> -1");
|
||||
CHECK(v == 0, "TC-AI-043 参数错时不写 out");
|
||||
CHECK(adc_input_raw(ADC_SEM_UA, &v) == -2, "TC-AI-044 TPAFE 无有效帧 -> -2");
|
||||
CHECK(adc_input_raw(ADC_SEM_UB, &v) == -2, "TC-AI-045 STM32 无有效扫描 -> -2");
|
||||
CHECK(adc_input_raw(ADC_SEM_UA, NULL) == -1, "TC-ADCIN-040 out=NULL -> -1");
|
||||
CHECK(adc_input_raw(ADC_SEM_COUNT, &v) == -1, "TC-ADCIN-041 ch 越界 -> -1");
|
||||
CHECK(adc_input_raw((adc_semantic_t)(-1), &v) == -1, "TC-ADCIN-042 ch 负数 -> -1");
|
||||
CHECK(v == 0, "TC-ADCIN-043 参数错时不写 out");
|
||||
CHECK(adc_input_raw(ADC_SEM_UA, &v) == -2, "TC-ADCIN-044 TPAFE 无有效帧 -> -2");
|
||||
CHECK(adc_input_raw(ADC_SEM_UB, &v) == -2, "TC-ADCIN-045 STM32 无有效扫描 -> -2");
|
||||
}
|
||||
|
||||
/* ===================== TC-AI-046..04B:raw TPAFE 取数与补码 ===================== */
|
||||
/* ===================== TC-ADCIN-046..04B:raw TPAFE 取数与补码 ===================== */
|
||||
|
||||
static void tc_raw_tpafe(void) {
|
||||
int32_t v = 0;
|
||||
@@ -468,16 +468,16 @@ static void tc_raw_tpafe(void) {
|
||||
s_fake_tpafe[7] = 1007;
|
||||
s_snapshot_rc = 1;
|
||||
|
||||
CHECK(adc_input_poll() == 1, "TC-AI-046 poll 透传 TPAFE 快照码 1");
|
||||
CHECK(s_snapshot_count == (uint8_t)ADC_INPUT_TPAFE_CH_NUM, "TC-AI-047 快照请求 8 通道");
|
||||
CHECK(s_snapshot_dst != NULL, "TC-AI-048 快照目的缓冲非空");
|
||||
CHECK((adc_input_raw(ADC_SEM_UA, &v) == 0) && (v == 3006), "TC-AI-049 UA -> buf[6]=3006");
|
||||
CHECK((adc_input_raw(ADC_SEM_UN, &v) == 0) && (v == 2005), "TC-AI-04A UN -> buf[5]=2005");
|
||||
CHECK(adc_input_poll() == 1, "TC-ADCIN-046 poll 透传 TPAFE 快照码 1");
|
||||
CHECK(s_snapshot_count == (uint8_t)ADC_INPUT_TPAFE_CH_NUM, "TC-ADCIN-047 快照请求 8 通道");
|
||||
CHECK(s_snapshot_dst != NULL, "TC-ADCIN-048 快照目的缓冲非空");
|
||||
CHECK((adc_input_raw(ADC_SEM_UA, &v) == 0) && (v == 3006), "TC-ADCIN-049 UA -> buf[6]=3006");
|
||||
CHECK((adc_input_raw(ADC_SEM_UN, &v) == 0) && (v == 2005), "TC-ADCIN-04A UN -> buf[5]=2005");
|
||||
CHECK((adc_input_raw(ADC_SEM_IA, &v) == 0) && (v == -1234),
|
||||
"TC-AI-04B IA -> buf[2]=-1234(补码负值原样保留)");
|
||||
"TC-ADCIN-04B IA -> buf[2]=-1234(补码负值原样保留)");
|
||||
}
|
||||
|
||||
/* ===================== TC-AI-050..058:poll 契约 ===================== */
|
||||
/* ===================== TC-ADCIN-050..058:poll 契约 ===================== */
|
||||
|
||||
static void tc_poll(void) {
|
||||
int32_t v = 0;
|
||||
@@ -487,16 +487,16 @@ static void tc_poll(void) {
|
||||
(void)adc_input_init();
|
||||
s_snapshot_rc = 0;
|
||||
dma_beat(100);
|
||||
CHECK(adc_input_poll() == 0, "TC-AI-050 快照无新帧 -> poll 返回 0");
|
||||
CHECK(adc_input_raw(ADC_SEM_UA, &v) == -2, "TC-AI-051 无新帧时 TPAFE 侧无效");
|
||||
CHECK(adc_input_stm32_rc() == ADC_INPUT_RC_OK, "TC-AI-052 同拍 STM32 取帧照常执行");
|
||||
CHECK(adc_input_poll() == 0, "TC-ADCIN-050 快照无新帧 -> poll 返回 0");
|
||||
CHECK(adc_input_raw(ADC_SEM_UA, &v) == -2, "TC-ADCIN-051 无新帧时 TPAFE 侧无效");
|
||||
CHECK(adc_input_stm32_rc() == ADC_INPUT_RC_OK, "TC-ADCIN-052 同拍 STM32 取帧照常执行");
|
||||
|
||||
/* --- 参数错(-1):返回 -1,TPAFE 无效 --- */
|
||||
fakes_reset();
|
||||
(void)adc_input_init();
|
||||
s_snapshot_rc = -1;
|
||||
CHECK(adc_input_poll() == -1, "TC-AI-053 快照参数错 -> poll 返回 -1");
|
||||
CHECK(adc_input_raw(ADC_SEM_UA, &v) == -2, "TC-AI-054 参数错时 TPAFE 侧无效");
|
||||
CHECK(adc_input_poll() == -1, "TC-ADCIN-053 快照参数错 -> poll 返回 -1");
|
||||
CHECK(adc_input_raw(ADC_SEM_UA, &v) == -2, "TC-ADCIN-054 参数错时 TPAFE 侧无效");
|
||||
|
||||
/* --- 已有有效帧后再"无新帧":保持上次有效值(不清零) --- */
|
||||
fakes_reset();
|
||||
@@ -507,7 +507,7 @@ static void tc_poll(void) {
|
||||
s_snapshot_rc = 0;
|
||||
(void)adc_input_poll();
|
||||
CHECK((adc_input_raw(ADC_SEM_UA, &v) == 0) && (v == 777),
|
||||
"TC-AI-055 已有有效帧后无新帧不清零");
|
||||
"TC-ADCIN-055 已有有效帧后无新帧不清零");
|
||||
|
||||
/* --- STM32 失败不阻断 TPAFE、不影响 poll 返回值 --- */
|
||||
fakes_reset();
|
||||
@@ -515,36 +515,36 @@ static void tc_poll(void) {
|
||||
s_fake_tpafe[2] = 55;
|
||||
s_snapshot_rc = 1;
|
||||
/* 不注入任何 DMA 完成 = STM32 侧停摆 */
|
||||
CHECK(adc_input_poll() == 1, "TC-AI-056 STM32 停摆不影响 poll 返回值(仍为 1)");
|
||||
CHECK(adc_input_poll() == 1, "TC-ADCIN-056 STM32 停摆不影响 poll 返回值(仍为 1)");
|
||||
CHECK((adc_input_raw(ADC_SEM_IA, &v) == 0) && (v == 55),
|
||||
"TC-AI-057 STM32 停摆不影响 TPAFE 取数");
|
||||
CHECK(adc_input_stm32_rc() == ADC_INPUT_RC_STALL, "TC-AI-058 STM32 停摆另由状态码暴露");
|
||||
"TC-ADCIN-057 STM32 停摆不影响 TPAFE 取数");
|
||||
CHECK(adc_input_stm32_rc() == ADC_INPUT_RC_STALL, "TC-ADCIN-058 STM32 停摆另由状态码暴露");
|
||||
}
|
||||
|
||||
/* ===================== TC-AI-060..066:rc / errs 观测 ===================== */
|
||||
/* ===================== TC-ADCIN-060..066:rc / errs 观测 ===================== */
|
||||
|
||||
static void tc_rc_errs(void) {
|
||||
fakes_reset();
|
||||
(void)adc_input_init();
|
||||
|
||||
CHECK(adc_input_stm32_rc() == ADC_INPUT_RC_NOT_RUN, "TC-AI-060 init 后未扫描 = NOT_RUN(-3)");
|
||||
CHECK(adc_input_stm32_errs() == 0u, "TC-AI-061 init 后失败计数 = 0");
|
||||
CHECK(adc_input_stm32_rc() == ADC_INPUT_RC_NOT_RUN, "TC-ADCIN-060 init 后未扫描 = NOT_RUN(-3)");
|
||||
CHECK(adc_input_stm32_errs() == 0u, "TC-ADCIN-061 init 后失败计数 = 0");
|
||||
|
||||
dma_beat(100);
|
||||
(void)stm32_take(); /* 成功 */
|
||||
CHECK((adc_input_stm32_rc() == ADC_INPUT_RC_OK) && (adc_input_stm32_errs() == 0u),
|
||||
"TC-AI-062 成功: rc=OK 且 errs 不变");
|
||||
"TC-ADCIN-062 成功: rc=OK 且 errs 不变");
|
||||
|
||||
(void)stm32_take(); /* 停摆 1(单拍 = 相位伪影,不计) */
|
||||
(void)stm32_take(); /* 停摆 2 -> 计 1 */
|
||||
CHECK(adc_input_stm32_errs() == 1u, "TC-AI-063 连续两拍停摆累计 = 1");
|
||||
CHECK(adc_input_stm32_rc() == ADC_INPUT_RC_STALL, "TC-AI-064 rc = 最近一次(STALL)");
|
||||
CHECK(adc_input_stm32_errs() == 1u, "TC-ADCIN-063 连续两拍停摆累计 = 1");
|
||||
CHECK(adc_input_stm32_rc() == ADC_INPUT_RC_STALL, "TC-ADCIN-064 rc = 最近一次(STALL)");
|
||||
|
||||
dma_beat(200);
|
||||
(void)stm32_take(); /* 恢复成功 */
|
||||
CHECK(adc_input_stm32_rc() == ADC_INPUT_RC_OK, "TC-AI-065 恢复成功后 rc=OK");
|
||||
CHECK(adc_input_stm32_errs() == 1u, "TC-AI-066 errs 单调递增(不因成功回落)");
|
||||
CHECK(adc_input_stm32_seq() == 2u, "TC-AI-067 seq 只由 DMA 完成回调推进");
|
||||
CHECK(adc_input_stm32_rc() == ADC_INPUT_RC_OK, "TC-ADCIN-065 恢复成功后 rc=OK");
|
||||
CHECK(adc_input_stm32_errs() == 1u, "TC-ADCIN-066 errs 单调递增(不因成功回落)");
|
||||
CHECK(adc_input_stm32_seq() == 2u, "TC-ADCIN-067 seq 只由 DMA 完成回调推进");
|
||||
}
|
||||
|
||||
/* ===================== main ===================== */
|
||||
|
||||
@@ -16,43 +16,43 @@
|
||||
*
|
||||
* 覆盖点(对应 docs/测试说明/配置文件单元测试说明.md 的 TC-CFG-xxx):
|
||||
* —— 值类型编解码(s_encode / s_decode 经公开 load/save 间接验证 + 直接白盒)——
|
||||
* TC-CFG-001 UINT 1/2/4 字节小端往返(含 0 / 最大值)
|
||||
* TC-CFG-002 UINT 非法:空 / 非数字 / 带后缀 / 超范围
|
||||
* TC-CFG-003 IP4 正常与非法(段数不足、>255、前导非数字、多余后缀)
|
||||
* TC-CFG-004 MAC 三种分隔符 + 大小写 + 非法
|
||||
* TC-CFG-005 STR 正常 / 超长拒绝 / 边界(恰好放下)
|
||||
* TC-CONFIG-001 UINT 1/2/4 字节小端往返(含 0 / 最大值)
|
||||
* TC-CONFIG-002 UINT 非法:空 / 非数字 / 带后缀 / 超范围
|
||||
* TC-CONFIG-003 IP4 正常与非法(段数不足、>255、前导非数字、多余后缀)
|
||||
* TC-CONFIG-004 MAC 三种分隔符 + 大小写 + 非法
|
||||
* TC-CONFIG-005 STR 正常 / 超长拒绝 / 边界(恰好放下)
|
||||
* —— INI 解析(s_split_line / s_match_section / s_key_value / s_parse)——
|
||||
* TC-CFG-010 注释(; 与 #)与空行忽略
|
||||
* TC-CFG-011 CRLF / LF 混排
|
||||
* TC-CFG-012 段名大小写无关匹配、前后空白修剪
|
||||
* TC-CFG-013 键名大小写无关、值前后空白修剪
|
||||
* TC-CFG-014 未知段 / 未知键留默认(不崩溃)
|
||||
* TC-CFG-015 键值行出现在段头之前 = 忽略
|
||||
* TC-CONFIG-010 注释(; 与 #)与空行忽略
|
||||
* TC-CONFIG-011 CRLF / LF 混排
|
||||
* TC-CONFIG-012 段名大小写无关匹配、前后空白修剪
|
||||
* TC-CONFIG-013 键名大小写无关、值前后空白修剪
|
||||
* TC-CONFIG-014 未知段 / 未知键留默认(不崩溃)
|
||||
* TC-CONFIG-015 键值行出现在段头之前 = 忽略
|
||||
* —— 注册校验(cfg_file_register)——
|
||||
* TC-CFG-020 正常注册 / 重复段名拒绝 / NULL 参数拒绝
|
||||
* TC-CFG-021 非法键定义拒绝(UINT len 非 1/2/4、MAC len≠6、STR len>79)
|
||||
* TC-CFG-022 段名超长拒绝(≥ CFG_NAME_MAX)
|
||||
* TC-CFG-023 挂回调段 data_size > CFG_SNAP_MAX 拒绝
|
||||
* TC-CFG-024 键名超长拒绝(≥ CFG_NAME_MAX);恰好 15 字符(= CFG_FILE_MAX_NAME_LEN)接受
|
||||
* TC-CONFIG-020 正常注册 / 重复段名拒绝 / NULL 参数拒绝
|
||||
* TC-CONFIG-021 非法键定义拒绝(UINT len 非 1/2/4、MAC len≠6、STR len>79)
|
||||
* TC-CONFIG-022 段名超长拒绝(≥ CFG_NAME_MAX)
|
||||
* TC-CONFIG-023 挂回调段 data_size > CFG_SNAP_MAX 拒绝
|
||||
* TC-CONFIG-024 键名超长拒绝(≥ CFG_NAME_MAX);恰好 15 字符(= CFG_FILE_MAX_NAME_LEN)接受
|
||||
* —— load 契约(cfg_file_load)——
|
||||
* TC-CFG-030 文件缺失 -> 生成出厂模板写盘 + 返回 0
|
||||
* TC-CFG-031 文件存在 -> 解析有效键进 RAM 副本
|
||||
* TC-CFG-032 超长文件(> CFG_FILE_MAX_LEN)-> 工厂默认 + 重建模板 + 自检留痕
|
||||
* TC-CFG-033 读取失败 -> 返回 -1(RAM 保持工厂默认)
|
||||
* TC-CFG-034 未注册任何段 -> 返回 -1
|
||||
* TC-CONFIG-030 文件缺失 -> 生成出厂模板写盘 + 返回 0
|
||||
* TC-CONFIG-031 文件存在 -> 解析有效键进 RAM 副本
|
||||
* TC-CONFIG-032 超长文件(> CFG_FILE_MAX_LEN)-> 工厂默认 + 重建模板 + 自检留痕
|
||||
* TC-CONFIG-033 读取失败 -> 返回 -1(RAM 保持工厂默认)
|
||||
* TC-CONFIG-034 未注册任何段 -> 返回 -1
|
||||
* —— save 契约(cfg_file_save)——
|
||||
* TC-CFG-040 文件缺失 -> 重建完整文档
|
||||
* TC-CFG-041 外科手术:保留注释/未知段/未知键,受管键原位改写
|
||||
* TC-CFG-042 缺失受管段/键补写
|
||||
* TC-CFG-043 输出超长 -> 拒绝保存(-1) 且原文件不动
|
||||
* TC-CFG-044 受管键行超 CFG_LINE_TEST_MAX -> 拒绝保存(-1) 原文件不动(P2-1);
|
||||
* TC-CONFIG-040 文件缺失 -> 重建完整文档
|
||||
* TC-CONFIG-041 外科手术:保留注释/未知段/未知键,受管键原位改写
|
||||
* TC-CONFIG-042 缺失受管段/键补写
|
||||
* TC-CONFIG-043 输出超长 -> 拒绝保存(-1) 且原文件不动
|
||||
* TC-CONFIG-044 受管键行超 CFG_LINE_TEST_MAX -> 拒绝保存(-1) 原文件不动(P2-1);
|
||||
* 非受管键的超长行照旧放过(原样保留)
|
||||
* —— poll 契约(cfg_file_poll)——
|
||||
* TC-CFG-050 首轮建立基线(不重载)
|
||||
* TC-CFG-051 沉降去抖:连续 2 次稳定才重载
|
||||
* TC-CFG-052 与基线一致不重载
|
||||
* TC-CFG-053 变更后重载 + 挂回调段差异触发回调
|
||||
* TC-CFG-054 溢出到文件超长 -> 工厂默认 + 重建模板 + 自检留痕(不触发回调)
|
||||
* TC-CONFIG-050 首轮建立基线(不重载)
|
||||
* TC-CONFIG-051 沉降去抖:连续 2 次稳定才重载
|
||||
* TC-CONFIG-052 与基线一致不重载
|
||||
* TC-CONFIG-053 变更后重载 + 挂回调段差异触发回调
|
||||
* TC-CONFIG-054 溢出到文件超长 -> 工厂默认 + 重建模板 + 自检留痕(不触发回调)
|
||||
*
|
||||
* 通过:全部 TC PASS(main 返回 0)。
|
||||
* 入口:int main(void),返回 0=PASS / 1=FAIL(由 run 脚本判读)。
|
||||
@@ -333,9 +333,9 @@ static void register_std(void) {
|
||||
|
||||
/* ===================== 用例 ===================== */
|
||||
|
||||
/* TC-CFG-001/002:UINT 往返与非法值 */
|
||||
/* TC-CONFIG-001/002:UINT 往返与非法值 */
|
||||
static void tc_uint(void) {
|
||||
printf("[TC-CFG-001] UINT encode/decode round-trip\n");
|
||||
printf("[TC-CONFIG-001] UINT encode/decode round-trip\n");
|
||||
{
|
||||
uint8_t d1[1]; uint8_t d2[2]; uint8_t d4[4];
|
||||
CHECK(s_decode_uint(d1, 1u, "255") == 0 && d1[0] == 0xFFu, "u8 max 255");
|
||||
@@ -349,7 +349,7 @@ static void tc_uint(void) {
|
||||
"u16 0x1234 little-endian order");
|
||||
}
|
||||
|
||||
printf("[TC-CFG-002] UINT illegal values rejected\n");
|
||||
printf("[TC-CONFIG-002] UINT illegal values rejected\n");
|
||||
{
|
||||
uint8_t d[4];
|
||||
CHECK(s_decode_uint(d, 1u, "") == -1, "empty rejected");
|
||||
@@ -362,11 +362,11 @@ static void tc_uint(void) {
|
||||
}
|
||||
}
|
||||
|
||||
/* TC-CFG-003:IP4 */
|
||||
/* TC-CONFIG-003:IP4 */
|
||||
static void tc_ip4(void) {
|
||||
uint8_t d[4];
|
||||
|
||||
printf("[TC-CFG-003] IPv4 decode\n");
|
||||
printf("[TC-CONFIG-003] IPv4 decode\n");
|
||||
CHECK(s_decode_ip4(d, "0.0.0.0") == 0 && d[0] == 0u && d[3] == 0u, "all-zero");
|
||||
CHECK(s_decode_ip4(d, "255.255.255.255") == 0 &&
|
||||
d[0] == 255u && d[3] == 255u, "all-255");
|
||||
@@ -380,11 +380,11 @@ static void tc_ip4(void) {
|
||||
CHECK(s_decode_ip4(d, "") == -1, "empty rejected");
|
||||
}
|
||||
|
||||
/* TC-CFG-004:MAC */
|
||||
/* TC-CONFIG-004:MAC */
|
||||
static void tc_mac(void) {
|
||||
uint8_t d[6];
|
||||
|
||||
printf("[TC-CFG-004] MAC decode (separators/case)\n");
|
||||
printf("[TC-CONFIG-004] MAC decode (separators/case)\n");
|
||||
CHECK(s_decode_mac(d, "00:11:22:33:44:55") == 0 &&
|
||||
d[0] == 0x00u && d[5] == 0x55u, "colon separator");
|
||||
CHECK(s_decode_mac(d, "00-11-22-33-44-55") == 0 &&
|
||||
@@ -404,11 +404,11 @@ static void tc_mac(void) {
|
||||
CHECK(s_decode_mac(d, "") == -1, "empty rejected");
|
||||
}
|
||||
|
||||
/* TC-CFG-005:STR */
|
||||
/* TC-CONFIG-005:STR */
|
||||
static void tc_str(void) {
|
||||
uint8_t d[8];
|
||||
|
||||
printf("[TC-CFG-005] STR decode (length boundary)\n");
|
||||
printf("[TC-CONFIG-005] STR decode (length boundary)\n");
|
||||
CHECK(s_decode_str(d, 8u, "hello") == 0 && d[0] == 'h' && d[5] == '\0',
|
||||
"normal string + NUL");
|
||||
CHECK(s_decode_str(d, 8u, "1234567") == 0 && d[6] == '7' && d[7] == '\0',
|
||||
@@ -417,9 +417,9 @@ static void tc_str(void) {
|
||||
CHECK(s_decode_str(d, 8u, "") == 0 && d[0] == '\0', "empty string ok");
|
||||
}
|
||||
|
||||
/* TC-CFG-010~015:INI 解析 */
|
||||
/* TC-CONFIG-010~015:INI 解析 */
|
||||
static void tc_parse(void) {
|
||||
printf("[TC-CFG-010..015] INI parsing via load\n");
|
||||
printf("[TC-CONFIG-010..015] INI parsing via load\n");
|
||||
{
|
||||
vfs_reset();
|
||||
register_std();
|
||||
@@ -446,7 +446,7 @@ static void tc_parse(void) {
|
||||
CHECK(s_sys_data.baud == 9600u, "multi-section: sys parsed");
|
||||
}
|
||||
|
||||
printf("[TC-CFG-012] section/key name case-insensitive + value whitespace trim\n");
|
||||
printf("[TC-CONFIG-012] section/key name case-insensitive + value whitespace trim\n");
|
||||
{
|
||||
vfs_reset();
|
||||
register_std();
|
||||
@@ -462,7 +462,7 @@ static void tc_parse(void) {
|
||||
CHECK(s_net_data.ip[0] == 1u && s_net_data.ip[3] == 4u, "value whitespace trimmed");
|
||||
}
|
||||
|
||||
printf("[TC-CFG-011] LF-only line endings\n");
|
||||
printf("[TC-CONFIG-011] LF-only line endings\n");
|
||||
{
|
||||
vfs_reset();
|
||||
register_std();
|
||||
@@ -472,7 +472,7 @@ static void tc_parse(void) {
|
||||
CHECK(s_net_data.ip[3] == 8u, "LF: ip parsed");
|
||||
}
|
||||
|
||||
printf("[TC-CFG-015] key-value before any section ignored\n");
|
||||
printf("[TC-CONFIG-015] key-value before any section ignored\n");
|
||||
{
|
||||
vfs_reset();
|
||||
register_std();
|
||||
@@ -482,7 +482,7 @@ static void tc_parse(void) {
|
||||
CHECK(s_net_data.ip[0] == 5u, "valid key after section parsed");
|
||||
}
|
||||
|
||||
printf("[TC-CFG-014b] invalid value keeps factory default + logs\n");
|
||||
printf("[TC-CONFIG-014b] invalid value keeps factory default + logs\n");
|
||||
{
|
||||
vfs_reset();
|
||||
register_std();
|
||||
@@ -495,9 +495,9 @@ static void tc_parse(void) {
|
||||
}
|
||||
}
|
||||
|
||||
/* TC-CFG-020~023:register 校验 */
|
||||
/* TC-CONFIG-020~023:register 校验 */
|
||||
static void tc_register(void) {
|
||||
printf("[TC-CFG-020] register validation\n");
|
||||
printf("[TC-CONFIG-020] register validation\n");
|
||||
{
|
||||
cfg_section_reg_t r;
|
||||
vfs_reset();
|
||||
@@ -518,7 +518,7 @@ static void tc_register(void) {
|
||||
CHECK(cfg_file_register(&r) == -1, "NULL p_data rejected");
|
||||
}
|
||||
|
||||
printf("[TC-CFG-021] invalid key definitions rejected\n");
|
||||
printf("[TC-CONFIG-021] invalid key definitions rejected\n");
|
||||
{
|
||||
cfg_section_reg_t r;
|
||||
static const cfg_key_def_t bad_uint[] = { { "k", CFG_VAL_UINT, 0u, 3u } };
|
||||
@@ -544,7 +544,7 @@ static void tc_register(void) {
|
||||
CHECK(cfg_file_register(&r) == -1, "key len=0 rejected");
|
||||
}
|
||||
|
||||
printf("[TC-CFG-022] section name length limit\n");
|
||||
printf("[TC-CONFIG-022] section name length limit\n");
|
||||
{
|
||||
cfg_section_reg_t r;
|
||||
vfs_reset();
|
||||
@@ -558,7 +558,7 @@ static void tc_register(void) {
|
||||
CHECK(cfg_file_register(&r) == -1, "section name >= 16 chars rejected");
|
||||
}
|
||||
|
||||
printf("[TC-CFG-023] callback section data_size limit\n");
|
||||
printf("[TC-CONFIG-023] callback section data_size limit\n");
|
||||
{
|
||||
cfg_section_reg_t r;
|
||||
vfs_reset();
|
||||
@@ -576,7 +576,7 @@ static void tc_register(void) {
|
||||
CHECK(cfg_file_register(&r) == 0, "same section without callback accepted");
|
||||
}
|
||||
|
||||
printf("[TC-CFG-024] key name length limit\n");
|
||||
printf("[TC-CONFIG-024] key name length limit\n");
|
||||
{
|
||||
cfg_section_reg_t r;
|
||||
static const cfg_key_def_t long_key[] = {
|
||||
@@ -602,9 +602,9 @@ static void tc_register(void) {
|
||||
}
|
||||
}
|
||||
|
||||
/* TC-CFG-030~034:load 契约 */
|
||||
/* TC-CONFIG-030~034:load 契约 */
|
||||
static void tc_load(void) {
|
||||
printf("[TC-CFG-030] missing file -> factory template written\n");
|
||||
printf("[TC-CONFIG-030] missing file -> factory template written\n");
|
||||
{
|
||||
vfs_reset();
|
||||
register_std();
|
||||
@@ -618,7 +618,7 @@ static void tc_load(void) {
|
||||
CHECK(strstr(vfs_get(), "u8=7") != NULL, "template has default u8=7");
|
||||
}
|
||||
|
||||
printf("[TC-CFG-032] oversized file -> factory default + regenerate + syslog\n");
|
||||
printf("[TC-CONFIG-032] oversized file -> factory default + regenerate + syslog\n");
|
||||
{
|
||||
size_t i;
|
||||
vfs_reset();
|
||||
@@ -637,7 +637,7 @@ static void tc_load(void) {
|
||||
CHECK(s_vfs_len <= CFG_FILE_MAX_LEN, "file regenerated within limit");
|
||||
}
|
||||
|
||||
printf("[TC-CFG-033] read failure -> -1, RAM keeps factory default\n");
|
||||
printf("[TC-CONFIG-033] read failure -> -1, RAM keeps factory default\n");
|
||||
{
|
||||
vfs_reset();
|
||||
register_std();
|
||||
@@ -647,16 +647,16 @@ static void tc_load(void) {
|
||||
CHECK(s_net_data.u8 == s_net_def.u8, "RAM stays factory default");
|
||||
}
|
||||
|
||||
printf("[TC-CFG-034] load with no registered section -> -1\n");
|
||||
printf("[TC-CONFIG-034] load with no registered section -> -1\n");
|
||||
{
|
||||
vfs_reset();
|
||||
CHECK(cfg_file_load() == -1, "no section registered returns -1");
|
||||
}
|
||||
}
|
||||
|
||||
/* TC-CFG-040~043:save 契约 */
|
||||
/* TC-CONFIG-040~043:save 契约 */
|
||||
static void tc_save(void) {
|
||||
printf("[TC-CFG-040] save with missing file -> full document\n");
|
||||
printf("[TC-CONFIG-040] save with missing file -> full document\n");
|
||||
{
|
||||
vfs_reset();
|
||||
register_std();
|
||||
@@ -668,7 +668,7 @@ static void tc_save(void) {
|
||||
CHECK(strstr(vfs_get(), "baud=38400") != NULL, "second section written");
|
||||
}
|
||||
|
||||
printf("[TC-CFG-041] surgical save preserves comments/unknown\n");
|
||||
printf("[TC-CONFIG-041] surgical save preserves comments/unknown\n");
|
||||
{
|
||||
vfs_reset();
|
||||
register_std();
|
||||
@@ -689,7 +689,7 @@ static void tc_save(void) {
|
||||
CHECK(strstr(vfs_get(), "u8=200") != NULL, "managed key rewritten in place");
|
||||
}
|
||||
|
||||
printf("[TC-CFG-042] surgical save appends missing managed section/key\n");
|
||||
printf("[TC-CONFIG-042] surgical save appends missing managed section/key\n");
|
||||
{
|
||||
vfs_reset();
|
||||
register_std();
|
||||
@@ -703,7 +703,7 @@ static void tc_save(void) {
|
||||
CHECK(strstr(vfs_get(), "baud=57600") != NULL, "missing key written");
|
||||
}
|
||||
|
||||
printf("[TC-CFG-043] output overflow -> reject, original untouched\n");
|
||||
printf("[TC-CONFIG-043] output overflow -> reject, original untouched\n");
|
||||
{
|
||||
size_t i;
|
||||
vfs_reset();
|
||||
@@ -725,7 +725,7 @@ static void tc_save(void) {
|
||||
}
|
||||
}
|
||||
|
||||
printf("[TC-CFG-044] over-long managed key line -> reject (P2-1)\n");
|
||||
printf("[TC-CONFIG-044] over-long managed key line -> reject (P2-1)\n");
|
||||
{
|
||||
char buf[512];
|
||||
size_t n;
|
||||
@@ -772,9 +772,9 @@ static void tc_save(void) {
|
||||
}
|
||||
}
|
||||
|
||||
/* TC-CFG-050~054:poll 契约 */
|
||||
/* TC-CONFIG-050~054:poll 契约 */
|
||||
static void tc_poll(void) {
|
||||
printf("[TC-CFG-050] poll first round establishes baseline\n");
|
||||
printf("[TC-CONFIG-050] poll first round establishes baseline\n");
|
||||
{
|
||||
vfs_reset();
|
||||
register_std();
|
||||
@@ -784,7 +784,7 @@ static void tc_poll(void) {
|
||||
CHECK(s_base_valid == 1u, "baseline established");
|
||||
}
|
||||
|
||||
printf("[TC-CFG-051/052] settle debounce + no-change skip\n");
|
||||
printf("[TC-CONFIG-051/052] settle debounce + no-change skip\n");
|
||||
{
|
||||
vfs_reset();
|
||||
register_std();
|
||||
@@ -801,7 +801,7 @@ static void tc_poll(void) {
|
||||
CHECK(s_net_data.u8 == 88u, "reloaded after settle");
|
||||
}
|
||||
|
||||
printf("[TC-CFG-053] change triggers reload + callback\n");
|
||||
printf("[TC-CONFIG-053] change triggers reload + callback\n");
|
||||
{
|
||||
vfs_reset();
|
||||
register_std();
|
||||
@@ -815,7 +815,7 @@ static void tc_poll(void) {
|
||||
CHECK(s_net_cb_count >= 1, "callback fired on section change");
|
||||
}
|
||||
|
||||
printf("[TC-CFG-055] content change without size/mtime token change -> not detected\n");
|
||||
printf("[TC-CONFIG-055] content change without size/mtime token change -> not detected\n");
|
||||
{
|
||||
vfs_reset();
|
||||
register_std();
|
||||
@@ -830,7 +830,7 @@ static void tc_poll(void) {
|
||||
"same-token change ignored (size+mtime is the change signal)");
|
||||
}
|
||||
|
||||
printf("[TC-CFG-054] poll detects oversized file -> factory + regenerate + syslog\n");
|
||||
printf("[TC-CONFIG-054] poll detects oversized file -> factory + regenerate + syslog\n");
|
||||
{
|
||||
size_t i;
|
||||
vfs_reset();
|
||||
|
||||
+48
-48
@@ -22,17 +22,17 @@
|
||||
* 读数在跳变后 60 ms 内回到 ±0.05 Hz
|
||||
*
|
||||
* 覆盖点:
|
||||
* TC-FR-001 50 Hz 收敛时序(J3)+ 稳态精度(J1 子集)
|
||||
* TC-FR-002 扫频 45~55 Hz @0.5 Hz(J1,逐点判 + 最坏值打印)
|
||||
* TC-FR-003 噪声鲁棒(J2,最坏值打印)
|
||||
* TC-FR-004 频率阶跃 50->51(J4)
|
||||
* TC-FR-005 零幅浮空不发散(J5)+ 恢复后重新收敛
|
||||
* TC-FR-006 直流偏置抑制(全周傅氏滤直流 -> 测频不受影响)
|
||||
* TC-FR-007 3/5 次谐波污染抑制(相量基波选择性)
|
||||
* TC-FR-008 相位跳变假值钳制(J6)
|
||||
* TC-FR-009 UA 无幅值 -> 自动落 IA 源
|
||||
* TC-FR-010 init 幂等 / get 参数守卫 / 未收敛 -2
|
||||
* TC-FR-011 幅值门中途失效 -> valid 清零 + 读数保持(J5 中途版)
|
||||
* TC-FREQ-001 50 Hz 收敛时序(J3)+ 稳态精度(J1 子集)
|
||||
* TC-FREQ-002 扫频 45~55 Hz @0.5 Hz(J1,逐点判 + 最坏值打印)
|
||||
* TC-FREQ-003 噪声鲁棒(J2,最坏值打印)
|
||||
* TC-FREQ-004 频率阶跃 50->51(J4)
|
||||
* TC-FREQ-005 零幅浮空不发散(J5)+ 恢复后重新收敛
|
||||
* TC-FREQ-006 直流偏置抑制(全周傅氏滤直流 -> 测频不受影响)
|
||||
* TC-FREQ-007 3/5 次谐波污染抑制(相量基波选择性)
|
||||
* TC-FREQ-008 相位跳变假值钳制(J6)
|
||||
* TC-FREQ-009 UA 无幅值 -> 自动落 IA 源
|
||||
* TC-FREQ-010 init 幂等 / get 参数守卫 / 未收敛 -2
|
||||
* TC-FREQ-011 幅值门中途失效 -> valid 清零 + 读数保持(J5 中途版)
|
||||
*
|
||||
* 通过:全部 TC PASS(main 返回 0)。
|
||||
* 创建日期:2026-10-12(B8)
|
||||
@@ -134,7 +134,7 @@ static void chain_reset(void) {
|
||||
(void)freq_init();
|
||||
}
|
||||
|
||||
/* ===================== TC-FR-001:50 Hz 收敛时序 + 稳态精度 ===================== */
|
||||
/* ===================== TC-FREQ-001:50 Hz 收敛时序 + 稳态精度 ===================== */
|
||||
static void tc_converge_50(void) {
|
||||
float f = 0.0f;
|
||||
uint32_t first_valid_t = 0u, phasor_ready_t = 0u;
|
||||
@@ -155,17 +155,17 @@ static void tc_converge_50(void) {
|
||||
got = 1;
|
||||
}
|
||||
}
|
||||
CHECK(got, "TC-FR-001 freq becomes valid at 50 Hz");
|
||||
CHECK(got, "TC-FREQ-001 freq becomes valid at 50 Hz");
|
||||
CHECK((first_valid_t >= phasor_ready_t)
|
||||
&& ((first_valid_t - phasor_ready_t) <= 40u),
|
||||
"TC-FR-001 J3: first valid reading <= 40 ms after first phasor");
|
||||
"TC-FREQ-001 J3: first valid reading <= 40 ms after first phasor");
|
||||
(void)freq_get(&f);
|
||||
printf(" [DATA] 50 Hz steady: f=%.4f err=%.4f Hz (first valid @%u ms, phasor @%u ms)\n",
|
||||
(double)f, (double)f - 50.0, (unsigned)first_valid_t, (unsigned)phasor_ready_t);
|
||||
CHECK(fabsf(f - 50.0f) <= 0.01f, "TC-FR-001 J1(50Hz): |err| <= 0.01 Hz");
|
||||
CHECK(fabsf(f - 50.0f) <= 0.01f, "TC-FREQ-001 J1(50Hz): |err| <= 0.01 Hz");
|
||||
}
|
||||
|
||||
/* ===================== TC-FR-002:扫频 45~55 Hz @0.5 Hz(J1) ===================== */
|
||||
/* ===================== TC-FREQ-002:扫频 45~55 Hz @0.5 Hz(J1) ===================== */
|
||||
static void tc_sweep(void) {
|
||||
double worst = 0.0, worst_f = 0.0;
|
||||
int ok = 1;
|
||||
@@ -178,17 +178,17 @@ static void tc_sweep(void) {
|
||||
|
||||
chain_reset();
|
||||
drive_n(150u, f_true, 1000.0, 0.0, 0.0, 0.0, 0.0, 1u);
|
||||
CHECK(freq_get(&f_meas) == 0, "TC-FR-002 freq valid at each sweep point");
|
||||
CHECK(freq_get(&f_meas) == 0, "TC-FREQ-002 freq valid at each sweep point");
|
||||
err = fabs((double)f_meas - f_true);
|
||||
if (err > worst) { worst = err; worst_f = f_true; }
|
||||
if (err > 0.02) { ok = 0; }
|
||||
}
|
||||
printf(" [DATA] sweep 45.00~55.00 Hz step 0.5: worst |err| = %.4f Hz @ %.1f Hz (J1 <= 0.02)\n",
|
||||
worst, worst_f);
|
||||
CHECK(ok, "TC-FR-002 J1: |f_meas - f_true| <= 0.02 Hz over 45~55 Hz");
|
||||
CHECK(ok, "TC-FREQ-002 J1: |f_meas - f_true| <= 0.02 Hz over 45~55 Hz");
|
||||
}
|
||||
|
||||
/* ===================== TC-FR-003:噪声鲁棒(J2) ===================== */
|
||||
/* ===================== TC-FREQ-003:噪声鲁棒(J2) ===================== */
|
||||
static void tc_noise(void) {
|
||||
double worst = 0.0;
|
||||
int ok = 1;
|
||||
@@ -207,10 +207,10 @@ static void tc_noise(void) {
|
||||
if (err > 0.10) { ok = 0; }
|
||||
}
|
||||
printf(" [DATA] noise rms=1%% amp: worst |err| = %.4f Hz (J2 <= 0.10)\n", worst);
|
||||
CHECK(ok, "TC-FR-003 J2: |err| <= 0.10 Hz with 1% noise");
|
||||
CHECK(ok, "TC-FREQ-003 J2: |err| <= 0.10 Hz with 1% noise");
|
||||
}
|
||||
|
||||
/* ===================== TC-FR-004:频率阶跃 50->51(J4) ===================== */
|
||||
/* ===================== TC-FREQ-004:频率阶跃 50->51(J4) ===================== */
|
||||
static void tc_step(void) {
|
||||
float f = 0.0f;
|
||||
uint32_t settle = 0u;
|
||||
@@ -236,12 +236,12 @@ static void tc_step(void) {
|
||||
}
|
||||
printf(" [DATA] step 50->51: settle = %u ms, final f=%.4f err=%.4f\n",
|
||||
(unsigned)settle, (double)f, (double)f - 51.0);
|
||||
CHECK((settle != 0u) && (settle <= 120u), "TC-FR-004 J4: settle <= 120 ms");
|
||||
CHECK(ok, "TC-FR-004 J4: stays within +/-0.05 Hz after settle");
|
||||
CHECK(fabsf(f - 51.0f) <= 0.01f, "TC-FR-004 J1(51Hz): steady |err| <= 0.01 Hz");
|
||||
CHECK((settle != 0u) && (settle <= 120u), "TC-FREQ-004 J4: settle <= 120 ms");
|
||||
CHECK(ok, "TC-FREQ-004 J4: stays within +/-0.05 Hz after settle");
|
||||
CHECK(fabsf(f - 51.0f) <= 0.01f, "TC-FREQ-004 J1(51Hz): steady |err| <= 0.01 Hz");
|
||||
}
|
||||
|
||||
/* ===================== TC-FR-005:零幅浮空不发散(J5) ===================== */
|
||||
/* ===================== TC-FREQ-005:零幅浮空不发散(J5) ===================== */
|
||||
static void tc_zero_amp(void) {
|
||||
float f = 123.0f;
|
||||
uint32_t i;
|
||||
@@ -254,17 +254,17 @@ static void tc_zero_amp(void) {
|
||||
(void)freq_get(&f);
|
||||
if (!(f == f)) { no_nan = 0; } /* NaN 自比较为假 */
|
||||
}
|
||||
CHECK(never_valid, "TC-FR-005 J5: zero-amplitude never asserts valid");
|
||||
CHECK(no_nan && (f == 0.0f), "TC-FR-005 J5: reading stays 0, no divergence/NaN");
|
||||
CHECK(never_valid, "TC-FREQ-005 J5: zero-amplitude never asserts valid");
|
||||
CHECK(no_nan && (f == 0.0f), "TC-FREQ-005 J5: reading stays 0, no divergence/NaN");
|
||||
/* 恢复:重新注入波形后应再次收敛 */
|
||||
drive_n(150u, 49.0, 1000.0, 0.0, 0.0, 0.0, 0.0, 1u);
|
||||
(void)freq_get(&f);
|
||||
printf(" [DATA] recover after float: f=%.4f err=%.4f\n", (double)f, (double)f - 49.0);
|
||||
CHECK((freq_valid() != 0u) && (fabsf(f - 49.0f) <= 0.01f),
|
||||
"TC-FR-005 recovers and meets J1 after waveform returns");
|
||||
"TC-FREQ-005 recovers and meets J1 after waveform returns");
|
||||
}
|
||||
|
||||
/* ===================== TC-FR-006:直流偏置抑制 ===================== */
|
||||
/* ===================== TC-FREQ-006:直流偏置抑制 ===================== */
|
||||
static void tc_dc_offset(void) {
|
||||
float f = 0.0f;
|
||||
|
||||
@@ -272,10 +272,10 @@ static void tc_dc_offset(void) {
|
||||
drive_n(150u, 50.3, 1000.0, 8000.0, 0.0, 0.0, 0.0, 1u); /* DC = 8000 码 */
|
||||
(void)freq_get(&f);
|
||||
printf(" [DATA] DC=8000: f=%.4f err=%.4f\n", (double)f, (double)f - 50.3);
|
||||
CHECK(fabsf(f - 50.3f) <= 0.01f, "TC-FR-006 DC offset rejected: |err| <= 0.01 Hz");
|
||||
CHECK(fabsf(f - 50.3f) <= 0.01f, "TC-FREQ-006 DC offset rejected: |err| <= 0.01 Hz");
|
||||
}
|
||||
|
||||
/* ===================== TC-FR-007:3/5 次谐波污染 ===================== */
|
||||
/* ===================== TC-FREQ-007:3/5 次谐波污染 ===================== */
|
||||
static void tc_harmonics(void) {
|
||||
float f = 0.0f;
|
||||
|
||||
@@ -283,10 +283,10 @@ static void tc_harmonics(void) {
|
||||
drive_n(150u, 48.0, 1000.0, 0.0, 200.0, 100.0, 0.0, 1u); /* 20%/10% 谐波 */
|
||||
(void)freq_get(&f);
|
||||
printf(" [DATA] h3=20%% h5=10%%: f=%.4f err=%.4f\n", (double)f, (double)f - 48.0);
|
||||
CHECK(fabsf(f - 48.0f) <= 0.01f, "TC-FR-007 harmonics rejected: |err| <= 0.01 Hz");
|
||||
CHECK(fabsf(f - 48.0f) <= 0.01f, "TC-FREQ-007 harmonics rejected: |err| <= 0.01 Hz");
|
||||
}
|
||||
|
||||
/* ===================== TC-FR-008:相位跳变假值钳制(J6) ===================== */
|
||||
/* ===================== TC-FREQ-008:相位跳变假值钳制(J6) ===================== */
|
||||
static void tc_phase_jump(void) {
|
||||
float f = 0.0f;
|
||||
uint32_t i;
|
||||
@@ -306,11 +306,11 @@ static void tc_phase_jump(void) {
|
||||
}
|
||||
printf(" [DATA] after jump: f=%.4f err=%.4f (recover window 60 ms)\n",
|
||||
(double)f, (double)f - 50.0);
|
||||
CHECK(ok, "TC-FR-008 J6: recovers to +/-0.05 Hz within 60 ms after jump");
|
||||
CHECK(freq_valid() != 0u, "TC-FR-008 J6: still valid after clamp path");
|
||||
CHECK(ok, "TC-FREQ-008 J6: recovers to +/-0.05 Hz within 60 ms after jump");
|
||||
CHECK(freq_valid() != 0u, "TC-FREQ-008 J6: still valid after clamp path");
|
||||
}
|
||||
|
||||
/* ===================== TC-FR-009:UA 无幅值 -> IA 回退 ===================== */
|
||||
/* ===================== TC-FREQ-009:UA 无幅值 -> IA 回退 ===================== */
|
||||
static void tc_src_fallback(void) {
|
||||
float f = 0.0f;
|
||||
|
||||
@@ -319,39 +319,39 @@ static void tc_src_fallback(void) {
|
||||
(void)freq_get(&f);
|
||||
printf(" [DATA] UA=0 IA=1000: f=%.4f err=%.4f\n", (double)f, (double)f - 52.0);
|
||||
CHECK((freq_valid() != 0u) && (fabsf(f - 52.0f) <= 0.01f),
|
||||
"TC-FR-009 falls back to IA source when UA below amplitude gate");
|
||||
"TC-FREQ-009 falls back to IA source when UA below amplitude gate");
|
||||
}
|
||||
|
||||
/* ===================== TC-FR-010:init 幂等 / 参数守卫 ===================== */
|
||||
/* ===================== TC-FREQ-010:init 幂等 / 参数守卫 ===================== */
|
||||
static void tc_init_guards(void) {
|
||||
float f = 5.0f;
|
||||
|
||||
chain_reset();
|
||||
CHECK(freq_get(&f) == -2, "TC-FR-010 get before convergence -> -2");
|
||||
CHECK((f == 0.0f), "TC-FR-010 get -2 writes 0 to out");
|
||||
CHECK(freq_get(NULL) == -1, "TC-FR-010 NULL out -> -1");
|
||||
CHECK(freq_valid() == 0u, "TC-FR-010 valid=0 before convergence");
|
||||
CHECK(freq_last() == 0.0f, "TC-FR-010 last=0 before convergence");
|
||||
CHECK(freq_get(&f) == -2, "TC-FREQ-010 get before convergence -> -2");
|
||||
CHECK((f == 0.0f), "TC-FREQ-010 get -2 writes 0 to out");
|
||||
CHECK(freq_get(NULL) == -1, "TC-FREQ-010 NULL out -> -1");
|
||||
CHECK(freq_valid() == 0u, "TC-FREQ-010 valid=0 before convergence");
|
||||
CHECK(freq_last() == 0.0f, "TC-FREQ-010 last=0 before convergence");
|
||||
(void)freq_init();
|
||||
CHECK(freq_get(&f) == -2, "TC-FR-010 freq_init idempotent (still -2)");
|
||||
CHECK(freq_get(&f) == -2, "TC-FREQ-010 freq_init idempotent (still -2)");
|
||||
}
|
||||
|
||||
/* ===================== TC-FR-011:幅值门中途失效 -> 保持 ===================== */
|
||||
/* ===================== TC-FREQ-011:幅值门中途失效 -> 保持 ===================== */
|
||||
static void tc_gate_hold(void) {
|
||||
float f_before = 0.0f, f_after = 0.0f;
|
||||
|
||||
chain_reset();
|
||||
drive_n(150u, 50.0, 1000.0, 0.0, 0.0, 0.0, 0.0, 1u);
|
||||
(void)freq_get(&f_before);
|
||||
CHECK(freq_valid() == 1u, "TC-FR-011 valid before gate loss");
|
||||
CHECK(freq_valid() == 1u, "TC-FREQ-011 valid before gate loss");
|
||||
|
||||
drive_n(50u, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1u); /* 波形消失 */
|
||||
CHECK(freq_valid() == 0u, "TC-FR-011 J5: valid cleared on gate loss");
|
||||
CHECK(freq_valid() == 0u, "TC-FREQ-011 J5: valid cleared on gate loss");
|
||||
(void)freq_get(&f_after);
|
||||
printf(" [DATA] hold: before=%.4f held=%.4f delta=%.4f\n",
|
||||
(double)f_before, (double)f_after, (double)(f_after - f_before));
|
||||
CHECK(fabsf(f_after - f_before) <= 0.3f,
|
||||
"TC-FR-011 J5: reading bounded (|delta| <= 0.3 Hz) during gate loss");
|
||||
"TC-FREQ-011 J5: reading bounded (|delta| <= 0.3 Hz) during gate loss");
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
|
||||
@@ -13,16 +13,16 @@
|
||||
* 毫秒级穷举。用户名侧信道路径(错用户名也走哈希)同属纯逻辑。
|
||||
*
|
||||
* 覆盖点:
|
||||
* TC-FA-001 user_match:相等 / 大小写不敏感 / 不等 / NULL
|
||||
* TC-FA-002 正确用户名+正确口令 → OK,计数 0
|
||||
* TC-FA-003 错口令 → FAIL,计数 1
|
||||
* TC-FA-004 错用户名+对口令 → FAIL(哈希路径已走,时间拉平)
|
||||
* TC-FA-005 连续 5 次失败 → 第 6 次(锁定期内)LOCKED,对口令也拒
|
||||
* TC-FA-006 锁定期满(+60000 tick)→ 对口令 OK,计数清零
|
||||
* TC-FA-007 成功清零计数:3 败 + 1 成 → 再 4 败不触发锁定(第 5 败才锁)
|
||||
* TC-FA-008 tick 32 位回绕:锁定期内回绕点仍 LOCKED,期满回绕点放行
|
||||
* TC-FA-009 配置 pwd_hash 非法 hex → 恒 FAIL(fail-closed)
|
||||
* TC-FA-010 空口令 / NULL 口令 → FAIL;NULL creds/state → FAIL
|
||||
* TC-FTPAUTH-001 user_match:相等 / 大小写不敏感 / 不等 / NULL
|
||||
* TC-FTPAUTH-002 正确用户名+正确口令 → OK,计数 0
|
||||
* TC-FTPAUTH-003 错口令 → FAIL,计数 1
|
||||
* TC-FTPAUTH-004 错用户名+对口令 → FAIL(哈希路径已走,时间拉平)
|
||||
* TC-FTPAUTH-005 连续 5 次失败 → 第 6 次(锁定期内)LOCKED,对口令也拒
|
||||
* TC-FTPAUTH-006 锁定期满(+60000 tick)→ 对口令 OK,计数清零
|
||||
* TC-FTPAUTH-007 成功清零计数:3 败 + 1 成 → 再 4 败不触发锁定(第 5 败才锁)
|
||||
* TC-FTPAUTH-008 tick 32 位回绕:锁定期内回绕点仍 LOCKED,期满回绕点放行
|
||||
* TC-FTPAUTH-009 配置 pwd_hash 非法 hex → 恒 FAIL(fail-closed)
|
||||
* TC-FTPAUTH-010 空口令 / NULL 口令 → FAIL;NULL creds/state → FAIL
|
||||
*
|
||||
* 通过:全部 TC PASS(main 返回 0)。
|
||||
* 入口:int main(void),返回 0=PASS / 1=FAIL(由 run 脚本判读)。
|
||||
@@ -54,18 +54,18 @@ static int s_failed;
|
||||
|
||||
static const ftp_auth_creds_t s_creds = { "admin", DEF_HASH, 1u };
|
||||
|
||||
/* ===================== TC-FA-001:user_match ===================== */
|
||||
/* ===================== TC-FTPAUTH-001:user_match ===================== */
|
||||
|
||||
static void tc_user_match(void)
|
||||
{
|
||||
CHECK(ftp_auth_user_match("admin", "admin") == 1, "TC-FA-001a 相等匹配");
|
||||
CHECK(ftp_auth_user_match("admin", "ADMIN") == 1, "TC-FA-001b 大小写不敏感");
|
||||
CHECK(ftp_auth_user_match("admin", "root") == 0, "TC-FA-001c 不等拒绝");
|
||||
CHECK(ftp_auth_user_match("admin", "admin2") == 0, "TC-FA-001d 前缀不算匹配");
|
||||
CHECK(ftp_auth_user_match("admin", NULL) == 0, "TC-FA-001e NULL 拒绝");
|
||||
CHECK(ftp_auth_user_match("admin", "admin") == 1, "TC-FTPAUTH-001a 相等匹配");
|
||||
CHECK(ftp_auth_user_match("admin", "ADMIN") == 1, "TC-FTPAUTH-001b 大小写不敏感");
|
||||
CHECK(ftp_auth_user_match("admin", "root") == 0, "TC-FTPAUTH-001c 不等拒绝");
|
||||
CHECK(ftp_auth_user_match("admin", "admin2") == 0, "TC-FTPAUTH-001d 前缀不算匹配");
|
||||
CHECK(ftp_auth_user_match("admin", NULL) == 0, "TC-FTPAUTH-001e NULL 拒绝");
|
||||
}
|
||||
|
||||
/* ===================== TC-FA-002..004:基本判定 ===================== */
|
||||
/* ===================== TC-FTPAUTH-002..004:基本判定 ===================== */
|
||||
|
||||
static void tc_basic(void)
|
||||
{
|
||||
@@ -73,20 +73,20 @@ static void tc_basic(void)
|
||||
|
||||
(void)memset(&st, 0, sizeof(st));
|
||||
CHECK(ftp_auth_check(&s_creds, 1u, "admin", &st, 1000u) == FTP_AUTH_OK,
|
||||
"TC-FA-002 对用户名+对口令 → OK");
|
||||
CHECK(st.fail_count == 0u, "TC-FA-002b 成功后计数为 0");
|
||||
"TC-FTPAUTH-002 对用户名+对口令 → OK");
|
||||
CHECK(st.fail_count == 0u, "TC-FTPAUTH-002b 成功后计数为 0");
|
||||
|
||||
(void)memset(&st, 0, sizeof(st));
|
||||
CHECK(ftp_auth_check(&s_creds, 1u, "wrong", &st, 1000u) == FTP_AUTH_FAIL,
|
||||
"TC-FA-003 错口令 → FAIL");
|
||||
CHECK(st.fail_count == 1u, "TC-FA-003b 失败计数 1");
|
||||
"TC-FTPAUTH-003 错口令 → FAIL");
|
||||
CHECK(st.fail_count == 1u, "TC-FTPAUTH-003b 失败计数 1");
|
||||
|
||||
(void)memset(&st, 0, sizeof(st));
|
||||
CHECK(ftp_auth_check(&s_creds, 0u, "admin", &st, 1000u) == FTP_AUTH_FAIL,
|
||||
"TC-FA-004 错用户名+对口令 → FAIL(哈希路径已走)");
|
||||
"TC-FTPAUTH-004 错用户名+对口令 → FAIL(哈希路径已走)");
|
||||
}
|
||||
|
||||
/* ===================== TC-FA-005..006:锁定与解锁 ===================== */
|
||||
/* ===================== TC-FTPAUTH-005..006:锁定与解锁 ===================== */
|
||||
|
||||
static void tc_lock(void)
|
||||
{
|
||||
@@ -96,25 +96,25 @@ static void tc_lock(void)
|
||||
(void)memset(&st, 0, sizeof(st));
|
||||
for (int i = 0; i < 5; i++) {
|
||||
CHECK(ftp_auth_check(&s_creds, 1u, "wrong", &st, t) == FTP_AUTH_FAIL,
|
||||
"TC-FA-005 第 1..5 次失败 → FAIL");
|
||||
"TC-FTPAUTH-005 第 1..5 次失败 → FAIL");
|
||||
}
|
||||
CHECK(st.fail_count == 5u, "TC-FA-005b 计数到达 FAIL_MAX");
|
||||
CHECK(st.fail_count == 5u, "TC-FTPAUTH-005b 计数到达 FAIL_MAX");
|
||||
/* 锁定期内:对口令也 LOCKED,且不再计数 */
|
||||
CHECK(ftp_auth_check(&s_creds, 1u, "admin", &st, t + 1u) == FTP_AUTH_LOCKED,
|
||||
"TC-FA-005c 锁定期内对口令 → LOCKED");
|
||||
CHECK(st.fail_count == 5u, "TC-FA-005d LOCKED 不改变计数");
|
||||
"TC-FTPAUTH-005c 锁定期内对口令 → LOCKED");
|
||||
CHECK(st.fail_count == 5u, "TC-FTPAUTH-005d LOCKED 不改变计数");
|
||||
/* 59999 tick:仍在窗内(差值 < 60000) */
|
||||
CHECK(ftp_auth_check(&s_creds, 1u, "admin", &st,
|
||||
st.lock_until_tick - 1u) == FTP_AUTH_LOCKED,
|
||||
"TC-FA-005e 窗内最后 1 tick 仍 LOCKED");
|
||||
"TC-FTPAUTH-005e 窗内最后 1 tick 仍 LOCKED");
|
||||
/* 期满:恰好到达 lock_until → 放行 */
|
||||
CHECK(ftp_auth_check(&s_creds, 1u, "admin", &st,
|
||||
st.lock_until_tick) == FTP_AUTH_OK,
|
||||
"TC-FA-006 期满对口令 → OK");
|
||||
CHECK(st.fail_count == 0u, "TC-FA-006b 解锁成功后计数清零");
|
||||
"TC-FTPAUTH-006 期满对口令 → OK");
|
||||
CHECK(st.fail_count == 0u, "TC-FTPAUTH-006b 解锁成功后计数清零");
|
||||
}
|
||||
|
||||
/* ===================== TC-FA-007:成功清零计数 ===================== */
|
||||
/* ===================== TC-FTPAUTH-007:成功清零计数 ===================== */
|
||||
|
||||
static void tc_reset(void)
|
||||
{
|
||||
@@ -126,19 +126,19 @@ static void tc_reset(void)
|
||||
(void)ftp_auth_check(&s_creds, 1u, "wrong", &st, t);
|
||||
}
|
||||
CHECK(ftp_auth_check(&s_creds, 1u, "admin", &st, t) == FTP_AUTH_OK,
|
||||
"TC-FA-007a 3 败后成功 → OK");
|
||||
CHECK(st.fail_count == 0u, "TC-FA-007b 成功清零");
|
||||
"TC-FTPAUTH-007a 3 败后成功 → OK");
|
||||
CHECK(st.fail_count == 0u, "TC-FTPAUTH-007b 成功清零");
|
||||
for (int i = 0; i < 4; i++) {
|
||||
CHECK(ftp_auth_check(&s_creds, 1u, "wrong", &st, t) == FTP_AUTH_FAIL,
|
||||
"TC-FA-007c 清零后再 4 败仍 FAIL(未锁)");
|
||||
"TC-FTPAUTH-007c 清零后再 4 败仍 FAIL(未锁)");
|
||||
}
|
||||
CHECK(ftp_auth_check(&s_creds, 1u, "wrong", &st, t) == FTP_AUTH_FAIL,
|
||||
"TC-FA-007d 第 5 败 FAIL 并上锁");
|
||||
"TC-FTPAUTH-007d 第 5 败 FAIL 并上锁");
|
||||
CHECK(ftp_auth_check(&s_creds, 1u, "admin", &st, t + 1u) == FTP_AUTH_LOCKED,
|
||||
"TC-FA-007e 连续 5 败后 LOCKED");
|
||||
"TC-FTPAUTH-007e 连续 5 败后 LOCKED");
|
||||
}
|
||||
|
||||
/* ===================== TC-FA-008:tick 32 位回绕 ===================== */
|
||||
/* ===================== TC-FTPAUTH-008:tick 32 位回绕 ===================== */
|
||||
|
||||
static void tc_wraparound(void)
|
||||
{
|
||||
@@ -150,13 +150,13 @@ static void tc_wraparound(void)
|
||||
st.lock_until_tick = 0xFFFFFFF0u;
|
||||
/* 回绕前 240 tick:仍在窗内 */
|
||||
CHECK(ftp_auth_check(&s_creds, 1u, "admin", &st, 0xFFFFFF00u) == FTP_AUTH_LOCKED,
|
||||
"TC-FA-008a 回绕前窗内 → LOCKED");
|
||||
"TC-FTPAUTH-008a 回绕前窗内 → LOCKED");
|
||||
/* 回绕后 32 tick:now=0x10,(int32_t)(0x10-0xFFFFFFF0)=+32 → 期满 */
|
||||
CHECK(ftp_auth_check(&s_creds, 1u, "admin", &st, 0x00000010u) == FTP_AUTH_OK,
|
||||
"TC-FA-008b 回绕后期满 → OK(有符号差抗回绕)");
|
||||
"TC-FTPAUTH-008b 回绕后期满 → OK(有符号差抗回绕)");
|
||||
}
|
||||
|
||||
/* ===================== TC-FA-009..010:fail-closed 边界 ===================== */
|
||||
/* ===================== TC-FTPAUTH-009..010:fail-closed 边界 ===================== */
|
||||
|
||||
static void tc_fail_closed(void)
|
||||
{
|
||||
@@ -165,17 +165,17 @@ static void tc_fail_closed(void)
|
||||
|
||||
(void)memset(&st, 0, sizeof(st));
|
||||
CHECK(ftp_auth_check(&bad_creds, 1u, "admin", &st, 1000u) == FTP_AUTH_FAIL,
|
||||
"TC-FA-009 非法 hex 配置 → 恒 FAIL(无人能登录,fail-closed)");
|
||||
"TC-FTPAUTH-009 非法 hex 配置 → 恒 FAIL(无人能登录,fail-closed)");
|
||||
|
||||
(void)memset(&st, 0, sizeof(st));
|
||||
CHECK(ftp_auth_check(&s_creds, 1u, "", &st, 1000u) == FTP_AUTH_FAIL,
|
||||
"TC-FA-010a 空口令 → FAIL");
|
||||
"TC-FTPAUTH-010a 空口令 → FAIL");
|
||||
CHECK(ftp_auth_check(&s_creds, 1u, NULL, &st, 1000u) == FTP_AUTH_FAIL,
|
||||
"TC-FA-010b NULL 口令 → FAIL");
|
||||
"TC-FTPAUTH-010b NULL 口令 → FAIL");
|
||||
CHECK(ftp_auth_check(NULL, 1u, "admin", &st, 1000u) == FTP_AUTH_FAIL,
|
||||
"TC-FA-010c NULL creds → FAIL");
|
||||
"TC-FTPAUTH-010c NULL creds → FAIL");
|
||||
CHECK(ftp_auth_check(&s_creds, 1u, "admin", NULL, 1000u) == FTP_AUTH_FAIL,
|
||||
"TC-FA-010d NULL state → FAIL");
|
||||
"TC-FTPAUTH-010d NULL state → FAIL");
|
||||
}
|
||||
|
||||
/* ===================== main ===================== */
|
||||
|
||||
@@ -10,29 +10,29 @@
|
||||
* 发送经 send_apdu 回调全量捕获,时基由测试注入。
|
||||
*
|
||||
* 覆盖点(docs/子系统设计/IEC104上行设计说明.md §7):
|
||||
* TC-104-001 CP56Time2a 往返 / 闰年 / IV / 钳位
|
||||
* TC-104-002 IOA 3B 与短浮点小端往返
|
||||
* TC-104-003 APCI 重组:半帧 / 粘帧 / 坏起始符 / 坏长度
|
||||
* TC-104-004 STARTDT 握手 → RUN
|
||||
* TC-104-005 OPEN 态 I 帧忽略(序号不消费)
|
||||
* TC-104-006 总召全流程:actcon→4 分片(首召 COT=4)→actterm;二召 COT=2;RBT→COT=4
|
||||
* TC-104-007 遥信变位 COV(COT=3);无效位不触发
|
||||
* TC-104-008 遥测死区 COV:死区内不发 / 越死区发
|
||||
* TC-104-009 k 窗:12 未确认停发;S 确认后恢复
|
||||
* TC-104-010 w 阈:收满 8 发 S
|
||||
* TC-104-011 t2 到期发 S
|
||||
* TC-104-012 t3 空闲发 TESTFR act;未答 t1 超时 → IDLE;con 清挂起不误杀
|
||||
* TC-104-013 遥控两段式:选择/执行成功;失配 PN;拒绝类选择段即 PN
|
||||
* TC-104-014 定值两段写(真实 prot_set):越界 PN;执行后 get_f + selfcheck
|
||||
* TC-104-015 C_RD:YC 命中 / 定值命中 / 未知 IOA COT14+EVI
|
||||
* TC-104-016 C_CS:clock_sync 收正确 epoch;IV → PN;clock_sync 失败 → PN
|
||||
* TC-104-017 未知类型 COT12+EVI;错公共地址 COT13+EVI
|
||||
* TC-104-018 STOPDT:数据停发,TESTFR 仍应答
|
||||
* TC-104-019 序号错 → IDLE(链路故障)
|
||||
* TC-104-020 pts:无效通道 IV / 未就绪 NT / 无效遥信 IV / is_dp / 表尺寸
|
||||
* TC-104-021 C_TS / C_RP actcon
|
||||
* TC-104-022 周期上送 COT=1(YC 组 + 频率)
|
||||
* TC-104-023 k 窗满 COV 不丢事件(pend 暂存,窗开后补发)
|
||||
* TC-IEC104-001 CP56Time2a 往返 / 闰年 / IV / 钳位
|
||||
* TC-IEC104-002 IOA 3B 与短浮点小端往返
|
||||
* TC-IEC104-003 APCI 重组:半帧 / 粘帧 / 坏起始符 / 坏长度
|
||||
* TC-IEC104-004 STARTDT 握手 → RUN
|
||||
* TC-IEC104-005 OPEN 态 I 帧忽略(序号不消费)
|
||||
* TC-IEC104-006 总召全流程:actcon→4 分片(首召 COT=4)→actterm;二召 COT=2;RBT→COT=4
|
||||
* TC-IEC104-007 遥信变位 COV(COT=3);无效位不触发
|
||||
* TC-IEC104-008 遥测死区 COV:死区内不发 / 越死区发
|
||||
* TC-IEC104-009 k 窗:12 未确认停发;S 确认后恢复
|
||||
* TC-IEC104-010 w 阈:收满 8 发 S
|
||||
* TC-IEC104-011 t2 到期发 S
|
||||
* TC-IEC104-012 t3 空闲发 TESTFR act;未答 t1 超时 → IDLE;con 清挂起不误杀
|
||||
* TC-IEC104-013 遥控两段式:选择/执行成功;失配 PN;拒绝类选择段即 PN
|
||||
* TC-IEC104-014 定值两段写(真实 prot_set):越界 PN;执行后 get_f + selfcheck
|
||||
* TC-IEC104-015 C_RD:YC 命中 / 定值命中 / 未知 IOA COT14+EVI
|
||||
* TC-IEC104-016 C_CS:clock_sync 收正确 epoch;IV → PN;clock_sync 失败 → PN
|
||||
* TC-IEC104-017 未知类型 COT12+EVI;错公共地址 COT13+EVI
|
||||
* TC-IEC104-018 STOPDT:数据停发,TESTFR 仍应答
|
||||
* TC-IEC104-019 序号错 → IDLE(链路故障)
|
||||
* TC-IEC104-020 pts:无效通道 IV / 未就绪 NT / 无效遥信 IV / is_dp / 表尺寸
|
||||
* TC-IEC104-021 C_TS / C_RP actcon
|
||||
* TC-IEC104-022 周期上送 COT=1(YC 组 + 频率)
|
||||
* TC-IEC104-023 k 窗满 COV 不丢事件(pend 暂存,窗开后补发)
|
||||
*
|
||||
* 通过:全部 TC PASS(main 返回 0)。
|
||||
* 创建日期:2026-10-12(B4)
|
||||
|
||||
@@ -21,15 +21,15 @@
|
||||
* 主机侧由 harness 的 /utf-8 保证注释里的中文被正确解码。
|
||||
*
|
||||
* 用例前缀:TC-NP-NNN(NP = NAND Port);分组:
|
||||
* TC-NP-000 假芯片自洽(几何 / 上电态)
|
||||
* TC-NP-100..108 dhara_nand_is_free 整页扫描(N-12)
|
||||
* TC-NP-110..112 dhara_nand_is_free 越界守卫(N-13)
|
||||
* TC-NP-200..207 dhara_nand_prog(越界 / NULL / 往返 / 双编程探针 / 失败注入)
|
||||
* TC-NP-300..307 dhara_nand_read(越界 / 越窗 offset+length / 部分读 / ECC / E-42)
|
||||
* TC-NP-400..405 dhara_nand_copy(src 与 dst 双端守卫 / 正常搬页)
|
||||
* TC-NP-500..504 dhara_nand_erase(越界块零标坏块 / 整块回 0xFF / 失败注入)
|
||||
* TC-NP-600..605 dhara_nand_is_bad / dhara_nand_mark_bad(越界保守判坏、BBT 不变)
|
||||
* TC-NP-700 dhara map 级场景(写入 -> 重新 resume,双编程计数为 0)
|
||||
* TC-NANDPORT-000 假芯片自洽(几何 / 上电态)
|
||||
* TC-NANDPORT-100..108 dhara_nand_is_free 整页扫描(N-12)
|
||||
* TC-NANDPORT-110..112 dhara_nand_is_free 越界守卫(N-13)
|
||||
* TC-NANDPORT-200..207 dhara_nand_prog(越界 / NULL / 往返 / 双编程探针 / 失败注入)
|
||||
* TC-NANDPORT-300..307 dhara_nand_read(越界 / 越窗 offset+length / 部分读 / ECC / E-42)
|
||||
* TC-NANDPORT-400..405 dhara_nand_copy(src 与 dst 双端守卫 / 正常搬页)
|
||||
* TC-NANDPORT-500..504 dhara_nand_erase(越界块零标坏块 / 整块回 0xFF / 失败注入)
|
||||
* TC-NANDPORT-600..605 dhara_nand_is_bad / dhara_nand_mark_bad(越界保守判坏、BBT 不变)
|
||||
* TC-NANDPORT-700 dhara map 级场景(写入 -> 重新 resume,双编程计数为 0)
|
||||
*
|
||||
* 通过:全部 CHECK 通过(main 返回 0)。
|
||||
* 入口:int main(void),返回 0=PASS / 1=FAIL(由 run 脚本判读)。
|
||||
@@ -402,7 +402,7 @@ static int s_failed;
|
||||
|
||||
/* dhara 核心(真实源,非桩):nand_ftl.c 引用 dhara_map_*,必须一并纳入才能链接。
|
||||
* 纳入后本编译单元 = 移植层 + 它服务的 FTL 本体,故 dhara map 级场景
|
||||
* (TC-NP-700 写入 -> 重新 resume)测的是真链路。顺序:journal 在 map 之前。 */
|
||||
* (TC-NANDPORT-700 写入 -> 重新 resume)测的是真链路。顺序:journal 在 map 之前。 */
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4100 4244 4334 4701)
|
||||
@@ -428,7 +428,7 @@ static struct dhara_nand s_ut_nand;
|
||||
* N-12 修复**之前**的 dhara_nand_is_free:只读页首 64 B 就回答"空闲"。
|
||||
* 本函数按当时的形状内联一份(同样经假芯片的两段式读),用来证明本套件**有牙**:
|
||||
* 对同一页,旧算法答 1(误判空闲)、新实现答 0。将来有人把 is_free 改回只看
|
||||
* 页首,TC-NP-105 立刻变红——而不是"测试跟着实现一起改回去"。
|
||||
* 页首,TC-NANDPORT-105 立刻变红——而不是"测试跟着实现一起改回去"。
|
||||
*/
|
||||
static int old_is_free_first64(const struct dhara_nand *n, dhara_page_t p) {
|
||||
uint8_t buf[64];
|
||||
@@ -449,18 +449,18 @@ static int old_is_free_first64(const struct dhara_nand *n, dhara_page_t p) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ===================== TC-NP-100..108:dhara_nand_is_free(整页扫描) =====================
|
||||
/* ===================== TC-NANDPORT-100..108:dhara_nand_is_free(整页扫描) =====================
|
||||
*
|
||||
* N-12:旧实现只看页首 64 B,会把"页首 0xFF、后段有数据"的已编程页误判空闲
|
||||
* -> dhara 往已编程页再编程 = 数据丢失。本组把"必须扫完整页"钉死,
|
||||
* 并用 TC-NP-105 的旧算法对照证明这组断言真的能咬人。
|
||||
* 并用 TC-NANDPORT-105 的旧算法对照证明这组断言真的能咬人。
|
||||
*/
|
||||
static void tc_is_free(void) {
|
||||
static uint8_t page_buf[FAKE_PAGE_SIZE];
|
||||
struct dhara_nand zeroed;
|
||||
|
||||
/* TC-NP-100:整页擦除 -> 1 */
|
||||
printf("[TC-NP-100] erased page is free\n");
|
||||
/* TC-NANDPORT-100:整页擦除 -> 1 */
|
||||
printf("[TC-NANDPORT-100] erased page is free\n");
|
||||
fake_chip_reset();
|
||||
CHECK(dhara_nand_is_free(&s_ut_nand, 0u) == 1, "erased page -> is_free = 1");
|
||||
CHECK(g_fake_page_read_cnt == 1u, "one page_read only (no per-byte commands)");
|
||||
@@ -469,8 +469,8 @@ static void tc_is_free(void) {
|
||||
CHECK(g_fake_isfree_scan_cnt == (FAKE_PAGE_SIZE / 64u),
|
||||
"64B column-read fingerprint calibrated (proves scenario really calls is_free)");
|
||||
|
||||
/* TC-NP-101:第 0 字节有数据 -> 0(快路径) */
|
||||
printf("[TC-NP-101] byte 0 programmed -> not free\n");
|
||||
/* TC-NANDPORT-101:第 0 字节有数据 -> 0(快路径) */
|
||||
printf("[TC-NANDPORT-101] byte 0 programmed -> not free\n");
|
||||
fake_chip_reset();
|
||||
(void)memset(page_buf, 0xFF, sizeof(page_buf));
|
||||
page_buf[0] = 0x00u;
|
||||
@@ -479,10 +479,10 @@ static void tc_is_free(void) {
|
||||
CHECK(g_fake_read_cache_cnt == 1u,
|
||||
"early exit on first chunk = fast path (same cost as the old impl)");
|
||||
|
||||
/* TC-NP-102:N-12 回归用例
|
||||
/* TC-NANDPORT-102:N-12 回归用例
|
||||
* 页首 64 B 全 0xFF、第 1000 字节 = 0x00 -> 必须答"非空"。
|
||||
* 旧实现只看页首 64 B 会误判空闲,dhara 遂往这一页再编程。 */
|
||||
printf("[TC-NP-102] N-12 regression: hole in first 64B, data at byte 1000\n");
|
||||
printf("[TC-NANDPORT-102] N-12 regression: hole in first 64B, data at byte 1000\n");
|
||||
fake_chip_reset();
|
||||
(void)memset(page_buf, 0xFF, sizeof(page_buf));
|
||||
page_buf[1000] = 0x00u;
|
||||
@@ -492,8 +492,8 @@ static void tc_is_free(void) {
|
||||
CHECK(g_fake_read_cache_cnt > 1u,
|
||||
"scan continues past the first 64B (old impl stopped here = root cause)");
|
||||
|
||||
/* TC-NP-103:只有最后一个字节非 0xFF -> 0 */
|
||||
printf("[TC-NP-103] only last byte programmed -> not free\n");
|
||||
/* TC-NANDPORT-103:只有最后一个字节非 0xFF -> 0 */
|
||||
printf("[TC-NANDPORT-103] only last byte programmed -> not free\n");
|
||||
fake_chip_reset();
|
||||
(void)memset(page_buf, 0xFF, sizeof(page_buf));
|
||||
page_buf[FAKE_PAGE_SIZE - 1u] = 0x5Au;
|
||||
@@ -503,8 +503,8 @@ static void tc_is_free(void) {
|
||||
CHECK(g_fake_read_cache_cnt == (FAKE_PAGE_SIZE / 64u),
|
||||
"full scan to the page tail before answering (32 column reads)");
|
||||
|
||||
/* TC-NP-104:只有第 64 字节非 0xFF -> 0(旧窗口右边界外的第一个字节) */
|
||||
printf("[TC-NP-104] only byte 64 programmed -> not free\n");
|
||||
/* TC-NANDPORT-104:只有第 64 字节非 0xFF -> 0(旧窗口右边界外的第一个字节) */
|
||||
printf("[TC-NANDPORT-104] only byte 64 programmed -> not free\n");
|
||||
fake_chip_reset();
|
||||
(void)memset(page_buf, 0xFF, sizeof(page_buf));
|
||||
page_buf[64u] = 0x00u;
|
||||
@@ -512,10 +512,10 @@ static void tc_is_free(void) {
|
||||
CHECK(dhara_nand_is_free(&s_ut_nand, 4u) == 0,
|
||||
"only byte 64 (first byte outside the old window) -> is_free = 0");
|
||||
|
||||
/* TC-NP-105:旧算法对照(证明本套件有牙)
|
||||
/* TC-NANDPORT-105:旧算法对照(证明本套件有牙)
|
||||
* 同一页形态:旧算法答 1 = 误判空闲,新实现答 0。
|
||||
* 任何人把 is_free 改回"只看页首",这条立刻红。 */
|
||||
printf("[TC-NP-105] old-algorithm contrast (test has teeth)\n");
|
||||
printf("[TC-NANDPORT-105] old-algorithm contrast (test has teeth)\n");
|
||||
fake_chip_reset();
|
||||
(void)memset(page_buf, 0xFF, sizeof(page_buf));
|
||||
page_buf[1000] = 0x00u;
|
||||
@@ -525,8 +525,8 @@ static void tc_is_free(void) {
|
||||
CHECK(dhara_nand_is_free(&s_ut_nand, 5u) == 0,
|
||||
"new implementation answers not-free -> 0 (opposite verdict = teeth)");
|
||||
|
||||
/* TC-NP-106:读失败保守判非空(E-42 同族) */
|
||||
printf("[TC-NP-106] read failure is answered conservatively\n");
|
||||
/* TC-NANDPORT-106:读失败保守判非空(E-42 同族) */
|
||||
printf("[TC-NANDPORT-106] read failure is answered conservatively\n");
|
||||
fake_chip_reset();
|
||||
s_fail_page_read = 1;
|
||||
CHECK(dhara_nand_is_free(&s_ut_nand, 6u) == 0,
|
||||
@@ -536,8 +536,8 @@ static void tc_is_free(void) {
|
||||
CHECK(dhara_nand_is_free(&s_ut_nand, 7u) == 0,
|
||||
"read_from_cache failure -> not free (E-42 family)");
|
||||
|
||||
/* TC-NP-107:NULL / num_blocks = 0 的几何守卫 */
|
||||
printf("[TC-NP-107] NULL geometry / zero blocks guard\n");
|
||||
/* TC-NANDPORT-107:NULL / num_blocks = 0 的几何守卫 */
|
||||
printf("[TC-NANDPORT-107] NULL geometry / zero blocks guard\n");
|
||||
fake_chip_reset();
|
||||
CHECK(dhara_nand_is_free(NULL, 0u) == 0, "n = NULL -> not free, no crash");
|
||||
CHECK(fake_chip_access_total() == 0u, "n = NULL causes zero chip access");
|
||||
@@ -547,8 +547,8 @@ static void tc_is_free(void) {
|
||||
CHECK(dhara_nand_is_free(&zeroed, 0u) == 0, "num_blocks = 0 -> not free");
|
||||
CHECK(fake_chip_access_total() == 0u, "num_blocks = 0 causes zero chip access");
|
||||
|
||||
/* TC-NP-108:擦除后重新判空(假芯片语义自洽,防"擦除没生效"假绿) */
|
||||
printf("[TC-NP-108] fake chip erase really clears the array\n");
|
||||
/* TC-NANDPORT-108:擦除后重新判空(假芯片语义自洽,防"擦除没生效"假绿) */
|
||||
printf("[TC-NANDPORT-108] fake chip erase really clears the array\n");
|
||||
fake_chip_reset();
|
||||
fake_fill_pattern(page_buf, FAKE_PAGE_SIZE, 7u);
|
||||
fake_poke_page(8u, page_buf, FAKE_PAGE_SIZE);
|
||||
@@ -557,9 +557,9 @@ static void tc_is_free(void) {
|
||||
CHECK(dhara_nand_is_free(&s_ut_nand, 8u) == 1, "after erase -> free (fake chip sane)");
|
||||
}
|
||||
|
||||
/* ===================== TC-NP-110..112:is_free 越界守卫(N-13) ===================== */
|
||||
/* ===================== TC-NANDPORT-110..112:is_free 越界守卫(N-13) ===================== */
|
||||
static void tc_is_free_oob(void) {
|
||||
printf("[TC-NP-110] is_free out-of-range pages (N-13)\n");
|
||||
printf("[TC-NANDPORT-110] is_free out-of-range pages (N-13)\n");
|
||||
|
||||
fake_chip_reset();
|
||||
CHECK(dhara_nand_is_free(&s_ut_nand, DHARA_PAGE_NONE) == 0,
|
||||
@@ -567,13 +567,13 @@ static void tc_is_free_oob(void) {
|
||||
CHECK(fake_chip_access_total() == 0u,
|
||||
"DHARA_PAGE_NONE causes zero chip access (no truncated address)");
|
||||
|
||||
printf("[TC-NP-111] is_free at total_pages boundary\n");
|
||||
printf("[TC-NANDPORT-111] is_free at total_pages boundary\n");
|
||||
fake_chip_reset();
|
||||
CHECK(dhara_nand_is_free(&s_ut_nand, UT_OOB_PAGE) == 0,
|
||||
"page == total_pages -> is_free = 0");
|
||||
CHECK(fake_chip_access_total() == 0u, "page == total_pages -> zero chip access");
|
||||
|
||||
printf("[TC-NP-112] is_free beyond total_pages\n");
|
||||
printf("[TC-NANDPORT-112] is_free beyond total_pages\n");
|
||||
fake_chip_reset();
|
||||
CHECK(dhara_nand_is_free(&s_ut_nand, UT_OOB_PAGE + 1u) == 0,
|
||||
"page == total_pages + 1 -> is_free = 0");
|
||||
@@ -586,13 +586,13 @@ static int fake_no_write_access(void) {
|
||||
(g_fake_program_exec_cnt == 0u) && (g_fake_block_erase_cnt == 0u);
|
||||
}
|
||||
|
||||
/* ===================== TC-NP-200..205:dhara_nand_prog ===================== */
|
||||
/* ===================== TC-NANDPORT-200..205:dhara_nand_prog ===================== */
|
||||
static void tc_prog(void) {
|
||||
static uint8_t page_buf[FAKE_PAGE_SIZE];
|
||||
dhara_error_t err;
|
||||
|
||||
/* TC-NP-200:越界页 -> -1 + CORRUPT_MAP + 零写入 */
|
||||
printf("[TC-NP-200] prog out-of-range page -> -1, zero write\n");
|
||||
/* TC-NANDPORT-200:越界页 -> -1 + CORRUPT_MAP + 零写入 */
|
||||
printf("[TC-NANDPORT-200] prog out-of-range page -> -1, zero write\n");
|
||||
fake_chip_reset();
|
||||
fake_fill_pattern(page_buf, FAKE_PAGE_SIZE, 11u);
|
||||
err = DHARA_E_NONE;
|
||||
@@ -602,10 +602,10 @@ static void tc_prog(void) {
|
||||
CHECK(fake_no_write_access(), "prog out-of-range -> zero write access");
|
||||
CHECK(g_fake_mark_bad_cnt == 0u, "prog out-of-range -> no block marked bad");
|
||||
|
||||
/* TC-NP-201:DHARA_PAGE_NONE -> -1 + CORRUPT_MAP + 零写入
|
||||
/* TC-NANDPORT-201:DHARA_PAGE_NONE -> -1 + CORRUPT_MAP + 零写入
|
||||
* 旧实现会把 0xffffffff 加偏移送进 SPI 命令,被地址位截断成某个真实页
|
||||
* -> 静默写坏无辜数据;现在必须在守卫处就挡住。 */
|
||||
printf("[TC-NP-201] prog DHARA_PAGE_NONE -> -1, zero write (N-13)\n");
|
||||
printf("[TC-NANDPORT-201] prog DHARA_PAGE_NONE -> -1, zero write (N-13)\n");
|
||||
fake_chip_reset();
|
||||
err = DHARA_E_NONE;
|
||||
CHECK(dhara_nand_prog(&s_ut_nand, DHARA_PAGE_NONE, page_buf, &err) == -1,
|
||||
@@ -613,16 +613,16 @@ static void tc_prog(void) {
|
||||
CHECK(err == DHARA_E_CORRUPT_MAP, "prog DHARA_PAGE_NONE -> DHARA_E_CORRUPT_MAP");
|
||||
CHECK(fake_chip_access_total() == 0u, "prog DHARA_PAGE_NONE -> zero chip access");
|
||||
|
||||
/* TC-NP-202:data == NULL -> -1(守卫顺带挡住空指针) */
|
||||
printf("[TC-NP-202] prog with NULL data -> -1\n");
|
||||
/* TC-NANDPORT-202:data == NULL -> -1(守卫顺带挡住空指针) */
|
||||
printf("[TC-NANDPORT-202] prog with NULL data -> -1\n");
|
||||
fake_chip_reset();
|
||||
err = DHARA_E_NONE;
|
||||
CHECK(dhara_nand_prog(&s_ut_nand, 0u, NULL, &err) == -1, "prog data = NULL -> -1");
|
||||
CHECK(err == DHARA_E_CORRUPT_MAP, "prog data = NULL -> DHARA_E_CORRUPT_MAP");
|
||||
CHECK(fake_no_write_access(), "prog data = NULL -> zero write access");
|
||||
|
||||
/* TC-NP-203:正常页 -> 0 且回读一致 */
|
||||
printf("[TC-NP-203] prog a valid page -> 0, read-back matches\n");
|
||||
/* TC-NANDPORT-203:正常页 -> 0 且回读一致 */
|
||||
printf("[TC-NANDPORT-203] prog a valid page -> 0, read-back matches\n");
|
||||
fake_chip_reset();
|
||||
err = DHARA_E_NONE;
|
||||
CHECK(dhara_nand_prog(&s_ut_nand, 64u, page_buf, &err) == 0, "prog page 64 -> 0");
|
||||
@@ -630,8 +630,8 @@ static void tc_prog(void) {
|
||||
CHECK(fake_page_equals(64u, page_buf, FAKE_PAGE_SIZE), "prog page 64 content on chip");
|
||||
CHECK(g_fake_double_program_cnt == 0u, "prog onto an erased page -> no violation");
|
||||
|
||||
/* TC-NP-204:最后一个合法页(上界内边界) */
|
||||
printf("[TC-NP-204] prog last valid page (boundary inside)\n");
|
||||
/* TC-NANDPORT-204:最后一个合法页(上界内边界) */
|
||||
printf("[TC-NANDPORT-204] prog last valid page (boundary inside)\n");
|
||||
fake_chip_reset();
|
||||
err = DHARA_E_NONE;
|
||||
CHECK(dhara_nand_prog(&s_ut_nand, UT_TOTAL_PAGES - 1u, page_buf, &err) == 0,
|
||||
@@ -639,8 +639,8 @@ static void tc_prog(void) {
|
||||
CHECK(fake_page_equals(UT_TOTAL_PAGES - 1u, page_buf, FAKE_PAGE_SIZE),
|
||||
"last valid page content on chip");
|
||||
|
||||
/* TC-NP-205:双编程探针自检——同一页再编程必须被记违规(防探针是死码) */
|
||||
printf("[TC-NP-205] double-program probe really fires\n");
|
||||
/* TC-NANDPORT-205:双编程探针自检——同一页再编程必须被记违规(防探针是死码) */
|
||||
printf("[TC-NANDPORT-205] double-program probe really fires\n");
|
||||
fake_chip_reset();
|
||||
err = DHARA_E_NONE;
|
||||
(void)dhara_nand_prog(&s_ut_nand, 128u, page_buf, &err);
|
||||
@@ -648,8 +648,8 @@ static void tc_prog(void) {
|
||||
CHECK(g_fake_double_program_cnt == 1u, "reprogramming a programmed page -> 1 violation");
|
||||
CHECK(g_fake_last_double_program_page == 128u, "violation records the offending page");
|
||||
|
||||
/* TC-NP-206:编程失败 -> BAD_BLOCK + 标坏该块(错误分类不被守卫改动破坏) */
|
||||
printf("[TC-NP-206] program failure -> BAD_BLOCK + mark bad\n");
|
||||
/* TC-NANDPORT-206:编程失败 -> BAD_BLOCK + 标坏该块(错误分类不被守卫改动破坏) */
|
||||
printf("[TC-NANDPORT-206] program failure -> BAD_BLOCK + mark bad\n");
|
||||
fake_chip_reset();
|
||||
s_fail_program_exec = 1;
|
||||
err = DHARA_E_NONE;
|
||||
@@ -659,9 +659,9 @@ static void tc_prog(void) {
|
||||
CHECK(g_fake_mark_bad_cnt == 1u, "program failure marks exactly one block bad");
|
||||
CHECK(g_fake_mark_bad_log[0] == 2u, "the block marked bad is the page's own block");
|
||||
|
||||
/* TC-NP-207:program_load 失败(装载阶段)-> 同样 BAD_BLOCK + 标坏该块,
|
||||
/* TC-NANDPORT-207:program_load 失败(装载阶段)-> 同样 BAD_BLOCK + 标坏该块,
|
||||
* 且在 exec 之前就短路(真实芯片:02h 都没成,10h 自然不发) */
|
||||
printf("[TC-NP-207] program_load failure -> BAD_BLOCK + mark bad\n");
|
||||
printf("[TC-NANDPORT-207] program_load failure -> BAD_BLOCK + mark bad\n");
|
||||
fake_chip_reset();
|
||||
s_fail_program_load = 1;
|
||||
err = DHARA_E_NONE;
|
||||
@@ -673,14 +673,14 @@ static void tc_prog(void) {
|
||||
CHECK(g_fake_mark_bad_log[0] == 3u, "the block marked bad is the page's own block");
|
||||
}
|
||||
|
||||
/* ===================== TC-NP-300..307:dhara_nand_read ===================== */
|
||||
/* ===================== TC-NANDPORT-300..307:dhara_nand_read ===================== */
|
||||
static void tc_read(void) {
|
||||
static uint8_t page_buf[FAKE_PAGE_SIZE];
|
||||
static uint8_t rd[FAKE_PAGE_SIZE];
|
||||
dhara_error_t err;
|
||||
|
||||
/* TC-NP-300/301:越界页 -> -1 + CORRUPT_MAP + 零访问 */
|
||||
printf("[TC-NP-300] read out-of-range page -> -1, zero access\n");
|
||||
/* TC-NANDPORT-300/301:越界页 -> -1 + CORRUPT_MAP + 零访问 */
|
||||
printf("[TC-NANDPORT-300] read out-of-range page -> -1, zero access\n");
|
||||
fake_chip_reset();
|
||||
err = DHARA_E_NONE;
|
||||
CHECK(dhara_nand_read(&s_ut_nand, UT_OOB_PAGE, 0u, 512u, rd, &err) == -1,
|
||||
@@ -688,7 +688,7 @@ static void tc_read(void) {
|
||||
CHECK(err == DHARA_E_CORRUPT_MAP, "read out-of-range -> DHARA_E_CORRUPT_MAP");
|
||||
CHECK(fake_chip_access_total() == 0u, "read out-of-range -> zero chip access");
|
||||
|
||||
printf("[TC-NP-301] read DHARA_PAGE_NONE -> -1, zero access\n");
|
||||
printf("[TC-NANDPORT-301] read DHARA_PAGE_NONE -> -1, zero access\n");
|
||||
fake_chip_reset();
|
||||
err = DHARA_E_NONE;
|
||||
CHECK(dhara_nand_read(&s_ut_nand, DHARA_PAGE_NONE, 0u, 512u, rd, &err) == -1,
|
||||
@@ -696,8 +696,8 @@ static void tc_read(void) {
|
||||
CHECK(err == DHARA_E_CORRUPT_MAP, "read DHARA_PAGE_NONE -> DHARA_E_CORRUPT_MAP");
|
||||
CHECK(fake_chip_access_total() == 0u, "read DHARA_PAGE_NONE -> zero chip access");
|
||||
|
||||
/* TC-NP-302:offset + length 越过 2048 -> -1 */
|
||||
printf("[TC-NP-302] read spanning past the page end -> -1\n");
|
||||
/* TC-NANDPORT-302:offset + length 越过 2048 -> -1 */
|
||||
printf("[TC-NANDPORT-302] read spanning past the page end -> -1\n");
|
||||
fake_chip_reset();
|
||||
err = DHARA_E_NONE;
|
||||
CHECK(dhara_nand_read(&s_ut_nand, 0u, 2000u, 100u, rd, &err) == -1,
|
||||
@@ -712,16 +712,16 @@ static void tc_read(void) {
|
||||
CHECK(dhara_nand_read(&s_ut_nand, 0u, 0u, FAKE_PAGE_SIZE + 1u, rd, &err) == -1,
|
||||
"read length 2049 -> -1");
|
||||
|
||||
/* TC-NP-303:NULL data -> -1 */
|
||||
printf("[TC-NP-303] read with NULL data -> -1\n");
|
||||
/* TC-NANDPORT-303:NULL data -> -1 */
|
||||
printf("[TC-NANDPORT-303] read with NULL data -> -1\n");
|
||||
fake_chip_reset();
|
||||
err = DHARA_E_NONE;
|
||||
CHECK(dhara_nand_read(&s_ut_nand, 0u, 0u, 512u, NULL, &err) == -1,
|
||||
"read data = NULL -> -1");
|
||||
CHECK(fake_chip_access_total() == 0u, "read data = NULL -> zero chip access");
|
||||
|
||||
/* TC-NP-304:正常部分读 -> 0 且内容正确 */
|
||||
printf("[TC-NP-304] partial read returns the right slice\n");
|
||||
/* TC-NANDPORT-304:正常部分读 -> 0 且内容正确 */
|
||||
printf("[TC-NANDPORT-304] partial read returns the right slice\n");
|
||||
prep_content_page(page_buf, 21u);
|
||||
err = DHARA_E_NONE;
|
||||
CHECK(dhara_nand_read(&s_ut_nand, UT_SRC_PAGE, 1024u, 512u, rd, &err) == 0,
|
||||
@@ -729,16 +729,16 @@ static void tc_read(void) {
|
||||
CHECK(memcmp(rd, &page_buf[1024], 512u) == 0, "partial read returns the right bytes");
|
||||
CHECK(g_fake_page_read_cnt == 1u, "partial read issues one page_read");
|
||||
|
||||
/* TC-NP-305:整页读 -> 0 且内容正确(边界 length == 2048) */
|
||||
printf("[TC-NP-305] full page read\n");
|
||||
/* TC-NANDPORT-305:整页读 -> 0 且内容正确(边界 length == 2048) */
|
||||
printf("[TC-NANDPORT-305] full page read\n");
|
||||
prep_content_page(page_buf, 21u);
|
||||
err = DHARA_E_NONE;
|
||||
CHECK(dhara_nand_read(&s_ut_nand, UT_SRC_PAGE, 0u, FAKE_PAGE_SIZE, rd, &err) == 0,
|
||||
"full page read (length == 2048) -> 0");
|
||||
CHECK(memcmp(rd, page_buf, FAKE_PAGE_SIZE) == 0, "full page read matches the chip");
|
||||
|
||||
/* TC-NP-306:ECC 不可纠正 -> -1 + DHARA_E_ECC */
|
||||
printf("[TC-NP-306] uncorrectable ECC -> -1 + DHARA_E_ECC\n");
|
||||
/* TC-NANDPORT-306:ECC 不可纠正 -> -1 + DHARA_E_ECC */
|
||||
printf("[TC-NANDPORT-306] uncorrectable ECC -> -1 + DHARA_E_ECC\n");
|
||||
prep_content_page(page_buf, 21u);
|
||||
s_fail_check_ecc = 1;
|
||||
err = DHARA_E_NONE;
|
||||
@@ -746,8 +746,8 @@ static void tc_read(void) {
|
||||
"check_ecc failure -> -1");
|
||||
CHECK(err == DHARA_E_ECC, "check_ecc failure -> DHARA_E_ECC");
|
||||
|
||||
/* TC-NP-307:E-42 同族——read_from_cache 失败必须 -1(旧实现返回 0 交垃圾) */
|
||||
printf("[TC-NP-307] E-42: read_from_cache failure must not report success\n");
|
||||
/* TC-NANDPORT-307:E-42 同族——read_from_cache 失败必须 -1(旧实现返回 0 交垃圾) */
|
||||
printf("[TC-NANDPORT-307] E-42: read_from_cache failure must not report success\n");
|
||||
prep_content_page(page_buf, 21u);
|
||||
s_fail_read_cache = 1;
|
||||
err = DHARA_E_NONE;
|
||||
@@ -756,13 +756,13 @@ static void tc_read(void) {
|
||||
CHECK(err == DHARA_E_ECC, "read_from_cache failure -> DHARA_E_ECC");
|
||||
}
|
||||
|
||||
/* ===================== TC-NP-400..405:dhara_nand_copy ===================== */
|
||||
/* ===================== TC-NANDPORT-400..405:dhara_nand_copy ===================== */
|
||||
static void tc_copy(void) {
|
||||
static uint8_t page_buf[FAKE_PAGE_SIZE];
|
||||
dhara_error_t err;
|
||||
|
||||
/* TC-NP-400:src 越界 -> -1 + CORRUPT_MAP + 零写入 */
|
||||
printf("[TC-NP-400] copy with out-of-range src -> -1, zero write\n");
|
||||
/* TC-NANDPORT-400:src 越界 -> -1 + CORRUPT_MAP + 零写入 */
|
||||
printf("[TC-NANDPORT-400] copy with out-of-range src -> -1, zero write\n");
|
||||
fake_chip_reset();
|
||||
err = DHARA_E_NONE;
|
||||
CHECK(dhara_nand_copy(&s_ut_nand, UT_OOB_PAGE, 100u, &err) == -1,
|
||||
@@ -771,8 +771,8 @@ static void tc_copy(void) {
|
||||
CHECK(fake_no_write_access(), "copy bad src -> zero write access");
|
||||
CHECK(fake_chip_access_total() == 0u, "copy bad src -> zero chip access at all");
|
||||
|
||||
/* TC-NP-401:src = DHARA_PAGE_NONE -> -1 + CORRUPT_MAP */
|
||||
printf("[TC-NP-401] copy with DHARA_PAGE_NONE src -> -1\n");
|
||||
/* TC-NANDPORT-401:src = DHARA_PAGE_NONE -> -1 + CORRUPT_MAP */
|
||||
printf("[TC-NANDPORT-401] copy with DHARA_PAGE_NONE src -> -1\n");
|
||||
fake_chip_reset();
|
||||
err = DHARA_E_NONE;
|
||||
CHECK(dhara_nand_copy(&s_ut_nand, DHARA_PAGE_NONE, 100u, &err) == -1,
|
||||
@@ -780,9 +780,9 @@ static void tc_copy(void) {
|
||||
CHECK(err == DHARA_E_CORRUPT_MAP, "copy DHARA_PAGE_NONE src -> DHARA_E_CORRUPT_MAP");
|
||||
CHECK(fake_chip_access_total() == 0u, "copy DHARA_PAGE_NONE src -> zero chip access");
|
||||
|
||||
/* TC-NP-402:dst 越界 -> -1 + CORRUPT_MAP + 零写入 + 零标坏块
|
||||
/* TC-NANDPORT-402:dst 越界 -> -1 + CORRUPT_MAP + 零写入 + 零标坏块
|
||||
* dst 越界最致命:那是一次写入,旧实现会静默写进被截断出来的无辜页。 */
|
||||
printf("[TC-NP-402] copy with out-of-range dst -> -1, zero write, zero mark-bad\n");
|
||||
printf("[TC-NANDPORT-402] copy with out-of-range dst -> -1, zero write, zero mark-bad\n");
|
||||
prep_content_page(page_buf, 31u);
|
||||
err = DHARA_E_NONE;
|
||||
CHECK(dhara_nand_copy(&s_ut_nand, UT_SRC_PAGE, UT_OOB_PAGE, &err) == -1,
|
||||
@@ -791,8 +791,8 @@ static void tc_copy(void) {
|
||||
CHECK(fake_no_write_access(), "copy bad dst -> zero write access");
|
||||
CHECK(g_fake_mark_bad_cnt == 0u, "copy bad dst -> no block marked bad");
|
||||
|
||||
/* TC-NP-403:dst = DHARA_PAGE_NONE(哨兵漏进来的真实形态) */
|
||||
printf("[TC-NP-403] copy with DHARA_PAGE_NONE dst -> -1, zero write\n");
|
||||
/* TC-NANDPORT-403:dst = DHARA_PAGE_NONE(哨兵漏进来的真实形态) */
|
||||
printf("[TC-NANDPORT-403] copy with DHARA_PAGE_NONE dst -> -1, zero write\n");
|
||||
prep_content_page(page_buf, 31u);
|
||||
err = DHARA_E_NONE;
|
||||
CHECK(dhara_nand_copy(&s_ut_nand, UT_SRC_PAGE, DHARA_PAGE_NONE, &err) == -1,
|
||||
@@ -801,8 +801,8 @@ static void tc_copy(void) {
|
||||
CHECK(fake_no_write_access(), "copy DHARA_PAGE_NONE dst -> zero write access");
|
||||
CHECK(g_fake_mark_bad_cnt == 0u, "copy DHARA_PAGE_NONE dst -> zero mark_bad");
|
||||
|
||||
/* TC-NP-404:正常 copy -> 0 且目标页与源一致 */
|
||||
printf("[TC-NP-404] normal copy moves the page content\n");
|
||||
/* TC-NANDPORT-404:正常 copy -> 0 且目标页与源一致 */
|
||||
printf("[TC-NANDPORT-404] normal copy moves the page content\n");
|
||||
prep_content_page(page_buf, 31u);
|
||||
err = DHARA_E_NONE;
|
||||
CHECK(dhara_nand_copy(&s_ut_nand, UT_SRC_PAGE, 128u, &err) == 0,
|
||||
@@ -811,8 +811,8 @@ static void tc_copy(void) {
|
||||
CHECK(fake_page_equals(128u, page_buf, FAKE_PAGE_SIZE), "dst page equals src content");
|
||||
CHECK(g_fake_double_program_cnt == 0u, "copy onto an erased page -> no violation");
|
||||
|
||||
/* TC-NP-405:copy 到已编程页 -> 探针记下双编程(场景层的判据基础) */
|
||||
printf("[TC-NP-405] copy onto a programmed page is recorded as a violation\n");
|
||||
/* TC-NANDPORT-405:copy 到已编程页 -> 探针记下双编程(场景层的判据基础) */
|
||||
printf("[TC-NANDPORT-405] copy onto a programmed page is recorded as a violation\n");
|
||||
prep_content_page(page_buf, 31u);
|
||||
err = DHARA_E_NONE;
|
||||
(void)dhara_nand_copy(&s_ut_nand, UT_SRC_PAGE, 128u, &err);
|
||||
@@ -820,14 +820,14 @@ static void tc_copy(void) {
|
||||
CHECK(g_fake_double_program_cnt == 1u, "second copy onto the same dst -> 1 violation");
|
||||
}
|
||||
|
||||
/* ===================== TC-NP-500..504:dhara_nand_erase ===================== */
|
||||
/* ===================== TC-NANDPORT-500..504:dhara_nand_erase ===================== */
|
||||
static void tc_erase(void) {
|
||||
static uint8_t page_buf[FAKE_PAGE_SIZE];
|
||||
dhara_error_t err;
|
||||
uint32_t i;
|
||||
|
||||
/* TC-NP-500:越界块 -> -1 + CORRUPT_MAP + 零标坏块 */
|
||||
printf("[TC-NP-500] erase out-of-range block -> -1, zero mark-bad\n");
|
||||
/* TC-NANDPORT-500:越界块 -> -1 + CORRUPT_MAP + 零标坏块 */
|
||||
printf("[TC-NANDPORT-500] erase out-of-range block -> -1, zero mark-bad\n");
|
||||
fake_chip_reset();
|
||||
err = DHARA_E_NONE;
|
||||
CHECK(dhara_nand_erase(&s_ut_nand, UT_OOB_BLOCK, &err) == -1,
|
||||
@@ -836,8 +836,8 @@ static void tc_erase(void) {
|
||||
CHECK(g_fake_mark_bad_cnt == 0u, "erase out-of-range -> no block marked bad");
|
||||
CHECK(fake_chip_access_total() == 0u, "erase out-of-range -> zero chip access");
|
||||
|
||||
/* TC-NP-501:块号 = 0xffffffff(哨兵当块号用) */
|
||||
printf("[TC-NP-501] erase block 0xffffffff -> -1\n");
|
||||
/* TC-NANDPORT-501:块号 = 0xffffffff(哨兵当块号用) */
|
||||
printf("[TC-NANDPORT-501] erase block 0xffffffff -> -1\n");
|
||||
fake_chip_reset();
|
||||
err = DHARA_E_NONE;
|
||||
CHECK(dhara_nand_erase(&s_ut_nand, 0xFFFFFFFFu, &err) == -1,
|
||||
@@ -846,8 +846,8 @@ static void tc_erase(void) {
|
||||
CHECK(g_fake_mark_bad_cnt == 0u, "erase block 0xffffffff -> zero mark_bad");
|
||||
CHECK(fake_chip_access_total() == 0u, "erase block 0xffffffff -> zero chip access");
|
||||
|
||||
/* TC-NP-502:正常擦除 -> 0 且该块全页回 0xFF */
|
||||
printf("[TC-NP-502] erase a valid block clears every page\n");
|
||||
/* TC-NANDPORT-502:正常擦除 -> 0 且该块全页回 0xFF */
|
||||
printf("[TC-NANDPORT-502] erase a valid block clears every page\n");
|
||||
fake_chip_reset();
|
||||
fake_fill_pattern(page_buf, FAKE_PAGE_SIZE, 41u);
|
||||
for (i = 0; i < FAKE_PAGES_PER_BLOCK; i++) {
|
||||
@@ -860,15 +860,15 @@ static void tc_erase(void) {
|
||||
CHECK(fake_block_all_ff(2u), "after erase every page of block 2 reads 0xFF");
|
||||
CHECK(g_fake_block_erase_cnt == 1u, "erase issues one block-erase command");
|
||||
|
||||
/* TC-NP-503:最后一个合法块(上界内边界) */
|
||||
printf("[TC-NP-503] erase last valid block (boundary inside)\n");
|
||||
/* TC-NANDPORT-503:最后一个合法块(上界内边界) */
|
||||
printf("[TC-NANDPORT-503] erase last valid block (boundary inside)\n");
|
||||
fake_chip_reset();
|
||||
err = DHARA_E_NONE;
|
||||
CHECK(dhara_nand_erase(&s_ut_nand, UT_OOB_BLOCK - 1u, &err) == 0,
|
||||
"erase block == num_blocks - 1 -> 0");
|
||||
|
||||
/* TC-NP-504:擦除失败 -> BAD_BLOCK + 标坏该块 */
|
||||
printf("[TC-NP-504] erase failure -> BAD_BLOCK + mark bad\n");
|
||||
/* TC-NANDPORT-504:擦除失败 -> BAD_BLOCK + 标坏该块 */
|
||||
printf("[TC-NANDPORT-504] erase failure -> BAD_BLOCK + mark bad\n");
|
||||
fake_chip_reset();
|
||||
s_fail_block_erase = 1;
|
||||
err = DHARA_E_NONE;
|
||||
@@ -878,10 +878,10 @@ static void tc_erase(void) {
|
||||
CHECK(g_fake_mark_bad_log[0] == 3u, "the block marked bad is the one that failed");
|
||||
}
|
||||
|
||||
/* ===================== TC-NP-600..605:is_bad / mark_bad ===================== */
|
||||
/* ===================== TC-NANDPORT-600..605:is_bad / mark_bad ===================== */
|
||||
static void tc_bad_block(void) {
|
||||
/* TC-NP-600:越界块 is_bad -> 1 且不碰驱动 */
|
||||
printf("[TC-NP-600] is_bad out-of-range block -> 1, zero access\n");
|
||||
/* TC-NANDPORT-600:越界块 is_bad -> 1 且不碰驱动 */
|
||||
printf("[TC-NANDPORT-600] is_bad out-of-range block -> 1, zero access\n");
|
||||
fake_chip_reset();
|
||||
CHECK(dhara_nand_is_bad(&s_ut_nand, UT_OOB_BLOCK) == 1,
|
||||
"is_bad block == num_blocks -> 1 (conservative)");
|
||||
@@ -889,20 +889,20 @@ static void tc_bad_block(void) {
|
||||
"is_bad block = 0xffffffff -> 1 (conservative)");
|
||||
CHECK(g_fake_is_bad_cnt == 0u, "is_bad out-of-range never reaches the driver");
|
||||
|
||||
/* TC-NP-601:NULL 几何 is_bad -> 1 */
|
||||
printf("[TC-NP-601] is_bad with NULL geometry -> 1\n");
|
||||
/* TC-NANDPORT-601:NULL 几何 is_bad -> 1 */
|
||||
printf("[TC-NANDPORT-601] is_bad with NULL geometry -> 1\n");
|
||||
fake_chip_reset();
|
||||
CHECK(dhara_nand_is_bad(NULL, 0u) == 1, "is_bad n = NULL -> 1, no crash");
|
||||
CHECK(g_fake_is_bad_cnt == 0u, "is_bad n = NULL -> zero driver access");
|
||||
|
||||
/* TC-NP-602:合法好块 -> 0(透传驱动) */
|
||||
printf("[TC-NP-602] is_bad on a valid block passes through\n");
|
||||
/* TC-NANDPORT-602:合法好块 -> 0(透传驱动) */
|
||||
printf("[TC-NANDPORT-602] is_bad on a valid block passes through\n");
|
||||
fake_chip_reset();
|
||||
CHECK(dhara_nand_is_bad(&s_ut_nand, 5u) == 0, "good block -> is_bad = 0");
|
||||
CHECK(g_fake_is_bad_cnt == 1u, "valid block reaches the driver once");
|
||||
|
||||
/* TC-NP-603/604:越界 mark_bad -> 坏块表不变、计数为 0 */
|
||||
printf("[TC-NP-603] mark_bad out-of-range leaves the BBT untouched\n");
|
||||
/* TC-NANDPORT-603/604:越界 mark_bad -> 坏块表不变、计数为 0 */
|
||||
printf("[TC-NANDPORT-603] mark_bad out-of-range leaves the BBT untouched\n");
|
||||
fake_chip_reset();
|
||||
fake_bad_snapshot();
|
||||
dhara_nand_mark_bad(&s_ut_nand, UT_OOB_BLOCK);
|
||||
@@ -910,7 +910,7 @@ static void tc_bad_block(void) {
|
||||
CHECK(fake_bad_unchanged(), "mark_bad out-of-range -> BBT unchanged");
|
||||
CHECK(fake_chip_access_total() == 0u, "mark_bad out-of-range -> zero chip access");
|
||||
|
||||
printf("[TC-NP-604] mark_bad with 0xffffffff leaves the BBT untouched\n");
|
||||
printf("[TC-NANDPORT-604] mark_bad with 0xffffffff leaves the BBT untouched\n");
|
||||
fake_chip_reset();
|
||||
fake_bad_snapshot();
|
||||
dhara_nand_mark_bad(&s_ut_nand, 0xFFFFFFFFu);
|
||||
@@ -919,8 +919,8 @@ static void tc_bad_block(void) {
|
||||
dhara_nand_mark_bad(NULL, 0u);
|
||||
CHECK(g_fake_mark_bad_cnt == 0u, "mark_bad n = NULL -> driver not called, no crash");
|
||||
|
||||
/* TC-NP-605:合法块 mark_bad -> 驱动收到一次、块号正确、随后 is_bad = 1 */
|
||||
printf("[TC-NP-605] mark_bad on a valid block really marks it\n");
|
||||
/* TC-NANDPORT-605:合法块 mark_bad -> 驱动收到一次、块号正确、随后 is_bad = 1 */
|
||||
printf("[TC-NANDPORT-605] mark_bad on a valid block really marks it\n");
|
||||
fake_chip_reset();
|
||||
dhara_nand_mark_bad(&s_ut_nand, 7u);
|
||||
CHECK(g_fake_mark_bad_cnt == 1u, "valid mark_bad reaches the driver once");
|
||||
@@ -928,7 +928,7 @@ static void tc_bad_block(void) {
|
||||
CHECK(dhara_nand_is_bad(&s_ut_nand, 7u) == 1, "marked block now reports bad");
|
||||
}
|
||||
|
||||
/* ===================== TC-NP-700:dhara map 级场景(真链路) =====================
|
||||
/* ===================== TC-NANDPORT-700:dhara map 级场景(真链路) =====================
|
||||
*
|
||||
* 用真实 dhara_map_* 跑一轮"写入 -> sync -> 重新 resume -> 读回",断言:
|
||||
* - 数据往返一致;
|
||||
@@ -941,7 +941,7 @@ static void tc_dhara_scenario(void) {
|
||||
dhara_error_t err;
|
||||
int rc;
|
||||
|
||||
printf("[TC-NP-700] dhara map write -> resume -> read round-trip\n");
|
||||
printf("[TC-NANDPORT-700] dhara map write -> resume -> read round-trip\n");
|
||||
fake_chip_reset();
|
||||
s_initialized = 0;
|
||||
CHECK(nand_ftl_init() == 0, "first init on a blank chip creates the volume");
|
||||
@@ -994,10 +994,10 @@ int main(void) {
|
||||
s_ut_nand.num_blocks, (unsigned long)UT_TOTAL_PAGES);
|
||||
|
||||
fake_chip_reset();
|
||||
CHECK(FAKE_TOTAL_PAGES == 2048u, "TC-NP-000 fake chip geometry (32 x 64 pages)");
|
||||
CHECK(fake_page_all_ff(0u), "TC-NP-000b power-on state is all 0xFF");
|
||||
CHECK(FAKE_TOTAL_PAGES == 2048u, "TC-NANDPORT-000 fake chip geometry (32 x 64 pages)");
|
||||
CHECK(fake_page_all_ff(0u), "TC-NANDPORT-000b power-on state is all 0xFF");
|
||||
CHECK(UT_TOTAL_PAGES == ((dhara_page_t)FAKE_USABLE_BLOCKS * FAKE_PAGES_PER_BLOCK),
|
||||
"TC-NP-000c guard bound = num_blocks << log2_ppb");
|
||||
"TC-NANDPORT-000c guard bound = num_blocks << log2_ppb");
|
||||
|
||||
printf("-- dhara_nand_is_free: whole-page scan (N-12) --\n");
|
||||
tc_is_free();
|
||||
|
||||
@@ -15,18 +15,18 @@
|
||||
* 3. 不占 MCU 的 RAM,毫秒级完成。
|
||||
*
|
||||
* 覆盖点(对应 docs/算法/继电保护功能复现规划.md §3.2):
|
||||
* TC-PH-001 L2-1 系数表逐项等于 sin(2πk/N)·(√2/N) / cos(2πk/N)·(√2/N)(防转录错)
|
||||
* TC-PH-002 L2-1 系数表精确零点(sin@0,10 / cos@5,15)与归一化 Σcoe² = 1/N
|
||||
* TC-PH-003 L2-3 纯基波:fAmSQ = A/√2(有效值),fAm = √2·fAmSQ(幅值)
|
||||
* TC-PH-004 L2-3/L2-4 实部虚部与相位:atan2(fIm,fRe) = 注入相角
|
||||
* TC-PH-005 直流 + 2/3/5 次谐波被完全滤除(基波读数不变)
|
||||
* TC-PH-006 任意次谐波提取(索引步进 = 谐波次数):k=2 / k=5
|
||||
* TC-PH-007 频率偏离 50 Hz 的幅值误差(±1 Hz ≤ 1.5%,±2 Hz ≤ 3%,见 §9 Q3)
|
||||
* TC-PH-010 采样环:入环/取窗时序、回绕、饱和、帧计数、参数守卫
|
||||
* TC-PH-020 L2-2 实例层:实例数/实例表/未攒满一周波不产出
|
||||
* TC-PH-021 L2-6 滑动窗:连续滑动 20 拍基波读数恒定
|
||||
* TC-PH-022 L2-7 双区交换:使用区交替 + get 返回**最后一次** run 的结果(非陈旧)
|
||||
* TC-PH-030..034 phasor_zero 四字段清零 / phasor_init 双区清零 + 使用区与就绪标志复位 + 幂等
|
||||
* TC-PHASOR-001 L2-1 系数表逐项等于 sin(2πk/N)·(√2/N) / cos(2πk/N)·(√2/N)(防转录错)
|
||||
* TC-PHASOR-002 L2-1 系数表精确零点(sin@0,10 / cos@5,15)与归一化 Σcoe² = 1/N
|
||||
* TC-PHASOR-003 L2-3 纯基波:fAmSQ = A/√2(有效值),fAm = √2·fAmSQ(幅值)
|
||||
* TC-PHASOR-004 L2-3/L2-4 实部虚部与相位:atan2(fIm,fRe) = 注入相角
|
||||
* TC-PHASOR-005 直流 + 2/3/5 次谐波被完全滤除(基波读数不变)
|
||||
* TC-PHASOR-006 任意次谐波提取(索引步进 = 谐波次数):k=2 / k=5
|
||||
* TC-PHASOR-007 频率偏离 50 Hz 的幅值误差(±1 Hz ≤ 1.5%,±2 Hz ≤ 3%,见 §9 Q3)
|
||||
* TC-PHASOR-010 采样环:入环/取窗时序、回绕、饱和、帧计数、参数守卫
|
||||
* TC-PHASOR-020 L2-2 实例层:实例数/实例表/未攒满一周波不产出
|
||||
* TC-PHASOR-021 L2-6 滑动窗:连续滑动 20 拍基波读数恒定
|
||||
* TC-PHASOR-022 L2-7 双区交换:使用区交替 + get 返回**最后一次** run 的结果(非陈旧)
|
||||
* TC-PHASOR-030..034 phasor_zero 四字段清零 / phasor_init 双区清零 + 使用区与就绪标志复位 + 幂等
|
||||
*
|
||||
* 通过:全部 TC PASS(main 返回 0)。
|
||||
* 入口:int main(void),返回 0=PASS / 1=FAIL(由 run 脚本判读)。
|
||||
@@ -98,7 +98,7 @@ static void frame_at(float *f, uint32_t t, double amp, double phase) {
|
||||
}
|
||||
}
|
||||
|
||||
/* ===================== TC-PH-001/002:L2-1 系数表 ===================== */
|
||||
/* ===================== TC-PHASOR-001/002:L2-1 系数表 ===================== */
|
||||
|
||||
static void tc_table(void) {
|
||||
const double scale = sqrt(2.0) / (double)PHASOR_N;
|
||||
@@ -136,7 +136,7 @@ static void tc_table(void) {
|
||||
"L2-1 sin[5] == sqrt(2)/N (peak coefficient)");
|
||||
}
|
||||
|
||||
/* ===================== TC-PH-003/004:基波幅值 / 有效值 / 相位 ===================== */
|
||||
/* ===================== TC-PHASOR-003/004:基波幅值 / 有效值 / 相位 ===================== */
|
||||
|
||||
static void tc_fundamental(void) {
|
||||
static const struct { double amp; double ph; } k_case[] = {
|
||||
@@ -176,7 +176,7 @@ static void tc_fundamental(void) {
|
||||
CHECK(ok_ph, "L2-4/L2-3 atan2(fIm,fRe) == injected phase (6 amp/phase cases)");
|
||||
}
|
||||
|
||||
/* ===================== TC-PH-005:直流与谐波被滤除 ===================== */
|
||||
/* ===================== TC-PHASOR-005:直流与谐波被滤除 ===================== */
|
||||
|
||||
static void tc_filtering(void) {
|
||||
const double amp = 57.7, exp_rms = amp / sqrt(2.0);
|
||||
@@ -218,7 +218,7 @@ static void tc_filtering(void) {
|
||||
CHECK(ok, "L2-3 DC + 2nd/3rd/5th harmonics fully rejected (5 cases, err <= 1%)");
|
||||
}
|
||||
|
||||
/* ===================== TC-PH-006:任意次谐波提取 ===================== */
|
||||
/* ===================== TC-PHASOR-006:任意次谐波提取 ===================== */
|
||||
|
||||
static void tc_harmonic(void) {
|
||||
/* 基波 100 + 二次 25 + 五次 12(峰值);三根谱线应各自独立读出 */
|
||||
@@ -263,7 +263,7 @@ static void tc_harmonic(void) {
|
||||
}
|
||||
}
|
||||
|
||||
/* ===================== TC-PH-007:频率敏感性 ===================== */
|
||||
/* ===================== TC-PHASOR-007:频率敏感性 ===================== */
|
||||
|
||||
static void tc_freqdev(void) {
|
||||
const double amp = 57.7, exp_rms = amp / sqrt(2.0);
|
||||
@@ -302,7 +302,7 @@ static void tc_freqdev(void) {
|
||||
CHECK(ok, "L2-3 frequency sensitivity: 50Hz<=0.1%, +-1Hz<=1.5%, +-2Hz<=3% (worst phase)");
|
||||
}
|
||||
|
||||
/* ===================== TC-PH-010:采样环 ===================== */
|
||||
/* ===================== TC-PHASOR-010:采样环 ===================== */
|
||||
|
||||
static void tc_ring(void) {
|
||||
float f[ADC_SEM_COUNT];
|
||||
@@ -360,7 +360,7 @@ static void tc_ring(void) {
|
||||
CHECK(sample_ring_push_frame(f, 3u) == -1, "L2-in ring: wrong frame length rejected");
|
||||
}
|
||||
|
||||
/* ===================== TC-PH-020/021/022:实例层 + 滑动窗 + 双区 ===================== */
|
||||
/* ===================== TC-PHASOR-020/021/022:实例层 + 滑动窗 + 双区 ===================== */
|
||||
|
||||
static void tc_instances(void) {
|
||||
const double amp = 100.0, exp_rms = amp / sqrt(2.0);
|
||||
@@ -433,7 +433,7 @@ static void tc_instances(void) {
|
||||
CHECK(ok, "L2-2/L2-6 instance results == phasor_calc() on the same ring window");
|
||||
}
|
||||
|
||||
/* ===================== TC-PH-030..034:phasor_zero / init 清零 ===================== */
|
||||
/* ===================== TC-PHASOR-030..034:phasor_zero / init 清零 ===================== */
|
||||
|
||||
static void tc_zero(void) {
|
||||
phasor_t p;
|
||||
@@ -444,7 +444,7 @@ static void tc_zero(void) {
|
||||
p.fRe = 1.0f; p.fIm = -2.0f; p.fAm = 3.0f; p.fAmSQ = 4.0f;
|
||||
phasor_zero(&p);
|
||||
CHECK((p.fRe == 0.0f) && (p.fIm == 0.0f) && (p.fAm == 0.0f) && (p.fAmSQ == 0.0f),
|
||||
"TC-PH-030 phasor_zero clears all four fields");
|
||||
"TC-PHASOR-030 phasor_zero clears all four fields");
|
||||
|
||||
/* 2) 经 phasor_init:先把双区写成脏值,init 后必须全零,使用区复位、就绪标志清 */
|
||||
for (i = 0u; i < (uint8_t)PHASOR_INST_N; i++) {
|
||||
@@ -463,16 +463,16 @@ static void tc_zero(void) {
|
||||
zones_dirty = 1;
|
||||
}
|
||||
}
|
||||
CHECK(zones_dirty == 0, "TC-PH-031 phasor_init zeroes both result zones");
|
||||
CHECK(s_use_zone == 0u, "TC-PH-032 phasor_init resets use zone to 0");
|
||||
CHECK(phasor_get(0u, &p) == -2, "TC-PH-033 phasor_init clears ready (get -> -2)");
|
||||
CHECK(zones_dirty == 0, "TC-PHASOR-031 phasor_init zeroes both result zones");
|
||||
CHECK(s_use_zone == 0u, "TC-PHASOR-032 phasor_init resets use zone to 0");
|
||||
CHECK(phasor_get(0u, &p) == -2, "TC-PHASOR-033 phasor_init clears ready (get -> -2)");
|
||||
|
||||
/* 3) 幂等:重复 init 不改变结果 */
|
||||
(void)phasor_init();
|
||||
CHECK((s_use_zone == 0u) && (phasor_get(0u, &p) == -2), "TC-PH-034 phasor_init is idempotent");
|
||||
CHECK((s_use_zone == 0u) && (phasor_get(0u, &p) == -2), "TC-PHASOR-034 phasor_init is idempotent");
|
||||
}
|
||||
|
||||
/* ===================== TC-PH-022:L2-7 双区指针原子交换 ===================== */
|
||||
/* ===================== TC-PHASOR-022:L2-7 双区指针原子交换 ===================== */
|
||||
|
||||
static void tc_dualzone(void) {
|
||||
const double amp = 100.0;
|
||||
|
||||
@@ -5,24 +5,24 @@
|
||||
* 被测对象:真实源文件(#include 原样纳入):
|
||||
* prot_elm.c + prot_set.c(判据吃定值 RAM)
|
||||
* phasor.c + sample_ring.c + freq.c(prot_elm.c 链接依赖;
|
||||
* TC-PE-001~010 走 prot_elm_eval 纯判据路径,TC-PE-013 走
|
||||
* TC-PROTELEM-001~010 走 prot_elm_eval 纯判据路径,TC-PROTELEM-013 走
|
||||
* run() 适配层 = 合成波形跑真实 L2+测频链)
|
||||
*
|
||||
* 覆盖点(docs/算法/继电保护功能复现规划.md §3.3 L3-1/3/4/6、§8 验收):
|
||||
* TC-PE-001 init:全状态清零、动作位图 0
|
||||
* TC-PE-002 过量滞回 + 定时限:1.01× 定值启动、延时到点动作、
|
||||
* TC-PROTELEM-001 init:全状态清零、动作位图 0
|
||||
* TC-PROTELEM-002 过量滞回 + 定时限:1.01× 定值启动、延时到点动作、
|
||||
* 返回系数内保持、跌破返回门槛释放(1.2×/0.9× 验收口径的核)
|
||||
* TC-PE-003 延时 0:启动同拍即动作
|
||||
* TC-PE-004 欠量方向(UV):低于定值启动、高于返回门槛释放
|
||||
* TC-PE-005 投退=0:不判据、状态复位
|
||||
* TC-PE-006 定值闭锁(L5-1 联动):locked → 全元件复位;解锁后恢复
|
||||
* TC-PE-007 时基回绕:跨 0xFFFFFFFF 的延时判定仍正确
|
||||
* TC-PE-008 动作位图聚合
|
||||
* TC-PE-009 守卫:state(NULL)/越界编号、name 越界
|
||||
* TC-PE-010 跨上下文复归请求(B5):request 不当拍生效、下一拍 eval 头部消费
|
||||
* TC-PE-011 过频 OF(B8/L3-5):越限 + RET_OF 滞回 + 定时限
|
||||
* TC-PE-012 低频 UF(B8/L3-5):欠量方向 + RET_UF 滞回 + 方向隔离
|
||||
* TC-PE-013 run() 接线(B8):测频驱动 OF 动作;幅值门失效 OF 复位且
|
||||
* TC-PROTELEM-003 延时 0:启动同拍即动作
|
||||
* TC-PROTELEM-004 欠量方向(UV):低于定值启动、高于返回门槛释放
|
||||
* TC-PROTELEM-005 投退=0:不判据、状态复位
|
||||
* TC-PROTELEM-006 定值闭锁(L5-1 联动):locked → 全元件复位;解锁后恢复
|
||||
* TC-PROTELEM-007 时基回绕:跨 0xFFFFFFFF 的延时判定仍正确
|
||||
* TC-PROTELEM-008 动作位图聚合
|
||||
* TC-PROTELEM-009 守卫:state(NULL)/越界编号、name 越界
|
||||
* TC-PROTELEM-010 跨上下文复归请求(B5):request 不当拍生效、下一拍 eval 头部消费
|
||||
* TC-PROTELEM-011 过频 OF(B8/L3-5):越限 + RET_OF 滞回 + 定时限
|
||||
* TC-PROTELEM-012 低频 UF(B8/L3-5):欠量方向 + RET_UF 滞回 + 方向隔离
|
||||
* TC-PROTELEM-013 run() 接线(B8):测频驱动 OF 动作;幅值门失效 OF 复位且
|
||||
* 相量类元件仍被评估(不整拍跳过)
|
||||
*
|
||||
* 通过:全部 TC PASS(main 返回 0)。
|
||||
@@ -65,7 +65,7 @@ static void mk_base(float m[PE_COUNT]) {
|
||||
static void tc_init_clear(void) {
|
||||
prot_set_init();
|
||||
prot_elm_init();
|
||||
CHECK(prot_elm_active_mask() == 0u, "TC-PE-001 init: active mask 0");
|
||||
CHECK(prot_elm_active_mask() == 0u, "TC-PROTELEM-001 init: active mask 0");
|
||||
{
|
||||
prot_elm_state_t st;
|
||||
uint32_t i;
|
||||
@@ -77,7 +77,7 @@ static void tc_init_clear(void) {
|
||||
clean = 0;
|
||||
}
|
||||
}
|
||||
CHECK(clean, "TC-PE-001 init: all element states clear");
|
||||
CHECK(clean, "TC-PROTELEM-001 init: all element states clear");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,33 +95,33 @@ static void tc_over_hysteresis(void) {
|
||||
prot_elm_eval(1000u, m);
|
||||
prot_elm_state(PE_OC1, &st);
|
||||
CHECK((st.picked == 0u) && (st.enabled != 0u),
|
||||
"TC-PE-002 0.99x set: no pickup");
|
||||
"TC-PROTELEM-002 0.99x set: no pickup");
|
||||
|
||||
m[PE_OC1] = 10.1f;
|
||||
prot_elm_eval(1001u, m);
|
||||
prot_elm_state(PE_OC1, &st);
|
||||
CHECK((st.picked != 0u) && (st.asserted == 0u),
|
||||
"TC-PE-002 1.01x set: pickup before delay");
|
||||
"TC-PROTELEM-002 1.01x set: pickup before delay");
|
||||
|
||||
prot_elm_eval(1100u, m); /* 1100-1001 = 99 ms */
|
||||
prot_elm_state(PE_OC1, &st);
|
||||
CHECK(st.asserted == 0u, "TC-PE-002 not asserted at 99ms");
|
||||
CHECK(st.asserted == 0u, "TC-PROTELEM-002 not asserted at 99ms");
|
||||
|
||||
prot_elm_eval(1101u, m); /* 100 ms 整 */
|
||||
prot_elm_state(PE_OC1, &st);
|
||||
CHECK(st.asserted != 0u, "TC-PE-002 asserted at 100ms");
|
||||
CHECK(st.asserted != 0u, "TC-PROTELEM-002 asserted at 100ms");
|
||||
|
||||
m[PE_OC1] = 9.7f; /* 返回门槛(9.492)与动作门槛(10)之间 */
|
||||
prot_elm_eval(1200u, m);
|
||||
prot_elm_state(PE_OC1, &st);
|
||||
CHECK((st.picked != 0u) && (st.asserted != 0u),
|
||||
"TC-PE-002 hysteresis: holds between return and pickup threshold");
|
||||
"TC-PROTELEM-002 hysteresis: holds between return and pickup threshold");
|
||||
|
||||
m[PE_OC1] = 9.4f; /* 跌破返回门槛 */
|
||||
prot_elm_eval(1300u, m);
|
||||
prot_elm_state(PE_OC1, &st);
|
||||
CHECK((st.picked == 0u) && (st.asserted == 0u),
|
||||
"TC-PE-002 below return threshold: drops out");
|
||||
"TC-PROTELEM-002 below return threshold: drops out");
|
||||
}
|
||||
|
||||
static void tc_zero_delay(void) {
|
||||
@@ -136,7 +136,7 @@ static void tc_zero_delay(void) {
|
||||
prot_elm_eval(5000u, m);
|
||||
prot_elm_state(PE_OC3, &st);
|
||||
CHECK((st.picked != 0u) && (st.asserted != 0u),
|
||||
"TC-PE-003 dly=0: asserted on the same beat as pickup");
|
||||
"TC-PROTELEM-003 dly=0: asserted on the same beat as pickup");
|
||||
}
|
||||
|
||||
static void tc_under_direction(void) {
|
||||
@@ -152,27 +152,27 @@ static void tc_under_direction(void) {
|
||||
m[PE_UV] = 25.0f;
|
||||
prot_elm_eval(2000u, m);
|
||||
prot_elm_state(PE_UV, &st);
|
||||
CHECK(st.picked == 0u, "TC-PE-004 UV above set: no pickup");
|
||||
CHECK(st.picked == 0u, "TC-PROTELEM-004 UV above set: no pickup");
|
||||
|
||||
m[PE_UV] = 19.0f;
|
||||
prot_elm_eval(2001u, m);
|
||||
prot_elm_state(PE_UV, &st);
|
||||
CHECK(st.picked != 0u, "TC-PE-004 UV below set: pickup");
|
||||
CHECK(st.picked != 0u, "TC-PROTELEM-004 UV below set: pickup");
|
||||
|
||||
prot_elm_eval(2051u, m); /* 50 ms */
|
||||
prot_elm_state(PE_UV, &st);
|
||||
CHECK(st.asserted != 0u, "TC-PE-004 UV asserted after delay");
|
||||
CHECK(st.asserted != 0u, "TC-PROTELEM-004 UV asserted after delay");
|
||||
|
||||
m[PE_UV] = 20.5f; /* 20 与 20.996 之间:保持 */
|
||||
prot_elm_eval(2100u, m);
|
||||
prot_elm_state(PE_UV, &st);
|
||||
CHECK(st.asserted != 0u, "TC-PE-004 UV holds below return threshold");
|
||||
CHECK(st.asserted != 0u, "TC-PROTELEM-004 UV holds below return threshold");
|
||||
|
||||
m[PE_UV] = 21.5f; /* 高于返回门槛:释放 */
|
||||
prot_elm_eval(2200u, m);
|
||||
prot_elm_state(PE_UV, &st);
|
||||
CHECK((st.picked == 0u) && (st.asserted == 0u),
|
||||
"TC-PE-004 UV above return threshold: drops out");
|
||||
"TC-PROTELEM-004 UV above return threshold: drops out");
|
||||
}
|
||||
|
||||
static void tc_disabled(void) {
|
||||
@@ -187,7 +187,7 @@ static void tc_disabled(void) {
|
||||
prot_elm_eval(3000u, m);
|
||||
prot_elm_state(PE_OC2, &st);
|
||||
CHECK((st.enabled == 0u) && (st.picked == 0u) && (st.asserted == 0u),
|
||||
"TC-PE-005 enable=0: no judgement even at 999x");
|
||||
"TC-PROTELEM-005 enable=0: no judgement even at 999x");
|
||||
}
|
||||
|
||||
static void tc_set_lock(void) {
|
||||
@@ -201,20 +201,20 @@ static void tc_set_lock(void) {
|
||||
(void)prot_set_set(PS_OC1_DLY, PROT_SET_Q10(0.0));
|
||||
prot_elm_eval(4000u, m);
|
||||
prot_elm_state(PE_OC1, &st);
|
||||
CHECK(st.asserted != 0u, "TC-PE-006 pre: element operates while settings valid");
|
||||
CHECK(st.asserted != 0u, "TC-PROTELEM-006 pre: element operates while settings valid");
|
||||
|
||||
(void)prot_set_set(PS_OC1_CUR, PROT_SET_Q10(9.0)); /* 改值不封存 */
|
||||
CHECK(prot_set_selfcheck() == -1, "TC-PE-006 tamper detected by selfcheck");
|
||||
CHECK(prot_set_selfcheck() == -1, "TC-PROTELEM-006 tamper detected by selfcheck");
|
||||
prot_elm_eval(4100u, m);
|
||||
prot_elm_state(PE_OC1, &st);
|
||||
CHECK((st.enabled == 0u) && (st.asserted == 0u),
|
||||
"TC-PE-006 settings lock resets all elements (L5-1 gating)");
|
||||
"TC-PROTELEM-006 settings lock resets all elements (L5-1 gating)");
|
||||
|
||||
prot_set_seal();
|
||||
prot_elm_eval(4200u, m);
|
||||
prot_elm_state(PE_OC1, &st);
|
||||
CHECK((st.enabled != 0u) && (st.asserted != 0u),
|
||||
"TC-PE-006 unlock restores judgement");
|
||||
"TC-PROTELEM-006 unlock restores judgement");
|
||||
}
|
||||
|
||||
static void tc_tick_wrap(void) {
|
||||
@@ -228,15 +228,15 @@ static void tc_tick_wrap(void) {
|
||||
m[PE_OC2] = 5.1f; /* OC2 定值 5.0 */
|
||||
prot_elm_eval(0xFFFFFFF0u, m); /* 启动点贴近回绕 */
|
||||
prot_elm_state(PE_OC2, &st);
|
||||
CHECK(st.picked != 0u, "TC-PE-007 pickup near tick wrap");
|
||||
CHECK(st.picked != 0u, "TC-PROTELEM-007 pickup near tick wrap");
|
||||
|
||||
prot_elm_eval(0x00000010u, m); /* 回绕后 32 ms */
|
||||
prot_elm_state(PE_OC2, &st);
|
||||
CHECK(st.asserted == 0u, "TC-PE-007 not asserted at 32ms after wrap");
|
||||
CHECK(st.asserted == 0u, "TC-PROTELEM-007 not asserted at 32ms after wrap");
|
||||
|
||||
prot_elm_eval(0x00000060u, m); /* 回绕后 112 ms */
|
||||
prot_elm_state(PE_OC2, &st);
|
||||
CHECK(st.asserted != 0u, "TC-PE-007 asserted at 112ms across wrap");
|
||||
CHECK(st.asserted != 0u, "TC-PROTELEM-007 asserted at 112ms across wrap");
|
||||
}
|
||||
|
||||
static void tc_active_mask(void) {
|
||||
@@ -251,7 +251,7 @@ static void tc_active_mask(void) {
|
||||
m[PE_OV] = 130.0f; /* OV 定值 120 */
|
||||
prot_elm_eval(6000u, m);
|
||||
CHECK(prot_elm_active_mask() == ((1uL << PE_OC1) | (1uL << PE_OV)),
|
||||
"TC-PE-008 active mask aggregates OC1+OV only");
|
||||
"TC-PROTELEM-008 active mask aggregates OC1+OV only");
|
||||
}
|
||||
|
||||
static void tc_guards(void) {
|
||||
@@ -261,12 +261,12 @@ static void tc_guards(void) {
|
||||
prot_elm_init();
|
||||
prot_elm_state(PE_COUNT, &st);
|
||||
CHECK((st.enabled == 0u) && (st.picked == 0u) && (st.asserted == 0u),
|
||||
"TC-PE-009 out-of-range id -> zero state");
|
||||
"TC-PROTELEM-009 out-of-range id -> zero state");
|
||||
prot_elm_state(PE_OC1, NULL); /* 不得崩溃 */
|
||||
CHECK(prot_elm_name(PE_COUNT) != NULL, "TC-PE-009 name out-of-range -> fallback");
|
||||
CHECK(prot_elm_name(PE_3U0) != NULL, "TC-PE-009 name valid id -> non-NULL");
|
||||
CHECK(prot_elm_name(PE_COUNT) != NULL, "TC-PROTELEM-009 name out-of-range -> fallback");
|
||||
CHECK(prot_elm_name(PE_3U0) != NULL, "TC-PROTELEM-009 name valid id -> non-NULL");
|
||||
prot_elm_eval(7000u, NULL); /* NULL 测量:按 0 处理,不得崩溃 */
|
||||
CHECK(1, "TC-PE-009 eval(NULL meas) survives");
|
||||
CHECK(1, "TC-PROTELEM-009 eval(NULL meas) survives");
|
||||
}
|
||||
|
||||
static void tc_request_reset(void) {
|
||||
@@ -279,11 +279,11 @@ static void tc_request_reset(void) {
|
||||
m[PE_OC1] = 999.0f; /* OC1 默认 dly=0 → 启动同拍动作 */
|
||||
prot_elm_eval(1000u, m);
|
||||
prot_elm_state(PE_OC1, &st);
|
||||
CHECK(st.asserted != 0u, "TC-PE-010 pre: OC1 asserted (default dly=0)");
|
||||
CHECK(st.asserted != 0u, "TC-PROTELEM-010 pre: OC1 asserted (default dly=0)");
|
||||
|
||||
prot_elm_request_reset(); /* 跨上下文请求:不当拍生效 */
|
||||
prot_elm_state(PE_OC1, &st);
|
||||
CHECK(st.asserted != 0u, "TC-PE-010 request alone does not reset");
|
||||
CHECK(st.asserted != 0u, "TC-PROTELEM-010 request alone does not reset");
|
||||
|
||||
/* 下一拍头部消费请求 → 复位;测量落在滞回保持区(9.6 ∈ [返回9.5, 动作10))
|
||||
* ——不复位则 picked/asserted 保持,复位后保持清零,可区分 */
|
||||
@@ -291,12 +291,12 @@ static void tc_request_reset(void) {
|
||||
prot_elm_eval(1100u, m);
|
||||
prot_elm_state(PE_OC1, &st);
|
||||
CHECK((st.picked == 0u) && (st.asserted == 0u),
|
||||
"TC-PE-010 next eval consumes request -> cleared in hysteresis band");
|
||||
"TC-PROTELEM-010 next eval consumes request -> cleared in hysteresis band");
|
||||
}
|
||||
|
||||
/* ===================== OF/UF(L3-5,B8)===================== */
|
||||
|
||||
/* TC-PE-011:过频——越限 + RET_OF 滞回 + 定时限(判据核级) */
|
||||
/* TC-PROTELEM-011:过频——越限 + RET_OF 滞回 + 定时限(判据核级) */
|
||||
static void tc_of_hysteresis(void) {
|
||||
float m[PE_COUNT];
|
||||
prot_elm_state_t st;
|
||||
@@ -311,36 +311,36 @@ static void tc_of_hysteresis(void) {
|
||||
prot_elm_eval(1000u, m);
|
||||
prot_elm_state(PE_OF, &st);
|
||||
CHECK((st.picked == 0u) && (st.enabled != 0u),
|
||||
"TC-PE-011 OF 50.9 (<51): no pickup");
|
||||
"TC-PROTELEM-011 OF 50.9 (<51): no pickup");
|
||||
|
||||
m[PE_OF] = 51.1f;
|
||||
prot_elm_eval(1001u, m);
|
||||
prot_elm_state(PE_OF, &st);
|
||||
CHECK((st.picked != 0u) && (st.asserted == 0u),
|
||||
"TC-PE-011 OF 51.1: pickup before delay");
|
||||
"TC-PROTELEM-011 OF 51.1: pickup before delay");
|
||||
|
||||
prot_elm_eval(1100u, m);
|
||||
prot_elm_state(PE_OF, &st);
|
||||
CHECK(st.asserted == 0u, "TC-PE-011 OF not asserted at 99ms");
|
||||
CHECK(st.asserted == 0u, "TC-PROTELEM-011 OF not asserted at 99ms");
|
||||
|
||||
prot_elm_eval(1101u, m);
|
||||
prot_elm_state(PE_OF, &st);
|
||||
CHECK(st.asserted != 0u, "TC-PE-011 OF asserted at 100ms");
|
||||
CHECK(st.asserted != 0u, "TC-PROTELEM-011 OF asserted at 100ms");
|
||||
|
||||
m[PE_OF] = 50.7f; /* 50.49 与 51 之间:滞回保持 */
|
||||
prot_elm_eval(1200u, m);
|
||||
prot_elm_state(PE_OF, &st);
|
||||
CHECK((st.picked != 0u) && (st.asserted != 0u),
|
||||
"TC-PE-011 OF holds between return(50.49) and pickup(51)");
|
||||
"TC-PROTELEM-011 OF holds between return(50.49) and pickup(51)");
|
||||
|
||||
m[PE_OF] = 50.4f; /* 跌破返回门槛 */
|
||||
prot_elm_eval(1300u, m);
|
||||
prot_elm_state(PE_OF, &st);
|
||||
CHECK((st.picked == 0u) && (st.asserted == 0u),
|
||||
"TC-PE-011 OF below return threshold: drops out");
|
||||
"TC-PROTELEM-011 OF below return threshold: drops out");
|
||||
}
|
||||
|
||||
/* TC-PE-012:低频——欠量方向 + RET_UF 滞回(与 OF 系数独立,勿混 0.95/1.05) */
|
||||
/* TC-PROTELEM-012:低频——欠量方向 + RET_UF 滞回(与 OF 系数独立,勿混 0.95/1.05) */
|
||||
static void tc_uf_direction(void) {
|
||||
float m[PE_COUNT];
|
||||
prot_elm_state_t st;
|
||||
@@ -354,36 +354,36 @@ static void tc_uf_direction(void) {
|
||||
m[PE_UF] = 49.1f;
|
||||
prot_elm_eval(2000u, m);
|
||||
prot_elm_state(PE_UF, &st);
|
||||
CHECK(st.picked == 0u, "TC-PE-012 UF 49.1 (>49): no pickup");
|
||||
CHECK(st.picked == 0u, "TC-PROTELEM-012 UF 49.1 (>49): no pickup");
|
||||
|
||||
m[PE_UF] = 48.9f;
|
||||
prot_elm_eval(2001u, m);
|
||||
prot_elm_state(PE_UF, &st);
|
||||
CHECK(st.picked != 0u, "TC-PE-012 UF 48.9 (<49): pickup");
|
||||
CHECK(st.picked != 0u, "TC-PROTELEM-012 UF 48.9 (<49): pickup");
|
||||
|
||||
prot_elm_eval(2051u, m);
|
||||
prot_elm_state(PE_UF, &st);
|
||||
CHECK(st.asserted != 0u, "TC-PE-012 UF asserted after 50ms");
|
||||
CHECK(st.asserted != 0u, "TC-PROTELEM-012 UF asserted after 50ms");
|
||||
|
||||
m[PE_UF] = 49.3f; /* 49 与 49.49 之间:保持 */
|
||||
prot_elm_eval(2100u, m);
|
||||
prot_elm_state(PE_UF, &st);
|
||||
CHECK(st.asserted != 0u, "TC-PE-012 UF holds below return threshold");
|
||||
CHECK(st.asserted != 0u, "TC-PROTELEM-012 UF holds below return threshold");
|
||||
|
||||
m[PE_UF] = 49.6f; /* 高于返回门槛:释放 */
|
||||
prot_elm_eval(2200u, m);
|
||||
prot_elm_state(PE_UF, &st);
|
||||
CHECK((st.picked == 0u) && (st.asserted == 0u),
|
||||
"TC-PE-012 UF above return threshold: drops out");
|
||||
"TC-PROTELEM-012 UF above return threshold: drops out");
|
||||
|
||||
/* OF 不得被低频误启动(方向隔离);UF 不得被过频误启动 */
|
||||
m[PE_OF] = 52.0f;
|
||||
m[PE_UF] = 52.0f;
|
||||
prot_elm_eval(2300u, m);
|
||||
prot_elm_state(PE_OF, &st);
|
||||
CHECK(st.picked != 0u, "TC-PE-012 OF picks at 52 (over direction)");
|
||||
CHECK(st.picked != 0u, "TC-PROTELEM-012 OF picks at 52 (over direction)");
|
||||
prot_elm_state(PE_UF, &st);
|
||||
CHECK(st.picked == 0u, "TC-PE-012 UF NOT picked at 52 (direction isolation)");
|
||||
CHECK(st.picked == 0u, "TC-PROTELEM-012 UF NOT picked at 52 (direction isolation)");
|
||||
}
|
||||
|
||||
/* ---- run() 适配层驱动:合成波形跑真实 L2+测频链(同 freq_test 口径) ---- */
|
||||
@@ -403,7 +403,7 @@ static void drive_beat(double f, double amp) {
|
||||
s_t++;
|
||||
}
|
||||
|
||||
/* TC-PE-013:run() 级——freq 有效读数驱动 OF 动作;幅值门失效后 OF 复位
|
||||
/* TC-PROTELEM-013:run() 级——freq 有效读数驱动 OF 动作;幅值门失效后 OF 复位
|
||||
* 且相量类元件仍被评估(不整拍跳过,B5 行为不回归) */
|
||||
static void tc_run_freq_wiring(void) {
|
||||
prot_elm_state_t st;
|
||||
@@ -424,9 +424,9 @@ static void tc_run_freq_wiring(void) {
|
||||
}
|
||||
prot_elm_state(PE_OF, &st);
|
||||
CHECK((st.picked != 0u) && (st.asserted != 0u),
|
||||
"TC-PE-013 run(): OF asserted from measured 52.5 Hz");
|
||||
"TC-PROTELEM-013 run(): OF asserted from measured 52.5 Hz");
|
||||
prot_elm_state(PE_UF, &st);
|
||||
CHECK(st.picked == 0u, "TC-PE-013 run(): UF clear at 52.5 Hz");
|
||||
CHECK(st.picked == 0u, "TC-PROTELEM-013 run(): UF clear at 52.5 Hz");
|
||||
|
||||
/* 波形消失(浮空):freq 幅值门失效 -> OF 按方向填充复位;
|
||||
* 同时相量 rms=0 -> UV(定值 20,dly=0)启动 = 证明未整拍跳过 */
|
||||
@@ -436,10 +436,10 @@ static void tc_run_freq_wiring(void) {
|
||||
}
|
||||
prot_elm_state(PE_OF, &st);
|
||||
CHECK((st.picked == 0u) && (st.asserted == 0u),
|
||||
"TC-PE-013 run(): OF resets when freq source loses amplitude");
|
||||
"TC-PROTELEM-013 run(): OF resets when freq source loses amplitude");
|
||||
prot_elm_state(PE_UV, &st);
|
||||
CHECK(st.picked != 0u,
|
||||
"TC-PE-013 run(): UV still evaluated with zero-amplitude (no whole-beat skip)");
|
||||
"TC-PROTELEM-013 run(): UV still evaluated with zero-amplitude (no whole-beat skip)");
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
|
||||
+112
-112
@@ -5,22 +5,22 @@
|
||||
* 被测对象:真实源文件(#include 原样纳入)。纯逻辑,无需桩。
|
||||
*
|
||||
* 覆盖点(docs/算法/继电保护功能复现规划.md §5.2 / §3.4 L5-1):
|
||||
* TC-PS-001 init:默认值装载、越界位图 0、selfcheck 通过、未闭锁
|
||||
* TC-PS-002 set:范围内写入生效;越界拒写且原值不动
|
||||
* TC-PS-003 校验和封存语义:set 后未 seal → selfcheck 失败并闭锁;
|
||||
* TC-PROTSET-001 init:默认值装载、越界位图 0、selfcheck 通过、未闭锁
|
||||
* TC-PROTSET-002 set:范围内写入生效;越界拒写且原值不动
|
||||
* TC-PROTSET-003 校验和封存语义:set 后未 seal → selfcheck 失败并闭锁;
|
||||
* seal → 通过并解锁(L5-1 核心闭环)
|
||||
* TC-PS-004 load_raw:合法整表装载并封存;含越界项 → 整表不装载 +
|
||||
* TC-PROTSET-004 load_raw:合法整表装载并封存;含越界项 → 整表不装载 +
|
||||
* bad_mask 指认越界项(定值一致性:宁可全旧不可半新)
|
||||
* TC-PS-005 Q10 往返精度(±1 LSB)
|
||||
* TC-PS-006 元数据表自检:min<=max、投退项 0..1、非零通讯地址不重复
|
||||
* TC-PS-007 越界编号守卫(get/set)
|
||||
* TC-PS-008 全局软压板 PS_GLOBAL_EN(B7):默认投入、set_sealed 原子写
|
||||
* TC-PROTSET-005 Q10 往返精度(±1 LSB)
|
||||
* TC-PROTSET-006 元数据表自检:min<=max、投退项 0..1、非零通讯地址不重复
|
||||
* TC-PROTSET-007 越界编号守卫(get/set)
|
||||
* TC-PROTSET-008 全局软压板 PS_GLOBAL_EN(B7):默认投入、set_sealed 原子写
|
||||
* 不破坏 selfcheck、脏标志三件套(peek/take/mark)
|
||||
* TC-PS-009 持久化 blob 往返:serialize → init 清场 → parse 恢复
|
||||
* TC-PROTSET-009 持久化 blob 往返:serialize → init 清场 → parse 恢复
|
||||
* (位精确 + 封存自洽 + parse 不置脏)
|
||||
* TC-PS-010 损坏 blob 整表拒绝(all-or-nothing):值区位翻转/坏 magic/
|
||||
* TC-PROTSET-010 损坏 blob 整表拒绝(all-or-nothing):值区位翻转/坏 magic/
|
||||
* 截断/超长/坏版本/伪造自洽越界 → 全部拒绝且活跃值区一字不动
|
||||
* TC-PS-011 OF/UF 定值行(B8):40 项 / blob 版本 2 / 本地项地址 0 /
|
||||
* TC-PROTSET-011 OF/UF 定值行(B8):40 项 / blob 版本 2 / 本地项地址 0 /
|
||||
* 默认值与范围 / 返回系数独立性 / 64 位 bad_mask(bit 39)/
|
||||
* B7 旧档(32 项)换代拒绝
|
||||
*
|
||||
@@ -40,46 +40,46 @@ static int s_total = 0, s_passed = 0, s_failed = 0;
|
||||
|
||||
#include "prot_set.c"
|
||||
|
||||
/* TC-PS-001 */
|
||||
/* TC-PROTSET-001 */
|
||||
static void tc_init(void) {
|
||||
prot_set_init();
|
||||
CHECK(prot_set_bad_mask() == 0u, "TC-PS-001 init: no bad items");
|
||||
CHECK(prot_set_selfcheck() == 0, "TC-PS-001 init: selfcheck pass");
|
||||
CHECK(prot_set_locked() == 0u, "TC-PS-001 init: not locked");
|
||||
CHECK(prot_set_bad_mask() == 0u, "TC-PROTSET-001 init: no bad items");
|
||||
CHECK(prot_set_selfcheck() == 0, "TC-PROTSET-001 init: selfcheck pass");
|
||||
CHECK(prot_set_locked() == 0u, "TC-PROTSET-001 init: not locked");
|
||||
CHECK(prot_set_get_f(PS_OC1_CUR) > 9.99f && prot_set_get_f(PS_OC1_CUR) < 10.01f,
|
||||
"TC-PS-001 default OC1 current = 10.0 A");
|
||||
"TC-PROTSET-001 default OC1 current = 10.0 A");
|
||||
CHECK(prot_set_get_ctl(PS_OC3_TRIP) == 0u,
|
||||
"TC-PS-001 default OC3 = alarm (trip off)");
|
||||
"TC-PROTSET-001 default OC3 = alarm (trip off)");
|
||||
}
|
||||
|
||||
/* TC-PS-002 */
|
||||
/* TC-PROTSET-002 */
|
||||
static void tc_set_range(void) {
|
||||
prot_set_init();
|
||||
CHECK(prot_set_set(PS_OC2_CUR, PROT_SET_Q10(7.5)) == 0,
|
||||
"TC-PS-002 in-range set accepted");
|
||||
"TC-PROTSET-002 in-range set accepted");
|
||||
CHECK(prot_set_get_f(PS_OC2_CUR) > 7.49f && prot_set_get_f(PS_OC2_CUR) < 7.51f,
|
||||
"TC-PS-002 value readable after set");
|
||||
"TC-PROTSET-002 value readable after set");
|
||||
CHECK(prot_set_set(PS_OC2_CUR, PROT_SET_Q10(101.0)) == -1,
|
||||
"TC-PS-002 over-max set rejected");
|
||||
"TC-PROTSET-002 over-max set rejected");
|
||||
CHECK(prot_set_get_f(PS_OC2_CUR) > 7.49f && prot_set_get_f(PS_OC2_CUR) < 7.51f,
|
||||
"TC-PS-002 rejected set leaves value unchanged");
|
||||
"TC-PROTSET-002 rejected set leaves value unchanged");
|
||||
CHECK(prot_set_set(PS_OC1_EN, PROT_SET_Q10(2)) == -1,
|
||||
"TC-PS-002 ctl item rejects value 2");
|
||||
"TC-PROTSET-002 ctl item rejects value 2");
|
||||
}
|
||||
|
||||
/* TC-PS-003 */
|
||||
/* TC-PROTSET-003 */
|
||||
static void tc_seal_selfcheck(void) {
|
||||
prot_set_init();
|
||||
CHECK(prot_set_set(PS_OC1_CUR, PROT_SET_Q10(8.0)) == 0, "TC-PS-003 set ok");
|
||||
CHECK(prot_set_set(PS_OC1_CUR, PROT_SET_Q10(8.0)) == 0, "TC-PROTSET-003 set ok");
|
||||
CHECK(prot_set_selfcheck() == -1,
|
||||
"TC-PS-003 set-without-seal => selfcheck FAIL (tamper detect)");
|
||||
CHECK(prot_set_locked() == 1u, "TC-PS-003 selfcheck failure latches lock");
|
||||
"TC-PROTSET-003 set-without-seal => selfcheck FAIL (tamper detect)");
|
||||
CHECK(prot_set_locked() == 1u, "TC-PROTSET-003 selfcheck failure latches lock");
|
||||
prot_set_seal();
|
||||
CHECK(prot_set_selfcheck() == 0, "TC-PS-003 seal => selfcheck pass");
|
||||
CHECK(prot_set_locked() == 0u, "TC-PS-003 seal clears lock");
|
||||
CHECK(prot_set_selfcheck() == 0, "TC-PROTSET-003 seal => selfcheck pass");
|
||||
CHECK(prot_set_locked() == 0u, "TC-PROTSET-003 seal clears lock");
|
||||
}
|
||||
|
||||
/* TC-PS-004 */
|
||||
/* TC-PROTSET-004 */
|
||||
static void tc_load_raw(void) {
|
||||
int32_t tbl[PS_ID_COUNT];
|
||||
uint32_t i;
|
||||
@@ -89,38 +89,38 @@ static void tc_load_raw(void) {
|
||||
tbl[i] = prot_set_get((prot_set_id_t)i);
|
||||
}
|
||||
tbl[PS_OL_CUR] = PROT_SET_Q10(1.5);
|
||||
CHECK(prot_set_load_raw(tbl) == 0, "TC-PS-004 valid table loads");
|
||||
CHECK(prot_set_load_raw(tbl) == 0, "TC-PROTSET-004 valid table loads");
|
||||
CHECK(prot_set_get_f(PS_OL_CUR) > 1.49f && prot_set_get_f(PS_OL_CUR) < 1.51f,
|
||||
"TC-PS-004 loaded value visible");
|
||||
CHECK(prot_set_selfcheck() == 0, "TC-PS-004 load_raw auto-seals");
|
||||
"TC-PROTSET-004 loaded value visible");
|
||||
CHECK(prot_set_selfcheck() == 0, "TC-PROTSET-004 load_raw auto-seals");
|
||||
|
||||
tbl[PS_OC3_DLY] = PROT_SET_Q10(60001.0); /* 越上限 */
|
||||
tbl[PS_OL_CUR] = PROT_SET_Q10(2.5); /* 合法改动 */
|
||||
CHECK(prot_set_load_raw(tbl) == -1, "TC-PS-004 bad table rejected");
|
||||
CHECK(prot_set_load_raw(tbl) == -1, "TC-PROTSET-004 bad table rejected");
|
||||
CHECK(prot_set_bad_mask() == (1uLL << PS_OC3_DLY),
|
||||
"TC-PS-004 bad_mask points at the offending item");
|
||||
"TC-PROTSET-004 bad_mask points at the offending item");
|
||||
CHECK(prot_set_get_f(PS_OL_CUR) > 1.49f && prot_set_get_f(PS_OL_CUR) < 1.51f,
|
||||
"TC-PS-004 rejected load keeps OLD table (all-or-nothing)");
|
||||
CHECK(prot_set_load_raw(0) == -1, "TC-PS-004 NULL table rejected");
|
||||
"TC-PROTSET-004 rejected load keeps OLD table (all-or-nothing)");
|
||||
CHECK(prot_set_load_raw(0) == -1, "TC-PROTSET-004 NULL table rejected");
|
||||
}
|
||||
|
||||
/* TC-PS-005 */
|
||||
/* TC-PROTSET-005 */
|
||||
static void tc_q10_roundtrip(void) {
|
||||
float v = 12.345f;
|
||||
int32_t q;
|
||||
|
||||
prot_set_init();
|
||||
q = PROT_SET_Q10(v);
|
||||
CHECK(prot_set_set(PS_OC1_CUR, q) == 0, "TC-PS-005 set ok");
|
||||
CHECK(prot_set_set(PS_OC1_CUR, q) == 0, "TC-PROTSET-005 set ok");
|
||||
{
|
||||
float back = prot_set_get_f(PS_OC1_CUR);
|
||||
float err = back - v;
|
||||
if (err < 0.0f) { err = -err; }
|
||||
CHECK(err < 0.001f, "TC-PS-005 Q10 roundtrip error < 1 LSB");
|
||||
CHECK(err < 0.001f, "TC-PROTSET-005 Q10 roundtrip error < 1 LSB");
|
||||
}
|
||||
}
|
||||
|
||||
/* TC-PS-006 */
|
||||
/* TC-PROTSET-006 */
|
||||
static void tc_meta_sanity(void) {
|
||||
uint32_t i, j;
|
||||
int ok_range = 1, ok_ctl = 1, ok_addr = 1;
|
||||
@@ -136,40 +136,40 @@ static void tc_meta_sanity(void) {
|
||||
if (g_prot_set_meta[j].comm_addr == m->comm_addr) { ok_addr = 0; }
|
||||
}
|
||||
}
|
||||
CHECK(ok_range, "TC-PS-006 meta: min<=def<=max for all items");
|
||||
CHECK(ok_ctl, "TC-PS-006 meta: ctl items are 0..1");
|
||||
CHECK(ok_addr, "TC-PS-006 meta: comm addresses unique");
|
||||
CHECK((uint32_t)PS_ID_COUNT <= 64u, "TC-PS-006 item count fits 64-bit bad_mask (B8: 40)");
|
||||
CHECK(ok_range, "TC-PROTSET-006 meta: min<=def<=max for all items");
|
||||
CHECK(ok_ctl, "TC-PROTSET-006 meta: ctl items are 0..1");
|
||||
CHECK(ok_addr, "TC-PROTSET-006 meta: comm addresses unique");
|
||||
CHECK((uint32_t)PS_ID_COUNT <= 64u, "TC-PROTSET-006 item count fits 64-bit bad_mask (B8: 40)");
|
||||
}
|
||||
|
||||
/* TC-PS-007 */
|
||||
/* TC-PROTSET-007 */
|
||||
static void tc_id_guard(void) {
|
||||
prot_set_init();
|
||||
CHECK(prot_set_get(PS_ID_COUNT) == 0, "TC-PS-007 get out-of-range id -> 0");
|
||||
CHECK(prot_set_set(PS_ID_COUNT, 0) == -1, "TC-PS-007 set out-of-range id -> -1");
|
||||
CHECK(prot_set_set_sealed(PS_ID_COUNT, 0) == -1, "TC-PS-007 set_sealed id guard");
|
||||
CHECK(prot_set_get(PS_ID_COUNT) == 0, "TC-PROTSET-007 get out-of-range id -> 0");
|
||||
CHECK(prot_set_set(PS_ID_COUNT, 0) == -1, "TC-PROTSET-007 set out-of-range id -> -1");
|
||||
CHECK(prot_set_set_sealed(PS_ID_COUNT, 0) == -1, "TC-PROTSET-007 set_sealed id guard");
|
||||
}
|
||||
|
||||
/* TC-PS-008(B7:全局软压板 + 原子写 + 脏标志) */
|
||||
/* TC-PROTSET-008(B7:全局软压板 + 原子写 + 脏标志) */
|
||||
static void tc_global_plate_dirty(void) {
|
||||
prot_set_init();
|
||||
CHECK(prot_set_dirty_peek() == 0u, "TC-PS-008 init not dirty");
|
||||
CHECK(prot_set_get_ctl(PS_GLOBAL_EN) == 1u, "TC-PS-008 global plate default IN");
|
||||
CHECK(prot_set_set(PS_GLOBAL_EN, PROT_SET_Q10(2)) == -1, "TC-PS-008 plate rejects 2");
|
||||
CHECK(prot_set_set_sealed(PS_GLOBAL_EN, 0) == 0, "TC-PS-008 plate OUT via set_sealed");
|
||||
CHECK(prot_set_get_ctl(PS_GLOBAL_EN) == 0u, "TC-PS-008 plate OUT readable");
|
||||
CHECK(prot_set_selfcheck() == 0, "TC-PS-008 set_sealed leaves selfcheck PASS (no unsealed window)");
|
||||
CHECK(prot_set_locked() == 0u, "TC-PS-008 set_sealed no lock");
|
||||
CHECK(prot_set_dirty_peek() == 1u, "TC-PS-008 set_sealed marks dirty");
|
||||
CHECK(prot_set_dirty_take() == 1u, "TC-PS-008 dirty take consumes");
|
||||
CHECK(prot_set_dirty_peek() == 0u, "TC-PS-008 dirty cleared after take");
|
||||
CHECK(prot_set_dirty_peek() == 0u, "TC-PROTSET-008 init not dirty");
|
||||
CHECK(prot_set_get_ctl(PS_GLOBAL_EN) == 1u, "TC-PROTSET-008 global plate default IN");
|
||||
CHECK(prot_set_set(PS_GLOBAL_EN, PROT_SET_Q10(2)) == -1, "TC-PROTSET-008 plate rejects 2");
|
||||
CHECK(prot_set_set_sealed(PS_GLOBAL_EN, 0) == 0, "TC-PROTSET-008 plate OUT via set_sealed");
|
||||
CHECK(prot_set_get_ctl(PS_GLOBAL_EN) == 0u, "TC-PROTSET-008 plate OUT readable");
|
||||
CHECK(prot_set_selfcheck() == 0, "TC-PROTSET-008 set_sealed leaves selfcheck PASS (no unsealed window)");
|
||||
CHECK(prot_set_locked() == 0u, "TC-PROTSET-008 set_sealed no lock");
|
||||
CHECK(prot_set_dirty_peek() == 1u, "TC-PROTSET-008 set_sealed marks dirty");
|
||||
CHECK(prot_set_dirty_take() == 1u, "TC-PROTSET-008 dirty take consumes");
|
||||
CHECK(prot_set_dirty_peek() == 0u, "TC-PROTSET-008 dirty cleared after take");
|
||||
prot_set_dirty_mark();
|
||||
CHECK(prot_set_dirty_peek() == 1u, "TC-PS-008 dirty mark re-arms (write-fail retry)");
|
||||
CHECK(prot_set_set_sealed(PS_GLOBAL_EN, PROT_SET_Q10(2)) == -1, "TC-PS-008 set_sealed range check");
|
||||
CHECK(prot_set_get_ctl(PS_GLOBAL_EN) == 0u, "TC-PS-008 rejected set_sealed keeps value");
|
||||
CHECK(prot_set_dirty_peek() == 1u, "TC-PROTSET-008 dirty mark re-arms (write-fail retry)");
|
||||
CHECK(prot_set_set_sealed(PS_GLOBAL_EN, PROT_SET_Q10(2)) == -1, "TC-PROTSET-008 set_sealed range check");
|
||||
CHECK(prot_set_get_ctl(PS_GLOBAL_EN) == 0u, "TC-PROTSET-008 rejected set_sealed keeps value");
|
||||
}
|
||||
|
||||
/* TC-PS-009(B7:blob 往返) */
|
||||
/* TC-PROTSET-009(B7:blob 往返) */
|
||||
static void tc_store_roundtrip(void) {
|
||||
uint8_t blob[PROT_SET_BLOB_SZ];
|
||||
uint32_t len = 0u;
|
||||
@@ -180,15 +180,15 @@ static void tc_store_roundtrip(void) {
|
||||
(void)prot_set_set_sealed(PS_GLOBAL_EN, 0);
|
||||
(void)prot_set_dirty_take();
|
||||
cur = prot_set_get(PS_OC1_CUR);
|
||||
CHECK(prot_set_store_serialize(blob, sizeof(blob), &len) == 0, "TC-PS-009 serialize ok");
|
||||
CHECK(len == (uint32_t)PROT_SET_BLOB_SZ, "TC-PS-009 blob exact size");
|
||||
CHECK(prot_set_store_serialize(blob, sizeof(blob), &len) == 0, "TC-PROTSET-009 serialize ok");
|
||||
CHECK(len == (uint32_t)PROT_SET_BLOB_SZ, "TC-PROTSET-009 blob exact size");
|
||||
prot_set_init();
|
||||
CHECK(prot_set_get(PS_OC1_CUR) != cur, "TC-PS-009 init wiped to defaults");
|
||||
CHECK(prot_set_store_parse(blob, len) == 0, "TC-PS-009 parse ok");
|
||||
CHECK(prot_set_get(PS_OC1_CUR) == cur, "TC-PS-009 value round-trip bit-exact");
|
||||
CHECK(prot_set_get_ctl(PS_GLOBAL_EN) == 0u, "TC-PS-009 plate state round-trip");
|
||||
CHECK(prot_set_selfcheck() == 0, "TC-PS-009 parsed table sealed");
|
||||
CHECK(prot_set_dirty_peek() == 0u, "TC-PS-009 parse does not mark dirty");
|
||||
CHECK(prot_set_get(PS_OC1_CUR) != cur, "TC-PROTSET-009 init wiped to defaults");
|
||||
CHECK(prot_set_store_parse(blob, len) == 0, "TC-PROTSET-009 parse ok");
|
||||
CHECK(prot_set_get(PS_OC1_CUR) == cur, "TC-PROTSET-009 value round-trip bit-exact");
|
||||
CHECK(prot_set_get_ctl(PS_GLOBAL_EN) == 0u, "TC-PROTSET-009 plate state round-trip");
|
||||
CHECK(prot_set_selfcheck() == 0, "TC-PROTSET-009 parsed table sealed");
|
||||
CHECK(prot_set_dirty_peek() == 0u, "TC-PROTSET-009 parse does not mark dirty");
|
||||
}
|
||||
|
||||
/* 伪造辅助:按 blob 值区重算尾部 sum/sumn(构造"自洽但越界"的对抗样本) */
|
||||
@@ -205,7 +205,7 @@ static void s_forge_tail(uint8_t *b, uint32_t len) {
|
||||
s_put32(b + len - 4u, inv);
|
||||
}
|
||||
|
||||
/* TC-PS-010(B7:损坏 blob 整表拒绝,all-or-nothing) */
|
||||
/* TC-PROTSET-010(B7:损坏 blob 整表拒绝,all-or-nothing) */
|
||||
static void tc_store_corrupt(void) {
|
||||
uint8_t blob[PROT_SET_BLOB_SZ];
|
||||
uint32_t len = 0u;
|
||||
@@ -214,36 +214,36 @@ static void tc_store_corrupt(void) {
|
||||
prot_set_init();
|
||||
(void)prot_set_set_sealed(PS_OC2_CUR, PROT_SET_Q10(6.0));
|
||||
keep = prot_set_get(PS_OC2_CUR);
|
||||
CHECK(prot_set_store_serialize(blob, sizeof(blob), &len) == 0, "TC-PS-010 serialize ok");
|
||||
CHECK(prot_set_store_serialize(blob, sizeof(blob), &len) == 0, "TC-PROTSET-010 serialize ok");
|
||||
|
||||
blob[PROT_SET_BLOB_HDR_SZ] ^= 0x01u; /* 值区一位翻转:sum 对不符 */
|
||||
CHECK(prot_set_store_parse(blob, len) == -1, "TC-PS-010 flipped value byte rejected (sum pair)");
|
||||
CHECK(prot_set_get(PS_OC2_CUR) == keep, "TC-PS-010 reject leaves values untouched");
|
||||
CHECK(prot_set_store_parse(blob, len) == -1, "TC-PROTSET-010 flipped value byte rejected (sum pair)");
|
||||
CHECK(prot_set_get(PS_OC2_CUR) == keep, "TC-PROTSET-010 reject leaves values untouched");
|
||||
|
||||
(void)prot_set_store_serialize(blob, sizeof(blob), &len);
|
||||
blob[0] ^= 0xFFu; /* magic 破坏 */
|
||||
CHECK(prot_set_store_parse(blob, len) == -1, "TC-PS-010 bad magic rejected");
|
||||
CHECK(prot_set_store_parse(blob, len) == -1, "TC-PROTSET-010 bad magic rejected");
|
||||
|
||||
(void)prot_set_store_serialize(blob, sizeof(blob), &len);
|
||||
CHECK(prot_set_store_parse(blob, len - 4u) == -1, "TC-PS-010 truncated blob rejected");
|
||||
CHECK(prot_set_store_parse(blob, len + 4u) == -1, "TC-PS-010 oversized blob rejected");
|
||||
CHECK(prot_set_store_parse(blob, len - 4u) == -1, "TC-PROTSET-010 truncated blob rejected");
|
||||
CHECK(prot_set_store_parse(blob, len + 4u) == -1, "TC-PROTSET-010 oversized blob rejected");
|
||||
|
||||
(void)prot_set_store_serialize(blob, sizeof(blob), &len);
|
||||
blob[5] ^= 0x02u; /* version 高字节:1 -> 0x200 */
|
||||
CHECK(prot_set_store_parse(blob, len) == -1, "TC-PS-010 version mismatch rejected");
|
||||
CHECK(prot_set_store_parse(blob, len) == -1, "TC-PROTSET-010 version mismatch rejected");
|
||||
|
||||
/* 对抗样本:越限定值 + 重算 sum 对(校验全过、范围必拦) */
|
||||
(void)prot_set_store_serialize(blob, sizeof(blob), &len);
|
||||
s_put32(blob + PROT_SET_BLOB_HDR_SZ + 4u * (uint32_t)PS_OC1_CUR,
|
||||
(uint32_t)(g_prot_set_meta[PS_OC1_CUR].max + 1));
|
||||
s_forge_tail(blob, len);
|
||||
CHECK(prot_set_store_parse(blob, len) == -1, "TC-PS-010 forged consistent out-of-range rejected");
|
||||
CHECK(prot_set_bad_mask() == (1uLL << PS_OC1_CUR), "TC-PS-010 bad_mask points at item");
|
||||
CHECK(prot_set_get(PS_OC1_CUR) == PROT_SET_Q10(10.0), "TC-PS-010 defaults still intact");
|
||||
CHECK(prot_set_selfcheck() == 0, "TC-PS-010 active table still self-consistent after all rejects");
|
||||
CHECK(prot_set_store_parse(blob, len) == -1, "TC-PROTSET-010 forged consistent out-of-range rejected");
|
||||
CHECK(prot_set_bad_mask() == (1uLL << PS_OC1_CUR), "TC-PROTSET-010 bad_mask points at item");
|
||||
CHECK(prot_set_get(PS_OC1_CUR) == PROT_SET_Q10(10.0), "TC-PROTSET-010 defaults still intact");
|
||||
CHECK(prot_set_selfcheck() == 0, "TC-PROTSET-010 active table still self-consistent after all rejects");
|
||||
}
|
||||
|
||||
/* TC-PS-011(B8:OF/UF 定值行 + 40 项 + 64 位 bad_mask + 换代拒绝) */
|
||||
/* TC-PROTSET-011(B8:OF/UF 定值行 + 40 项 + 64 位 bad_mask + 换代拒绝) */
|
||||
static void tc_of_uf_meta(void) {
|
||||
uint8_t blob[PROT_SET_BLOB_SZ];
|
||||
uint32_t len = 0u;
|
||||
@@ -251,10 +251,10 @@ static void tc_of_uf_meta(void) {
|
||||
prot_set_init();
|
||||
|
||||
/* 结构:40 项、blob 版本 2、尺寸随项数自适应 */
|
||||
CHECK((uint32_t)PS_ID_COUNT == 40u, "TC-PS-011 PS_ID_COUNT == 40 (32 + 8 OF/UF)");
|
||||
CHECK(PROT_SET_BLOB_VER == 2u, "TC-PS-011 blob version bumped to 2 (B8)");
|
||||
CHECK((uint32_t)PS_ID_COUNT == 40u, "TC-PROTSET-011 PS_ID_COUNT == 40 (32 + 8 OF/UF)");
|
||||
CHECK(PROT_SET_BLOB_VER == 2u, "TC-PROTSET-011 blob version bumped to 2 (B8)");
|
||||
CHECK((uint32_t)PROT_SET_BLOB_SZ == (PROT_SET_BLOB_HDR_SZ + 4u * 40u + 8u),
|
||||
"TC-PS-011 blob size = hdr + 4*40 + tail");
|
||||
"TC-PROTSET-011 blob size = hdr + 4*40 + tail");
|
||||
|
||||
/* 地址:参考逐项地址不在本仓库 -> 8 项全部本地项(comm_addr=0,104 不可寻址) */
|
||||
CHECK((g_prot_set_meta[PS_OF_EN].comm_addr == 0u)
|
||||
@@ -265,60 +265,60 @@ static void tc_of_uf_meta(void) {
|
||||
&& (g_prot_set_meta[PS_UF_DLY].comm_addr == 0u)
|
||||
&& (g_prot_set_meta[PS_RET_OF].comm_addr == 0u)
|
||||
&& (g_prot_set_meta[PS_RET_UF].comm_addr == 0u),
|
||||
"TC-PS-011 OF/UF items all local (comm_addr=0, pending reference table)");
|
||||
"TC-PROTSET-011 OF/UF items all local (comm_addr=0, pending reference table)");
|
||||
|
||||
/* 投退 = ctl 项(0/1),其余 = 模拟量 Q10 */
|
||||
CHECK((g_prot_set_meta[PS_OF_EN].is_ctl == 1u) && (g_prot_set_meta[PS_UF_EN].is_ctl == 1u)
|
||||
&& (g_prot_set_meta[PS_OF_HZ].is_ctl == 0u) && (g_prot_set_meta[PS_RET_UF].is_ctl == 0u),
|
||||
"TC-PS-011 EN items are ctl, HZ/DLY/RET are Q10 analog");
|
||||
"TC-PROTSET-011 EN items are ctl, HZ/DLY/RET are Q10 analog");
|
||||
|
||||
/* 出厂默认(拟定值)与范围 */
|
||||
CHECK(prot_set_get(PS_OF_EN) == PROT_SET_Q10(1.0), "TC-PS-011 OF EN default 1");
|
||||
CHECK(prot_set_get(PS_UF_EN) == PROT_SET_Q10(1.0), "TC-PS-011 UF EN default 1");
|
||||
CHECK(prot_set_get(PS_OF_HZ) == PROT_SET_Q10(51.0), "TC-PS-011 OF default 51.0 Hz");
|
||||
CHECK(prot_set_get(PS_UF_HZ) == PROT_SET_Q10(49.0), "TC-PS-011 UF default 49.0 Hz");
|
||||
CHECK(prot_set_get(PS_OF_DLY) == PROT_SET_Q10(1000.0), "TC-PS-011 OF default 1000 ms");
|
||||
CHECK(prot_set_get(PS_UF_DLY) == PROT_SET_Q10(1000.0), "TC-PS-011 UF default 1000 ms");
|
||||
CHECK(prot_set_get(PS_RET_OF) == PROT_SET_Q10(0.99), "TC-PS-011 RET_OF default 0.99");
|
||||
CHECK(prot_set_get(PS_RET_UF) == PROT_SET_Q10(1.01), "TC-PS-011 RET_UF default 1.01");
|
||||
CHECK(prot_set_get(PS_OF_EN) == PROT_SET_Q10(1.0), "TC-PROTSET-011 OF EN default 1");
|
||||
CHECK(prot_set_get(PS_UF_EN) == PROT_SET_Q10(1.0), "TC-PROTSET-011 UF EN default 1");
|
||||
CHECK(prot_set_get(PS_OF_HZ) == PROT_SET_Q10(51.0), "TC-PROTSET-011 OF default 51.0 Hz");
|
||||
CHECK(prot_set_get(PS_UF_HZ) == PROT_SET_Q10(49.0), "TC-PROTSET-011 UF default 49.0 Hz");
|
||||
CHECK(prot_set_get(PS_OF_DLY) == PROT_SET_Q10(1000.0), "TC-PROTSET-011 OF default 1000 ms");
|
||||
CHECK(prot_set_get(PS_UF_DLY) == PROT_SET_Q10(1000.0), "TC-PROTSET-011 UF default 1000 ms");
|
||||
CHECK(prot_set_get(PS_RET_OF) == PROT_SET_Q10(0.99), "TC-PROTSET-011 RET_OF default 0.99");
|
||||
CHECK(prot_set_get(PS_RET_UF) == PROT_SET_Q10(1.01), "TC-PROTSET-011 RET_UF default 1.01");
|
||||
CHECK((g_prot_set_meta[PS_OF_HZ].min == PROT_SET_Q10(50.0))
|
||||
&& (g_prot_set_meta[PS_OF_HZ].max == PROT_SET_Q10(55.0)),
|
||||
"TC-PS-011 OF range 50.0~55.0 Hz");
|
||||
"TC-PROTSET-011 OF range 50.0~55.0 Hz");
|
||||
CHECK((g_prot_set_meta[PS_UF_HZ].min == PROT_SET_Q10(45.0))
|
||||
&& (g_prot_set_meta[PS_UF_HZ].max == PROT_SET_Q10(50.0)),
|
||||
"TC-PS-011 UF range 45.0~50.0 Hz");
|
||||
"TC-PROTSET-011 UF range 45.0~50.0 Hz");
|
||||
|
||||
/* 频率返回系数与电气量系数独立:返回**门槛** = 定值×系数(Q10 乘积
|
||||
* /1024)——OF 门槛 < 动作门槛、UF 门槛 > 动作门槛(方向相反) */
|
||||
CHECK(((int64_t)prot_set_get(PS_OF_HZ) * (int64_t)prot_set_get(PS_RET_OF)) / 1024
|
||||
< (int64_t)prot_set_get(PS_OF_HZ),
|
||||
"TC-PS-011 OF return threshold (set x 0.99) below pickup");
|
||||
"TC-PROTSET-011 OF return threshold (set x 0.99) below pickup");
|
||||
CHECK(((int64_t)prot_set_get(PS_UF_HZ) * (int64_t)prot_set_get(PS_RET_UF)) / 1024
|
||||
> (int64_t)prot_set_get(PS_UF_HZ),
|
||||
"TC-PS-011 UF return threshold (set x 1.01) above pickup");
|
||||
"TC-PROTSET-011 UF return threshold (set x 1.01) above pickup");
|
||||
|
||||
/* 投退可经 set_sealed 投/退(YK 口径同 GLOBAL_EN;Q10(2)=2048 越界拒) */
|
||||
CHECK(prot_set_set_sealed(PS_OF_EN, 0) == 0, "TC-PS-011 OF EN set_sealed OK");
|
||||
CHECK(prot_set_get_ctl(PS_OF_EN) == 0u, "TC-PS-011 OF EN readable after seal");
|
||||
CHECK(prot_set_set_sealed(PS_OF_EN, PROT_SET_Q10(2)) == -1, "TC-PS-011 OF EN rejects Q10(2)");
|
||||
CHECK(prot_set_selfcheck() == 0, "TC-PS-011 no lock after OF/UF seal ops");
|
||||
CHECK(prot_set_set_sealed(PS_OF_EN, 0) == 0, "TC-PROTSET-011 OF EN set_sealed OK");
|
||||
CHECK(prot_set_get_ctl(PS_OF_EN) == 0u, "TC-PROTSET-011 OF EN readable after seal");
|
||||
CHECK(prot_set_set_sealed(PS_OF_EN, PROT_SET_Q10(2)) == -1, "TC-PROTSET-011 OF EN rejects Q10(2)");
|
||||
CHECK(prot_set_selfcheck() == 0, "TC-PROTSET-011 no lock after OF/UF seal ops");
|
||||
|
||||
/* 64 位 bad_mask:末项(bit 39 > 31)越界可指认 */
|
||||
(void)prot_set_set_sealed(PS_OC1_CUR, PROT_SET_Q10(11.0));
|
||||
(void)prot_set_dirty_take();
|
||||
CHECK(prot_set_store_serialize(blob, sizeof(blob), &len) == 0, "TC-PS-011 serialize ok");
|
||||
CHECK(prot_set_store_serialize(blob, sizeof(blob), &len) == 0, "TC-PROTSET-011 serialize ok");
|
||||
s_put32(blob + PROT_SET_BLOB_HDR_SZ + 4u * (uint32_t)PS_RET_UF,
|
||||
(uint32_t)(g_prot_set_meta[PS_RET_UF].max + 1));
|
||||
s_forge_tail(blob, len);
|
||||
CHECK(prot_set_store_parse(blob, len) == -1, "TC-PS-011 out-of-range RET_UF rejected");
|
||||
CHECK(prot_set_store_parse(blob, len) == -1, "TC-PROTSET-011 out-of-range RET_UF rejected");
|
||||
CHECK(prot_set_bad_mask() == (1uLL << PS_RET_UF),
|
||||
"TC-PS-011 bad_mask bit 39 addressable (64-bit mask, B8)");
|
||||
CHECK(prot_set_get(PS_RET_UF) == PROT_SET_Q10(1.01), "TC-PS-011 default RET_UF intact");
|
||||
"TC-PROTSET-011 bad_mask bit 39 addressable (64-bit mask, B8)");
|
||||
CHECK(prot_set_get(PS_RET_UF) == PROT_SET_Q10(1.01), "TC-PROTSET-011 default RET_UF intact");
|
||||
|
||||
/* 换代语义:B7 旧档(ver=1 / 32 项 = 144 B)在新固件必被拒 -> 出厂默认 */
|
||||
CHECK(prot_set_store_parse(blob, 8u + 4u * 32u + 8u) == -1,
|
||||
"TC-PS-011 legacy 32-item blob length rejected");
|
||||
CHECK(prot_set_selfcheck() == 0, "TC-PS-011 active table intact after legacy reject");
|
||||
"TC-PROTSET-011 legacy 32-item blob length rejected");
|
||||
CHECK(prot_set_selfcheck() == 0, "TC-PROTSET-011 active table intact after legacy reject");
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
|
||||
@@ -12,14 +12,14 @@
|
||||
* 看不出哪一步坏;标准向量在主机侧毫秒级钉死。
|
||||
*
|
||||
* 覆盖点:
|
||||
* TC-SH-001 FIPS 180-4 向量:空串
|
||||
* TC-SH-002 FIPS 180-4 向量:"abc"
|
||||
* TC-SH-003 FIPS 180-4 向量:56 字节(补位跨分组边界)
|
||||
* TC-SH-004 FIPS 180-4 向量:1,000,000 × 'a'(流式,长度字段进第二分组)
|
||||
* TC-SH-005 流式任意切分与一次性计算等价(逐字节喂入)
|
||||
* TC-SH-006 hex_eq:小写匹配 / 大写匹配
|
||||
* TC-SH-007 hex_eq:内容不等 / 非法字符 / 长度 63/65 / NULL → 全 0
|
||||
* TC-SH-008 默认口令哈希钉值:SHA256("adminadmin") = FTP_CFG_DEF_HASH 同源值
|
||||
* TC-SHA256-001 FIPS 180-4 向量:空串
|
||||
* TC-SHA256-002 FIPS 180-4 向量:"abc"
|
||||
* TC-SHA256-003 FIPS 180-4 向量:56 字节(补位跨分组边界)
|
||||
* TC-SHA256-004 FIPS 180-4 向量:1,000,000 × 'a'(流式,长度字段进第二分组)
|
||||
* TC-SHA256-005 流式任意切分与一次性计算等价(逐字节喂入)
|
||||
* TC-SHA256-006 hex_eq:小写匹配 / 大写匹配
|
||||
* TC-SHA256-007 hex_eq:内容不等 / 非法字符 / 长度 63/65 / NULL → 全 0
|
||||
* TC-SHA256-008 默认口令哈希钉值:SHA256("adminadmin") = FTP_CFG_DEF_HASH 同源值
|
||||
*
|
||||
* 通过:全部 TC PASS(main 返回 0)。
|
||||
* 入口:int main(void),返回 0=PASS / 1=FAIL(由 run 脚本判读)。
|
||||
@@ -65,7 +65,7 @@ static int hex_eq_vector(const uint8_t d[SHA256_DIGEST_SIZE], const char *want)
|
||||
return strcmp(got, want) == 0;
|
||||
}
|
||||
|
||||
/* ===================== TC-SH-001..004:标准向量 ===================== */
|
||||
/* ===================== TC-SHA256-001..004:标准向量 ===================== */
|
||||
|
||||
static void tc_vectors(void)
|
||||
{
|
||||
@@ -73,15 +73,15 @@ static void tc_vectors(void)
|
||||
|
||||
sha256_calc("", 0u, d);
|
||||
CHECK(hex_eq_vector(d, "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"),
|
||||
"TC-SH-001 空串向量");
|
||||
"TC-SHA256-001 空串向量");
|
||||
|
||||
sha256_calc("abc", 3u, d);
|
||||
CHECK(hex_eq_vector(d, "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"),
|
||||
"TC-SH-002 \"abc\" 向量");
|
||||
"TC-SHA256-002 \"abc\" 向量");
|
||||
|
||||
sha256_calc("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", 56u, d);
|
||||
CHECK(hex_eq_vector(d, "248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1"),
|
||||
"TC-SH-003 56 字节向量(补位跨分组)");
|
||||
"TC-SHA256-003 56 字节向量(补位跨分组)");
|
||||
|
||||
{
|
||||
sha256_ctx_t ctx;
|
||||
@@ -93,10 +93,10 @@ static void tc_vectors(void)
|
||||
sha256_final(&ctx, d);
|
||||
}
|
||||
CHECK(hex_eq_vector(d, "cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0"),
|
||||
"TC-SH-004 1e6 × 'a' 向量(流式)");
|
||||
"TC-SHA256-004 1e6 × 'a' 向量(流式)");
|
||||
}
|
||||
|
||||
/* ===================== TC-SH-005:流式等价 ===================== */
|
||||
/* ===================== TC-SHA256-005:流式等价 ===================== */
|
||||
|
||||
static void tc_stream_equiv(void)
|
||||
{
|
||||
@@ -111,10 +111,10 @@ static void tc_stream_equiv(void)
|
||||
sha256_update(&ctx, &msg[i], 1u);
|
||||
}
|
||||
sha256_final(&ctx, d2);
|
||||
CHECK(memcmp(d1, d2, sizeof(d1)) == 0, "TC-SH-005 逐字节喂入与一次性等价");
|
||||
CHECK(memcmp(d1, d2, sizeof(d1)) == 0, "TC-SHA256-005 逐字节喂入与一次性等价");
|
||||
}
|
||||
|
||||
/* ===================== TC-SH-006..007:hex_eq ===================== */
|
||||
/* ===================== TC-SHA256-006..007:hex_eq ===================== */
|
||||
|
||||
static void tc_hex_eq(void)
|
||||
{
|
||||
@@ -131,11 +131,11 @@ static void tc_hex_eq(void)
|
||||
}
|
||||
upper[64] = '\0';
|
||||
|
||||
CHECK(sha256_hex_eq(d, lower) == 1, "TC-SH-006a 小写 hex 匹配");
|
||||
CHECK(sha256_hex_eq(d, upper) == 1, "TC-SH-006b 大写 hex 匹配(大小写不敏感)");
|
||||
CHECK(sha256_hex_eq(d, lower) == 1, "TC-SHA256-006a 小写 hex 匹配");
|
||||
CHECK(sha256_hex_eq(d, upper) == 1, "TC-SHA256-006b 大写 hex 匹配(大小写不敏感)");
|
||||
|
||||
lower[63] = (char)((lower[63] == '0') ? '1' : '0');
|
||||
CHECK(sha256_hex_eq(d, lower) == 0, "TC-SH-007a 内容不等 → 0");
|
||||
CHECK(sha256_hex_eq(d, lower) == 0, "TC-SHA256-007a 内容不等 → 0");
|
||||
lower[63] = (char)((lower[63] == '0') ? '1' : '0'); /* 还原 */
|
||||
|
||||
{
|
||||
@@ -144,22 +144,22 @@ static void tc_hex_eq(void)
|
||||
memcpy(bad, lower, 64);
|
||||
bad[64] = '\0';
|
||||
bad[10] = 'g';
|
||||
CHECK(sha256_hex_eq(d, bad) == 0, "TC-SH-007b 非法 hex 字符 → 0");
|
||||
CHECK(sha256_hex_eq(d, bad) == 0, "TC-SHA256-007b 非法 hex 字符 → 0");
|
||||
}
|
||||
|
||||
memcpy(shortv, lower, 63);
|
||||
shortv[63] = '\0';
|
||||
CHECK(sha256_hex_eq(d, shortv) == 0, "TC-SH-007c 长度 63 → 0");
|
||||
CHECK(sha256_hex_eq(d, shortv) == 0, "TC-SHA256-007c 长度 63 → 0");
|
||||
|
||||
memcpy(longv, lower, 64);
|
||||
longv[64] = 'a';
|
||||
longv[65] = '\0';
|
||||
CHECK(sha256_hex_eq(d, longv) == 0, "TC-SH-007d 长度 65 → 0");
|
||||
CHECK(sha256_hex_eq(d, longv) == 0, "TC-SHA256-007d 长度 65 → 0");
|
||||
|
||||
CHECK(sha256_hex_eq(d, NULL) == 0, "TC-SH-007e NULL → 0");
|
||||
CHECK(sha256_hex_eq(d, NULL) == 0, "TC-SHA256-007e NULL → 0");
|
||||
}
|
||||
|
||||
/* ===================== TC-SH-008:默认口令哈希钉值 ===================== */
|
||||
/* ===================== TC-SHA256-008:默认口令哈希钉值 ===================== */
|
||||
|
||||
static void tc_default_hash(void)
|
||||
{
|
||||
@@ -168,7 +168,7 @@ static void tc_default_hash(void)
|
||||
/* 与 ftp_cfg.h FTP_CFG_DEF_HASH 同源钉值(两处若漂移本测试立刻红) */
|
||||
sha256_calc("adminadmin", 10u, d);
|
||||
CHECK(sha256_hex_eq(d, "d82494f05d6917ba02f7aaa29689ccb444bb73f20380876cb05d1f37537b7892") == 1,
|
||||
"TC-SH-008 SHA256(\"adminadmin\") = 出厂默认 pwd_hash");
|
||||
"TC-SHA256-008 SHA256(\"adminadmin\") = 出厂默认 pwd_hash");
|
||||
}
|
||||
|
||||
/* ===================== main ===================== */
|
||||
|
||||
@@ -14,27 +14,27 @@
|
||||
* - 其余用例用 sys_clock_set(unix, NULL) 建立确定基准(无 RTC 副作用)。
|
||||
*
|
||||
* 覆盖点(对应 docs/测试说明/系统时钟单元测试说明.md 的 TC-CLK-xxx):
|
||||
* TC-CLK-000 未初始化:sys_clock_get / get_time / get_str 的无效语义
|
||||
* TC-CLK-001 init 正常:RTC 合法 → 返回 0,基准 = 换算 Unix 秒
|
||||
* TC-CLK-002 init 闰年换算:2024-02-29 / 2000-02-29(世纪闰)/ 2/29→3/1 间隔
|
||||
* TC-CLK-003 init 月末边界:1/31、2/28、4/30 的 Unix 秒精确值
|
||||
* TC-CLK-004 init 世纪边界:2000-01-01、2038 上限(0x7FFFFFFF)、Unix 0 经 set
|
||||
* TC-CLK-005 init RTC 读失败 → 降级默认时间,返回 -1 + 打错误日志
|
||||
* TC-CLK-006 init RTC 越界(年份/月/日非法)→ 自愈写回默认时间(返回 0)
|
||||
* TC-CLK-020 init 越界且写回失败 → 降级默认时间 + 返回 -1
|
||||
* TC-CLK-007 init 越界 → 自动写回默认时间并复验(rtc 被修正)
|
||||
* TC-CLK-008 get 正常推进:tick +1000 → +1 秒(含亚秒截断)
|
||||
* TC-CLK-009 get 未跨阈值不回绕:tick + 29 天仍线性
|
||||
* TC-CLK-010 get 30 天再基准化:窗口清零、墙钟值无损、含亚秒余数结转
|
||||
* TC-CLK-011 get tick 回绕(无符号差)安全
|
||||
* TC-CLK-012 get 再基准化后长期不漂移(多轮 30 天)
|
||||
* TC-CLK-013 get_str 格式化 + 未初始化占位串
|
||||
* TC-CLK-014 get_time 日历字段(年/月/日/时/分/秒/星期)与已知日期对照
|
||||
* TC-CLK-015 get_time NULL 参数被拒
|
||||
* TC-CLK-016 set 更新基准 + 写回 RTC(观察 sd2506_set_time 被调)
|
||||
* TC-CLK-017 set sd_time=NULL 不碰 RTC
|
||||
* TC-CLK-018 set_unix 写回 RTC 且日历字段正确(含星期)
|
||||
* TC-CLK-019 星期(Zeller)与已知日期对照穷举(跨世纪/闰/月末)
|
||||
* TC-SYSCLK-000 未初始化:sys_clock_get / get_time / get_str 的无效语义
|
||||
* TC-SYSCLK-001 init 正常:RTC 合法 → 返回 0,基准 = 换算 Unix 秒
|
||||
* TC-SYSCLK-002 init 闰年换算:2024-02-29 / 2000-02-29(世纪闰)/ 2/29→3/1 间隔
|
||||
* TC-SYSCLK-003 init 月末边界:1/31、2/28、4/30 的 Unix 秒精确值
|
||||
* TC-SYSCLK-004 init 世纪边界:2000-01-01、2038 上限(0x7FFFFFFF)、Unix 0 经 set
|
||||
* TC-SYSCLK-005 init RTC 读失败 → 降级默认时间,返回 -1 + 打错误日志
|
||||
* TC-SYSCLK-006 init RTC 越界(年份/月/日非法)→ 自愈写回默认时间(返回 0)
|
||||
* TC-SYSCLK-020 init 越界且写回失败 → 降级默认时间 + 返回 -1
|
||||
* TC-SYSCLK-007 init 越界 → 自动写回默认时间并复验(rtc 被修正)
|
||||
* TC-SYSCLK-008 get 正常推进:tick +1000 → +1 秒(含亚秒截断)
|
||||
* TC-SYSCLK-009 get 未跨阈值不回绕:tick + 29 天仍线性
|
||||
* TC-SYSCLK-010 get 30 天再基准化:窗口清零、墙钟值无损、含亚秒余数结转
|
||||
* TC-SYSCLK-011 get tick 回绕(无符号差)安全
|
||||
* TC-SYSCLK-012 get 再基准化后长期不漂移(多轮 30 天)
|
||||
* TC-SYSCLK-013 get_str 格式化 + 未初始化占位串
|
||||
* TC-SYSCLK-014 get_time 日历字段(年/月/日/时/分/秒/星期)与已知日期对照
|
||||
* TC-SYSCLK-015 get_time NULL 参数被拒
|
||||
* TC-SYSCLK-016 set 更新基准 + 写回 RTC(观察 sd2506_set_time 被调)
|
||||
* TC-SYSCLK-017 set sd_time=NULL 不碰 RTC
|
||||
* TC-SYSCLK-018 set_unix 写回 RTC 且日历字段正确(含星期)
|
||||
* TC-SYSCLK-019 星期(Zeller)与已知日期对照穷举(跨世纪/闰/月末)
|
||||
*
|
||||
* 通过:全部 TC PASS(main 返回 0)。
|
||||
* 入口:int main(void),返回 0=PASS / 1=FAIL(由 run 脚本判读)。
|
||||
@@ -189,7 +189,7 @@ static void tc_000_uninitialized(void) {
|
||||
sd2506_time_t t;
|
||||
char buf[32];
|
||||
|
||||
printf("TC-CLK-000 未初始化语义\n");
|
||||
printf("TC-SYSCLK-000 未初始化语义\n");
|
||||
/* 注意:本用例不做 sys_clock_init / sys_clock_set */
|
||||
CHECK_EQ_U32(sys_clock_get(), UINT32_MAX, "未初始化 get 返回 UINT32_MAX");
|
||||
CHECK(sys_clock_get_time(&t) == -1, "未初始化 get_time 返回 -1");
|
||||
@@ -201,7 +201,7 @@ static void tc_000_uninitialized(void) {
|
||||
|
||||
static void tc_001_init_ok(void) {
|
||||
int rc;
|
||||
printf("TC-CLK-001 init 正常(RTC 合法)\n");
|
||||
printf("TC-SYSCLK-001 init 正常(RTC 合法)\n");
|
||||
rtc_set(2026, 8, 24, 0, 0, 0);
|
||||
s_rtc_read_rc = SD2506_OK;
|
||||
s_rtc_write_rc = SD2506_OK;
|
||||
@@ -216,7 +216,7 @@ static void tc_001_init_ok(void) {
|
||||
}
|
||||
|
||||
static void tc_002_init_leap(void) {
|
||||
printf("TC-CLK-002 init 闰年换算\n");
|
||||
printf("TC-SYSCLK-002 init 闰年换算\n");
|
||||
/* 2024 是闰年:2/29 存在 */
|
||||
rtc_set(2024, 2, 29, 12, 0, 0);
|
||||
s_rtc_read_rc = SD2506_OK;
|
||||
@@ -240,7 +240,7 @@ static void tc_002_init_leap(void) {
|
||||
}
|
||||
|
||||
static void tc_003_init_month_end(void) {
|
||||
printf("TC-CLK-003 init 月末边界\n");
|
||||
printf("TC-SYSCLK-003 init 月末边界\n");
|
||||
rtc_set(2026, 1, 31, 0, 0, 0); s_rtc_read_rc = SD2506_OK;
|
||||
CHECK(sys_clock_init() == 0, "1/31 合法");
|
||||
CHECK_EQ_U32(sys_clock_get(), ref_unix(2026, 1, 31, 0, 0, 0), "1/31 换算");
|
||||
@@ -262,7 +262,7 @@ static void tc_003_init_month_end(void) {
|
||||
}
|
||||
|
||||
static void tc_004_init_epoch_bounds(void) {
|
||||
printf("TC-CLK-004 init 世纪边界(Unix 下限 / 2038 上限)\n");
|
||||
printf("TC-SYSCLK-004 init 世纪边界(Unix 下限 / 2038 上限)\n");
|
||||
/*
|
||||
* 注意:init 接受的 RTC 年份范围是 2000~2099(越界即判故障并自愈),
|
||||
* 故"Unix 0(1970-01-01)"**不可能经 init 建立**——1970 会被判越界。
|
||||
@@ -291,7 +291,7 @@ static void tc_004_init_epoch_bounds(void) {
|
||||
}
|
||||
|
||||
static void tc_005_init_rtc_read_fail(void) {
|
||||
printf("TC-CLK-005 init RTC 读失败 → 降级默认时间并返回 -1\n");
|
||||
printf("TC-SYSCLK-005 init RTC 读失败 → 降级默认时间并返回 -1\n");
|
||||
s_rtc_read_rc = SD2506_ERROR; /* 注入读故障 */
|
||||
s_rtc_write_rc = SD2506_OK;
|
||||
clear_obs();
|
||||
@@ -309,7 +309,7 @@ static void tc_005_init_rtc_read_fail(void) {
|
||||
}
|
||||
|
||||
static void tc_006_init_out_of_range_selfheal(void) {
|
||||
printf("TC-CLK-006 init RTC 越界 → 自愈写回默认时间(返回 0)\n");
|
||||
printf("TC-SYSCLK-006 init RTC 越界 → 自愈写回默认时间(返回 0)\n");
|
||||
/*
|
||||
* RTC_DEFAULT_INIT_ENABLE=1 且 FORCE=0 时:越界值触发"写回默认时间",
|
||||
* 写成功且复读合法 → rtc_ok 恢复为 1 → **返回 0**(自愈,非降级)。
|
||||
@@ -335,7 +335,7 @@ static void tc_006_init_out_of_range_selfheal(void) {
|
||||
}
|
||||
|
||||
static void tc_020_init_selfheal_fail_degrades(void) {
|
||||
printf("TC-CLK-020 init 越界且写回失败 → 降级默认时间并返回 -1\n");
|
||||
printf("TC-SYSCLK-020 init 越界且写回失败 → 降级默认时间并返回 -1\n");
|
||||
/*
|
||||
* 组合故障:读成功但值越界(触发写回),写回失败 → 复读仍越界 →
|
||||
* rtc_ok 清 0 → 走降级分支(启用默认值时建基准 + 返回 -1)。
|
||||
@@ -356,7 +356,7 @@ static void tc_020_init_selfheal_fail_degrades(void) {
|
||||
}
|
||||
|
||||
static void tc_007_init_corrects_rtc(void) {
|
||||
printf("TC-CLK-007 init 越界 → 自动写回默认时间并复验\n");
|
||||
printf("TC-SYSCLK-007 init 越界 → 自动写回默认时间并复验\n");
|
||||
rtc_set(1999, 1, 1, 0, 0, 0); /* 越界,触发校时写回 */
|
||||
s_rtc_read_rc = SD2506_OK;
|
||||
s_rtc_write_rc = SD2506_OK;
|
||||
@@ -372,7 +372,7 @@ static void tc_007_init_corrects_rtc(void) {
|
||||
}
|
||||
|
||||
static void tc_008_get_advance(void) {
|
||||
printf("TC-CLK-008 get 正常推进(含亚秒截断)\n");
|
||||
printf("TC-SYSCLK-008 get 正常推进(含亚秒截断)\n");
|
||||
base_at(1000000u, 5000u);
|
||||
CHECK_EQ_U32(sys_clock_get(), 1000000u, "基准时刻 = 基准值");
|
||||
tick_advance(999u);
|
||||
@@ -384,7 +384,7 @@ static void tc_008_get_advance(void) {
|
||||
}
|
||||
|
||||
static void tc_009_get_no_rebase_below_threshold(void) {
|
||||
printf("TC-CLK-009 未达 30 天阈值不触发再基准化\n");
|
||||
printf("TC-SYSCLK-009 未达 30 天阈值不触发再基准化\n");
|
||||
base_at(2000000u, 0u);
|
||||
/* 29 天 < 30 天阈值:线性推进,基准不动 */
|
||||
tick_advance(29u * 24u * 3600u * 1000u);
|
||||
@@ -393,7 +393,7 @@ static void tc_009_get_no_rebase_below_threshold(void) {
|
||||
}
|
||||
|
||||
static void tc_010_get_rebase_at_threshold(void) {
|
||||
printf("TC-CLK-010 30 天惰性再基准化(窗口清零、值无损、余数结转)\n");
|
||||
printf("TC-SYSCLK-010 30 天惰性再基准化(窗口清零、值无损、余数结转)\n");
|
||||
base_at(3000000u, 0u);
|
||||
|
||||
/* 推进恰好 30 天 + 1500ms(余数 500ms 应结转到新窗) */
|
||||
@@ -411,7 +411,7 @@ static void tc_010_get_rebase_at_threshold(void) {
|
||||
}
|
||||
|
||||
static void tc_011_get_tick_wrap(void) {
|
||||
printf("TC-CLK-011 tick 回绕(无符号差)安全\n");
|
||||
printf("TC-SYSCLK-011 tick 回绕(无符号差)安全\n");
|
||||
/* 基准设在接近 2^32 处 */
|
||||
base_at(4000000u, 0xFFFFF000u);
|
||||
/* 推进 0x2000 ms(跨越 2^32 回绕):差 = 0x2000 = 8192ms → +8s */
|
||||
@@ -420,7 +420,7 @@ static void tc_011_get_tick_wrap(void) {
|
||||
}
|
||||
|
||||
static void tc_012_get_long_run_no_drift(void) {
|
||||
printf("TC-CLK-012 多轮再基准化长期不漂移\n");
|
||||
printf("TC-SYSCLK-012 多轮再基准化长期不漂移\n");
|
||||
base_at(5000000u, 0u);
|
||||
/*
|
||||
* 惰性再基准化的**正确用法**:周期性调用 get() 让差值窗口始终 < 30 天。
|
||||
@@ -439,7 +439,7 @@ static void tc_012_get_long_run_no_drift(void) {
|
||||
}
|
||||
|
||||
static void tc_013_get_str(void) {
|
||||
printf("TC-CLK-013 get_str 格式化\n");
|
||||
printf("TC-SYSCLK-013 get_str 格式化\n");
|
||||
char buf[32];
|
||||
base_at(ref_unix(2026, 10, 2, 13, 4, 5), 0u);
|
||||
memset(buf, 0, sizeof(buf));
|
||||
@@ -453,7 +453,7 @@ static void tc_013_get_str(void) {
|
||||
}
|
||||
|
||||
static void tc_014_get_time_fields(void) {
|
||||
printf("TC-CLK-014 get_time 日历字段\n");
|
||||
printf("TC-SYSCLK-014 get_time 日历字段\n");
|
||||
sd2506_time_t t;
|
||||
/* 2026-10-02 是周五(已知) */
|
||||
base_at(ref_unix(2026, 10, 2, 8, 9, 10), 0u);
|
||||
@@ -465,13 +465,13 @@ static void tc_014_get_time_fields(void) {
|
||||
}
|
||||
|
||||
static void tc_015_get_time_null(void) {
|
||||
printf("TC-CLK-015 get_time NULL 参数被拒\n");
|
||||
printf("TC-SYSCLK-015 get_time NULL 参数被拒\n");
|
||||
base_at(6000000u, 0u);
|
||||
CHECK(sys_clock_get_time(NULL) == -1, "p_time == NULL → 返回 -1");
|
||||
}
|
||||
|
||||
static void tc_016_set_writes_rtc(void) {
|
||||
printf("TC-CLK-016 set 更新基准 + 写回 RTC\n");
|
||||
printf("TC-SYSCLK-016 set 更新基准 + 写回 RTC\n");
|
||||
sd2506_time_t sd;
|
||||
memset(&sd, 0, sizeof(sd));
|
||||
sd.year = 2027; sd.month = 3; sd.day = 15;
|
||||
@@ -497,7 +497,7 @@ static void tc_016_set_writes_rtc(void) {
|
||||
}
|
||||
|
||||
static void tc_017_set_no_rtc(void) {
|
||||
printf("TC-CLK-017 set sd_time=NULL 不碰 RTC\n");
|
||||
printf("TC-SYSCLK-017 set sd_time=NULL 不碰 RTC\n");
|
||||
clear_obs();
|
||||
CHECK(sys_clock_set(8000000u, NULL) == 0, "set(NULL) 返回 0");
|
||||
CHECK(s_rtc_set_calls == 0, "sd_time == NULL → 不写 RTC");
|
||||
@@ -505,7 +505,7 @@ static void tc_017_set_no_rtc(void) {
|
||||
}
|
||||
|
||||
static void tc_018_set_unix_fields(void) {
|
||||
printf("TC-CLK-018 set_unix 写回 RTC 且字段正确\n");
|
||||
printf("TC-SYSCLK-018 set_unix 写回 RTC 且字段正确\n");
|
||||
sd2506_time_t expect_week;
|
||||
uint32_t u = ref_unix(2026, 10, 2, 15, 30, 45);
|
||||
clear_obs();
|
||||
@@ -521,7 +521,7 @@ static void tc_018_set_unix_fields(void) {
|
||||
}
|
||||
|
||||
static void tc_019_week_known_dates(void) {
|
||||
printf("TC-CLK-019 星期(Zeller)已知日期穷举\n");
|
||||
printf("TC-SYSCLK-019 星期(Zeller)已知日期穷举\n");
|
||||
/* 期望值经 Python datetime 独立核对(0=周日);
|
||||
* 覆盖 1/2 月(Zeller 需上调为上年 13/14 月的分支)与 3~12 月(2026-10-02
|
||||
* 修正前全部错误),以及世纪闰年、非闰世纪、范围首尾。*/
|
||||
|
||||
@@ -27,36 +27,36 @@
|
||||
*
|
||||
* 覆盖点(TC-TS-xxx):
|
||||
* —— time_sync_delay_fed(可喂心跳的分片延时)——
|
||||
* TC-TS-001 0ms 不睡眠不喂狗
|
||||
* TC-TS-002 恰好一片(50ms)
|
||||
* TC-TS-003 非整片(120ms)切成 50/50/20,每片喂心跳
|
||||
* TC-TS-004 长延时(2000ms)= 40 片 × 50ms,每片喂心跳
|
||||
* TC-TS-005 不足一片(49ms)单片处理
|
||||
* TC-TS-006 总预算 30s = 600 片(片长上限恒 50ms)
|
||||
* TC-TIMESYNC-001 0ms 不睡眠不喂狗
|
||||
* TC-TIMESYNC-002 恰好一片(50ms)
|
||||
* TC-TIMESYNC-003 非整片(120ms)切成 50/50/20,每片喂心跳
|
||||
* TC-TIMESYNC-004 长延时(2000ms)= 40 片 × 50ms,每片喂心跳
|
||||
* TC-TIMESYNC-005 不足一片(49ms)单片处理
|
||||
* TC-TIMESYNC-006 总预算 30s = 600 片(片长上限恒 50ms)
|
||||
* —— time_sync_open_listener(监听建立与重试)——
|
||||
* TC-TS-010 首次成功:socket/bind/listen 各一次,端口经 net_htons,无退避
|
||||
* TC-TS-011 bind 失败 -> 关 socket + 退避 2000ms + 留痕,随后重试成功
|
||||
* TC-TS-012 listen 失败 -> 关 socket + 退避 2000ms,随后重试成功
|
||||
* TC-TS-013 socket 连续失败 -> 5 次后返回 -1(5 条 ERROR,5×500ms 退避)
|
||||
* TC-TS-014 第 3 次重试成功并返回新描述符
|
||||
* TC-TS-015 每次重试前 + 每片延时各喂一次心跳,且心跳位恒为 TIMESYNC
|
||||
* TC-TIMESYNC-010 首次成功:socket/bind/listen 各一次,端口经 net_htons,无退避
|
||||
* TC-TIMESYNC-011 bind 失败 -> 关 socket + 退避 2000ms + 留痕,随后重试成功
|
||||
* TC-TIMESYNC-012 listen 失败 -> 关 socket + 退避 2000ms,随后重试成功
|
||||
* TC-TIMESYNC-013 socket 连续失败 -> 5 次后返回 -1(5 条 ERROR,5×500ms 退避)
|
||||
* TC-TIMESYNC-014 第 3 次重试成功并返回新描述符
|
||||
* TC-TIMESYNC-015 每次重试前 + 每片延时各喂一次心跳,且心跳位恒为 TIMESYNC
|
||||
* —— time_sync_handle_conn(时间包重组状态机)——
|
||||
* TC-TS-020 8 字节一次收齐 -> 大端解析 epoch + 更新墙钟 + 关连接
|
||||
* TC-TS-021 分段送达(4+4)-> 累积后解析;第二次只请求剩余 12 字节
|
||||
* TC-TS-022 一次到达 16 字节 -> 只取前 8 字节
|
||||
* TC-TS-023 前缀非 "TIME" -> 不更新墙钟,但仍关连接
|
||||
* TC-TS-024 对端关闭(n==0)-> 立即退出、不解析
|
||||
* TC-TS-025 真错误(n==-1)-> 立即退出、不解析
|
||||
* TC-TS-026 只收到 4 字节后 EOF -> 不足 8 字节不解析
|
||||
* TC-TS-027 30s 预算耗尽 -> 留痕 "no TIME packet in 30s, drop conn"
|
||||
* TC-TS-028 剩余预算不足一片 -> 末片按剩余(20ms)切分
|
||||
* TC-TS-029 32 位 tick 回绕 -> 预算计算仍正确
|
||||
* TC-TIMESYNC-020 8 字节一次收齐 -> 大端解析 epoch + 更新墙钟 + 关连接
|
||||
* TC-TIMESYNC-021 分段送达(4+4)-> 累积后解析;第二次只请求剩余 12 字节
|
||||
* TC-TIMESYNC-022 一次到达 16 字节 -> 只取前 8 字节
|
||||
* TC-TIMESYNC-023 前缀非 "TIME" -> 不更新墙钟,但仍关连接
|
||||
* TC-TIMESYNC-024 对端关闭(n==0)-> 立即退出、不解析
|
||||
* TC-TIMESYNC-025 真错误(n==-1)-> 立即退出、不解析
|
||||
* TC-TIMESYNC-026 只收到 4 字节后 EOF -> 不足 8 字节不解析
|
||||
* TC-TIMESYNC-027 30s 预算耗尽 -> 留痕 "no TIME packet in 30s, drop conn"
|
||||
* TC-TIMESYNC-028 剩余预算不足一片 -> 末片按剩余(20ms)切分
|
||||
* TC-TIMESYNC-029 32 位 tick 回绕 -> 预算计算仍正确
|
||||
* —— time_sync_task(任务主循环)——
|
||||
* TC-TS-040 sys_evtHandle==NULL:跳过就绪屏障;accept 轮询->成功->处理->收尾
|
||||
* TC-TS-041 就绪屏障:100ms 分片等待 NET_READY(osFlagsNoClear 不消费就绪位)
|
||||
* TC-TS-042 屏障未就绪期间持续喂心跳(2026-10-02 台架根因的回归防线)
|
||||
* TC-TS-043 网络代次变化 -> 关闭旧监听并重监听
|
||||
* TC-TS-044 监听建立失败 -> 5 次重试后放弃并退避 2000ms
|
||||
* TC-TIMESYNC-040 sys_evtHandle==NULL:跳过就绪屏障;accept 轮询->成功->处理->收尾
|
||||
* TC-TIMESYNC-041 就绪屏障:100ms 分片等待 NET_READY(osFlagsNoClear 不消费就绪位)
|
||||
* TC-TIMESYNC-042 屏障未就绪期间持续喂心跳(2026-10-02 台架根因的回归防线)
|
||||
* TC-TIMESYNC-043 网络代次变化 -> 关闭旧监听并重监听
|
||||
* TC-TIMESYNC-044 监听建立失败 -> 5 次重试后放弃并退避 2000ms
|
||||
*
|
||||
* 通过:全部 TC PASS(main 返回 0)。
|
||||
* 入口:int main(void),返回 0=PASS / 1=FAIL(由 run 脚本判读)。
|
||||
@@ -413,51 +413,51 @@ static int delays_all(uint32_t v, int n) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ===================== TC-TS-001..006:delay_fed ===================== */
|
||||
/* ===================== TC-TIMESYNC-001..006:delay_fed ===================== */
|
||||
|
||||
static void tc_delay_fed(void) {
|
||||
fakes_reset();
|
||||
time_sync_delay_fed(0U);
|
||||
CHECK((s_beat_calls == 0) && (s_delay_calls == 0), "TC-TS-001 delay_fed(0) 不睡眠不喂狗");
|
||||
CHECK((s_beat_calls == 0) && (s_delay_calls == 0), "TC-TIMESYNC-001 delay_fed(0) 不睡眠不喂狗");
|
||||
|
||||
fakes_reset();
|
||||
time_sync_delay_fed(50U);
|
||||
CHECK((s_beat_calls == 1) && (s_delay_calls == 1) && (s_delays[0] == 50U),
|
||||
"TC-TS-002 delay_fed(50) = 1 片 50ms + 1 次心跳");
|
||||
"TC-TIMESYNC-002 delay_fed(50) = 1 片 50ms + 1 次心跳");
|
||||
|
||||
fakes_reset();
|
||||
time_sync_delay_fed(120U);
|
||||
CHECK((s_beat_calls == 3) && (s_delay_calls == 3), "TC-TS-003 delay_fed(120) 切成 3 片");
|
||||
CHECK((s_beat_calls == 3) && (s_delay_calls == 3), "TC-TIMESYNC-003 delay_fed(120) 切成 3 片");
|
||||
CHECK((s_delays[0] == 50U) && (s_delays[1] == 50U) && (s_delays[2] == 20U),
|
||||
"TC-TS-003b 片长 50/50/20(末片为余数)");
|
||||
"TC-TIMESYNC-003b 片长 50/50/20(末片为余数)");
|
||||
|
||||
fakes_reset();
|
||||
time_sync_delay_fed(2000U);
|
||||
CHECK((s_delay_calls == 40) && (s_beat_calls == 40) && delays_all(50U, 40),
|
||||
"TC-TS-004 delay_fed(2000) = 40 片 × 50ms,每片喂一次心跳");
|
||||
"TC-TIMESYNC-004 delay_fed(2000) = 40 片 × 50ms,每片喂一次心跳");
|
||||
|
||||
fakes_reset();
|
||||
time_sync_delay_fed(49U);
|
||||
CHECK((s_beat_calls == 1) && (s_delays[0] == 49U), "TC-TS-005 不足一片(49ms)单片处理");
|
||||
CHECK((s_beat_calls == 1) && (s_delays[0] == 49U), "TC-TIMESYNC-005 不足一片(49ms)单片处理");
|
||||
|
||||
fakes_reset();
|
||||
time_sync_delay_fed(30000U);
|
||||
CHECK(s_delay_calls == 600, "TC-TS-006 总预算 30s = 600 片(片长上限恒 50ms)");
|
||||
CHECK(s_delay_calls == 600, "TC-TIMESYNC-006 总预算 30s = 600 片(片长上限恒 50ms)");
|
||||
}
|
||||
|
||||
/* ===================== TC-TS-010..015:open_listener ===================== */
|
||||
/* ===================== TC-TIMESYNC-010..015:open_listener ===================== */
|
||||
|
||||
static void tc_open_listener(void) {
|
||||
fakes_reset();
|
||||
{
|
||||
int s = time_sync_open_listener();
|
||||
CHECK(s == 5, "TC-TS-010 open_listener 成功返回 socket 描述符");
|
||||
CHECK(s == 5, "TC-TIMESYNC-010 open_listener 成功返回 socket 描述符");
|
||||
CHECK((s_socket_calls == 1) && (s_bind_calls == 1) && (s_listen_calls == 1),
|
||||
"TC-TS-010b socket / bind / listen 各一次");
|
||||
CHECK(s_htons_last == (uint16_t)TIME_SYNC_PORT, "TC-TS-010c 端口经 net_htons(8888)");
|
||||
CHECK(s_bind_port == net_htons((uint16_t)TIME_SYNC_PORT), "TC-TS-010d sin_port 为网络序");
|
||||
CHECK(s_bind_family == (uint16_t)NET_AF_INET, "TC-TS-010e sin_family = NET_AF_INET");
|
||||
CHECK(s_delay_calls == 0, "TC-TS-010f 成功路径无退避延时");
|
||||
"TC-TIMESYNC-010b socket / bind / listen 各一次");
|
||||
CHECK(s_htons_last == (uint16_t)TIME_SYNC_PORT, "TC-TIMESYNC-010c 端口经 net_htons(8888)");
|
||||
CHECK(s_bind_port == net_htons((uint16_t)TIME_SYNC_PORT), "TC-TIMESYNC-010d sin_port 为网络序");
|
||||
CHECK(s_bind_family == (uint16_t)NET_AF_INET, "TC-TIMESYNC-010e sin_family = NET_AF_INET");
|
||||
CHECK(s_delay_calls == 0, "TC-TIMESYNC-010f 成功路径无退避延时");
|
||||
}
|
||||
|
||||
fakes_reset();
|
||||
@@ -465,10 +465,10 @@ static void tc_open_listener(void) {
|
||||
s_bind_seq_n = 1;
|
||||
{
|
||||
int s = time_sync_open_listener();
|
||||
CHECK(s == 5, "TC-TS-011 bind 失败一次后重试成功");
|
||||
CHECK((s_close_calls == 1) && (s_close_socks[0] == 5), "TC-TS-011b bind 失败关闭该 socket");
|
||||
CHECK(s_delay_calls == 40, "TC-TS-011c bind 失败退避 2000ms(40 片)");
|
||||
CHECK(g_tstest_err_count == 1, "TC-TS-011d bind 失败留痕 DBG_ERROR");
|
||||
CHECK(s == 5, "TC-TIMESYNC-011 bind 失败一次后重试成功");
|
||||
CHECK((s_close_calls == 1) && (s_close_socks[0] == 5), "TC-TIMESYNC-011b bind 失败关闭该 socket");
|
||||
CHECK(s_delay_calls == 40, "TC-TIMESYNC-011c bind 失败退避 2000ms(40 片)");
|
||||
CHECK(g_tstest_err_count == 1, "TC-TIMESYNC-011d bind 失败留痕 DBG_ERROR");
|
||||
}
|
||||
|
||||
fakes_reset();
|
||||
@@ -476,19 +476,19 @@ static void tc_open_listener(void) {
|
||||
s_listen_seq_n = 1;
|
||||
{
|
||||
int s = time_sync_open_listener();
|
||||
CHECK(s == 5, "TC-TS-012 listen 失败一次后重试成功");
|
||||
CHECK((s_close_calls == 1) && (s_close_socks[0] == 5), "TC-TS-012b listen 失败关闭该 socket");
|
||||
CHECK(s_delay_calls == 40, "TC-TS-012c listen 失败退避 2000ms");
|
||||
CHECK(s == 5, "TC-TIMESYNC-012 listen 失败一次后重试成功");
|
||||
CHECK((s_close_calls == 1) && (s_close_socks[0] == 5), "TC-TIMESYNC-012b listen 失败关闭该 socket");
|
||||
CHECK(s_delay_calls == 40, "TC-TIMESYNC-012c listen 失败退避 2000ms");
|
||||
}
|
||||
|
||||
fakes_reset();
|
||||
s_socket_default = -1;
|
||||
{
|
||||
int s = time_sync_open_listener();
|
||||
CHECK(s == -1, "TC-TS-013 socket 连续失败 -> 返回 -1");
|
||||
CHECK(s_socket_calls == 5, "TC-TS-013b 重试上限 5 次");
|
||||
CHECK(g_tstest_err_count == 5, "TC-TS-013c 每次失败各留痕一条(5 条 DBG_ERROR)");
|
||||
CHECK(s_delay_calls == 50, "TC-TS-013d 每次失败退避 500ms(5 × 10 片)");
|
||||
CHECK(s == -1, "TC-TIMESYNC-013 socket 连续失败 -> 返回 -1");
|
||||
CHECK(s_socket_calls == 5, "TC-TIMESYNC-013b 重试上限 5 次");
|
||||
CHECK(g_tstest_err_count == 5, "TC-TIMESYNC-013c 每次失败各留痕一条(5 条 DBG_ERROR)");
|
||||
CHECK(s_delay_calls == 50, "TC-TIMESYNC-013d 每次失败退避 500ms(5 × 10 片)");
|
||||
}
|
||||
|
||||
fakes_reset();
|
||||
@@ -498,23 +498,23 @@ static void tc_open_listener(void) {
|
||||
s_socket_seq_n = 3;
|
||||
{
|
||||
int s = time_sync_open_listener();
|
||||
CHECK(s == 9, "TC-TS-014 第 3 次重试成功并返回新描述符");
|
||||
CHECK(s_socket_calls == 3, "TC-TS-014b 恰好尝试 3 次");
|
||||
CHECK(s_delay_calls == 20, "TC-TS-014c 两次失败退避 500ms × 2");
|
||||
CHECK(s == 9, "TC-TIMESYNC-014 第 3 次重试成功并返回新描述符");
|
||||
CHECK(s_socket_calls == 3, "TC-TIMESYNC-014b 恰好尝试 3 次");
|
||||
CHECK(s_delay_calls == 20, "TC-TIMESYNC-014c 两次失败退避 500ms × 2");
|
||||
}
|
||||
|
||||
fakes_reset();
|
||||
s_socket_default = -1;
|
||||
(void)time_sync_open_listener();
|
||||
CHECK(s_beat_calls == 55, "TC-TS-015 每轮重试(5) + 每片延时(50) 各喂一次心跳");
|
||||
CHECK(s_beat_id_bad == 0, "TC-TS-015b 心跳位恒为 TASK_WD_TIMESYNC");
|
||||
CHECK(s_beat_calls == 55, "TC-TIMESYNC-015 每轮重试(5) + 每片延时(50) 各喂一次心跳");
|
||||
CHECK(s_beat_id_bad == 0, "TC-TIMESYNC-015b 心跳位恒为 TASK_WD_TIMESYNC");
|
||||
}
|
||||
|
||||
/* ===================== TC-TS-020..029:handle_conn =====================
|
||||
/* ===================== TC-TIMESYNC-020..029:handle_conn =====================
|
||||
* ⚠ 契约变更:handle_conn **不再** net_close
|
||||
* (单连接模式下 conn==listen,close 会连监听一起毁);会话收尾只返回外层,
|
||||
* 由 time_sync_task 在 `conn != ls`(模拟器多连接后端)时才关数据 fd。
|
||||
* 故本组断言一律为 s_close_calls == 0;任务级关闭见 TC-TS-040e。 */
|
||||
* 故本组断言一律为 s_close_calls == 0;任务级关闭见 TC-TIMESYNC-040e。 */
|
||||
|
||||
static void tc_handle_conn(void) {
|
||||
uint8_t pkt[16];
|
||||
@@ -526,13 +526,13 @@ static void tc_handle_conn(void) {
|
||||
s_recv_seq_n = 1;
|
||||
s_tick = 100U;
|
||||
time_sync_handle_conn(7);
|
||||
CHECK(s_set_unix_calls == 1, "TC-TS-020 TIME 包一次收齐 -> 更新墙钟一次");
|
||||
CHECK(s_set_unix_last == 0x12345678u, "TC-TS-020b epoch 按大端解析");
|
||||
CHECK((s_recv_calls == 1) && (s_recv_len_log[0] == 16), "TC-TS-020c 首次请求 16 字节");
|
||||
CHECK(s_recv_to_log[0] == 50U, "TC-TS-020d 单次等待片长 = 50ms");
|
||||
CHECK(s_close_calls == 0, "TC-TS-020e 处理完**不**关闭连接(close 交外层 conn!=ls 分支)");
|
||||
CHECK(s_drop_calls == 0, "TC-TS-020g 成功会话不拆(drop 只用于放弃路径)");
|
||||
CHECK(g_tstest_info_count == 1, "TC-TS-020f 留痕 wall clock updated");
|
||||
CHECK(s_set_unix_calls == 1, "TC-TIMESYNC-020 TIME 包一次收齐 -> 更新墙钟一次");
|
||||
CHECK(s_set_unix_last == 0x12345678u, "TC-TIMESYNC-020b epoch 按大端解析");
|
||||
CHECK((s_recv_calls == 1) && (s_recv_len_log[0] == 16), "TC-TIMESYNC-020c 首次请求 16 字节");
|
||||
CHECK(s_recv_to_log[0] == 50U, "TC-TIMESYNC-020d 单次等待片长 = 50ms");
|
||||
CHECK(s_close_calls == 0, "TC-TIMESYNC-020e 处理完**不**关闭连接(close 交外层 conn!=ls 分支)");
|
||||
CHECK(s_drop_calls == 0, "TC-TIMESYNC-020g 成功会话不拆(drop 只用于放弃路径)");
|
||||
CHECK(g_tstest_info_count == 1, "TC-TIMESYNC-020f 留痕 wall clock updated");
|
||||
|
||||
/* 2) 分段送达:4 + 4 */
|
||||
fakes_reset();
|
||||
@@ -541,11 +541,11 @@ static void tc_handle_conn(void) {
|
||||
recv_set(1, 4, pkt + 4, 4, 10U);
|
||||
s_recv_seq_n = 2;
|
||||
time_sync_handle_conn(3);
|
||||
CHECK((s_set_unix_calls == 1) && (s_set_unix_last == 10u), "TC-TS-021 分段送达累积后解析正确");
|
||||
CHECK(s_recv_calls == 2, "TC-TS-021b 读了两次");
|
||||
CHECK((s_set_unix_calls == 1) && (s_set_unix_last == 10u), "TC-TIMESYNC-021 分段送达累积后解析正确");
|
||||
CHECK(s_recv_calls == 2, "TC-TIMESYNC-021b 读了两次");
|
||||
CHECK((s_recv_len_log[0] == 16) && (s_recv_len_log[1] == 12),
|
||||
"TC-TS-021c 第二次只请求剩余 12 字节");
|
||||
CHECK((s_recv_to_log[0] == 50U) && (s_recv_to_log[1] == 50U), "TC-TS-021d 每片 50ms(预算充裕)");
|
||||
"TC-TIMESYNC-021c 第二次只请求剩余 12 字节");
|
||||
CHECK((s_recv_to_log[0] == 50U) && (s_recv_to_log[1] == 50U), "TC-TIMESYNC-021d 每片 50ms(预算充裕)");
|
||||
|
||||
/* 3) 16 字节一次到达(只取前 8) */
|
||||
fakes_reset();
|
||||
@@ -553,8 +553,8 @@ static void tc_handle_conn(void) {
|
||||
recv_set(0, 16, pkt, 16, 0U);
|
||||
s_recv_seq_n = 1;
|
||||
time_sync_handle_conn(4);
|
||||
CHECK((s_set_unix_calls == 1) && (s_set_unix_last == 5u), "TC-TS-022 超长包只取前 8 字节");
|
||||
CHECK(s_recv_calls == 1, "TC-TS-022b 一次读够即停");
|
||||
CHECK((s_set_unix_calls == 1) && (s_set_unix_last == 5u), "TC-TIMESYNC-022 超长包只取前 8 字节");
|
||||
CHECK(s_recv_calls == 1, "TC-TIMESYNC-022b 一次读够即停");
|
||||
|
||||
/* 4) 前缀不是 TIME */
|
||||
fakes_reset();
|
||||
@@ -569,23 +569,23 @@ static void tc_handle_conn(void) {
|
||||
recv_set(0, 8, pkt, 8, 0U);
|
||||
s_recv_seq_n = 1;
|
||||
time_sync_handle_conn(4);
|
||||
CHECK(s_set_unix_calls == 0, "TC-TS-023 非 TIME 前缀不更新墙钟");
|
||||
CHECK(s_close_calls == 0, "TC-TS-023b 非 TIME 前缀也不关闭连接");
|
||||
CHECK(s_set_unix_calls == 0, "TC-TIMESYNC-023 非 TIME 前缀不更新墙钟");
|
||||
CHECK(s_close_calls == 0, "TC-TIMESYNC-023b 非 TIME 前缀也不关闭连接");
|
||||
|
||||
/* 5) 对端关闭(EOF) */
|
||||
fakes_reset();
|
||||
recv_set(0, 0, NULL, 0, 0U);
|
||||
s_recv_seq_n = 1;
|
||||
time_sync_handle_conn(6);
|
||||
CHECK((s_set_unix_calls == 0) && (s_recv_calls == 1), "TC-TS-024 对端关闭(EOF)立即退出不解析");
|
||||
CHECK(s_close_calls == 0, "TC-TS-024b EOF 也不关闭连接(net 层 auto_relisten 收口监听)");
|
||||
CHECK((s_set_unix_calls == 0) && (s_recv_calls == 1), "TC-TIMESYNC-024 对端关闭(EOF)立即退出不解析");
|
||||
CHECK(s_close_calls == 0, "TC-TIMESYNC-024b EOF 也不关闭连接(net 层 auto_relisten 收口监听)");
|
||||
|
||||
/* 6) 真错误 */
|
||||
fakes_reset();
|
||||
recv_set(0, -1, NULL, 0, 0U);
|
||||
s_recv_seq_n = 1;
|
||||
time_sync_handle_conn(6);
|
||||
CHECK((s_recv_calls == 1) && (s_set_unix_calls == 0), "TC-TS-025 真错误立即退出不解析");
|
||||
CHECK((s_recv_calls == 1) && (s_set_unix_calls == 0), "TC-TIMESYNC-025 真错误立即退出不解析");
|
||||
|
||||
/* 7) 4 字节后 EOF */
|
||||
fakes_reset();
|
||||
@@ -594,27 +594,27 @@ static void tc_handle_conn(void) {
|
||||
recv_set(1, 0, NULL, 0, 0U);
|
||||
s_recv_seq_n = 2;
|
||||
time_sync_handle_conn(6);
|
||||
CHECK(s_set_unix_calls == 0, "TC-TS-026 不足 8 字节不解析");
|
||||
CHECK(s_recv_calls == 2, "TC-TS-026b 继续等待后续字节");
|
||||
CHECK(s_set_unix_calls == 0, "TC-TIMESYNC-026 不足 8 字节不解析");
|
||||
CHECK(s_recv_calls == 2, "TC-TIMESYNC-026b 继续等待后续字节");
|
||||
|
||||
/* 8) 30s 预算耗尽 */
|
||||
fakes_reset();
|
||||
recv_set(0, -2, NULL, 0, 30000U);
|
||||
s_recv_seq_n = 1;
|
||||
time_sync_handle_conn(6);
|
||||
CHECK(s_recv_calls == 1, "TC-TS-027 预算耗尽后不再读(只读 1 次)");
|
||||
CHECK(g_tstest_info_count == 1, "TC-TS-027b 留痕 no TIME packet in 30s, drop conn");
|
||||
CHECK(s_close_calls == 0, "TC-TS-027c 预算耗尽也不关闭连接");
|
||||
CHECK(s_drop_calls == 1, "TC-TS-027d 预算耗尽主动拆会话(E-02 收口:net_drop_conn 拆连接保监听)");
|
||||
CHECK(s_recv_calls == 1, "TC-TIMESYNC-027 预算耗尽后不再读(只读 1 次)");
|
||||
CHECK(g_tstest_info_count == 1, "TC-TIMESYNC-027b 留痕 no TIME packet in 30s, drop conn");
|
||||
CHECK(s_close_calls == 0, "TC-TIMESYNC-027c 预算耗尽也不关闭连接");
|
||||
CHECK(s_drop_calls == 1, "TC-TIMESYNC-027d 预算耗尽主动拆会话(E-02 收口:net_drop_conn 拆连接保监听)");
|
||||
|
||||
/* 9) 剩余预算不足一片 */
|
||||
fakes_reset();
|
||||
recv_set(0, -2, NULL, 0, 29980U);
|
||||
s_recv_seq_n = 1;
|
||||
time_sync_handle_conn(6);
|
||||
CHECK(s_recv_calls == 2, "TC-TS-028 两次等待后结束");
|
||||
CHECK(s_recv_calls == 2, "TC-TIMESYNC-028 两次等待后结束");
|
||||
CHECK((s_recv_to_log[0] == 50U) && (s_recv_to_log[1] == 20U),
|
||||
"TC-TS-028b 第二次片长 = 剩余 20ms");
|
||||
"TC-TIMESYNC-028b 第二次片长 = 剩余 20ms");
|
||||
|
||||
/* 10) 32 位 tick 回绕 */
|
||||
fakes_reset();
|
||||
@@ -623,10 +623,10 @@ static void tc_handle_conn(void) {
|
||||
s_recv_seq_n = 1;
|
||||
time_sync_handle_conn(6);
|
||||
CHECK((s_recv_calls == 2) && (s_recv_to_log[0] == 50U) && (s_recv_to_log[1] == 50U),
|
||||
"TC-TS-029 32 位 tick 回绕后预算计算仍正确");
|
||||
"TC-TIMESYNC-029 32 位 tick 回绕后预算计算仍正确");
|
||||
}
|
||||
|
||||
/* ===================== TC-TS-040..044:time_sync_task ===================== */
|
||||
/* ===================== TC-TIMESYNC-040..044:time_sync_task ===================== */
|
||||
|
||||
static void tc_task(void) {
|
||||
uint8_t pkt[16];
|
||||
@@ -646,15 +646,15 @@ static void tc_task(void) {
|
||||
time_sync_task(NULL);
|
||||
}
|
||||
CHECK((s_wd_bind_calls == 1) && (s_wd_bind_id_bad == 0),
|
||||
"TC-TS-040 任务入口登记心跳位(task_wd_bind 一次)");
|
||||
CHECK(s_evt_calls == 0, "TC-TS-040b sys_evtHandle==NULL 时跳过就绪屏障");
|
||||
CHECK(s_accept_calls == 3, "TC-TS-040c accept 轮询 3 次(2 次无连接 + 1 次成功)");
|
||||
CHECK((s_set_unix_calls == 1) && (s_set_unix_last == 9u), "TC-TS-040d 收到时间包并更新墙钟");
|
||||
CHECK(s_close_calls == 1, "TC-TS-040e 连接被关闭一次");
|
||||
CHECK(s_delay_calls == 9, "TC-TS-040f 延时片数 = 4+4+1(200+200+50ms)");
|
||||
CHECK(delays_all(50U, 9), "TC-TS-040g 所有延时均按 50ms 分片");
|
||||
CHECK(s_beat_calls == 13, "TC-TS-040h 心跳次数 = 主循环1 + 退避8 + 收连接1 + 收尾1 + 次轮1");
|
||||
CHECK(s_beat_id_bad == 0, "TC-TS-040i 所有心跳均打 TIMESYNC 位");
|
||||
"TC-TIMESYNC-040 任务入口登记心跳位(task_wd_bind 一次)");
|
||||
CHECK(s_evt_calls == 0, "TC-TIMESYNC-040b sys_evtHandle==NULL 时跳过就绪屏障");
|
||||
CHECK(s_accept_calls == 3, "TC-TIMESYNC-040c accept 轮询 3 次(2 次无连接 + 1 次成功)");
|
||||
CHECK((s_set_unix_calls == 1) && (s_set_unix_last == 9u), "TC-TIMESYNC-040d 收到时间包并更新墙钟");
|
||||
CHECK(s_close_calls == 1, "TC-TIMESYNC-040e 连接被关闭一次");
|
||||
CHECK(s_delay_calls == 9, "TC-TIMESYNC-040f 延时片数 = 4+4+1(200+200+50ms)");
|
||||
CHECK(delays_all(50U, 9), "TC-TIMESYNC-040g 所有延时均按 50ms 分片");
|
||||
CHECK(s_beat_calls == 13, "TC-TIMESYNC-040h 心跳次数 = 主循环1 + 退避8 + 收连接1 + 收尾1 + 次轮1");
|
||||
CHECK(s_beat_id_bad == 0, "TC-TIMESYNC-040i 所有心跳均打 TIMESYNC 位");
|
||||
|
||||
/* B) 就绪屏障:2 次未就绪 + 1 次就绪 */
|
||||
fakes_reset();
|
||||
@@ -667,12 +667,12 @@ static void tc_task(void) {
|
||||
if (setjmp(s_jmp) == 0) {
|
||||
time_sync_task(NULL);
|
||||
}
|
||||
CHECK(s_evt_calls == 3, "TC-TS-041 就绪屏障轮询 3 次(2 次未就绪 + 1 次就绪)");
|
||||
CHECK(s_evt_last_timeout == 100U, "TC-TS-041b 屏障等待按 100ms 分片");
|
||||
CHECK(s_evt_last_flags == SYS_EVT_NET_READY, "TC-TS-041c 等待 NET_READY 位");
|
||||
CHECK(s_evt_last_options == (osFlagsWaitAny | osFlagsNoClear), "TC-TS-041d 就绪位不被消费");
|
||||
CHECK(s_beat_calls == 3, "TC-TS-041e 未就绪的两次各喂一次心跳(+主循环 1 次)");
|
||||
CHECK(s_wd_bind_calls == 1, "TC-TS-041f 仍先登记心跳路由");
|
||||
CHECK(s_evt_calls == 3, "TC-TIMESYNC-041 就绪屏障轮询 3 次(2 次未就绪 + 1 次就绪)");
|
||||
CHECK(s_evt_last_timeout == 100U, "TC-TIMESYNC-041b 屏障等待按 100ms 分片");
|
||||
CHECK(s_evt_last_flags == SYS_EVT_NET_READY, "TC-TIMESYNC-041c 等待 NET_READY 位");
|
||||
CHECK(s_evt_last_options == (osFlagsWaitAny | osFlagsNoClear), "TC-TIMESYNC-041d 就绪位不被消费");
|
||||
CHECK(s_beat_calls == 3, "TC-TIMESYNC-041e 未就绪的两次各喂一次心跳(+主循环 1 次)");
|
||||
CHECK(s_wd_bind_calls == 1, "TC-TIMESYNC-041f 仍先登记心跳路由");
|
||||
|
||||
/* C) 屏障期间持续喂心跳(就绪位长期不置位) */
|
||||
fakes_reset();
|
||||
@@ -682,8 +682,8 @@ static void tc_task(void) {
|
||||
if (setjmp(s_jmp) == 0) {
|
||||
time_sync_task(NULL);
|
||||
}
|
||||
CHECK(s_evt_calls == 4, "TC-TS-042 屏障等待 4 次均未就绪(循环未挂死)");
|
||||
CHECK(s_beat_calls == 3, "TC-TS-042b 每次未就绪后各喂一次心跳(第 4 次跳出前)");
|
||||
CHECK(s_evt_calls == 4, "TC-TIMESYNC-042 屏障等待 4 次均未就绪(循环未挂死)");
|
||||
CHECK(s_beat_calls == 3, "TC-TIMESYNC-042b 每次未就绪后各喂一次心跳(第 4 次跳出前)");
|
||||
|
||||
/* D) 网络代次变化 -> 关闭旧监听并重监听 */
|
||||
fakes_reset();
|
||||
@@ -695,12 +695,12 @@ static void tc_task(void) {
|
||||
if (setjmp(s_jmp) == 0) {
|
||||
time_sync_task(NULL);
|
||||
}
|
||||
CHECK((s_close_calls == 1) && (s_close_socks[0] == 5), "TC-TS-043 代次变化时关闭旧监听");
|
||||
CHECK((s_close_calls == 1) && (s_close_socks[0] == 5), "TC-TIMESYNC-043 代次变化时关闭旧监听");
|
||||
/* INFO 三条:两次 open_listener 成功各一条 "TCP listen on" + 一条 "network re-init, relisten" */
|
||||
CHECK(g_tstest_info_count == 3, "TC-TS-043b 留痕 network re-init, relisten(另含 2 条 listen 成功)");
|
||||
CHECK(s_accept_calls == 2, "TC-TS-043c 每次循环只轮询一次 accept 即放弃");
|
||||
CHECK(g_tstest_info_count == 3, "TC-TIMESYNC-043b 留痕 network re-init, relisten(另含 2 条 listen 成功)");
|
||||
CHECK(s_accept_calls == 2, "TC-TIMESYNC-043c 每次循环只轮询一次 accept 即放弃");
|
||||
CHECK((s_socket_calls == 2) && (s_bind_calls == 2) && (s_listen_calls == 2),
|
||||
"TC-TS-043d 第二次循环重建了监听");
|
||||
"TC-TIMESYNC-043d 第二次循环重建了监听");
|
||||
|
||||
/* E) 监听建立失败 -> 5 次重试后放弃并退避 2000ms */
|
||||
fakes_reset();
|
||||
@@ -709,11 +709,11 @@ static void tc_task(void) {
|
||||
if (setjmp(s_jmp) == 0) {
|
||||
time_sync_task(NULL);
|
||||
}
|
||||
CHECK(s_socket_calls == 5, "TC-TS-044 open_listener 内部重试 5 次后放弃");
|
||||
CHECK(g_tstest_err_count == 6, "TC-TS-044b 5 条 net_socket FAIL + 1 条 retry later");
|
||||
CHECK(s_delay_calls == 90, "TC-TS-044c 退避 5×500ms + 2000ms = 90 片");
|
||||
CHECK(s_beat_calls == 97, "TC-TS-044d 心跳次数 = 2 + 5 + 50 + 40");
|
||||
CHECK(s_beat_id_bad == 0, "TC-TS-044e 所有心跳均打 TIMESYNC 位");
|
||||
CHECK(s_socket_calls == 5, "TC-TIMESYNC-044 open_listener 内部重试 5 次后放弃");
|
||||
CHECK(g_tstest_err_count == 6, "TC-TIMESYNC-044b 5 条 net_socket FAIL + 1 条 retry later");
|
||||
CHECK(s_delay_calls == 90, "TC-TIMESYNC-044c 退避 5×500ms + 2000ms = 90 片");
|
||||
CHECK(s_beat_calls == 97, "TC-TIMESYNC-044d 心跳次数 = 2 + 5 + 50 + 40");
|
||||
CHECK(s_beat_id_bad == 0, "TC-TIMESYNC-044e 所有心跳均打 TIMESYNC 位");
|
||||
}
|
||||
|
||||
/* ===================== main ===================== */
|
||||
|
||||
@@ -16,20 +16,20 @@
|
||||
* 3. 不占 MCU 的 RAM,毫秒级完成。
|
||||
*
|
||||
* 覆盖点:
|
||||
* TC-VL-001 init 首次调用创建互斥量并返回 0
|
||||
* TC-VL-002 init 幂等(重复调用不再创建)
|
||||
* TC-VL-003 init 在 osMutexNew 失败时返回 -1
|
||||
* TC-VL-004 init 失败后可重试成功(s_lock 未被污染)
|
||||
* TC-VL-005 wait 成功后返回 1,且把 timeout 原样透传给 osMutexWait
|
||||
* TC-VL-006 wait 超时(osMutexWait != osOK)返回 0
|
||||
* TC-VL-007 wait 在锁未创建时自动 init,再正常获取
|
||||
* TC-VL-008 ⭐ fail-open:锁未创建且创建失败 -> 返回 1 且**不调用** osMutexWait
|
||||
* TC-VL-009 fail-open 之后 release 无害(s_lock 仍为 NULL,不调用 osMutexRelease)
|
||||
* TC-VL-010 已创建时 wait 不再调用 osMutexNew
|
||||
* TC-VL-011 release 在已持锁时调用 osMutexRelease 一次
|
||||
* TC-VL-012 release 在锁未创建时静默返回(不崩溃、不调用)
|
||||
* TC-VL-013 完整周期 init -> wait -> release -> wait -> release
|
||||
* TC-VL-014 wait(0) 的 timeout 透传为 0(defaultTask 的 try 语义)
|
||||
* TC-VOLLOCK-001 init 首次调用创建互斥量并返回 0
|
||||
* TC-VOLLOCK-002 init 幂等(重复调用不再创建)
|
||||
* TC-VOLLOCK-003 init 在 osMutexNew 失败时返回 -1
|
||||
* TC-VOLLOCK-004 init 失败后可重试成功(s_lock 未被污染)
|
||||
* TC-VOLLOCK-005 wait 成功后返回 1,且把 timeout 原样透传给 osMutexWait
|
||||
* TC-VOLLOCK-006 wait 超时(osMutexWait != osOK)返回 0
|
||||
* TC-VOLLOCK-007 wait 在锁未创建时自动 init,再正常获取
|
||||
* TC-VOLLOCK-008 ⭐ fail-open:锁未创建且创建失败 -> 返回 1 且**不调用** osMutexWait
|
||||
* TC-VOLLOCK-009 fail-open 之后 release 无害(s_lock 仍为 NULL,不调用 osMutexRelease)
|
||||
* TC-VOLLOCK-010 已创建时 wait 不再调用 osMutexNew
|
||||
* TC-VOLLOCK-011 release 在已持锁时调用 osMutexRelease 一次
|
||||
* TC-VOLLOCK-012 release 在锁未创建时静默返回(不崩溃、不调用)
|
||||
* TC-VOLLOCK-013 完整周期 init -> wait -> release -> wait -> release
|
||||
* TC-VOLLOCK-014 wait(0) 的 timeout 透传为 0(defaultTask 的 try 语义)
|
||||
*
|
||||
* 通过:全部 TC PASS(main 返回 0)。
|
||||
* 入口:int main(void),返回 0=PASS / 1=FAIL(由 run 脚本判读)。
|
||||
@@ -110,76 +110,76 @@ static void fakes_reset(void) {
|
||||
s_lock = NULL;
|
||||
}
|
||||
|
||||
/* ===================== TC-VL-001..004:vol_lock_init ===================== */
|
||||
/* ===================== TC-VOLLOCK-001..004:vol_lock_init ===================== */
|
||||
|
||||
static void tc_init(void) {
|
||||
fakes_reset();
|
||||
CHECK(vol_lock_init() == 0, "TC-VL-001 init 首次调用返回 0");
|
||||
CHECK(s_new_calls == 1, "TC-VL-001b init 创建互斥量一次(osMutexNew)");
|
||||
CHECK(s_lock != NULL, "TC-VL-001c 模块静态态已持有句柄");
|
||||
CHECK(vol_lock_init() == 0, "TC-VOLLOCK-001 init 首次调用返回 0");
|
||||
CHECK(s_new_calls == 1, "TC-VOLLOCK-001b init 创建互斥量一次(osMutexNew)");
|
||||
CHECK(s_lock != NULL, "TC-VOLLOCK-001c 模块静态态已持有句柄");
|
||||
|
||||
CHECK(vol_lock_init() == 0, "TC-VL-002 init 重复调用仍返回 0(幂等)");
|
||||
CHECK(s_new_calls == 1, "TC-VL-002b 幂等:不再创建第二个互斥量");
|
||||
CHECK(vol_lock_init() == 0, "TC-VOLLOCK-002 init 重复调用仍返回 0(幂等)");
|
||||
CHECK(s_new_calls == 1, "TC-VOLLOCK-002b 幂等:不再创建第二个互斥量");
|
||||
|
||||
fakes_reset();
|
||||
s_new_fail = 1;
|
||||
CHECK(vol_lock_init() == -1, "TC-VL-003 osMutexNew 失败 -> init 返回 -1");
|
||||
CHECK(s_lock == NULL, "TC-VL-003b 失败时不留下半初始化句柄");
|
||||
CHECK(vol_lock_init() == -1, "TC-VOLLOCK-003 osMutexNew 失败 -> init 返回 -1");
|
||||
CHECK(s_lock == NULL, "TC-VOLLOCK-003b 失败时不留下半初始化句柄");
|
||||
|
||||
s_new_fail = 0;
|
||||
CHECK(vol_lock_init() == 0, "TC-VL-004 失败后重试可成功(返回 0)");
|
||||
CHECK(s_new_calls == 2, "TC-VL-004b 重试确实再次调用 osMutexNew");
|
||||
CHECK(vol_lock_init() == 0, "TC-VOLLOCK-004 失败后重试可成功(返回 0)");
|
||||
CHECK(s_new_calls == 2, "TC-VOLLOCK-004b 重试确实再次调用 osMutexNew");
|
||||
}
|
||||
|
||||
/* ===================== TC-VL-005..010:vol_lock_wait ===================== */
|
||||
/* ===================== TC-VOLLOCK-005..010:vol_lock_wait ===================== */
|
||||
|
||||
static void tc_wait(void) {
|
||||
/* --- 已创建:超时值原样透传 --- */
|
||||
fakes_reset();
|
||||
(void)vol_lock_init();
|
||||
CHECK(vol_lock_wait(100U) == 1, "TC-VL-005 wait 获取成功返回 1");
|
||||
CHECK(s_wait_calls == 1, "TC-VL-005b osMutexWait 被调用一次");
|
||||
CHECK(s_last_timeout == 100U, "TC-VL-005c timeout 原样透传给 osMutexWait");
|
||||
CHECK(vol_lock_wait(100U) == 1, "TC-VOLLOCK-005 wait 获取成功返回 1");
|
||||
CHECK(s_wait_calls == 1, "TC-VOLLOCK-005b osMutexWait 被调用一次");
|
||||
CHECK(s_last_timeout == 100U, "TC-VOLLOCK-005c timeout 原样透传给 osMutexWait");
|
||||
|
||||
fakes_reset();
|
||||
(void)vol_lock_init();
|
||||
CHECK(vol_lock_wait(0U) == 1, "TC-VL-014 wait(0) 获取成功返回 1(try 语义)");
|
||||
CHECK(s_last_timeout == 0U, "TC-VL-014b wait(0) 的 timeout 透传为 0");
|
||||
CHECK(vol_lock_wait(0U) == 1, "TC-VOLLOCK-014 wait(0) 获取成功返回 1(try 语义)");
|
||||
CHECK(s_last_timeout == 0U, "TC-VOLLOCK-014b wait(0) 的 timeout 透传为 0");
|
||||
|
||||
/* --- 超时:osMutexWait != osOK -> 返回 0 --- */
|
||||
fakes_reset();
|
||||
(void)vol_lock_init();
|
||||
s_wait_ok = 0;
|
||||
CHECK(vol_lock_wait(50U) == 0, "TC-VL-006 osMutexWait 非 osOK -> wait 返回 0");
|
||||
CHECK(s_wait_calls == 1, "TC-VL-006b 超时路径确实尝试过等待");
|
||||
CHECK(vol_lock_wait(50U) == 0, "TC-VOLLOCK-006 osMutexWait 非 osOK -> wait 返回 0");
|
||||
CHECK(s_wait_calls == 1, "TC-VOLLOCK-006b 超时路径确实尝试过等待");
|
||||
|
||||
/* --- 锁未创建:自动 init 后正常获取 --- */
|
||||
fakes_reset();
|
||||
CHECK(vol_lock_wait(10U) == 1, "TC-VL-007 锁未创建时 wait 自动 init 并获取");
|
||||
CHECK(s_new_calls == 1, "TC-VL-007b 自动 init 创建了互斥量");
|
||||
CHECK(s_wait_calls == 1, "TC-VL-007c 随后执行了一次等待");
|
||||
CHECK(vol_lock_wait(10U) == 1, "TC-VOLLOCK-007 锁未创建时 wait 自动 init 并获取");
|
||||
CHECK(s_new_calls == 1, "TC-VOLLOCK-007b 自动 init 创建了互斥量");
|
||||
CHECK(s_wait_calls == 1, "TC-VOLLOCK-007c 随后执行了一次等待");
|
||||
|
||||
/* --- ⭐ fail-open:创建失败必须返回 1 且绝不阻塞 --- */
|
||||
fakes_reset();
|
||||
s_new_fail = 1;
|
||||
CHECK(vol_lock_wait(0U) == 1, "TC-VL-008 fail-open:锁创建失败仍返回 1(不阻塞喂狗点)");
|
||||
CHECK(s_wait_calls == 0, "TC-VL-008b fail-open 时**不调用** osMutexWait(零阻塞)");
|
||||
CHECK(s_lock == NULL, "TC-VL-008c fail-open 后仍无句柄");
|
||||
CHECK(vol_lock_wait(0U) == 1, "TC-VOLLOCK-008 fail-open:锁创建失败仍返回 1(不阻塞喂狗点)");
|
||||
CHECK(s_wait_calls == 0, "TC-VOLLOCK-008b fail-open 时**不调用** osMutexWait(零阻塞)");
|
||||
CHECK(s_lock == NULL, "TC-VOLLOCK-008c fail-open 后仍无句柄");
|
||||
|
||||
/* --- fail-open 之后 release 无害 --- */
|
||||
vol_lock_release();
|
||||
CHECK(s_release_calls == 0, "TC-VL-009 fail-open 后 release 不调用 osMutexRelease(判空静默)");
|
||||
CHECK(s_release_calls == 0, "TC-VOLLOCK-009 fail-open 后 release 不调用 osMutexRelease(判空静默)");
|
||||
|
||||
/* --- 已创建时 wait 不再创建 --- */
|
||||
fakes_reset();
|
||||
(void)vol_lock_init();
|
||||
(void)vol_lock_wait(0U);
|
||||
(void)vol_lock_wait(0U);
|
||||
CHECK(s_new_calls == 1, "TC-VL-010 多次 wait 不重复创建互斥量");
|
||||
CHECK(s_wait_calls == 2, "TC-VL-010b 每次 wait 各等待一次");
|
||||
CHECK(s_new_calls == 1, "TC-VOLLOCK-010 多次 wait 不重复创建互斥量");
|
||||
CHECK(s_wait_calls == 2, "TC-VOLLOCK-010b 每次 wait 各等待一次");
|
||||
}
|
||||
|
||||
/* ===================== TC-VL-011..013:vol_lock_release ===================== */
|
||||
/* ===================== TC-VOLLOCK-011..013:vol_lock_release ===================== */
|
||||
|
||||
static void tc_release(void) {
|
||||
/* --- 已持锁:释放一次 --- */
|
||||
@@ -187,23 +187,23 @@ static void tc_release(void) {
|
||||
(void)vol_lock_init();
|
||||
(void)vol_lock_wait(0U);
|
||||
vol_lock_release();
|
||||
CHECK(s_release_calls == 1, "TC-VL-011 已持锁时 release 调用 osMutexRelease 一次");
|
||||
CHECK(s_release_calls == 1, "TC-VOLLOCK-011 已持锁时 release 调用 osMutexRelease 一次");
|
||||
|
||||
/* --- 锁未创建:静默返回 --- */
|
||||
fakes_reset();
|
||||
vol_lock_release();
|
||||
CHECK(s_release_calls == 0, "TC-VL-012 锁未创建时 release 静默返回(不调用、不崩溃)");
|
||||
CHECK(s_release_calls == 0, "TC-VOLLOCK-012 锁未创建时 release 静默返回(不调用、不崩溃)");
|
||||
|
||||
/* --- 完整周期 --- */
|
||||
fakes_reset();
|
||||
CHECK(vol_lock_init() == 0, "TC-VL-013 周期:init -> 0");
|
||||
CHECK(vol_lock_wait(0U) == 1, "TC-VL-013b 周期:wait -> 1");
|
||||
CHECK(vol_lock_init() == 0, "TC-VOLLOCK-013 周期:init -> 0");
|
||||
CHECK(vol_lock_wait(0U) == 1, "TC-VOLLOCK-013b 周期:wait -> 1");
|
||||
vol_lock_release();
|
||||
CHECK(vol_lock_wait(100U) == 1, "TC-VL-013c 周期:再 wait -> 1(可重复获取)");
|
||||
CHECK(vol_lock_wait(100U) == 1, "TC-VOLLOCK-013c 周期:再 wait -> 1(可重复获取)");
|
||||
vol_lock_release();
|
||||
CHECK(s_new_calls == 1, "TC-VL-013d 周期:全程只创建一次互斥量");
|
||||
CHECK(s_release_calls == 2, "TC-VL-013e 周期:释放两次");
|
||||
CHECK(s_last_timeout == 100U, "TC-VL-013f 周期:第二次 wait 的 timeout 透传正确");
|
||||
CHECK(s_new_calls == 1, "TC-VOLLOCK-013d 周期:全程只创建一次互斥量");
|
||||
CHECK(s_release_calls == 2, "TC-VOLLOCK-013e 周期:释放两次");
|
||||
CHECK(s_last_timeout == 100U, "TC-VOLLOCK-013f 周期:第二次 wait 的 timeout 透传正确");
|
||||
}
|
||||
|
||||
/* ===================== main ===================== */
|
||||
|
||||
@@ -11,19 +11,19 @@
|
||||
* 把模块静态态恢复到"刚上电"。
|
||||
*
|
||||
* 覆盖点(对应 docs/测试说明/看门狗单元测试说明.md 的 TC-WD-xxx):
|
||||
* TC-WD-001 未启动时 poll 不做任何判定(也不喂狗)
|
||||
* TC-WD-002 节流:< 100ms 的 poll 直接返回
|
||||
* TC-WD-003 全员到位置位 → 喂狗一次,且位图取走清零
|
||||
* TC-WD-004 取走清零语义:旧位不残留(下一轮必须重新置位)
|
||||
* TC-WD-005 掩码判定:缺任一位不喂,last_mask 精确记录
|
||||
* TC-WD-006 连续 1..7 次缺席不喂不报;第 8 次打 [WD] task stall
|
||||
* TC-WD-007 停喂后 stall 日志持续复报(现状行为,见用例内说明)
|
||||
* TC-WD-008 恢复:重新全员到位 → 喂狗 + streak 归零
|
||||
* TC-WD-009 节流窗口边界 99/100/199/200
|
||||
* TC-WD-010 tick 回绕安全(无符号差)
|
||||
* TC-WD-011 观测接口:last_mask / is_armed
|
||||
* TC-WD-013 非法任务 ID 被忽略(防位图越界)
|
||||
* TC-WD-014 start 幂等
|
||||
* TC-WATCHDOG-001 未启动时 poll 不做任何判定(也不喂狗)
|
||||
* TC-WATCHDOG-002 节流:< 100ms 的 poll 直接返回
|
||||
* TC-WATCHDOG-003 全员到位置位 → 喂狗一次,且位图取走清零
|
||||
* TC-WATCHDOG-004 取走清零语义:旧位不残留(下一轮必须重新置位)
|
||||
* TC-WATCHDOG-005 掩码判定:缺任一位不喂,last_mask 精确记录
|
||||
* TC-WATCHDOG-006 连续 1..7 次缺席不喂不报;第 8 次打 [WD] task stall
|
||||
* TC-WATCHDOG-007 停喂后 stall 日志持续复报(现状行为,见用例内说明)
|
||||
* TC-WATCHDOG-008 恢复:重新全员到位 → 喂狗 + streak 归零
|
||||
* TC-WATCHDOG-009 节流窗口边界 99/100/199/200
|
||||
* TC-WATCHDOG-010 tick 回绕安全(无符号差)
|
||||
* TC-WATCHDOG-011 观测接口:last_mask / is_armed
|
||||
* TC-WATCHDOG-013 非法任务 ID 被忽略(防位图越界)
|
||||
* TC-WATCHDOG-014 start 幂等
|
||||
*
|
||||
* 通过:全部 TC PASS(main 返回 0)。
|
||||
* 入口:int main(void),返回 0=PASS / 1=FAIL(由 run 脚本判读)。
|
||||
@@ -108,7 +108,7 @@ static void poll_advance(uint32_t ms) {
|
||||
|
||||
/*
|
||||
* 启动并清空喂狗计数:task_wd_start() 内部会先喂一次(让首个抽样窗口从启动
|
||||
* 时刻起算,见生产代码注释),该次喂狗由 TC-WD-015 单独断言;其余用例只关心
|
||||
* 时刻起算,见生产代码注释),该次喂狗由 TC-WATCHDOG-015 单独断言;其余用例只关心
|
||||
* "启动之后 poll 的喂狗行为",故此处把计数归零。
|
||||
*/
|
||||
static void start_and_clear(void) {
|
||||
@@ -131,7 +131,7 @@ static void beat_all(void) {
|
||||
/* ===================== 用例 ===================== */
|
||||
|
||||
static void tc_001_not_armed(void) {
|
||||
printf("TC-WD-001 未启动时 poll 不做判定\n");
|
||||
printf("TC-WATCHDOG-001 未启动时 poll 不做判定\n");
|
||||
beat_all();
|
||||
poll_advance(1000);
|
||||
CHECK(s_feed_count == 0, "未启动时 poll 不喂狗");
|
||||
@@ -139,7 +139,7 @@ static void tc_001_not_armed(void) {
|
||||
}
|
||||
|
||||
static void tc_002_throttle(void) {
|
||||
printf("TC-WD-002 节流:< 100ms 直接返回\n");
|
||||
printf("TC-WATCHDOG-002 节流:< 100ms 直接返回\n");
|
||||
start_and_clear();
|
||||
beat_all();
|
||||
poll_advance(50); /* 50ms < 100ms → 不抽样 */
|
||||
@@ -149,7 +149,7 @@ static void tc_002_throttle(void) {
|
||||
}
|
||||
|
||||
static void tc_003_all_beat_feeds(void) {
|
||||
printf("TC-WD-003 全员到位 → 喂狗一次\n");
|
||||
printf("TC-WATCHDOG-003 全员到位 → 喂狗一次\n");
|
||||
start_and_clear();
|
||||
beat_all();
|
||||
poll_advance(100);
|
||||
@@ -158,7 +158,7 @@ static void tc_003_all_beat_feeds(void) {
|
||||
}
|
||||
|
||||
static void tc_004_take_and_clear(void) {
|
||||
printf("TC-WD-004 取走清零:旧位不残留\n");
|
||||
printf("TC-WATCHDOG-004 取走清零:旧位不残留\n");
|
||||
start_and_clear();
|
||||
beat_all();
|
||||
poll_advance(100); /* 消费位图并喂狗 */
|
||||
@@ -168,7 +168,7 @@ static void tc_004_take_and_clear(void) {
|
||||
}
|
||||
|
||||
static void tc_005_mask_required(void) {
|
||||
printf("TC-WD-005 掩码判定:缺任一位不喂\n");
|
||||
printf("TC-WATCHDOG-005 掩码判定:缺任一位不喂\n");
|
||||
start_and_clear();
|
||||
/* 故意缺 UI(bit4) */
|
||||
task_wd_beat(TASK_WD_DEFAULT);
|
||||
@@ -185,7 +185,7 @@ static void tc_005_mask_required(void) {
|
||||
}
|
||||
|
||||
static void tc_006_stall_8(void) {
|
||||
printf("TC-WD-006 连续 8 次缺席 → 打 stall 并停喂\n");
|
||||
printf("TC-WATCHDOG-006 连续 8 次缺席 → 打 stall 并停喂\n");
|
||||
start_and_clear();
|
||||
beat_all(); poll_advance(100); /* streak 清零 */
|
||||
int err0 = g_wdtest_err_count;
|
||||
@@ -199,7 +199,7 @@ static void tc_006_stall_8(void) {
|
||||
}
|
||||
|
||||
static void tc_007_stall_repeats_until_reset(void) {
|
||||
printf("TC-WD-007 停喂后 stall 日志持续复报(当前设计:每 100ms 一条)\n");
|
||||
printf("TC-WATCHDOG-007 停喂后 stall 日志持续复报(当前设计:每 100ms 一条)\n");
|
||||
start_and_clear();
|
||||
for (int i = 0; i < 8; i++) poll_advance(100); /* 第 8 次触发 */
|
||||
int err8 = g_wdtest_err_count;
|
||||
@@ -217,7 +217,7 @@ static void tc_007_stall_repeats_until_reset(void) {
|
||||
}
|
||||
|
||||
static void tc_008_recover(void) {
|
||||
printf("TC-WD-008 恢复:重新全员到位 → 喂狗 + streak 归零\n");
|
||||
printf("TC-WATCHDOG-008 恢复:重新全员到位 → 喂狗 + streak 归零\n");
|
||||
start_and_clear();
|
||||
for (int i = 0; i < 8; i++) poll_advance(100); /* 触发 stall */
|
||||
beat_all();
|
||||
@@ -229,7 +229,7 @@ static void tc_008_recover(void) {
|
||||
}
|
||||
|
||||
static void tc_009_throttle_boundary(void) {
|
||||
printf("TC-WD-009 节流窗口边界 99/100/199/200\n");
|
||||
printf("TC-WATCHDOG-009 节流窗口边界 99/100/199/200\n");
|
||||
start_and_clear();
|
||||
beat_all();
|
||||
poll_advance(99); CHECK(s_feed_count == 0, "99ms 不判");
|
||||
@@ -240,7 +240,7 @@ static void tc_009_throttle_boundary(void) {
|
||||
}
|
||||
|
||||
static void tc_010_tick_wrap(void) {
|
||||
printf("TC-WD-010 tick 回绕安全\n");
|
||||
printf("TC-WATCHDOG-010 tick 回绕安全\n");
|
||||
start_and_clear();
|
||||
s_tick = 0xFFFFFF00u; /* 推到接近 2^32 回绕 */
|
||||
task_wd_poll(); /* 建立基线(此处可能不判,取决节流) */
|
||||
@@ -251,7 +251,7 @@ static void tc_010_tick_wrap(void) {
|
||||
}
|
||||
|
||||
static void tc_011_observers(void) {
|
||||
printf("TC-WD-011 观测接口语义\n");
|
||||
printf("TC-WATCHDOG-011 观测接口语义\n");
|
||||
start_and_clear();
|
||||
CHECK(task_wd_is_armed() == 1, "is_armed == 1(已启动)");
|
||||
beat_all();
|
||||
@@ -261,7 +261,7 @@ static void tc_011_observers(void) {
|
||||
}
|
||||
|
||||
static void tc_013_bad_id(void) {
|
||||
printf("TC-WD-013 非法任务 ID 被忽略\n");
|
||||
printf("TC-WATCHDOG-013 非法任务 ID 被忽略\n");
|
||||
start_and_clear();
|
||||
task_wd_beat((task_wd_id_t)(TASK_WD_ID_MAX + 3)); /* 非法:应被忽略 */
|
||||
poll_advance(100);
|
||||
@@ -270,7 +270,7 @@ static void tc_013_bad_id(void) {
|
||||
}
|
||||
|
||||
static void tc_014_start_idempotent(void) {
|
||||
printf("TC-WD-014 start 幂等\n");
|
||||
printf("TC-WATCHDOG-014 start 幂等\n");
|
||||
task_wd_start();
|
||||
task_wd_start();
|
||||
CHECK(s_start_count == 1, "重复 start 只启动 IWDG 一次");
|
||||
@@ -278,14 +278,14 @@ static void tc_014_start_idempotent(void) {
|
||||
}
|
||||
|
||||
static void tc_015_start_feeds_once(void) {
|
||||
printf("TC-WD-015 start 先喂一次(首个窗口从启动时刻起算)\n");
|
||||
printf("TC-WATCHDOG-015 start 先喂一次(首个窗口从启动时刻起算)\n");
|
||||
task_wd_start();
|
||||
CHECK(s_start_count == 1, "start 启动 IWDG 一次");
|
||||
CHECK(s_feed_count == 1, "start 内部先喂狗一次(避免启动即超时)");
|
||||
}
|
||||
|
||||
static void tc_016_stall_not_armed_no_feed(void) {
|
||||
printf("TC-WD-016 未启动时即便全员到位也不喂\n");
|
||||
printf("TC-WATCHDOG-016 未启动时即便全员到位也不喂\n");
|
||||
/* 未 start:poll 直接返回 */
|
||||
beat_all();
|
||||
poll_advance(500);
|
||||
|
||||
Reference in New Issue
Block a user