feat: add power board ymodem proxy
实现功率板北向YMODEM透明转发状态机,取消协议板自动重发,增加双EOT、包号、CRC和超时校验。仅提交源码及Keil源文件配置,不包含编译产物。
This commit is contained in:
@@ -22,11 +22,12 @@
|
||||
#include <rtdbg.h>
|
||||
#include "chrg_north_pkg.h"
|
||||
#include "chrg_lcd.h"
|
||||
#include "chrg_ymodem_proxy.h"
|
||||
|
||||
#include "stm32f4xx_hal.h"
|
||||
|
||||
#define HOLD_REG_FIRMWARE_VERSION 0x0300U /* 协议板固件版本,只读 */
|
||||
#define CHRG_FIRMWARE_VERSION 0x0139U /* 当前协议板版本:V1.1.41 */
|
||||
#define CHRG_FIRMWARE_VERSION 0x013AU /* 当前协议板版本:V1.1.42 */
|
||||
|
||||
|
||||
rt_uint8_t ucDiscInBuf[(TOTAL_DISC_REGS+BITS_UCHAR-1)/BITS_UCHAR];
|
||||
@@ -37,6 +38,7 @@ rt_uint16_t usRegProBuf[TOTAL_HOLD_ALL_REGS]; //北向protcal???
|
||||
//rt_uint16_t usRegTestBuf[TOTAL_TEST_REGS];
|
||||
rt_uint8_t g_proto_pData[80] = {0};//上位机协议指令,控制四个通道;二维
|
||||
rt_uint16_t g_proto_reqLen = 0;
|
||||
#if 0 /* 旧YMODEM重发状态机已由chrg_ymodem_proxy替代。 */
|
||||
rt_uint8_t mobude_ymodem_buf[MB_YMODEM_DATA_SIZE] = {0};//南向功率板升级缓冲区
|
||||
rt_uint8_t mobude_ymodem_buf_2[MB_YMODEM_DATA_SIZE] = {0};//南向功率板升级缓冲区
|
||||
|
||||
@@ -65,6 +67,7 @@ static const rt_uint8_t g_ymodem_update_frame[8] =
|
||||
static const rt_uint8_t g_ymodem_jump_frame[8] =
|
||||
{ID_ELOAD, 0x06, 0x00, 0x0F, 0x00, 0x0F, 0xF8, 0x2F};
|
||||
static void chrg_ymodem_session_stop(void);
|
||||
#endif
|
||||
/* 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=待生效,防止重复覆盖 */
|
||||
@@ -1414,6 +1417,7 @@ eMBException funcTrimELoad (rt_uint8_t *reqFrame, rt_uint16_t reqLen,
|
||||
其它说明: -
|
||||
*****************************************************************/
|
||||
|
||||
#if 0 /* 旧YMODEM时序只作参考,禁止编译和运行。 */
|
||||
Ymodem_state ystate = Ymodem_No;
|
||||
rt_uint8_t s_first_soh_rcvd = 0;
|
||||
|
||||
@@ -1633,6 +1637,7 @@ static void chrg_ymodem_session_stop(void)
|
||||
chrg_ymodem_protocol_reset();
|
||||
ystate = Ymodem_No;
|
||||
}
|
||||
#endif
|
||||
|
||||
eMBException funYmodemUpadata (rt_uint8_t *reqFrame, rt_uint16_t reqLen,
|
||||
rt_uint8_t *resFrame, rt_uint16_t *resLen)
|
||||
@@ -1651,16 +1656,13 @@ eMBException funYmodemUpadata (rt_uint8_t *reqFrame, rt_uint16_t reqLen,
|
||||
ch = (eIDX_SOU_CH)ch_num;
|
||||
|
||||
if (reqFrame[5] == 0xFF) {
|
||||
if (chrg_ymodem_session_start(ch) != 0) {
|
||||
if (chrg_ymodem_proxy_enter((rt_uint8_t)ch) != 0) {
|
||||
return MB_EX_SLAVE_BUSY;
|
||||
}
|
||||
} else if (reqFrame[5] == 0x00) {
|
||||
chrg_eload_clear_ymodem_resp();
|
||||
if (chrg_ymodem_send_control_frame(g_ymodem_jump_frame) != 0) {
|
||||
chrg_ymodem_session_stop();
|
||||
if (chrg_ymodem_proxy_exit((rt_uint8_t)ch) != 0) {
|
||||
return MB_EX_SLAVE_DEVICE_FAILURE;
|
||||
}
|
||||
chrg_ymodem_session_stop();
|
||||
} else {
|
||||
return MB_EX_ILLEGAL_DATA_VALUE;
|
||||
}
|
||||
@@ -1757,6 +1759,7 @@ static int chrg_comm_parse_msg (struct chrg_comm_t *pCOMM)
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if 0 /* 旧版协议板自动重发实现,禁止编译。 */
|
||||
/*
|
||||
* 旧版Ymodem处理代码保留在下方注释中作为历史参考。当前实现使用完整拼帧、
|
||||
* CRC校验和停止等待重发机制,不再依赖一次串口接收刚好得到一整帧。
|
||||
@@ -2199,6 +2202,7 @@ static rt_uint8_t ymodem_send(struct chrg_comm_t *pCOMM)
|
||||
// return eStatus;
|
||||
//}
|
||||
|
||||
#endif
|
||||
/*****************************************************************
|
||||
函数名称: chrg_comm_updata_north
|
||||
函数描述: 解析南向程序数据包
|
||||
@@ -2226,17 +2230,15 @@ static int chrg_comm_updata_north (struct chrg_comm_t *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);
|
||||
}
|
||||
process_ret = chrg_ymodem_proxy_feed_north(pCOMM->rx_buf,
|
||||
pCOMM->rx_len);
|
||||
(void)process_ret;
|
||||
}
|
||||
|
||||
need_tx = ymodem_send(pCOMM);
|
||||
if ((need_tx != 0) && (pCOMM->tx_len > 0)) {
|
||||
pCOMM->tx_len = chrg_ymodem_proxy_poll(pCOMM->tx_buf,
|
||||
sizeof(pCOMM->tx_buf));
|
||||
need_tx = (pCOMM->tx_len > 0U) ? 1U : 0U;
|
||||
if (need_tx != 0U) {
|
||||
ret = chrg_tty_send(pCOMM->tty, pCOMM->tx_buf, pCOMM->tx_len);
|
||||
}
|
||||
// uint8_t need_tx = 0;
|
||||
|
||||
@@ -41,6 +41,13 @@ static rt_uint8_t g_sou_measure_once_active_mask = 0U;
|
||||
* round, which also covers the south board's slower power-up time. */
|
||||
static rt_uint8_t g_sou_version_ready[TOTAL_SOU_CHS] = {0U};
|
||||
|
||||
void chrg_roll_sou_version_invalidate(rt_uint8_t ch)
|
||||
{
|
||||
if (ch < TOTAL_SOU_CHS) {
|
||||
g_sou_version_ready[ch] = 0U;
|
||||
}
|
||||
}
|
||||
|
||||
/* COM批量命令按通道轮询发送。一次写命令收到匹配回码后才移动游标;
|
||||
* 回码错误或超时时游标保持不变,使同一条命令优先完成重发,避免破坏
|
||||
* 本通道批次内的寄存器执行顺序。 */
|
||||
|
||||
@@ -95,6 +95,8 @@ extern void chrg_roll_sou_thread_entry (void *data);
|
||||
其它说明: 数据在函数内完成复制,调用者返回后可以立即复用原缓冲区
|
||||
*****************************************************************/
|
||||
extern int chrg_send_sou_upadata_data(const rt_uint8_t *buf, rt_uint16_t leng);
|
||||
/* 升级跳转App后强制目标通道重新读取功率板版本。 */
|
||||
extern void chrg_roll_sou_version_invalidate(rt_uint8_t ch);
|
||||
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);
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
/* CHRG application version. Keep this value synchronized with the changelog. */
|
||||
#define CHRG_VERSION_MAJOR 1U
|
||||
#define CHRG_VERSION_MINOR 1U
|
||||
#define CHRG_VERSION_PATCH 41U
|
||||
#define CHRG_VERSION_STRING "V1.1.41"
|
||||
#define CHRG_VERSION_PATCH 42U
|
||||
#define CHRG_VERSION_STRING "V1.1.42"
|
||||
|
||||
/*
|
||||
* Channel polling mode:
|
||||
|
||||
@@ -156,7 +156,7 @@ 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
|
||||
#define ELOAD_YMODEM_RESP_DEPTH 16
|
||||
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;
|
||||
@@ -172,6 +172,8 @@ void chrg_eload_set_ymodem_resp(rt_uint8_t resp)
|
||||
rt_hw_interrupt_enable(level);
|
||||
return;
|
||||
}
|
||||
/* 保留新到达的ACK/NAK/CAN;队列满仅会汰汰最旧字节,
|
||||
* 正常停止等待流程下队列不应到达此深度。 */
|
||||
g_ymodem_resp_read = (g_ymodem_resp_read + 1) % ELOAD_YMODEM_RESP_DEPTH;
|
||||
g_ymodem_resp_count--;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,540 @@
|
||||
#include <string.h>
|
||||
#include <rtthread.h>
|
||||
|
||||
#include "chrg_def.h"
|
||||
#include "chrg_thread.h"
|
||||
#include "chrg_south.h"
|
||||
#include "chrg_roll_sou.h"
|
||||
#include "chrg_eload.h"
|
||||
#include "chrg_ymodem_proxy.h"
|
||||
|
||||
#define LOG_TAG "chrg.upgrade"
|
||||
#include <rtdbg.h>
|
||||
|
||||
#define YMODEM_RX_FRAME_TIMEOUT_MS 1000U
|
||||
#define YMODEM_SESSION_IDLE_MS 15000U
|
||||
#define YMODEM_ENTER_TIMEOUT_MS 15000U
|
||||
#define YMODEM_RESPONSE_TIMEOUT_MS 10000U
|
||||
|
||||
typedef struct {
|
||||
chrg_ymodem_proxy_state_t state;
|
||||
rt_uint8_t ch;
|
||||
rt_uint8_t expected_packet;
|
||||
rt_uint8_t current_packet;
|
||||
rt_uint8_t meta_ack_seen;
|
||||
rt_uint8_t eot2_ack_seen;
|
||||
rt_uint8_t deferred_c;
|
||||
rt_uint16_t rx_len;
|
||||
rt_uint16_t expected_len;
|
||||
rt_tick_t rx_tick;
|
||||
rt_tick_t response_tick;
|
||||
rt_tick_t activity_tick;
|
||||
rt_uint8_t rx_buf[YMODEM_STX_SIZE];
|
||||
rt_uint8_t north_pending[2];
|
||||
rt_uint8_t north_pending_len;
|
||||
} chrg_ymodem_proxy_t;
|
||||
|
||||
static chrg_ymodem_proxy_t g_proxy = {
|
||||
.state = YMODEM_PROXY_IDLE,
|
||||
.ch = 0xFFU
|
||||
};
|
||||
|
||||
static const rt_uint8_t g_enter_frame[8] =
|
||||
{ID_ELOAD, 0x06, 0x00, 0x0F, 0x00, 0xFF, 0xF8, 0x6B};
|
||||
static const rt_uint8_t g_exit_frame[8] =
|
||||
{ID_ELOAD, 0x06, 0x00, 0x0F, 0x00, 0x0F, 0xF8, 0x2F};
|
||||
static const rt_uint8_t g_cancel_frame[2] = {YM_CAN, YM_CAN};
|
||||
|
||||
static const char *chrg_ymodem_proxy_state_name(chrg_ymodem_proxy_state_t state)
|
||||
{
|
||||
switch (state) {
|
||||
case YMODEM_PROXY_IDLE: return "IDLE";
|
||||
case YMODEM_PROXY_ENTERING: return "ENTERING";
|
||||
case YMODEM_PROXY_WAIT_C: return "WAIT_C";
|
||||
case YMODEM_PROXY_WAIT_META: return "WAIT_META";
|
||||
case YMODEM_PROXY_WAIT_META_RESP: return "META_RESP";
|
||||
case YMODEM_PROXY_WAIT_DATA: return "WAIT_DATA";
|
||||
case YMODEM_PROXY_WAIT_DATA_RESP: return "DATA_RESP";
|
||||
case YMODEM_PROXY_WAIT_EOT1_RESP: return "EOT1_RESP";
|
||||
case YMODEM_PROXY_WAIT_EOT2: return "EOT2";
|
||||
case YMODEM_PROXY_WAIT_EOT2_RESP: return "EOT2_RESP";
|
||||
case YMODEM_PROXY_WAIT_END_SOH: return "END_SOH";
|
||||
case YMODEM_PROXY_WAIT_END_ACK: return "END_ACK";
|
||||
case YMODEM_PROXY_TRANSFER_DONE: return "DONE";
|
||||
case YMODEM_PROXY_EXITING: return "EXITING";
|
||||
case YMODEM_PROXY_VERIFY: return "VERIFY";
|
||||
default: return "ABORT";
|
||||
}
|
||||
}
|
||||
|
||||
static void chrg_ymodem_proxy_reset(void)
|
||||
{
|
||||
rt_memset(&g_proxy, 0, sizeof(g_proxy));
|
||||
g_proxy.state = YMODEM_PROXY_IDLE;
|
||||
g_proxy.ch = 0xFFU;
|
||||
}
|
||||
|
||||
static void chrg_ymodem_proxy_session_stop(void)
|
||||
{
|
||||
struct chrg_thread_t *thread = &chrgthr[IDX_THR_ROLL_SOU];
|
||||
struct chrg_rollsou_t *roll = &chrgrollsou;
|
||||
|
||||
if (thread->mutex != RT_NULL) {
|
||||
rt_mutex_take(thread->mutex, RT_WAITING_FOREVER);
|
||||
roll->mode = 0U;
|
||||
roll->send_flag = 0U;
|
||||
roll->leng = 0U;
|
||||
roll->updata_result = 0;
|
||||
roll->run = RUN_AUTO;
|
||||
rt_mutex_release(thread->mutex);
|
||||
}
|
||||
chrg_eload_clear_ymodem_resp();
|
||||
if (chrgsouth.rb != RT_NULL) {
|
||||
rt_ringbuffer_reset(chrgsouth.rb);
|
||||
}
|
||||
chrg_ymodem_proxy_reset();
|
||||
}
|
||||
|
||||
static void chrg_ymodem_proxy_queue_north(rt_uint8_t first,
|
||||
rt_uint8_t second, rt_uint8_t length)
|
||||
{
|
||||
if ((length == 0U) || (g_proxy.north_pending_len != 0U)) {
|
||||
return;
|
||||
}
|
||||
g_proxy.north_pending[0] = first;
|
||||
g_proxy.north_pending[1] = second;
|
||||
g_proxy.north_pending_len = length;
|
||||
}
|
||||
|
||||
static void chrg_ymodem_proxy_abort(const char *reason)
|
||||
{
|
||||
if (g_proxy.state == YMODEM_PROXY_ABORT) {
|
||||
return;
|
||||
}
|
||||
LOG_E("abort ch=%u state=%s reason=%s", g_proxy.ch + 1U,
|
||||
chrg_ymodem_proxy_state_name(g_proxy.state), reason);
|
||||
(void)chrg_send_sou_upadata_data(g_cancel_frame, sizeof(g_cancel_frame));
|
||||
/* 取消必须覆盖尚未发送的NAK,确保PC必然收到CAN CAN。 */
|
||||
g_proxy.north_pending[0] = YM_CAN;
|
||||
g_proxy.north_pending[1] = YM_CAN;
|
||||
g_proxy.north_pending_len = 2U;
|
||||
g_proxy.state = YMODEM_PROXY_ABORT;
|
||||
g_proxy.activity_tick = rt_tick_get();
|
||||
}
|
||||
|
||||
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 1U;
|
||||
return 0U;
|
||||
}
|
||||
|
||||
static rt_uint16_t chrg_ymodem_crc16(const rt_uint8_t *data,
|
||||
rt_uint16_t length)
|
||||
{
|
||||
rt_uint16_t crc = 0U;
|
||||
rt_uint16_t i;
|
||||
rt_uint8_t bit;
|
||||
|
||||
for (i = 0U; i < length; i++) {
|
||||
crc ^= (rt_uint16_t)data[i] << 8;
|
||||
for (bit = 0U; bit < 8U; bit++) {
|
||||
crc = (crc & 0x8000U) ?
|
||||
(rt_uint16_t)((crc << 1) ^ 0x1021U) :
|
||||
(rt_uint16_t)(crc << 1);
|
||||
}
|
||||
}
|
||||
return 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]) != 0xFFU) {
|
||||
return RT_FALSE;
|
||||
}
|
||||
data_len = (frame[0] == SOH) ? 128U : 1024U;
|
||||
frame_crc = ((rt_uint16_t)frame[length - 2U] << 8) |
|
||||
frame[length - 1U];
|
||||
return (chrg_ymodem_crc16(&frame[YMODEM_DATA_OFFSET], data_len) ==
|
||||
frame_crc) ? RT_TRUE : RT_FALSE;
|
||||
}
|
||||
|
||||
static rt_bool_t chrg_ymodem_metadata_valid(const rt_uint8_t *frame)
|
||||
{
|
||||
const rt_uint8_t *data = &frame[YMODEM_DATA_OFFSET];
|
||||
rt_uint16_t name_len = 0U;
|
||||
rt_uint16_t pos;
|
||||
rt_bool_t digit_seen = RT_FALSE;
|
||||
|
||||
if ((frame[0] != SOH) || (frame[1] != 0U)) return RT_FALSE;
|
||||
while ((name_len < 128U) && (data[name_len] != 0U)) name_len++;
|
||||
if ((name_len < 4U) || (name_len >= 127U) ||
|
||||
(data[name_len - 4U] != '.') ||
|
||||
((data[name_len - 3U] | 0x20U) != 'u') ||
|
||||
((data[name_len - 2U] | 0x20U) != 'p') ||
|
||||
((data[name_len - 1U] | 0x20U) != 'k')) return RT_FALSE;
|
||||
for (pos = name_len + 1U; pos < 128U && data[pos] != 0U; pos++) {
|
||||
if ((data[pos] < '0') || (data[pos] > '9')) return RT_FALSE;
|
||||
digit_seen = RT_TRUE;
|
||||
}
|
||||
return digit_seen;
|
||||
}
|
||||
|
||||
static rt_bool_t chrg_ymodem_end_soh_valid(const rt_uint8_t *frame)
|
||||
{
|
||||
rt_uint16_t i;
|
||||
if ((frame[0] != SOH) || (frame[1] != 0U)) return RT_FALSE;
|
||||
for (i = 0U; i < 128U; i++) {
|
||||
if (frame[YMODEM_DATA_OFFSET + i] != 0U) return RT_FALSE;
|
||||
}
|
||||
return RT_TRUE;
|
||||
}
|
||||
|
||||
static int chrg_ymodem_proxy_submit_frame(const rt_uint8_t *frame,
|
||||
rt_uint16_t length, chrg_ymodem_proxy_state_t next_state)
|
||||
{
|
||||
int ret = chrg_send_sou_upadata_data(frame, length);
|
||||
if (ret != 0) return ret;
|
||||
g_proxy.current_packet = (length > 1U) ? frame[1] : 0U;
|
||||
g_proxy.state = next_state;
|
||||
g_proxy.response_tick = rt_tick_get();
|
||||
g_proxy.activity_tick = g_proxy.response_tick;
|
||||
LOG_I("south tx ch=%u state=%s type=%02x pkt=%u len=%u",
|
||||
g_proxy.ch + 1U, chrg_ymodem_proxy_state_name(next_state),
|
||||
frame[0], g_proxy.current_packet, length);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int chrg_ymodem_proxy_prepare_channel(rt_uint8_t ch)
|
||||
{
|
||||
struct chrg_thread_t *thread = &chrgthr[IDX_THR_ROLL_SOU];
|
||||
struct chrg_rollsou_t *roll = &chrgrollsou;
|
||||
|
||||
if ((ch >= TOTAL_SOU_CHS) || (thread->mutex == RT_NULL)) return -1;
|
||||
if (rt_mutex_take(thread->mutex,
|
||||
rt_tick_from_millisecond(100U)) != RT_EOK) return -2;
|
||||
roll->run = RUN_UPDATA;
|
||||
roll->ch = ch;
|
||||
roll->mode = 1U;
|
||||
roll->send_flag = 0U;
|
||||
roll->leng = 0U;
|
||||
roll->updata_result = 0;
|
||||
rt_mutex_release(thread->mutex);
|
||||
rt_thread_mdelay(25U);
|
||||
chrg_eload_clear_ymodem_resp();
|
||||
if (chrgsouth.rb != RT_NULL) rt_ringbuffer_reset(chrgsouth.rb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int chrg_ymodem_proxy_enter(rt_uint8_t ch)
|
||||
{
|
||||
rt_tick_t start;
|
||||
rt_uint8_t response;
|
||||
|
||||
if (g_proxy.state != YMODEM_PROXY_IDLE) return -1;
|
||||
if (chrg_ymodem_proxy_prepare_channel(ch) != 0) return -2;
|
||||
chrg_ymodem_proxy_reset();
|
||||
g_proxy.ch = ch;
|
||||
g_proxy.state = YMODEM_PROXY_ENTERING;
|
||||
g_proxy.activity_tick = rt_tick_get();
|
||||
if (chrg_send_sou_upadata_data(g_enter_frame, sizeof(g_enter_frame)) != 0) {
|
||||
chrg_ymodem_proxy_session_stop();
|
||||
return -3;
|
||||
}
|
||||
start = rt_tick_get();
|
||||
while ((rt_tick_t)(rt_tick_get() - start) <
|
||||
rt_tick_from_millisecond(YMODEM_ENTER_TIMEOUT_MS)) {
|
||||
response = chrg_eload_get_ymodem_resp();
|
||||
if (response == ACK) {
|
||||
g_proxy.state = YMODEM_PROXY_WAIT_C;
|
||||
g_proxy.activity_tick = rt_tick_get();
|
||||
return 0;
|
||||
}
|
||||
if (response == ACK_C) g_proxy.deferred_c = 1U;
|
||||
if ((response == NAK) || (response == YM_CAN)) break;
|
||||
rt_thread_mdelay(1U);
|
||||
}
|
||||
chrg_ymodem_proxy_session_stop();
|
||||
return -4;
|
||||
}
|
||||
|
||||
int chrg_ymodem_proxy_exit(rt_uint8_t ch)
|
||||
{
|
||||
rt_tick_t start;
|
||||
rt_uint8_t response;
|
||||
|
||||
if ((g_proxy.state != YMODEM_PROXY_TRANSFER_DONE) ||
|
||||
(ch != g_proxy.ch)) return -1;
|
||||
g_proxy.state = YMODEM_PROXY_EXITING;
|
||||
chrg_eload_clear_ymodem_resp();
|
||||
if (chrg_send_sou_upadata_data(g_exit_frame, sizeof(g_exit_frame)) != 0)
|
||||
return -2;
|
||||
start = rt_tick_get();
|
||||
while ((rt_tick_t)(rt_tick_get() - start) <
|
||||
rt_tick_from_millisecond(YMODEM_RESPONSE_TIMEOUT_MS)) {
|
||||
response = chrg_eload_get_ymodem_resp();
|
||||
if (response == ACK) {
|
||||
chrg_roll_sou_version_invalidate(ch);
|
||||
chrg_ymodem_proxy_session_stop();
|
||||
return 0;
|
||||
}
|
||||
if ((response == NAK) || (response == YM_CAN)) break;
|
||||
rt_thread_mdelay(1U);
|
||||
}
|
||||
chrg_ymodem_proxy_session_stop();
|
||||
return -3;
|
||||
}
|
||||
|
||||
static int chrg_ymodem_proxy_handle_frame(const rt_uint8_t *frame,
|
||||
rt_uint16_t length)
|
||||
{
|
||||
if (!chrg_ymodem_frame_valid(frame, length)) {
|
||||
chrg_ymodem_proxy_queue_north(NAK, 0U, 1U);
|
||||
return -1;
|
||||
}
|
||||
if (frame[0] == YM_CAN) {
|
||||
chrg_ymodem_proxy_abort("north CAN");
|
||||
return 0;
|
||||
}
|
||||
switch (g_proxy.state) {
|
||||
case YMODEM_PROXY_WAIT_META:
|
||||
if (!chrg_ymodem_metadata_valid(frame)) break;
|
||||
g_proxy.meta_ack_seen = 0U;
|
||||
return chrg_ymodem_proxy_submit_frame(frame, length,
|
||||
YMODEM_PROXY_WAIT_META_RESP);
|
||||
case YMODEM_PROXY_WAIT_DATA:
|
||||
if (frame[0] == EOT) {
|
||||
return chrg_ymodem_proxy_submit_frame(frame, length,
|
||||
YMODEM_PROXY_WAIT_EOT1_RESP);
|
||||
}
|
||||
if ((frame[1] != g_proxy.expected_packet) ||
|
||||
((g_proxy.expected_packet == 1U) &&
|
||||
((frame[0] != STX) || (length != YMODEM_STX_SIZE)))) break;
|
||||
return chrg_ymodem_proxy_submit_frame(frame, length,
|
||||
YMODEM_PROXY_WAIT_DATA_RESP);
|
||||
case YMODEM_PROXY_WAIT_EOT2:
|
||||
if (frame[0] != EOT) break;
|
||||
g_proxy.eot2_ack_seen = 0U;
|
||||
return chrg_ymodem_proxy_submit_frame(frame, length,
|
||||
YMODEM_PROXY_WAIT_EOT2_RESP);
|
||||
case YMODEM_PROXY_WAIT_END_SOH:
|
||||
if (!chrg_ymodem_end_soh_valid(frame)) break;
|
||||
return chrg_ymodem_proxy_submit_frame(frame, length,
|
||||
YMODEM_PROXY_WAIT_END_ACK);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
LOG_W("north frame rejected ch=%u state=%s type=%02x pkt=%u len=%u expected=%u",
|
||||
g_proxy.ch + 1U, chrg_ymodem_proxy_state_name(g_proxy.state),
|
||||
frame[0], (length > 1U) ? frame[1] : 0U, length,
|
||||
g_proxy.expected_packet);
|
||||
chrg_ymodem_proxy_queue_north(NAK, 0U, 1U);
|
||||
return -2;
|
||||
}
|
||||
|
||||
int chrg_ymodem_proxy_feed_north(const rt_uint8_t *data,
|
||||
rt_uint16_t length)
|
||||
{
|
||||
rt_uint16_t offset = 0U;
|
||||
rt_uint16_t copy_len;
|
||||
|
||||
if ((data == RT_NULL) || (length == 0U) ||
|
||||
(g_proxy.state == YMODEM_PROXY_IDLE)) return -1;
|
||||
while (offset < length) {
|
||||
/* CAN在任意会话阶段都必须抢占普通停止等待限制。 */
|
||||
if ((g_proxy.expected_len == 0U) &&
|
||||
(data[offset] == YM_CAN)) {
|
||||
chrg_ymodem_proxy_abort("north CAN");
|
||||
return 0;
|
||||
}
|
||||
if ((g_proxy.state == YMODEM_PROXY_WAIT_META_RESP) ||
|
||||
(g_proxy.state == YMODEM_PROXY_WAIT_DATA_RESP) ||
|
||||
(g_proxy.state == YMODEM_PROXY_WAIT_EOT1_RESP) ||
|
||||
(g_proxy.state == YMODEM_PROXY_WAIT_EOT2_RESP) ||
|
||||
(g_proxy.state == YMODEM_PROXY_WAIT_END_ACK)) {
|
||||
chrg_ymodem_proxy_queue_north(NAK, 0U, 1U);
|
||||
return -2;
|
||||
}
|
||||
if (g_proxy.expected_len == 0U) {
|
||||
g_proxy.expected_len = chrg_ymodem_frame_size(data[offset]);
|
||||
if (g_proxy.expected_len == 0U) {
|
||||
chrg_ymodem_proxy_queue_north(NAK, 0U, 1U);
|
||||
return -3;
|
||||
}
|
||||
g_proxy.rx_len = 0U;
|
||||
g_proxy.rx_tick = rt_tick_get();
|
||||
}
|
||||
copy_len = g_proxy.expected_len - g_proxy.rx_len;
|
||||
if (copy_len > (length - offset)) copy_len = length - offset;
|
||||
rt_memcpy(&g_proxy.rx_buf[g_proxy.rx_len], &data[offset], copy_len);
|
||||
g_proxy.rx_len += copy_len;
|
||||
offset += copy_len;
|
||||
g_proxy.activity_tick = rt_tick_get();
|
||||
if (g_proxy.rx_len == g_proxy.expected_len) {
|
||||
int ret = chrg_ymodem_proxy_handle_frame(g_proxy.rx_buf,
|
||||
g_proxy.rx_len);
|
||||
g_proxy.rx_len = 0U;
|
||||
g_proxy.expected_len = 0U;
|
||||
g_proxy.rx_tick = 0U;
|
||||
if (ret != 0) return ret;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void chrg_ymodem_proxy_handle_south(rt_uint8_t response)
|
||||
{
|
||||
g_proxy.activity_tick = rt_tick_get();
|
||||
LOG_I("south rx ch=%u state=%s resp=%02x pkt=%u",
|
||||
g_proxy.ch + 1U, chrg_ymodem_proxy_state_name(g_proxy.state),
|
||||
response, g_proxy.current_packet);
|
||||
if (response == YM_CAN) {
|
||||
chrg_ymodem_proxy_abort("south CAN");
|
||||
return;
|
||||
}
|
||||
switch (g_proxy.state) {
|
||||
case YMODEM_PROXY_WAIT_C:
|
||||
if (response == ACK_C) {
|
||||
chrg_ymodem_proxy_queue_north(ACK_C, 0U, 1U);
|
||||
g_proxy.state = YMODEM_PROXY_WAIT_META;
|
||||
}
|
||||
break;
|
||||
case YMODEM_PROXY_WAIT_META_RESP:
|
||||
if (response == ACK) {
|
||||
g_proxy.meta_ack_seen = 1U;
|
||||
chrg_ymodem_proxy_queue_north(ACK, 0U, 1U);
|
||||
} else if ((response == ACK_C) && g_proxy.meta_ack_seen) {
|
||||
chrg_ymodem_proxy_queue_north(ACK_C, 0U, 1U);
|
||||
g_proxy.expected_packet = 1U;
|
||||
g_proxy.state = YMODEM_PROXY_WAIT_DATA;
|
||||
} else if (response == NAK) {
|
||||
chrg_ymodem_proxy_queue_north(NAK, 0U, 1U);
|
||||
g_proxy.state = YMODEM_PROXY_WAIT_META;
|
||||
}
|
||||
break;
|
||||
case YMODEM_PROXY_WAIT_DATA_RESP:
|
||||
if (response == ACK) {
|
||||
chrg_ymodem_proxy_queue_north(ACK, 0U, 1U);
|
||||
g_proxy.expected_packet++;
|
||||
g_proxy.state = YMODEM_PROXY_WAIT_DATA;
|
||||
} else if (response == NAK) {
|
||||
chrg_ymodem_proxy_queue_north(NAK, 0U, 1U);
|
||||
g_proxy.state = YMODEM_PROXY_WAIT_DATA;
|
||||
}
|
||||
break;
|
||||
case YMODEM_PROXY_WAIT_EOT1_RESP:
|
||||
if (response == NAK) {
|
||||
chrg_ymodem_proxy_queue_north(NAK, 0U, 1U);
|
||||
g_proxy.state = YMODEM_PROXY_WAIT_EOT2;
|
||||
} else if (response == ACK) {
|
||||
chrg_ymodem_proxy_abort("first EOT returned ACK");
|
||||
}
|
||||
break;
|
||||
case YMODEM_PROXY_WAIT_EOT2_RESP:
|
||||
if (response == ACK) {
|
||||
g_proxy.eot2_ack_seen = 1U;
|
||||
chrg_ymodem_proxy_queue_north(ACK, 0U, 1U);
|
||||
} else if ((response == ACK_C) && g_proxy.eot2_ack_seen) {
|
||||
chrg_ymodem_proxy_queue_north(ACK_C, 0U, 1U);
|
||||
g_proxy.state = YMODEM_PROXY_WAIT_END_SOH;
|
||||
} else if (response == NAK) {
|
||||
chrg_ymodem_proxy_queue_north(NAK, 0U, 1U);
|
||||
g_proxy.state = YMODEM_PROXY_WAIT_EOT2;
|
||||
}
|
||||
break;
|
||||
case YMODEM_PROXY_WAIT_END_ACK:
|
||||
if (response == ACK) {
|
||||
chrg_ymodem_proxy_queue_north(ACK, 0U, 1U);
|
||||
g_proxy.state = YMODEM_PROXY_TRANSFER_DONE;
|
||||
} else if (response == NAK) {
|
||||
chrg_ymodem_proxy_queue_north(NAK, 0U, 1U);
|
||||
g_proxy.state = YMODEM_PROXY_WAIT_END_SOH;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
rt_uint16_t chrg_ymodem_proxy_poll(rt_uint8_t *output,
|
||||
rt_uint16_t capacity)
|
||||
{
|
||||
rt_tick_t now;
|
||||
rt_uint8_t response;
|
||||
rt_uint16_t length;
|
||||
|
||||
if ((output == RT_NULL) || (capacity == 0U) ||
|
||||
(g_proxy.state == YMODEM_PROXY_IDLE)) return 0U;
|
||||
now = rt_tick_get();
|
||||
/* CAN已交给南向发送线程且北向CAN已发出后再恢复普通轮询,
|
||||
* 禁止session_stop提前清掉尚未真正发送的南向CAN。 */
|
||||
if ((g_proxy.state == YMODEM_PROXY_ABORT) &&
|
||||
(g_proxy.north_pending_len == 0U) &&
|
||||
(chrgrollsou.send_flag == 0U)) {
|
||||
chrg_ymodem_proxy_session_stop();
|
||||
return 0U;
|
||||
}
|
||||
if (g_proxy.deferred_c && (g_proxy.state == YMODEM_PROXY_WAIT_C)) {
|
||||
g_proxy.deferred_c = 0U;
|
||||
chrg_ymodem_proxy_handle_south(ACK_C);
|
||||
}
|
||||
response = chrg_eload_get_ymodem_resp();
|
||||
if (response != 0U) chrg_ymodem_proxy_handle_south(response);
|
||||
if ((g_proxy.expected_len != 0U) && (g_proxy.rx_tick != 0U) &&
|
||||
((rt_tick_t)(now - g_proxy.rx_tick) >=
|
||||
rt_tick_from_millisecond(YMODEM_RX_FRAME_TIMEOUT_MS))) {
|
||||
g_proxy.rx_len = 0U;
|
||||
g_proxy.expected_len = 0U;
|
||||
g_proxy.rx_tick = 0U;
|
||||
chrg_ymodem_proxy_queue_north(NAK, 0U, 1U);
|
||||
}
|
||||
if ((g_proxy.response_tick != 0U) &&
|
||||
((g_proxy.state == YMODEM_PROXY_WAIT_META_RESP) ||
|
||||
(g_proxy.state == YMODEM_PROXY_WAIT_DATA_RESP) ||
|
||||
(g_proxy.state == YMODEM_PROXY_WAIT_EOT1_RESP) ||
|
||||
(g_proxy.state == YMODEM_PROXY_WAIT_EOT2_RESP) ||
|
||||
(g_proxy.state == YMODEM_PROXY_WAIT_END_ACK)) &&
|
||||
((rt_tick_t)(now - g_proxy.response_tick) >=
|
||||
rt_tick_from_millisecond(YMODEM_RESPONSE_TIMEOUT_MS))) {
|
||||
chrg_ymodem_proxy_abort("south response timeout");
|
||||
}
|
||||
if ((g_proxy.state != YMODEM_PROXY_ABORT) &&
|
||||
(g_proxy.activity_tick != 0U) &&
|
||||
((rt_tick_t)(now - g_proxy.activity_tick) >=
|
||||
rt_tick_from_millisecond(YMODEM_SESSION_IDLE_MS))) {
|
||||
chrg_ymodem_proxy_abort("session idle timeout");
|
||||
}
|
||||
if (g_proxy.north_pending_len == 0U) return 0U;
|
||||
length = g_proxy.north_pending_len;
|
||||
if (length > capacity) return 0U;
|
||||
rt_memcpy(output, g_proxy.north_pending, length);
|
||||
g_proxy.north_pending_len = 0U;
|
||||
return length;
|
||||
}
|
||||
|
||||
rt_bool_t chrg_ymodem_proxy_active(void)
|
||||
{
|
||||
return (g_proxy.state != YMODEM_PROXY_IDLE) ? RT_TRUE : RT_FALSE;
|
||||
}
|
||||
|
||||
rt_uint8_t chrg_ymodem_proxy_channel(void)
|
||||
{
|
||||
return g_proxy.ch;
|
||||
}
|
||||
|
||||
chrg_ymodem_proxy_state_t chrg_ymodem_proxy_state(void)
|
||||
{
|
||||
return g_proxy.state;
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
#ifndef __CHRG_YMODEM_PROXY_H__
|
||||
#define __CHRG_YMODEM_PROXY_H__
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
typedef enum {
|
||||
YMODEM_PROXY_IDLE = 0,
|
||||
YMODEM_PROXY_ENTERING,
|
||||
YMODEM_PROXY_WAIT_C,
|
||||
YMODEM_PROXY_WAIT_META,
|
||||
YMODEM_PROXY_WAIT_META_RESP,
|
||||
YMODEM_PROXY_WAIT_DATA,
|
||||
YMODEM_PROXY_WAIT_DATA_RESP,
|
||||
YMODEM_PROXY_WAIT_EOT1_RESP,
|
||||
YMODEM_PROXY_WAIT_EOT2,
|
||||
YMODEM_PROXY_WAIT_EOT2_RESP,
|
||||
YMODEM_PROXY_WAIT_END_SOH,
|
||||
YMODEM_PROXY_WAIT_END_ACK,
|
||||
YMODEM_PROXY_TRANSFER_DONE,
|
||||
YMODEM_PROXY_EXITING,
|
||||
YMODEM_PROXY_VERIFY,
|
||||
YMODEM_PROXY_ABORT
|
||||
} chrg_ymodem_proxy_state_t;
|
||||
|
||||
extern int chrg_ymodem_proxy_enter(rt_uint8_t ch);
|
||||
extern int chrg_ymodem_proxy_exit(rt_uint8_t ch);
|
||||
extern int chrg_ymodem_proxy_feed_north(const rt_uint8_t *data,
|
||||
rt_uint16_t length);
|
||||
extern rt_uint16_t chrg_ymodem_proxy_poll(rt_uint8_t *output,
|
||||
rt_uint16_t capacity);
|
||||
extern rt_bool_t chrg_ymodem_proxy_active(void);
|
||||
extern rt_uint8_t chrg_ymodem_proxy_channel(void);
|
||||
extern chrg_ymodem_proxy_state_t chrg_ymodem_proxy_state(void);
|
||||
|
||||
#endif
|
||||
@@ -503,6 +503,11 @@
|
||||
<FileType>1</FileType>
|
||||
<FilePath>applications\utils\chrg_eload.c</FilePath>
|
||||
</File>
|
||||
<File>
|
||||
<FileName>chrg_ymodem_proxy.c</FileName>
|
||||
<FileType>1</FileType>
|
||||
<FilePath>applications\utils\chrg_ymodem_proxy.c</FilePath>
|
||||
</File>
|
||||
<File>
|
||||
<FileName>chrg_utils.c</FileName>
|
||||
<FileType>1</FileType>
|
||||
|
||||
Reference in New Issue
Block a user