fix(vd960DBN): BLE 分包粒度动态化 — 修复 offlog_query Too large noti 丢包
- 根因: MAX_BLE_DAT_RESPONSE_LEN=96 写死, MTU 协商 96 后整包 102B > MTU-3=93 peripheralChar4Notify 直接 return 丢第一包, 小程序重组不完整 - peripheral.c: 新增 peripheral_get_mtu() getter - dbn_ble_srv.c: ble_notify_chunk_max() 按 min(MTU-9,94) 动态分包 4 处 MAX_BLE_DAT_RESPONSE_LEN 统一替换 (set_response_buf/to_notify/iot_net/iot_topic) - 消除 BLE_Notify_Buf.buf[100] 写 102B 越界 2B 隐患 - 隔离 C 测试 MTU=23/96/185/517 四组全过, 重组 130B 逐字节一致
This commit is contained in:
@@ -11,6 +11,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "net_srv.h"
|
#include "net_srv.h"
|
||||||
#include "offlog.h"
|
#include "offlog.h"
|
||||||
|
extern uint16_t peripheral_get_mtu(void);
|
||||||
|
|
||||||
uint8_t g_flag_notify_temp = 0; //临时通知notify flag, 0 disable, 1 enable
|
uint8_t g_flag_notify_temp = 0; //临时通知notify flag, 0 disable, 1 enable
|
||||||
|
|
||||||
@@ -181,6 +182,24 @@ static uint8_t set_net_info_to_ready(uint8_t * dat_dst)
|
|||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* =============================================================
|
||||||
|
* ble_notify_chunk_max: max dat bytes per notify packet
|
||||||
|
* follow negotiated MTU to avoid 'Too large noti' drop:
|
||||||
|
* whole pkt = 4B header(magic/header/len/cmd) + dat + 2B ckb
|
||||||
|
* must satisfy whole pkt <= peripheralMTU - 3 (ATT opcode+handle)
|
||||||
|
* and whole pkt <= MAX_BLE_Notify_Buf_LEN (local buf, no overflow)
|
||||||
|
* MTU=23 -> 14, MTU=96 -> 87, MTU>=103 -> 94
|
||||||
|
* =============================================================
|
||||||
|
static uint16_t ble_notify_chunk_max(void)
|
||||||
|
{
|
||||||
|
uint16_t _mtu = peripheral_get_mtu();
|
||||||
|
if (_mtu < 23) _mtu = ATT_MTU_SIZE; /* fallback before negotiation */
|
||||||
|
uint16_t _limit = _mtu - 9; /* pkt limit - header4 - ckb2 */
|
||||||
|
if (_limit > (MAX_BLE_Notify_Buf_LEN - 6))
|
||||||
|
_limit = MAX_BLE_Notify_Buf_LEN - 6;
|
||||||
|
return _limit;
|
||||||
|
}
|
||||||
|
|
||||||
void set_response_iot_net(Buf_DBN_BLE *response_dst)
|
void set_response_iot_net(Buf_DBN_BLE *response_dst)
|
||||||
{ // config iot_net
|
{ // config iot_net
|
||||||
uint8_t ret = 0;
|
uint8_t ret = 0;
|
||||||
@@ -205,11 +224,14 @@ void set_response_iot_net(Buf_DBN_BLE *response_dst)
|
|||||||
memcpy(&(response_dst->dat[i]), iot_net_info.password, strlen(iot_net_info.password));
|
memcpy(&(response_dst->dat[i]), iot_net_info.password, strlen(iot_net_info.password));
|
||||||
i += strlen(iot_net_info.password);
|
i += strlen(iot_net_info.password);
|
||||||
response_dst->dat_len = i;
|
response_dst->dat_len = i;
|
||||||
response_dst->pkg_amount = i / MAX_BLE_DAT_RESPONSE_LEN;
|
{
|
||||||
if((i % MAX_BLE_DAT_RESPONSE_LEN) > 0)
|
uint16_t _chunk = ble_notify_chunk_max();
|
||||||
|
response_dst->pkg_amount = i / _chunk;
|
||||||
|
if((i % _chunk) > 0)
|
||||||
{
|
{
|
||||||
response_dst->pkg_amount += 1;
|
response_dst->pkg_amount += 1;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
response_dst->pkg_seq = 0;
|
response_dst->pkg_seq = 0;
|
||||||
|
|
||||||
response_dst->flag = 1;
|
response_dst->flag = 1;
|
||||||
@@ -232,11 +254,14 @@ void set_response_iot_topic(Buf_DBN_BLE *response_dst)
|
|||||||
memcpy(&(response_dst->dat[i]), g_iot_topic.topic_sub, strlen(g_iot_topic.topic_sub));
|
memcpy(&(response_dst->dat[i]), g_iot_topic.topic_sub, strlen(g_iot_topic.topic_sub));
|
||||||
i += strlen(g_iot_topic.topic_sub);
|
i += strlen(g_iot_topic.topic_sub);
|
||||||
response_dst->dat_len = i;
|
response_dst->dat_len = i;
|
||||||
response_dst->pkg_amount = i / MAX_BLE_DAT_RESPONSE_LEN;
|
{
|
||||||
if((i % MAX_BLE_DAT_RESPONSE_LEN) > 0)
|
uint16_t _chunk = ble_notify_chunk_max();
|
||||||
|
response_dst->pkg_amount = i / _chunk;
|
||||||
|
if((i % _chunk) > 0)
|
||||||
{
|
{
|
||||||
response_dst->pkg_amount += 1;
|
response_dst->pkg_amount += 1;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
response_dst->pkg_seq = 0;
|
response_dst->pkg_seq = 0;
|
||||||
response_dst->flag = 1;
|
response_dst->flag = 1;
|
||||||
}
|
}
|
||||||
@@ -250,8 +275,9 @@ uint8_t set_response_buf(Buf_DBN_BLE *response_dst, uint8_t magic, uint8_t cmd,
|
|||||||
response_dst->magic = magic;
|
response_dst->magic = magic;
|
||||||
response_dst->cmd = cmd;
|
response_dst->cmd = cmd;
|
||||||
|
|
||||||
uint8_t _amount = dat_len / MAX_BLE_DAT_RESPONSE_LEN;
|
uint16_t _chunk = ble_notify_chunk_max();
|
||||||
if((dat_len % MAX_BLE_DAT_RESPONSE_LEN) > 0)
|
uint8_t _amount = dat_len / _chunk;
|
||||||
|
if((dat_len % _chunk) > 0)
|
||||||
{
|
{
|
||||||
_amount++;
|
_amount++;
|
||||||
}
|
}
|
||||||
@@ -369,9 +395,12 @@ uint8_t set_response_to_notify(Buf_DBN_BLE *response_ori, BLE_Notify_Buf * notif
|
|||||||
uint8_t _pkg_amount = response_ori->pkg_amount;
|
uint8_t _pkg_amount = response_ori->pkg_amount;
|
||||||
uint8_t _pkg_seq = response_ori->pkg_seq;
|
uint8_t _pkg_seq = response_ori->pkg_seq;
|
||||||
uint8_t _remain_len = response_ori->dat_len - response_ori->dat_offset;
|
uint8_t _remain_len = response_ori->dat_len - response_ori->dat_offset;
|
||||||
if(_remain_len > MAX_BLE_DAT_RESPONSE_LEN)
|
|
||||||
{
|
{
|
||||||
_remain_len = MAX_BLE_DAT_RESPONSE_LEN;
|
uint16_t _chunk = ble_notify_chunk_max();
|
||||||
|
if(_remain_len > _chunk)
|
||||||
|
{
|
||||||
|
_remain_len = (uint8_t)_chunk;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_pkg_seq += 1;
|
_pkg_seq += 1;
|
||||||
notify_dst->buf[1] = (_pkg_amount << 4)|(_pkg_seq);
|
notify_dst->buf[1] = (_pkg_amount << 4)|(_pkg_seq);
|
||||||
|
|||||||
@@ -147,6 +147,11 @@ static uint8_t attDeviceName[GAP_DEVICE_NAME_LEN] = "DLD960GA"; // "Simple Perip
|
|||||||
static peripheralConnItem_t peripheralConnList;
|
static peripheralConnItem_t peripheralConnList;
|
||||||
|
|
||||||
static uint16_t peripheralMTU = ATT_MTU_SIZE;
|
static uint16_t peripheralMTU = ATT_MTU_SIZE;
|
||||||
|
/* getter for dbn_ble_srv.c: dynamic notify chunk by negotiated MTU */
|
||||||
|
uint16_t peripheral_get_mtu(void)
|
||||||
|
{
|
||||||
|
return peripheralMTU;
|
||||||
|
}
|
||||||
/*********************************************************************
|
/*********************************************************************
|
||||||
* LOCAL FUNCTIONS
|
* LOCAL FUNCTIONS
|
||||||
*/
|
*/
|
||||||
@@ -703,7 +708,7 @@ static void peripheralChar4Notify(uint8_t *pValue, uint16_t len)
|
|||||||
attHandleValueNoti_t noti;
|
attHandleValueNoti_t noti;
|
||||||
if(len > (peripheralMTU - 3))
|
if(len > (peripheralMTU - 3))
|
||||||
{
|
{
|
||||||
PRINT("Too large noti\n");
|
PRINT("Too large noti, len:%d, peripheralMTU:%d\n", len, peripheralMTU);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
noti.len = len;
|
noti.len = len;
|
||||||
|
|||||||
@@ -6,6 +6,68 @@
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## 2026-08-12 — BLE 分包粒度动态化修复(Too large noti 丢包)
|
||||||
|
|
||||||
|
### 背景
|
||||||
|
|
||||||
|
`CMD_DBN_OFFLOG_QUERY` 拉取 4 条日志时响应 dat=130B,`set_response_buf` 按 **写死的 `MAX_BLE_DAT_RESPONSE_LEN=96`** 分包:第一包 = 帧头4 + dat96 + ckb2 = **102B**。而小程序把 MTU 协商到 96 后,ATT 通知 payload 上限 = 96-3 = **93B**,`peripheralChar4Notify` 判定 `102 > 93` → **"Too large noti" 直接 return,第一包永久丢失**,小程序重组永远不完整(只收到第二包 34B)。
|
||||||
|
|
||||||
|
现场日志证据:
|
||||||
|
|
||||||
|
```
|
||||||
|
BLE: offlog_query start_seq=1 req=4 fetched=4
|
||||||
|
Too large noti, len:102, peripheralMTU:96
|
||||||
|
```
|
||||||
|
|
||||||
|
### 根因链
|
||||||
|
|
||||||
|
| # | 环节 | 问题 |
|
||||||
|
|---|------|------|
|
||||||
|
| 1 | `BLE_BUFF_MAX_LEN=100` (config.h) | `MAX_BLE_DAT_RESPONSE_LEN = 100-4 = 96` 分包块大小**写死** |
|
||||||
|
| 2 | 分包粒度不随协商 MTU 变化 | MTU 协商到 96 后,每包 96B dat 必然超 93B 上限 |
|
||||||
|
| 3 | `BLE_Notify_Buf.buf[100]` | `set_response_to_notify` 写 102B → **越界 2B**(UB,可能踩坏相邻 `g_flag_notify_temp`/`g_buf_ble_response`) |
|
||||||
|
| 4 | `peripheralChar4Notify` 超限 return | 丢包无重传,小程序重组永久不完整 |
|
||||||
|
|
||||||
|
> 2026-08-10 日志中"响应超 96B 自动分包(既有机制)"的假设不成立:分包机制存在但**粒度没跟随协商 MTU**。
|
||||||
|
|
||||||
|
### 修复:`ble_notify_chunk_max()` 动态分包
|
||||||
|
|
||||||
|
```c
|
||||||
|
/* 整包 = 帧头4(magic/header/len/cmd) + dat + ckb2
|
||||||
|
须满足 整包 <= peripheralMTU - 3 (ATT opcode+handle)
|
||||||
|
且 整包 <= MAX_BLE_Notify_Buf_LEN (本地缓冲防越界)
|
||||||
|
MTU=23 -> 14, MTU=96 -> 87, MTU>=103 -> 94 */
|
||||||
|
static uint16_t ble_notify_chunk_max(void)
|
||||||
|
{
|
||||||
|
uint16_t _mtu = peripheral_get_mtu();
|
||||||
|
if (_mtu < 23) _mtu = ATT_MTU_SIZE; /* 未协商兜底 */
|
||||||
|
uint16_t _limit = _mtu - 9; /* 整包上限-帧头4-ckb2 */
|
||||||
|
if (_limit > (MAX_BLE_Notify_Buf_LEN - 6))
|
||||||
|
_limit = MAX_BLE_Notify_Buf_LEN - 6;
|
||||||
|
return _limit;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
改动文件(GBK+CRLF,全部 Python 二进制替换):
|
||||||
|
|
||||||
|
| 文件 | 改动 |
|
||||||
|
|------|------|
|
||||||
|
| `peripheral.c` | 新增 `peripheral_get_mtu()` getter(peripheralMTU 是 static) |
|
||||||
|
| `dbn_ble_srv.c` | 新增 `ble_notify_chunk_max()`;`set_response_buf` / `set_response_to_notify` / `set_response_iot_net` / `set_response_iot_topic` 四处 `MAX_BLE_DAT_RESPONSE_LEN` 全部改用动态 chunk(组包包数与实际切包必须同一粒度,否则 pkg_amount 错乱) |
|
||||||
|
|
||||||
|
### 验证
|
||||||
|
|
||||||
|
- 隔离 C 测试(真实函数体 + mock `peripheral_get_mtu`):MTU=23/96/185/517 四组,每组验证 chunk 上限、单包 ≤ MTU-3、单包 ≤ 100B 缓冲、帧结构一致、seq 递增、**重组 130B 完整且逐字节一致**,全部 PASS
|
||||||
|
- MTU=96 时:2 包(93B + 49B)✓;MTU=185 时:2 包(100B + 42B)✓;MTU=23 未协商时降级 10 包(每包 20B,pkg_amount=10 ≤ header 高4位上限15)
|
||||||
|
- 顺带消除 `g_notify_buftemp.buf[100]` 越界 2B 隐患
|
||||||
|
- 待板级验证:MRS 真编译 + 真机小程序 QUERY 拉 4 条日志(本地无 RISC-V 工具链)
|
||||||
|
|
||||||
|
### 小程序端(可选优化,非必须)
|
||||||
|
|
||||||
|
- Android 可在连接后 `wx.setBLEMTU({mtu: 185})`,分包粒度升到 94B/包,减少包数;iOS 系统自动协商,固件已自适应,不调也能正常拉取
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## 2026-08-10 — BLE 读取脱机日志接口 (OFFLOG_STAT/QUERY/CLEAR)
|
## 2026-08-10 — BLE 读取脱机日志接口 (OFFLOG_STAT/QUERY/CLEAR)
|
||||||
|
|
||||||
### 背景
|
### 背景
|
||||||
|
|||||||
Reference in New Issue
Block a user