@@ -0,0 +1,475 @@
/*
* 模块名称:量纲回归主机侧单测(「数据可信」卡 7 · 道A)
* 被测对象:真实源文件(#include 原样纳入,全链路 L1.5→L2→L3):
* adc_cal.c + prot_set.c + sample_ring.c + phasor.c + freq.c +
* prot_elm.c
* 平台依赖桩:dbg_log.h( stub/)、cfg_file_register(捕获计数)、
* adc_input_desc( V0.1 权威来源表,同 adc_cal 套件)。
*
* 本卡的存在理由(短板评测 + 「数据可信」§2.2):台架此前"通过"是因为没有
* 一条判据检查**不该动作时不动作**——"码值当工程量"的错配曾让 OC 拿 ~11000
* 码值比 10 A 定值恒假动作。本套件把这条固化成回归:用例从 **ADC 码值** 出发、
* **显式写出码值↔二次值换算**,走真实 折算→采样环→全周傅氏→元件判据 链;
* 任何一环把量纲弄丢(比如折算点被旁路),断言立刻翻转。
*
* ROM 系数覆写(#undef/#define):把"板级理论系数"替换为合成端子侧口径
* ( 10 mV/码,K_DIM),模拟卡 12 标定完成后的 ROM/默认状态——合法带随之
* 锚定合成值,adc_cal_set 走正规路径置 VALID,测试不白盒改引擎内存。
*
* 覆盖点(族 TC-HOST-PROTDIM,属主登记处 = 本目录):
* TC-PROTDIM-001 标定链基线:0.5 A/100 V/0 V 注入 → 七类元件全静默(含
* OL: 0.5 < 1 A 定值)+ IA 相量有效值 = 0.5 A ±0.5 %
* TC-PROTDIM-002 反错配对照:同一批码值,raw 直灌 → OC1 假动作(复现历史
* 事故);经 adc_cal_apply → OC1 静默(折算点不可旁路)
* TC-PROTDIM-003 OC1( 10 A, dly=0):9.995 不动作 / 10.5 启动即动作 /
* 9.6 滞回保持 / 9.49 释放
* TC-PROTDIM-004 OC2( 5 A, 500 ms):6 A 启动,启动后 499 ms 不动作、
* 501 ms 动作;4.8 保持(ret 4.75)、4.6 释放
* TC-PROTDIM-005 OC3( 2 A, 3000 ms):同上时序(2.1 A)
* TC-PROTDIM-006 OL( 1 A, 10 s):1.05 A 启动、9999/10001 ms 时序、
* 0.96 保持(ret 0.95)、0.93 释放
* TC-PROTDIM-007 OV( 120 V, 10 s):100 V 静默;121 V 启动、到点动作;
* 115 保持(ret 114)、113 释放
* TC-PROTDIM-008 UV( 20 V, 10 s,欠量方向):21 V 静默;19.9 V 启动、
* 到点动作;20.5 保持(ret 21)、21.6 释放
* TC-PROTDIM-009 3U0( 15 V, 5 s):14 V 静默;15.1 启动到点;
* 14.4 保持(ret 14.25)、14.1 释放
* TC-PROTDIM-010 聚合与独立性:OC1+OV 同拍动作位图 = 双位;撤 IA →
* OC1 返回、OV 保持(互不污染)
*
* 通过:全部 TC PASS( main 返回 0)。
* 创建日期:2026-10-25(道A 卡 7)
*/
# include <math.h>
# include <stdint.h>
# include <stdio.h>
# include <string.h>
/* 桩头先于生产源码 */
# include "dbg_log.h"
int g_dimtest_err_count = 0 ;
int g_dimtest_info_count = 0 ;
int g_dimtest_debug_count = 0 ;
# include "cfg_file.h"
static int s_reg_count = 0 ;
int cfg_file_register ( const cfg_section_reg_t * p_reg ) {
( void ) p_reg ;
s_reg_count + + ;
return 0 ;
}
/* V0.1 权威来源表(docs/硬件平台/ADC通道映射说明.md §3/§5,同 adc_cal 套件桩) */
# include "adc_input.h"
static const adc_channel_desc_t s_desc_stub [ ADC_SEM_COUNT ] = {
{ ADC_SRC_TPAFE , 6u } , { ADC_SRC_STM32 , 14u } , { ADC_SRC_STM32 , 3u } ,
{ ADC_SRC_TPAFE , 5u } , { ADC_SRC_TPAFE , 2u } , { ADC_SRC_STM32 , 6u } ,
{ ADC_SRC_STM32 , 1u } , { ADC_SRC_STM32 , 2u } , { ADC_SRC_STM32 , 5u } ,
} ;
const adc_channel_desc_t * adc_input_desc ( adc_semantic_t ch ) {
if ( ( unsigned ) ch > = ( unsigned ) ADC_SEM_COUNT ) {
return NULL ;
}
return & s_desc_stub [ ( unsigned ) ch ] ;
}
/* ---- 测试框架(同 prot_elm 套件) ---- */
static int s_total = 0 , s_passed = 0 , s_failed = 0 ;
# define CHECK(cond, name) do { \
s_total++; \
if (cond) { s_passed++; printf(" [PASS] %s\n", name); } \
else { s_failed++; printf(" [FAIL] %s (line %d)\n", name, __LINE__); } \
} while (0)
/* ---- 合成"标定后"板级口径(覆写 adc_cal.h 的 ROM 常量,必须在纳入 .c 之前) ----
* K_DIM = 655360000 Q16 = 10000 µV/码 = 10 mV/码:
* 电压类 100 V rms → 峰值 141.42 V → 14142 码(TPAFE 半量程内,量级刻意
* 贴近卡 12 端子变比标定后的真实形态);电流类二次值经变换器落到同一定标。
* B_IA = -30 码(零点偏移,经 apply 精确对消——验证 b 参与全链而非仅落盘)。 */
# include "adc_cal.h"
# undef ADC_CAL_K_Q16_TPAFE
# undef ADC_CAL_K_Q16_STM32
# define ADC_CAL_K_Q16_TPAFE (655360000L)
# define ADC_CAL_K_Q16_STM32 (655360000L)
# define K_DIM ADC_CAL_K_Q16_TPAFE
# define B_IA_DIM (-30L)
/* ===================== 被测生产源文件 ===================== */
# include "prot_set.c"
# include "sample_ring.c"
# include "phasor.c"
# include "freq.c"
# include "prot_elm.c"
# include "adc_cal.c"
/* ===================== 波形/时基(同 prot_elm 套件 run() 级用例口径) ===================== */
static uint32_t s_t = 0u ;
static long my_lround ( double x ) { return ( long ) ( ( x > = 0.0 ) ? ( x + 0.5 ) : ( x - 0.5 ) ) ; }
/* 显式换算(卡 7 的核心手法,两处方向都要有):
* code = round(eng[V 或 A] × 65536× 1e6 / k_q16) − b (期望 → 码值)
* eng = (code + b) × k_q16 / 65536 / 1e6 = adc_cal_apply (码值 → 工程量)
* 上面两式必须互逆——若实现(adc_cal_apply)与期望推导脱钩,全部 TC 翻转。 */
static int32_t dim_code ( double eng , double b_codes ) {
return ( int32_t ) ( my_lround ( eng * 65536.0e6 / ( double ) K_DIM ) - b_codes ) ;
}
/* 一拍:三相量按 50 Hz 正弦(峰值 = rms×√2),其余电气量通道给 0 码值,
* TEMP 透传 0;随后跑真实 L2 链。 */
static void dim_beat ( double ia_rms , double ua_rms , double un_rms ) {
float frame [ ADC_SEM_COUNT ] ;
double s50 = sin ( 2.0 * 3.14159265358979 * 50.0 * ( double ) s_t / 1000.0 ) ;
int32_t ci_ia , ci_ua , ci_un ;
uint8_t c ;
ci_ia = dim_code ( ia_rms * 1.4142135623730951 * s50 , ( double ) B_IA_DIM ) ;
ci_ua = dim_code ( ua_rms * 1.4142135623730951 * s50 , 0.0 ) ;
ci_un = dim_code ( un_rms * 1.4142135623730951 * s50 , 0.0 ) ;
frame [ ADC_SEM_IA ] = adc_cal_apply ( ADC_SEM_IA , ci_ia ) ;
frame [ ADC_SEM_UA ] = adc_cal_apply ( ADC_SEM_UA , ci_ua ) ;
frame [ ADC_SEM_UN ] = adc_cal_apply ( ADC_SEM_UN , ci_un ) ;
for ( c = 0u ; c < ( uint8_t ) ADC_SEM_COUNT ; c + + ) {
if ( ( c ! = ( uint8_t ) ADC_SEM_IA ) & & ( c ! = ( uint8_t ) ADC_SEM_UA ) & &
( c ! = ( uint8_t ) ADC_SEM_UN ) ) {
frame [ c ] = adc_cal_apply ( ( adc_semantic_t ) c , 0L ) ;
}
}
( void ) sample_ring_push_frame ( frame , ( uint8_t ) ADC_SEM_COUNT ) ;
phasor_run ( ) ;
freq_run ( ) ;
prot_elm_run ( s_t ) ;
s_t + + ;
}
/* TC 起手:定值/元件全复位 + 标定注入(set 正规路径)+ 中性 45 拍收敛 */
static void dim_setup ( void ) {
prot_set_init ( ) ;
adc_cal_init ( ) ;
( void ) adc_cal_set ( ADC_SEM_UA , K_DIM , 0L ) ;
( void ) adc_cal_set ( ADC_SEM_UN , K_DIM , 0L ) ;
( void ) adc_cal_set ( ADC_SEM_IA , K_DIM , B_IA_DIM ) ;
prot_elm_init ( ) ;
}
static void set_en ( prot_set_id_t id , int on ) {
( void ) prot_set_set ( id , PROT_SET_Q10 ( on ? 1.0 : 0.0 ) ) ;
}
/* 只留一个电气量元件家族:默认全 EN=1,逐个关到只剩目标 */
static void isolate_oc_family ( void ) {
set_en ( PS_OC1_EN , 1 ) ; set_en ( PS_OC2_EN , 0 ) ; set_en ( PS_OC3_EN , 0 ) ;
set_en ( PS_OL_EN , 0 ) ; set_en ( PS_OV_EN , 0 ) ; set_en ( PS_UV_EN , 0 ) ;
set_en ( PS_3U0_EN , 0 ) ;
}
static int pick_of ( prot_elm_id_t e ) {
prot_elm_state_t st ;
prot_elm_state ( e , & st ) ;
return ( st . picked ! = 0u ) ? 1 : 0 ;
}
static int assert_of ( prot_elm_id_t e ) {
prot_elm_state_t st ;
prot_elm_state ( e , & st ) ;
return ( st . asserted ! = 0u ) ? 1 : 0 ;
}
/* 把 IA 拉到 far_below 收敛 45 拍(确保 picked 干净归零、t0 无效) */
static void settle_oc ( double ia_rms , uint32_t beats ) {
uint32_t i ;
for ( i = 0u ; i < beats ; i + + ) { dim_beat ( ia_rms , 100.0 , 0.0 ) ; }
}
/* ===================== TC-PROTDIM-001 标定链基线 ===================== */
static void tc_001_baseline ( void ) {
phasor_t p ;
double want_rms ;
double got ;
uint32_t i ;
int quiet = 1 ;
printf ( " [TC-PROTDIM-001] calibrated chain baseline: no element moves \n " ) ;
dim_setup ( ) ;
for ( i = 0u ; i < 60u ; i + + ) { dim_beat ( 0.5 , 100.0 , 0.0 ) ; }
/* 换算链可验证:C01-IA( idx0)有效值 = 注入 0.5 A ±0.5 %
* ( b=-30 码应被 apply 精确对消;若折算丢失,这里会是 ~700 量级码值) */
want_rms = 0.5 ;
CHECK ( phasor_get ( 0u , & p ) = = 0 , " 001: C01-IA phasor ready " ) ;
got = ( double ) p . fAmSQ ;
CHECK ( ( got > want_rms * 0.995 ) & & ( got < want_rms * 1.005 ) ,
" 001: IA rms = 0.5 A (secondary domain, b cancelled) " ) ;
for ( i = 0u ; i < ( uint32_t ) PE_OC1 ; i + + ) {
if ( ( pick_of ( ( prot_elm_id_t ) i ) ! = 0 ) | | ( assert_of ( ( prot_elm_id_t ) i ) ! = 0 ) ) {
quiet = 0 ;
}
}
CHECK ( quiet , " 001: OC1/OC2/OC3/OL/OV/UV/3U0 all silent at 0.5A/100V/0V " ) ;
CHECK ( prot_elm_active_mask ( ) = = 0u , " 001: active mask 0 " ) ;
}
/* ===================== TC-PROTDIM-002 反错配对照 ===================== */
static void tc_002_mismatch_trap ( void ) {
float raw [ ADC_SEM_COUNT ] ;
uint32_t i ;
printf ( " [TC-PROTDIM-002] raw-codes-as-engineering trap / apply guard \n " ) ;
dim_setup ( ) ;
isolate_oc_family ( ) ;
set_en ( PS_OC2_EN , 0 ) ;
/* (a) 复现历史事故:把"码值本身"当工程量灌环(等价于折算点被旁路)。
* 3.36 A 物理电流的码值 ~672 → 比 OC1(10 A) → 必假动作 */
for ( i = 0u ; i < ( uint32_t ) ADC_SEM_COUNT ; i + + ) {
raw [ i ] = 0.0f ;
}
for ( i = 0u ; i < 45u ; i + + ) {
double s50 = sin ( 2.0 * 3.14159265358979 * 50.0 * ( double ) s_t / 1000.0 ) ;
raw [ ADC_SEM_IA ] = ( float ) ( ( double ) dim_code ( 3.36 * 1.4142135623730951 * s50 ,
( double ) B_IA_DIM ) ) ;
( void ) sample_ring_push_frame ( raw , ( uint8_t ) ADC_SEM_COUNT ) ;
phasor_run ( ) ;
prot_elm_run ( s_t ) ;
s_t + + ;
}
CHECK ( ( pick_of ( PE_OC1 ) ! = 0 ) & & ( assert_of ( PE_OC1 ) ! = 0 ) ,
" 002a: raw code domain falsely trips OC1 (documents the incident) " ) ;
/* (b) 同一物理量经正规折算链:3.36 A < 10 A → 必须静默。
* (若生产链有人绕过 adc_cal_apply,本断言与 001 一起翻红) */
for ( i = 0u ; i < 45u ; i + + ) { dim_beat ( 3.36 , 100.0 , 0.0 ) ; }
CHECK ( ( pick_of ( PE_OC1 ) = = 0 ) & & ( assert_of ( PE_OC1 ) = = 0 ) ,
" 002b: same physical current via apply() stays silent " ) ;
}
/* ===================== TC-PROTDIM-003 OC1:滞回 + dly0 ===================== */
static void tc_003_oc1 ( void ) {
printf ( " [TC-PROTDIM-003] OC1 10A/dly0 hysteresis \n " ) ;
dim_setup ( ) ;
isolate_oc_family ( ) ;
settle_oc ( 3.0 , 45u ) ;
settle_oc ( 9.995 , 45u ) ;
CHECK ( pick_of ( PE_OC1 ) = = 0 , " 003: 9.995 A below set: no pickup " ) ;
settle_oc ( 10.5 , 45u ) ;
CHECK ( ( pick_of ( PE_OC1 ) ! = 0 ) & & ( assert_of ( PE_OC1 ) ! = 0 ) ,
" 003: 10.5 A -> picked AND asserted (dly=0 same-beat) " ) ;
settle_oc ( 9.6 , 45u ) ;
CHECK ( ( pick_of ( PE_OC1 ) ! = 0 ) & & ( assert_of ( PE_OC1 ) ! = 0 ) ,
" 003: 9.6 A inside hysteresis (ret=9.5): holds " ) ;
settle_oc ( 9.49 , 45u ) ;
CHECK ( ( pick_of ( PE_OC1 ) = = 0 ) & & ( assert_of ( PE_OC1 ) = = 0 ) ,
" 003: 9.49 A below return threshold: drops out " ) ;
}
/* 过量定时限通用核:启动拍受控(先远低收敛),到点前后各验一次 */
static void timed_over_case ( prot_elm_id_t e , prot_set_id_t cur_id , double trip ,
double hold , double drop , float dly_ms ,
const char * tag ) {
uint32_t t_pick = 0u ;
uint32_t i ;
uint32_t settle ;
char nm [ 96 ] ;
int pre_ok = 1 , post_ok = 0 , hold_ok = 0 , drop_ok = 0 , trip_ok = 0 ;
( void ) cur_id ;
( void ) tag ;
/* 1) 远低收敛;2) 阶跃到 trip,逐拍轮询到 picked(记录启动拍) */
for ( i = 0u ; i < 45u ; i + + ) { dim_beat ( 0.1 * trip , 100.0 , 0.0 ) ; }
for ( i = 0u ; i < 400u ; i + + ) {
dim_beat ( trip , 100.0 , 0.0 ) ;
if ( pick_of ( e ) ! = 0 ) { t_pick = s_t - 1u ; trip_ok = 1 ; break ; }
}
if ( trip_ok = = 0 ) {
( void ) snprintf ( nm , sizeof ( nm ) , " %s: step to trip level picks up " , tag ) ;
CHECK ( 0 , nm ) ;
return ;
}
/* 3) 到点前 2 ms 不许动作、到点后 2 ms 必须动作(同幅值持续注入) */
settle = 0u ;
for ( i = t_pick ; i < ( t_pick + ( uint32_t ) dly_ms - 2u ) ; i + + ) {
dim_beat ( trip , 100.0 , 0.0 ) ;
settle + + ;
}
( void ) settle ;
if ( assert_of ( e ) ! = 0 ) { pre_ok = 0 ; }
for ( i = 0u ; i < 5u ; i + + ) { dim_beat ( trip , 100.0 , 0.0 ) ; }
post_ok = assert_of ( e ) ;
( void ) snprintf ( nm , sizeof ( nm ) , " %s: no assert before setpoint-2ms " , tag ) ;
CHECK ( pre_ok ! = 0 & & post_ok ! = 0 , nm ) ;
/* 4) 返回系数滞回带内保持、跌破释放 */
for ( i = 0u ; i < 45u ; i + + ) { dim_beat ( hold , 100.0 , 0.0 ) ; }
hold_ok = ( pick_of ( e ) ! = 0 ) & & ( assert_of ( e ) ! = 0 ) ;
for ( i = 0u ; i < 45u ; i + + ) { dim_beat ( drop , 100.0 , 0.0 ) ; }
drop_ok = ( pick_of ( e ) = = 0 ) & & ( assert_of ( e ) = = 0 ) ;
( void ) snprintf ( nm , sizeof ( nm ) , " %s: holds inside return band " , tag ) ;
CHECK ( hold_ok ! = 0 , nm ) ;
( void ) snprintf ( nm , sizeof ( nm ) , " %s: returns below return threshold " , tag ) ;
CHECK ( drop_ok ! = 0 , nm ) ;
}
/* ===================== TC-PROTDIM-004~006 OC2/OC3/OL ===================== */
static void tc_004_oc2 ( void ) {
printf ( " [TC-PROTDIM-004] OC2 5A/500ms timed+return \n " ) ;
dim_setup ( ) ;
isolate_oc_family ( ) ;
set_en ( PS_OC2_EN , 1 ) ;
timed_over_case ( PE_OC2 , PS_OC2_CUR , 6.0 , 4.8 , 4.6 , 500.0f , " 004:OC2 " ) ;
}
static void tc_005_oc3 ( void ) {
printf ( " [TC-PROTDIM-005] OC3 2A/3000ms timed+return \n " ) ;
dim_setup ( ) ;
isolate_oc_family ( ) ;
set_en ( PS_OC3_EN , 1 ) ;
timed_over_case ( PE_OC3 , PS_OC3_CUR , 2.1 , 1.95 , 1.89 , 3000.0f , " 005:OC3 " ) ;
}
static void tc_006_ol ( void ) {
printf ( " [TC-PROTDIM-006] OL 1A/10s timed+return \n " ) ;
dim_setup ( ) ;
isolate_oc_family ( ) ;
set_en ( PS_OL_EN , 1 ) ;
timed_over_case ( PE_OL , PS_OL_CUR , 1.05 , 0.96 , 0.93 , 10000.0f , " 006:OL " ) ;
}
/* ===================== TC-PROTDIM-007 OV(电压域走 UA) ===================== */
static void tc_007_ov ( void ) {
uint32_t t_pick = 0u ;
uint32_t i ;
int ok ;
printf ( " [TC-PROTDIM-007] OV 120V/10s (UA secondary domain) \n " ) ;
dim_setup ( ) ;
isolate_oc_family ( ) ;
set_en ( PS_OV_EN , 1 ) ;
for ( i = 0u ; i < 45u ; i + + ) { dim_beat ( 0.0 , 100.0 , 0.0 ) ; }
CHECK ( pick_of ( PE_OV ) = = 0 , " 007: nominal 100 V silent " ) ;
for ( i = 0u ; i < 400u ; i + + ) {
dim_beat ( 0.0 , 121.0 , 0.0 ) ;
if ( pick_of ( PE_OV ) ! = 0 ) { t_pick = s_t - 1u ; break ; }
}
CHECK ( pick_of ( PE_OV ) ! = 0 , " 007: 121 V picks up " ) ;
for ( i = t_pick ; i < ( t_pick + 9998u ) ; i + + ) { dim_beat ( 0.0 , 121.0 , 0.0 ) ; }
ok = ( assert_of ( PE_OV ) = = 0 ) ;
for ( i = 0u ; i < 5u ; i + + ) { dim_beat ( 0.0 , 121.0 , 0.0 ) ; }
CHECK ( ( ok ! = 0 ) & & ( assert_of ( PE_OV ) ! = 0 ) ,
" 007: asserts exactly at +10000ms window (not earlier) " ) ;
for ( i = 0u ; i < 45u ; i + + ) { dim_beat ( 0.0 , 115.0 , 0.0 ) ; }
CHECK ( assert_of ( PE_OV ) ! = 0 , " 007: 115 V holds (ret=114) " ) ;
for ( i = 0u ; i < 45u ; i + + ) { dim_beat ( 0.0 , 113.0 , 0.0 ) ; }
CHECK ( ( pick_of ( PE_OV ) = = 0 ) & & ( assert_of ( PE_OV ) = = 0 ) ,
" 007: 113 V returns " ) ;
}
/* ===================== TC-PROTDIM-008 UV(欠量方向) ===================== */
static void tc_008_uv ( void ) {
uint32_t t_pick = 0u ;
uint32_t i ;
int ok ;
printf ( " [TC-PROTDIM-008] UV 20V/10s under-direction \n " ) ;
dim_setup ( ) ;
isolate_oc_family ( ) ;
set_en ( PS_UV_EN , 1 ) ;
for ( i = 0u ; i < 45u ; i + + ) { dim_beat ( 0.0 , 21.0 , 0.0 ) ; }
CHECK ( pick_of ( PE_UV ) = = 0 , " 008: 21 V above set(20): silent " ) ;
for ( i = 0u ; i < 400u ; i + + ) {
dim_beat ( 0.0 , 19.9 , 0.0 ) ;
if ( pick_of ( PE_UV ) ! = 0 ) { t_pick = s_t - 1u ; break ; }
}
CHECK ( pick_of ( PE_UV ) ! = 0 , " 008: 19.9 V picks up " ) ;
for ( i = t_pick ; i < ( t_pick + 9998u ) ; i + + ) { dim_beat ( 0.0 , 19.9 , 0.0 ) ; }
ok = ( assert_of ( PE_UV ) = = 0 ) ;
for ( i = 0u ; i < 5u ; i + + ) { dim_beat ( 0.0 , 19.9 , 0.0 ) ; }
CHECK ( ( ok ! = 0 ) & & ( assert_of ( PE_UV ) ! = 0 ) , " 008: asserts at +10000ms " ) ;
for ( i = 0u ; i < 45u ; i + + ) { dim_beat ( 0.0 , 20.5 , 0.0 ) ; }
CHECK ( assert_of ( PE_UV ) ! = 0 , " 008: 20.5 V holds under return(21) " ) ;
for ( i = 0u ; i < 45u ; i + + ) { dim_beat ( 0.0 , 21.6 , 0.0 ) ; }
CHECK ( ( pick_of ( PE_UV ) = = 0 ) & & ( assert_of ( PE_UV ) = = 0 ) , " 008: 21.6 V returns " ) ;
}
/* ===================== TC-PROTDIM-009 3U0( UN 通道) ===================== */
static void tc_009_3u0 ( void ) {
uint32_t t_pick = 0u ;
uint32_t i ;
int ok ;
printf ( " [TC-PROTDIM-009] 3U0 15V/5s via UN channel \n " ) ;
dim_setup ( ) ;
isolate_oc_family ( ) ;
set_en ( PS_3U0_EN , 1 ) ;
for ( i = 0u ; i < 45u ; i + + ) { dim_beat ( 0.0 , 100.0 , 14.0 ) ; }
CHECK ( pick_of ( PE_3U0 ) = = 0 , " 009: 14 V below set(15): silent " ) ;
for ( i = 0u ; i < 400u ; i + + ) {
dim_beat ( 0.0 , 100.0 , 15.1 ) ;
if ( pick_of ( PE_3U0 ) ! = 0 ) { t_pick = s_t - 1u ; break ; }
}
CHECK ( pick_of ( PE_3U0 ) ! = 0 , " 009: 15.1 V picks up " ) ;
for ( i = t_pick ; i < ( t_pick + 4998u ) ; i + + ) { dim_beat ( 0.0 , 100.0 , 15.1 ) ; }
ok = ( assert_of ( PE_3U0 ) = = 0 ) ;
for ( i = 0u ; i < 5u ; i + + ) { dim_beat ( 0.0 , 100.0 , 15.1 ) ; }
CHECK ( ( ok ! = 0 ) & & ( assert_of ( PE_3U0 ) ! = 0 ) , " 009: asserts at +5000ms " ) ;
for ( i = 0u ; i < 45u ; i + + ) { dim_beat ( 0.0 , 100.0 , 14.4 ) ; }
CHECK ( assert_of ( PE_3U0 ) ! = 0 , " 009: 14.4 V holds (ret=14.25) " ) ;
for ( i = 0u ; i < 45u ; i + + ) { dim_beat ( 0.0 , 100.0 , 14.1 ) ; }
CHECK ( ( pick_of ( PE_3U0 ) = = 0 ) & & ( assert_of ( PE_3U0 ) = = 0 ) , " 009: 14.1 V returns " ) ;
}
/* ===================== TC-PROTDIM-010 聚合位图与独立性 ===================== */
static void tc_010_mask ( void ) {
uint32_t i ;
printf ( " [TC-PROTDIM-010] dual assert mask independence \n " ) ;
dim_setup ( ) ;
isolate_oc_family ( ) ;
set_en ( PS_OV_EN , 1 ) ;
( void ) prot_set_set ( PS_OV_DLY , PROT_SET_Q10 ( 0.0 ) ) ; /* 同拍聚合,聚焦位图 */
for ( i = 0u ; i < 45u ; i + + ) { dim_beat ( 10.5 , 121.0 , 0.0 ) ; }
CHECK ( ( assert_of ( PE_OC1 ) ! = 0 ) & & ( assert_of ( PE_OV ) ! = 0 ) ,
" 010: OC1+OV both asserted " ) ;
CHECK ( prot_elm_active_mask ( ) = = ( ( 1uL < < PE_OC1 ) | ( 1uL < < PE_OV ) ) ,
" 010: active mask = bit0|bit4 exactly " ) ;
for ( i = 0u ; i < 45u ; i + + ) { dim_beat ( 3.0 , 121.0 , 0.0 ) ; }
CHECK ( ( assert_of ( PE_OC1 ) = = 0 ) & & ( assert_of ( PE_OV ) ! = 0 ) ,
" 010: IA withdrawn -> OC1 returns, OV untouched " ) ;
CHECK ( prot_elm_active_mask ( ) = = ( 1uL < < PE_OV ) , " 010: mask = OV only " ) ;
}
int main ( void ) {
printf ( " === Prot Dim Regression Tests === \n " ) ;
adc_cal_init ( ) ; /* 先把 RAM 系数置成合成 ROM(各 TC 内还会重跑) */
tc_001_baseline ( ) ;
tc_002_mismatch_trap ( ) ;
tc_003_oc1 ( ) ;
tc_004_oc2 ( ) ;
tc_005_oc3 ( ) ;
tc_006_ol ( ) ;
tc_007_ov ( ) ;
tc_008_uv ( ) ;
tc_009_3u0 ( ) ;
tc_010_mask ( ) ;
printf ( " \n === Prot Dim Regression Tests: %d/%d PASSED (failed=%d) === \n " ,
s_passed , s_total , s_failed ) ;
return ( s_failed = = 0 ) ? 0 : 1 ;
}