chore: 发布V1.1.26版本,修复Sink角色切换初始化残留问题
1. 更新所有文件版本号至V1.1.26,同步固件版本寄存器值 2. 修复Sink角色往返时初始化上下文残留问题,切换回Sink时重新执行完整初始化 3. 优化Sink配置生效逻辑,同角色仅复制PC可写配置,保留运行状态 4. 增加初始化阶段入队标记,避免沿用旧成功结果跳过未执行命令 5. 停止入队失败时由北向轮询重试,不依赖On_work或通道使能 6. 新增Sink初始化回归测试套件,覆盖14种场景验证流程正确性
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
/****************************************************************************
|
||||
文件名称 : chrg_comm.c
|
||||
完成日期 :
|
||||
当前版本号 : V1.1.24
|
||||
当前版本号 : V1.1.26
|
||||
主要功能 : 实现对外通讯协议 MODBUS 服务端,以独立线程等待处理响应请求数据。
|
||||
版本历史 : 创建原始版本
|
||||
说明 :
|
||||
@@ -2547,13 +2547,62 @@ static void chrg_comm_get_param_diff(eIDX_ID role,
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************
|
||||
函数名称: chrg_comm_sink_config_equal
|
||||
函数描述: 只比较PC可写配置,忽略影子区中过期的状态机和量测快照
|
||||
其它说明: 测试参数子结构仅包含配置;test_mode_old及执行步骤不参与比较
|
||||
*****************************************************************/
|
||||
static rt_bool_t chrg_comm_sink_config_equal(const struct chrg_switch_t *a,
|
||||
const struct chrg_switch_t *b)
|
||||
{
|
||||
return (a->CV_mode == b->CV_mode) && (a->protoCmd == b->protoCmd) &&
|
||||
(a->sink.protocol == b->sink.protocol) &&
|
||||
(a->sink.Pro_Group == b->sink.Pro_Group) &&
|
||||
(a->sink.pro_loadv == b->sink.pro_loadv) &&
|
||||
(a->sink.pro_loadc == b->sink.pro_loadc) &&
|
||||
(a->sink.cc_set == b->sink.cc_set) &&
|
||||
(a->sink.loadv == b->sink.loadv) && (a->sink.loadc == b->sink.loadc) &&
|
||||
(a->sink.volt_on == b->sink.volt_on) &&
|
||||
(a->sink.Now_State == b->sink.Now_State) &&
|
||||
(a->sink.test.test_mode == b->sink.test.test_mode) &&
|
||||
(a->sink.test.short_test.hold_time == b->sink.test.short_test.hold_time) &&
|
||||
(a->sink.test.short_test.set_mode == b->sink.test.short_test.set_mode) &&
|
||||
(a->sink.test.short_test.have_curr_flag == b->sink.test.short_test.have_curr_flag) &&
|
||||
(rt_memcmp(&a->sink.test.OCP_test, &b->sink.test.OCP_test,
|
||||
sizeof(a->sink.test.OCP_test)) == 0) &&
|
||||
(rt_memcmp(&a->sink.test.change_test, &b->sink.test.change_test,
|
||||
sizeof(a->sink.test.change_test)) == 0);
|
||||
}
|
||||
|
||||
/*****************************************************************
|
||||
函数名称: chrg_comm_copy_sink_config
|
||||
函数描述: 将PC配置逐项应用到Sink,保留实际运行状态、旧测试模式和量测
|
||||
其它说明: 禁止复制整个switch/sink/test,避免覆盖初始化及回码推进结果
|
||||
*****************************************************************/
|
||||
static void chrg_comm_copy_sink_config(struct chrg_switch_t *pReal,
|
||||
const struct chrg_switch_t *pShadow)
|
||||
{
|
||||
pReal->CV_mode = pShadow->CV_mode;
|
||||
pReal->protoCmd = pShadow->protoCmd;
|
||||
pReal->sink.protocol = pShadow->sink.protocol;
|
||||
pReal->sink.Pro_Group = pShadow->sink.Pro_Group;
|
||||
pReal->sink.pro_loadv = pShadow->sink.pro_loadv;
|
||||
pReal->sink.pro_loadc = pShadow->sink.pro_loadc;
|
||||
pReal->sink.cc_set = pShadow->sink.cc_set;
|
||||
pReal->sink.loadv = pShadow->sink.loadv;
|
||||
pReal->sink.loadc = pShadow->sink.loadc;
|
||||
pReal->sink.volt_on = pShadow->sink.volt_on;
|
||||
pReal->sink.Now_State = pShadow->sink.Now_State;
|
||||
pReal->sink.test.test_mode = pShadow->sink.test.test_mode;
|
||||
pReal->sink.test.short_test = pShadow->sink.test.short_test;
|
||||
pReal->sink.test.OCP_test = pShadow->sink.test.OCP_test;
|
||||
pReal->sink.test.change_test = pShadow->sink.test.change_test;
|
||||
}
|
||||
|
||||
/*****************************************************************
|
||||
函数名称: chrg_comm_apply_sink_effect
|
||||
函数描述: 处理COM参数生效后的同角色负载启停、测试和差异更新
|
||||
输入参数: ch:通道 pReal:运行参数 pShadow:待生效影子参数
|
||||
输出参数: 更新pReal并按需提交南向命令
|
||||
返回说明: MB_EX_NONE:成功 MB_EX_SLAVE_BUSY:命令提交失败
|
||||
其它说明: 角色切换不在本函数处理,由chrg_mb_write_sys统一调度
|
||||
函数描述: 应用同角色负载配置;相同初始化请求继续等待,不取消退出Short批次
|
||||
返回说明: 初始化期间不同配置返回忙,PC需重试;停止请求不受此限制
|
||||
*****************************************************************/
|
||||
static eMBException chrg_comm_apply_sink_effect(rt_uint8_t ch,
|
||||
struct chrg_switch_t *pReal, const struct chrg_switch_t *pShadow)
|
||||
@@ -2574,6 +2623,25 @@ static eMBException chrg_comm_apply_sink_effect(rt_uint8_t ch,
|
||||
rt_uint16_t sink_work = pShadow->sink.Now_State;
|
||||
chrg_param_diff_t diff_info;
|
||||
|
||||
/* 初始化是一个完整事务。相同运行请求只推进原事务;不同参数必须
|
||||
* 等待完成后重试,禁止先部分应用新配置或清掉尚未确认的退出命令。 */
|
||||
if ((sink_work == 0x01) &&
|
||||
((old_work_mode == SINK_WORK_INIT) ||
|
||||
(old_work_mode == SINK_WORK_INIT_AUX_WAIT))) {
|
||||
if (!chrg_comm_sink_config_equal(pReal, pShadow)) {
|
||||
return MB_EX_SLAVE_BUSY;
|
||||
}
|
||||
return (chrg_sink_work((eIDX_SOU_CH)ch, pReal) == 0) ?
|
||||
MB_EX_NONE : MB_EX_SLAVE_BUSY;
|
||||
}
|
||||
/* 未完成安全停止前不能用新运行请求打断停止批次。 */
|
||||
if ((sink_work == 0x01) &&
|
||||
((old_work_mode == SINK_WORK_STOP) ||
|
||||
(old_work_mode == SINK_WORK_STOP_WAIT) ||
|
||||
(old_work_mode == SINK_WORK_STOP_RELAY) ||
|
||||
(old_work_mode == SINK_WORK_STOP_RELAY_WAIT))) {
|
||||
return MB_EX_SLAVE_BUSY;
|
||||
}
|
||||
chrg_comm_get_param_diff(ID_SINK, pReal, pShadow, &diff_info);
|
||||
/*
|
||||
* 协议类型、CC和协议组号变化需要完整握手;协议电压和协议电流
|
||||
@@ -2605,7 +2673,7 @@ static eMBException chrg_comm_apply_sink_effect(rt_uint8_t ch,
|
||||
return MB_EX_SLAVE_BUSY;
|
||||
}
|
||||
}
|
||||
rt_memcpy(pReal, pShadow, sizeof(struct chrg_switch_t));
|
||||
chrg_comm_copy_sink_config(pReal, pShadow);
|
||||
|
||||
if (sink_work == 0x01) {
|
||||
curr_test = pReal->sink.test.test_mode;
|
||||
@@ -2934,6 +3002,9 @@ static eMBException chrg_mb_write_sys(rt_uint8_t ch, rt_uint16_t reg_offset,
|
||||
struct chrg_thread_t *pTHR_NOR;
|
||||
eIDX_ID old_id;
|
||||
eIDX_ID new_id;
|
||||
rt_bool_t sink_config_changed;
|
||||
rt_uint8_t old_sink_sub;
|
||||
rt_uint8_t old_sink_on;
|
||||
int switch_ret;
|
||||
|
||||
(void)pSOU;
|
||||
@@ -2956,13 +3027,8 @@ static eMBException chrg_mb_write_sys(rt_uint8_t ch, rt_uint16_t reg_offset,
|
||||
old_id = pReal->id;
|
||||
new_id = pSW->id;
|
||||
g_shadow_dirty[ch] = 0;
|
||||
/*
|
||||
* 使每次COM参数生效拥有独立版本。北向线程等待回码期间如果版本变化,
|
||||
* 必须放弃旧请求,防止旧回码把新配置的sub错误推进到下一步。
|
||||
*/
|
||||
pNOR->config_version[ch]++;
|
||||
|
||||
if (old_id != new_id) {
|
||||
pNOR->config_version[ch]++;
|
||||
/* 角色切换时清除旧Source协议切换的等待上下文。 */
|
||||
chrg_roll_nor_source_switch_reset(ch);
|
||||
rt_memcpy(pReal, pSW, sizeof(struct chrg_switch_t));
|
||||
@@ -2977,8 +3043,19 @@ static eMBException chrg_mb_write_sys(rt_uint8_t ch, rt_uint16_t reg_offset,
|
||||
}
|
||||
status = (switch_ret == 0) ? MB_EX_NONE : MB_EX_SLAVE_BUSY;
|
||||
} else if (new_id == ID_SINK) {
|
||||
sink_config_changed = !chrg_comm_sink_config_equal(pReal, pSW);
|
||||
old_sink_sub = pReal->sub;
|
||||
old_sink_on = pReal->sink.On_work;
|
||||
status = chrg_comm_apply_sink_effect(ch, pReal, pSW);
|
||||
/* 重复请求或初始化期间被拒绝的新配置不能作废正在等待的北向
|
||||
* 回码;只有配置确实应用或控制入口改变时才递增版本。
|
||||
* 即使南向暂时入队失败,已接受的新配置也必须隔离旧回码。 */
|
||||
if ((sink_config_changed && chrg_comm_sink_config_equal(pReal, pSW)) ||
|
||||
(old_sink_sub != pReal->sub) || (old_sink_on != pReal->sink.On_work)) {
|
||||
pNOR->config_version[ch]++;
|
||||
}
|
||||
} else {
|
||||
pNOR->config_version[ch]++;
|
||||
status = chrg_comm_apply_source_effect(ch, pReal, pSW);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/****************************************************************************
|
||||
文件名称 : chrg_roll_nor.c
|
||||
完成日期 :
|
||||
当前版本号 : V1.1.24
|
||||
当前版本号 : V1.1.26
|
||||
主要功能 : 实现北向通信轮巡请求命令。以独立线程处理。
|
||||
版本历史 : 创建原始版本
|
||||
说明 :
|
||||
@@ -1016,6 +1016,8 @@ void chrg_roll_nor_thread_entry (void *data)
|
||||
} else if ((pSW->id == ID_SINK) &&
|
||||
((pSW->sink.work_mode == SINK_WORK_INIT) ||
|
||||
(pSW->sink.work_mode == SINK_WORK_INIT_AUX_WAIT) ||
|
||||
/* STOP入队失败时On_work已清零,必须在使能过滤前继续重试。 */
|
||||
(pSW->sink.work_mode == SINK_WORK_STOP) ||
|
||||
(pSW->sink.work_mode == SINK_WORK_UNLOAD_WAIT) ||
|
||||
(pSW->sink.work_mode == SINK_WORK_LOW) ||
|
||||
(pSW->sink.work_mode == SINK_WORK_LOW_AUX_WAIT) ||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/****************************************************************************
|
||||
文件名称 : chrg_def.h
|
||||
完成日期 :
|
||||
当前版本号 : V1.1.24
|
||||
当前版本号 : V1.1.26
|
||||
主要功能 : 全局宏定义,常量,及结构体。
|
||||
版本历史 : 创建原始版本
|
||||
说明 :
|
||||
@@ -15,8 +15,8 @@
|
||||
/* CHRG application version. Keep this value synchronized with the changelog. */
|
||||
#define CHRG_VERSION_MAJOR 1U
|
||||
#define CHRG_VERSION_MINOR 1U
|
||||
#define CHRG_VERSION_PATCH 24U
|
||||
#define CHRG_VERSION_STRING "V1.1.24"
|
||||
#define CHRG_VERSION_PATCH 26U
|
||||
#define CHRG_VERSION_STRING "V1.1.26"
|
||||
/* Modbus version encoding: major<<8 + minor<<4 + patch. */
|
||||
#define CHRG_FIRMWARE_VERSION ((CHRG_VERSION_MAJOR << 8) + \
|
||||
(CHRG_VERSION_MINOR << 4) + CHRG_VERSION_PATCH)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/****************************************************************************
|
||||
文件名称 : chrg_sink.c
|
||||
完成日期 :
|
||||
当前版本号 : V1.1.24
|
||||
当前版本号 : V1.1.26
|
||||
主要功能 : 北向数据sink请求数据填充及发送。
|
||||
版本历史 : 创建原始版本
|
||||
说明 :
|
||||
@@ -34,6 +34,8 @@
|
||||
static rt_uint8_t g_sink_init_stage[TOTAL_SOU_CHS] = {0};
|
||||
static rt_tick_t g_sink_init_north_relay_tick[TOTAL_SOU_CHS] = {0};
|
||||
static rt_bool_t g_sink_init_in_progress[TOTAL_SOU_CHS] = {RT_FALSE};
|
||||
/* 只有当前阶段入队成功后,才允许消费该阶段的南向批次结果。 */
|
||||
static rt_bool_t g_sink_init_stage_submitted[TOTAL_SOU_CHS] = {RT_FALSE};
|
||||
|
||||
/* 主继电器闭合跟踪:1=已提交ALL_REL_ON(主继电器应已闭合) 0=未闭合/已断开。
|
||||
* 用于0V硬保护区分"首次开载/握手恢复"(主继电器未闭合,Now_voltage=0属正常)
|
||||
@@ -291,10 +293,12 @@ static int chrg_sink_init_submit_stage(eIDX_SOU_CH idx,
|
||||
rt_uint8_t total;
|
||||
rt_uint8_t start;
|
||||
rt_uint8_t count;
|
||||
int ret;
|
||||
|
||||
if ((idx >= TOTAL_SOU_CHS) || (pSW == RT_NULL)) {
|
||||
return -1;
|
||||
}
|
||||
g_sink_init_stage_submitted[idx] = RT_FALSE;
|
||||
total = chrg_sink_init_build_commands(pSW, regs, vals);
|
||||
|
||||
switch (g_sink_init_stage[idx]) {
|
||||
@@ -313,7 +317,11 @@ static int chrg_sink_init_submit_stage(eIDX_SOU_CH idx,
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
return chrg_sou_com_batch_submit(idx, ®s[start], &vals[start], count);
|
||||
ret = chrg_sou_com_batch_submit(idx, ®s[start], &vals[start], count);
|
||||
if (ret == 0) {
|
||||
g_sink_init_stage_submitted[idx] = RT_TRUE;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*****************************************************************
|
||||
@@ -336,20 +344,17 @@ static int chrg_sink_work_init(eIDX_SOU_CH idx, struct chrg_switch_t *pSW)
|
||||
g_sink_init_in_progress[idx] = RT_TRUE;
|
||||
g_sink_init_stage[idx] = SINK_INIT_STAGE_CLEAR_RELAY;
|
||||
g_sink_init_north_relay_tick[idx] = 0U;
|
||||
if (chrg_sink_init_submit_stage(idx, pSW) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* 入队失败也保留事务和等待入口,由等待分支持续重提当前阶段。 */
|
||||
pSW->sink.On_work = 1;
|
||||
pSW->sink.work_mode = SINK_WORK_INIT_AUX_WAIT;
|
||||
return 0;
|
||||
return chrg_sink_init_submit_stage(idx, pSW);
|
||||
}
|
||||
|
||||
/*****************************************************************
|
||||
函数名称: chrg_sink_work_init_aux_wait
|
||||
函数描述: 后台等待整组南向初始化命令完成,不阻塞北向协议握手
|
||||
输入参数: idx:南向功率通道编号 pSW:当前通道控制结构体
|
||||
输出参数: 初始化完成后进入SINK_WORK_WAIT,失败时重提整个初始化批次
|
||||
输出参数: 初始化完成后进入SINK_WORK_WAIT,失败时重提当前阶段
|
||||
返回说明: 0:继续等待或初始化完成 <0:参数错误
|
||||
其它说明: 重试时保留当前北向sub,禁止把正在执行的协议/CC事务拉回起点
|
||||
*****************************************************************/
|
||||
@@ -383,6 +388,10 @@ static int chrg_sink_work_init_aux_wait(eIDX_SOU_CH idx,
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/* 上一阶段成功后,新阶段可能因锁/队列满未入队;不能沿用旧成功结果。 */
|
||||
if (!g_sink_init_stage_submitted[idx]) {
|
||||
return chrg_sink_init_submit_stage(idx, pSW);
|
||||
}
|
||||
batch_result = chrg_sou_com_batch_get_result(idx);
|
||||
if (batch_result <= 0) {
|
||||
return chrg_sink_init_submit_stage(idx, pSW);
|
||||
@@ -400,6 +409,7 @@ static int chrg_sink_work_init_aux_wait(eIDX_SOU_CH idx,
|
||||
|
||||
/* 北向可能已推进到CC或电压查询,此处只更新南向完成状态。 */
|
||||
g_sink_init_in_progress[idx] = RT_FALSE;
|
||||
g_sink_init_stage_submitted[idx] = RT_FALSE;
|
||||
pSOU->online[idx] = 1;
|
||||
pSW->sink.test.test_mode_old = 0;
|
||||
pSW->sink.work_mode = SINK_WORK_WAIT;
|
||||
@@ -636,6 +646,7 @@ static int chrg_sink_work_stop_prepare(eIDX_SOU_CH idx,
|
||||
return -1;
|
||||
}
|
||||
g_sink_init_in_progress[idx] = RT_FALSE;
|
||||
g_sink_init_stage_submitted[idx] = RT_FALSE;
|
||||
if (chrg_sou_com_batch_cancel(idx) != 0) {
|
||||
return -1;
|
||||
}
|
||||
@@ -715,6 +726,13 @@ static int chrg_sink_work_switch(eIDX_SOU_CH idx, struct chrg_switch_t *pSW)
|
||||
rt_uint16_t eload_value = ELOAD_LOAD;
|
||||
int ret;
|
||||
|
||||
/* Source接管后,旧Sink初始化上下文已失效;返回Sink必须重新初始化,
|
||||
* 禁止把角色切换批次回码当作上次初始化阶段的完成结果。 */
|
||||
g_sink_init_in_progress[idx] = RT_FALSE;
|
||||
g_sink_init_stage_submitted[idx] = RT_FALSE;
|
||||
g_sink_init_stage[idx] = SINK_INIT_STAGE_CLEAR_RELAY;
|
||||
g_sink_init_north_relay_tick[idx] = 0U;
|
||||
|
||||
ret = chrg_sou_com_batch_submit(idx, ®, &value, 1);
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
@@ -1007,11 +1025,7 @@ int chrg_sink_volt_judge(eIDX_SOU_CH idx, struct chrg_switch_t *pSW)
|
||||
if (g_sink_init_in_progress[idx] ||
|
||||
(pSW->sink.work_mode == SINK_WORK_INIT) ||
|
||||
(pSW->sink.work_mode == SINK_WORK_INIT_AUX_WAIT)) {
|
||||
if (g_sink_init_in_progress[idx] &&
|
||||
(pSW->sink.work_mode != SINK_WORK_INIT) &&
|
||||
(pSW->sink.work_mode != SINK_WORK_INIT_AUX_WAIT)) {
|
||||
pSW->sink.work_mode = SINK_WORK_INIT_AUX_WAIT;
|
||||
}
|
||||
/* 统一入口负责恢复等待阶段及停止优先级,不能在这里覆盖STOP。 */
|
||||
return chrg_sink_work(idx, pSW);
|
||||
}
|
||||
|
||||
@@ -1191,10 +1205,12 @@ int chrg_sink_work(eIDX_SOU_CH idx, struct chrg_switch_t *pSW)
|
||||
}
|
||||
work_mode = pSW->sink.work_mode;
|
||||
workmode = work_mode;
|
||||
/* 初始化事务独占该通道,防止其它路径改成RUNING后追加普通启动命令。 */
|
||||
/* 已开始的初始化只能继续等待,重复INIT也不能被last_state去重卡住。
|
||||
* 停止、掉电保护和角色切换必须能抢占初始化,不能改回等待状态。 */
|
||||
if (g_sink_init_in_progress[idx] &&
|
||||
(work_mode != SINK_WORK_INIT) &&
|
||||
(work_mode != SINK_WORK_INIT_AUX_WAIT)) {
|
||||
(work_mode != SINK_WORK_STOP) &&
|
||||
(work_mode != SINK_WORK_LOW) &&
|
||||
(work_mode != SINK_WORK_SWITCH)) {
|
||||
pSW->sink.work_mode = SINK_WORK_INIT_AUX_WAIT;
|
||||
work_mode = SINK_WORK_INIT_AUX_WAIT;
|
||||
}
|
||||
@@ -1203,6 +1219,8 @@ int chrg_sink_work(eIDX_SOU_CH idx, struct chrg_switch_t *pSW)
|
||||
}
|
||||
/* 异步等待状态需要持续检查批次或新量测,其余相同状态保持去重。 */
|
||||
if ((work_mode == last_state[idx]) &&
|
||||
(work_mode != SINK_WORK_INIT) &&
|
||||
(work_mode != SINK_WORK_STOP) &&
|
||||
(work_mode != SINK_WORK_ON_TEST_SHORT) &&
|
||||
(work_mode != SINK_WORK_INIT_AUX_WAIT) &&
|
||||
(work_mode != SINK_WORK_STOP_WAIT) &&
|
||||
|
||||
Reference in New Issue
Block a user