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
@@ -212,7 +212,11 @@ typedef enum {
LUP_FRAME_STATE_HEADER, // 接收 Header (Addr, LEN, CMD) LUP_FRAME_STATE_HEADER, // 接收 Header (Addr, LEN, CMD)
LUP_FRAME_STATE_VALUE, // 接收 Value LUP_FRAME_STATE_VALUE, // 接收 Value
LUP_FRAME_STATE_CHECK, // 接收 Checksum 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; } LUP_FrameState;
typedef struct { typedef struct {
@@ -228,6 +232,11 @@ extern LUP_FrameParser g_lup_parser;
/* 喂一个字节给帧解析器,返回 1 表示帧接收完成 */ /* 喂一个字节给帧解析器,返回 1 表示帧接收完成 */
int lup_feed_byte(uint8_t byte); 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); const uint8_t *lup_frame_data(void);
uint16_t lup_frame_len(void); uint16_t lup_frame_len(void);
@@ -655,6 +655,110 @@ int lup_feed_byte(uint8_t byte)
// 不应该到达这里,调用方应在 COMPLETE 后 reset // 不应该到达这里,调用方应在 COMPLETE 后 reset
lup_frame_reset(); lup_frame_reset();
break; 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; 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 uint8_t uart2_dma_buf[UART2_DMA_BUF_LEN] __attribute__((aligned(4)));
static uint16_t uart2_dma_last = 0; /* 主循环消费位置 (DMA 写指针由硬件维护) */ static uint16_t uart2_dma_last = 0; /* 主循环消费位置 (DMA 写指针由硬件维护) */
static uint32_t uart2_dma_drop = 0; /* 溢出丢弃计数 (主循环消费不及时) */ static uint32_t uart2_dma_drop = 0; /* 溢出丢弃计数 (主循环消费不及时) */
static uint8_t uart2_dma_ota_mode = 0xFF; /* 上次 OTA 模式 (0xFF=未初始化, 首轮强制 reset) */
void uart2_dma_init(void) void uart2_dma_init(void)
{ {
@@ -67,19 +68,33 @@ void uart2_dma_poll(void)
if (n == 0) return; if (n == 0) return;
/* 溢出保护: 未消费 > 半缓冲 (256B) → 消费太慢被 DMA 覆盖, 重置解析器丢帧计数 */ /* 溢出保护: 未消费 > 半缓冲 (256B) → 消费太慢被 DMA 覆盖, 重置解析器丢帧计数
if (n > (UART2_DMA_BUF_LEN / 2)) { 2026-08-19: OTA 模式下 0x9F ACK 帧仅 7B, 停等协议同一时刻 Loop 至多回 1 帧,
uart2_dma_drop++; 放宽阈值到整缓冲 — 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(); lup_frame_reset();
uart2_dma_last = cur; uart2_dma_ota_mode = g_flag_counter_ota.flag;
return;
} }
while (n--) { while (n--) {
uint8_t b = uart2_dma_buf[uart2_dma_last]; uint8_t b = uart2_dma_buf[uart2_dma_last];
uart2_dma_last = (uint16_t)((uart2_dma_last + 1) & (UART2_DMA_BUF_LEN - 1)); 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 (与中断版同逻辑, 主循环无竞争) */ /* 帧接收完成 → 复制到 g_pkg_uart_2 (与中断版同逻辑, 主循环无竞争) */
const uint8_t *frame = lup_frame_data(); const uint8_t *frame = lup_frame_data();
uint16_t frame_len = lup_frame_len(); uint16_t frame_len = lup_frame_len();
@@ -90,6 +105,9 @@ void uart2_dma_poll(void)
g_pkg_uart_2.tick = 0; g_pkg_uart_2.tick = 0;
} }
lup_frame_reset(); 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{ 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);
} }
+42
View File
@@ -4,6 +4,47 @@
> >
> 项目定位: DLD960 通信板 — BLE 配网、TCP JSON 协议服务、Loop MCU 串口桥接 > 项目定位: DLD960 通信板 — BLE 配网、TCP JSON 协议服务、Loop MCU 串口桥接
## 2026-08-19 — UART2 RX DMA 下 BLE→Loop OTA 失效修复:0x9F 帧透传回 BLE
### 背景
DMA 改造(fed4335)后通过 BLE 给地感(Loop MCU)OTA 升级失效。代码排查 + DLD960LoopBootloader 源码确认根因。
### 根因
1. **`lup_feed_byte()` IDLE 态只认 `0x7F`**Loop bootloader 回的 0x9F 响应帧(pre_ok/addr_ok/data ACK)第一个字节就被丢弃
2. **OTA 是停等协议**`0xA7` (TRAN_PKG_WITH_BACK) 每收一块必须回 `back_9F_data()` ACK,工具等不到 ACK 不发下一块 → DBN 吞掉 ACK = 升级必然卡死
3. **`uart_srv` OTA 分支"忽略 Loop MCU 数据"**——即使解析成功也不透传回 BLE
4. DMA 版相对中断版丢失"收帧中 tick 归零";溢出保护 256B 阈值在 TX 阻塞窗口可能误杀 ACK
### 0x9F 帧格式(DLD960LoopBootloader 源码确认)
| 方向 | 帧格式 | 说明 |
|------|--------|------|
| 下行 | `9F SubL SubH LEN CMD DATA(LEN-1) CHECK` | CHECK = SUM(SubL..DATA)**无 XOR**LEN 含 CMD |
| 上行 | `9F SubL SubH 02 CMD Status CHECK` | 例:pre_ok = `9F 01 00 02 A5 00 A8` |
| CMD | `A5` READY / `A6` ADDR_START / `A7` TRAN_WITH_BACK(回ACK) / `A8` TRAN_WITHOUT_BACK(不回) | 总帧长 = LEN+5 与 0x7F 相同 |
### 变更
| 文件 | 变更 |
|------|------|
| `loop_uart_proto.h` | `LUP_FrameState` 追加 OTA 专用状态(OTA_LEN/OTA_CMD/OTA_CHECK);声明 `lup_feed_byte_ota()` |
| `loop_uart_proto.c` | 实现 `lup_feed_byte_ota()`:0x9F 帧状态机(SUM 校验,复用 `g_lup_parser` 缓冲);`lup_feed_byte` 加 default 防御性 reset |
| `usart_biz.c` | `uart2_dma_poll`:OTA 模式切换时 reset 解析器 + 按 `g_flag_counter_ota.flag` 选 0x9F/0x7F 解析器 + OTA 模式溢出阈值放宽到整缓冲(0x9F ACK 仅 7B,停等协议同刻至多 1 帧)+ 收帧中 tick 归零(对齐中断版);`uart_srv` OTA 分支:0x9F 帧 `set_response_tran_to_notify` 透传回 BLE + `InitPkgUart` 清 flag |
### 验证
- gcc 隔离单测 `tests/test_lup_ota_parser.c`**8 断言全过**bootloader 真实帧向量 pre_ok/addr_ok/addr_err/data ACK、错误校验拒绝并复位、0x7F 帧隔离、两帧粘包独立解析)
- `gcc -fsyntax-only``loop_uart_proto.c`/`usart_biz.c` 无新错误(仅 RISC-V interrupt attribute 假阳性 + 原有 unused warning
### 遗留
- **`g_flag_counter_ota.flag` 无退出机制**:升级完成后 DBN 仍卡 OTA 透传态,只能断电重启恢复 0x7F 通信——待定加"OTA 超时/完成帧自动退出"
- 待板级:MRS 编译 + 真机 BLE OTA 全流程回归
---
## 2026-08-18 — log_query 改为 hex 原始字节上报(协议 V1.03/V1.07 修订) ## 2026-08-18 — log_query 改为 hex 原始字节上报(协议 V1.03/V1.07 修订)
### 背景 ### 背景
@@ -1370,6 +1411,7 @@ TCP 超时要等 ~2 分钟才触发 `SINT_STAT_TIM_OUT`,
| 版本 | 时间 | 说明 | | 版本 | 时间 | 说明 |
|------|------|------| |------|------|------|
| V4.4 | 2026-08-19 | UART2 DMA 下 BLE→Loop OTA 修复: lup_feed_byte_ota 0x9F 帧解析+透传回 BLE (停等 ACK), DMA poll OTA 模式切换/溢出阈值/tick 归零, 单测 8 例 |
| V4.3 | 2026-08-18 | log_query 改 hex 原始字节上报 (协议 V1.03/V1.07 修订): offlog_evt_to_hex/snap_rec_to_hex, 2 条快照 406B<800B, 快照 count 恢复 2 | | V4.3 | 2026-08-18 | log_query 改 hex 原始字节上报 (协议 V1.03/V1.07 修订): offlog_evt_to_hex/snap_rec_to_hex, 2 条快照 406B<800B, 快照 count 恢复 2 |
| V4.2 | 2026-08-18 | MQTT 命令集补齐: ssc_net_query/iot_net_query/iot_topic_query 只读组包 (协议 V1.02 对齐), 工具禁用未实现按钮 | | V4.2 | 2026-08-18 | MQTT 命令集补齐: ssc_net_query/iot_net_query/iot_topic_query 只读组包 (协议 V1.02 对齐), 工具禁用未实现按钮 |
| V4.1 | 2026-08-18 | TCP/MQTT 脱机日志快照流: log_stat/log_query/log_clear 支持 stream=snapshot (协议 V1.03/V1.07), snap_rec_to_json 序列化, 事件流 count=0 按上限 | | V4.1 | 2026-08-18 | TCP/MQTT 脱机日志快照流: log_stat/log_query/log_clear 支持 stream=snapshot (协议 V1.03/V1.07), snap_rec_to_json 序列化, 事件流 count=0 按上限 |
+262
View File
@@ -0,0 +1,262 @@
/*
* test_lup_ota_parser.c lup_feed_byte_ota 0x9F
*
* DLD960LoopBootloader (back_9F_pre_ok/addr_ok/data):
* pre_ok : 9F 01 00 02 A5 00 A8 (CHECK = 01+00+02+A5+00 = A8)
* addr_ok: 9F 01 00 02 A6 00 A9
* addr_err:9F 01 00 02 A6 01 AA
* data : 9F <sub_l> <sub_h> 02 A7 <status> <sum>
*
* : gcc -I../BLE/OnlyUpdateApp_Peripheral/APP/include -o test_lup_ota_parser test_lup_ota_parser.c
*/
#include <stdio.h>
#include <string.h>
#include <stdint.h>
/* ---- mock: 从 loop_uart_proto.h 复制的最小依赖 ---- */
#define LUP_MAGIC 0x7F
#define LUP_MAGIC_OTA 0x9F
#define LUP_MAX_VALUE_LEN 64
#define LUP_MAX_PKG_LEN (1 + 3 + LUP_MAX_VALUE_LEN + 2)
typedef enum {
LUP_FRAME_STATE_IDLE = 0,
LUP_FRAME_STATE_HEADER,
LUP_FRAME_STATE_VALUE,
LUP_FRAME_STATE_CHECK,
LUP_FRAME_STATE_COMPLETE,
LUP_FRAME_STATE_OTA_LEN,
LUP_FRAME_STATE_OTA_CMD,
LUP_FRAME_STATE_OTA_CHECK
} LUP_FrameState;
typedef struct {
LUP_FrameState state;
uint8_t buf[LUP_MAX_PKG_LEN];
uint16_t idx;
uint16_t value_len;
uint16_t value_idx;
} LUP_FrameParser;
static LUP_FrameParser g_lup_parser;
static void lup_frame_reset(void)
{
g_lup_parser.state = LUP_FRAME_STATE_IDLE;
g_lup_parser.idx = 0;
g_lup_parser.value_len = 0;
g_lup_parser.value_idx = 0;
memset(g_lup_parser.buf, 0, sizeof(g_lup_parser.buf));
}
static const uint8_t *lup_frame_data(void) { return g_lup_parser.buf; }
static uint16_t lup_frame_len(void) { return g_lup_parser.idx; }
/* ---- 嵌入被测函数体 (从 loop_uart_proto.c 提取) ---- */
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;
}
break;
case LUP_FRAME_STATE_HEADER:
p->buf[p->idx++] = byte;
if (p->idx == 3) {
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;
} else {
data_bytes = len_field - 1;
}
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;
} 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;
{
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:
lup_frame_reset();
break;
default:
lup_frame_reset();
break;
}
return 0;
}
/* ---- 测试辅助 ---- */
static int fails = 0;
/* 喂完整帧, 断言: 帧完成 且 len 正确 */
static void feed_frame(const uint8_t *frame, int len, const char *name)
{
int i, done = 0;
lup_frame_reset();
for (i = 0; i < len; i++) {
if (lup_feed_byte_ota(frame[i])) {
done = 1;
break;
}
}
if (!done) {
printf("FAIL %s: frame not completed\n", name);
fails++;
return;
}
if ((int)lup_frame_len() != len) {
printf("FAIL %s: len=%d expected %d\n", name, (int)lup_frame_len(), len);
fails++;
return;
}
if (memcmp(lup_frame_data(), frame, len) != 0) {
printf("FAIL %s: content mismatch\n", name);
fails++;
return;
}
printf("PASS %s\n", name);
}
/* 喂错误校验帧, 断言: 解析失败 (reset 回 IDLE) */
static void feed_bad(const uint8_t *frame, int len, const char *name)
{
int i, done = 0;
lup_frame_reset();
for (i = 0; i < len; i++) {
if (lup_feed_byte_ota(frame[i])) {
done = 1;
break;
}
}
if (done) {
printf("FAIL %s: bad checksum accepted\n", name);
fails++;
return;
}
if (g_lup_parser.state != LUP_FRAME_STATE_IDLE) {
printf("FAIL %s: parser not reset to IDLE (state=%d)\n", name, g_lup_parser.state);
fails++;
return;
}
printf("PASS %s\n", name);
}
int main(void)
{
uint8_t f1[] = {0x9F, 0x01, 0x00, 0x02, 0xA5, 0x00, 0xA8}; /* pre_ok */
uint8_t f2[] = {0x9F, 0x01, 0x00, 0x02, 0xA6, 0x00, 0xA9}; /* addr_ok */
uint8_t f3[] = {0x9F, 0x01, 0x00, 0x02, 0xA6, 0x01, 0xAA}; /* addr_err */
uint8_t f4[] = {0x9F, 0x05, 0x00, 0x02, 0xA7, 0x00, 0xAE}; /* data ACK sub=5 ok */
uint8_t f5[] = {0x9F, 0x34, 0x12, 0x02, 0xA7, 0x01, 0xF0}; /* data ACK sub=0x1234 err */
uint8_t bad[] = {0x9F, 0x01, 0x00, 0x02, 0xA5, 0x00, 0xA9}; /* CHECK 错 */
uint8_t v7f[] = {0x7F, 0x00, 0x04, 0x4A, 0x00, 0x4E, 0x4E}; /* 0x7F 帧不应被解析 */
feed_frame(f1, sizeof(f1), "pre_ok (9F 01 00 02 A5 00 A8)");
feed_frame(f2, sizeof(f2), "addr_ok (9F 01 00 02 A6 00 A9)");
feed_frame(f3, sizeof(f3), "addr_err(9F 01 00 02 A6 01 AA)");
feed_frame(f4, sizeof(f4), "data ack sub=5 (9F 05 00 02 A7 00 AE)");
feed_frame(f5, sizeof(f5), "data ack sub=0x1234 err (9F 34 12 02 A7 01 F0)");
feed_bad(bad, sizeof(bad), "bad checksum rejected");
/* 0x7F 帧: IDLE 不认 → 应无帧完成, 状态回 IDLE */
{
int i, done = 0;
lup_frame_reset();
for (i = 0; i < (int)sizeof(v7f); i++) {
if (lup_feed_byte_ota(v7f[i])) { done = 1; break; }
}
if (done) {
printf("FAIL 0x7F frame parsed by ota parser\n");
fails++;
} else if (g_lup_parser.state != LUP_FRAME_STATE_IDLE) {
printf("FAIL 0x7F frame left parser non-IDLE (state=%d)\n", g_lup_parser.state);
fails++;
} else {
printf("PASS 0x7F frame ignored by ota parser\n");
}
}
/* 粘帧: 两帧连续 → 各自解析成功 */
{
uint8_t glue[14];
int i, done_cnt = 0;
memcpy(glue, f1, 7);
memcpy(glue + 7, f2, 7);
lup_frame_reset();
for (i = 0; i < 14; i++) {
if (lup_feed_byte_ota(glue[i])) {
done_cnt++;
if (done_cnt == 1 && memcmp(lup_frame_data(), f1, 7) != 0) {
printf("FAIL glue frame1 mismatch\n"); fails++;
}
if (done_cnt == 2 && memcmp(lup_frame_data(), f2, 7) != 0) {
printf("FAIL glue frame2 mismatch\n"); fails++;
}
lup_frame_reset();
}
}
if (done_cnt != 2) {
printf("FAIL glue: %d frames completed, expected 2\n", done_cnt);
fails++;
} else {
printf("PASS glued frames parsed independently\n");
}
}
printf("\n%s (%d failures)\n", fails ? "FAILED" : "ALL PASS", fails);
return fails ? 1 : 0;
}