Files
chrg/tests/sink_init/cases.c
T
yhf c8bfef090a chore: 发布V1.1.26版本,修复Sink角色切换初始化残留问题
1. 更新所有文件版本号至V1.1.26,同步固件版本寄存器值
2. 修复Sink角色往返时初始化上下文残留问题,切换回Sink时重新执行完整初始化
3. 优化Sink配置生效逻辑,同角色仅复制PC可写配置,保留运行状态
4. 增加初始化阶段入队标记,避免沿用旧成功结果跳过未执行命令
5. 停止入队失败时由北向轮询重试,不依赖On_work或通道使能
6. 新增Sink初始化回归测试套件,覆盖14种场景验证流程正确性
2026-09-17 12:01:50 +08:00

211 lines
10 KiB
C

/* 本文件由 run.cjs 拼接到真实产品函数后。每个场景独立进程,静态状态不会串扰。 */
#include <stdio.h>
#include <stdlib.h>
struct chrg_north_t chrgnorth;
struct chrg_south_t chrgsouth;
struct chrg_thread_t chrgthr[TOTAL_THRS];
static rt_tick_t now;
static int pending, result, fail_submit, cancel_count, submit_count;
static int queue_capacity = 1;
static rt_uint16_t last_reg, last_val;
static rt_uint32_t sample_seq;
#define CHECK(x) do { if (!(x)) { fprintf(stderr, "line %d: %s\n", __LINE__, #x); exit(1); } } while (0)
rt_tick_t rt_tick_get(void) { return now; }
rt_tick_t rt_tick_from_millisecond(rt_int32_t ms) { return (rt_tick_t)ms; }
int rt_kprintf(const char *format, ...) { (void)format; return 0; }
rt_err_t rt_mutex_take(rt_mutex_t mutex, rt_int32_t timeout)
{ (void)mutex; (void)timeout; return 0; }
rt_err_t rt_mutex_release(rt_mutex_t mutex) { (void)mutex; return 0; }
void chrg_roll_nor_source_switch_reset(rt_uint8_t ch) { (void)ch; CHECK(0); }
int chrg_source_work_state(rt_uint8_t ch, struct chrg_switch_t *p)
{ (void)ch; (void)p; CHECK(0); return -1; }
static eMBException chrg_comm_apply_source_effect(rt_uint8_t ch,
struct chrg_switch_t *p, const struct chrg_switch_t *s)
{ (void)ch; (void)p; (void)s; CHECK(0); return MB_EX_SLAVE_BUSY; }
int chrg_sou_com_batch_submit(eIDX_SOU_CH ch, const rt_uint16_t *regs,
const rt_uint16_t *vals, rt_uint8_t count)
{
(void)ch;
CHECK(count > 0);
if (fail_submit) { fail_submit--; return -1; }
CHECK(pending < queue_capacity); /* 角色切换允许连续两批,其余场景禁止重复提交。 */
submit_count++;
last_reg = regs[0]; last_val = vals[0];
pending++; result = 0;
return 0;
}
int chrg_sou_com_batch_cancel(eIDX_SOU_CH ch)
{ (void)ch; cancel_count++; pending = 0; result = -1; return 0; }
rt_bool_t chrg_sou_com_batch_is_pending(eIDX_SOU_CH ch)
{ (void)ch; return pending; }
int chrg_sou_com_batch_get_result(eIDX_SOU_CH ch)
{ (void)ch; return result; }
int chrg_sou_measure_once_submit(eIDX_SOU_CH ch) { (void)ch; return 0; }
rt_uint32_t chrg_eload_get_sample_seq(rt_uint8_t ch) { (void)ch; return sample_seq; }
void chrg_nor_sw_rel(eIDX_NOR_CH ch, eIDX_ID id) { (void)ch; (void)id; }
/* 北向串口不在这些场景的执行路径中,意外调用立即失败。 */
rt_uint8_t u16_to_u8v(rt_uint16_t value, rt_uint8_t *buf)
{ (void)value; (void)buf; CHECK(0); return 0; }
int chrg_north_pkg_encode(eIDX_ID id, rt_uint8_t cmd, rt_uint8_t *in,
rt_uint8_t len, rt_uint8_t *out, rt_uint16_t *out_len)
{ (void)id; (void)cmd; (void)in; (void)len; (void)out; (void)out_len; CHECK(0); return -1; }
int chrg_north_send(rt_uint8_t *data, rt_size_t length)
{ (void)data; (void)length; CHECK(0); return -1; }
static struct chrg_switch_t *fixture(void)
{
struct chrg_switch_t *p = &chrgnorth.sw[0];
p->id = ID_SINK;
p->CV_mode = MODE_CONSTANT_CURRENT;
p->sink.On_work = 1;
p->sink.Now_State = 1;
p->sink.loadc = 1000;
p->sink.volt_on = 4000;
p->sink.pro_loadv = 5000;
p->sink.pro_loadc = 1000;
p->sink.work_mode = SINK_WORK_ON_TEST_SHORT;
p->sink.test.test_mode = SINK_TEST_SHORT;
p->sink.test.test_mode_old = SINK_TEST_SHORT;
return p;
}
static void exit_short(struct chrg_switch_t *p)
{
struct chrg_switch_t shadow = *p;
shadow.sink.test.test_mode = 0;
CHECK(chrg_comm_apply_sink_effect(0, p, &shadow) == MB_EX_NONE);
CHECK(p->sink.work_mode == SINK_WORK_INIT_AUX_WAIT);
CHECK(pending && last_reg == 0x40 && last_val == 0);
}
static void ack(void) { pending = 0; result = 1; }
static void complete_init(struct chrg_switch_t *p)
{
ack(); CHECK(chrg_sink_work(0, p) == 0);
CHECK(pending && last_reg == REG_REL_ON && last_val == ALL_REL_OFF);
ack(); CHECK(chrg_sink_work(0, p) == 0);
now += 31; CHECK(chrg_sink_work(0, p) == 0);
CHECK(pending && last_reg == REG_REL_ON && last_val == FU_REL_ON);
ack(); CHECK(chrg_sink_work(0, p) == 0);
CHECK(p->sink.work_mode == SINK_WORK_WAIT);
CHECK(!g_sink_init_in_progress[0] && p->sink.test.test_mode_old == 0);
}
int main(int argc, char **argv)
{
struct chrg_switch_t *p = fixture();
struct chrg_switch_t s;
int cancels, submits;
CHECK(argc == 2);
if (!strcmp(argv[1], "preserve_runtime")) {
p->sink.test.test_mode = p->sink.test.test_mode_old = 0;
p->sink.work_mode = SINK_WORK_RUNING;
p->sub = IDX_GET_SINK_VC;
p->Now_voltage = 5010; p->Now_current = 1000;
p->Sink_voltage_seq = 77;
CHECK(chrg_sink_work(0, p) == 0); ack();
s = *p;
s.sink.work_mode = SINK_WORK_INIT; s.sink.On_work = 0;
s.sub = IDX_SET_SINK_CC_BEFORE_PD;
s.Now_voltage = 0; s.Now_current = 0; s.Sink_voltage_seq = 1;
CHECK(chrg_comm_apply_sink_effect(0, p, &s) == MB_EX_NONE);
CHECK(p->sink.work_mode == SINK_WORK_RUNING && p->sink.On_work == 1);
CHECK(p->sub == IDX_GET_SINK_VC && p->Now_voltage == 5010);
CHECK(p->Now_current == 1000 && p->Sink_voltage_seq == 77 && !pending);
} else if (!strcmp(argv[1], "first_submit_failure")) {
s = *p; s.sink.test.test_mode = 0; fail_submit = 1;
CHECK(chrg_comm_apply_sink_effect(0, p, &s) == MB_EX_SLAVE_BUSY);
CHECK(chrg_sink_work(0, p) == 0);
CHECK(pending && last_reg == 0x40);
complete_init(p);
} else {
exit_short(p);
cancels = cancel_count; submits = submit_count; s = *p;
if (!strcmp(argv[1], "duplicate_version") || !strcmp(argv[1], "busy_version")) {
int busy = !strcmp(argv[1], "busy_version");
chrgnorth.config_version[0] = 17;
if (busy) s.sink.loadc = 800;
CHECK(chrg_mb_write_sys(0, SYS_REG_PARAM_EFFECT, 1, &s,
&chrgnorth, &chrgsouth) == (busy ? MB_EX_SLAVE_BUSY : MB_EX_NONE));
CHECK(chrgnorth.config_version[0] == 17);
CHECK(g_shadow_dirty[0] == busy);
CHECK(cancel_count == cancels && pending);
} else if (!strcmp(argv[1], "duplicate_exit")) {
CHECK(chrg_comm_apply_sink_effect(0, p, &s) == MB_EX_NONE);
CHECK(cancel_count == cancels && submit_count == submits);
CHECK(p->sink.work_mode == SINK_WORK_INIT_AUX_WAIT && pending);
complete_init(p);
} else if (!strcmp(argv[1], "busy_changed_config")) {
struct chrg_switch_t before = *p;
s.sink.loadc = 800; s.sink.volt_on = 4500;
CHECK(chrg_comm_apply_sink_effect(0, p, &s) == MB_EX_SLAVE_BUSY);
CHECK(memcmp(p, &before, sizeof(*p)) == 0);
CHECK(cancel_count == cancels && submit_count == submits && pending);
} else if (!strcmp(argv[1], "recover_init")) {
p->sink.work_mode = SINK_WORK_INIT; /* 硬件截图的状态组合。 */
CHECK(chrg_sink_work(0, p) == 0);
CHECK(p->sink.work_mode == SINK_WORK_INIT_AUX_WAIT);
CHECK(cancel_count == cancels && submit_count == submits);
complete_init(p);
} else if (!strcmp(argv[1], "stop_during_init")) {
s.sink.Now_State = 2;
CHECK(chrg_comm_apply_sink_effect(0, p, &s) == MB_EX_NONE);
CHECK(!g_sink_init_in_progress[0] && p->sink.On_work == 0);
CHECK(p->sink.work_mode == SINK_WORK_STOP_WAIT);
CHECK(pending && last_reg == REG_WORK && last_val == WORK_STOP);
} else if (!strcmp(argv[1], "stop_submit_retry")) {
s.sink.Now_State = 2; fail_submit = 1;
CHECK(chrg_comm_apply_sink_effect(0, p, &s) == MB_EX_SLAVE_BUSY);
CHECK(p->sink.work_mode == SINK_WORK_STOP && p->sink.On_work == 0);
CHECK(poll_state(p) == 0);
CHECK(p->sink.work_mode == SINK_WORK_STOP_WAIT);
CHECK(pending && last_reg == REG_WORK && last_val == WORK_STOP);
} else if (!strcmp(argv[1], "role_roundtrip")) {
ack(); CHECK(chrg_sink_work(0, p) == 0);
ack(); CHECK(chrg_sink_work(0, p) == 0);
now += 31; CHECK(chrg_sink_work(0, p) == 0);
CHECK(g_sink_init_stage[0] == SINK_INIT_STAGE_REST);
/* 模拟Source接管时取消旧批次并清On_work,保留真实Sink静态上下文。 */
CHECK(chrg_sou_com_batch_cancel(0) == 0);
p->sink.On_work = 0;
p->source.On_Flag = 1;
p->sink.work_mode = SINK_WORK_SWITCH;
queue_capacity = 2;
CHECK(chrg_sink_work(0, p) == 0);
CHECK(p->sink.work_mode == SINK_WORK_INIT);
ack(); /* 角色切换批次已成功,但不代表新Sink初始化成功。 */
CHECK(chrg_sink_work(0, p) == 0);
CHECK(p->sink.work_mode == SINK_WORK_INIT_AUX_WAIT);
CHECK(p->sink.On_work == 1 && pending && last_reg == 0x40);
complete_init(p);
} else if (!strcmp(argv[1], "rest_submit_failure")) {
ack(); CHECK(chrg_sink_work(0, p) == 0);
ack(); CHECK(chrg_sink_work(0, p) == 0);
now += 31; fail_submit = 1;
CHECK(chrg_sink_work(0, p) != 0);
CHECK(!pending && result == 1);
CHECK(chrg_sink_work(0, p) == 0);
CHECK(pending && last_reg == REG_REL_ON && last_val == FU_REL_ON);
CHECK(g_sink_init_in_progress[0] && p->sink.test.test_mode_old == 1);
ack(); CHECK(chrg_sink_work(0, p) == 0);
CHECK(p->sink.work_mode == SINK_WORK_WAIT);
} else if (!strcmp(argv[1], "stage_submit_failure")) {
ack(); fail_submit = 1;
CHECK(chrg_sink_work(0, p) != 0);
CHECK(!pending && result == 1); /* 故意保留上一阶段成功结果。 */
CHECK(chrg_sink_work(0, p) == 0);
CHECK(pending && last_reg == REG_REL_ON && last_val == ALL_REL_OFF);
CHECK(g_sink_init_stage[0] == SINK_INIT_STAGE_AUX_RELAY);
} else if (!strcmp(argv[1], "failed_batch_retry")) {
pending = 0; result = -1;
CHECK(chrg_sink_work(0, p) == 0);
CHECK(pending && last_reg == 0x40 && p->sink.test.test_mode_old == 1);
complete_init(p);
} else if (!strcmp(argv[1], "complete_then_restart")) {
complete_init(p); s = *p; s.sink.test.test_mode = 1;
CHECK(chrg_comm_apply_sink_effect(0, p, &s) == MB_EX_NONE);
CHECK(p->sink.work_mode == SINK_WORK_ON_TEST_SHORT && pending);
ack(); exit_short(p); complete_init(p);
} else { CHECK(0); }
}
return 0;
}