diff --git a/apps/chrg/applications/thread/chrg_comm.c b/apps/chrg/applications/thread/chrg_comm.c index f57780e..9066f7b 100644 --- a/apps/chrg/applications/thread/chrg_comm.c +++ b/apps/chrg/applications/thread/chrg_comm.c @@ -36,10 +36,41 @@ rt_uint8_t g_proto_pData[80] = {0};//上位机协议指令,控制四个通道 rt_uint16_t g_proto_reqLen = 0; rt_uint8_t mobude_ymodem_buf[MB_YMODEM_DATA_SIZE] = {0};//南向功率板升级缓冲区 rt_uint8_t mobude_ymodem_buf_2[MB_YMODEM_DATA_SIZE] = {0};//南向功率板升级缓冲区 + +#define YMODEM_C_PERIOD_MS 1000 +#define YMODEM_META_ACK_TIMEOUT_MS 3000 +#define YMODEM_DATA_ACK_TIMEOUT_MS 1000 +#define YMODEM_MAX_RETRIES 3 + +/* COM侧升级会话状态:接收缓存负责拼帧,备份缓存负责超时/NAK重发。 */ +static rt_uint16_t g_ymodem_rx_len = 0; +static rt_uint16_t g_ymodem_expected_len = 0; +static rt_uint16_t g_ymodem_last_len = 0; +static rt_uint8_t g_ymodem_waiting_ack = 0; +static rt_uint8_t g_ymodem_retry_count = 0; +static rt_uint8_t g_ymodem_eot_done = 0; +static rt_tick_t g_ymodem_send_tick = 0; +static rt_tick_t g_ymodem_c_tick = 0; /* Modbus 影子寄存器: 0x06/0x10 写操作暂存到此, PARAM_EFFECT 生效后复制到实际 pNOR->sw */ static struct chrg_switch_t g_shadow_sw[TOTAL_NOR_CHS]; static rt_uint8_t g_shadow_dirty[TOTAL_NOR_CHS] = {0}; /* 0=已生效 1=待生效,防止重复覆盖 */ +/* + * Source和Sink共用的参数差异结果。前五项是两个角色都具备的控制属性, + * 后三项只用于Sink快充协议配置;Source比较时保持为RT_FALSE。 + */ +typedef struct +{ + rt_bool_t protocol_changed; + rt_bool_t cc_changed; + rt_bool_t cv_changed; + rt_bool_t voltage_changed; + rt_bool_t current_changed; + rt_bool_t group_changed; + rt_bool_t pro_voltage_changed; + rt_bool_t pro_current_changed; +} chrg_param_diff_t; + /* 首次写入影子寄存器前,从真实结构体同步,避免覆盖运行中的关键标志位 */ static void chrg_shadow_sync(rt_uint8_t ch) { @@ -66,6 +97,8 @@ 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 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); +static int chrg_sink_diff_send_reg(eIDX_SOU_CH ch, + const chrg_param_diff_t *pDiff, struct chrg_switch_t *pReal); /*! \brief Function to set bits in a byte buffer. * @@ -185,16 +218,6 @@ rt_uint8_t mb_get_bits (rt_uint8_t * ucByteBuf, rt_uint16_t usBitOffset, rt_uint return (rt_uint8_t)usWordBuf; } -static void set_ymodem_update_channel(struct chrg_north_t *pNOR,struct chrg_south_t *pSOU,eIDX_SOU_CH ch) -{ - for (int i = 0; i < 4; i++) { - pNOR->enable[i] = 0; - pSOU->enable[i] = 0; - } - pNOR->enable[ch] = 1; - pSOU->enable[ch] = 1; -} - static eMBException mb_error (eMBErrorCode eErrorCode) { eMBException eStatus; @@ -361,20 +384,12 @@ eMBErrorCode mb_reg_test_cb (rt_uint8_t *req, rt_uint8_t *pucRegBuffer, rt_uint1 *****************************************************************/ eMBErrorCode mb_ymodem_updata_cb (rt_uint8_t *state, rt_uint8_t *pucRegBuffer) { - eMBErrorCode eStatus = MB_ENOERR; - - switch (*state) { - /* read current register values from the protocol stack. */ - case 0: - /* 返回值反映实际ymodem升级状态: ACK_C=空闲, ACK=升级中 */ - pucRegBuffer[0] = (*state == Ymodem_No) ? ACK_C : ACK; - break; - case 1: - pucRegBuffer[0] = (*state == Ymodem_No) ? ACK_C : ACK; - break; - /* write current register values with new values from the protocol stack. */ - } - return eStatus; + if ((state == RT_NULL) || (pucRegBuffer == RT_NULL)) { + return MB_EINVAL; + } + /* Ymodem_No的枚举值为0xFF,不能用只覆盖0和1的switch生成响应。 */ + pucRegBuffer[0] = (*state == Ymodem_No) ? ACK_C : ACK; + return MB_ENOERR; } eMBErrorCode mb_reg_coils_cb (rt_uint8_t *req, rt_uint8_t *pucRegBuffer, rt_uint16_t usAddress, @@ -1112,13 +1127,13 @@ eMBException funcWriteMultipleHoldingRegister (rt_uint8_t *reqFrame, rt_uint16_t switch (sout_reg) { case REG_VOLTAGE_OUT + 1: - pSW->source.max_vol = sou_value; + pSW->source.vc.set_voltage = sou_value; pSW->sink.loadv = sou_value; chrg_set_sou_reg(ch, sout_reg, sou_value); rt_kprintf("voltage=%d", sou_value); break; case REG_CURRENT_OUT + 1: - pSW->source.protective_curr = sou_value; + pSW->source.vc.set_current = sou_value; pSW->sink.loadc = sou_value; chrg_set_sou_reg(ch, sout_reg, sou_value); break; @@ -1303,54 +1318,135 @@ eMBException funcTrimELoad (rt_uint8_t *reqFrame, rt_uint16_t reqLen, Ymodem_state ystate = Ymodem_No; rt_uint8_t s_first_soh_rcvd = 0; + +/***************************************************************** +函数名称: chrg_ymodem_protocol_reset +函数描述: 清空COM侧Ymodem拼帧、重发和握手状态 +输入参数: - +输出参数: - +返回说明: - +其它说明: 不改变南向轮询模式和目标通道 +*****************************************************************/ +static void chrg_ymodem_protocol_reset(void) +{ + rt_memset(mobude_ymodem_buf, 0, sizeof(mobude_ymodem_buf)); + rt_memset(mobude_ymodem_buf_2, 0, sizeof(mobude_ymodem_buf_2)); + g_ymodem_rx_len = 0; + g_ymodem_expected_len = 0; + g_ymodem_last_len = 0; + g_ymodem_waiting_ack = 0; + g_ymodem_retry_count = 0; + g_ymodem_eot_done = 0; + g_ymodem_send_tick = 0; + g_ymodem_c_tick = rt_tick_get(); + s_first_soh_rcvd = 0; +} + +/***************************************************************** +函数名称: chrg_ymodem_session_start +函数描述: 停止普通南向请求并进入指定通道的升级透传模式 +输入参数: ch:需要升级的南向功率板通道 +输出参数: - +返回说明: 0:成功 <0:线程互斥锁未就绪或加锁失败 +其它说明: 不修改chrgnorth.enable和chrgsouth.enable,升级结束后恢复自动轮询 +*****************************************************************/ +static int chrg_ymodem_session_start(eIDX_SOU_CH ch) +{ + struct chrg_thread_t *pTHR = &chrgthr[IDX_THR_ROLL_SOU]; + struct chrg_rollsou_t *pROLL = &chrgrollsou; + struct chrg_south_t *pSOU = &chrgsouth; + + if ((ch >= TOTAL_SOU_CHS) || (pTHR->mutex == RT_NULL)) { + return -1; + } + if (rt_mutex_take(pTHR->mutex, rt_tick_from_millisecond(100)) != RT_EOK) { + return -2; + } + /* 先阻止南向线程继续发普通Modbus请求,等待已发请求退出邮箱等待。 */ + pROLL->run = RUN_UPDATA; + pROLL->ch = (rt_uint8_t)ch; + pROLL->send_flag = 0; + pROLL->leng = 0; + pROLL->updata_result = 0; + rt_mutex_release(pTHR->mutex); + rt_thread_mdelay(25); + + chrg_eload_clear_ymodem_resp(); + if (pSOU->rb != RT_NULL) { + rt_ringbuffer_reset(pSOU->rb); + } + chrg_ymodem_protocol_reset(); + + rt_mutex_take(pTHR->mutex, RT_WAITING_FOREVER); + pROLL->mode = 1; + pROLL->run = RUN_UPDATA; + pROLL->ch = (rt_uint8_t)ch; + rt_mutex_release(pTHR->mutex); + ystate = Ymodem_Wait; + return 0; +} + +/***************************************************************** +函数名称: chrg_ymodem_session_stop +函数描述: 退出南向升级透传模式并恢复普通自动轮询 +输入参数: - +输出参数: - +返回说明: - +其它说明: 清除残留升级应答,避免其被普通Modbus解析器误识别 +*****************************************************************/ +static void chrg_ymodem_session_stop(void) +{ + struct chrg_thread_t *pTHR = &chrgthr[IDX_THR_ROLL_SOU]; + struct chrg_rollsou_t *pROLL = &chrgrollsou; + struct chrg_south_t *pSOU = &chrgsouth; + + if (pTHR->mutex != RT_NULL) { + rt_mutex_take(pTHR->mutex, RT_WAITING_FOREVER); + pROLL->mode = 0; + pROLL->send_flag = 0; + pROLL->leng = 0; + pROLL->updata_result = 0; + pROLL->run = RUN_AUTO; + rt_mutex_release(pTHR->mutex); + } + chrg_eload_clear_ymodem_resp(); + if (pSOU->rb != RT_NULL) { + rt_ringbuffer_reset(pSOU->rb); + } + chrg_ymodem_protocol_reset(); + ystate = Ymodem_No; +} + eMBException funYmodemUpadata (rt_uint8_t *reqFrame, rt_uint16_t reqLen, rt_uint8_t *resFrame, rt_uint16_t *resLen) { - rt_uint8_t test_mode = 0; // 测试模式 0x01/0x02/0x03 - eIDX_SOU_CH ch = IDX_SOU_CH1; // 通道枚举 - rt_uint8_t chNum = 0; // 通道号 1~4 - chNum = reqFrame[4]; - ch = (eIDX_SOU_CH)(chNum); - struct chrg_north_t *pNOR = &chrgnorth; - struct chrg_south_t *pSOU = &chrgsouth; - struct chrg_rollsou_t *pROLL = &chrgrollsou; - // Modbus异常 - eMBException eStatus = MB_EX_NONE; - eMBErrorCode eRegStatus; - if(chNum<0||chNum>3){ - return 0; + rt_uint8_t ch_num; + eIDX_SOU_CH ch; + + if ((reqFrame == RT_NULL) || (resFrame == RT_NULL) || (resLen == RT_NULL) || + (reqLen != 8)) { + return MB_EX_ILLEGAL_DATA_VALUE; } - rt_kprintf("ch = %d",ch); - //解析上位机的帧头判断状态 - if(reqLen==8){ - if(reqFrame[5] == 0xff){ - pROLL->mode = 1; - set_ymodem_update_channel(pNOR, pSOU, ch); - ystate = Ymodem_Wait; - pROLL->ch = ch; - s_first_soh_rcvd = 0; - chrg_eload_clear_ymodem_resp(); /* 进入升级时清除残留应答 */ - } - if(reqFrame[5] == 0x00){ - pROLL->mode = 0; - ystate = Ymodem_No; - set_ymodem_update_channel(pNOR, pSOU, ch); - s_first_soh_rcvd = 0; - chrg_eload_clear_ymodem_resp(); /* 退出升级时清除残留应答 */ - } + ch_num = reqFrame[4]; + if (ch_num >= TOTAL_SOU_CHS) { + return MB_EX_ILLEGAL_DATA_ADDRESS; + } + ch = (eIDX_SOU_CH)ch_num; + + if (reqFrame[5] == 0xFF) { + if (chrg_ymodem_session_start(ch) != 0) { + return MB_EX_SLAVE_BUSY; } + } else if (reqFrame[5] == 0x00) { + chrg_ymodem_session_stop(); + } else { + return MB_EX_ILLEGAL_DATA_VALUE; + } - #if SINK_TEST_DEBUG - rt_kprintf("test_mode=%d\n",test_mode); - //rt_kprintf("test_flag=%d\n",pTset->test_mode); - #endif - - eRegStatus = mb_ymodem_updata_cb(&ystate,resFrame); - /************ 响应帧 ************/ - // rt_memcpy(resFrame, reqFrame, reqLen-2); - *resLen = 1;//reqLen -2; - - return eStatus; + /* 保留原0x20响应内容,外层统一补设备地址和Modbus CRC。 */ + (void)mb_ymodem_updata_cb(&ystate, resFrame); + *resLen = 1; + return MB_EX_NONE; } static struct code_func_t funcHandlers[MB_HANDLERS_MAX] = { @@ -1435,6 +1531,279 @@ static int chrg_comm_parse_msg (struct chrg_comm_t *pCOMM) return ret; } +/* + * 旧版Ymodem处理代码保留在下方注释中作为历史参考。当前实现使用完整拼帧、 + * CRC校验和停止等待重发机制,不再依赖一次串口接收刚好得到一整帧。 + */ + +/***************************************************************** +函数名称: chrg_ymodem_frame_size +函数描述: 根据Ymodem控制字符取得一帧应接收的总长度 +输入参数: header:Ymodem帧头或控制字符 +输出参数: - +返回说明: 133:SOH帧 1029:STX帧 1:EOT/CAN 0:无效字符 +其它说明: - +*****************************************************************/ +static rt_uint16_t chrg_ymodem_frame_size(rt_uint8_t header) +{ + if (header == SOH) { + return YMODEM_SOH_SIZE; + } + if (header == STX) { + return YMODEM_STX_SIZE; + } + if ((header == EOT) || (header == YM_CAN)) { + return 1; + } + return 0; +} + +/***************************************************************** +函数名称: chrg_ymodem_crc16 +函数描述: 计算Ymodem数据区使用的CRC16-XMODEM校验值 +输入参数: data:数据区地址 length:数据区长度 +输出参数: - +返回说明: CRC16-XMODEM校验值 +其它说明: 初值0,多项式0x1021,结果按高字节在前写入Ymodem帧 +*****************************************************************/ +static rt_uint16_t chrg_ymodem_crc16(const rt_uint8_t *data, rt_uint16_t length) +{ + rt_uint16_t crc = 0; + rt_uint16_t i; + rt_uint8_t bit; + + for (i = 0; i < length; i++) { + crc ^= (rt_uint16_t)data[i] << 8; + for (bit = 0; bit < 8; bit++) { + crc = (crc & 0x8000) ? (rt_uint16_t)((crc << 1) ^ 0x1021) : + (rt_uint16_t)(crc << 1); + } + } + return crc; +} + +/***************************************************************** +函数名称: chrg_ymodem_frame_valid +函数描述: 校验Ymodem数据帧长度、包号反码和数据区CRC +输入参数: frame:完整Ymodem帧 length:帧总长度 +输出参数: - +返回说明: RT_TRUE:有效 RT_FALSE:无效 +其它说明: EOT和CAN为单字节控制帧,不包含包号与CRC +*****************************************************************/ +static rt_bool_t chrg_ymodem_frame_valid(const rt_uint8_t *frame, rt_uint16_t length) +{ + rt_uint16_t data_len; + rt_uint16_t frame_crc; + + if ((frame == RT_NULL) || (length != chrg_ymodem_frame_size(frame[0]))) { + return RT_FALSE; + } + if ((frame[0] == EOT) || (frame[0] == YM_CAN)) { + return RT_TRUE; + } + if ((rt_uint8_t)(frame[1] + frame[2]) != 0xFF) { + return RT_FALSE; + } + data_len = (frame[0] == SOH) ? 128 : 1024; + frame_crc = ((rt_uint16_t)frame[length - 2] << 8) | frame[length - 1]; + return chrg_ymodem_crc16(&frame[YMODEM_DATA_OFFSET], data_len) == frame_crc; +} + +/***************************************************************** +函数名称: chrg_ymodem_resend_last +函数描述: 将最近一次完整Ymodem帧重新提交给南向发送线程 +输入参数: - +输出参数: - +返回说明: 0:提交成功 -1:无可重发帧 其它:南向提交错误 +其它说明: 仅在NAK或等待应答超时时调用,始终使用原帧实际长度 +*****************************************************************/ +static int chrg_ymodem_resend_last(void) +{ + int ret; + + if (g_ymodem_last_len == 0) { + return -1; + } + ret = chrg_send_sou_upadata_data(mobude_ymodem_buf_2, g_ymodem_last_len); + if (ret == 0) { + g_ymodem_retry_count++; + g_ymodem_send_tick = rt_tick_get(); + g_ymodem_waiting_ack = 1; + } + return ret; +} + +/***************************************************************** +函数名称: chrg_ymodem_process +函数描述: 累计COM串口分段数据,形成完整Ymodem帧后提交到南向线程 +输入参数: data:本次串口数据 length:本次数据长度 +输出参数: - +返回说明: 0:处理完成 -2:仍在等待上一帧应答 -3:帧校验失败 -4:提交失败 +其它说明: 一帧可由多次串口接收组成,只有完整且校验通过后才会发送到功率板 +*****************************************************************/ +static int chrg_ymodem_process(const rt_uint8_t *data, rt_uint16_t length) +{ + rt_uint16_t offset = 0; + rt_uint16_t copy_len; + int ret; + + if ((data == RT_NULL) || (length == 0)) { + return 0; + } + while (offset < length) { + if (g_ymodem_waiting_ack != 0) { + return -2; + } + if (g_ymodem_expected_len == 0) { + g_ymodem_expected_len = chrg_ymodem_frame_size(data[offset]); + if (g_ymodem_expected_len == 0) { + offset++; + continue; + } + g_ymodem_rx_len = 0; + } + + copy_len = g_ymodem_expected_len - g_ymodem_rx_len; + if (copy_len > (length - offset)) { + copy_len = length - offset; + } + rt_memcpy(&mobude_ymodem_buf[g_ymodem_rx_len], &data[offset], copy_len); + g_ymodem_rx_len += copy_len; + offset += copy_len; + if (g_ymodem_rx_len < g_ymodem_expected_len) { + continue; + } + + if (!chrg_ymodem_frame_valid(mobude_ymodem_buf, g_ymodem_rx_len)) { + g_ymodem_rx_len = 0; + g_ymodem_expected_len = 0; + return -3; + } + + g_ymodem_last_len = g_ymodem_rx_len; + rt_memcpy(mobude_ymodem_buf_2, mobude_ymodem_buf, g_ymodem_last_len); + if (mobude_ymodem_buf[0] == SOH) { + if (g_ymodem_eot_done != 0) { + /* 第二次EOT之后的0号空SOH是Ymodem收尾帧,只回复ACK。 */ + ystate = Ymodem_Rec_Finish; + } else if ((mobude_ymodem_buf[1] == 0) && (s_first_soh_rcvd == 0)) { + /* 只有传输开始时的0号SOH是文件名/大小帧,需要回复ACK+C。 */ + ystate = Ymodem_Rec_Start; + s_first_soh_rcvd = 1; + } else { + /* 包号非0的SOH是普通128字节固件数据帧,只回复ACK。 */ + ystate = Ymodem_Rec_1024; + } + } else if (mobude_ymodem_buf[0] == STX) { + ystate = Ymodem_Rec_1024; + } else if (mobude_ymodem_buf[0] == EOT) { + ystate = Ymodem_Rec_End; + } else { + ystate = Ymodem_Rec_Finish; + } + + ret = chrg_send_sou_upadata_data(mobude_ymodem_buf_2, g_ymodem_last_len); + g_ymodem_rx_len = 0; + g_ymodem_expected_len = 0; + if (ret != 0) { + return -4; + } + g_ymodem_retry_count = 0; + g_ymodem_waiting_ack = 1; + g_ymodem_send_tick = rt_tick_get(); + } + return 0; +} + +/***************************************************************** +函数名称: ymodem_send +函数描述: 处理南向Ymodem应答、生成上位机应答并执行超时重发 +输入参数: pCOMM:COM通信对象 +输出参数: pCOMM->tx_buf和pCOMM->tx_len +返回说明: 1:需要向上位机发送数据 0:本轮无数据发送 +其它说明: 首包前每秒发送一次C;SOH首包和第二次EOT后按Ymodem规则发送ACK+C +*****************************************************************/ +static rt_uint8_t ymodem_send(struct chrg_comm_t *pCOMM) +{ + rt_uint8_t south_resp; + rt_uint32_t timeout_ms; + rt_tick_t now; + + pCOMM->tx_len = 0; + now = rt_tick_get(); + if ((s_first_soh_rcvd == 0) && (g_ymodem_waiting_ack == 0) && + ((now - g_ymodem_c_tick) >= rt_tick_from_millisecond(YMODEM_C_PERIOD_MS))) { + pCOMM->tx_buf[0] = ACK_C; + pCOMM->tx_len = 1; + g_ymodem_c_tick = now; + return 1; + } + + south_resp = chrg_eload_get_ymodem_resp(); + if (south_resp == ACK) { + g_ymodem_waiting_ack = 0; + g_ymodem_retry_count = 0; + if (ystate == Ymodem_Rec_Start) { + pCOMM->tx_buf[0] = ACK; + pCOMM->tx_buf[1] = ACK_C; + pCOMM->tx_len = 2; + } else if (ystate == Ymodem_Rec_End) { + pCOMM->tx_buf[0] = ACK; + pCOMM->tx_buf[1] = ACK_C; + pCOMM->tx_len = 2; + g_ymodem_eot_done = 1; + ystate = Ymodem_Rec_Finish; + } else { + pCOMM->tx_buf[0] = ACK; + pCOMM->tx_len = 1; + } + return 1; + } + if (south_resp == NAK) { + if (g_ymodem_retry_count >= YMODEM_MAX_RETRIES) { + pCOMM->tx_buf[0] = YM_CAN; + pCOMM->tx_buf[1] = YM_CAN; + pCOMM->tx_len = 2; + chrg_ymodem_session_stop(); + return 1; + } + (void)chrg_ymodem_resend_last(); + return 0; + } + if (south_resp == ACK_C) { + /* 等待当前帧ACK时忽略功率板周期C,避免打乱上位机停止等待握手。 */ + if (g_ymodem_waiting_ack != 0) { + return 0; + } + pCOMM->tx_buf[0] = ACK_C; + pCOMM->tx_len = 1; + return 1; + } + if (south_resp == YM_CAN) { + pCOMM->tx_buf[0] = YM_CAN; + pCOMM->tx_buf[1] = YM_CAN; + pCOMM->tx_len = 2; + chrg_ymodem_session_stop(); + return 1; + } + + if (g_ymodem_waiting_ack != 0) { + timeout_ms = (ystate == Ymodem_Rec_Start) ? + YMODEM_META_ACK_TIMEOUT_MS : YMODEM_DATA_ACK_TIMEOUT_MS; + if ((now - g_ymodem_send_tick) >= rt_tick_from_millisecond(timeout_ms)) { + if (g_ymodem_retry_count >= YMODEM_MAX_RETRIES) { + pCOMM->tx_buf[0] = YM_CAN; + pCOMM->tx_buf[1] = YM_CAN; + pCOMM->tx_len = 2; + chrg_ymodem_session_stop(); + return 1; + } + (void)chrg_ymodem_resend_last(); + } + } + return 0; +} + ///***************************************************************** //函数名称: ymodem_send //函数描述: 每隔一秒发一次0x43告诉上位机准备数据 @@ -1572,10 +1941,36 @@ static int chrg_comm_parse_msg (struct chrg_comm_t *pCOMM) *****************************************************************/ static int chrg_comm_updata_north (struct chrg_comm_t *pCOMM) { -// if (RT_NULL == pCOMM) { -// return -1; -// } int ret = 0; + int process_ret; + rt_uint8_t need_tx; + + if (pCOMM == RT_NULL) { + return -1; + } + + /* 升级模式中仍允许接收0x20停止命令,必须先校验地址和Modbus CRC。 */ + if ((pCOMM->rx_len == 8) && (pCOMM->rx_buf[1] == MB_YMODEM_UPDATAE) && + ((pCOMM->rx_buf[0] == pCOMM->addr) || + (pCOMM->rx_buf[0] == MB_ADDRESS_BROADCAST)) && + (mb_crc16(pCOMM->rx_buf, pCOMM->rx_len) == 0)) { + return chrg_comm_parse_msg(pCOMM); + } + + if (pCOMM->rx_len > 0) { + process_ret = chrg_ymodem_process(pCOMM->rx_buf, pCOMM->rx_len); + if ((process_ret == -3) || (process_ret == -4)) { + /* 本地校验或南向提交失败时要求上位机重发当前帧。 */ + pCOMM->tx_buf[0] = NAK; + pCOMM->tx_len = 1; + return chrg_tty_send(pCOMM->tty, pCOMM->tx_buf, pCOMM->tx_len); + } + } + + need_tx = ymodem_send(pCOMM); + if ((need_tx != 0) && (pCOMM->tx_len > 0)) { + ret = chrg_tty_send(pCOMM->tty, pCOMM->tx_buf, pCOMM->tx_len); + } // uint8_t need_tx = 0; // pCOMM->tx_len = 0; //进来先清空发送缓冲区 // eMBException eStatus = MB_EX_NONE; @@ -1643,9 +2038,12 @@ void chrg_comm_thread_entry (void *data) len = chrg_tty_recv(pTTY, pCOMM->rx_buf, sizeof(pCOMM->rx_buf)); // LOG_HEX("Num=", len, pCOMM->rx_buf, len); if(pROLL->mode==0x01){ //升级模式走单独协议 - pCOMM->rx_len = len; + pCOMM->rx_len = (len > 0) ? (rt_uint16_t)len : 0; pCOMM->tx_len = 0; chrg_comm_updata_north(pCOMM); + if (len <= 0) { + rt_thread_mdelay(1); + } }else{ if (len <= 0) { rt_thread_mdelay(1); @@ -1829,12 +2227,11 @@ static void chrg_mb_write_src(rt_uint8_t ch, rt_uint16_t reg_offset, rt_uint16_t //rt_kprintf("[SRC CH%d] MinVolt=%d mV\n", ch + 1, sou_value); break; case SRC_REG_MAX_VOLT: // 0x04: 最大电压 (mV) - pSW->source.max_vol = sou_value; + pSW->source.vc.set_voltage = sou_value; // rt_kprintf("[SRC CH%d] MaxVolt=%d mV\n", ch + 1, sou_value); break; case SRC_REG_MAX_CURR: // 0x05: 最大电流 (mA) - pSW->source.protective_curr = sou_value; pSW->source.vc.set_current = sou_value; //rt_kprintf("[SRC CH%d] MaxCurr=%d mA\n", ch + 1, sou_value); break; @@ -1855,207 +2252,292 @@ 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 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) +/***************************************************************** +函数名称: chrg_comm_get_param_diff +函数描述: 按当前角色统一比较运行参数与待生效影子参数 +输入参数: role:当前角色 pReal:正在运行的参数 pShadow:待生效参数 +输出参数: pDiff:各公共属性及Sink专用协议属性的变化标志 +返回说明: - +其它说明: 本函数只计算差异,不修改状态、不发送命令;Source的电压电流 + 使用vc.set_voltage/set_current,Sink使用loadv/loadc +*****************************************************************/ +static void chrg_comm_get_param_diff(eIDX_ID role, + const struct chrg_switch_t *pReal, + const struct chrg_switch_t *pShadow, + chrg_param_diff_t *pDiff) { - struct chrg_comm_t *pCOMM = &chrgcomm; - switch (reg_offset) - { - case SYS_REG_ROLE_SWITCH: // 0x00: 源/载状态切换 - if (sou_value == 0x01) - { - pSW->id = ID_SINK; - } - else if (sou_value == 0x02) - { - pSW->id = ID_SOURCE; - } - break; + if ((pReal == RT_NULL) || (pShadow == RT_NULL) || (pDiff == RT_NULL)) { + return; + } + rt_memset(pDiff, 0, sizeof(*pDiff)); + pDiff->cv_changed = (pReal->CV_mode != pShadow->CV_mode); - 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); + if (role == ID_SOURCE) { + pDiff->protocol_changed = + (pReal->source.protocol != pShadow->source.protocol); + pDiff->cc_changed = + (pReal->source.cc_set != pShadow->source.cc_set); + pDiff->voltage_changed = + (pReal->source.vc.set_voltage != pShadow->source.vc.set_voltage); + pDiff->current_changed = + (pReal->source.vc.set_current != pShadow->source.vc.set_current); + } else if (role == ID_SINK) { + pDiff->protocol_changed = + (pReal->sink.protocol != pShadow->sink.protocol); + pDiff->cc_changed = + (pReal->sink.cc_set != pShadow->sink.cc_set); + pDiff->voltage_changed = + (pReal->sink.loadv != pShadow->sink.loadv); + pDiff->current_changed = + (pReal->sink.loadc != pShadow->sink.loadc); + pDiff->group_changed = + (pReal->sink.Pro_Group != pShadow->sink.Pro_Group); + pDiff->pro_voltage_changed = + (pReal->sink.pro_loadv != pShadow->sink.pro_loadv); + pDiff->pro_current_changed = + (pReal->sink.pro_loadc != pShadow->sink.pro_loadc); + } +} - /* - * pReal保存当前正在运行的真实状态,pSW指向COM影子配置。 - * 必须在rt_memcpy之前保存old_id,否则复制后会丢失旧角色, - * 无法判断本次生效是普通参数更新还是Source/Sink角色切换。 - */ - eIDX_ID old_id = pReal->id; +/***************************************************************** +函数名称: chrg_comm_apply_sink_effect +函数描述: 处理COM参数生效后的同角色负载启停、测试和差异更新 +输入参数: ch:通道 pReal:运行参数 pShadow:待生效影子参数 +输出参数: 更新pReal并按需提交南向命令 +返回说明: MB_EX_NONE:成功 MB_EX_SLAVE_BUSY:命令提交失败 +其它说明: 角色切换不在本函数处理,由chrg_mb_write_sys统一调度 +*****************************************************************/ +static eMBException chrg_comm_apply_sink_effect(rt_uint8_t ch, + struct chrg_switch_t *pReal, const struct chrg_switch_t *pShadow) +{ + rt_bool_t pro_change; + rt_uint8_t curr_test; + rt_uint8_t curr_test_old; + 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_uint16_t sink_work = pShadow->sink.Now_State; + chrg_param_diff_t diff_info; - 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; - /* COM参数统一生效;复制完成后的id就是本次请求的目标角色。 */ - rt_memcpy(pReal, &g_shadow_sw[ch], sizeof(struct chrg_switch_t)); - eIDX_ID new_id = pReal->id; + chrg_comm_get_param_diff(ID_SINK, pReal, pShadow, &diff_info); + /* Sink以下属性变化时需要从CC开始重新执行北向协议配置链路。 */ + pro_change = diff_info.protocol_changed || diff_info.group_changed || + diff_info.pro_voltage_changed || diff_info.pro_current_changed || + diff_info.cc_changed || diff_info.cv_changed; + rt_memcpy(pReal, pShadow, sizeof(struct chrg_switch_t)); - if (old_id != new_id) - { - int switch_ret; - - /* - * SWITCH表示“切换进入new_id对应角色”,因此必须按new_id - * 选择状态机,保证ID_SOURCE只使用Source状态机,ID_SINK - * 只使用Sink状态机。SWITCH内部先停止旧角色,再转入INIT。 - */ - if (new_id == ID_SOURCE) { - pReal->source.work_mode = SOURCE_WORK_SWITCH; - switch_ret = chrg_source_work_state(ch, pReal); + if (sink_work == 0x01) { + curr_test = pReal->sink.test.test_mode; + curr_test_old = pReal->sink.test.test_mode_old; + if (((curr_test_old == 0) && (curr_test != 0)) || + ((curr_test == 0) && (curr_test_old != 0))) { + if (curr_test_old == 0) { + if (curr_test == SINK_TEST_DYNA) { + pReal->sink.work_mode = SINK_WORK_ON_TEST_DYNA; + } else if (curr_test == SINK_TEST_OCP) { + pReal->sink.work_mode = SINK_WORK_ON_TEST_OCP; } else { - pReal->sink.work_mode = SINK_WORK_SWITCH; - switch_ret = chrg_sink_work((eIDX_SOU_CH)ch, pReal); + pReal->sink.work_mode = SINK_WORK_ON_TEST_SHORT; } - - /* 入队失败时保留影子待生效标志,让COM返回忙并允许重试。 */ - if (switch_ret != 0) { - g_shadow_dirty[ch] = 1; - rt_mutex_release(pTHR_NOR->mutex); - return MB_EX_SLAVE_BUSY; - } - - /* - * 角色切换路径已经完成状态安排,必须直接返回,避免继续执行 - * 下方同角色启动/停止逻辑并再次覆盖INIT状态。 - */ - rt_mutex_release(pTHR_NOR->mutex); - return MB_EX_NONE; + pReal->sink.test.test_mode_old = curr_test; + } else { + pReal->sub = IDX_SET_SINK_CCLINE; + pReal->sink.work_mode = SINK_WORK_INIT; } + } else if (pReal->sink.On_work == 0) { + pReal->sink.On_work = 1; + pReal->sub = IDX_SET_SINK_CCLINE; + pReal->sink.work_mode = SINK_WORK_INIT; + } else if (pro_change) { + pReal->sub = IDX_SET_SINK_CCLINE; + pReal->sink.work_mode = SINK_WORK_WAIT; + } else 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; + return MB_EX_SLAVE_BUSY; + } + } else { + pReal->sink.On_work = 0; + pReal->sink.work_mode = SINK_WORK_STOP; + } - if (new_id == ID_SINK) - { - if (sink_work == 0x01) // 负载启动 - { - rt_uint8_t curr_test = pReal->sink.test.test_mode; - rt_uint8_t curr_test_old = pReal->sink.test.test_mode_old; - // 测试模式状态发生切换:0<->非0 - if ((curr_test_old == 0 && curr_test != 0) || (curr_test == 0 && curr_test_old != 0)) - { - if (curr_test_old == 0) - { - // 从正常模式进入测试模式 - pReal->sink.work_mode = (curr_test == 3) ? SINK_WORK_ON_TEST_DYNA : SINK_WORK_ON_TEST_SHORT; - pReal->sink.test.test_mode_old = curr_test; - } - else - { - // 从测试模式切回正常模式 - pReal->sub = IDX_SET_SINK_CCLINE; - pReal->sink.work_mode = SINK_WORK_INIT; - } - } - else - { - // 测试模式无变化,处理负载初始化/参数更新 - if (pReal->sink.On_work == 0) - { - // 负载首次启动硬件初始化 - pReal->sink.On_work = 1; - pReal->sub = IDX_SET_SINK_CCLINE; - pReal->sink.work_mode = SINK_WORK_INIT; - } - else - { - if (pro_change) - { - // 协议参数变更,重新初始化链路 - pReal->sub = IDX_SET_SINK_CCLINE; - pReal->sink.work_mode = SINK_WORK_WAIT; - } - else - { - // 仅下发差异寄存器 - 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; - } - } - } - } - } - else // sink_work == 0x00 负载停止 - { - pReal->sink.On_work = 0; - pReal->sink.work_mode = SINK_WORK_STOP; - } - if (chrg_sink_work(ch, pReal) != 0) { - g_shadow_dirty[ch] = 1; - rt_mutex_release(pTHR_NOR->mutex); - return MB_EX_SLAVE_BUSY; - } + return (chrg_sink_work((eIDX_SOU_CH)ch, pReal) == 0) ? + MB_EX_NONE : MB_EX_SLAVE_BUSY; +} + +/***************************************************************** +函数名称: chrg_comm_apply_source_effect +函数描述: 处理COM参数生效后的同角色电源启停和参数差异更新 +输入参数: ch:通道 pReal:运行参数 pShadow:待生效影子参数 +输出参数: 更新pReal、Source状态和必要的南向寄存器 +返回说明: MB_EX_NONE:成功 MB_EX_SLAVE_BUSY:命令提交失败 +其它说明: 快充协议只重置北向sub并进入WAIT;标准协议直接更新CV、电压和电流 +*****************************************************************/ +static eMBException chrg_comm_apply_source_effect(rt_uint8_t ch, + struct chrg_switch_t *pReal, const struct chrg_switch_t *pShadow) +{ + chrg_param_diff_t diff_info; + rt_uint8_t old_cv_mode = pReal->CV_mode; + rt_uint16_t old_voltage = pReal->source.vc.set_voltage; + rt_uint16_t old_current = pReal->source.vc.set_current; + rt_uint16_t source_work = pShadow->source.Now_State; + rt_uint16_t regs[3]; + rt_uint16_t vals[3]; + rt_uint8_t count = 0; + + chrg_comm_get_param_diff(ID_SOURCE, pReal, pShadow, &diff_info); + rt_memcpy(pReal, pShadow, sizeof(struct chrg_switch_t)); + + if (source_work == 0x01) { + if (pReal->source.On_Flag == 0) { + /* 首次启动仍需初始化功率板、继电器和WORK_START。 */ + pReal->sub = IDX_SET_SOURCE_CC_SET; + pReal->source.On_Flag = 1; + pReal->source.work_mode = SOURCE_WORK_INIT; + return (chrg_source_work_state(ch, pReal) == 0) ? + MB_EX_NONE : MB_EX_SLAVE_BUSY; + } + + /* 协议或CC变化时,从CC设置开始重新执行北向配置链路。 */ + if (diff_info.protocol_changed || diff_info.cc_changed) { + pReal->sub = IDX_SET_SOURCE_CC_SET; + } + + pReal->source.work_mode = SOURCE_WORK_WAIT; + + if (pReal->source.protocol != PRO_NONE) { + /* 快充目标值由北向协商回码决定,COM生效阶段不直接写功率板。 */ + return MB_EX_NONE; + } + + /* 从快充切到标准协议时强制同步全部直接控制参数。 */ + if (diff_info.protocol_changed || diff_info.cv_changed) { + regs[count] = REG_MODE; + vals[count++] = pReal->CV_mode; + } + if (diff_info.protocol_changed || diff_info.voltage_changed) { + regs[count] = REG_VOLTAGE_OUT + 1; + vals[count++] = pReal->source.vc.set_voltage; + } + if (diff_info.protocol_changed || diff_info.current_changed) { + regs[count] = REG_CURRENT_OUT + 1; + vals[count++] = pReal->source.vc.set_current; + } + + if ((count > 0) && (chrg_sou_com_batch_submit((eIDX_SOU_CH)ch, + regs, vals, count) != 0)) { + pReal->CV_mode = old_cv_mode; + pReal->source.vc.set_voltage = old_voltage; + pReal->source.vc.set_current = old_current; + return MB_EX_SLAVE_BUSY; + } + pReal->source.work_mode = SOURCE_WORK_RUNING; + return MB_EX_NONE; + } + + pReal->source.On_Flag = 0; + pReal->source.work_mode = SOURCE_WORK_STOP; + return (chrg_source_work_state(ch, pReal) == 0) ? + MB_EX_NONE : MB_EX_SLAVE_BUSY; +} + +/***************************************************************** +函数名称: chrg_mb_write_sys +函数描述: 处理系统区角色切换和影子参数生效 +输入参数: ch:通道 reg_offset:系统寄存器偏移 sou_value:写入值 + pSW:影子参数 pNOR:北向总控 pSOU:南向总控 +输出参数: 更新角色或将参数分发给对应角色处理函数 +返回说明: MB_EX_NONE:成功 MB_EX_SLAVE_BUSY:命令提交失败 +其它说明: 同角色Source/Sink逻辑分别封装,角色切换仍统一走SWITCH状态 +*****************************************************************/ +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) +{ + eMBException status; + struct chrg_switch_t *pReal; + struct chrg_thread_t *pTHR_NOR; + eIDX_ID old_id; + eIDX_ID new_id; + int switch_ret; + + (void)pSOU; + switch (reg_offset) { + case SYS_REG_ROLE_SWITCH: + if (sou_value == 0x01) { + pSW->id = ID_SINK; + } else if (sou_value == 0x02) { + pSW->id = ID_SOURCE; + } + break; + + case SYS_REG_PARAM_EFFECT: + if (sou_value != 0x01) { + break; + } + pReal = &pNOR->sw[ch]; + pTHR_NOR = &chrgthr[IDX_THR_ROLL_NOR]; + rt_mutex_take(pTHR_NOR->mutex, RT_WAITING_FOREVER); + old_id = pReal->id; + new_id = pSW->id; + g_shadow_dirty[ch] = 0; + + if (old_id != new_id) { + rt_memcpy(pReal, pSW, sizeof(struct chrg_switch_t)); + if (new_id == ID_SOURCE) { + pReal->source.work_mode = SOURCE_WORK_SWITCH; + switch_ret = chrg_source_work_state(ch, pReal); + } else { + pReal->sink.work_mode = SINK_WORK_SWITCH; + switch_ret = chrg_sink_work((eIDX_SOU_CH)ch, pReal); } - else if (new_id == ID_SOURCE && source_work == 0x01) - { - /* COM只触发状态,初始化命令由Source状态机统一下发。 */ - pReal->sub = IDX_SET_SOURCE_CC_SET; - pReal->source.On_Flag = 1; - pReal->source.work_mode = SOURCE_WORK_INIT; - } - else if (new_id == ID_SOURCE && source_work == 0x00) - { - /* 停止动作同样交给状态机处理,避免COM直接控制硬件。 */ - pReal->source.On_Flag = 0; - pReal->source.work_mode = SOURCE_WORK_STOP; - } - rt_mutex_release(pTHR_NOR->mutex); - } - break; + status = (switch_ret == 0) ? MB_EX_NONE : MB_EX_SLAVE_BUSY; + } else if (new_id == ID_SINK) { + status = chrg_comm_apply_sink_effect(ch, pReal, pSW); + } else { + status = chrg_comm_apply_source_effect(ch, pReal, pSW); + } + + if (status != MB_EX_NONE) { + g_shadow_dirty[ch] = 1; + } + rt_mutex_release(pTHR_NOR->mutex); + return status; + 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, - sink_proto_diff_t *pDiff, - rt_uint8_t *pChange) -{ - pDiff->proto_changed = (pReal->sink.protocol != pShadow->sink.protocol) ? 1 : 0; - pDiff->group_changed = (pReal->sink.Pro_Group != pShadow->sink.Pro_Group) ? 1 : 0; - pDiff->ccset_changed = (pReal->sink.cc_set != pShadow->sink.cc_set) ? 1 : 0; - pDiff->pro_volt_changed = (pReal->sink.pro_loadv != pShadow->sink.pro_loadv) ? 1 : 0; - pDiff->pro_curr_changed = (pReal->sink.pro_loadc != pShadow->sink.pro_loadc) ? 1 : 0; - pDiff->volt_changed = (pReal->sink.loadv != pShadow->sink.loadv) ? 1 : 0; - pDiff->curr_changed = (pReal->sink.loadc != pShadow->sink.loadc) ? 1 : 0; - pDiff->cvmode_changed = (pReal->CV_mode != pShadow->CV_mode) ? 1 : 0; - // 任意一项变更则 pro_change = 0,全部不变 = 1 - *pChange = (!pDiff->proto_changed && !pDiff->group_changed && - !pDiff->pro_volt_changed && !pDiff->pro_curr_changed && - !pDiff->ccset_changed && !pDiff->cvmode_changed) ? 0 : 1; - -} -int chrg_sink_diff_send_reg(eIDX_SOU_CH ch, sink_proto_diff_t *pDiff, struct chrg_switch_t *pReal) +/***************************************************************** +函数名称: chrg_sink_diff_send_reg +函数描述: 根据统一差异结果下发普通负载的CV、电压或电流变化 +输入参数: ch:南向通道 pDiff:统一参数差异 pReal:已生效运行参数 +输出参数: - +返回说明: 0:无差异或提交成功 <0:南向批量队列提交失败 +其它说明: 协议、组号和CC变化由Sink生效函数重置北向sub,本函数只处理 + 不需要重配协议的功率参数 +*****************************************************************/ +static int chrg_sink_diff_send_reg(eIDX_SOU_CH ch, + const chrg_param_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) { + if (pDiff->voltage_changed) { regs[count] = REG_VOLTAGE_OUT + 1; vals[count++] = pReal->sink.loadv; } - } else if (pDiff->curr_changed) { + } else if (pDiff->current_changed) { regs[count] = REG_CURRENT_OUT + 1; vals[count++] = pReal->sink.loadc; } - if (pDiff->cvmode_changed) { + if (pDiff->cv_changed) { regs[count] = REG_MODE; vals[count++] = pReal->CV_mode; } diff --git a/apps/chrg/applications/thread/chrg_comm.h b/apps/chrg/applications/thread/chrg_comm.h index 549ab17..6a440ea 100644 --- a/apps/chrg/applications/thread/chrg_comm.h +++ b/apps/chrg/applications/thread/chrg_comm.h @@ -19,24 +19,6 @@ #define MB_HANDLERS_MAX (16) -typedef struct -{ - //北向协议设置 - rt_uint8_t proto_changed; - rt_uint8_t group_changed; - rt_uint16_t pro_volt_changed; - rt_uint16_t pro_curr_changed; - //南向功率设置 - rt_uint8_t volt_changed; - rt_uint8_t curr_changed; - rt_uint8_t ccset_changed; - rt_uint8_t cvmode_changed; -} sink_proto_diff_t; -static void chrg_sink_get_proto_diff(struct chrg_switch_t *pReal, - struct chrg_switch_t *pShadow, - sink_proto_diff_t *pDiff, - rt_uint8_t *pNoChange); - typedef enum { MB_REG_READ, /*!< Read register values and pass to protocol stack. */ MB_REG_WRITE /*!< Update register values. */ @@ -228,8 +210,6 @@ 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 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 68b78b0..68da6aa 100644 --- a/apps/chrg/applications/thread/chrg_north.c +++ b/apps/chrg/applications/thread/chrg_north.c @@ -27,100 +27,6 @@ #define SOURCE_VOLT_ERROR_MV 200U #define SOURCE_VOLT_RETRY_FRAMES 3U -/***************************************************************** -函数名称: chrg_source_voltage_control -函数描述: 统一处理Source目标电压、误差判断和状态机切换 -输入参数: idx:当前通道 pSW:通道控制结构体 volt_mv:目标电压(mV) - curr_ma:目标电流(mA) -输出参数: 更新source.vc及source.work_mode -返回说明: 0:状态处理成功 <0:参数错误或命令提交失败 -其它说明: 目标电压变化时立即进入RUNING;实际电压与目标值的绝对误差 - 小于等于200mV时进入WAIT;连续3次超过误差范围时重发 -*****************************************************************/ -static int chrg_source_voltage_control(eIDX_SOU_CH idx, - struct chrg_switch_t *pSW, - rt_uint16_t volt_mv, - rt_uint16_t curr_ma) -{ - rt_uint16_t volt_error; - static rt_uint16_t last_volt_mv[TOTAL_SOU_CHS] = {0}; - static rt_uint8_t last_volt_valid[TOTAL_SOU_CHS] = {0}; - static rt_uint8_t last_protocol[TOTAL_SOU_CHS] = {0}; - static rt_uint8_t volt_retry_count[TOTAL_SOU_CHS] = {0}; - rt_bool_t need_set = RT_FALSE; - int ret; - - if ((idx >= TOTAL_SOU_CHS) || (pSW == RT_NULL)) { - return -1; - } - - /* 保存本次目标值,RUNING状态只使用其中的目标电压下发命令。 */ - pSW->source.vc.set_voltage = volt_mv; - pSW->source.vc.set_current = curr_ma; - - if (!pSW->source.On_Flag) { - /* 关机后清除历史缓存,下一次启动必须重新设置目标电压。 */ - last_volt_valid[idx] = 0; - volt_retry_count[idx] = 0; - return 0; - } - - /* 使用绝对误差,避免实际电压低于目标值时发生无符号下溢。 */ - volt_error = (pSW->Now_voltage >= volt_mv) ? - (pSW->Now_voltage - volt_mv) : - (volt_mv - pSW->Now_voltage); - - if (!last_volt_valid[idx] || - (last_protocol[idx] != (rt_uint8_t)pSW->source.protocol) || - (volt_mv != last_volt_mv[idx])) { - /* 首次设置、协议切换或目标变化时立即下发新电压。 */ - need_set = RT_TRUE; - } else if (volt_error <= SOURCE_VOLT_ERROR_MV) { - /* 实际电压误差不超过200mV即可视为设置成功。 */ - volt_retry_count[idx] = 0; - } else { - /* 给功率板三个反馈周期的稳定时间,避免每帧重复写电压。 */ - if (volt_retry_count[idx] < SOURCE_VOLT_RETRY_FRAMES) { - volt_retry_count[idx]++; - } - if (volt_retry_count[idx] >= SOURCE_VOLT_RETRY_FRAMES) { - need_set = RT_TRUE; - } - } - - pSW->source.work_mode = need_set ? - SOURCE_WORK_RUNING : SOURCE_WORK_WAIT; - ret = chrg_source_work_state(idx, pSW); - if ((ret == 0) && need_set) { - /* 只有命令成功提交后才更新缓存,失败时下一次继续重试。 */ - last_volt_mv[idx] = volt_mv; - last_protocol[idx] = (rt_uint8_t)pSW->source.protocol; - last_volt_valid[idx] = 1; - volt_retry_count[idx] = 0; - } - - return ret; -} - -/***************************************************************** -函数名称: chrg_source_standard_output -函数描述: 使用COM配置值驱动标准协议电源输出 -输入参数: idx:当前通道 pSW:通道控制结构体 -输出参数: 更新source.vc及source.work_mode -返回说明: 无返回值 -其它说明: 外部协议值0x20映射为PRO_NONE;本函数不解析北向协议返回 - 数据,目标电压和保护电流直接使用COM配置值 -*****************************************************************/ -void chrg_source_standard_output(eIDX_SOU_CH idx, struct chrg_switch_t *pSW) -{ - if (pSW == RT_NULL) { - return; - } - - (void)chrg_source_voltage_control(idx, pSW, - pSW->source.max_vol, pSW->source.protective_curr); -} - /***************************************************************** 函数名称: chrg_source_parse 函数描述: 按电源协议类型处理目标电压并驱动Source状态机 @@ -128,9 +34,8 @@ void chrg_source_standard_output(eIDX_SOU_CH idx, struct chrg_switch_t *pSW) pNOR:北向总控结构体 输出参数: 更新电压、电流、source.work_mode及电压重试计数 返回说明: - -其它说明: 标准协议不解析frame_data,直接使用COM配置值;快充协议读取 - frame_data[8~11]中的协商目标值。新目标立即进入RUNING, - 实际误差连续3帧超过200mV时重发 +其它说明: 标准协议只在本函数中识别,不使用北向返回值控制输出;快充协议 + 读取frame_data[8~11]中的协商目标值,并统一交给RUNING状态比较 *****************************************************************/ void chrg_source_parse(rt_uint8_t *frame_data, eIDX_SOU_CH idx, struct chrg_switch_t *pSW, struct chrg_north_t *pNOR) @@ -142,19 +47,22 @@ void chrg_source_parse(rt_uint8_t *frame_data, eIDX_SOU_CH idx, return; } - /* 标准协议使用COM设定值,不读取北向协议返回帧。 */ + /* 标准协议仍在北向解析入口处判断,但输出已经由INIT/COM直接完成。 + * 不读取北向返回电压,也不在这里重复下发南向电压。 */ if (pSW->source.protocol == PRO_NONE) { - chrg_source_standard_output(idx, pSW); return; } - if (frame_data == RT_NULL) { + if ((frame_data == RT_NULL) || !pSW->source.On_Flag) { return; } volt_mv = (frame_data[8] << 8) | frame_data[9]; curr_ma = (frame_data[10] << 8) | frame_data[11]; - /* 快充只负责解析北向协商结果,后续控制逻辑与标准协议共用。 */ - (void)chrg_source_voltage_control(idx, pSW, volt_mv, curr_ma); + pSW->source.vc.set_voltage = volt_mv; + pSW->source.vc.set_current = curr_ma; + /* 北向只负责提取本次返回值;新旧电压比较放在RUNING状态完成。 */ + pSW->source.work_mode = SOURCE_WORK_RUNING; + (void)chrg_source_work_state(idx, pSW); } /***************************************************************** @@ -170,13 +78,10 @@ void chrg_source_setting(rt_uint8_t *frame_data, eIDX_SOU_CH idx, struct chrg_switch_t *pSW, struct chrg_north_t *pNOR) { //执行输出调整 - if (pSW->source.On_Flag == 1) { - if(pSW->source.protocol == PRO_NONE){//标准下输出设定值 - chrg_source_standard_output(idx, pSW); - } - else{ //快充部分按协商结果输出 + if (pSW->source.On_Flag == 1) { + if (pSW->source.protocol != PRO_NONE) { + /* 标准协议不依赖北向返回值;快充协议继续解析协商结果。 */ chrg_source_parse(frame_data, idx, pSW, pNOR); -// rt_kprintf("set_end\r\n"); } }else if(pSW->source.On_Flag == 0){ //chrg_source_stop(frame_data,pSW,idx,&pNOR->enable[idx]); diff --git a/apps/chrg/applications/thread/chrg_roll_sou.c b/apps/chrg/applications/thread/chrg_roll_sou.c index 8fb6887..974309c 100644 --- a/apps/chrg/applications/thread/chrg_roll_sou.c +++ b/apps/chrg/applications/thread/chrg_roll_sou.c @@ -34,6 +34,42 @@ struct chrg_rollsou_t chrgrollsou = { .part = MB_R_PART1, }; + +/***************************************************************** +函数名称: chrg_send_sou_upadata_data +函数描述: 缓存一帧升级数据并切换南向线程到升级发送状态 +输入参数: buf:升级帧数据 leng:升级帧长度 +输出参数: - +返回说明: 0:提交成功 -1:参数错误 -2:上一帧尚未发送 -3:互斥锁超时 +其它说明: 使用结构体内部数组保存数据,防止COM接收缓存变化导致升级帧损坏 +*****************************************************************/ +int chrg_send_sou_upadata_data(const rt_uint8_t *buf, rt_uint16_t leng) +{ + struct chrg_thread_t *pTHR = &chrgthr[IDX_THR_ROLL_SOU]; + struct chrg_rollsou_t *pROLL = &chrgrollsou; + + if ((buf == RT_NULL) || (leng == 0) || (leng > sizeof(pROLL->updata_buf)) || + (pTHR->mutex == RT_NULL)) { + return -1; + } + if (rt_mutex_take(pTHR->mutex, + rt_tick_from_millisecond(SOU_MUTEX_TIMEOUT_MS)) != RT_EOK) { + return -3; + } + if (pROLL->send_flag != 0) { + rt_mutex_release(pTHR->mutex); + return -2; + } + + memcpy(pROLL->updata_buf, buf, leng); + pROLL->leng = leng; + pROLL->updata_result = 0; + pROLL->send_flag = 1; + pROLL->run = RUN_UPDATA; + rt_mutex_release(pTHR->mutex); + return 0; +} + //向通道批量缓存添加一条寄存器 int chrg_sou_com_batch_submit(eIDX_SOU_CH ch, const rt_uint16_t *regs, const rt_uint16_t *vals, rt_uint8_t count) @@ -523,7 +559,7 @@ void chrg_roll_sou_thread_entry (void *data) single_value = pROLL->value; rt_mutex_release(pTHR->mutex); command_valid = RT_FALSE; - if (run != RUN_COM) { + if ((run != RUN_COM) && (run != RUN_UPDATA)) { retry_count = 0; } // rt_kprintf("------ROLL SOU START \n--------"); @@ -570,6 +606,28 @@ void chrg_roll_sou_thread_entry (void *data) } break; + case RUN_UPDATA: + { + /* + * 升级响应是单字节ACK/NAK/C,不是Modbus消息,因此本分支发送后 + * 直接返回循环,由COM升级状态机读取响应,不能进入下方邮箱等待。 + */ + if ((pROLL->mode != 1) || (pROLL->send_flag == 0) || + (pROLL->leng == 0) || (pROLL->leng > sizeof(pROLL->updata_buf))) { + rt_thread_mdelay(1); + continue; + } + chrg_south_switch((eIDX_SOU_CH)single_ch); + ret = chrg_eload_send_ymodem_data(pROLL->updata_buf, pROLL->leng); + + rt_mutex_take(pTHR->mutex, RT_WAITING_FOREVER); + pROLL->updata_result = (rt_int16_t)ret; + pROLL->send_flag = 0; + rt_mutex_release(pTHR->mutex); + rt_thread_mdelay(1); + continue; + } + case RUN_CONSOLE: { chrg_south_switch((eIDX_SOU_CH)single_ch); chrg_eload_refresh(ID_ELOAD, single_part); diff --git a/apps/chrg/applications/thread/chrg_roll_sou.h b/apps/chrg/applications/thread/chrg_roll_sou.h index 3836c7b..a009f2a 100644 --- a/apps/chrg/applications/thread/chrg_roll_sou.h +++ b/apps/chrg/applications/thread/chrg_roll_sou.h @@ -48,9 +48,10 @@ struct chrg_rollsou_t { rt_uint16_t reg; // LCD 触发时,寄存器地址 rt_uint16_t value; // LCD 触发时,寄存器值 - rt_uint8_t *updata_data;//南向升级的数据 - rt_uint16_t leng; - rt_uint8_t send_flag; //发送标志位 + rt_uint8_t updata_buf[YMODEM_STX_SIZE];/* 南向升级帧缓存,避免上层缓冲区被提前覆盖 */ + rt_uint16_t leng; /* 当前待发送升级帧的实际长度 */ + rt_int16_t updata_result;/* 最近一次升级帧发送结果 */ + rt_uint8_t send_flag; /* 1:升级帧待发送或正在发送,0:允许提交下一帧 */ rt_uint8_t mode;// 0 为正常轮询,1为升级,2为校准 }; @@ -84,7 +85,15 @@ 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); +/***************************************************************** +函数名称: chrg_send_sou_upadata_data +函数描述: 将一帧升级数据复制到南向升级缓存并唤醒升级发送分支 +输入参数: buf:升级帧数据 leng:升级帧长度 +输出参数: - +返回说明: 0:提交成功 -1:参数错误 -2:上一帧尚未发送 -3:互斥锁超时 +其它说明: 数据在函数内完成复制,调用者返回后可以立即复用原缓冲区 +*****************************************************************/ +extern int chrg_send_sou_upadata_data(const rt_uint8_t *buf, rt_uint16_t leng); 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); diff --git a/apps/chrg/applications/thread/chrg_south.c b/apps/chrg/applications/thread/chrg_south.c index 310f24e..873fa46 100644 --- a/apps/chrg/applications/thread/chrg_south.c +++ b/apps/chrg/applications/thread/chrg_south.c @@ -448,7 +448,8 @@ void chrg_south_thread_entry (void *data) rt_uint8_t resp_byte; while (rt_ringbuffer_data_len(pSOU->rb) > 0) { rt_ringbuffer_getchar(pSOU->rb, &resp_byte); - if (resp_byte == ACK || resp_byte == NAK || resp_byte == ACK_C) { + if (resp_byte == ACK || resp_byte == NAK || + resp_byte == ACK_C || resp_byte == YM_CAN) { chrg_eload_set_ymodem_resp(resp_byte); } } diff --git a/apps/chrg/applications/utils/chrg_eload.c b/apps/chrg/applications/utils/chrg_eload.c index 12f822f..ca8eda9 100644 --- a/apps/chrg/applications/utils/chrg_eload.c +++ b/apps/chrg/applications/utils/chrg_eload.c @@ -32,10 +32,31 @@ static rt_uint8_t g_eload_ymodem_ready = 0; // 应答就绪标志(1=有新应 函数描述: 存储南向板返回的ymodem应答字节(由chrg_roll_sou在RUN_UPDATA调用) 输入参数: resp: 南向ymodem应答 (ACK=0x06 / NAK=0x15 / 'C'=0x43) *****************************************************************/ +#define ELOAD_YMODEM_RESP_DEPTH 8 +static rt_uint8_t g_ymodem_resp_queue[ELOAD_YMODEM_RESP_DEPTH]; +static rt_uint8_t g_ymodem_resp_read = 0; +static rt_uint8_t g_ymodem_resp_write = 0; +static rt_uint8_t g_ymodem_resp_count = 0; + void chrg_eload_set_ymodem_resp(rt_uint8_t resp) { - g_eload_ymodem_resp = resp; - g_eload_ymodem_ready = 1; + rt_base_t level = rt_hw_interrupt_disable(); + + /* 队列已满时丢弃周期性的C,保留更关键的ACK/NAK/CAN。 */ + if (g_ymodem_resp_count >= ELOAD_YMODEM_RESP_DEPTH) { + if (resp == ACK_C) { + rt_hw_interrupt_enable(level); + return; + } + g_ymodem_resp_read = (g_ymodem_resp_read + 1) % ELOAD_YMODEM_RESP_DEPTH; + g_ymodem_resp_count--; + } + g_ymodem_resp_queue[g_ymodem_resp_write] = resp; + g_ymodem_resp_write = (g_ymodem_resp_write + 1) % ELOAD_YMODEM_RESP_DEPTH; + g_ymodem_resp_count++; + g_eload_ymodem_resp = resp; + g_eload_ymodem_ready = 1; + rt_hw_interrupt_enable(level); } /***************************************************************** @@ -45,13 +66,19 @@ void chrg_eload_set_ymodem_resp(rt_uint8_t resp) *****************************************************************/ rt_uint8_t chrg_eload_get_ymodem_resp(void) { - rt_uint8_t resp = 0; - if (g_eload_ymodem_ready) { - resp = g_eload_ymodem_resp; - g_eload_ymodem_ready = 0; - g_eload_ymodem_resp = 0; - } - return resp; + rt_uint8_t resp = 0; + rt_base_t level = rt_hw_interrupt_disable(); + + if (g_ymodem_resp_count > 0) { + resp = g_ymodem_resp_queue[g_ymodem_resp_read]; + g_ymodem_resp_read = (g_ymodem_resp_read + 1) % ELOAD_YMODEM_RESP_DEPTH; + g_ymodem_resp_count--; + } + g_eload_ymodem_ready = (g_ymodem_resp_count > 0); + g_eload_ymodem_resp = g_eload_ymodem_ready ? + g_ymodem_resp_queue[g_ymodem_resp_read] : 0; + rt_hw_interrupt_enable(level); + return resp; } /***************************************************************** @@ -60,8 +87,15 @@ rt_uint8_t chrg_eload_get_ymodem_resp(void) *****************************************************************/ void chrg_eload_clear_ymodem_resp(void) { - g_eload_ymodem_resp = 0; - g_eload_ymodem_ready = 0; + rt_base_t level = rt_hw_interrupt_disable(); + + g_ymodem_resp_read = 0; + g_ymodem_resp_write = 0; + g_ymodem_resp_count = 0; + g_eload_ymodem_resp = 0; + g_eload_ymodem_ready = 0; + rt_memset(g_ymodem_resp_queue, 0, sizeof(g_ymodem_resp_queue)); + rt_hw_interrupt_enable(level); } static int memcmp_8bytes(const rt_uint8_t *buf1, const rt_uint8_t *buf2) diff --git a/apps/chrg/applications/utils/chrg_sink.c b/apps/chrg/applications/utils/chrg_sink.c index a39b9a4..1e12396 100644 --- a/apps/chrg/applications/utils/chrg_sink.c +++ b/apps/chrg/applications/utils/chrg_sink.c @@ -144,10 +144,14 @@ static int chrg_sink_work_init(eIDX_SOU_CH idx, struct chrg_switch_t *pSW) rt_uint16_t vals[5] = {0, pSW->CV_mode,pSW->sink.volt_on, 0, 0}; rt_uint8_t count = 3; - if (pSW->sink.test.test_mode_old == 1) { + if (pSW->sink.test.test_mode_old == SINK_TEST_SHORT) { regs[count] = ModbusRTU_ShortTest_CMD_MODE_FLAG; vals[count++] = ModbusRTU_DYNA_CMD_MODE_STOP; - } else if (pSW->sink.test.test_mode_old == 3) { + } else if (pSW->sink.test.test_mode_old == SINK_TEST_OCP) { + /* 从OCP测试返回普通负载时,先停止功率板的OCP测试状态机。 */ + regs[count] = ModbusRTU_OCPTest_CMD_MODE_FLAG; + vals[count++] = ModbusRTU_DYNA_CMD_MODE_STOP; + } else if (pSW->sink.test.test_mode_old == SINK_TEST_DYNA) { regs[count] = ModbusRTU_DYNA_CMD_MODE_FLAG; vals[count++] = ModbusRTU_DYNA_CMD_MODE_STOP; } @@ -159,7 +163,6 @@ static int chrg_sink_work_init(eIDX_SOU_CH idx, struct chrg_switch_t *pSW) } pSW->sink.On_work = 1; - pSOU->enable[idx] = 1; pSOU->online[idx] = 1; pNOR->enable[idx] = 1; @@ -315,6 +318,36 @@ static int chrg_sink_TEST_SHORT_ON(rt_uint8_t ch, struct chrg_switch_t *pSW) return chrg_sou_com_batch_submit((eIDX_SOU_CH)ch, regs, vals, 3); } +/***************************************************************** +函数名称: chrg_sink_TEST_OCP_ON +函数描述: 配置并启动负载OCP过流保护测试 +输入参数: ch:南向功率通道编号 pSW:当前通道控制结构体 +输出参数: - +返回说明: 0:命令提交成功 非0:命令提交失败 +其它说明: 一次提交功率继电器、OCP参数、测试命令和WORK_START; + set_mode为0时保持指定时间后恢复,为1时一直保持 +*****************************************************************/ +static int chrg_sink_TEST_OCP_ON(rt_uint8_t ch, struct chrg_switch_t *pSW) +{ + struct test_OCP *pOCP = &pSW->sink.test.OCP_test; + rt_uint16_t regs[11] = {REG_REL_ON, REG_REL_ON, + ModbusRTU_OCPTest_StartCurrent, ModbusRTU_OCPTest_StopCurrent, + ModbusRTU_OCPTest_Step_CURR, ModbusRTU_OCPTest_Step_Hold_Time, + ModbusRTU_OCPTest_Vtrig_Stop, ModbusRTU_OCPTest_Hold_Time, + ModbusRTU_OCPTest_HOLD_CURR, ModbusRTU_OCPTest_CMD_MODE_FLAG, + REG_WORK}; + rt_uint16_t vals[11] = {0x02, 0x03, + pOCP->start_curr, pOCP->end_curr, pOCP->change_curr, + pOCP->change_keep_time, pOCP->stop_volt, pOCP->hold_time, + pOCP->hold_curr, ModbusRTU_DYNA_CMD_MODE_RUN_NO_CURR, + WORK_START}; + + if (pOCP->set_mode != 0) { + vals[9] = ModbusRTU_DYNA_CMD_MODE_RUN_ALWAYS_KEPP; + } + return chrg_sou_com_batch_submit((eIDX_SOU_CH)ch, regs, vals, 11); +} + /***************************************************************** 函数名称: chrg_sink_work @@ -354,6 +387,9 @@ int chrg_sink_work(eIDX_SOU_CH idx, struct chrg_switch_t *pSW) case SINK_WORK_ON_TEST_SHORT: ret = chrg_sink_TEST_SHORT_ON(idx,pSW); break; + case SINK_WORK_ON_TEST_OCP: + ret = chrg_sink_TEST_OCP_ON(idx,pSW); + break; case SINK_WORK_LOW: ret = chrg_sink_nor_work_low(idx,pSW); break; diff --git a/apps/chrg/applications/utils/chrg_sink.h b/apps/chrg/applications/utils/chrg_sink.h index 6e3376c..a78e841 100644 --- a/apps/chrg/applications/utils/chrg_sink.h +++ b/apps/chrg/applications/utils/chrg_sink.h @@ -211,6 +211,7 @@ enum { SINK_WORK_SWITCH, // 停止旧电源后进入负载INIT SINK_WORK_ON_TEST_DYNA, SINK_WORK_ON_TEST_SHORT, + SINK_WORK_ON_TEST_OCP, // 配置并启动OCP过流保护测试 }; // sink 参数结构 @@ -234,11 +235,9 @@ struct chrg_sink_t { rt_uint8_t work_mode; // 0=停止 1=工作 2=低电压 }; - //纹波寄存器 #define ModbusRTU_Ripple_Value 0x35 //读取纹波 - /******************** 负载测试 ************************* */ #define ModbusRTU_CAL_WriteEnable 0x34 //使能写入;0x4361代表使能写入;C+a ASCII码 #define ModbusRTU_Test_CMD 0x4361 // diff --git a/apps/chrg/applications/utils/chrg_source.c b/apps/chrg/applications/utils/chrg_source.c index 7641413..2834040 100644 --- a/apps/chrg/applications/utils/chrg_source.c +++ b/apps/chrg/applications/utils/chrg_source.c @@ -41,7 +41,7 @@ int chrg_source_init_submit(rt_uint8_t idx, struct chrg_switch_t *pSW) pSW->CV_mode, 0x03, 0, - pSW->source.protective_curr, + pSW->source.vc.set_current, WORK_START }; @@ -72,8 +72,7 @@ static int chrg_source_work_init(eIDX_SOU_CH idx, struct chrg_switch_t *pSW) } pSW->source.On_Flag = 1; - pSOU->enable[idx] = 1; - pNOR->enable[idx] = 1; + pNOR->enable[idx] = 1; pSOU->online[idx] = 1; chrg_nor_sw_rel((eIDX_NOR_CH)idx, ID_SOURCE); pSW->source.work_mode = SOURCE_WORK_WAIT; @@ -902,8 +901,8 @@ rt_uint8_t pd_fill_single_group_need_src_com(rt_uint8_t *data, rt_uint8_t start_ data[idx++] = 0x13; data[idx++] = 0x88; // 4. 电流/功率(高+低,直接取已拆分好的值) - data[idx++] = source->protective_curr >> 8; - data[idx++] = source->protective_curr & 0xFF; + data[idx++] = source->vc.set_current >> 8; + data[idx++] = source->vc.set_current & 0xFF; // 5. 保留位6字节(直接填0) memset(&data[idx], 0x00, 6); idx+=6; @@ -914,11 +913,11 @@ rt_uint8_t pd_fill_single_group_need_src_com(rt_uint8_t *data, rt_uint8_t start_ data[idx++] = source->min_vol >> 8; data[idx++] = source->min_vol & 0xFF; // 3. 最大电压(高+低,直接取已拆分好的值) - data[idx++] = source->max_vol >> 8; - data[idx++] = source->max_vol & 0xFF; + data[idx++] = source->vc.set_voltage >> 8; + data[idx++] = source->vc.set_voltage & 0xFF; // 4. 电流/功率(高+低,直接取已拆分好的值) - data[idx++] = source->protective_curr >> 8; - data[idx++] = source->protective_curr & 0xFF; + data[idx++] = source->vc.set_current >> 8; + data[idx++] = source->vc.set_current & 0xFF; // 5. 保留位6字节(直接填0) memset(&data[idx], 0x00, 6); idx+=6; @@ -936,11 +935,11 @@ rt_uint8_t pd_fill_single_group_no_src_com(rt_uint8_t *data, rt_uint8_t start_id data[idx++] = source->min_vol >> 8; data[idx++] = source->min_vol & 0xFF; // 3. 最大电压(高+低,直接取已拆分好的值) - data[idx++] = source->max_vol >> 8; - data[idx++] = source->max_vol & 0xFF; + data[idx++] = source->vc.set_voltage >> 8; + data[idx++] = source->vc.set_voltage & 0xFF; // 4. 电流/功率(高+低,直接取已拆分好的值) - data[idx++] = source->protective_curr >> 8; - data[idx++] = source->protective_curr & 0xFF; + data[idx++] = source->vc.set_current >> 8; + data[idx++] = source->vc.set_current & 0xFF; // 5. 保留位6字节(直接填0) memset(&data[idx], 0x00, 6); idx+=6; @@ -961,8 +960,8 @@ rt_uint8_t pd_fill_single_group_FCP_AFC(rt_uint8_t *data, rt_uint8_t start_idx,s data[idx++] = 0x13; data[idx++] = 0x88; // 4. 电流/功率(高+低,直接取已拆分好的值) - data[idx++] = source->protective_curr >> 8; - data[idx++] = source->protective_curr & 0xFF; + data[idx++] = source->vc.set_current >> 8; + data[idx++] = source->vc.set_current & 0xFF; // 5. 保留位6字节(直接填0) memset(&data[idx], 0x00, 6); idx+=6; @@ -970,14 +969,14 @@ rt_uint8_t pd_fill_single_group_FCP_AFC(rt_uint8_t *data, rt_uint8_t start_idx,s data[idx++] = 0x00; data[idx++] = 0x00; // 2. 最小电压(高+低,直接取已拆分好的值) - data[idx++] = source->max_vol >> 8; - data[idx++] = source->max_vol & 0xFF; + data[idx++] = source->vc.set_voltage >> 8; + data[idx++] = source->vc.set_voltage & 0xFF; // 3. 最大电压(高+低,直接取已拆分好的值) - data[idx++] = source->max_vol >> 8; - data[idx++] = source->max_vol & 0xFF; + data[idx++] = source->vc.set_voltage >> 8; + data[idx++] = source->vc.set_voltage & 0xFF; // 4. 电流/功率(高+低,直接取已拆分好的值) - data[idx++] = source->protective_curr >> 8; - data[idx++] = source->protective_curr & 0xFF; + data[idx++] = source->vc.set_current >> 8; + data[idx++] = source->vc.set_current & 0xFF; // 5. 保留位6字节(直接填0) memset(&data[idx], 0x00, 6); idx+=6; @@ -998,8 +997,8 @@ rt_uint8_t pd_fill_single_group_UFCS(rt_uint8_t *data, rt_uint8_t start_idx,stru data[idx++] = 0x13; data[idx++] = 0x88; // 4. 电流/功率(高+低,直接取已拆分好的值) - data[idx++] = source->protective_curr >> 8; - data[idx++] = source->protective_curr & 0xFF; + data[idx++] = source->vc.set_current >> 8; + data[idx++] = source->vc.set_current & 0xFF; // 5. 保留位6字节(直接填0) memset(&data[idx], 0x00, 6); idx+=6; @@ -1010,11 +1009,11 @@ rt_uint8_t pd_fill_single_group_UFCS(rt_uint8_t *data, rt_uint8_t start_idx,stru data[idx++] = source->min_vol >> 8; data[idx++] = source->min_vol & 0xFF; // 3. 最大电压(高+低,直接取已拆分好的值) - data[idx++] = source->max_vol >> 8; - data[idx++] = source->max_vol & 0xFF; + data[idx++] = source->vc.set_voltage >> 8; + data[idx++] = source->vc.set_voltage & 0xFF; // 4. 电流/功率(高+低,直接取已拆分好的值) - data[idx++] = source->protective_curr >> 8; - data[idx++] = source->protective_curr & 0xFF; + data[idx++] = source->vc.set_current >> 8; + data[idx++] = source->vc.set_current & 0xFF; // 5. 保留位6字节(直接填0) memset(&data[idx], 0x00, 6); idx+=6; diff --git a/apps/chrg/applications/utils/chrg_source.h b/apps/chrg/applications/utils/chrg_source.h index dba1737..d03c88f 100644 --- a/apps/chrg/applications/utils/chrg_source.h +++ b/apps/chrg/applications/utils/chrg_source.h @@ -150,10 +150,8 @@ struct chrg_src_t { rt_uint8_t pps; // PPS类型 rt_uint8_t pro_gear_idx; // 挡位 rt_uint16_t min_vol; // 最小电压 mV - rt_uint16_t max_vol; // 最大电压 mV rt_uint8_t vol_lvl; // CC线电平 rt_uint8_t cc_set; // cc线选择 //0代表1+2,1代表cc1,2代表cc2 - rt_uint16_t protective_curr; // 保护电流 rt_uint8_t Now_State; // 当前状态 rt_uint8_t On_Flag; // 启动总标志(0/1) rt_uint8_t LCD_Set_Pro_Flag; // LCD设置协议标志位