/* 本文件由 run.cjs 拼接到真实产品函数后。每个场景独立进程,静态状态不会串扰。 */ #include #include 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; }