Files
wangfq a8120cc852 feat(vd960DBN): 事件日志区动态分区 — JEDEC ID 选档 (ROADMAP 落地)
- offlog.h: OfflogPart 运行时分区表 + g_offlog_part; AREA_BASE 改 0x090000
  (参数64KB+OTA512KB); 容量宏展开为运行时值(主体零改动)
- offlog.c: offlog_part_detect() 读 JEDEC ID → 事件区容量
  W25Q32=512KB/16256条, Q64=1MB/32640, Q128=2MB/65408, Q256=4MB/130944
- storage.c/h: SPI_Flash_ReadJEDEC_ID() (0x9F, 校验 EF 40)
- 旧固件事件区 0x010000 自动废弃(新地址无 magic → 重建), 预期行为
- 测试: mock JEDEC=0x16 + g_offlog_part, 15 例全过
- 文档: BLE/MQTT/TCP 协议 capacity 8064→动态, 交互示例, devlog
2026-08-12 16:46:19 +08:00

246 lines
8.1 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* test_ble_offlog.c — dbn_ble_srv.c 脱机日志 3 case 的隔离验证
*
* 直接从 dbn_ble_srv.c 提取 case 文本嵌入本文件, 测的是源文件真实代码。
* Mock: offlog_* / set_response_buf / PRINT / Buf_DBN_BLE 类型。
*
* 编译: gcc -I../BLE/OnlyUpdateApp_Peripheral/APP/include \
* -o test_ble_offlog test_ble_offlog.c (需先跑 extract_offlog_cases.py)
* 运行: ./test_ble_offlog
*/
#include <stdio.h>
#include <string.h>
#include <stdint.h>
/* ============ 类型/宏 (来自 dbn_ble_srv.h 编辑后, 避免 include BLE 栈) ============ */
#define MAGIC_BYTE_DBN_DEFAULT 0x8F
#define CMD_DBN_OFFLOG_STAT 0x25
#define CMD_DBN_OFFLOG_QUERY 0x26
#define CMD_DBN_OFFLOG_CLEAR 0x27
#define MAX_BLE_TMP_BUF_LEN 132
#define MAX_BLE_DAT_BUF_LEN 132
#define MAX_BLE_DAT_RESPONSE_LEN (100 - 4) /* 单包数据上限 96B */
typedef struct _BLE_Notify_Buf_ {
uint8_t flag;
uint8_t len;
uint8_t buf[100];
} BLE_Notify_Buf;
typedef struct _BUF_DBN_BLE_ {
uint8_t flag;
uint8_t magic;
uint8_t cmd;
uint8_t dat_len ;
uint8_t dat_offset;
uint8_t pkg_amount;
uint8_t pkg_seq;
uint8_t dat[MAX_BLE_DAT_BUF_LEN];
} Buf_DBN_BLE;
#include "offlog.h"
#define PRINT(...) ((void)0)
/* ============ 全局 (来自 dbn_ble_srv.c) ============ */
static uint8_t tmp_ble_buf[MAX_BLE_TMP_BUF_LEN];
static Buf_DBN_BLE g_buf_ble_response;
/* ============ offlog mock ============ */
static uint32_t mock_count = 0;
static uint32_t mock_seq_last = 0;
static uint32_t mock_boot = 0;
static uint8_t mock_enabled = 1;
uint16_t offlog_count(void) { return (uint16_t)mock_count; }
uint32_t offlog_seq_last(void) { return mock_seq_last; }
uint32_t offlog_boot_seq(void) { return mock_boot; }
uint8_t offlog_enabled(void) { return mock_enabled; }
void offlog_clear(void) { mock_count = 1; mock_seq_last++; } /* 审计留痕: count 归 1, seq 继续 */
int offlog_read_idx(uint16_t idx, OfflogEvt *out)
{
uint32_t seq_first;
if (idx >= mock_count) return -1;
seq_first = mock_seq_last - mock_count + 1;
memset(out, 0, sizeof(OfflogEvt));
out->magic = OFFLOG_EVT_MAGIC;
out->type = (idx % 3 == 0) ? OFFLOG_EVT_BOOT :
(idx % 3 == 1) ? OFFLOG_EVT_IOT_READY : OFFLOG_EVT_COIL;
out->seq = seq_first + idx;
out->boot_seq = 2;
out->ts_ms = 1000 + idx * 100;
out->unix_ts = 1784768575UL;
if (idx % 3 == 2) { /* COIL: sub=1 ch=1 value=97 */
out->payload[0] = 1; out->payload[1] = 1;
out->payload[2] = 0; out->payload[3] = 0; out->payload[4] = 0; out->payload[5] = 97;
}
return 0;
}
/* g_offlog_part: OFFLOG_MAX_RECORDS 宏展开为运行时值, 此处 mock W25Q32 (512KB) */
OfflogPart g_offlog_part = { OFFLOG_CHIP_W25Q32, 0x80000UL, 127, 16256 };
/* ============ set_response_buf mock: 只记录调用参数 ============ */
static uint8_t last_cmd = 0;
static uint8_t last_len = 0;
static uint8_t last_dat[160];
uint8_t set_response_buf(Buf_DBN_BLE *response_dst, uint8_t magic, uint8_t cmd,
uint8_t *dat, uint8_t dat_len)
{
uint8_t i;
memset(last_dat, 0, sizeof(last_dat));
last_cmd = cmd;
last_len = dat_len;
for (i = 0; i < dat_len; i++) last_dat[i] = dat[i];
return 0;
}
/* ============ 被测: 从 dbn_ble_srv.c 提取的 3 case (嵌入 switch) ============ */
static void run_case(uint8_t cmd, uint8_t *pkg, uint8_t len)
{
uint8_t _cmd = cmd;
switch (_cmd) {
#include "offlog_cases_embedded.c"
default: break;
}
}
/* ============ 断言 ============ */
static int failures = 0;
#define CHECK(cond) do { \
if (!(cond)) { printf("FAIL %s:%d %s\n", __FILE__, __LINE__, #cond); failures++; } \
} while (0)
static uint8_t pkg[16];
static void test_stat_ok(void)
{
mock_enabled = 1; mock_count = 1234; mock_seq_last = 1333; mock_boot = 2;
memset(tmp_ble_buf, 0, sizeof(tmp_ble_buf));
run_case(0x25, NULL, 0);
CHECK(last_cmd == 0x25);
CHECK(last_len == 19);
/* status=0 */
CHECK(last_dat[0] == 0x00);
/* boot_seq=2 LE */
CHECK(last_dat[1] == 0x02 && last_dat[2] == 0x00);
/* count=1234 LE */
CHECK(last_dat[3] == 0xD2 && last_dat[4] == 0x04 && last_dat[5] == 0x00 && last_dat[6] == 0x00);
/* capacity=16256 LE (W25Q32 512KB: 127 数据扇区 x 128) */
CHECK(last_dat[7] == 0x80 && last_dat[8] == 0x3F && last_dat[9] == 0x00 && last_dat[10] == 0x00);
/* seq_first=100 LE */
CHECK(last_dat[11] == 0x64 && last_dat[12] == 0x00 && last_dat[13] == 0x00 && last_dat[14] == 0x00);
/* seq_last=1333 LE */
CHECK(last_dat[15] == 0x35 && last_dat[16] == 0x05 && last_dat[17] == 0x00 && last_dat[18] == 0x00);
printf("PASS test_stat_ok\n");
}
static void test_stat_disabled(void)
{
mock_enabled = 0;
run_case(0x25, NULL, 0);
CHECK(last_cmd == 0x25);
CHECK(last_len == 1);
CHECK(last_dat[0] == 0x01);
printf("PASS test_stat_disabled\n");
}
static void test_query_ok(void)
{
/* 10 条: seq 11..20, 请求 start_seq=13 count=4 → 返回 seq 13,14,15,16 */
mock_enabled = 1; mock_count = 10; mock_seq_last = 20; mock_boot = 2;
memset(pkg, 0, sizeof(pkg));
pkg[4] = 13; /* start_seq LE */
pkg[5] = 0; pkg[6] = 0; pkg[7] = 0;
pkg[8] = 4; /* count */
memset(tmp_ble_buf, 0, sizeof(tmp_ble_buf));
run_case(0x26, pkg, 11);
CHECK(last_cmd == 0x26);
CHECK(last_len == 2 + 4 * 32); /* status + count + 4×32B */
CHECK(last_dat[0] == 0x00); /* status ok */
CHECK(last_dat[1] == 4); /* fetched 4 */
/* 记录0 (idx=2, seq=13): type=coil (mock: idx%3==2 → COIL), 仅查 magic+seq */
CHECK(last_dat[2] == OFFLOG_EVT_MAGIC);
CHECK(last_dat[6] == 13); /* seq LE32 偏移4 */
CHECK(last_dat[7] == 0);
/* 记录1 (idx=3, seq=14): type=boot */
CHECK(last_dat[2+32+1] == OFFLOG_EVT_BOOT);
CHECK(last_dat[2+32+4] == 14);
/* 记录2 (idx=4, seq=15): type=iot_ready, payload 空 */
CHECK(last_dat[2+64+1] == OFFLOG_EVT_IOT_READY);
CHECK(last_dat[2+64+4] == 15);
/* 记录3 (idx=5, seq=16): type=coil, payload sub=1 ch=1 value=97 */
CHECK(last_dat[2+96+1] == OFFLOG_EVT_COIL);
CHECK(last_dat[2+96+4] == 16);
CHECK(last_dat[2+96+20] == 1); /* payload[0] sub */
CHECK(last_dat[2+96+21] == 1); /* payload[1] ch */
CHECK(last_dat[2+96+25] == 97); /* payload[5] value LSB */
printf("PASS test_query_ok\n");
}
static void test_query_range_error(void)
{
mock_enabled = 1; mock_count = 10; mock_seq_last = 20; mock_boot = 2;
memset(pkg, 0, sizeof(pkg));
pkg[4] = 100; /* 越界 > seq_last */
pkg[8] = 4;
run_case(0x26, pkg, 11);
CHECK(last_cmd == 0x26);
CHECK(last_len == 2);
CHECK(last_dat[0] == 0x00);
CHECK(last_dat[1] == 0); /* 空 records */
printf("PASS test_query_range_error\n");
}
static void test_query_short_frame(void)
{
mock_enabled = 1;
pkg[8] = 4;
run_case(0x26, pkg, 9); /* len < 11 */
CHECK(last_cmd == 0x26);
CHECK(last_len == 1);
CHECK(last_dat[0] == 0x02); /* bad request */
printf("PASS test_query_short_frame\n");
}
static void test_query_disabled(void)
{
mock_enabled = 0;
pkg[8] = 4;
run_case(0x26, pkg, 11);
CHECK(last_cmd == 0x26);
CHECK(last_len == 1);
CHECK(last_dat[0] == 0x01); /* disabled */
printf("PASS test_query_disabled\n");
}
static void test_clear(void)
{
mock_enabled = 1; mock_count = 5; mock_seq_last = 30;
run_case(0x27, NULL, 0);
CHECK(last_cmd == 0x27);
CHECK(last_len == 1);
CHECK(last_dat[0] == 0x00);
/* offlog_clear mock: count 归 1, seq_last 递增 */
CHECK(mock_count == 1);
CHECK(mock_seq_last == 31);
printf("PASS test_clear\n");
}
int main(void)
{
test_stat_ok();
test_stat_disabled();
test_query_ok();
test_query_range_error();
test_query_short_frame();
test_query_disabled();
test_clear();
if (failures == 0) printf("\nALL PASS\n");
else printf("\n%d FAILURES\n", failures);
return failures ? 1 : 0;
}