fix(vd960DBN): BLE→Loop OTA 失效修复 — 0x9F 帧透传回 BLE
DMA 改造(fed4335)后 UART2 RX 走 lup_feed_byte 只认 0x7F, Loop bootloader
回的 0x9F 响应帧(pre_ok/addr_ok/data ACK)全被吞; OTA 是停等协议
(0xA7 WITH_BACK 每块必回 ACK), 工具等不到 ACK 升级必然卡死。
- loop_uart_proto: 新增 lup_feed_byte_ota() 0x9F 帧状态机 (SUM 校验无 XOR,
复用 g_lup_parser), 枚举追加 OTA 专用状态
- usart_biz: uart2_dma_poll 按 g_flag_counter_ota.flag 切换 0x9F/0x7F 解析器,
模式切换 reset, OTA 溢出阈值放宽整缓冲, 补收帧 tick 归零;
uart_srv OTA 分支 0x9F 帧透传回 BLE + 清 flag
- 单测 tests/test_lup_ota_parser.c 8 断言全过 (bootloader 真实帧向量)
- 遗留: g_flag_counter_ota.flag 无退出机制, 升级后需断电重启
This commit is contained in:
@@ -212,7 +212,11 @@ typedef enum {
|
||||
LUP_FRAME_STATE_HEADER, // 接收 Header (Addr, LEN, CMD)
|
||||
LUP_FRAME_STATE_VALUE, // 接收 Value
|
||||
LUP_FRAME_STATE_CHECK, // 接收 Checksum
|
||||
LUP_FRAME_STATE_COMPLETE // 帧完成
|
||||
LUP_FRAME_STATE_COMPLETE, // 帧完成
|
||||
/* 0x9F OTA 专用状态 (2026-08-19): 帧格式 9F SubL SubH LEN CMD DATA CHECK */
|
||||
LUP_FRAME_STATE_OTA_LEN, // 0x9F: 收 LEN (含 CMD)
|
||||
LUP_FRAME_STATE_OTA_CMD, // 0x9F: 收 CMD
|
||||
LUP_FRAME_STATE_OTA_CHECK // 0x9F: 收 CHECK (仅 SUM, 无 XOR)
|
||||
} LUP_FrameState;
|
||||
|
||||
typedef struct {
|
||||
@@ -228,6 +232,11 @@ extern LUP_FrameParser g_lup_parser;
|
||||
/* 喂一个字节给帧解析器,返回 1 表示帧接收完成 */
|
||||
int lup_feed_byte(uint8_t byte);
|
||||
|
||||
/* 0x9F OTA 帧解析器 (OTA 模式专用, g_flag_counter_ota.flag=1 时使用)
|
||||
* 帧格式: 9F SubL SubH LEN CMD DATA(LEN-1) CHECK(SUM)
|
||||
* 与 0x7F 共用 g_lup_parser 缓冲/索引, 状态值独立 (LUP_FRAME_STATE_OTA_*) */
|
||||
int lup_feed_byte_ota(uint8_t byte);
|
||||
|
||||
/* 取完整帧的指针和数据长度 */
|
||||
const uint8_t *lup_frame_data(void);
|
||||
uint16_t lup_frame_len(void);
|
||||
|
||||
@@ -655,6 +655,110 @@ int lup_feed_byte(uint8_t byte)
|
||||
// 不应该到达这里,调用方应在 COMPLETE 后 reset
|
||||
lup_frame_reset();
|
||||
break;
|
||||
default:
|
||||
/* 未知状态 (含 0x9F OTA 专用状态值): 防御性复位, 防状态机跑飞 */
|
||||
lup_frame_reset();
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*===========================================================================
|
||||
* 0x9F OTA 帧解析器 (OTA 模式专用, 2026-08-19)
|
||||
*
|
||||
* 帧格式 (DLD960LoopBootloader 源码确认):
|
||||
* [9F] [SubL] [SubH] [LEN] [CMD] [DATA: LEN-1] [CHECK: SUM]
|
||||
* - SubL/SubH: 分包序号, 2 字节小端 (低字节在前)
|
||||
* - LEN: 含 CMD 的字节数, 故 DATA = LEN - 1
|
||||
* - CHECK: 仅 SUM 校验 (无 XOR), 从 SubL 累加到 DATA 最后字节
|
||||
* 总帧长 = LEN + 5 (与 0x7F 相同)
|
||||
*
|
||||
* 状态机复用 g_lup_parser (缓冲/索引), 状态值独立 (LUP_FRAME_STATE_OTA_*)
|
||||
* 调用方 (uart2_dma_poll) 在 OTA 模式切换时负责 lup_frame_reset()
|
||||
*===========================================================================*/
|
||||
int lup_feed_byte_ota(uint8_t byte)
|
||||
{
|
||||
LUP_FrameParser *p = &g_lup_parser;
|
||||
|
||||
switch (p->state) {
|
||||
case LUP_FRAME_STATE_IDLE:
|
||||
if (byte == LUP_MAGIC_OTA) {
|
||||
p->buf[0] = byte;
|
||||
p->idx = 1;
|
||||
p->state = LUP_FRAME_STATE_HEADER; /* 复用 HEADER: 收 SubL/SubH */
|
||||
}
|
||||
break;
|
||||
|
||||
case LUP_FRAME_STATE_HEADER:
|
||||
p->buf[p->idx++] = byte;
|
||||
if (p->idx == 3) { /* SubL + SubH 收完 */
|
||||
p->state = LUP_FRAME_STATE_OTA_LEN;
|
||||
}
|
||||
break;
|
||||
|
||||
case LUP_FRAME_STATE_OTA_LEN:
|
||||
p->buf[p->idx++] = byte;
|
||||
{
|
||||
uint8_t len_field = p->buf[3];
|
||||
uint16_t data_bytes;
|
||||
if (len_field < 1) {
|
||||
data_bytes = 0; /* LEN<1 非法, 按无数据直接到 CHECK */
|
||||
} else {
|
||||
data_bytes = len_field - 1; /* LEN 含 CMD */
|
||||
}
|
||||
if (data_bytes > LUP_MAX_VALUE_LEN) {
|
||||
lup_frame_reset(); /* 非法长度, 丢弃 */
|
||||
break;
|
||||
}
|
||||
p->value_len = data_bytes;
|
||||
p->value_idx = 0;
|
||||
}
|
||||
p->state = LUP_FRAME_STATE_OTA_CMD;
|
||||
break;
|
||||
|
||||
case LUP_FRAME_STATE_OTA_CMD:
|
||||
p->buf[p->idx++] = byte;
|
||||
if (p->value_len > 0) {
|
||||
p->state = LUP_FRAME_STATE_VALUE; /* 复用 VALUE: 收 DATA */
|
||||
} else {
|
||||
p->state = LUP_FRAME_STATE_OTA_CHECK;
|
||||
}
|
||||
break;
|
||||
|
||||
case LUP_FRAME_STATE_VALUE:
|
||||
p->buf[p->idx++] = byte;
|
||||
p->value_idx++;
|
||||
if (p->value_idx >= p->value_len) {
|
||||
p->state = LUP_FRAME_STATE_OTA_CHECK;
|
||||
}
|
||||
break;
|
||||
|
||||
case LUP_FRAME_STATE_OTA_CHECK:
|
||||
p->buf[p->idx++] = byte;
|
||||
{
|
||||
/* SUM = SubL+SubH+LEN+CMD+DATA (不含 magic 0x9F, 不含本 CHECK) */
|
||||
uint8_t sum = 0;
|
||||
uint16_t i;
|
||||
for (i = 1; i < (uint16_t)(p->idx - 1); i++) {
|
||||
sum += p->buf[i];
|
||||
}
|
||||
if (sum == p->buf[p->idx - 1]) {
|
||||
p->state = LUP_FRAME_STATE_COMPLETE;
|
||||
return 1; /* 帧完成 */
|
||||
}
|
||||
lup_frame_reset(); /* 校验失败, 丢弃 */
|
||||
}
|
||||
break;
|
||||
|
||||
case LUP_FRAME_STATE_COMPLETE:
|
||||
// 不应该到达这里,调用方应在 COMPLETE 后 reset
|
||||
lup_frame_reset();
|
||||
break;
|
||||
|
||||
default:
|
||||
lup_frame_reset();
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -28,6 +28,7 @@ void USART2_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
|
||||
static uint8_t uart2_dma_buf[UART2_DMA_BUF_LEN] __attribute__((aligned(4)));
|
||||
static uint16_t uart2_dma_last = 0; /* 主循环消费位置 (DMA 写指针由硬件维护) */
|
||||
static uint32_t uart2_dma_drop = 0; /* 溢出丢弃计数 (主循环消费不及时) */
|
||||
static uint8_t uart2_dma_ota_mode = 0xFF; /* 上次 OTA 模式 (0xFF=未初始化, 首轮强制 reset) */
|
||||
|
||||
void uart2_dma_init(void)
|
||||
{
|
||||
@@ -67,19 +68,33 @@ void uart2_dma_poll(void)
|
||||
|
||||
if (n == 0) return;
|
||||
|
||||
/* 溢出保护: 未消费 > 半缓冲 (256B) → 消费太慢被 DMA 覆盖, 重置解析器丢帧计数 */
|
||||
if (n > (UART2_DMA_BUF_LEN / 2)) {
|
||||
uart2_dma_drop++;
|
||||
/* 溢出保护: 未消费 > 半缓冲 (256B) → 消费太慢被 DMA 覆盖, 重置解析器丢帧计数
|
||||
2026-08-19: OTA 模式下 0x9F ACK 帧仅 7B, 停等协议同一时刻 Loop 至多回 1 帧,
|
||||
放宽阈值到整缓冲 — 256B 阈值在 TX 阻塞窗口可能误杀 ACK */
|
||||
{
|
||||
uint16_t drop_thr = g_flag_counter_ota.flag ? UART2_DMA_BUF_LEN : (UART2_DMA_BUF_LEN / 2);
|
||||
if (n > drop_thr) {
|
||||
uart2_dma_drop++;
|
||||
lup_frame_reset();
|
||||
uart2_dma_last = cur;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* OTA 模式切换 (0x7F ↔ 0x9F) 时重置帧解析器, 防旧模式残留状态污染 */
|
||||
if (g_flag_counter_ota.flag != uart2_dma_ota_mode) {
|
||||
lup_frame_reset();
|
||||
uart2_dma_last = cur;
|
||||
return;
|
||||
uart2_dma_ota_mode = g_flag_counter_ota.flag;
|
||||
}
|
||||
|
||||
while (n--) {
|
||||
uint8_t b = uart2_dma_buf[uart2_dma_last];
|
||||
uart2_dma_last = (uint16_t)((uart2_dma_last + 1) & (UART2_DMA_BUF_LEN - 1));
|
||||
|
||||
if (lup_feed_byte(b)) {
|
||||
/* OTA 模式走 0x9F 帧解析 (bootloader 的 pre_ok/addr_ok/data ACK),
|
||||
非 OTA 保持 0x7F 协议解析 */
|
||||
int done = g_flag_counter_ota.flag ? lup_feed_byte_ota(b) : lup_feed_byte(b);
|
||||
if (done) {
|
||||
/* 帧接收完成 → 复制到 g_pkg_uart_2 (与中断版同逻辑, 主循环无竞争) */
|
||||
const uint8_t *frame = lup_frame_data();
|
||||
uint16_t frame_len = lup_frame_len();
|
||||
@@ -90,6 +105,9 @@ void uart2_dma_poll(void)
|
||||
g_pkg_uart_2.tick = 0;
|
||||
}
|
||||
lup_frame_reset();
|
||||
} else if (g_lup_parser.state != LUP_FRAME_STATE_IDLE) {
|
||||
/* 收帧中 → tick 归零 (对齐中断版行为, 防 TIM3 半帧兜底误判) */
|
||||
g_pkg_uart_2.tick = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -273,7 +291,14 @@ void uart_srv(void)
|
||||
}
|
||||
}
|
||||
else{
|
||||
// OTA 模式 — 忽略 Loop MCU 数据
|
||||
/* OTA 模式 (2026-08-19): Loop bootloader 回的 0x9F 帧
|
||||
(back_9F_pre_ok / addr_ok / data ACK) 透传回 BLE 工具,
|
||||
否则停等协议 (0xA7 WITH_BACK) 永远等不到 ACK */
|
||||
if(g_flag_bt_state){
|
||||
g_flag_notify_temp = set_response_tran_to_notify(g_pkg_uart_2.pkg, g_pkg_uart_2.offset, &g_notify_buftemp);
|
||||
}
|
||||
/* OTA 模式同样清 flag — 残留帧会在 OTA 结束后被误处理 */
|
||||
InitPkgUart(&g_pkg_uart_2);
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user