diff --git a/apps/chrg/applications/thread/chrg_comm.c b/apps/chrg/applications/thread/chrg_comm.c index 402a739..3cc4c1f 100644 --- a/apps/chrg/applications/thread/chrg_comm.c +++ b/apps/chrg/applications/thread/chrg_comm.c @@ -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; @@ -2228,23 +2234,40 @@ static void chrg_mb_write_sys(rt_uint8_t ch, rt_uint16_t reg_offset, rt_uint16_t } break; - case SYS_REG_PARAM_EFFECT: // 0x01: 参数生效标志 - if (sou_value == 0x01) - { - g_shadow_dirty[ch] = 0; // 标记已生效 + case SYS_REG_PARAM_EFFECT: // 0x01: 参数生效标志 + if (sou_value == 0x01) + { + struct chrg_switch_t *pReal = &pNOR->sw[ch]; + rt_uint8_t pro_change = 0; + sink_proto_diff_t diff_info; + struct chrg_thread_t *pTHR_NOR = &chrgthr[IDX_THR_ROLL_NOR]; + rt_mutex_take(pTHR_NOR->mutex, RT_WAITING_FOREVER); - 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; + 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; - struct chrg_thread_t *pTHR_NOR = &chrgthr[IDX_THR_ROLL_NOR]; - rt_mutex_take(pTHR_NOR->mutex, RT_WAITING_FOREVER); - rt_memcpy(pReal, &g_shadow_sw[ch], sizeof(struct chrg_switch_t)); + rt_memcpy(pReal, &g_shadow_sw[ch], sizeof(struct chrg_switch_t)); if (new_id == ID_SINK) { if (sink_work == 0x01) // 负载启动 @@ -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) { @@ -2311,10 +2345,12 @@ static void chrg_mb_write_sys(rt_uint8_t ch, rt_uint16_t reg_offset, rt_uint16_t rt_mutex_release(pTHR_NOR->mutex); } break; - default: - rt_kprintf("[SYS CH%d] Unknown reg offset=0x%02X\n", ch + 1, reg_offset); - break; - } + default: + 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) -{ - chrg_sou_com_sou_set(); - 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->cvmode_changed){ - chrg_sou_com_batch_add_reg(ch, REG_MODE, pReal->CV_mode); - } +int chrg_sink_diff_send_reg(eIDX_SOU_CH ch, sink_proto_diff_t *pDiff, struct chrg_switch_t *pReal) +{ + rt_uint16_t regs[2]; + rt_uint16_t vals[2]; + rt_uint8_t count = 0; + + if (pReal->CV_mode == 0x01) { + 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) { + 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; } diff --git a/apps/chrg/applications/thread/chrg_comm.h b/apps/chrg/applications/thread/chrg_comm.h index 0754c9a..549ab17 100644 --- a/apps/chrg/applications/thread/chrg_comm.h +++ b/apps/chrg/applications/thread/chrg_comm.h @@ -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 diff --git a/apps/chrg/applications/thread/chrg_north.c b/apps/chrg/applications/thread/chrg_north.c index 39bdd49..cd26970 100644 --- a/apps/chrg/applications/thread/chrg_north.c +++ b/apps/chrg/applications/thread/chrg_north.c @@ -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); + pFrame->length = LEN_FRAME_HEAD; + pFrame->findhead = 1; + pFrame->last_tick = rt_tick_get(); - 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; + 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[LEN_FRAME_HEAD], len_rb); - pFrame->length = LEN_FRAME_HEAD + len_rb; - pFrame->findhead = 1; - pFrame->last_tick = rt_tick_get(); 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 diff --git a/apps/chrg/applications/thread/chrg_north.h b/apps/chrg/applications/thread/chrg_north.h index 9004694..abefd28 100644 --- a/apps/chrg/applications/thread/chrg_north.h +++ b/apps/chrg/applications/thread/chrg_north.h @@ -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 = 开启 diff --git a/apps/chrg/applications/thread/chrg_roll_sou.c b/apps/chrg/applications/thread/chrg_roll_sou.c index 94be810..23f36cd 100644 --- a/apps/chrg/applications/thread/chrg_roll_sou.c +++ b/apps/chrg/applications/thread/chrg_roll_sou.c @@ -391,6 +391,9 @@ #define LOG_TAG "chrg.rollsou" #include +#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,30 +403,48 @@ 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; + 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 (RT_NULL != pMB_R) - { - rt_free(pMB_R); - pMB_R = 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); + } + } 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; } diff --git a/apps/chrg/applications/thread/chrg_roll_sou.h b/apps/chrg/applications/thread/chrg_roll_sou.h index b707c96..8115eab 100644 --- a/apps/chrg/applications/thread/chrg_roll_sou.h +++ b/apps/chrg/applications/thread/chrg_roll_sou.h @@ -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 diff --git a/apps/chrg/applications/thread/chrg_south.c b/apps/chrg/applications/thread/chrg_south.c index 2fb6463..310f24e 100644 --- a/apps/chrg/applications/thread/chrg_south.c +++ b/apps/chrg/applications/thread/chrg_south.c @@ -23,6 +23,8 @@ #define DBG_LEVEL DBG_LOG #include +#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); + pFrame->length = MB_ACK_HEAD_SIZE; + pFrame->findhead = 1; + pFrame->last_tick = rt_tick_get(); - 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; + 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[MB_ACK_HEAD_SIZE], len_rb); - pFrame->length = MB_ACK_HEAD_SIZE + len_rb; - pFrame->findhead = 1; - pFrame->last_tick = rt_tick_get(); 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); } diff --git a/apps/chrg/applications/thread/chrg_thread.c b/apps/chrg/applications/thread/chrg_thread.c index d15de89..cdfb7fe 100644 --- a/apps/chrg/applications/thread/chrg_thread.c +++ b/apps/chrg/applications/thread/chrg_thread.c @@ -146,32 +146,40 @@ rt_err_t chrg_thread_evt_send (eIDX_THRS idx, rt_uint32_t data) 返回说明: 0: OK , !=0 : FAILED 其它说明: - *****************************************************************/ +static void chrg_thread_mb_free(void *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); +} + rt_err_t chrg_thread_mb_send (eIDX_THRS idx, void *data) { - rt_err_t ret = RT_EOK; + rt_err_t ret; - if (idx >= TOTAL_THRS) { + 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) { - 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->payload) { - rt_free(pMB->payload); - } - rt_free(pMB); - } - } else { - LOG_E("mb send failed. [%d]", ret); - } - } + 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; diff --git a/apps/chrg/applications/utils/chrg_sink.c b/apps/chrg/applications/utils/chrg_sink.c index 64b705d..4be4501 100644 --- a/apps/chrg/applications/utils/chrg_sink.c +++ b/apps/chrg/applications/utils/chrg_sink.c @@ -444,67 +444,72 @@ 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; pSOU->online[idx] = 1; 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) - { - chrg_sou_com_batch_add_reg(idx, REG_VOLTAGE_OUT+1, pSW->sink.loadv); - } - 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); +static int chrg_sink_work_volt_runing(eIDX_SOU_CH idx, struct chrg_switch_t *pSW) +{ + 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; + } + 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,70 +517,80 @@ 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 (work_mode == last_state[idx]) - { - return; - } - chrg_sou_com_sou_set(); + if ((idx >= TOTAL_SOU_CHS) || (pSW == RT_NULL)) { + return -1; + } + work_mode = pSW->sink.work_mode; + + // 本次状态和上次一致,直接跳过,不重复下发寄存器 + if (work_mode == last_state[idx]) { + return 0; + } 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); - break; + ret = chrg_sink_nor_work_off(idx,pSW); + break; + default: + break; } -// 更新缓存,保存本次最新状态 - last_state[idx] = work_mode; + if (ret == 0) { + last_state[idx] = work_mode; + } + return ret; } diff --git a/apps/chrg/applications/utils/chrg_sink.h b/apps/chrg/applications/utils/chrg_sink.h index 6eba83d..1025ce4 100644 --- a/apps/chrg/applications/utils/chrg_sink.h +++ b/apps/chrg/applications/utils/chrg_sink.h @@ -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 diff --git a/apps/chrg/debug_hot.ini b/apps/chrg/debug_hot.ini index bccb64e..d5b340e 100644 --- a/apps/chrg/debug_hot.ini +++ b/apps/chrg/debug_hot.ini @@ -1 +1,4 @@ -LOAD %L INCREMENTAL \ No newline at end of file +LOAD %L INCREMENTAL +BS HardFault_Handler +BS rt_assert_handler +G diff --git a/apps/chrg/keil_flash.log b/apps/chrg/keil_flash.log new file mode 100644 index 0000000..69d25eb --- /dev/null +++ b/apps/chrg/keil_flash.log @@ -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 diff --git a/apps/chrg/keil_rebuild.log b/apps/chrg/keil_rebuild.log new file mode 100644 index 0000000..53f749a --- /dev/null +++ b/apps/chrg/keil_rebuild.log @@ -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 diff --git a/apps/chrg/keil_trace_build.log b/apps/chrg/keil_trace_build.log new file mode 100644 index 0000000..d96d67b --- /dev/null +++ b/apps/chrg/keil_trace_build.log @@ -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 diff --git a/apps/chrg/keil_trace_build2.log b/apps/chrg/keil_trace_build2.log new file mode 100644 index 0000000..37fa659 --- /dev/null +++ b/apps/chrg/keil_trace_build2.log @@ -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 diff --git a/docs/修改计划.md b/docs/修改计划.md new file mode 100644 index 0000000..15d3a41 --- /dev/null +++ b/docs/修改计划.md @@ -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`。这几项可以直接区分锁等待、堆耗尽和状态机无限重试。 + +未修改任何文件。 \ No newline at end of file