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:
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user