fix: 修复南向分包、线程通信和批量下发逻辑
1. apps/chrg/debug_hot.ini: 增加调试断点配置 2. apps/chrg/applications/thread/chrg_north.h: 开启北向调试日志 3. 修正多个头文件函数返回值类型,从void改为int 4. 重构chrg_thread.c: 新增mb消息释放函数,优化邮箱发送逻辑 5. 重写chrg_south.c: 修复分包越界和内存泄漏,增加帧超时处理 6. 重构chrg_sink.c: 统一批量下发接口,修正初始化和运行逻辑 7. 重写chrg_comm.c: 修复系统寄存器写入逻辑,增加通道激活校验 8. 重构chrg_north.c: 修复北向分包越界和内存泄漏,增加超时处理和诊断命令 9. 重构chrg_roll_sou.c: 重构批量下发逻辑,增加重试机制和错误处理
This commit is contained in:
@@ -65,7 +65,7 @@ struct chrg_comm_t chrgcomm = {
|
||||
|
||||
static void chrg_mb_write_sink(rt_uint8_t ch, rt_uint16_t reg_offset, rt_uint16_t sou_value, struct chrg_switch_t *pSW);
|
||||
static void chrg_mb_write_src(rt_uint8_t ch, rt_uint16_t reg_offset, rt_uint16_t sou_value, struct chrg_switch_t *pSW);
|
||||
static void chrg_mb_write_sys(rt_uint8_t ch, rt_uint16_t reg_offset, rt_uint16_t sou_value, struct chrg_switch_t *pSW, struct chrg_north_t *pNOR, struct chrg_south_t *pSOU);
|
||||
static eMBException chrg_mb_write_sys(rt_uint8_t ch, rt_uint16_t reg_offset, rt_uint16_t sou_value, struct chrg_switch_t *pSW, struct chrg_north_t *pNOR, struct chrg_south_t *pSOU);
|
||||
|
||||
/*! \brief Function to set bits in a byte buffer.
|
||||
*
|
||||
@@ -960,7 +960,10 @@ eMBException funcWriteHoldingRegister (rt_uint8_t *reqFrame, rt_uint16_t reqLen,
|
||||
}
|
||||
else if (regAddress_H == HOLD_REG_SYS_BASE)
|
||||
{
|
||||
chrg_mb_write_sys(ch, reg_offset, sou_value, pSW, pNOR, pSOU);
|
||||
eStatus = chrg_mb_write_sys(ch, reg_offset, sou_value, pSW, pNOR, pSOU);
|
||||
if (eStatus != MB_EX_NONE) {
|
||||
return eStatus;
|
||||
}
|
||||
}
|
||||
|
||||
build_response:
|
||||
@@ -1355,23 +1358,23 @@ eMBException funcSinkTest (rt_uint8_t *reqFrame, rt_uint16_t reqLen,
|
||||
rt_kprintf("test_flag=%d\n",pTset->test_mode);
|
||||
#endif
|
||||
/*********************************************************/
|
||||
switch(test_mode)
|
||||
{
|
||||
case 0x01:
|
||||
// 短路测试(OCPC)
|
||||
sink_test_short_set(pSW, pData, devStatus);
|
||||
break;
|
||||
case 0x02:
|
||||
// OCP 测试
|
||||
sink_test_ocp_set(pSW, pData, devStatus);
|
||||
break;
|
||||
case 0x03:
|
||||
// 动态测试
|
||||
sink_test_dynamic_set(pSW, pData, devStatus);
|
||||
break;
|
||||
default:
|
||||
return MB_EX_ILLEGAL_FUNCTION;
|
||||
}
|
||||
// switch(test_mode)
|
||||
// {
|
||||
// case 0x01:
|
||||
// // 短路测试(OCPC)
|
||||
// sink_test_short_set(pSW, pData, devStatus);
|
||||
// break;
|
||||
// case 0x02:
|
||||
// // OCP 测试
|
||||
// sink_test_ocp_set(pSW, pData, devStatus);
|
||||
// break;
|
||||
// case 0x03:
|
||||
// // 动态测试
|
||||
// sink_test_dynamic_set(pSW, pData, devStatus);
|
||||
// break;
|
||||
// default:
|
||||
// return MB_EX_ILLEGAL_FUNCTION;
|
||||
// }
|
||||
/************ 启动 / 停止控制 ************/
|
||||
if(devStatus == 0) //启动
|
||||
{
|
||||
@@ -1515,7 +1518,10 @@ eMBException funcWriteMultipleHoldingRegister (rt_uint8_t *reqFrame, rt_uint16_t
|
||||
}
|
||||
else if (regAddress_H == HOLD_REG_SYS_BASE)
|
||||
{
|
||||
chrg_mb_write_sys(ch, ch_reg_offset, sou_value, pSW, pNOR, pSOU);
|
||||
eStatus = chrg_mb_write_sys(ch, ch_reg_offset, sou_value, pSW, pNOR, pSOU);
|
||||
if (eStatus != MB_EX_NONE) {
|
||||
return eStatus;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2210,7 +2216,7 @@ static void chrg_mb_write_src(rt_uint8_t ch, rt_uint16_t reg_offset, rt_uint16_t
|
||||
//rt_kprintf("ret_offset = %d, value = %d",reg_offset,sou_value);
|
||||
}
|
||||
|
||||
static void chrg_mb_write_sys(rt_uint8_t ch, rt_uint16_t reg_offset, rt_uint16_t sou_value,
|
||||
static eMBException chrg_mb_write_sys(rt_uint8_t ch, rt_uint16_t reg_offset, rt_uint16_t sou_value,
|
||||
struct chrg_switch_t *pSW, struct chrg_north_t *pNOR, struct chrg_south_t *pSOU)
|
||||
{
|
||||
struct chrg_comm_t *pCOMM = &chrgcomm;
|
||||
@@ -2231,19 +2237,36 @@ static void chrg_mb_write_sys(rt_uint8_t ch, rt_uint16_t reg_offset, rt_uint16_t
|
||||
case SYS_REG_PARAM_EFFECT: // 0x01: 参数生效标志
|
||||
if (sou_value == 0x01)
|
||||
{
|
||||
g_shadow_dirty[ch] = 0; // 标记已生效
|
||||
|
||||
struct chrg_switch_t *pReal = &pNOR->sw[ch];
|
||||
rt_uint8_t pro_change = 0;
|
||||
sink_proto_diff_t diff_info;
|
||||
chrg_sink_get_proto_diff(pReal, pSW, &diff_info, &pro_change);
|
||||
eIDX_ID old_id = pReal->id;
|
||||
eIDX_ID new_id = pReal->id;
|
||||
rt_uint16_t sink_work = pSW->sink.Now_State;
|
||||
rt_uint16_t source_work = pSW->source.Now_State;
|
||||
//rt_uint8_t old_sink_test = pReal->sink.test.test_mode;
|
||||
struct chrg_thread_t *pTHR_NOR = &chrgthr[IDX_THR_ROLL_NOR];
|
||||
rt_mutex_take(pTHR_NOR->mutex, RT_WAITING_FOREVER);
|
||||
|
||||
eIDX_ID old_id = pReal->id;
|
||||
eIDX_ID new_id = pSW->id;
|
||||
rt_bool_t old_active = RT_FALSE;
|
||||
if (old_id == ID_SOURCE) {
|
||||
old_active = (pReal->source.On_Flag || pReal->source.Now_State);
|
||||
} else if (old_id == ID_SINK) {
|
||||
old_active = (pReal->sink.On_work || pReal->sink.Now_State);
|
||||
}
|
||||
|
||||
if ((old_id != new_id) && old_active) {
|
||||
rt_mutex_release(pTHR_NOR->mutex);
|
||||
LOG_W("CH%d direction change rejected while active: %d -> %d",
|
||||
ch + 1, old_id, new_id);
|
||||
return MB_EX_SLAVE_BUSY;
|
||||
}
|
||||
|
||||
g_shadow_dirty[ch] = 0;
|
||||
chrg_sink_get_proto_diff(pReal, pSW, &diff_info, &pro_change);
|
||||
rt_uint16_t sink_work = pSW->sink.Now_State;
|
||||
rt_uint16_t source_work = pSW->source.Now_State;
|
||||
rt_uint8_t old_cv_mode = pReal->CV_mode;
|
||||
rt_uint16_t old_loadv = pReal->sink.loadv;
|
||||
rt_uint16_t old_loadc = pReal->sink.loadc;
|
||||
//rt_uint8_t old_sink_test = pReal->sink.test.test_mode;
|
||||
rt_memcpy(pReal, &g_shadow_sw[ch], sizeof(struct chrg_switch_t));
|
||||
if (new_id == ID_SINK)
|
||||
{
|
||||
@@ -2288,7 +2311,14 @@ static void chrg_mb_write_sys(rt_uint8_t ch, rt_uint16_t reg_offset, rt_uint16_t
|
||||
else
|
||||
{
|
||||
// 仅下发差异寄存器
|
||||
chrg_sink_diff_send_reg((eIDX_SOU_CH)ch, &diff_info, pReal);
|
||||
if (chrg_sink_diff_send_reg((eIDX_SOU_CH)ch, &diff_info, pReal) != 0) {
|
||||
pReal->CV_mode = old_cv_mode;
|
||||
pReal->sink.loadv = old_loadv;
|
||||
pReal->sink.loadc = old_loadc;
|
||||
g_shadow_dirty[ch] = 1;
|
||||
rt_mutex_release(pTHR_NOR->mutex);
|
||||
return MB_EX_SLAVE_BUSY;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2298,7 +2328,11 @@ static void chrg_mb_write_sys(rt_uint8_t ch, rt_uint16_t reg_offset, rt_uint16_t
|
||||
pReal->sink.On_work = 0;
|
||||
pReal->sink.work_mode = SINK_WORK_STOP;
|
||||
}
|
||||
chrg_sink_work(ch, pReal);
|
||||
if (chrg_sink_work(ch, pReal) != 0) {
|
||||
g_shadow_dirty[ch] = 1;
|
||||
rt_mutex_release(pTHR_NOR->mutex);
|
||||
return MB_EX_SLAVE_BUSY;
|
||||
}
|
||||
}
|
||||
else if (new_id == ID_SOURCE && source_work == 0x01)
|
||||
{
|
||||
@@ -2315,6 +2349,8 @@ static void chrg_mb_write_sys(rt_uint8_t ch, rt_uint16_t reg_offset, rt_uint16_t
|
||||
rt_kprintf("[SYS CH%d] Unknown reg offset=0x%02X\n", ch + 1, reg_offset);
|
||||
break;
|
||||
}
|
||||
|
||||
return MB_EX_NONE;
|
||||
}
|
||||
void chrg_sink_get_proto_diff(struct chrg_switch_t *pReal,
|
||||
struct chrg_switch_t *pShadow,
|
||||
@@ -2335,23 +2371,31 @@ void chrg_sink_get_proto_diff(struct chrg_switch_t *pReal,
|
||||
!pDiff->ccset_changed && !pDiff->cvmode_changed) ? 0 : 1;
|
||||
|
||||
}
|
||||
void chrg_sink_diff_send_reg(eIDX_SOU_CH ch, sink_proto_diff_t *pDiff, struct chrg_switch_t *pReal)
|
||||
int chrg_sink_diff_send_reg(eIDX_SOU_CH ch, sink_proto_diff_t *pDiff, struct chrg_switch_t *pReal)
|
||||
{
|
||||
chrg_sou_com_sou_set();
|
||||
rt_uint16_t regs[2];
|
||||
rt_uint16_t vals[2];
|
||||
rt_uint8_t count = 0;
|
||||
|
||||
if (pReal->CV_mode == 0x01) {
|
||||
if (pDiff->volt_changed)
|
||||
{
|
||||
chrg_sou_com_batch_add_reg(ch, REG_VOLTAGE_OUT+1, pReal->sink.loadv);
|
||||
}
|
||||
}else{
|
||||
if (pDiff->curr_changed)
|
||||
{
|
||||
chrg_sou_com_batch_add_reg(ch, REG_CURRENT_OUT+1, pReal->sink.loadc);
|
||||
if (pDiff->volt_changed) {
|
||||
regs[count] = REG_VOLTAGE_OUT + 1;
|
||||
vals[count++] = pReal->sink.loadv;
|
||||
}
|
||||
} else if (pDiff->curr_changed) {
|
||||
regs[count] = REG_CURRENT_OUT + 1;
|
||||
vals[count++] = pReal->sink.loadc;
|
||||
}
|
||||
if (pDiff->cvmode_changed) {
|
||||
chrg_sou_com_batch_add_reg(ch, REG_MODE, pReal->CV_mode);
|
||||
regs[count] = REG_MODE;
|
||||
vals[count++] = pReal->CV_mode;
|
||||
}
|
||||
|
||||
if ((count > 0) && (chrg_sou_com_batch_submit(ch, regs, vals, count) != 0)) {
|
||||
LOG_E("CH%d sink diff batch submit failed", ch + 1);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -228,7 +228,7 @@ extern void chrg_comm_thread_entry (void *data);
|
||||
|
||||
extern rt_uint8_t chrg_com_sink_on(rt_uint8_t ch, struct chrg_switch_t *pSW, rt_uint8_t *enable);
|
||||
extern rt_uint8_t chrg_com_source_on(rt_uint8_t ch, rt_uint8_t protoCmd, struct chrg_switch_t *pSW, rt_uint8_t *enable);
|
||||
extern void chrg_sink_diff_send_reg(eIDX_SOU_CH ch, sink_proto_diff_t *pDiff, struct chrg_switch_t *pReal);
|
||||
extern int chrg_sink_diff_send_reg(eIDX_SOU_CH ch, sink_proto_diff_t *pDiff, struct chrg_switch_t *pReal);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -269,13 +269,14 @@ static void chrg_north_handle_Seting_Volt(rt_uint8_t *frame_data, rt_uint16_t fr
|
||||
struct chrg_north_t chrgnorth = {
|
||||
.devname = DEV_NAME_NORTH, // 设备名
|
||||
.tty = RT_NULL, // 串口句柄初始为空
|
||||
.enable = {0, 0, 0, 0}, // 4个通道使能初始关闭
|
||||
.enable = {1, 0, 0, 0}, // 4个通道使能初始关闭
|
||||
.free_flag = 1,
|
||||
// 通道1(IDX_NOR_CH1)初始化
|
||||
.sw[IDX_NOR_CH1] = {
|
||||
.CV_mode = 2,
|
||||
.change_flag = 0,
|
||||
.show_step = 0,
|
||||
.sub = IDX_GET_SINK_VC,
|
||||
.id = ID_SINK, // 初始为负载模式
|
||||
.source = { // 电源侧参数初始化
|
||||
.On_Flag = 0, // 启动标志初始关闭
|
||||
@@ -374,7 +375,7 @@ int chrg_north_send (rt_uint8_t *data, rt_size_t length)
|
||||
|
||||
if (RT_NULL != pTTY) {
|
||||
#if DEBUG_NORTH //是否打印
|
||||
// LOG_HEX("sendN", 32, data, length);
|
||||
LOG_HEX("sendN", 32, data, length);
|
||||
#endif
|
||||
ret = chrg_tty_send(pTTY, data, length);
|
||||
}
|
||||
@@ -406,22 +407,8 @@ static int chrg_north_frame_head (struct rt_ringbuffer *rb, rt_uint8_t *head, eI
|
||||
len_rb = rt_ringbuffer_data_len(rb);
|
||||
|
||||
|
||||
if (len_rb < LEN_FRAME_HEAD + 2) { // 最短5字节
|
||||
// =============================
|
||||
// 简单版:打印错误帧 + 清空缓冲区
|
||||
// =============================
|
||||
rt_kprintf("[ERROR] 帧长度不足,len=%d, data: ", len_rb);
|
||||
|
||||
// 把所有数据读出来、打印、同时清空
|
||||
rt_uint8_t dummy;
|
||||
while (rt_ringbuffer_getchar(rb, &dummy) == RT_EOK)
|
||||
{
|
||||
rt_kprintf("%02x ", dummy); // 打印每一个字节
|
||||
}
|
||||
|
||||
rt_kprintf("\r\n");
|
||||
|
||||
return -1;
|
||||
if (len_rb < LEN_FRAME_HEAD) {
|
||||
return 0;
|
||||
}
|
||||
for (i = 0; i < len_rb - 2; i++) { // 找头三个字节 [帧长, 0x00, id]
|
||||
ret = rt_ringbuffer_getchar(rb, &data);
|
||||
@@ -486,10 +473,77 @@ static int chrg_north_frame_head (struct rt_ringbuffer *rb, rt_uint8_t *head, eI
|
||||
其它说明: -
|
||||
*****************************************************************/
|
||||
int a_number;
|
||||
|
||||
#define NORTH_FRAME_TIMEOUT_MS 100
|
||||
|
||||
static void chrg_north_frame_reset(struct pickup_info_t *pFrame, rt_bool_t release)
|
||||
{
|
||||
if (RT_NULL == pFrame) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (release && (RT_NULL != pFrame->pMB)) {
|
||||
if (RT_NULL != pFrame->pMB->payload) {
|
||||
rt_free(pFrame->pMB->payload);
|
||||
}
|
||||
rt_free(pFrame->pMB);
|
||||
}
|
||||
|
||||
pFrame->last_tick = 0;
|
||||
pFrame->length = 0;
|
||||
pFrame->findhead = 0;
|
||||
pFrame->len_msg = 0;
|
||||
pFrame->pMB = RT_NULL;
|
||||
}
|
||||
|
||||
static int chrg_north_frame_append(struct rt_ringbuffer *rb,
|
||||
struct pickup_info_t *pFrame)
|
||||
{
|
||||
rt_size_t remaining;
|
||||
rt_size_t copied;
|
||||
|
||||
if ((RT_NULL == rb)||(RT_NULL == pFrame)||(RT_NULL == pFrame->pMB)||
|
||||
(RT_NULL == pFrame->pMB->payload)||(pFrame->len_msg <= 0)||
|
||||
(pFrame->length > (rt_size_t)pFrame->len_msg)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
remaining = (rt_size_t)pFrame->len_msg - pFrame->length;
|
||||
if (0 == remaining) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
copied = rt_ringbuffer_data_len(rb);
|
||||
if (copied > remaining) {
|
||||
copied = remaining;
|
||||
}
|
||||
if (copied > 0) {
|
||||
copied = rt_ringbuffer_get(rb,
|
||||
&pFrame->pMB->payload[pFrame->length], copied);
|
||||
pFrame->length += copied;
|
||||
pFrame->last_tick = rt_tick_get();
|
||||
}
|
||||
|
||||
return (pFrame->length == (rt_size_t)pFrame->len_msg) ? 1 : 0;
|
||||
}
|
||||
|
||||
static void chrg_north_frame_dispatch(struct pickup_info_t *pFrame)
|
||||
{
|
||||
struct mb_msg_t *pMB = pFrame->pMB;
|
||||
|
||||
if (pMB->length == 21) {
|
||||
chrg_north_handle_Seting_Volt(pMB->payload, pMB->length);
|
||||
}
|
||||
|
||||
chrg_north_frame_reset(pFrame, RT_FALSE);
|
||||
chrg_thread_mb_send(IDX_THR_NORTH, pMB);
|
||||
}
|
||||
|
||||
static int chrg_north_pickup_frame (struct rt_ringbuffer *rb,
|
||||
struct pickup_info_t *pFrame, eIDX_NOR_CH idx)
|
||||
{
|
||||
int cnt = 0;
|
||||
int status = 0;
|
||||
rt_size_t len_rb = 0;
|
||||
if ((RT_NULL == rb)||(RT_NULL == pFrame)) {
|
||||
return -1;
|
||||
@@ -503,63 +557,52 @@ static int chrg_north_pickup_frame (struct rt_ringbuffer *rb,
|
||||
pFrame->len_msg = chrg_north_frame_head(rb, pFrame->head, pSW->id);
|
||||
// rt_kprintf("msg=:%d",pFrame->len_msg);
|
||||
if (pFrame->len_msg > 0) {
|
||||
if ((pFrame->len_msg < LEN_FRAME_HEAD)||
|
||||
(pFrame->len_msg >= SIZE_BUF_TTY)) {
|
||||
LOG_E("invalid msg length: %d", pFrame->len_msg);
|
||||
chrg_north_frame_reset(pFrame, RT_TRUE);
|
||||
return -3;
|
||||
}
|
||||
|
||||
pFrame->pMB = (struct mb_msg_t *)rt_malloc(sizeof(struct mb_msg_t));
|
||||
if (RT_NULL == pFrame->pMB) {
|
||||
LOG_E("malloc mb failed.");
|
||||
chrg_north_frame_reset(pFrame, RT_FALSE);
|
||||
return -2;
|
||||
}
|
||||
pFrame->pMB->length = pFrame->len_msg;
|
||||
if (pFrame->pMB->length >= SIZE_BUF_TTY) {
|
||||
rt_free(pFrame->pMB);
|
||||
pFrame->pMB = RT_NULL;
|
||||
LOG_E("too long msg.");
|
||||
return -3;
|
||||
}
|
||||
pFrame->pMB->payload = RT_NULL;
|
||||
pFrame->pMB->payload = (rt_uint8_t *)rt_malloc(pFrame->len_msg);
|
||||
if (RT_NULL == pFrame->pMB->payload) {
|
||||
LOG_E("malloc buf failed.");
|
||||
chrg_north_frame_reset(pFrame, RT_TRUE);
|
||||
return -4;
|
||||
}
|
||||
rt_memcpy(pFrame->pMB->payload, pFrame->head, LEN_FRAME_HEAD);
|
||||
|
||||
len_rb = rt_ringbuffer_data_len(rb);
|
||||
// rt_kprintf("len_rb=%d\r\n",len_rb);
|
||||
// rt_kprintf("len=%d",pFrame->len_msg - LEN_FRAME_HEAD);
|
||||
if (len_rb >= pFrame->len_msg - LEN_FRAME_HEAD) {
|
||||
rt_ringbuffer_get(rb, &pFrame->pMB->payload[LEN_FRAME_HEAD],
|
||||
pFrame->len_msg - LEN_FRAME_HEAD);
|
||||
if(pFrame->pMB->length==21){
|
||||
chrg_north_handle_Seting_Volt(pFrame->pMB->payload, pFrame->pMB->length);
|
||||
}
|
||||
chrg_thread_mb_send(IDX_THR_NORTH, pFrame->pMB);
|
||||
pFrame->length = 0;
|
||||
pFrame->len_msg = 0;
|
||||
cnt++;
|
||||
} else {
|
||||
rt_ringbuffer_get(rb, &pFrame->pMB->payload[LEN_FRAME_HEAD], len_rb);
|
||||
pFrame->length = LEN_FRAME_HEAD + len_rb;
|
||||
pFrame->length = LEN_FRAME_HEAD;
|
||||
pFrame->findhead = 1;
|
||||
pFrame->last_tick = rt_tick_get();
|
||||
|
||||
status = chrg_north_frame_append(rb, pFrame);
|
||||
if (status > 0) {
|
||||
chrg_north_frame_dispatch(pFrame);
|
||||
cnt++;
|
||||
} else if (status < 0) {
|
||||
chrg_north_frame_reset(pFrame, RT_TRUE);
|
||||
return -5;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
len_rb = rt_ringbuffer_data_len(rb);
|
||||
int len_need = pFrame->len_msg - LEN_FRAME_HEAD;
|
||||
if (len_rb >= len_need) {
|
||||
rt_ringbuffer_get(rb, &pFrame->pMB->payload[pFrame->length], len_need);
|
||||
|
||||
chrg_thread_mb_send(IDX_THR_NORTH, pFrame->pMB);
|
||||
//chrg_north_pkg_decode(pFrame->pMB->payload, pFrame->len_msg, pSW);
|
||||
|
||||
pFrame->length = 0;
|
||||
pFrame->findhead = 0;
|
||||
pFrame->len_msg = 0;
|
||||
status = chrg_north_frame_append(rb, pFrame);
|
||||
if (status > 0) {
|
||||
chrg_north_frame_dispatch(pFrame);
|
||||
cnt++;
|
||||
} else if (status < 0) {
|
||||
chrg_north_frame_reset(pFrame, RT_TRUE);
|
||||
return -5;
|
||||
} else {
|
||||
rt_ringbuffer_get(rb, &pFrame->pMB->payload[pFrame->length], len_rb);
|
||||
pFrame->length += len_rb;
|
||||
pFrame->last_tick = rt_tick_get();
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -587,6 +630,7 @@ void chrg_north_thread_entry (void *data)
|
||||
}
|
||||
|
||||
int len = 0;
|
||||
rt_size_t put_len = 0;
|
||||
struct chrg_tty_t *pTTY = RT_NULL;
|
||||
struct chrg_north_t *pNOR = &chrgnorth;
|
||||
//北向协议板线程体通道初始化为CH1,
|
||||
@@ -613,6 +657,13 @@ void chrg_north_thread_entry (void *data)
|
||||
}
|
||||
|
||||
while (1) {
|
||||
if (pNOR->frame.findhead &&
|
||||
((rt_tick_t)(rt_tick_get() - pNOR->frame.last_tick) >=
|
||||
rt_tick_from_millisecond(NORTH_FRAME_TIMEOUT_MS))) {
|
||||
chrg_north_frame_reset(&pNOR->frame, RT_TRUE);
|
||||
LOG_W("partial frame timeout");
|
||||
}
|
||||
|
||||
rt_memset(pNOR->rx_buf, 0, sizeof(pNOR->rx_buf));
|
||||
len = chrg_tty_recv(pTTY, pNOR->rx_buf, sizeof(pNOR->rx_buf));
|
||||
if (len <= 0) {
|
||||
@@ -620,17 +671,16 @@ void chrg_north_thread_entry (void *data)
|
||||
continue;
|
||||
}
|
||||
|
||||
rt_ringbuffer_put(pNOR->rb, pNOR->rx_buf, len);
|
||||
put_len = rt_ringbuffer_put(pNOR->rb, pNOR->rx_buf, len);
|
||||
if (put_len != (rt_size_t)len) {
|
||||
LOG_E("north ringbuffer overflow: recv=%d put=%d", len, put_len);
|
||||
rt_ringbuffer_reset(pNOR->rb);
|
||||
chrg_north_frame_reset(&pNOR->frame, RT_TRUE);
|
||||
continue;
|
||||
}
|
||||
#if DEBUG_NORTH
|
||||
LOG_HEX("recvN", 32, pNOR->rx_buf, len);
|
||||
#endif
|
||||
if (1 == pNOR->frame.findhead) {
|
||||
if (rt_tick_get() >= pNOR->frame.last_tick + 100) { // 100ms
|
||||
pNOR->frame.findhead = 0; // reset
|
||||
//LOG_E("timeo\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
chrg_north_pickup_frame(pNOR->rb, &pNOR->frame, pNOR->idx);
|
||||
}
|
||||
}
|
||||
@@ -654,5 +704,25 @@ static int north_ch(rt_uint8_t argc, char **argv)
|
||||
|
||||
MSH_CMD_EXPORT(north_ch, north channel select);
|
||||
|
||||
static int north_diag(int argc, char **argv)
|
||||
{
|
||||
rt_uint8_t i;
|
||||
struct chrg_north_t *pNOR = &chrgnorth;
|
||||
struct chrg_rollnor_t *pROLL = &chrgrollnor;
|
||||
|
||||
rt_kprintf("roll: run=%d idx=%d ch=%d type=%d sub=%d\r\n",
|
||||
pROLL->run, pROLL->idx, pROLL->ch, pROLL->type, pROLL->sub);
|
||||
rt_kprintf("rx: rb_len=%d findhead=%d frame_len=%d received=%d\r\n",
|
||||
pNOR->rb ? rt_ringbuffer_data_len(pNOR->rb) : 0,
|
||||
pNOR->frame.findhead, pNOR->frame.len_msg, pNOR->frame.length);
|
||||
for (i = 0; i < TOTAL_NOR_CHS; i++) {
|
||||
rt_kprintf("ch%d: enable=%d id=%d sub=%d\r\n", i,
|
||||
pNOR->enable[i], pNOR->sw[i].id, pNOR->sw[i].sub);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
MSH_CMD_EXPORT(north_diag, show north polling and frame state);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
#define LEN_FRAME_HEAD (3) // [帧长, 0x00, id]
|
||||
#define MIN_FRAME_LENGTH (5) // 帧最短5字节
|
||||
#define WORK_MIN_VOLT 3000 // 工作电压下限,单位mV
|
||||
#define DEBUG_NORTH 0x00 // 0 = 关闭,1 = 开启
|
||||
#define DEBUG_NORTH 0x01 // 0 = 关闭,1 = 开启
|
||||
#define LCD_OPEN 0x01 // 0为关闭屏幕显示 1为打开
|
||||
#define TRIM_NORTH 0x00 // 0 = 关闭, 1 = 开启
|
||||
#define SINK_TEST_DEBUG 0x00 // 0 = 关闭,1 = 开启
|
||||
|
||||
@@ -391,6 +391,9 @@
|
||||
#define LOG_TAG "chrg.rollsou"
|
||||
#include <rtdbg.h>
|
||||
|
||||
#define SOU_MUTEX_TIMEOUT_MS 100
|
||||
#define SOU_COM_MAX_ATTEMPTS 3
|
||||
|
||||
chrg_rollsou_com_t g_sou_com_batch = {0};
|
||||
|
||||
struct chrg_rollsou_t chrgrollsou = {
|
||||
@@ -400,29 +403,47 @@ struct chrg_rollsou_t chrgrollsou = {
|
||||
|
||||
};
|
||||
//向通道批量缓存添加一条寄存器
|
||||
int chrg_sou_com_batch_add_reg(eIDX_SOU_CH ch, rt_uint16_t reg, rt_uint16_t val)
|
||||
{
|
||||
if(ch >= TOTAL_SOU_CHS) return -1;
|
||||
sou_com_batch_ch_t *pBatch = &g_sou_com_batch.ch[ch];
|
||||
if(pBatch->reg_cnt >= SOU_COM_BATCH_REG_MAX)
|
||||
{
|
||||
LOG_E("sou com batch reg full");
|
||||
return -2;
|
||||
}
|
||||
pBatch->reg_list[pBatch->reg_cnt] = reg;
|
||||
pBatch->val_list[pBatch->reg_cnt] = val;
|
||||
pBatch->reg_cnt++;
|
||||
pBatch->pending = RT_TRUE;
|
||||
return 0;
|
||||
}
|
||||
//启动批量下发(填充完影子结构体后调用)
|
||||
void chrg_sou_com_sou_set(void)
|
||||
int chrg_sou_com_batch_submit(eIDX_SOU_CH ch, const rt_uint16_t *regs,
|
||||
const rt_uint16_t *vals, rt_uint8_t count)
|
||||
{
|
||||
struct chrg_thread_t *pTHR = &chrgthr[IDX_THR_ROLL_SOU];
|
||||
struct chrg_rollsou_t *pROLL = &chrgrollsou;
|
||||
pROLL->run = RUN_COM;
|
||||
sou_com_batch_ch_t *pBatch;
|
||||
rt_uint8_t i;
|
||||
|
||||
if ((ch >= TOTAL_SOU_CHS) || (RT_NULL == regs) || (RT_NULL == vals) ||
|
||||
(count == 0) || (count > SOU_COM_BATCH_REG_MAX) || (RT_NULL == pTHR->mutex)) {
|
||||
return -1;
|
||||
}
|
||||
if (rt_mutex_take(pTHR->mutex, rt_tick_from_millisecond(SOU_MUTEX_TIMEOUT_MS)) != RT_EOK) {
|
||||
LOG_E("sou com batch lock timeout");
|
||||
return -3;
|
||||
}
|
||||
|
||||
pBatch = &g_sou_com_batch.ch[ch];
|
||||
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");
|
||||
rt_mutex_release(pTHR->mutex);
|
||||
return -2;
|
||||
}
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
pBatch->reg_list[pBatch->reg_cnt] = regs[i];
|
||||
pBatch->val_list[pBatch->reg_cnt] = vals[i];
|
||||
pBatch->reg_cnt++;
|
||||
}
|
||||
pBatch->pending = RT_TRUE;
|
||||
pROLL->run = RUN_COM;
|
||||
rt_mutex_release(pTHR->mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int chrg_sou_com_batch_add_reg(eIDX_SOU_CH ch, rt_uint16_t reg, rt_uint16_t val)
|
||||
{
|
||||
return chrg_sou_com_batch_submit(ch, ®, &val, 1);
|
||||
}
|
||||
//启动批量下发(填充完影子结构体后调用)
|
||||
|
||||
/*****************************************************************
|
||||
函数名称: chrg_set_sou_reg
|
||||
@@ -437,11 +458,16 @@ void chrg_set_sou_reg (eIDX_SOU_CH idx, rt_uint16_t reg, rt_uint16_t value)
|
||||
struct chrg_thread_t *pTHR = &chrgthr[IDX_THR_ROLL_SOU];
|
||||
struct chrg_rollsou_t *pROLL = &chrgrollsou;
|
||||
|
||||
if (RT_NULL == pTHR->mutex) {
|
||||
return;
|
||||
}
|
||||
if (rt_mutex_take(pTHR->mutex, rt_tick_from_millisecond(100)) != RT_EOK) {
|
||||
LOG_E("sou command lock timeout");
|
||||
return;
|
||||
}
|
||||
pROLL->ch = idx;
|
||||
pROLL->reg = reg;
|
||||
pROLL->value = value;
|
||||
|
||||
rt_mutex_take(pTHR->mutex, RT_WAITING_FOREVER);
|
||||
pROLL->run = RUN_LCD;
|
||||
rt_mutex_release(pTHR->mutex);
|
||||
}
|
||||
@@ -455,18 +481,153 @@ void chrg_set_sou_reg (eIDX_SOU_CH idx, rt_uint16_t reg, rt_uint16_t value)
|
||||
其它说明: -
|
||||
*****************************************************************/
|
||||
void chrg_set_sou_reg_com (eIDX_SOU_CH idx, rt_uint16_t reg, rt_uint16_t value)
|
||||
{
|
||||
chrg_sou_com_batch_add_reg(idx, reg, value);
|
||||
}
|
||||
|
||||
static int sou_com_batch_next(rt_uint8_t *ch, rt_uint16_t *reg, rt_uint16_t *value)
|
||||
{
|
||||
struct chrg_thread_t *pTHR = &chrgthr[IDX_THR_ROLL_SOU];
|
||||
struct chrg_rollsou_t *pROLL = &chrgrollsou;
|
||||
rt_uint8_t idx;
|
||||
|
||||
if ((RT_NULL == pTHR->mutex) ||
|
||||
(rt_mutex_take(pTHR->mutex, rt_tick_from_millisecond(SOU_MUTEX_TIMEOUT_MS)) != RT_EOK)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (idx = 0; idx < TOTAL_SOU_CHS; idx++) {
|
||||
sou_com_batch_ch_t *pBatch = &g_sou_com_batch.ch[idx];
|
||||
if (pBatch->pending != RT_TRUE) {
|
||||
continue;
|
||||
}
|
||||
if ((pBatch->reg_cnt == 0) || (pBatch->cur_idx >= pBatch->reg_cnt)) {
|
||||
pBatch->pending = RT_FALSE;
|
||||
pBatch->cur_idx = 0;
|
||||
pBatch->reg_cnt = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
*ch = idx;
|
||||
*reg = pBatch->reg_list[pBatch->cur_idx];
|
||||
*value = pBatch->val_list[pBatch->cur_idx];
|
||||
rt_mutex_release(pTHR->mutex);
|
||||
return 1;
|
||||
}
|
||||
|
||||
pROLL->run = RUN_AUTO;
|
||||
rt_mutex_release(pTHR->mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sou_com_batch_complete(rt_uint8_t ch, rt_uint16_t reg, rt_uint16_t value)
|
||||
{
|
||||
struct chrg_thread_t *pTHR = &chrgthr[IDX_THR_ROLL_SOU];
|
||||
sou_com_batch_ch_t *pBatch;
|
||||
|
||||
if ((ch >= TOTAL_SOU_CHS) || (RT_NULL == pTHR->mutex) ||
|
||||
(rt_mutex_take(pTHR->mutex, rt_tick_from_millisecond(SOU_MUTEX_TIMEOUT_MS)) != RT_EOK)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
pBatch = &g_sou_com_batch.ch[ch];
|
||||
if ((pBatch->pending != RT_TRUE) || (pBatch->cur_idx >= pBatch->reg_cnt) ||
|
||||
(pBatch->reg_list[pBatch->cur_idx] != reg) ||
|
||||
(pBatch->val_list[pBatch->cur_idx] != value)) {
|
||||
rt_mutex_release(pTHR->mutex);
|
||||
return -1;
|
||||
}
|
||||
|
||||
pBatch->cur_idx++;
|
||||
if (pBatch->cur_idx >= pBatch->reg_cnt) {
|
||||
pBatch->pending = RT_FALSE;
|
||||
pBatch->cur_idx = 0;
|
||||
pBatch->reg_cnt = 0;
|
||||
}
|
||||
rt_mutex_release(pTHR->mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sou_com_batch_cancel(rt_uint8_t ch)
|
||||
{
|
||||
struct chrg_thread_t *pTHR = &chrgthr[IDX_THR_ROLL_SOU];
|
||||
sou_com_batch_ch_t *pBatch;
|
||||
|
||||
if ((ch >= TOTAL_SOU_CHS) || (RT_NULL == pTHR->mutex) ||
|
||||
(rt_mutex_take(pTHR->mutex, rt_tick_from_millisecond(SOU_MUTEX_TIMEOUT_MS)) != RT_EOK)) {
|
||||
return -1;
|
||||
}
|
||||
pBatch = &g_sou_com_batch.ch[ch];
|
||||
pBatch->pending = RT_FALSE;
|
||||
pBatch->cur_idx = 0;
|
||||
pBatch->reg_cnt = 0;
|
||||
rt_mutex_release(pTHR->mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static rt_bool_t sou_com_batch_pending_locked(void)
|
||||
{
|
||||
rt_uint8_t idx;
|
||||
|
||||
for (idx = 0; idx < TOTAL_SOU_CHS; idx++) {
|
||||
if (g_sou_com_batch.ch[idx].pending == RT_TRUE) {
|
||||
return RT_TRUE;
|
||||
}
|
||||
}
|
||||
return RT_FALSE;
|
||||
}
|
||||
|
||||
static void sou_single_command_finish(rt_uint8_t expected_run)
|
||||
{
|
||||
struct chrg_thread_t *pTHR = &chrgthr[IDX_THR_ROLL_SOU];
|
||||
struct chrg_rollsou_t *pROLL = &chrgrollsou;
|
||||
|
||||
pROLL->ch = idx;
|
||||
pROLL->reg = reg;
|
||||
pROLL->value = value;
|
||||
|
||||
rt_mutex_take(pTHR->mutex, RT_WAITING_FOREVER);
|
||||
pROLL->run = RUN_COM;
|
||||
if ((RT_NULL == pTHR->mutex) ||
|
||||
(rt_mutex_take(pTHR->mutex, rt_tick_from_millisecond(SOU_MUTEX_TIMEOUT_MS)) != RT_EOK)) {
|
||||
return;
|
||||
}
|
||||
if (pROLL->run == expected_run) {
|
||||
pROLL->run = sou_com_batch_pending_locked() ? RUN_COM : RUN_AUTO;
|
||||
}
|
||||
rt_mutex_release(pTHR->mutex);
|
||||
rt_kprintf("ch=:%d,reg=%02x,value=%02x\n",idx,reg,value);
|
||||
}
|
||||
|
||||
static rt_bool_t sou_com_response_matches(struct mb_msg_t *pMB, rt_uint16_t reg,
|
||||
rt_uint16_t value)
|
||||
{
|
||||
return (pMB != RT_NULL) && (pMB->payload != RT_NULL) && (pMB->length == 8) &&
|
||||
(pMB->payload[0] == ID_ELOAD) && (pMB->payload[1] == MB_REGISTER_WR) &&
|
||||
(u8v_to_u16(&pMB->payload[2]) == reg) &&
|
||||
(u8v_to_u16(&pMB->payload[4]) == value) &&
|
||||
(mb_crc16(pMB->payload, pMB->length) == 0);
|
||||
}
|
||||
|
||||
static void sou_msg_free(struct mb_msg_t **ppMB)
|
||||
{
|
||||
if ((ppMB == RT_NULL) || (*ppMB == RT_NULL)) {
|
||||
return;
|
||||
}
|
||||
if ((*ppMB)->payload != RT_NULL) {
|
||||
rt_free((*ppMB)->payload);
|
||||
(*ppMB)->payload = RT_NULL;
|
||||
}
|
||||
rt_free(*ppMB);
|
||||
*ppMB = RT_NULL;
|
||||
}
|
||||
|
||||
static void sou_com_command_failed(rt_uint8_t ch, rt_uint16_t reg, rt_uint16_t value,
|
||||
const char *reason, rt_uint8_t *retry_count)
|
||||
{
|
||||
(*retry_count)++;
|
||||
if (*retry_count < SOU_COM_MAX_ATTEMPTS) {
|
||||
return;
|
||||
}
|
||||
|
||||
LOG_E("com batch failed after %d attempts: ch=%d reg=0x%04x value=0x%04x (%s)",
|
||||
SOU_COM_MAX_ATTEMPTS, ch, reg, value, reason);
|
||||
if (sou_com_batch_cancel(ch) == 0) {
|
||||
*retry_count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -489,16 +650,32 @@ void chrg_roll_sou_thread_entry (void *data)
|
||||
|
||||
rt_uint8_t run = 0;
|
||||
rt_uint8_t index = 0, idx = 0;
|
||||
rt_uint8_t batch_ch = 0;
|
||||
rt_uint8_t retry_count = 0;
|
||||
rt_uint8_t command_ch = 0;
|
||||
rt_uint8_t single_ch = 0;
|
||||
rt_uint8_t single_part = 0;
|
||||
rt_uint16_t command_reg = 0;
|
||||
rt_uint16_t command_value = 0;
|
||||
rt_uint16_t single_reg = 0;
|
||||
rt_uint16_t single_value = 0;
|
||||
rt_bool_t command_valid = RT_FALSE;
|
||||
rt_err_t ret = RT_EOK;
|
||||
struct chrg_rollsou_t *pROLL = &chrgrollsou;
|
||||
struct chrg_thread_t *pTS = &chrgthr[IDX_THR_SOUTH];
|
||||
struct mb_msg_t *pMB_R = RT_NULL;
|
||||
sou_com_batch_ch_t *pCurBatch = RT_NULL;
|
||||
while (1) {
|
||||
rt_mutex_take(pTHR->mutex, RT_WAITING_FOREVER);
|
||||
run = pROLL->run;
|
||||
single_ch = pROLL->ch;
|
||||
single_part = pROLL->part;
|
||||
single_reg = pROLL->reg;
|
||||
single_value = pROLL->value;
|
||||
rt_mutex_release(pTHR->mutex);
|
||||
rt_uint8_t batch_ch = 0; // 缓存当前正在下发的批量通道
|
||||
command_valid = RT_FALSE;
|
||||
if (run != RUN_COM) {
|
||||
retry_count = 0;
|
||||
}
|
||||
// rt_kprintf("------ROLL SOU START \n--------");
|
||||
switch (run) {
|
||||
case RUN_AUTO: {
|
||||
@@ -523,44 +700,29 @@ void chrg_roll_sou_thread_entry (void *data)
|
||||
break;
|
||||
|
||||
case RUN_LCD: {
|
||||
chrg_south_switch((eIDX_SOU_CH)pROLL->ch);
|
||||
chrg_eload_write_reg(ID_ELOAD, pROLL->reg, pROLL->value);
|
||||
chrg_south_switch((eIDX_SOU_CH)single_ch);
|
||||
chrg_eload_write_reg(ID_ELOAD, single_reg, single_value);
|
||||
}
|
||||
break;
|
||||
|
||||
case RUN_COM:
|
||||
{
|
||||
pCurBatch = RT_NULL;
|
||||
// 遍历查找有待下发批量任务的通道
|
||||
for(idx = 0; idx < TOTAL_SOU_CHS; idx++)
|
||||
{
|
||||
if(g_sou_com_batch.ch[idx].pending == RT_TRUE)
|
||||
{
|
||||
pCurBatch = &g_sou_com_batch.ch[idx];
|
||||
break;
|
||||
int next_ret = sou_com_batch_next(&command_ch, &command_reg, &command_value);
|
||||
if (next_ret <= 0) {
|
||||
retry_count = 0;
|
||||
rt_thread_mdelay(1);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// 无任何批量任务,切回自动轮巡
|
||||
if(pCurBatch == RT_NULL)
|
||||
{
|
||||
rt_mutex_take(pTHR->mutex, RT_WAITING_FOREVER);
|
||||
pROLL->run = RUN_AUTO;
|
||||
rt_mutex_release(pTHR->mutex);
|
||||
break;
|
||||
}
|
||||
// 切换当前通道串口
|
||||
chrg_south_switch((eIDX_SOU_CH)idx);
|
||||
batch_ch = idx;
|
||||
// 发送当前下标寄存器
|
||||
rt_uint16_t reg = pCurBatch->reg_list[pCurBatch->cur_idx];
|
||||
rt_uint16_t val = pCurBatch->val_list[pCurBatch->cur_idx];
|
||||
chrg_eload_write_reg(ID_ELOAD, reg, val);
|
||||
batch_ch = command_ch;
|
||||
command_valid = RT_TRUE;
|
||||
chrg_south_switch((eIDX_SOU_CH)command_ch);
|
||||
chrg_eload_write_reg(ID_ELOAD, command_reg, command_value);
|
||||
}
|
||||
break;
|
||||
|
||||
case RUN_CONSOLE: {
|
||||
chrg_south_switch((eIDX_SOU_CH)pROLL->ch);
|
||||
chrg_eload_refresh(ID_ELOAD, pROLL->part);
|
||||
chrg_south_switch((eIDX_SOU_CH)single_ch);
|
||||
chrg_eload_refresh(ID_ELOAD, single_part);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -571,76 +733,48 @@ void chrg_roll_sou_thread_entry (void *data)
|
||||
break;
|
||||
}
|
||||
|
||||
pMB_R = RT_NULL;
|
||||
ret = rt_mb_recv(pTS->mb, (rt_uint32_t *)&pMB_R, 50);
|
||||
if ((RT_EOK == ret)&&(RT_NULL != pMB_R))
|
||||
{
|
||||
if (0 == mb_crc16(pMB_R->payload, pMB_R->length))
|
||||
{
|
||||
if (RUN_AUTO != run)
|
||||
{
|
||||
if(run == RUN_COM)
|
||||
{
|
||||
// CRC校验成功,本条发送完成,下标+1,下发下一条
|
||||
sou_com_batch_ch_t *pBatch = &g_sou_com_batch.ch[batch_ch];
|
||||
pBatch->cur_idx++;
|
||||
// 当前通道全部指令发完,清除pending标记
|
||||
if(pBatch->cur_idx >= pBatch->reg_cnt)
|
||||
{
|
||||
pBatch->pending = RT_FALSE;
|
||||
pBatch->cur_idx = 0;
|
||||
pBatch->reg_cnt = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// LCD/CONSOLE单条模式,应答成功直接切回自动轮巡
|
||||
rt_mutex_take(pTHR->mutex, RT_WAITING_FOREVER);
|
||||
pROLL->run = RUN_AUTO;
|
||||
rt_mutex_release(pTHR->mutex);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// AUTO自动采集,解析返回数据
|
||||
chrg_eload_parse(idx, pROLL->part, pMB_R->payload, pMB_R->length);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_E("crc failed, resend current reg");
|
||||
// CRC错误,不递增cur_idx,下一轮重发本条
|
||||
if ((RT_EOK == ret) && (RT_NULL != pMB_R)) {
|
||||
rt_bool_t response_valid;
|
||||
|
||||
if (run == RUN_COM) {
|
||||
response_valid = command_valid &&
|
||||
sou_com_response_matches(pMB_R, command_reg, command_value);
|
||||
} else {
|
||||
response_valid = (pMB_R->payload != RT_NULL) &&
|
||||
(mb_crc16(pMB_R->payload, pMB_R->length) == 0);
|
||||
}
|
||||
|
||||
// 释放报文内存
|
||||
if (RT_NULL != pMB_R->payload)
|
||||
{
|
||||
rt_free(pMB_R->payload);
|
||||
pMB_R->payload = RT_NULL;
|
||||
if (response_valid) {
|
||||
if (run == RUN_COM) {
|
||||
if (sou_com_batch_complete(batch_ch, command_reg, command_value) == 0) {
|
||||
retry_count = 0;
|
||||
} else {
|
||||
sou_com_command_failed(batch_ch, command_reg, command_value,
|
||||
"batch changed", &retry_count);
|
||||
}
|
||||
if (RT_NULL != pMB_R)
|
||||
{
|
||||
rt_free(pMB_R);
|
||||
pMB_R = RT_NULL;
|
||||
} else if (run != RUN_AUTO) {
|
||||
sou_single_command_finish(run);
|
||||
} else {
|
||||
chrg_eload_parse(idx, pROLL->part, pMB_R->payload, pMB_R->length);
|
||||
}
|
||||
} else if (run == RUN_COM) {
|
||||
sou_com_command_failed(batch_ch, command_reg, command_value,
|
||||
"invalid response", &retry_count);
|
||||
} else {
|
||||
LOG_E("crc failed");
|
||||
}
|
||||
|
||||
sou_msg_free(&pMB_R);
|
||||
rt_thread_mdelay(20);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 应答超时处理
|
||||
if (RUN_AUTO != run)
|
||||
{
|
||||
if(run == RUN_COM)
|
||||
{
|
||||
// 批量下发超时:不递增cur_idx,下一轮循环重发当前寄存器
|
||||
LOG_E("com batch timeout, resend current reg");
|
||||
}
|
||||
else
|
||||
{
|
||||
// LCD/CONSOLE单条超时,切回自动轮巡
|
||||
rt_mutex_take(pTHR->mutex, RT_WAITING_FOREVER);
|
||||
pROLL->run = RUN_AUTO;
|
||||
rt_mutex_release(pTHR->mutex);
|
||||
}
|
||||
} else {
|
||||
sou_msg_free(&pMB_R);
|
||||
if ((run == RUN_COM) && command_valid) {
|
||||
sou_com_command_failed(batch_ch, command_reg, command_value,
|
||||
"timeout", &retry_count);
|
||||
} else if (run != RUN_AUTO) {
|
||||
sou_single_command_finish(run);
|
||||
}
|
||||
}
|
||||
// rt_kprintf("------ROLL SOU END \n--------");
|
||||
@@ -670,10 +804,15 @@ static int south_send(rt_uint8_t argc, char **argv)
|
||||
}
|
||||
|
||||
struct chrg_rollsou_t *pROLL = &chrgrollsou;
|
||||
struct chrg_thread_t *pTHR = &chrgthr[IDX_THR_ROLL_SOU];
|
||||
if ((RT_NULL == pTHR->mutex) ||
|
||||
(rt_mutex_take(pTHR->mutex, rt_tick_from_millisecond(SOU_MUTEX_TIMEOUT_MS)) != RT_EOK)) {
|
||||
return -1;
|
||||
}
|
||||
pROLL->run = RUN_CONSOLE;
|
||||
pROLL->ch = (rt_uint8_t)ch;
|
||||
pROLL->part = (rt_uint8_t)pt;
|
||||
|
||||
rt_mutex_release(pTHR->mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -688,15 +827,23 @@ static int south_run (int argc, char **argv)
|
||||
}
|
||||
|
||||
struct chrg_rollsou_t *pROLL = &chrgrollsou;
|
||||
struct chrg_thread_t *pTHR = &chrgthr[IDX_THR_ROLL_SOU];
|
||||
rt_uint8_t new_run;
|
||||
|
||||
if (rt_strcmp(argv[1], "start") == 0) {
|
||||
pROLL->run = RUN_AUTO;
|
||||
new_run = RUN_AUTO;
|
||||
} else if (rt_strcmp(argv[1], "stop") == 0) {
|
||||
pROLL->run = RUN_NONE;
|
||||
new_run = RUN_NONE;
|
||||
} else {
|
||||
rt_kprintf("help : %s start|stop\r\n", argv[0]);
|
||||
return -1;
|
||||
}
|
||||
if ((RT_NULL == pTHR->mutex) ||
|
||||
(rt_mutex_take(pTHR->mutex, rt_tick_from_millisecond(SOU_MUTEX_TIMEOUT_MS)) != RT_EOK)) {
|
||||
return -1;
|
||||
}
|
||||
pROLL->run = new_run;
|
||||
rt_mutex_release(pTHR->mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -83,8 +83,9 @@ extern void chrg_set_sou_reg_com (eIDX_SOU_CH idx, rt_uint16_t reg, rt_uint16_t
|
||||
extern void chrg_roll_sou_thread_entry (void *data);
|
||||
|
||||
extern void chrg_send_sou_upadata_data (rt_uint8_t *buf,rt_uint16_t leng);
|
||||
extern void chrg_sou_com_sou_set(void);
|
||||
extern int chrg_sou_com_batch_add_reg(eIDX_SOU_CH ch, rt_uint16_t reg, rt_uint16_t val);
|
||||
extern int chrg_sou_com_batch_submit(eIDX_SOU_CH ch, const rt_uint16_t *regs,
|
||||
const rt_uint16_t *vals, rt_uint8_t count);
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
#define DBG_LEVEL DBG_LOG
|
||||
#include <rtdbg.h>
|
||||
|
||||
#define SOUTH_FRAME_TIMEOUT_MS 100
|
||||
|
||||
#define MB_ACK_HEAD_SIZE 3 // modbus 响应头3字节
|
||||
|
||||
struct chrg_south_t chrgsouth = {
|
||||
@@ -249,10 +251,70 @@ static int chrg_south_frame_head (struct rt_ringbuffer *rb, rt_uint8_t *head, eI
|
||||
返回说明: <0: 错误 >0:帧长度
|
||||
其它说明: -
|
||||
*****************************************************************/
|
||||
static void chrg_south_frame_reset(struct pickup_info_t *pFrame, rt_bool_t release)
|
||||
{
|
||||
if (RT_NULL == pFrame) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (release && (RT_NULL != pFrame->pMB)) {
|
||||
if (RT_NULL != pFrame->pMB->payload) {
|
||||
rt_free(pFrame->pMB->payload);
|
||||
}
|
||||
rt_free(pFrame->pMB);
|
||||
}
|
||||
|
||||
pFrame->last_tick = 0;
|
||||
pFrame->length = 0;
|
||||
pFrame->findhead = 0;
|
||||
pFrame->len_msg = 0;
|
||||
pFrame->pMB = RT_NULL;
|
||||
}
|
||||
|
||||
static int chrg_south_frame_append(struct rt_ringbuffer *rb,
|
||||
struct pickup_info_t *pFrame)
|
||||
{
|
||||
rt_size_t remaining;
|
||||
rt_size_t copied;
|
||||
|
||||
if ((RT_NULL == rb)||(RT_NULL == pFrame)||(RT_NULL == pFrame->pMB)||
|
||||
(RT_NULL == pFrame->pMB->payload)||(pFrame->len_msg <= 0)||
|
||||
(pFrame->length > (rt_size_t)pFrame->len_msg)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
remaining = (rt_size_t)pFrame->len_msg - pFrame->length;
|
||||
if (0 == remaining) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
copied = rt_ringbuffer_data_len(rb);
|
||||
if (copied > remaining) {
|
||||
copied = remaining;
|
||||
}
|
||||
if (copied > 0) {
|
||||
copied = rt_ringbuffer_get(rb,
|
||||
&pFrame->pMB->payload[pFrame->length], copied);
|
||||
pFrame->length += copied;
|
||||
pFrame->last_tick = rt_tick_get();
|
||||
}
|
||||
|
||||
return (pFrame->length == (rt_size_t)pFrame->len_msg) ? 1 : 0;
|
||||
}
|
||||
|
||||
static void chrg_south_frame_dispatch(struct pickup_info_t *pFrame)
|
||||
{
|
||||
struct mb_msg_t *pMB = pFrame->pMB;
|
||||
|
||||
chrg_south_frame_reset(pFrame, RT_FALSE);
|
||||
chrg_thread_mb_send(IDX_THR_SOUTH, pMB);
|
||||
}
|
||||
|
||||
static int chrg_south_pickup_frame (struct rt_ringbuffer *rb,
|
||||
struct pickup_info_t *pFrame)
|
||||
{
|
||||
int cnt = 0;
|
||||
int status = 0;
|
||||
rt_size_t len_rb = 0;
|
||||
|
||||
if ((RT_NULL == rb)||(RT_NULL == pFrame)) {
|
||||
@@ -263,63 +325,55 @@ static int chrg_south_pickup_frame (struct rt_ringbuffer *rb,
|
||||
if (0 == pFrame->findhead) {
|
||||
pFrame->len_msg = chrg_south_frame_head(rb, pFrame->head, ID_ELOAD);
|
||||
if (pFrame->len_msg > 0) {
|
||||
if ((pFrame->len_msg < MB_ACK_HEAD_SIZE)||
|
||||
(pFrame->len_msg >= SIZE_BUF_TTY)) {
|
||||
LOG_E("invalid msg length: %d", pFrame->len_msg);
|
||||
chrg_south_frame_reset(pFrame, RT_TRUE);
|
||||
return -3;
|
||||
}
|
||||
|
||||
pFrame->pMB = (struct mb_msg_t *)rt_malloc(sizeof(struct mb_msg_t));
|
||||
if (RT_NULL == pFrame->pMB) {
|
||||
LOG_E("malloc mb failed.");
|
||||
chrg_south_frame_reset(pFrame, RT_FALSE);
|
||||
return -2;
|
||||
}
|
||||
|
||||
pFrame->pMB->length = pFrame->len_msg;
|
||||
if (pFrame->pMB->length >= SIZE_BUF_TTY) {
|
||||
rt_free(pFrame->pMB);
|
||||
pFrame->pMB = RT_NULL;
|
||||
LOG_E("too long msg.");
|
||||
return -3;
|
||||
}
|
||||
|
||||
pFrame->pMB->payload = RT_NULL;
|
||||
pFrame->pMB->payload = (rt_uint8_t *)rt_malloc(pFrame->len_msg);
|
||||
if (RT_NULL == pFrame->pMB->payload) {
|
||||
LOG_E("malloc buf failed.");
|
||||
chrg_south_frame_reset(pFrame, RT_TRUE);
|
||||
return -4;
|
||||
}
|
||||
|
||||
rt_memcpy(pFrame->pMB->payload, pFrame->head, MB_ACK_HEAD_SIZE);
|
||||
|
||||
len_rb = rt_ringbuffer_data_len(rb);
|
||||
if (len_rb >= pFrame->len_msg - MB_ACK_HEAD_SIZE) {
|
||||
rt_ringbuffer_get(rb, &pFrame->pMB->payload[MB_ACK_HEAD_SIZE],
|
||||
pFrame->len_msg - MB_ACK_HEAD_SIZE);
|
||||
|
||||
chrg_thread_mb_send(IDX_THR_SOUTH, pFrame->pMB);
|
||||
|
||||
pFrame->length = 0;
|
||||
pFrame->len_msg = 0;
|
||||
cnt++;
|
||||
} else {
|
||||
rt_ringbuffer_get(rb, &pFrame->pMB->payload[MB_ACK_HEAD_SIZE], len_rb);
|
||||
pFrame->length = MB_ACK_HEAD_SIZE + len_rb;
|
||||
pFrame->length = MB_ACK_HEAD_SIZE;
|
||||
pFrame->findhead = 1;
|
||||
pFrame->last_tick = rt_tick_get();
|
||||
|
||||
status = chrg_south_frame_append(rb, pFrame);
|
||||
if (status > 0) {
|
||||
chrg_south_frame_dispatch(pFrame);
|
||||
cnt++;
|
||||
} else if (status < 0) {
|
||||
chrg_south_frame_reset(pFrame, RT_TRUE);
|
||||
return -5;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
len_rb = rt_ringbuffer_data_len(rb);
|
||||
int len_need = pFrame->len_msg - MB_ACK_HEAD_SIZE;
|
||||
if (len_rb >= len_need) {
|
||||
rt_ringbuffer_get(rb, &pFrame->pMB->payload[pFrame->length], len_need);
|
||||
|
||||
chrg_thread_mb_send(IDX_THR_SOUTH, pFrame->pMB);
|
||||
|
||||
pFrame->length = 0;
|
||||
pFrame->findhead = 0;
|
||||
pFrame->len_msg = 0;
|
||||
status = chrg_south_frame_append(rb, pFrame);
|
||||
if (status > 0) {
|
||||
chrg_south_frame_dispatch(pFrame);
|
||||
cnt++;
|
||||
} else if (status < 0) {
|
||||
chrg_south_frame_reset(pFrame, RT_TRUE);
|
||||
return -5;
|
||||
} else {
|
||||
rt_ringbuffer_get(rb, &pFrame->pMB->payload[pFrame->length], len_rb);
|
||||
pFrame->length += len_rb;
|
||||
pFrame->last_tick = rt_tick_get();
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -373,6 +427,13 @@ void chrg_south_thread_entry (void *data)
|
||||
}
|
||||
|
||||
while (1) {
|
||||
if (pSOU->frame.findhead &&
|
||||
((rt_tick_t)(rt_tick_get() - pSOU->frame.last_tick) >=
|
||||
rt_tick_from_millisecond(SOUTH_FRAME_TIMEOUT_MS))) {
|
||||
chrg_south_frame_reset(&pSOU->frame, RT_TRUE);
|
||||
LOG_W("partial frame timeout");
|
||||
}
|
||||
|
||||
rt_memset(pSOU->rx_buf, 0, sizeof(pSOU->rx_buf));
|
||||
len = chrg_tty_recv(pTTY, pSOU->rx_buf, sizeof(pSOU->rx_buf));
|
||||
if (len <= 0) {
|
||||
@@ -396,13 +457,6 @@ void chrg_south_thread_entry (void *data)
|
||||
|
||||
//LOG_HEX("recvS", 32, pSOU->rx_buf, len);
|
||||
|
||||
if (1 == pSOU->frame.findhead) {
|
||||
if (rt_tick_get() >= pSOU->frame.last_tick + 100) { // 100ms
|
||||
pSOU->frame.findhead = 0; // reset
|
||||
//LOG_E("timeo\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
chrg_south_pickup_frame(pSOU->rb, &pSOU->frame);
|
||||
}
|
||||
|
||||
|
||||
@@ -146,32 +146,40 @@ rt_err_t chrg_thread_evt_send (eIDX_THRS idx, rt_uint32_t data)
|
||||
返回说明: 0: OK , !=0 : FAILED
|
||||
其它说明: -
|
||||
*****************************************************************/
|
||||
rt_err_t chrg_thread_mb_send (eIDX_THRS idx, void *data)
|
||||
static void chrg_thread_mb_free(void *data)
|
||||
{
|
||||
rt_err_t ret = RT_EOK;
|
||||
|
||||
if (idx >= TOTAL_THRS) {
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
struct chrg_thread_t *pTHR = &chrgthr[idx];
|
||||
|
||||
if (RT_NULL != pTHR->mb) {
|
||||
ret = rt_mb_send(pTHR->mb, (rt_uint32_t)data);
|
||||
if (RT_EOK != ret) {
|
||||
if (ret == -RT_EFULL) {
|
||||
LOG_E("mb full, drop message. [%d]", ret);
|
||||
if (RT_NULL != data) {
|
||||
struct mb_msg_t *pMB = (struct mb_msg_t *)data;
|
||||
|
||||
if (RT_NULL == pMB) {
|
||||
return;
|
||||
}
|
||||
if (RT_NULL != pMB->payload) {
|
||||
rt_free(pMB->payload);
|
||||
}
|
||||
rt_free(pMB);
|
||||
}
|
||||
} else {
|
||||
LOG_E("mb send failed. [%d]", ret);
|
||||
|
||||
rt_err_t chrg_thread_mb_send (eIDX_THRS idx, void *data)
|
||||
{
|
||||
rt_err_t ret;
|
||||
|
||||
if ((idx >= TOTAL_THRS)||(RT_NULL == data)) {
|
||||
chrg_thread_mb_free(data);
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
struct chrg_thread_t *pTHR = &chrgthr[idx];
|
||||
|
||||
if (RT_NULL == pTHR->mb) {
|
||||
LOG_E("mb '%s' is not ready.", pTHR->name);
|
||||
chrg_thread_mb_free(data);
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
ret = rt_mb_send(pTHR->mb, (rt_uint32_t)data);
|
||||
if (RT_EOK != ret) {
|
||||
LOG_E("mb send failed, drop message. [%d]", ret);
|
||||
chrg_thread_mb_free(data);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
@@ -444,10 +444,24 @@ int sink_set_pd (rt_uint8_t pd, rt_uint8_t *buf)
|
||||
//}
|
||||
|
||||
//sink开机初始化
|
||||
void chrg_sink_work_init(eIDX_SOU_CH idx, struct chrg_switch_t *pSW)
|
||||
static int chrg_sink_work_init(eIDX_SOU_CH idx, struct chrg_switch_t *pSW)
|
||||
{
|
||||
struct chrg_south_t *pSOU = &chrgsouth;
|
||||
struct chrg_north_t *pNOR = &chrgnorth;
|
||||
rt_uint16_t regs[3] = {REG_CURRENT_OUT + 1, REG_MODE, 0};
|
||||
rt_uint16_t vals[3] = {0, pSW->CV_mode, 0};
|
||||
rt_uint8_t count = 2;
|
||||
|
||||
if (pSW->sink.test.test_mode_old == 1) {
|
||||
regs[count] = ModbusRTU_ShortTest_CMD_MODE_FLAG;
|
||||
vals[count++] = ModbusRTU_DYNA_CMD_MODE_STOP;
|
||||
} else if (pSW->sink.test.test_mode_old == 3) {
|
||||
regs[count] = ModbusRTU_DYNA_CMD_MODE_FLAG;
|
||||
vals[count++] = ModbusRTU_DYNA_CMD_MODE_STOP;
|
||||
}
|
||||
if (chrg_sou_com_batch_submit(idx, regs, vals, count) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
pSW->sink.On_work = 1;
|
||||
pSOU->enable[idx] = 1;
|
||||
@@ -455,56 +469,47 @@ void chrg_sink_work_init(eIDX_SOU_CH idx, struct chrg_switch_t *pSW)
|
||||
pNOR->enable[idx] = 1;
|
||||
|
||||
chrg_nor_sw_rel((eIDX_NOR_CH)idx, ID_SINK); //打开北向继电器
|
||||
// 1. 电流输出置0
|
||||
chrg_sou_com_batch_add_reg(idx, REG_CURRENT_OUT+1, 0);
|
||||
// 2. 设置硬件恒压/恒流模式
|
||||
chrg_sou_com_batch_add_reg(idx,REG_MODE,pSW->CV_mode);
|
||||
switch(pSW->sink.test.test_mode_old){
|
||||
case 0:
|
||||
|
||||
break;
|
||||
case 1://短路测试退出
|
||||
chrg_sou_com_batch_add_reg((eIDX_SOU_CH)idx, ModbusRTU_ShortTest_CMD_MODE_FLAG , ModbusRTU_DYNA_CMD_MODE_STOP);
|
||||
break;
|
||||
case 2:
|
||||
|
||||
break;
|
||||
case 3:
|
||||
chrg_sou_com_batch_add_reg((eIDX_SOU_CH)idx, ModbusRTU_DYNA_CMD_MODE_FLAG , ModbusRTU_DYNA_CMD_MODE_STOP);
|
||||
break;
|
||||
}
|
||||
pSW->sink.test.test_mode_old = 0;
|
||||
pSW->sink.work_mode = SINK_WORK_WAIT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
//sink进入运行状态
|
||||
void chrg_sink_work_volt_runing(eIDX_SOU_CH idx, struct chrg_switch_t *pSW){
|
||||
chrg_sou_com_batch_add_reg(idx, 0x01, 0x02);
|
||||
//打开主继电器
|
||||
chrg_sou_com_batch_add_reg(idx, 0x01, 0x03);
|
||||
if(pSW->CV_mode == MODE_CONSTANT_VOLTAGE)
|
||||
static int chrg_sink_work_volt_runing(eIDX_SOU_CH idx, struct chrg_switch_t *pSW)
|
||||
{
|
||||
chrg_sou_com_batch_add_reg(idx, REG_VOLTAGE_OUT+1, pSW->sink.loadv);
|
||||
rt_uint16_t regs[4] = {0x01, 0x01, 0, REG_WORK};
|
||||
rt_uint16_t vals[4] = {0x02, 0x03, 0, WORK_START};
|
||||
|
||||
if (pSW->CV_mode == MODE_CONSTANT_VOLTAGE) {
|
||||
regs[2] = REG_VOLTAGE_OUT + 1;
|
||||
vals[2] = pSW->sink.loadv;
|
||||
} else {
|
||||
regs[2] = REG_CURRENT_OUT + 1;
|
||||
vals[2] = pSW->sink.loadc;
|
||||
}
|
||||
else
|
||||
{
|
||||
chrg_sou_com_batch_add_reg(idx, REG_CURRENT_OUT+1, pSW->sink.loadc);
|
||||
}
|
||||
chrg_sou_com_batch_add_reg(idx, REG_WORK, WORK_START);
|
||||
return chrg_sou_com_batch_submit(idx, regs, vals, 4);
|
||||
}
|
||||
|
||||
//sink进入低电压状态
|
||||
void chrg_sink_nor_work_low(eIDX_SOU_CH idx, struct chrg_switch_t *pSW)
|
||||
static int chrg_sink_nor_work_low(eIDX_SOU_CH idx, struct chrg_switch_t *pSW)
|
||||
{
|
||||
chrg_sou_com_batch_add_reg(idx, 0x01, 0x00);
|
||||
chrg_sou_com_batch_add_reg(idx, REG_WORK, WORK_STOP);
|
||||
rt_uint16_t regs[2] = {0x01, REG_WORK};
|
||||
rt_uint16_t vals[2] = {0x00, WORK_STOP};
|
||||
|
||||
return chrg_sou_com_batch_submit(idx, regs, vals, 2);
|
||||
}
|
||||
|
||||
//com端关机流程
|
||||
void chrg_sink_nor_work_off(eIDX_SOU_CH idx, struct chrg_switch_t *pSW)
|
||||
static int chrg_sink_nor_work_off(eIDX_SOU_CH idx, struct chrg_switch_t *pSW)
|
||||
{
|
||||
struct chrg_south_t *pSOU = &chrgsouth;
|
||||
struct chrg_north_t *pNOR = &chrgnorth;
|
||||
rt_uint16_t regs[2] = {0x01, REG_WORK};
|
||||
rt_uint16_t vals[2] = {0x00, WORK_STOP};
|
||||
|
||||
if (chrg_sou_com_batch_submit(idx, regs, vals, 2) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
pSW->sink.On_work = 0;
|
||||
pSOU->enable[idx] = 0;
|
||||
@@ -512,71 +517,81 @@ void chrg_sink_nor_work_off(eIDX_SOU_CH idx, struct chrg_switch_t *pSW)
|
||||
pNOR->enable[idx] = 0;
|
||||
|
||||
chrg_nor_sw_rel((eIDX_NOR_CH)idx, 0); //关闭北向继电器
|
||||
chrg_sou_com_batch_add_reg(idx, 0x01, 0x00);
|
||||
chrg_sou_com_batch_add_reg(idx, REG_WORK, WORK_STOP);
|
||||
return 0;
|
||||
}
|
||||
|
||||
//动态测试启动
|
||||
void chrg_sink_change_ON(rt_uint8_t ch, struct chrg_switch_t *pSW)
|
||||
static int chrg_sink_change_ON(rt_uint8_t ch, struct chrg_switch_t *pSW)
|
||||
{
|
||||
struct test *pTest = &pSW->sink.test;
|
||||
chrg_sou_com_batch_add_reg((eIDX_SOU_CH)ch, ModbusRTU_DYNA_L1, pTest->change_test.curr1_set);
|
||||
chrg_sou_com_batch_add_reg((eIDX_SOU_CH)ch, ModbusRTU_DYNA_T1 , pTest->change_test.time1_set);
|
||||
chrg_sou_com_batch_add_reg((eIDX_SOU_CH)ch, ModbusRTU_DYNA_L2 , pTest->change_test.curr2_set);
|
||||
chrg_sou_com_batch_add_reg((eIDX_SOU_CH)ch, ModbusRTU_DYNA_T2 , pTest->change_test.time2_set);
|
||||
chrg_sou_com_batch_add_reg((eIDX_SOU_CH)ch, ModbusRTU_DYNA_CMD_MODE_FLAG , ModbusRTU_DYNA_CMD_MODE_RUN);
|
||||
chrg_sou_com_batch_add_reg((eIDX_SOU_CH)ch, REG_WORK, WORK_START);
|
||||
rt_uint16_t regs[6] = {ModbusRTU_DYNA_L1, ModbusRTU_DYNA_T1,
|
||||
ModbusRTU_DYNA_L2, ModbusRTU_DYNA_T2, ModbusRTU_DYNA_CMD_MODE_FLAG, REG_WORK};
|
||||
rt_uint16_t vals[6] = {pTest->change_test.curr1_set, pTest->change_test.time1_set,
|
||||
pTest->change_test.curr2_set, pTest->change_test.time2_set,
|
||||
ModbusRTU_DYNA_CMD_MODE_RUN, WORK_START};
|
||||
|
||||
return chrg_sou_com_batch_submit((eIDX_SOU_CH)ch, regs, vals, 6);
|
||||
}
|
||||
|
||||
//短路测试启动
|
||||
void chrg_sink_SHOUT_ON(rt_uint8_t ch, struct chrg_switch_t *pSW)
|
||||
static int chrg_sink_SHOUT_ON(rt_uint8_t ch, struct chrg_switch_t *pSW)
|
||||
{
|
||||
struct test *pTest = &pSW->sink.test;
|
||||
chrg_sou_com_batch_add_reg((eIDX_SOU_CH)ch, ModbusRTU_ShortTest_CMD_MODE_FLAG , ModbusRTU_DYNA_CMD_MODE_RUN_ALWAYS_KEPP); //保持
|
||||
chrg_sou_com_batch_add_reg((eIDX_SOU_CH)ch, REG_WORK, WORK_START);
|
||||
rt_uint16_t regs[2] = {ModbusRTU_ShortTest_CMD_MODE_FLAG, REG_WORK};
|
||||
rt_uint16_t vals[2] = {ModbusRTU_DYNA_CMD_MODE_RUN_ALWAYS_KEPP, WORK_START};
|
||||
|
||||
return chrg_sou_com_batch_submit((eIDX_SOU_CH)ch, regs, vals, 2);
|
||||
}
|
||||
|
||||
|
||||
//负载工作
|
||||
void chrg_sink_work(eIDX_SOU_CH idx, struct chrg_switch_t *pSW){
|
||||
int chrg_sink_work(eIDX_SOU_CH idx, struct chrg_switch_t *pSW)
|
||||
{
|
||||
static uint8_t last_state[TOTAL_SOU_CHS] ={100,100,100,100};
|
||||
rt_uint8_t work_mode = pSW->sink.work_mode;
|
||||
rt_uint8_t work_mode;
|
||||
int ret = -1;
|
||||
|
||||
if ((idx >= TOTAL_SOU_CHS) || (pSW == RT_NULL)) {
|
||||
return -1;
|
||||
}
|
||||
work_mode = pSW->sink.work_mode;
|
||||
|
||||
// 本次状态和上次一致,直接跳过,不重复下发寄存器
|
||||
if (work_mode == last_state[idx])
|
||||
{
|
||||
return;
|
||||
if (work_mode == last_state[idx]) {
|
||||
return 0;
|
||||
}
|
||||
chrg_sou_com_sou_set();
|
||||
switch(work_mode){
|
||||
case SINK_WORK_INIT:
|
||||
chrg_sink_work_init(idx,pSW);
|
||||
ret = chrg_sink_work_init(idx,pSW);
|
||||
break;
|
||||
case SINK_WORK_WAIT:
|
||||
|
||||
ret = 0;
|
||||
break;
|
||||
case SINK_WORK_RUNING:
|
||||
chrg_sink_work_volt_runing(idx,pSW);
|
||||
ret = chrg_sink_work_volt_runing(idx,pSW);
|
||||
break;
|
||||
case SINK_WORK_RUNING_2:
|
||||
chrg_sink_work_volt_runing(idx,pSW);
|
||||
ret = chrg_sink_work_volt_runing(idx,pSW);
|
||||
break;
|
||||
case SINK_WORK_ON_TEST_CHANGE:
|
||||
chrg_sink_change_ON(idx,pSW);
|
||||
ret = chrg_sink_change_ON(idx,pSW);
|
||||
break;
|
||||
case SINK_WORK_ON_TEST_SHOUT:
|
||||
chrg_sink_SHOUT_ON(idx,pSW);
|
||||
ret = chrg_sink_SHOUT_ON(idx,pSW);
|
||||
break;
|
||||
case SINK_WORK_LOW:
|
||||
chrg_sink_nor_work_low(idx,pSW);
|
||||
ret = chrg_sink_nor_work_low(idx,pSW);
|
||||
break;
|
||||
case SINK_WORK_STOP:
|
||||
chrg_sink_nor_work_off(idx,pSW);
|
||||
ret = chrg_sink_nor_work_off(idx,pSW);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
// 更新缓存,保存本次最新状态
|
||||
if (ret == 0) {
|
||||
last_state[idx] = work_mode;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -384,7 +384,7 @@ extern void chrg_nor_sink_change_test(rt_uint8_t ch, struct chrg_switch_t *pSW);
|
||||
extern void chrg_nor_sink_test_stop(rt_uint8_t ch,struct chrg_switch_t *pSW,rt_uint8_t *enable);
|
||||
extern void chrg_nor_sink_test_run(rt_uint8_t ch, struct chrg_switch_t *pSW);
|
||||
|
||||
extern void chrg_sink_work(eIDX_SOU_CH idx, struct chrg_switch_t *pSW);
|
||||
extern int chrg_sink_work(eIDX_SOU_CH idx, struct chrg_switch_t *pSW);
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@@ -1 +1,4 @@
|
||||
LOAD %L INCREMENTAL
|
||||
BS HardFault_Handler
|
||||
BS rt_assert_handler
|
||||
G
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
Load "D:\\HUACE_Project\\3_Code\\HCDF_MID_405_Charger\\chrg_V.3.0\\apps\\chrg\\build\\keil\\Obj\\chrg.axf"
|
||||
Erase Done.Programming Done.Verify OK.Flash Load finished at 18:22:08
|
||||
@@ -0,0 +1,130 @@
|
||||
*** Using Compiler 'V6.16', folder: 'D:\Program Files\Keil_v5\ARM\ARMCLANG\Bin'
|
||||
Rebuild target 'chrg'
|
||||
compiling main.c...
|
||||
compiling chrg_switch.c...
|
||||
compiling chrg_wdt.c...
|
||||
compiling chrg_gpio.c...
|
||||
compiling chrg_tmr.c...
|
||||
compiling chrg_fal.c...
|
||||
compiling chrg_tty.c...
|
||||
compiling chrg_led.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...
|
||||
compiling chrg_utils.c...
|
||||
compiling syscall_mem.c...
|
||||
compiling syscalls.c...
|
||||
compiling cctype.c...
|
||||
compiling cstdlib.c...
|
||||
compiling cstring.c...
|
||||
compiling ctime.c...
|
||||
compiling cunistd.c...
|
||||
compiling cwchar.c...
|
||||
compiling device.c...
|
||||
compiling hwtimer.c...
|
||||
compiling completion_comm.c...
|
||||
compiling completion_up.c...
|
||||
compiling condvar.c...
|
||||
compiling dataqueue.c...
|
||||
compiling pipe.c...
|
||||
compiling ringblk_buf.c...
|
||||
compiling ringbuffer.c...
|
||||
compiling waitqueue.c...
|
||||
compiling workqueue.c...
|
||||
compiling dev_pin.c...
|
||||
compiling dev_serial.c...
|
||||
compiling dev_watchdog.c...
|
||||
compiling stm32f4xx_hal_msp.c...
|
||||
compiling board.c...
|
||||
compiling drv_flash_f4.c...
|
||||
compiling drv_gpio.c...
|
||||
compiling drv_tim.c...
|
||||
compiling drv_usart.c...
|
||||
compiling drv_usbd.c...
|
||||
compiling drv_wdt.c...
|
||||
compiling drv_common.c...
|
||||
compiling fal.c...
|
||||
compiling fal_flash.c...
|
||||
compiling fal_partition.c...
|
||||
compiling fal_rtt.c...
|
||||
compiling shell.c...
|
||||
compiling msh_parse.c...
|
||||
compiling cmd.c...
|
||||
compiling msh.c...
|
||||
compiling clock.c...
|
||||
compiling components.c...
|
||||
compiling cpu_up.c...
|
||||
compiling defunct.c...
|
||||
compiling idle.c...
|
||||
compiling ipc.c...
|
||||
compiling irq.c...
|
||||
compiling kservice.c...
|
||||
compiling memheap.c...
|
||||
compiling mempool.c...
|
||||
compiling object.c...
|
||||
compiling scheduler_comm.c...
|
||||
compiling scheduler_up.c...
|
||||
compiling thread.c...
|
||||
compiling timer.c...
|
||||
compiling rt_vsnprintf_tiny.c...
|
||||
compiling kerrno.c...
|
||||
compiling kstring.c...
|
||||
compiling rt_vsscanf.c...
|
||||
compiling kstdio.c...
|
||||
compiling atomic_arm.c...
|
||||
compiling div0.c...
|
||||
compiling showmem.c...
|
||||
assembling context_rvds.S...
|
||||
compiling cpuport.c...
|
||||
compiling usbdevice.c...
|
||||
compiling cdc_vcom.c...
|
||||
compiling usbdevice_core.c...
|
||||
assembling startup_stm32f405xx.s...
|
||||
compiling system_stm32f4xx.c...
|
||||
compiling stm32f4xx_hal_gpio.c...
|
||||
compiling stm32f4xx_hal_flash.c...
|
||||
compiling stm32f4xx_hal_usart.c...
|
||||
compiling stm32f4xx_hal_rng.c...
|
||||
compiling stm32f4xx_hal_uart.c...
|
||||
compiling stm32f4xx_hal_wwdg.c...
|
||||
compiling stm32f4xx_hal_tim.c...
|
||||
compiling stm32f4xx_hal_cryp_ex.c...
|
||||
compiling stm32f4xx_hal_pwr.c...
|
||||
compiling stm32f4xx_hal_rcc.c...
|
||||
compiling stm32f4xx_hal_hcd.c...
|
||||
compiling stm32f4xx_ll_usb.c...
|
||||
compiling stm32f4xx_hal_pccard.c...
|
||||
compiling stm32f4xx_hal_flash_ex.c...
|
||||
compiling stm32f4xx_hal_flash_ramfunc.c...
|
||||
compiling stm32f4xx_hal_tim_ex.c...
|
||||
compiling stm32f4xx_hal_lptim.c...
|
||||
compiling stm32f4xx_hal_cec.c...
|
||||
compiling stm32f4xx_hal_cryp.c...
|
||||
compiling stm32f4xx_hal.c...
|
||||
compiling stm32f4xx_hal_iwdg.c...
|
||||
compiling stm32f4xx_hal_pcd_ex.c...
|
||||
compiling stm32f4xx_hal_pcd.c...
|
||||
compiling stm32f4xx_hal_crc.c...
|
||||
compiling stm32f4xx_hal_dma_ex.c...
|
||||
compiling stm32f4xx_hal_cortex.c...
|
||||
compiling stm32f4xx_hal_dma.c...
|
||||
compiling stm32f4xx_hal_rcc_ex.c...
|
||||
compiling stm32f4xx_hal_pwr_ex.c...
|
||||
compiling ulog.c...
|
||||
compiling console_be.c...
|
||||
linking...
|
||||
Program Size: Code=139712 RO-data=15040 RW-data=8544 ZI-data=13704
|
||||
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:29
|
||||
@@ -0,0 +1,130 @@
|
||||
*** Using Compiler 'V6.16', folder: 'D:\Program Files\Keil_v5\ARM\ARMCLANG\Bin'
|
||||
Rebuild target 'chrg'
|
||||
compiling main.c...
|
||||
compiling chrg_switch.c...
|
||||
compiling chrg_wdt.c...
|
||||
compiling chrg_gpio.c...
|
||||
compiling chrg_tmr.c...
|
||||
compiling chrg_fal.c...
|
||||
compiling chrg_tty.c...
|
||||
compiling chrg_led.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...
|
||||
compiling chrg_utils.c...
|
||||
compiling syscall_mem.c...
|
||||
compiling syscalls.c...
|
||||
compiling cctype.c...
|
||||
compiling cstdlib.c...
|
||||
compiling cstring.c...
|
||||
compiling ctime.c...
|
||||
compiling cunistd.c...
|
||||
compiling cwchar.c...
|
||||
compiling device.c...
|
||||
compiling hwtimer.c...
|
||||
compiling completion_comm.c...
|
||||
compiling completion_up.c...
|
||||
compiling condvar.c...
|
||||
compiling dataqueue.c...
|
||||
compiling pipe.c...
|
||||
compiling ringblk_buf.c...
|
||||
compiling ringbuffer.c...
|
||||
compiling waitqueue.c...
|
||||
compiling workqueue.c...
|
||||
compiling dev_pin.c...
|
||||
compiling dev_serial.c...
|
||||
compiling dev_watchdog.c...
|
||||
compiling stm32f4xx_hal_msp.c...
|
||||
compiling board.c...
|
||||
compiling drv_flash_f4.c...
|
||||
compiling drv_gpio.c...
|
||||
compiling drv_tim.c...
|
||||
compiling drv_usart.c...
|
||||
compiling drv_usbd.c...
|
||||
compiling drv_wdt.c...
|
||||
compiling drv_common.c...
|
||||
compiling fal.c...
|
||||
compiling fal_flash.c...
|
||||
compiling fal_partition.c...
|
||||
compiling fal_rtt.c...
|
||||
compiling shell.c...
|
||||
compiling msh_parse.c...
|
||||
compiling cmd.c...
|
||||
compiling msh.c...
|
||||
compiling clock.c...
|
||||
compiling components.c...
|
||||
compiling cpu_up.c...
|
||||
compiling defunct.c...
|
||||
compiling idle.c...
|
||||
compiling ipc.c...
|
||||
compiling irq.c...
|
||||
compiling kservice.c...
|
||||
compiling memheap.c...
|
||||
compiling mempool.c...
|
||||
compiling object.c...
|
||||
compiling scheduler_comm.c...
|
||||
compiling scheduler_up.c...
|
||||
compiling thread.c...
|
||||
compiling timer.c...
|
||||
compiling rt_vsnprintf_tiny.c...
|
||||
compiling kerrno.c...
|
||||
compiling kstring.c...
|
||||
compiling rt_vsscanf.c...
|
||||
compiling kstdio.c...
|
||||
compiling atomic_arm.c...
|
||||
compiling div0.c...
|
||||
compiling showmem.c...
|
||||
assembling context_rvds.S...
|
||||
compiling cpuport.c...
|
||||
compiling usbdevice.c...
|
||||
compiling cdc_vcom.c...
|
||||
compiling usbdevice_core.c...
|
||||
assembling startup_stm32f405xx.s...
|
||||
compiling system_stm32f4xx.c...
|
||||
compiling stm32f4xx_hal_gpio.c...
|
||||
compiling stm32f4xx_hal_flash.c...
|
||||
compiling stm32f4xx_hal_usart.c...
|
||||
compiling stm32f4xx_hal_rng.c...
|
||||
compiling stm32f4xx_hal_uart.c...
|
||||
compiling stm32f4xx_hal_wwdg.c...
|
||||
compiling stm32f4xx_hal_tim.c...
|
||||
compiling stm32f4xx_hal_cryp_ex.c...
|
||||
compiling stm32f4xx_hal_pwr.c...
|
||||
compiling stm32f4xx_hal_rcc.c...
|
||||
compiling stm32f4xx_hal_hcd.c...
|
||||
compiling stm32f4xx_ll_usb.c...
|
||||
compiling stm32f4xx_hal_pccard.c...
|
||||
compiling stm32f4xx_hal_flash_ex.c...
|
||||
compiling stm32f4xx_hal_flash_ramfunc.c...
|
||||
compiling stm32f4xx_hal_tim_ex.c...
|
||||
compiling stm32f4xx_hal_lptim.c...
|
||||
compiling stm32f4xx_hal_cec.c...
|
||||
compiling stm32f4xx_hal_cryp.c...
|
||||
compiling stm32f4xx_hal.c...
|
||||
compiling stm32f4xx_hal_iwdg.c...
|
||||
compiling stm32f4xx_hal_pcd_ex.c...
|
||||
compiling stm32f4xx_hal_pcd.c...
|
||||
compiling stm32f4xx_hal_crc.c...
|
||||
compiling stm32f4xx_hal_dma_ex.c...
|
||||
compiling stm32f4xx_hal_cortex.c...
|
||||
compiling stm32f4xx_hal_dma.c...
|
||||
compiling stm32f4xx_hal_rcc_ex.c...
|
||||
compiling stm32f4xx_hal_pwr_ex.c...
|
||||
compiling ulog.c...
|
||||
compiling console_be.c...
|
||||
linking...
|
||||
Program Size: Code=139960 RO-data=15064 RW-data=8544 ZI-data=13704
|
||||
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:27
|
||||
@@ -0,0 +1,9 @@
|
||||
*** Using Compiler 'V6.16', folder: 'D:\Program Files\Keil_v5\ARM\ARMCLANG\Bin'
|
||||
Build target 'chrg'
|
||||
compiling chrg_north.c...
|
||||
linking...
|
||||
Program Size: Code=140256 RO-data=15160 RW-data=8544 ZI-data=13704
|
||||
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:02
|
||||
+111
@@ -0,0 +1,111 @@
|
||||
静态排查后,暂未看到明确的 ABBA 型互斥锁环。当前现象更像“内存破坏/资源泄漏后线程停滞”或“状态机无限重试”,而不是整个 RTOS 调度器死锁。
|
||||
|
||||
另外,代码中使用的是 STM32 内部 IWDG,不是外部独立看门狗。
|
||||
|
||||
**可疑点**
|
||||
|
||||
1. **高风险:南北向分包接收存在确定的越界写和泄漏路径**
|
||||
|
||||
[north](D:/proj/char/chrg_v/apps/chrg/applications/thread/chrg_north.c:548) 和 [south](D:/proj/char/chrg_v/apps/chrg/applications/thread/chrg_south.c:309) 在续接分包时计算:
|
||||
|
||||
```text
|
||||
len_need = len_msg - 帧头长度
|
||||
```
|
||||
|
||||
但此时 `pFrame->length` 已经包含之前收到的数据,正确的剩余长度应基于 `len_msg - pFrame->length`。当前代码却从 `payload[pFrame->length]` 开始写入整个“帧头后的总长度”。
|
||||
|
||||
例如总长 21 字节,首批已存 8 字节,下一次仍可能从偏移 8 写入 18 字节,最终写到偏移 26,越过 21 字节堆块。这会破坏相邻堆块、邮箱消息甚至 RT-Thread 内核对象,最终表现为随机线程卡死、互斥量异常或堆分配失败。
|
||||
|
||||
同时,分包超时路径只清除了 `findhead`:
|
||||
|
||||
- [chrg_north.c:627](D:/proj/char/chrg_v/apps/chrg/applications/thread/chrg_north.c:627)
|
||||
- [chrg_south.c:399](D:/proj/char/chrg_v/apps/chrg/applications/thread/chrg_south.c:399)
|
||||
|
||||
没有释放 `pMB/payload`,也没有清除 `length/len_msg`。而且没有新数据时会提前 `continue`,超时检查根本不会执行。串口噪声、丢字节或正常分包都可能不断积累泄漏。
|
||||
|
||||
此外,payload 分配失败时只返回,没有释放刚分配的 `pMB`:
|
||||
|
||||
- [chrg_north.c:518](D:/proj/char/chrg_v/apps/chrg/applications/thread/chrg_north.c:518)
|
||||
- [chrg_south.c:280](D:/proj/char/chrg_v/apps/chrg/applications/thread/chrg_south.c:280)
|
||||
|
||||
这是目前最符合“运行时间越长越容易出现”的可疑点。
|
||||
|
||||
2. **高风险:看门狗喂法无法覆盖业务线程死锁**
|
||||
|
||||
主线程每秒无条件喂狗:[main.c:36](D:/proj/char/chrg_v/apps/chrg/applications/main.c:36)。
|
||||
|
||||
北向轮询线程又在每轮无条件喂同一只狗:[chrg_roll_nor.c:421](D:/proj/char/chrg_v/apps/chrg/applications/thread/chrg_roll_nor.c:421)。
|
||||
|
||||
因此即使 `thr.comm`、`thr.sou`、`thr.rollsou`、LCD 线程全部停止工作,只要主线程或北向轮询线程仍能调度,IWDG 就永远不会复位。这只是在检测“CPU/调度器是否完全停止”,没有检测业务线程是否健康。
|
||||
|
||||
驱动最终调用的是 `HAL_IWDG_Refresh()`:[drv_wdt.c:40](D:/proj/char/chrg_v/rt-thread/bsp/stm32/libraries/HAL_Drivers/drivers/drv_wdt.c:40)。代码中没有找到外部 WDI 引脚翻转或外部看门狗驱动。
|
||||
|
||||
3. **高风险:当前新增的南向批处理可能永久停在 `RUN_COM`**
|
||||
|
||||
南向批处理遇到 CRC 错误或应答超时后,不增加重试次数、不设置截止时间,也不清除任务:
|
||||
|
||||
- CRC 错误:[chrg_roll_sou.c:608](D:/proj/char/chrg_v/apps/chrg/applications/thread/chrg_roll_sou.c:608)
|
||||
- 应答超时:[chrg_roll_sou.c:627](D:/proj/char/chrg_v/apps/chrg/applications/thread/chrg_roll_sou.c:627)
|
||||
|
||||
线程会一直重发同一个寄存器,`pending` 永远不清除,`run` 永远保持 `RUN_COM`,正常南向轮询无法恢复。这属于业务状态机死锁,调度器仍正常运行,所以看门狗不会复位。
|
||||
|
||||
这套批处理逻辑是当前工作区相对 `HEAD` 新增的,优先级很高。
|
||||
|
||||
4. **高风险:南向共享状态的互斥保护实际无效**
|
||||
|
||||
[chrg_set_sou_reg](D:/proj/char/chrg_v/apps/chrg/applications/thread/chrg_roll_sou.c:435) 先在锁外写入:
|
||||
|
||||
```text
|
||||
pROLL->ch
|
||||
pROLL->reg
|
||||
pROLL->value
|
||||
```
|
||||
|
||||
随后互斥量只保护 `pROLL->run`。消费者也只在锁内读取 `run`,实际使用 `ch/reg/value` 时已经离开锁。
|
||||
|
||||
多个生产者包括 LCD、Modbus 和状态机可能交叉覆盖这些字段,形成“通道来自命令 A、寄存器来自命令 B、值来自命令 C”的组合。
|
||||
|
||||
批处理数组 `g_sou_com_batch` 同样由生产者和 `thr.rollsou` 同时读写,却没有共同的锁:[chrg_roll_sou.c:394](D:/proj/char/chrg_v/apps/chrg/applications/thread/chrg_roll_sou.c:394)。
|
||||
|
||||
5. **中高风险:先切换 `RUN_COM`,再填充批处理数据**
|
||||
|
||||
[chrg_sink_diff_send_reg](D:/proj/char/chrg_v/apps/chrg/applications/thread/chrg_comm.c:2338) 先调用 `chrg_sou_com_sou_set()` 将状态切到 `RUN_COM`,然后才追加寄存器。
|
||||
|
||||
`chrg_sink_work()` 也是相同顺序:[chrg_sink.c:541](D:/proj/char/chrg_v/apps/chrg/applications/utils/chrg_sink.c:541)。
|
||||
|
||||
如果消费者在状态切换后看到尚未填充的批次,会认为没有任务并切回自动模式;随后加入的 `pending` 数据可能一直无人处理。当前线程优先级降低了部分窗口概率,但没有从同步机制上消除竞态。
|
||||
|
||||
6. **中高风险:应答邮箱没有请求、通道或序号关联**
|
||||
|
||||
邮箱消息只有 `length + payload`:[chrg_def.h:95](D:/proj/char/chrg_v/apps/chrg/applications/utils/chrg_def.h:95)。
|
||||
|
||||
南北轮询线程默认“收到的下一帧就是刚才请求的响应”。南向批处理只检查 CRC,任何延迟到达的旧响应都可能让当前批次 `cur_idx++`:[chrg_roll_sou.c:574](D:/proj/char/chrg_v/apps/chrg/applications/thread/chrg_roll_sou.c:574)。
|
||||
|
||||
在超时、重发、通道切换或邮箱积压后,请求与响应很容易错位,最终造成状态机停在错误步骤或无限重试。
|
||||
|
||||
7. **中风险:所有业务互斥量都是永久等待**
|
||||
|
||||
TTY、南北轮询互斥量统一使用 `RT_WAITING_FOREVER`。例如:
|
||||
|
||||
- [chrg_tty.c:457](D:/proj/char/chrg_v/apps/chrg/applications/bsp/chrg_tty.c:457)
|
||||
- [chrg_comm.c:2246](D:/proj/char/chrg_v/apps/chrg/applications/thread/chrg_comm.c:2246)
|
||||
- [chrg_roll_nor.c:439](D:/proj/char/chrg_v/apps/chrg/applications/thread/chrg_roll_nor.c:439)
|
||||
|
||||
目前没有发现确定的反向加锁环,但一旦锁所有者因堆破坏、状态机卡死或设备写阻塞而不再释放,其他线程会永久挂起,没有超时和故障上报。
|
||||
|
||||
8. **中风险:串口 RingBuffer 写入结果被忽略**
|
||||
|
||||
[chrg_north.c:623](D:/proj/char/chrg_v/apps/chrg/applications/thread/chrg_north.c:623) 和 [chrg_south.c:383](D:/proj/char/chrg_v/apps/chrg/applications/thread/chrg_south.c:383) 没有检查 `rt_ringbuffer_put()` 实际写入长度。
|
||||
|
||||
缓冲区满时会静默丢字节,随后触发分包超时、泄漏和上述越界路径,是长期运行后出现问题的重要放大器。
|
||||
|
||||
**优先判断**
|
||||
|
||||
最可能的两条故障链是:
|
||||
|
||||
1. 串口分包 → 长度计算错误/超时泄漏 → 堆损坏或耗尽 → 某些业务线程永久等待;主线程继续喂狗。
|
||||
2. 南向某条命令超时或响应错位 → `RUN_COM` 无限重发 → 南向业务永久停止;主线程和北向线程继续喂狗。
|
||||
|
||||
现场故障尚能进入 Shell 时,优先保存 `list_thread`、`list_mutex`、`list_mailbox`、`free` 输出,并检查是否持续打印 `com batch timeout, resend current reg`。这几项可以直接区分锁等待、堆耗尽和状态机无限重试。
|
||||
|
||||
未修改任何文件。
|
||||
Reference in New Issue
Block a user