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:
wangfq
2026-08-19 11:01:45 +08:00
parent 839d79b487
commit d67f955fd4
5 changed files with 450 additions and 8 deletions
@@ -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;