Merge pull request 'Feature' (#5) from feature into master
Reviewed-on: chrg/chrg#5
This commit is contained in:
@@ -26,3 +26,7 @@ There is no product-level automated test suite or coverage threshold. Every firm
|
||||
## Commit & Pull Request Guidelines
|
||||
|
||||
History uses short, lowercase, imperative summaries such as `fix south ch` and `add roll thread`; keep each commit focused and avoid generated artifacts. Pull requests should describe the affected target and behavior, link the issue, list build and hardware results, and include serial logs or LCD captures for user-visible or protocol changes. Call out changes to register maps, flash layout, linker scripts, or upgrade compatibility explicitly.
|
||||
|
||||
## Application Versioning
|
||||
|
||||
Every change to `apps/chrg` application code must increment the CHRG application version. Keep `CHRG_VERSION_*`, `CHRG_VERSION_STRING`, and `CHRG_FIRMWARE_VERSION` in `applications/utils/chrg_def.h`, the `当前版本号` field in affected application source headers, and `docs/修改日志.md` synchronized. Do not change the Bootloader version unless the Bootloader itself is intentionally released.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/****************************************************************************
|
||||
文件名称 : chrg_fal.c
|
||||
完成日期 :
|
||||
当前版本号 : V1.0
|
||||
当前版本号 : V1.1.24
|
||||
主要功能 : 初始化片上FLASH存储驱动,参数读/写FLASH接口实现;
|
||||
升级数据包写入实现;日志写入FLASH实现。
|
||||
版本历史 : 创建原始版本
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/****************************************************************************
|
||||
文件名称 : chrg_fal.h
|
||||
完成日期 :
|
||||
当前版本号 : V1.0
|
||||
当前版本号 : V1.1.24
|
||||
主要功能 : 提供参数读/写FLASH接口。
|
||||
版本历史 : 创建原始版本
|
||||
说明 :
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/****************************************************************************
|
||||
文件名称 : chrg_gpio.c
|
||||
完成日期 :
|
||||
当前版本号 : V1.0
|
||||
当前版本号 : V1.1.24
|
||||
主要功能 : 一般性 GPIO 读写操作: 管脚设置,读取等
|
||||
版本历史 : 创建原始版本
|
||||
说明 :
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/****************************************************************************
|
||||
文件名称 : chrg_gpio.h
|
||||
完成日期 :
|
||||
当前版本号 : V1.0
|
||||
当前版本号 : V1.1.24
|
||||
主要功能 :
|
||||
GPIO口宏定义。
|
||||
版本历史 : 创建原始版本
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/****************************************************************************
|
||||
文件名称 : chrg_led.c
|
||||
完成日期 :
|
||||
当前版本号 : V1.0
|
||||
当前版本号 : V1.1.24
|
||||
主要功能 : 采用系统软件定时器驱动多路GPIO
|
||||
LED灯,实现LED等工作模式初始化,闪烁方式等的功能。
|
||||
版本历史 : 创建原始版本
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/****************************************************************************
|
||||
文件名称 : chrg_led.h
|
||||
完成日期 :
|
||||
当前版本号 : V1.0
|
||||
当前版本号 : V1.1.24
|
||||
主要功能 : 控制LED灯工作模式。
|
||||
版本历史 : 创建原始版本
|
||||
说明 :
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/****************************************************************************
|
||||
文件名称 : chrg_rel.c
|
||||
完成日期 :
|
||||
当前版本号 : V1.0
|
||||
当前版本号 : V1.1.24
|
||||
主要功能 : sink/source 切换继电器操作。
|
||||
版本历史 : 创建原始版本
|
||||
说明 :
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/****************************************************************************
|
||||
文件名称 : chrg_rel.h
|
||||
完成日期 :
|
||||
当前版本号 : V1.0
|
||||
当前版本号 : V1.1.24
|
||||
主要功能 : sink/source 切换继电器操作。
|
||||
版本历史 : 创建原始版本
|
||||
说明 :
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/****************************************************************************
|
||||
文件名称 : chrg_switch.c
|
||||
完成日期 :
|
||||
当前版本号 : V1.0
|
||||
当前版本号 : V1.1.24
|
||||
主要功能 : SN74LV4052APW 选通操作接口。
|
||||
版本历史 : 创建原始版本
|
||||
说明 :
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/****************************************************************************
|
||||
文件名称 : chrg_switch.h
|
||||
完成日期 :
|
||||
当前版本号 : V1.0
|
||||
当前版本号 : V1.1.24
|
||||
主要功能 : SN74LV4052APW 选通操作接口。
|
||||
版本历史 : 创建原始版本
|
||||
说明 :
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/****************************************************************************
|
||||
文件名称 : chrg_tmr.c
|
||||
完成日期 :
|
||||
当前版本号 : V1.0
|
||||
当前版本号 : V1.1.24
|
||||
主要功能 : 芯片内支持的高精度(us级)硬件定时器操作实现:启动、停止、回调等接口。
|
||||
版本历史 : 创建原始版本
|
||||
说明 :
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/****************************************************************************
|
||||
文件名称 : chrg_tmr.h
|
||||
完成日期 :
|
||||
当前版本号 : V1.0
|
||||
当前版本号 : V1.1.24
|
||||
主要功能 : 高精度(us级)硬件定时器调用接口:启动、停止、读取时刻等接口。
|
||||
版本历史 : 创建原始版本
|
||||
说明 :
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/****************************************************************************
|
||||
文件名称 : chrg_tty.h
|
||||
完成日期 :
|
||||
当前版本号 : V1.0
|
||||
当前版本号 : V1.1.24
|
||||
主要功能 : 实现串口设备创建、销毁、配置、读取数据、发送数据等接口函数。
|
||||
版本历史 : 创建原始版本
|
||||
说明 :
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/****************************************************************************
|
||||
文件名称 : chrg_tty.h
|
||||
完成日期 :
|
||||
当前版本号 : V1.0
|
||||
当前版本号 : V1.1.24
|
||||
主要功能 : 串口设备调用接口:创建、销毁、配置、读取数据、发送数据等接口。
|
||||
版本历史 : 创建原始版本
|
||||
说明 :
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/****************************************************************************
|
||||
文件名称 : chrg_vcom.c
|
||||
完成日期 :
|
||||
当前版本号 : V1.0
|
||||
当前版本号 : V1.1.24
|
||||
主要功能 : 实现USB虚拟串口作为控制终端。
|
||||
版本历史 : 创建原始版本
|
||||
说明 :
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/****************************************************************************
|
||||
文件名称 : chrg_vcom.h
|
||||
完成日期 :
|
||||
当前版本号 : V1.0
|
||||
当前版本号 : V1.1.24
|
||||
主要功能 : 实现USB虚拟串口作为控制终端。
|
||||
版本历史 : 创建原始版本
|
||||
说明 :
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/****************************************************************************
|
||||
文件名称 : chrg_wdt.c
|
||||
完成日期 :
|
||||
当前版本号 : V1.0
|
||||
当前版本号 : V1.1.24
|
||||
主要功能 : 实现芯片内部看门狗初始化以及喂狗函数。
|
||||
版本历史 : 创建原始版本
|
||||
说明 :
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/****************************************************************************
|
||||
文件名称 : chrg_wdt.h
|
||||
完成日期 :
|
||||
当前版本号 : V1.0
|
||||
当前版本号 : V1.1.24
|
||||
主要功能 : 实现芯片内部看门狗初始化以及喂狗函数。
|
||||
版本历史 : 创建原始版本
|
||||
说明 :
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include "shell.h"
|
||||
#include "chrg_wdt.h"
|
||||
#include "chrg_def.h"
|
||||
|
||||
void show_app_version (void)
|
||||
{
|
||||
@@ -20,7 +21,8 @@ void show_app_version (void)
|
||||
HAL_GetUIDw2(), HAL_GetUIDw1(), HAL_GetUIDw0());
|
||||
rt_kprintf("================================================\r\n");
|
||||
#else
|
||||
rt_kprintf("\tcharger control via RT-Thread v%d.%d.%d built @ %s, %s\r\n",
|
||||
rt_kprintf("\tcharger firmware %s via RT-Thread v%d.%d.%d built @ %s, %s\r\n",
|
||||
CHRG_VERSION_STRING,
|
||||
RT_VERSION_MAJOR, RT_VERSION_MINOR, RT_VERSION_PATCH, __DATE__, __TIME__);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/****************************************************************************
|
||||
文件名称 : chrg_comm.c
|
||||
完成日期 :
|
||||
当前版本号 : V1.1.24
|
||||
当前版本号 : V1.1.32
|
||||
主要功能 : 实现对外通讯协议 MODBUS 服务端,以独立线程等待处理响应请求数据。
|
||||
版本历史 : 创建原始版本
|
||||
说明 :
|
||||
@@ -27,7 +27,8 @@
|
||||
#include "stm32f4xx_hal.h"
|
||||
|
||||
#define HOLD_REG_FIRMWARE_VERSION 0x0300U /* 协议板固件版本,只读 */
|
||||
#define CHRG_FIRMWARE_VERSION 0x0127U /* 当前协议板版本:V1.1.23 */
|
||||
#define CHRG_FIRMWARE_VERSION 0x0130U /* 当前协议板版本:V1.1.32 */
|
||||
|
||||
|
||||
rt_uint8_t ucDiscInBuf[(TOTAL_DISC_REGS+BITS_UCHAR-1)/BITS_UCHAR];
|
||||
rt_uint8_t ucCoilBuf[(TOTAL_COIL_REGS+BITS_UCHAR-1)/BITS_UCHAR];
|
||||
@@ -618,7 +619,7 @@ eMBException funcReadHoldingRegister (rt_uint8_t *reqFrame, rt_uint16_t reqLen,
|
||||
|
||||
/*
|
||||
* 协议板版本号使用独立的只读地址0x0300,不占用现有通道保持寄存器空间。
|
||||
* 当前版本V1.1.23编码为0x0127,Modbus响应按高字节在前返回01 27。
|
||||
* 当前版本由chrg_def.h统一定义,Modbus响应按高字节在前返回。
|
||||
* 该特殊地址只支持一次读取一个寄存器,避免与普通连续寄存器混用。
|
||||
*/
|
||||
if (regAddress == HOLD_REG_FIRMWARE_VERSION) {
|
||||
@@ -956,6 +957,41 @@ static rt_uint16_t src_type_lookup(rt_uint16_t reg_val,struct chrg_switch_t *pSW
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/*****************************************************************
|
||||
函数名称: chrg_comm_reg_decode
|
||||
函数描述: 将上位机分区地址解码为0起始通道号和通道内寄存器偏移
|
||||
输入参数: partition:分区高字节 address:分区低字节地址
|
||||
ch:通道输出 reg_offset:通道内偏移输出
|
||||
输出参数: ch、reg_offset
|
||||
返回说明: 0:地址有效 <0:分区、地址或参数无效
|
||||
其它说明: 统一供0x06和0x10使用,避免两条写入路径采用不同通道算法
|
||||
*****************************************************************/
|
||||
static int chrg_comm_reg_decode(rt_uint8_t partition,
|
||||
rt_uint16_t address, eIDX_SOU_CH *ch, rt_uint16_t *reg_offset)
|
||||
{
|
||||
rt_uint16_t regs_per_channel;
|
||||
|
||||
if ((ch == RT_NULL) || (reg_offset == RT_NULL)) {
|
||||
return -1;
|
||||
}
|
||||
if (partition == HOLD_REG_SINK_BASE) {
|
||||
regs_per_channel = TOTAL_SINK_CH_REGS;
|
||||
} else if (partition == HOLD_REG_SRC_BASE) {
|
||||
regs_per_channel = TOTAL_SRC_CH_REGS;
|
||||
} else if (partition == HOLD_REG_SYS_BASE) {
|
||||
regs_per_channel = TOTAL_SYS_CH_REGS;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
if (address >= (regs_per_channel * TOTAL_SOU_CHS)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
*ch = (eIDX_SOU_CH)(address / regs_per_channel);
|
||||
*reg_offset = address % regs_per_channel;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************
|
||||
函数名称: funcWriteHoldingRegister
|
||||
函数描述: 写单个保持寄存器(0x06功能码)
|
||||
@@ -964,7 +1000,7 @@ static rt_uint16_t src_type_lookup(rt_uint16_t reg_val,struct chrg_switch_t *pSW
|
||||
输出参数: -
|
||||
返回说明: MB_EX_NONE=成功, 其他=Modbus异常码
|
||||
其它说明: 新协议采用标准0x06功能码,寄存器地址区分功能区块:
|
||||
0x0000~0x0073 负载, 0x0080~0x0097 电源, 0x00A0~0x00A7 系统
|
||||
高字节选择分区,低字节按每通道50个地址计算通道和寄存器偏移
|
||||
*****************************************************************/
|
||||
eMBException funcWriteHoldingRegister (rt_uint8_t *reqFrame, rt_uint16_t reqLen,
|
||||
rt_uint8_t *resFrame, rt_uint16_t *resLen)
|
||||
@@ -976,8 +1012,9 @@ eMBException funcWriteHoldingRegister (rt_uint8_t *reqFrame, rt_uint16_t reqLen,
|
||||
rt_uint8_t regAddress_H = 0;
|
||||
rt_uint16_t sou_value = 0;
|
||||
/* ---- 提取通道号和区块内偏移 ---- */
|
||||
eIDX_SOU_CH ch;
|
||||
rt_uint16_t reg_offset; // 区块内寄存器偏移
|
||||
/* 使用越界枚举作为无效初值,禁止地址校验失败后误用随机通道。 */
|
||||
eIDX_SOU_CH ch = TOTAL_SOU_CHS;
|
||||
rt_uint16_t reg_offset = 0; // 区块内寄存器偏移
|
||||
|
||||
eMBException eStatus = MB_EX_NONE;
|
||||
eMBErrorCode eRegStatus;
|
||||
@@ -1011,26 +1048,8 @@ eMBException funcWriteHoldingRegister (rt_uint8_t *reqFrame, rt_uint16_t reqLen,
|
||||
}
|
||||
|
||||
/* ---- 地址范围校验 ---- */
|
||||
if(regAddress_H == HOLD_REG_SINK_BASE){
|
||||
if (REG_IS_SINK(regAddress)) {
|
||||
ch = (eIDX_SOU_CH)REG_GET_SINK_CH(regAddress);
|
||||
reg_offset = REG_GET_SINK_OFFSET(regAddress);
|
||||
}
|
||||
}else if (regAddress_H == HOLD_REG_SRC_BASE) {
|
||||
if (REG_IS_SRC(regAddress)) {
|
||||
ch = (eIDX_SOU_CH)REG_GET_SRC_CH(regAddress);
|
||||
reg_offset = REG_GET_SRC_OFFSET(regAddress);
|
||||
}
|
||||
} else if (regAddress_H == HOLD_REG_SYS_BASE) {
|
||||
if (REG_IS_SYS(regAddress)) {
|
||||
ch = (eIDX_SOU_CH)REG_GET_SYS_CH(regAddress);
|
||||
reg_offset = REG_GET_SYS_OFFSET(regAddress);
|
||||
}
|
||||
} else {
|
||||
return MB_EX_ILLEGAL_DATA_ADDRESS;
|
||||
}
|
||||
|
||||
if (ch > IDX_SOU_CH4) {
|
||||
if (chrg_comm_reg_decode(regAddress_H, regAddress,
|
||||
&ch, ®_offset) != 0) {
|
||||
return MB_EX_ILLEGAL_DATA_ADDRESS;
|
||||
}
|
||||
|
||||
@@ -1140,6 +1159,11 @@ eMBException funcWriteMultipleHoldingRegister (rt_uint8_t *reqFrame, rt_uint16_t
|
||||
#else
|
||||
rt_uint8_t regAddress_H = 0;
|
||||
rt_uint16_t regBaseOffset = 0;
|
||||
rt_uint16_t regEndOffset = 0;
|
||||
rt_uint16_t first_reg_offset = 0;
|
||||
rt_uint16_t last_reg_offset = 0;
|
||||
eIDX_SOU_CH first_ch = TOTAL_SOU_CHS;
|
||||
eIDX_SOU_CH last_ch = TOTAL_SOU_CHS;
|
||||
#endif
|
||||
|
||||
// ========== 公共校验逻辑(只写一遍)==========
|
||||
@@ -1212,17 +1236,21 @@ eMBException funcWriteMultipleHoldingRegister (rt_uint8_t *reqFrame, rt_uint16_t
|
||||
// 正常产品模式:分区地址逻辑
|
||||
regAddress_H = reqFrame[2];
|
||||
regBaseOffset = reqFrame[3];
|
||||
regEndOffset = regBaseOffset + cntReg - 1U;
|
||||
/* 起止地址必须属于同一有效通道,禁止一帧0x10跨通道改写参数。 */
|
||||
if ((chrg_comm_reg_decode(regAddress_H, regBaseOffset,
|
||||
&first_ch, &first_reg_offset) != 0) ||
|
||||
(chrg_comm_reg_decode(regAddress_H, regEndOffset,
|
||||
&last_ch, &last_reg_offset) != 0) ||
|
||||
(first_ch != last_ch) ||
|
||||
(last_reg_offset != (first_reg_offset + cntReg - 1U))) {
|
||||
return MB_EX_ILLEGAL_DATA_ADDRESS;
|
||||
}
|
||||
|
||||
for (int i = 0; i < cntReg; i++)
|
||||
{
|
||||
rt_uint16_t curr_part_offset = regBaseOffset + i;
|
||||
eIDX_SOU_CH ch = (eIDX_SOU_CH)(curr_part_offset / TOTAL_HOLD_CH_REGS);
|
||||
rt_uint16_t ch_reg_offset = curr_part_offset % TOTAL_HOLD_CH_REGS;
|
||||
|
||||
if (ch > IDX_SOU_CH4) {
|
||||
//rt_kprintf("WRITE MULTI REG: CH ERROR, ch=%d (part offset=%d)\n", ch, curr_part_offset);
|
||||
return MB_EX_ILLEGAL_DATA_ADDRESS;
|
||||
}
|
||||
eIDX_SOU_CH ch = first_ch;
|
||||
rt_uint16_t ch_reg_offset = first_reg_offset + i;
|
||||
pSW = &g_shadow_sw[ch];
|
||||
chrg_shadow_sync(ch); // 首次写同步真实状态
|
||||
rt_uint16_t sou_value = u8v_to_u16(&pWriteData[i * 2]);
|
||||
@@ -2548,13 +2576,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)
|
||||
@@ -2575,6 +2652,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和协议组号变化需要完整握手;协议电压和协议电流
|
||||
@@ -2606,7 +2702,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;
|
||||
@@ -2935,6 +3031,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;
|
||||
@@ -2957,13 +3056,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));
|
||||
@@ -2978,8 +3072,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_comm.h
|
||||
完成日期 :
|
||||
当前版本号 : V1.1.21
|
||||
当前版本号 : V1.1.31
|
||||
主要功能 : 实现对外通讯协议 MODBUS 服务端,以独立线程等待处理响应请求数据。
|
||||
版本历史 : 创建原始版本
|
||||
说明 :
|
||||
@@ -40,10 +40,10 @@ typedef enum {
|
||||
// ========== 新寄存器地址映射 (使用0x06/0x10标准Modbus功能码) ==========
|
||||
// 详细寄存器偏移定义见 chrg_regs.h
|
||||
|
||||
// 判断寄存器地址属于哪个区块的宏
|
||||
#define REG_IS_SINK(addr) (((addr / 4) < TOTAL_SINK_CH_REGS))
|
||||
#define REG_IS_SRC(addr) (((addr / 4) < TOTAL_SRC_CH_REGS))
|
||||
#define REG_IS_SYS(addr) (((addr / 4) < TOTAL_SYS_CH_REGS))
|
||||
// 分区低字节按4通道连续排列,每通道占用TOTAL_xxx_CH_REGS个地址
|
||||
#define REG_IS_SINK(addr) ((addr) < (TOTAL_SINK_CH_REGS * 4U))
|
||||
#define REG_IS_SRC(addr) ((addr) < (TOTAL_SRC_CH_REGS * 4U))
|
||||
#define REG_IS_SYS(addr) ((addr) < (TOTAL_SYS_CH_REGS * 4U))
|
||||
|
||||
// 根据地址提取通道号和区块内偏移
|
||||
#define REG_GET_SINK_CH(addr) ((addr) / TOTAL_SINK_CH_REGS)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/****************************************************************************
|
||||
文件名称 : chrg_lcd.c
|
||||
完成日期 :
|
||||
当前版本号 : V1.0
|
||||
当前版本号 : V1.1.24
|
||||
主要功能 : 实现与显示屏交互,向屏更新数据与接收屏控制数据,以独立线程处理。
|
||||
版本历史 : 创建原始版本
|
||||
说明 :
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/****************************************************************************
|
||||
文件名称 : chrg_lcd.h
|
||||
完成日期 :
|
||||
当前版本号 : V1.0
|
||||
当前版本号 : V1.1.24
|
||||
主要功能 : 实现与显示屏交互,向屏更新数据与接收屏控制数据。
|
||||
版本历史 : 创建原始版本
|
||||
说明 :
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/****************************************************************************
|
||||
文件名称 : chrg_north.c
|
||||
完成日期 :
|
||||
当前版本号 : V1.1.14
|
||||
当前版本号 : V1.1.24
|
||||
主要功能 : 实现北向通信交互,包括接收命令解析,发送请求命令,切换通路。以独立线程处理。
|
||||
版本历史 : 创建原始版本
|
||||
说明 :
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/****************************************************************************
|
||||
文件名称 : chrg_north.h
|
||||
完成日期 :
|
||||
当前版本号 : V1.1.22
|
||||
当前版本号 : V1.1.24
|
||||
主要功能 : 实现北向通信交互,包括接收命令解析,发送请求命令,切换通路。以独立线程处理。
|
||||
版本历史 : 创建原始版本
|
||||
说明 :
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/****************************************************************************
|
||||
文件名称 : chrg_roll_nor.c
|
||||
完成日期 :
|
||||
当前版本号 : V1.1.14
|
||||
当前版本号 : 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_roll_nor.h
|
||||
完成日期 :
|
||||
当前版本号 : V1.1.14
|
||||
当前版本号 : V1.1.24
|
||||
主要功能 : 实现北向通信轮巡请求命令。以独立线程处理。
|
||||
版本历史 : 创建原始版本
|
||||
说明 :
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/****************************************************************************
|
||||
文件名称 : chrg_roll_sou.c
|
||||
完成日期 :
|
||||
当前版本号 : V1.1.23
|
||||
当前版本号 : V1.1.31
|
||||
主要功能 : 实现南向通信轮巡请求命令。以独立线程处理。
|
||||
版本历史 : 创建原始版本
|
||||
说明 :
|
||||
@@ -25,7 +25,7 @@
|
||||
|
||||
#define SOU_MUTEX_TIMEOUT_MS 100
|
||||
#define SOU_RESPONSE_TIMEOUT_MS 20
|
||||
#define SOU_COM_MAX_ATTEMPTS 3
|
||||
#define SOU_COM_MAX_ATTEMPTS 10
|
||||
#define SOU_COM_RETRY_YIELD_MS 1U
|
||||
#define SOU_REL_SWITCH_DELAY_MS 100U
|
||||
#define SOU_CHANNEL_BIT(ch) ((rt_uint8_t)(1U << (ch)))
|
||||
@@ -168,23 +168,7 @@ int chrg_sou_com_batch_submit(eIDX_SOU_CH ch, const rt_uint16_t *regs,
|
||||
pBatch->cur_idx = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* 电流调节采用最新值有效策略。若同一通道仍有尚未发送的电流命令,
|
||||
* 直接覆盖旧值,避免四通道快速测试时队列积累过时的电流设置。
|
||||
* 当前命令已经发送时不覆盖,保证响应仍与原命令匹配。
|
||||
*/
|
||||
if ((count == 1) && (regs[0] == (REG_CURRENT_OUT + 1))) {
|
||||
for (i = pBatch->cur_idx; i < pBatch->reg_cnt; i++) {
|
||||
if (pBatch->reg_list[i] == regs[0]) {
|
||||
pBatch->val_list[i] = vals[0];
|
||||
pBatch->pending = RT_TRUE;
|
||||
pROLL->run = RUN_COM;
|
||||
rt_mutex_release(pTHR->mutex);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 电流命令与其它写命令一致,完整追加并等待回码,不再覆盖旧命令。 */
|
||||
if ((pBatch->reg_cnt > SOU_COM_BATCH_REG_MAX) ||
|
||||
(count > (SOU_COM_BATCH_REG_MAX - pBatch->reg_cnt))) {
|
||||
LOG_E("sou com batch reg full: ch=%d queued=%d append=%d max=%d",
|
||||
@@ -923,10 +907,13 @@ void chrg_roll_sou_thread_entry (void *data)
|
||||
measure_once = RT_TRUE;
|
||||
response_part = MB_R_PART1;
|
||||
chrg_led_flashing(IDX_LED3, TIMES_ONE, PULSE_TIME*2, PULSE_TIME*2);
|
||||
if (idx != (rt_uint8_t)pROLL->idx) {
|
||||
pROLL->idx = (eIDX_SOU_CH)idx;
|
||||
chrg_south_switch((eIDX_SOU_CH)idx);
|
||||
/* 插入命令可能改变物理选通,每次自动查询前必须重新选择通道。 */
|
||||
if (chrg_south_switch((eIDX_SOU_CH)idx) != 0) {
|
||||
sou_measure_once_finish(idx);
|
||||
rt_thread_mdelay(1);
|
||||
continue;
|
||||
}
|
||||
pROLL->idx = (eIDX_SOU_CH)idx;
|
||||
if (g_sou_version_ready[idx] == 0U) {
|
||||
version_probe = RT_TRUE;
|
||||
chrg_eload_read_version(ID_ELOAD);
|
||||
@@ -943,11 +930,14 @@ void chrg_roll_sou_thread_entry (void *data)
|
||||
continue;
|
||||
} else { // 通道启用
|
||||
chrg_led_flashing(IDX_LED3, TIMES_ONE, PULSE_TIME*2, PULSE_TIME*2);
|
||||
if (idx != (rt_uint8_t)pROLL->idx) {
|
||||
pROLL->idx = (eIDX_SOU_CH)idx;
|
||||
chrg_south_switch((eIDX_SOU_CH)idx);
|
||||
pROLL->part = MB_R_PART1;
|
||||
/* 不信任缓存通道,发送普通轮询前重新写入选通GPIO。 */
|
||||
if (chrg_south_switch((eIDX_SOU_CH)idx) != 0) {
|
||||
CHRG_CHANNEL_NEXT(index);
|
||||
rt_thread_mdelay(1);
|
||||
continue;
|
||||
}
|
||||
pROLL->idx = (eIDX_SOU_CH)idx;
|
||||
pROLL->part = response_part;
|
||||
if (g_sou_version_ready[idx] == 0U) {
|
||||
version_probe = RT_TRUE;
|
||||
chrg_eload_read_version(ID_ELOAD);
|
||||
@@ -962,7 +952,11 @@ void chrg_roll_sou_thread_entry (void *data)
|
||||
break;
|
||||
|
||||
case RUN_LCD: {
|
||||
chrg_south_switch((eIDX_SOU_CH)single_ch);
|
||||
if (chrg_south_switch((eIDX_SOU_CH)single_ch) != 0) {
|
||||
sou_single_command_finish(run);
|
||||
continue;
|
||||
}
|
||||
pROLL->idx = (eIDX_SOU_CH)single_ch;
|
||||
chrg_eload_write_reg(ID_ELOAD, single_reg, single_value);
|
||||
}
|
||||
break;
|
||||
@@ -976,9 +970,17 @@ void chrg_roll_sou_thread_entry (void *data)
|
||||
}
|
||||
batch_ch = command_ch;
|
||||
command_valid = RT_TRUE;
|
||||
chrg_south_switch((eIDX_SOU_CH)command_ch);
|
||||
/* COM队列通道必须与物理选通一致,选通失败时禁止发送本条命令。 */
|
||||
if (chrg_south_switch((eIDX_SOU_CH)command_ch) != 0) {
|
||||
sou_com_command_failed(batch_ch, command_reg, command_value,
|
||||
"channel switch", &retry_count[batch_ch]);
|
||||
continue;
|
||||
}
|
||||
pROLL->idx = (eIDX_SOU_CH)command_ch;
|
||||
#if SOUTH_COMMAND_DEBUG
|
||||
rt_kprintf("ch=%d",command_ch);
|
||||
rt_kprintf("[SOU_CMD] queue_ch=%u phy_ch=%u reg=0x%04X value=%u\r\n",
|
||||
command_ch + 1U, chrgsouth.idx + 1U,
|
||||
command_reg, command_value);
|
||||
#endif
|
||||
chrg_eload_write_reg(ID_ELOAD, command_reg, command_value);
|
||||
}
|
||||
@@ -995,7 +997,14 @@ void chrg_roll_sou_thread_entry (void *data)
|
||||
rt_thread_mdelay(1);
|
||||
continue;
|
||||
}
|
||||
chrg_south_switch((eIDX_SOU_CH)single_ch);
|
||||
if (chrg_south_switch((eIDX_SOU_CH)single_ch) != 0) {
|
||||
rt_mutex_take(pTHR->mutex, RT_WAITING_FOREVER);
|
||||
pROLL->updata_result = -1;
|
||||
pROLL->send_flag = 0;
|
||||
rt_mutex_release(pTHR->mutex);
|
||||
continue;
|
||||
}
|
||||
pROLL->idx = (eIDX_SOU_CH)single_ch;
|
||||
ret = chrg_eload_send_ymodem_data(pROLL->updata_buf, pROLL->leng);
|
||||
|
||||
rt_mutex_take(pTHR->mutex, RT_WAITING_FOREVER);
|
||||
@@ -1007,7 +1016,11 @@ void chrg_roll_sou_thread_entry (void *data)
|
||||
}
|
||||
|
||||
case RUN_CONSOLE: {
|
||||
chrg_south_switch((eIDX_SOU_CH)single_ch);
|
||||
if (chrg_south_switch((eIDX_SOU_CH)single_ch) != 0) {
|
||||
sou_single_command_finish(run);
|
||||
continue;
|
||||
}
|
||||
pROLL->idx = (eIDX_SOU_CH)single_ch;
|
||||
chrg_eload_refresh(ID_ELOAD, single_part);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/****************************************************************************
|
||||
文件名称 : chrg_roll_sou.h
|
||||
完成日期 :
|
||||
当前版本号 : V1.1.21
|
||||
当前版本号 : V1.1.24
|
||||
主要功能 : 实现南向通信轮巡请求命令。以独立线程处理。
|
||||
版本历史 : 创建原始版本
|
||||
说明 :
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/****************************************************************************
|
||||
文件名称 : chrg_south.c
|
||||
完成日期 :
|
||||
当前版本号 : V1.0
|
||||
当前版本号 : V1.1.31
|
||||
主要功能 : 实现南向通信交互,包括接收命令解析,发送请求命令,切换通路。以独立线程处理。
|
||||
版本历史 : 创建原始版本
|
||||
说明 :
|
||||
@@ -141,6 +141,10 @@ int chrg_south_switch (eIDX_SOU_CH ch)
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
/* 仅在GPIO选通成功后更新物理通道,供发送日志和轮询校验使用。 */
|
||||
if (ret == 0) {
|
||||
chrgsouth.idx = ch;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/****************************************************************************
|
||||
文件名称 : chrg_south.h
|
||||
完成日期 :
|
||||
当前版本号 : V1.0
|
||||
当前版本号 : V1.1.24
|
||||
主要功能 : 实现南向通信交互,包括接收命令解析,发送请求命令,切换通路。以独立线程处理。
|
||||
版本历史 : 创建原始版本
|
||||
说明 :
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/****************************************************************************
|
||||
文件名称 : chrg_thread.c
|
||||
完成日期 :
|
||||
当前版本号 : V1.0
|
||||
当前版本号 : V1.1.24
|
||||
主要功能 : 启动多个业务线程
|
||||
版本历史 : 创建原始版本
|
||||
说明 :
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/****************************************************************************
|
||||
文件名称 : chrg_thread.h
|
||||
完成日期 :
|
||||
当前版本号 : V1.0
|
||||
当前版本号 : V1.1.24
|
||||
主要功能 : 统一管理业务线程,业务线程信息定义。
|
||||
版本历史 : 创建原始版本
|
||||
说明 :
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/****************************************************************************
|
||||
文件名称 : chrg_def.h
|
||||
完成日期 :
|
||||
当前版本号 : V1.0
|
||||
当前版本号 : V1.1.32
|
||||
主要功能 : 全局宏定义,常量,及结构体。
|
||||
版本历史 : 创建原始版本
|
||||
说明 :
|
||||
@@ -12,6 +12,12 @@
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
/* CHRG application version. Keep this value synchronized with the changelog. */
|
||||
#define CHRG_VERSION_MAJOR 1U
|
||||
#define CHRG_VERSION_MINOR 1U
|
||||
#define CHRG_VERSION_PATCH 32U
|
||||
#define CHRG_VERSION_STRING "V1.1.32"
|
||||
|
||||
/*
|
||||
* Channel polling mode:
|
||||
* 1 - multi-channel hardware, advance the polling channel index;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/****************************************************************************
|
||||
文件名称 : chrg_eload.c
|
||||
完成日期 :
|
||||
当前版本号 : V1.1.22
|
||||
当前版本号 : V1.1.24
|
||||
主要功能 : 源载命令数据解析,封装,读写请求。
|
||||
版本历史 : 创建原始版本
|
||||
说明 :
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/****************************************************************************
|
||||
文件名称 : chrg_eload.h
|
||||
完成日期 :
|
||||
当前版本号 : V1.1.22
|
||||
当前版本号 : V1.1.28
|
||||
主要功能 : 源载命令数据解析,封装,读写请求,寄存器定义,数据结构定义。
|
||||
版本历史 : 创建原始版本
|
||||
说明 :
|
||||
@@ -61,6 +61,9 @@ static const rt_uint8_t LOAD[30] = {
|
||||
#define STA1_READY (0x01) // 就绪/停止
|
||||
#define STA1_RUNNING (0x02) // 运行
|
||||
#define STA1_FAULT (0x03) // 故障
|
||||
#define STA1_SHORT_TEST (0x05) // 短路测试中
|
||||
#define STA1_OCP_TEST (0x06) // OCP测试中
|
||||
#define STA1_DYNA_TEST (0x07) // 动态测试中
|
||||
#define REG_CV 0X07 // 电压地址
|
||||
|
||||
#define REG_REL_ON (0X01) // 主继电器控制寄存器
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/****************************************************************************
|
||||
文件名称 : chrg_north_pkg.c
|
||||
完成日期 :
|
||||
当前版本号 : V1.0
|
||||
当前版本号 : V1.1.24
|
||||
主要功能 : 北向数据编码、解码。
|
||||
版本历史 : 创建原始版本
|
||||
说明 :
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/****************************************************************************
|
||||
文件名称 : chrg_sink.c
|
||||
完成日期 :
|
||||
当前版本号 : V1.1.24
|
||||
当前版本号 : V1.1.28
|
||||
主要功能 : 北向数据sink请求数据填充及发送。
|
||||
版本历史 : 创建原始版本
|
||||
说明 :
|
||||
@@ -25,15 +25,19 @@
|
||||
#define SINK_UNLOAD_CONFIRM_COUNT 2U // 连续满足低电流条件的量测帧数
|
||||
#define SINK_SHORT_KEEPALIVE_MS 30U // 短路测试WORK_START保活下发周期
|
||||
#define SINK_INIT_NORTH_RELAY_DELAY_MS 30U // 辅助继电器回码后打开北向继电器的等待时间
|
||||
#define SINK_TEST_STATUS_RETRY_MAX 3U // 测试态退出确认的连续重发计数上限
|
||||
|
||||
#define SINK_INIT_STAGE_CLEAR_RELAY 0U
|
||||
#define SINK_INIT_STAGE_AUX_RELAY 1U
|
||||
#define SINK_INIT_STAGE_DELAY 2U
|
||||
#define SINK_INIT_STAGE_REST 3U
|
||||
#define SINK_INIT_STAGE_TEST_STOP 0U
|
||||
#define SINK_INIT_STAGE_TEST_STATUS 1U
|
||||
#define SINK_INIT_STAGE_AUX_RELAY 2U
|
||||
#define SINK_INIT_STAGE_DELAY 3U
|
||||
#define SINK_INIT_STAGE_REST 4U
|
||||
|
||||
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属正常)
|
||||
@@ -51,12 +55,51 @@ static rt_tick_t g_sink_unload_query_tick[TOTAL_SOU_CHS] = {0};
|
||||
static rt_uint8_t g_sink_unload_confirm_count[TOTAL_SOU_CHS] = {0};
|
||||
/* 记录各通道短路测试最近一次WORK_START的发送时间。 */
|
||||
static rt_tick_t g_sink_short_start_tick[TOTAL_SOU_CHS] = {0};
|
||||
/* 锁存关机前的短路状态,防止关机过程中影子参数覆盖测试状态。 */
|
||||
static rt_bool_t g_sink_stop_from_short[TOTAL_SOU_CHS] = {RT_FALSE};
|
||||
/* 只消费新的V_On电压采样,避免同一帧重复计入稳定确认。 */
|
||||
static rt_uint32_t g_sink_von_voltage_seq[TOTAL_SOU_CHS] = {0};
|
||||
/* 协议切换期间清零,避免旧电压样本累计成启动确认。 */
|
||||
static rt_uint8_t g_sink_von_stable_count[TOTAL_SOU_CHS] = {0};
|
||||
/* 自动停止带载后的恢复确认计数,独立于首次握手的电压确认计数。 */
|
||||
static rt_uint8_t g_sink_load_restart_confirm_count[TOTAL_SOU_CHS] = {0};
|
||||
static rt_uint32_t g_sink_init_test_sample_seq[TOTAL_SOU_CHS] = {0};
|
||||
static rt_uint8_t g_sink_init_test_stop_retry[TOTAL_SOU_CHS] = {0};
|
||||
static rt_uint32_t g_sink_stop_test_sample_seq[TOTAL_SOU_CHS] = {0};
|
||||
static rt_uint8_t g_sink_stop_test_stop_retry[TOTAL_SOU_CHS] = {0};
|
||||
static rt_bool_t g_sink_stop_test_confirmed[TOTAL_SOU_CHS] = {RT_FALSE};
|
||||
|
||||
static rt_uint8_t chrg_sink_power_status_get(eIDX_SOU_CH idx)
|
||||
{
|
||||
rt_uint16_t status1;
|
||||
|
||||
if (idx >= TOTAL_SOU_CHS) {
|
||||
return 0U;
|
||||
}
|
||||
status1 = chrgsouth.eload[idx].status1;
|
||||
if (((status1 & 0x00FFU) == 0U) && ((status1 >> 8) != 0U)) {
|
||||
status1 >>= 8;
|
||||
}
|
||||
return (rt_uint8_t)status1;
|
||||
}
|
||||
|
||||
static rt_bool_t chrg_sink_power_test_active(eIDX_SOU_CH idx)
|
||||
{
|
||||
rt_uint8_t status1 = chrg_sink_power_status_get(idx);
|
||||
|
||||
return (status1 == STA1_SHORT_TEST) ||
|
||||
(status1 == STA1_OCP_TEST) ||
|
||||
(status1 == STA1_DYNA_TEST);
|
||||
}
|
||||
|
||||
static rt_bool_t chrg_sink_test_exit_required(eIDX_SOU_CH idx,
|
||||
const struct chrg_switch_t *pSW)
|
||||
{
|
||||
return chrg_sink_power_test_active(idx) ||
|
||||
((pSW != RT_NULL) &&
|
||||
((pSW->sink.test.test_mode != SINK_NO_TEST) ||
|
||||
(pSW->sink.test.test_mode_old != SINK_NO_TEST)));
|
||||
}
|
||||
|
||||
enum {
|
||||
SINK_UNLOAD_NEXT_RUNNING = 0,
|
||||
@@ -256,8 +299,8 @@ static rt_uint8_t chrg_sink_init_build_commands(struct chrg_switch_t *pSW,
|
||||
{
|
||||
rt_uint8_t count;
|
||||
|
||||
regs[0] = ModbusRTU_ShortTest_CMD_MODE_FLAG;
|
||||
vals[0] = ModbusRTU_DYNA_CMD_MODE_STOP;
|
||||
regs[0] = REG_WORK;
|
||||
vals[0] = WORK_STOP;
|
||||
if (pSW->sink.test.test_mode_old == SINK_TEST_SHORT) {
|
||||
regs[1] = REG_REL_ON; vals[1] = ALL_REL_OFF;
|
||||
regs[2] = REG_REL_ON; vals[2] = FU_REL_ON;
|
||||
@@ -291,14 +334,16 @@ 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]) {
|
||||
case SINK_INIT_STAGE_CLEAR_RELAY:
|
||||
case SINK_INIT_STAGE_TEST_STOP:
|
||||
start = 0U;
|
||||
count = 1U;
|
||||
break;
|
||||
@@ -313,7 +358,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;
|
||||
}
|
||||
|
||||
/*****************************************************************
|
||||
@@ -334,22 +383,23 @@ static int chrg_sink_work_init(eIDX_SOU_CH idx, struct chrg_switch_t *pSW)
|
||||
return -1;
|
||||
}
|
||||
g_sink_init_in_progress[idx] = RT_TRUE;
|
||||
g_sink_init_stage[idx] = SINK_INIT_STAGE_CLEAR_RELAY;
|
||||
/* 功率板回读处于Short/OCP/DYNA时,先用WORK_STOP退出测试态。 */
|
||||
g_sink_init_stage[idx] = chrg_sink_test_exit_required(idx, pSW) ?
|
||||
SINK_INIT_STAGE_TEST_STOP : SINK_INIT_STAGE_AUX_RELAY;
|
||||
g_sink_init_test_sample_seq[idx] = 0U;
|
||||
g_sink_init_test_stop_retry[idx] = 0U;
|
||||
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,11 +433,37 @@ 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);
|
||||
}
|
||||
if (g_sink_init_stage[idx] == SINK_INIT_STAGE_CLEAR_RELAY) {
|
||||
if (g_sink_init_stage[idx] == SINK_INIT_STAGE_TEST_STOP) {
|
||||
g_sink_init_stage[idx] = SINK_INIT_STAGE_TEST_STATUS;
|
||||
g_sink_init_test_sample_seq[idx] = chrg_eload_get_sample_seq(idx);
|
||||
return (chrg_sou_measure_once_submit(idx) == 0) ? 0 : -1;
|
||||
}
|
||||
if (g_sink_init_stage[idx] == SINK_INIT_STAGE_TEST_STATUS) {
|
||||
rt_uint32_t sample_seq = chrg_eload_get_sample_seq(idx);
|
||||
|
||||
if (sample_seq == g_sink_init_test_sample_seq[idx]) {
|
||||
return (chrg_sou_measure_once_submit(idx) == 0) ? 0 : -1;
|
||||
}
|
||||
g_sink_init_test_sample_seq[idx] = sample_seq;
|
||||
if (chrg_sink_power_test_active(idx)) {
|
||||
if (g_sink_init_test_stop_retry[idx] >=
|
||||
SINK_TEST_STATUS_RETRY_MAX) {
|
||||
/* 达到一轮上限后重新计数,但仍保持在安全确认流程。 */
|
||||
g_sink_init_test_stop_retry[idx] = 0U;
|
||||
}
|
||||
g_sink_init_test_stop_retry[idx]++;
|
||||
g_sink_init_stage[idx] = SINK_INIT_STAGE_TEST_STOP;
|
||||
return chrg_sink_init_submit_stage(idx, pSW);
|
||||
}
|
||||
g_sink_init_test_stop_retry[idx] = 0U;
|
||||
g_sink_init_stage[idx] = SINK_INIT_STAGE_AUX_RELAY;
|
||||
return chrg_sink_init_submit_stage(idx, pSW);
|
||||
}
|
||||
@@ -400,6 +476,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;
|
||||
@@ -624,27 +701,54 @@ static int chrg_sink_work_low_aux_wait(eIDX_SOU_CH idx,
|
||||
输入参数: idx:南向功率通道编号 pSW:当前通道控制结构体
|
||||
输出参数: 清除运行、使能和在线标志,关闭北向继电器
|
||||
返回说明: 0:关机成功 <0:停止命令提交失败
|
||||
其它说明: 先断开功率继电器并发送WORK_STOP,再关闭软件通道
|
||||
其它说明: 功率板处于测试态时先发送WORK_STOP;短路兼容退出命令随后发送
|
||||
*****************************************************************/
|
||||
static int chrg_sink_work_stop_prepare(eIDX_SOU_CH idx,
|
||||
struct chrg_switch_t *pSW)
|
||||
{
|
||||
rt_uint16_t reg = REG_WORK;
|
||||
rt_uint16_t value = WORK_STOP;
|
||||
rt_uint16_t regs[3];
|
||||
rt_uint16_t values[3];
|
||||
rt_uint8_t count = 0U;
|
||||
rt_bool_t was_short;
|
||||
rt_bool_t power_test_active;
|
||||
rt_bool_t preserve_test_retry;
|
||||
|
||||
if ((idx >= TOTAL_SOU_CHS) || (pSW == RT_NULL)) {
|
||||
return -1;
|
||||
}
|
||||
preserve_test_retry = (pSW->sink.work_mode == SINK_WORK_STOP_WAIT) &&
|
||||
!g_sink_stop_test_confirmed[idx] &&
|
||||
(g_sink_stop_test_stop_retry[idx] != 0U);
|
||||
power_test_active = chrg_sink_power_test_active(idx);
|
||||
was_short = (power_test_active &&
|
||||
(chrg_sink_power_status_get(idx) == STA1_SHORT_TEST)) ||
|
||||
(pSW->sink.test.test_mode_old == SINK_TEST_SHORT) ||
|
||||
(pSW->sink.test.test_mode == SINK_TEST_SHORT) ||
|
||||
g_sink_stop_from_short[idx];
|
||||
g_sink_stop_from_short[idx] = was_short;
|
||||
g_sink_stop_test_sample_seq[idx] = 0U;
|
||||
if (!preserve_test_retry) {
|
||||
g_sink_stop_test_stop_retry[idx] = 0U;
|
||||
}
|
||||
g_sink_stop_test_confirmed[idx] = RT_FALSE;
|
||||
/* WORK_STOP必须是退出Short/OCP/DYNA的第一条南向命令。 */
|
||||
regs[count] = REG_WORK;
|
||||
values[count++] = WORK_STOP;
|
||||
if (was_short) {
|
||||
regs[count] = ModbusRTU_ShortTest_CMD_MODE_FLAG;
|
||||
values[count++] = ModbusRTU_DYNA_CMD_MODE_STOP;
|
||||
}
|
||||
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;
|
||||
}
|
||||
if (chrg_sou_com_batch_submit(idx, ®, &value, 1U) != 0) {
|
||||
if (chrg_sou_com_batch_submit(idx, regs, values, count) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* 主动关机先停止电子负载。WORK_STOP收到匹配回码后,必须通过
|
||||
* 停止命令之后的新P1量测连续确认低电流,才允许断开功率继电器。 */
|
||||
/* 短路退出和WORK_STOP全部收到匹配回码后,必须通过停止命令之后的
|
||||
* 新P1量测连续确认低电流,才允许断开功率继电器。 */
|
||||
chrg_sink_unload_confirm_reset(idx);
|
||||
pSW->sink.work_mode = SINK_WORK_STOP_WAIT;
|
||||
return 0;
|
||||
@@ -691,6 +795,10 @@ static int chrg_sink_work_stop_relay_wait(eIDX_SOU_CH idx,
|
||||
pNOR->enable[idx] = 0;
|
||||
g_sink_rel_main_closed[idx] = 0;
|
||||
g_sink_rel_main_ready[idx] = 0;
|
||||
g_sink_short_start_tick[idx] = 0U;
|
||||
g_sink_stop_from_short[idx] = RT_FALSE;
|
||||
pSW->sink.test.test_mode = SINK_NO_TEST;
|
||||
pSW->sink.test.test_mode_old = SINK_NO_TEST;
|
||||
|
||||
chrg_nor_sw_rel((eIDX_NOR_CH)idx, 0);
|
||||
/* 主动停止已经完成,退出异步等待状态,禁止下一轮重复执行。 */
|
||||
@@ -715,6 +823,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_TEST_STOP;
|
||||
g_sink_init_north_relay_tick[idx] = 0U;
|
||||
|
||||
ret = chrg_sou_com_batch_submit(idx, ®, &value, 1);
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
@@ -851,6 +966,30 @@ static int chrg_sink_work_current_wait(eIDX_SOU_CH idx,
|
||||
return chrg_sink_work_protocol_unload(idx, pSW);
|
||||
}
|
||||
|
||||
if ((next_action == SINK_UNLOAD_NEXT_STOP_RELAY) &&
|
||||
!g_sink_stop_test_confirmed[idx]) {
|
||||
rt_uint32_t test_sample_seq = chrg_eload_get_sample_seq(idx);
|
||||
|
||||
if (g_sink_stop_test_sample_seq[idx] == 0U) {
|
||||
g_sink_stop_test_sample_seq[idx] = test_sample_seq;
|
||||
return (chrg_sou_measure_once_submit(idx) == 0) ? 0 : -1;
|
||||
}
|
||||
if (test_sample_seq == g_sink_stop_test_sample_seq[idx]) {
|
||||
return (chrg_sou_measure_once_submit(idx) == 0) ? 0 : -1;
|
||||
}
|
||||
g_sink_stop_test_sample_seq[idx] = test_sample_seq;
|
||||
if (chrg_sink_power_test_active(idx)) {
|
||||
if (g_sink_stop_test_stop_retry[idx] >=
|
||||
SINK_TEST_STATUS_RETRY_MAX) {
|
||||
/* 达到一轮上限后重新计数,但仍保持在安全确认流程。 */
|
||||
g_sink_stop_test_stop_retry[idx] = 0U;
|
||||
}
|
||||
g_sink_stop_test_stop_retry[idx]++;
|
||||
return chrg_sink_work_stop_prepare(idx, pSW);
|
||||
}
|
||||
g_sink_stop_test_confirmed[idx] = RT_TRUE;
|
||||
}
|
||||
|
||||
if (!g_sink_unload_batch_confirmed[idx]) {
|
||||
/* 从最后一条写回码之后建立基线,排除RUN_COM之前残留的旧量测。 */
|
||||
g_sink_unload_sample_seq[idx] = chrg_eload_get_sample_seq(idx);
|
||||
@@ -1007,11 +1146,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 +1326,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 +1340,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) &&
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/****************************************************************************
|
||||
文件名称 : chrg_sink.c
|
||||
完成日期 :
|
||||
当前版本号 : V1.1.23
|
||||
当前版本号 : V1.1.24
|
||||
主要功能 : 北向数据sink请求数据填充及发送,命令字定义。
|
||||
版本历史 : 创建原始版本
|
||||
说明 :
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/****************************************************************************
|
||||
文件名称 : chrg_source.c
|
||||
完成日期 :
|
||||
当前版本号 : V1.1.14
|
||||
当前版本号 : V1.1.24
|
||||
主要功能 : 北向数据source请求数据填充及发送。
|
||||
版本历史 : 创建原始版本
|
||||
说明 :
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/****************************************************************************
|
||||
文件名称 : chrg_source.c
|
||||
完成日期 :
|
||||
当前版本号 : V1.1.14
|
||||
当前版本号 : V1.1.24
|
||||
主要功能 : 北向数据source请求数据填充及发送,命令字定义。
|
||||
版本历史 : 创建原始版本
|
||||
说明 :
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/****************************************************************************
|
||||
文件名称 : chrg_utils.c
|
||||
完成日期 :
|
||||
当前版本号 : V1.0
|
||||
当前版本号 : V1.1.24
|
||||
主要功能 : 一些通用数据封装,功能接口。
|
||||
版本历史 : 创建原始版本
|
||||
说明 :
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/****************************************************************************
|
||||
文件名称 : chrg_utils.h
|
||||
完成日期 :
|
||||
当前版本号 : V1.0
|
||||
当前版本号 : V1.1.24
|
||||
主要功能 : 一些通用数据封装,功能接口。
|
||||
版本历史 : 创建原始版本
|
||||
说明 :
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
*** Using Compiler 'V6.16', folder: 'D:\Program Files\Keil_v5\ARM\ARMCLANG\Bin'
|
||||
Build target 'chrg'
|
||||
compiling main.c...
|
||||
compiling chrg_switch.c...
|
||||
compiling chrg_vcom.c...
|
||||
compiling chrg_rel.c...
|
||||
compiling chrg_roll_nor.c...
|
||||
compiling chrg_north.c...
|
||||
compiling chrg_south.c...
|
||||
compiling chrg_comm.c...
|
||||
compiling chrg_roll_sou.c...
|
||||
compiling chrg_lcd.c...
|
||||
compiling chrg_thread.c...
|
||||
compiling chrg_source.c...
|
||||
compiling chrg_sink.c...
|
||||
compiling chrg_north_pkg.c...
|
||||
compiling chrg_eload.c...
|
||||
linking...
|
||||
Program Size: Code=152916 RO-data=15924 RW-data=9356 ZI-data=16188
|
||||
FromELF: creating hex file...
|
||||
After Build - User command #1: fromelf --bin .\build\keil\Obj\chrg.axf -o build/chrg.bin
|
||||
".\build\keil\Obj\chrg.axf" - 0 Error(s), 0 Warning(s).
|
||||
Build Time Elapsed: 00:00:07
|
||||
+15
-49
@@ -1,49 +1,15 @@
|
||||
\t (00:00:01) allegro 17.2 S079 Windows SPB 64-bit Edition
|
||||
\t (00:00:01) Journal start - Tue Sep 15 20:16:48 2026
|
||||
\t (00:00:01) Host=DESKTOP-5RA9F3K User=Adminuser Pid=20076 CPUs=20
|
||||
\t (00:00:01) CmdLine= D:\Cadence\SPB_17.2\tools\bin\allegro.exe
|
||||
\t (00:00:01)
|
||||
(00:00:01) Loading axlcore.cxt
|
||||
\t (00:00:02) Starting new design...
|
||||
\i (00:00:04) trapsize 29310
|
||||
\i (00:00:05) generaledit
|
||||
\i (00:00:12) open
|
||||
\i (00:00:13) fillin "HC_DFCD_Protocol_V3_0.brd"
|
||||
\i (00:00:13) trapsize 1230
|
||||
\i (00:00:13) QtSignal SPBFoldDockArea FoldAreaTabWidget currentChanged unnamed
|
||||
\t (00:00:13) Opening existing design...
|
||||
\i (00:00:13) trapsize 2757
|
||||
\d (00:00:13) Design opened: D:/HC-PMP-SW/Power_ControlPannel/MP_Control_sw_405/MP_SW_Chrg/chrg/docs/HC_DFCD_Protocol_V3_0.brd
|
||||
\i (00:00:13) generaledit
|
||||
\i (00:00:14) zoom out 1
|
||||
\i (00:00:14) setwindow pcb
|
||||
\i (00:00:14) zoom out 17.5318 56.5185
|
||||
\i (00:00:14) trapsize 5515
|
||||
\i (00:00:14) zoom out 1
|
||||
\i (00:00:14) setwindow pcb
|
||||
\i (00:00:14) zoom out 21.9438 59.0553
|
||||
\i (00:00:14) trapsize 11030
|
||||
\i (00:00:14) zoom out 1
|
||||
\i (00:00:14) setwindow pcb
|
||||
\i (00:00:14) zoom out 64.3442 57.9524
|
||||
\i (00:00:14) trapsize 22060
|
||||
\i (00:00:17) open
|
||||
\i (00:00:20) fillin "menu_cancel"
|
||||
\i (00:00:20) generaledit
|
||||
\i (00:00:20) zoom in 1
|
||||
\i (00:00:20) setwindow pcb
|
||||
\i (00:00:20) zoom in 19.5632 59.7117
|
||||
\i (00:00:20) trapsize 11030
|
||||
\i (00:00:20) zoom in 1
|
||||
\i (00:00:20) setwindow pcb
|
||||
\i (00:00:20) zoom in 11.6217 57.0646
|
||||
\i (00:00:20) trapsize 5515
|
||||
\i (00:00:22) open
|
||||
\i (00:00:26) fillin "menu_cancel"
|
||||
\i (00:00:26) generaledit
|
||||
\i (00:00:26) QtSignal SPBFoldDockArea FoldAreaTabWidget currentChanged "Start Page"
|
||||
\i (00:00:28) QtSignal SPBFoldDockArea FoldAreaTabWidget currentChanged HC_DFCD_Protocol_V3_0
|
||||
\i (00:00:28) opencd D:/HC-PMP-SW/Power_ControlPannel/MP_Control_sw_405/south/HC_DFCD_Source_Eload_V1_1/PCB/HC_DFCD_Source_Eload_V1_1.brd
|
||||
\t (00:00:28) Opening existing design...
|
||||
\i (00:00:29) trapsize 283
|
||||
\t (00:00:29) Journal end - Tue Sep 15 20:17:15 2026
|
||||
\t (00:00:05) allegro 17.2 S079 Windows SPB 64-bit Edition
|
||||
\t (00:00:05) Journal start - Wed Sep 16 22:17:09 2026
|
||||
\t (00:00:05) Host=DESKTOP-5RA9F3K User=Adminuser Pid=19892 CPUs=20
|
||||
\t (00:00:05) CmdLine= D:\Cadence\SPB_17.2\tools\bin\allegro.exe
|
||||
\t (00:00:05)
|
||||
(00:00:05) Loading axlcore.cxt
|
||||
\t (00:00:06) Starting new design...
|
||||
\i (00:00:06) trapsize 29310
|
||||
\i (00:00:07) generaledit
|
||||
\i (00:00:08) trapsize 1230
|
||||
\i (00:00:08) QtSignal SPBFoldDockArea FoldAreaTabWidget currentChanged unnamed
|
||||
\i (00:00:08) opencd D:/HC-PMP-SW/Power_ControlPannel/MP_Control_sw_405/south/HC_DFCD_Source_Eload_V1_1/PCB/HC_DFCD_Source_Eload_V1_1.brd
|
||||
\t (00:00:08) Opening existing design...
|
||||
\i (00:00:08) trapsize 283
|
||||
\t (00:00:08) Journal end - Wed Sep 16 22:17:12 2026
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+46
-96
@@ -1,105 +1,55 @@
|
||||
\t (00:00:06) allegro 17.2 S079 Windows SPB 64-bit Edition
|
||||
\t (00:00:06) Journal start - Fri Sep 11 15:37:07 2026
|
||||
\t (00:00:06) Host=DESKTOP-5RA9F3K User=Adminuser Pid=13160 CPUs=20
|
||||
\t (00:00:06) Journal start - Tue Sep 15 20:16:48 2026
|
||||
\t (00:00:06) Host=DESKTOP-5RA9F3K User=Adminuser Pid=8232 CPUs=20
|
||||
\t (00:00:06) CmdLine= D:\Cadence\SPB_17.2\tools\bin\allegro.exe
|
||||
\t (00:00:06)
|
||||
(00:00:06) Loading axlcore.cxt
|
||||
\t (00:00:06) Starting new design...
|
||||
\i (00:00:07) trapsize 29310
|
||||
\i (00:00:08) generaledit
|
||||
\i (00:00:11) open
|
||||
\i (00:00:12) fillin "HC_DFCD_Protocol_V3_0.brd"
|
||||
\i (00:00:12) trapsize 1230
|
||||
\i (00:00:12) QtSignal SPBFoldDockArea FoldAreaTabWidget currentChanged unnamed
|
||||
\t (00:00:12) Opening existing design...
|
||||
\i (00:00:12) trapsize 2757
|
||||
\d (00:00:12) Design opened: D:/HC-PMP-SW/Power_ControlPannel/MP_Control_sw_405/MP_SW_Chrg/chrg/docs/HC_DFCD_Protocol_V3_0.brd
|
||||
\t (00:00:07) Starting new design...
|
||||
\i (00:00:09) trapsize 29310
|
||||
\i (00:00:10) generaledit
|
||||
\i (00:00:18) xhilite
|
||||
\i (00:00:18) xname_flush
|
||||
\i (00:00:18) done
|
||||
\i (00:00:19) generaledit
|
||||
\i (00:00:33) xhilite
|
||||
\i (00:00:34) xname_flush
|
||||
\i (00:00:34) done
|
||||
\i (00:00:34) generaledit
|
||||
\i (00:20:00) exit
|
||||
\e (00:20:00) Do you want to save the changes you made to unnamed.brd?
|
||||
\i (12:51:55) fillin no
|
||||
\t (12:51:56) Journal end - Wed Sep 16 09:08:37 2026
|
||||
|
||||
\i (00:00:13) generaledit
|
||||
\i (00:00:13) zoom out 1
|
||||
\i (00:00:13) setwindow pcb
|
||||
\i (00:00:13) zoom out 27.8998 58.3935
|
||||
\i (00:00:13) trapsize 5515
|
||||
\i (00:00:13) zoom out 1
|
||||
\i (00:00:13) setwindow pcb
|
||||
\i (00:00:13) zoom out 27.7896 58.0627
|
||||
\i (00:00:13) trapsize 11030
|
||||
\i (00:00:13) zoom out 1
|
||||
\i (00:00:13) setwindow pcb
|
||||
\i (00:00:13) zoom out 96.9925 57.6215
|
||||
\i (00:00:13) trapsize 22060
|
||||
\i (00:00:13) zoom out 1
|
||||
\i (00:00:13) setwindow pcb
|
||||
\i (00:00:13) zoom out 299.2792 77.8006
|
||||
\i (00:00:13) trapsize 44119
|
||||
\i (00:00:13) zoom out 1
|
||||
\i (00:00:13) setwindow pcb
|
||||
\i (00:00:13) zoom out 710.9119 236.1887
|
||||
\i (00:00:13) trapsize 88239
|
||||
\i (00:00:13) zoom out 1
|
||||
\i (00:00:13) setwindow pcb
|
||||
\i (00:00:13) zoom out 1546.5306 547.6707
|
||||
\i (00:00:13) trapsize 176477
|
||||
\i (00:00:14) zoom in 1
|
||||
\i (00:00:14) zoom out 1
|
||||
\i (00:00:14) setwindow pcb
|
||||
\i (00:00:14) zoom in 101.1838 -64.7046
|
||||
\i (00:00:14) trapsize 88239
|
||||
\i (00:00:14) zoom in 1
|
||||
\i (00:00:14) setwindow pcb
|
||||
\i (00:00:14) zoom in 99.4190 -62.9398
|
||||
\i (00:00:14) trapsize 44119
|
||||
\i (00:00:14) zoom in 1
|
||||
\i (00:00:14) setwindow pcb
|
||||
\i (00:00:14) zoom in 92.3600 -31.1739
|
||||
\i (00:00:14) trapsize 22060
|
||||
\i (00:00:14) zoom in 1
|
||||
\i (00:00:14) setwindow pcb
|
||||
\i (00:00:14) zoom in 92.3600 -30.7327
|
||||
\i (00:00:14) trapsize 11030
|
||||
\i (00:00:14) zoom in 1
|
||||
\i (00:00:14) setwindow pcb
|
||||
\i (00:00:14) zoom in 92.3600 -30.5121
|
||||
\i (00:00:14) zoom out 17.5318 56.5185
|
||||
\i (00:00:14) trapsize 5515
|
||||
\i (00:00:15) drag_start grid 110.6695 -6.4671
|
||||
\i (00:00:15) drag_stop 188.9811 -20.1441
|
||||
\i (00:00:15) zoom out 1
|
||||
\i (00:00:15) setwindow pcb
|
||||
\i (00:00:15) zoom out 102.1765 2.3567
|
||||
\i (00:00:15) trapsize 11030
|
||||
\i (00:00:15) zoom out 1
|
||||
\i (00:00:15) setwindow pcb
|
||||
\i (00:00:15) zoom out 102.3972 1.6950
|
||||
\i (00:00:15) trapsize 22060
|
||||
\i (00:00:15) zoom out 1
|
||||
\i (00:00:15) setwindow pcb
|
||||
\i (00:00:15) zoom out 104.6031 47.3583
|
||||
\i (00:00:15) trapsize 44119
|
||||
\i (00:00:16) zoom in 1
|
||||
\i (00:00:16) setwindow pcb
|
||||
\i (00:00:16) zoom in -19.8131 37.6521
|
||||
\i (00:00:16) trapsize 22060
|
||||
\i (00:00:16) zoom in 1
|
||||
\i (00:00:16) setwindow pcb
|
||||
\i (00:00:16) zoom in -5.2538 42.5053
|
||||
\i (00:00:16) trapsize 11030
|
||||
\i (00:00:16) zoom in 1
|
||||
\i (00:00:16) setwindow pcb
|
||||
\i (00:00:16) zoom in -5.2537 42.7259
|
||||
\i (00:00:16) trapsize 5515
|
||||
\i (00:00:17) zoom in 1
|
||||
\i (00:00:17) setwindow pcb
|
||||
\i (00:00:17) zoom in 48.1306 62.4692
|
||||
\i (00:00:17) trapsize 2757
|
||||
\i (00:00:14) zoom out 1
|
||||
\i (00:00:14) setwindow pcb
|
||||
\i (00:00:14) zoom out 21.9438 59.0553
|
||||
\i (00:00:14) trapsize 11030
|
||||
\i (00:00:14) zoom out 1
|
||||
\i (00:00:14) setwindow pcb
|
||||
\i (00:00:14) zoom out 64.3442 57.9524
|
||||
\i (00:00:14) trapsize 22060
|
||||
\i (00:00:17) open
|
||||
\i (00:00:20) fillin "menu_cancel"
|
||||
\i (00:00:20) generaledit
|
||||
\i (00:00:20) zoom in 1
|
||||
\i (00:00:20) setwindow pcb
|
||||
\i (00:00:20) zoom in 64.2893 72.1203
|
||||
\i (00:00:20) trapsize 1379
|
||||
\i (00:00:21) zoom out 1
|
||||
\i (00:00:21) setwindow pcb
|
||||
\i (00:00:21) zoom out 61.4492 70.2728
|
||||
\i (00:00:21) trapsize 2757
|
||||
\i (00:00:21) zoom out 1
|
||||
\i (00:00:21) setwindow pcb
|
||||
\i (00:00:21) zoom out 58.1402 66.3021
|
||||
\i (00:00:21) trapsize 5515
|
||||
\i (00:10:52) exit
|
||||
\t (00:10:53) Journal end - Fri Sep 11 15:47:54 2026
|
||||
\i (00:00:20) zoom in 19.5632 59.7117
|
||||
\i (00:00:20) trapsize 11030
|
||||
\i (00:00:20) zoom in 1
|
||||
\i (00:00:20) setwindow pcb
|
||||
\i (00:00:20) zoom in 11.6217 57.0646
|
||||
\i (00:00:20) trapsize 5515
|
||||
\i (00:00:22) open
|
||||
\i (00:00:26) fillin "menu_cancel"
|
||||
\i (00:00:26) generaledit
|
||||
\i (00:00:26) QtSignal SPBFoldDockArea FoldAreaTabWidget currentChanged "Start Page"
|
||||
\i (00:00:28) QtSignal SPBFoldDockArea FoldAreaTabWidget currentChanged HC_DFCD_Protocol_V3_0
|
||||
\i (00:00:28) opencd D:/HC-PMP-SW/Power_ControlPannel/MP_Control_sw_405/south/HC_DFCD_Source_Eload_V1_1/PCB/HC_DFCD_Source_Eload_V1_1.brd
|
||||
\t (00:00:28) Opening existing design...
|
||||
\i (00:00:29) trapsize 283
|
||||
\t (00:00:29) Journal end - Tue Sep 15 20:17:15 2026
|
||||
|
||||
@@ -1,5 +1,87 @@
|
||||
# 修改日志
|
||||
|
||||
## V1.1.32 - 2026-09-17
|
||||
|
||||
### 版本号管理
|
||||
|
||||
- 协议板版本寄存器 `0x0300` 的版本编码移至 `chrg_comm.c` 管理,当前返回 `0x0130`(V1.1.32)。
|
||||
- 应用启动日志版本更新为 `V1.1.32`。
|
||||
|
||||
## V1.1.26 - 2026-09-17
|
||||
|
||||
### 修复Sink角色往返时初始化上下文残留
|
||||
|
||||
- Source切回Sink时清除旧Sink初始化阶段、提交标记和延时计时;重新执行清短路及继电器等完整初始化,避免角色切换回码被误判为旧初始化成功。
|
||||
- 应用版本更新为 `V1.1.26`,对外固件版本寄存器 `0x0300` 为 `0x012A`;Bootloader不变。
|
||||
|
||||
## V1.1.25 - 2026-09-17
|
||||
|
||||
### 修复Sink重复启动及退出Short时初始化卡住
|
||||
|
||||
- 同角色Sink参数生效只复制PC可写配置,不再覆盖实时work_mode、sub、On_work、test_mode_old及量测数据。
|
||||
- 初始化/退出Short期间,相同运行请求继续原事务,不重复取消批次;不同配置返回Modbus忙(异常码0x06),PC需等待后重新发送参数生效。停止流程未完成时也拒绝新运行请求。
|
||||
- 已开始的初始化收到重复INIT时恢复到INIT_AUX_WAIT,避免被last_state去重卡住;停止和掉电保护允许抢占初始化。
|
||||
- 按阶段记录初始化命令是否入队,入队失败或批次失败时重试当前阶段,禁止用上一阶段的成功结果跳过未发送的命令。
|
||||
- 重复/拒绝的Sink配置不再无条件递增北向配置版本,避免连续参数生效导致有效回码被反复丢弃。
|
||||
- STOP入队失败后由北向轮询继续重试,不依赖On_work或通道使能。
|
||||
- 应用版本V1.1.25,对外寄存器0x0300返回0x0129;Bootloader不变。不修改Von门槛、串口超时和南向队列容量。
|
||||
- 增加主机回归测试tests/sink_init(运行真实状态机及COM生效函数,模拟南向批次和时钟)。硬件仍需验证单/四通道循环启停、反复Short进入退出、通信超时恢复及停止安全性。
|
||||
|
||||
## V1.1.24 - 2026-09-15
|
||||
|
||||
### 统一应用版本定义
|
||||
|
||||
- CHRG应用版本统一为 `V1.1.24`,版本信息集中定义在 `chrg_def.h`。
|
||||
- 上位机读取寄存器 `0x0300` 返回 `0x0128`。
|
||||
- `apps/chrg` 各C源文件和头文件的文件头版本统一为 `V1.1.24`。
|
||||
- Bootloader版本保持 `V1.0.0` 不变。
|
||||
- 后续每次修改应用代码时,必须同步更新应用版本号、对外版本编码和本修改日志。
|
||||
## V1.1.31 - 2026-09-16
|
||||
|
||||
### 通道保护代码注释
|
||||
|
||||
- 补充上位机地址解码、非法通道初值、跨通道写保护的中文注释。
|
||||
- 补充南向物理选通同步、自动轮询重新选通及电流命令顺序入队的中文注释。
|
||||
- 协议板版本号更新为 `V1.1.31`,固件版本寄存器更新为 `0x012F`。
|
||||
|
||||
## V1.1.30 - 2026-09-16
|
||||
|
||||
### 南向通道选择与地址校验
|
||||
|
||||
- 南向物理选通成功后统一记录 `chrgsouth.idx`,自动轮询每次发送前重新选通目标通道。
|
||||
- COM、LCD、升级和控制台发送路径同步更新当前通道,选通失败时禁止继续发送。
|
||||
- 单寄存器写初始化通道变量,并通过统一解码函数拒绝非法分区和越界地址。
|
||||
- 多寄存器写按每通道50个地址计算通道,并拒绝跨通道写入。
|
||||
- `SOUTH_COMMAND_DEBUG` 日志增加队列通道、实际物理通道、寄存器和值。
|
||||
- 协议板版本号更新为 `V1.1.30`,固件版本寄存器更新为 `0x012E`。
|
||||
|
||||
## V1.1.29 - 2026-09-16
|
||||
|
||||
### 取消电流命令覆盖去重
|
||||
|
||||
- 删除南向队列对未发送电流命令的覆盖逻辑。
|
||||
- 同一通道新增的电流设置按提交顺序逐条发送,并分别等待功率板回码。
|
||||
- 协议板版本号更新为 `V1.1.29`,固件版本寄存器更新为 `0x012D`。
|
||||
- 待验证:快速连续设置电流时,确认每条电流命令都能在南向日志和功率板侧收到。
|
||||
|
||||
## V1.1.28 - 2026-09-16
|
||||
|
||||
### 测试态退出结果确认
|
||||
|
||||
- 初始化发送 `WORK_STOP` 后,通过新的 `P1` 量测重新读取功率板 `status1`。
|
||||
- 只有确认 `status1` 不再是 `0x05/0x06/0x07`,才继续打开辅助继电器和后续初始化命令。
|
||||
- 关机流程同样在关闭南向继电器前确认测试态已退出;每连续重发 `WORK_STOP` 3 次后重新计数,仍未退出时保持安全等待并继续重试。
|
||||
- 协议板版本号更新为 `V1.1.28`,固件版本寄存器更新为 `0x012C`。
|
||||
|
||||
## V1.1.27 - 2026-09-16
|
||||
|
||||
### 功率板测试状态退出保护
|
||||
|
||||
- 新增功率板 `status1=0x05/0x06/0x07` 的 Short、OCP、DYNA 状态定义。
|
||||
- 初始化前识别功率板测试状态,优先发送 `WORK_STOP` 后再继续初始化。
|
||||
- 负载关机流程调整为 `WORK_STOP` 优先,避免测试退出命令被后续启动状态覆盖。
|
||||
- 上位机版本寄存器 `0x0300` 更新为 `0x012B`(`V1.1.27`)。
|
||||
|
||||
## V1.1.23 - 2026-09-11
|
||||
|
||||
### 负载初始化继电器时序调整
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,28 @@
|
||||
# Sink 初始化回归验证
|
||||
|
||||
## 主机测试
|
||||
|
||||
在仓库根目录执行(需要 Node.js 和本机 GCC):
|
||||
|
||||
```powershell
|
||||
node tests/sink_init/run.cjs C:/Qt/Tools/mingw1310_64/bin/gcc.exe
|
||||
```
|
||||
|
||||
测试编译真实 `chrg_sink.c`、从 COM 提取的配置生效函数和北向状态调度片段;只模拟时钟、南向批次、继电器及无关外设。每个场景独立进程,临时产物自动清理。
|
||||
|
||||
14 个用例覆盖:旧影子配置保留实时状态、重复退出 Short、初始化中配置变化返回忙、重复 INIT 恢复、初始化中停止、首批/后续阶段入队失败、批次失败重试、完整初始化后再次退出 Short、重复/拒绝请求不改变配置版本、停止入队失败后台重试、Sink 初始化中切换角色后重新初始化。
|
||||
|
||||
主机测试不能验证实际串口回码匹配、线程竞争、继电器时序或功率板执行结果。
|
||||
|
||||
## 硬件验收(尚未执行)
|
||||
|
||||
使用现有 PC 指令和安全负载,先单通道,再四通道同时重复以下场景:
|
||||
|
||||
1. 普通 5V/1A 启停、Short 进入/退出各循环至少 100 次;退出期间重复发送同一参数生效请求。预期退出初始化持续推进,最终可恢复带载。
|
||||
2. 初始化期间修改配置并生效。预期返回 Modbus 忙(异常码 `0x06`),PC 在初始化完成后重试;旧事务参数及北向回码推进不被覆盖。
|
||||
3. 在各初始化阶段发送停止;短时断开南向通信后恢复。预期停止优先、未完成阶段重试,不以旧成功结果提前进入 WAIT。
|
||||
4. 初始化未完成时切 Source,再切回 Sink。预期重新清短路、配置继电器和负载参数,不复用旧初始化阶段。
|
||||
|
||||
用 Keil Watch 观察 `sink.work_mode`、`sink.On_work`、`sink.test.test_mode_old`、`g_sink_init_in_progress`、`g_sink_init_stage`、`g_sink_init_stage_submitted`、`sub` 和 `config_version`;避免高频打印。结合南向回码及实测电流确认执行,不能仅以入队成功作为验收依据。
|
||||
|
||||
本次应用版本为 **V1.1.26**,对外固件版本寄存器 `0x0300` 为 `0x012A`;Bootloader 不变。
|
||||
@@ -0,0 +1,210 @@
|
||||
/* 本文件由 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;
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
#include "rtthread.h"
|
||||
@@ -0,0 +1 @@
|
||||
#include "rtthread.h"
|
||||
@@ -0,0 +1,37 @@
|
||||
#ifndef HOST_RTTHREAD_H
|
||||
#define HOST_RTTHREAD_H
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
typedef uint8_t rt_uint8_t;
|
||||
typedef int8_t rt_int8_t;
|
||||
typedef uint16_t rt_uint16_t;
|
||||
typedef int16_t rt_int16_t;
|
||||
typedef uint32_t rt_uint32_t;
|
||||
typedef int32_t rt_int32_t;
|
||||
typedef uintptr_t rt_ubase_t;
|
||||
typedef intptr_t rt_base_t;
|
||||
typedef size_t rt_size_t;
|
||||
typedef int rt_bool_t;
|
||||
typedef int rt_err_t;
|
||||
typedef uint32_t rt_tick_t;
|
||||
typedef void *rt_device_t;
|
||||
typedef void *rt_mutex_t;
|
||||
typedef void *rt_event_t;
|
||||
typedef void *rt_sem_t;
|
||||
typedef void *rt_mailbox_t;
|
||||
typedef void *rt_mq_t;
|
||||
#define RT_NULL NULL
|
||||
#define RT_TRUE 1
|
||||
#define RT_FALSE 0
|
||||
#define RT_WAITING_FOREVER (-1)
|
||||
#define RT_TICK_PER_SECOND 1000
|
||||
#define rt_memcpy memcpy
|
||||
#define rt_memcmp memcmp
|
||||
#define rt_memset memset
|
||||
rt_tick_t rt_tick_get(void);
|
||||
rt_tick_t rt_tick_from_millisecond(rt_int32_t ms);
|
||||
int rt_kprintf(const char *format, ...);
|
||||
rt_err_t rt_mutex_take(rt_mutex_t mutex, rt_int32_t timeout);
|
||||
rt_err_t rt_mutex_release(rt_mutex_t mutex);
|
||||
#endif
|
||||
@@ -0,0 +1,62 @@
|
||||
// 使用真实 Sink 实现及 COM 生效函数;仅替换时钟、继电器和南向传输。
|
||||
// node tests/sink_init/run.cjs [gcc路径]。临时编译产物不写入固件工程。
|
||||
const fs = require('node:fs');
|
||||
const os = require('node:os');
|
||||
const path = require('node:path');
|
||||
const cp = require('node:child_process');
|
||||
const root = path.resolve(__dirname, '../..');
|
||||
const app = path.join(root, 'apps/chrg/applications');
|
||||
const cc = process.argv[2] || process.env.CC || 'gcc';
|
||||
if (path.isAbsolute(cc)) process.env.PATH = path.dirname(cc) + path.delimiter + process.env.PATH;
|
||||
const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'chrg-sink-test-'));
|
||||
const source = fs.readFileSync(path.join(app, 'thread/chrg_comm.c'), 'utf8');
|
||||
function definition(name) {
|
||||
const pattern = new RegExp('static\\s+[\\w]+\\s+' + name + '\\s*\\([^;{]*\\)\\s*\\{', 'g');
|
||||
const match = pattern.exec(source);
|
||||
if (!match) return '';
|
||||
let depth = 1, end = pattern.lastIndex;
|
||||
while (depth && end < source.length) {
|
||||
if (source[end] === '{') depth++;
|
||||
if (source[end] === '}') depth--;
|
||||
end++;
|
||||
}
|
||||
return source.slice(match.index, end);
|
||||
}
|
||||
const type = source.match(/typedef struct\s*\{[^}]*\}\s*chrg_param_diff_t;/)[0];
|
||||
const functions = ['chrg_comm_get_param_diff', 'chrg_comm_sink_config_equal',
|
||||
'chrg_comm_copy_sink_config', 'chrg_comm_handle_sink_load_current',
|
||||
'chrg_sink_diff_send_reg', 'chrg_comm_apply_sink_effect', 'chrg_mb_write_sys'];
|
||||
const roll = fs.readFileSync(path.join(app, 'thread/chrg_roll_nor.c'), 'utf8');
|
||||
const dispatch = roll.slice(roll.indexOf('void chrg_roll_nor_thread_entry'))
|
||||
.match(/if \(\(pSW->id == ID_SOURCE\)[\s\S]+?state_work_ret = chrg_sink_work[\s\S]+?\n\t\t\t\}/)[0];
|
||||
const unit = '#include "' + path.join(app, 'utils/chrg_sink.c').replaceAll('\\', '/') + '"\n' +
|
||||
'#include "chrg_thread.h"\n#define LOG_E(...) ((void)0)\n' +
|
||||
'static rt_uint8_t g_shadow_dirty[4], last_pd_pro[4];\n#define SOURCE_PD_STATE_UNKNOWN 255\n' +
|
||||
'static eMBException chrg_comm_apply_source_effect(rt_uint8_t ch, struct chrg_switch_t *p, const struct chrg_switch_t *s);\n' +
|
||||
type + '\n' + functions.map(definition).join('\n') + '\n' +
|
||||
'static int poll_state(struct chrg_switch_t *pSW) { int idx=0, state_work_ret=0;\n' + dispatch + '\nreturn state_work_ret; }\n' +
|
||||
fs.readFileSync(path.join(__dirname, 'cases.c'), 'utf8');
|
||||
const scenarios = ['duplicate_exit', 'preserve_runtime', 'busy_changed_config',
|
||||
'recover_init', 'stop_during_init', 'first_submit_failure', 'stage_submit_failure',
|
||||
'failed_batch_retry', 'complete_then_restart', 'duplicate_version',
|
||||
'busy_version', 'stop_submit_retry', 'rest_submit_failure', 'role_roundtrip'];
|
||||
try {
|
||||
fs.writeFileSync(path.join(dir, 'test.c'), unit);
|
||||
const exe = path.join(dir, process.platform === 'win32' ? 'test.exe' : 'test');
|
||||
const args = ['-std=c99', '-O0', '-ffunction-sections', '-fdata-sections',
|
||||
'-Werror=implicit-function-declaration', '-Wl,--gc-sections',
|
||||
'-I' + __dirname, ...['utils', 'thread', 'bsp'].map(p => '-I' + path.join(app, p)),
|
||||
path.join(dir, 'test.c'), '-o', exe];
|
||||
const build = cp.spawnSync(cc, args, {encoding: 'utf8'});
|
||||
if (build.status !== 0) throw Error(build.stderr || String(build.error || build.status));
|
||||
let failed = 0;
|
||||
for (const name of scenarios) {
|
||||
const run = cp.spawnSync(exe, [name], {encoding: 'utf8'});
|
||||
console.log((run.status === 0 ? 'PASS ' : 'FAIL ') + name);
|
||||
if (run.status !== 0) { failed++; console.log(run.stdout + run.stderr); }
|
||||
}
|
||||
console.log(`${scenarios.length - failed}/${scenarios.length} passed`);
|
||||
process.exitCode = failed ? 1 : 0;
|
||||
} finally {
|
||||
fs.rmSync(dir, {recursive: true, force: true});
|
||||
}
|
||||
Reference in New Issue
Block a user