feat: 启用 BLE 5.0 2M PHY 图传加速 + 移除未使用的 BluFi 组件 + BLE 断连内存泄漏修复
1、dzbj_ble.c 新增 BLE 5.0 2M PHY 请求(连接时自动协商,不支持则回退 1M); 2、dzbj_ble.c 新增 PHY 更新事件日志(tx_phy/rx_phy: 1=1M, 2=2M, 3=Coded); 3、dzbj_ble.c 断连时清理未完成的图片传输状态,释放 img_data/filepath/file_img 防止内存泄漏; 4、移除未使用的 BluFi 组件依赖(Kconfig select、编译检查、sdkconfig),解除与 BLE 5.0 的兼容冲突; 5、sdkconfig.defaults 及生产环境配置统一启用 BLE 5.0 + 保留 BLE 4.2 legacy advertising 兼容; 6、新增 BLE 图片传输问题分析与优化建议文档(含 UniApp vs Flutter 对比分析,供 APP 开发者参考); Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
af58123d66
commit
4e2f6906f9
2
.gitignore
vendored
2
.gitignore
vendored
@ -5,7 +5,7 @@
|
||||
|
||||
# 忽略根目录下的uniapp_code文件夹(这是APP端的业务)
|
||||
/uniapp_code
|
||||
|
||||
/Linux驱动开发
|
||||
|
||||
# 忽略 macOS 系统文件
|
||||
.DS_Store
|
||||
|
||||
1428
05-最新日志.txt
1428
05-最新日志.txt
File diff suppressed because it is too large
Load Diff
695
BLE图片传输问题分析与优化建议.md
Normal file
695
BLE图片传输问题分析与优化建议.md
Normal file
@ -0,0 +1,695 @@
|
||||
# BLE 图片传输失败分析与优化建议
|
||||
|
||||
## 一、问题现象
|
||||
|
||||
APP 通过 BLE 向设备传输一张 533934 字节(约 521KB)的 JPEG 图片,传输过程中 BLE 连接断开,图片未完整接收,设备屏幕未更新。
|
||||
|
||||
---
|
||||
|
||||
## 二、双端日志对照分析
|
||||
|
||||
### 2.1 APP 端日志(Flutter Web)
|
||||
|
||||
```
|
||||
[BLE Transfer] MTU 协商失败,使用默认值: FlutterBluePlusException | requestMtu | fbp-code: 2 | android-only
|
||||
[BLE Transfer] MTU=512, chunkSize=507
|
||||
[BLE Transfer] 服务: 0b00
|
||||
[BLE Transfer] 特征: 0b01 (write + writeWithoutResponse)
|
||||
[BLE Transfer] 特征: 0b02 (write + writeWithoutResponse)
|
||||
[BLE Transfer] JPEG 大小: 533934 字节
|
||||
[FBP] stopScan: already stopped
|
||||
(以上日志重复出现两次 —— APP 进行了两次连接尝试)
|
||||
```
|
||||
|
||||
### 2.2 设备端日志(ESP32-S3)
|
||||
|
||||
```
|
||||
I (14939) DZBJ_BLE: Connected, conn_id 0, remote 9c:76:0e:47:1b:de
|
||||
I (15959) DZBJ_BLE: 处理前序数据
|
||||
I (15959) DZBJ_BLE: 图片数据长度:533934
|
||||
I (16069) DZBJ_BLE: 传输通道建立成功,文件名称:face_1774336190.jpg,文件大小:533934
|
||||
I (16069) DZBJ_BLE: 获取到数据:第:1包,长度:509,是否结束:0
|
||||
I (19169) DZBJ_BLE: 获取到数据:第:101包,长度:509,是否结束:0 ← 3秒收100包
|
||||
I (23309) DZBJ_BLE: 获取到数据:第:201包,长度:509,是否结束:0 ← 4秒收100包
|
||||
I (25379) DZBJ_BLE: 获取到数据:第:1包,长度:509,是否结束:0 ← 包序号溢出*
|
||||
W (26369) BT_HCI: hcif disc complete: hdl 0x1, rsn 0x13 dev_find 1
|
||||
I (26369) DZBJ_BLE: Disconnected, reason 0x13 ← APP主动断开
|
||||
```
|
||||
|
||||
> *注:包序号字段为 `uint8_t`(0~255),第 256 包时溢出回到 0,日志显示为"第1包"。**传输本身未中断,仅是日志显示溢出**。设备端后续会修复此日志。
|
||||
|
||||
### 2.3 时间线还原
|
||||
|
||||
| 时间点 | 事件 | 说明 |
|
||||
|--------|------|------|
|
||||
| T+0s | BLE 连接建立 | MTU=512 生效 |
|
||||
| T+1s | 前序数据解析 | 文件名 + 文件大小 |
|
||||
| T+1.1s | 传输开始 | chunkSize=507 字节/包 |
|
||||
| T+1.1s ~ T+9.3s | 数据传输中 | 约收到 300 包 ≈ 150KB |
|
||||
| **T+10.3s** | **APP 断开连接** | reason 0x13 = Remote User Terminated |
|
||||
| - | 无"传输完成"日志 | 图片未保存,屏幕未更新 |
|
||||
|
||||
### 2.4 传输进度估算
|
||||
|
||||
- 需要总包数:533934 ÷ 505(每包纯数据) ≈ **1058 包**
|
||||
- 实际传输时间:约 10 秒
|
||||
- 已接收约:300~400 包(150KB~200KB)
|
||||
- **完成度:约 30%**
|
||||
|
||||
---
|
||||
|
||||
## 三、问题根因
|
||||
|
||||
### 3.1 核心原因:WriteWithoutResponse 无流控导致 BLE 缓冲区溢出
|
||||
|
||||
APP 使用 `writeWithoutResponse` 模式连续发送 1058 个数据包,此模式特点:
|
||||
|
||||
- **不等待设备端 ACK**,发送速度完全由 APP 端控制
|
||||
- ESP32-S3 的 BLE 协议栈有内部缓冲区(Bluedroid TX buffer),连续高速写入导致缓冲区积压
|
||||
- 当缓冲区满且链路层来不及发送时,**底层协议栈会主动断开连接**
|
||||
- BLE 规范中 WriteWithoutResponse 没有流控机制,必须由应用层自行控制节奏
|
||||
|
||||
### 3.2 次要原因:Flutter Web 环境 BLE 限制
|
||||
|
||||
- `js_primitives.dart` 表明 APP 运行在 **Flutter Web**(浏览器)环境
|
||||
- Web Bluetooth API 的 `requestMtu` 不可用(Android-only API),MTU 由浏览器自动协商
|
||||
- Web Bluetooth 的写入吞吐量和稳定性**显著低于** Android/iOS 原生 BLE
|
||||
- 浏览器对 BLE 操作有隐式超时和安全限制
|
||||
|
||||
### 3.3 APP 连接了两次
|
||||
|
||||
APP 日志出现两组完整的服务发现记录,但设备端只有一次连接/断连,可能原因:
|
||||
- 第一次连接极短(未成功开始传输),设备端未触发 CONNECT_EVT
|
||||
- 或第一次只完成了服务发现就断开,第二次才开始数据传输
|
||||
|
||||
---
|
||||
|
||||
## 四、APP 端优化建议
|
||||
|
||||
### 4.1 【P0 - 必须修复】添加发送流控
|
||||
|
||||
这是导致传输失败的直接原因,**必须修复**。
|
||||
|
||||
#### 方案 A:混合写入模式(推荐,改动最小)
|
||||
|
||||
每 N 包使用一次 `write`(带响应)作为同步点,其余用 `writeWithoutResponse`:
|
||||
|
||||
```dart
|
||||
const int SYNC_INTERVAL = 10; // 每 10 包同步一次
|
||||
|
||||
for (var i = 0; i < chunks.length; i++) {
|
||||
if (i % SYNC_INTERVAL == 0) {
|
||||
// 带响应写入:等待设备端 ACK,天然起到流控作用
|
||||
await characteristic.write(chunks[i], withoutResponse: false);
|
||||
} else {
|
||||
// 无响应写入:速度快
|
||||
await characteristic.write(chunks[i], withoutResponse: true);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**原理**:`write`(withoutResponse: false)会等待设备端 GATT 层 ACK,这个等待天然给设备端缓冲区消化数据的时间,避免溢出。
|
||||
|
||||
#### 方案 B:固定间隔延迟
|
||||
|
||||
如果不想用混合模式,在每批包之间加短延迟:
|
||||
|
||||
```dart
|
||||
for (var i = 0; i < chunks.length; i++) {
|
||||
await characteristic.write(chunks[i], withoutResponse: true);
|
||||
// 每 20 包暂停一下,让设备端消化缓冲区
|
||||
if (i % 20 == 0) {
|
||||
await Future.delayed(Duration(milliseconds: 10));
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 方案 C:基于 FlutterBluePlus 队列深度控制
|
||||
|
||||
FlutterBluePlus 3.x+ 支持写入队列管理:
|
||||
|
||||
```dart
|
||||
// 限制最大并发写入数,防止缓冲区溢出
|
||||
FlutterBluePlus.setWriteQueueSize(maxConcurrent: 5);
|
||||
```
|
||||
|
||||
### 4.2 【P0 - 必须修复】添加断连检测与错误处理
|
||||
|
||||
当前 APP 在传输中断后没有任何错误反馈,用户不知道发生了什么:
|
||||
|
||||
```dart
|
||||
// 监听连接状态变化
|
||||
device.connectionState.listen((state) {
|
||||
if (state == BluetoothConnectionState.disconnected) {
|
||||
if (transferInProgress) {
|
||||
showError("传输中断,已发送 ${sentBytes}/${totalBytes} 字节,请重试");
|
||||
transferInProgress = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 传输函数中添加异常捕获
|
||||
Future<void> transferImage(List<int> imageData) async {
|
||||
try {
|
||||
transferInProgress = true;
|
||||
for (var i = 0; i < chunks.length; i++) {
|
||||
if (!device.isConnected) {
|
||||
throw Exception("BLE 连接断开,传输中止于第 $i/${chunks.length} 包");
|
||||
}
|
||||
await characteristic.write(chunks[i], withoutResponse: i % 10 != 0);
|
||||
sentBytes = i * chunkSize;
|
||||
}
|
||||
transferInProgress = false;
|
||||
} catch (e) {
|
||||
transferInProgress = false;
|
||||
log("[BLE Transfer] 传输失败: $e");
|
||||
rethrow; // 向上层抛出,由 UI 处理
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4.3 【P1 - 建议修复】断连自动重试
|
||||
|
||||
```dart
|
||||
const int MAX_RETRIES = 3;
|
||||
|
||||
Future<bool> transferWithRetry(List<int> imageData) async {
|
||||
for (var attempt = 0; attempt < MAX_RETRIES; attempt++) {
|
||||
try {
|
||||
if (!device.isConnected) {
|
||||
await device.connect(timeout: Duration(seconds: 10));
|
||||
await device.discoverServices();
|
||||
}
|
||||
await transferImage(imageData);
|
||||
return true; // 传输成功
|
||||
} catch (e) {
|
||||
log("[BLE Transfer] 第 ${attempt + 1} 次尝试失败: $e");
|
||||
await device.disconnect();
|
||||
await Future.delayed(Duration(seconds: 2)); // 等待后重试
|
||||
}
|
||||
}
|
||||
return false; // 全部重试失败
|
||||
}
|
||||
```
|
||||
|
||||
### 4.4 【P1 - 建议修复】Flutter Web 平台适配
|
||||
|
||||
Web Bluetooth 吞吐量低于原生 BLE,需要更保守的传输策略:
|
||||
|
||||
```dart
|
||||
import 'package:flutter/foundation.dart' show kIsWeb;
|
||||
|
||||
// 根据平台调整传输参数
|
||||
int getSyncInterval() {
|
||||
if (kIsWeb) {
|
||||
return 5; // Web 环境:每 5 包同步一次(更保守)
|
||||
} else {
|
||||
return 15; // Native 环境:每 15 包同步一次
|
||||
}
|
||||
}
|
||||
|
||||
// Web 端建议同时降低传输并发
|
||||
int getChunkBatchSize() {
|
||||
if (kIsWeb) {
|
||||
return 10; // Web:每批 10 包 + 10ms 间隔
|
||||
} else {
|
||||
return 30; // Native:每批 30 包
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4.5 【P2 - 可选优化】传输进度 UI
|
||||
|
||||
```dart
|
||||
Future<void> transferImage(
|
||||
List<int> imageData, {
|
||||
void Function(double progress)? onProgress,
|
||||
}) async {
|
||||
final chunks = splitIntoChunks(imageData, chunkSize);
|
||||
for (var i = 0; i < chunks.length; i++) {
|
||||
await characteristic.write(chunks[i], withoutResponse: i % 10 != 0);
|
||||
onProgress?.call((i + 1) / chunks.length);
|
||||
}
|
||||
}
|
||||
|
||||
// UI 层调用
|
||||
transferImage(jpegData, onProgress: (progress) {
|
||||
setState(() => transferProgress = progress); // 0.0 ~ 1.0
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 五、BLE 图传协议参考
|
||||
|
||||
### 5.1 协议格式
|
||||
|
||||
#### 前序包(第一包,建立传输通道)
|
||||
|
||||
写入特征:`0x0B01`
|
||||
|
||||
| 偏移 | 长度 | 字段 | 说明 |
|
||||
|------|------|------|------|
|
||||
| 0 | 1 | type | 固定 `0xFD` 表示图片传输 |
|
||||
| 1 | 22 | filename | 文件名(UTF-8,'\0'填充) |
|
||||
| 23 | 3 | length | 文件总大小(大端序,3字节) |
|
||||
|
||||
#### 数据包(后续包)
|
||||
|
||||
写入特征:`0x0B01`
|
||||
|
||||
| 偏移 | 长度 | 字段 | 说明 |
|
||||
|------|------|------|------|
|
||||
| 0 | 1 | pkt_no | 包序号(0~255 循环,仅用于日志) |
|
||||
| 1 | 1 | isEnd | 0=继续传输, 1=最后一包 |
|
||||
| 2 | N | data | 图片数据(N = chunkSize - 2 = 505 字节) |
|
||||
|
||||
#### 图片编辑命令
|
||||
|
||||
写入特征:`0x0B02`
|
||||
|
||||
| 类型字节(末字节) | 说明 |
|
||||
|----------|------|
|
||||
| `0xFF` | 切换显示指定图片(payload 前 22 字节为文件名) |
|
||||
| `0xF1` | 删除指定图片 |
|
||||
|
||||
### 5.2 MTU 与包大小关系
|
||||
|
||||
```
|
||||
协商 MTU = 512
|
||||
ATT Header = 3 字节
|
||||
GATT Write Header = 2 字节(attribute handle)
|
||||
─────────────────────────
|
||||
可用 Payload = 512 - 3 - 2 = 507 字节(即 chunkSize)
|
||||
数据包头 = 2 字节(pkt_no + isEnd)
|
||||
每包纯图片数据 = 507 - 2 = 505 字节
|
||||
```
|
||||
|
||||
### 5.3 传输耗时预估
|
||||
|
||||
基于连接间隔 7.5~20ms(设备端配置 min_int=6, max_int=16),加入方案 A 流控后:
|
||||
|
||||
| 图片大小 | 总包数 | 无流控(当前) | 方案A 流控后预估 |
|
||||
|----------|--------|---------------|-----------------|
|
||||
| 100KB | ~203 | ~2s(可能断连) | ~4s |
|
||||
| 300KB | ~608 | ~6s(可能断连) | ~12s |
|
||||
| 500KB | ~1013 | ~10s(大概率断连) | ~20s |
|
||||
| 1MB | ~2026 | 必定断连 | ~40s |
|
||||
|
||||
---
|
||||
|
||||
## 六、设备端已完成的修复
|
||||
|
||||
以下问题已在最新固件中修复:
|
||||
|
||||
| 问题 | 影响 | 修复状态 |
|
||||
|------|------|----------|
|
||||
| BLE 断连后未清理传输状态 | `img_data` 内存泄漏,`SendStatus.isSend` 残留 | ✅ 已修复:`DISCONNECT_EVT` 中自动释放资源 |
|
||||
| BLE 5.0 2M PHY 未启用 | 传输速度只有 1M PHY | ✅ 已启用:连接后自动协商 2M PHY,速度翻倍 |
|
||||
| 未使用的 BluFi 组件占用编译资源 | 与 BLE 5.0 不兼容 | ✅ 已移除:两种模式均使用自定义 GATT Server |
|
||||
|
||||
---
|
||||
|
||||
## 七、测试验证清单
|
||||
|
||||
完成 APP 端优化后,请按以下步骤验证:
|
||||
|
||||
- [ ] **小图测试**:传输 50KB 图片,确认完整接收并显示
|
||||
- [ ] **大图测试**:传输 500KB+ 图片,确认不中途断连
|
||||
- [ ] **连续测试**:连续传 3~5 张图片,每次都成功
|
||||
- [ ] **弱信号测试**:手机距设备 3~5 米,测试传输稳定性
|
||||
- [ ] **Web 端测试**:在 Chrome 浏览器中完成上述全部测试
|
||||
- [ ] **断连恢复测试**:传输中手动关闭蓝牙再打开,确认 APP 能正确提示并重试
|
||||
|
||||
### 传输成功的设备端日志标志
|
||||
|
||||
```
|
||||
I DZBJ_BLE: 传输通道建立成功,文件名称:xxx.jpg,文件大小:533934
|
||||
I DZBJ_BLE: 获取到数据:第:101包,长度:509,是否结束:0
|
||||
I DZBJ_BLE: 获取到数据:第:201包,长度:509,是否结束:0
|
||||
...(中间持续接收)
|
||||
I DZBJ_BLE: 数据接收完毕,累计:533934字节,预期:533934字节 ← 累计 = 预期
|
||||
I DZBJ_BLE: 图片接收成功,数据直通显示(533934字节) ← 屏幕更新触发
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 八、BLE 5.0 2M PHY 已启用(设备端已完成)
|
||||
|
||||
设备端固件已启用 BLE 5.0 2M PHY,**APP 端无需任何修改**,PHY 协商在 BLE 链路层自动完成,对 GATT 操作完全透明。
|
||||
|
||||
### 8.1 设备端日志确认
|
||||
|
||||
```
|
||||
I BLE_INIT: Feature Config, ADV:1, BLE_50:1, ... ← BLE 5.0 已启用
|
||||
I DZBJ_BLE: Connected, conn_id 0, remote 73:8f:af:0d:36:7a
|
||||
I DZBJ_BLE: PHY update, status 0, tx_phy 1, rx_phy 1 ← 初始 1M PHY
|
||||
I DZBJ_BLE: PHY update, status 0, tx_phy 2, rx_phy 2 ← 自动切换到 2M PHY ✅
|
||||
```
|
||||
|
||||
### 8.2 速度对比
|
||||
|
||||
| PHY 模式 | 物理层速率 | 实际应用层吞吐量 | 533KB 图片预估耗时 |
|
||||
|----------|-----------|-----------------|-------------------|
|
||||
| 1M PHY(旧固件) | 1 Mbps | ~100-200 KB/s | ~3-5s |
|
||||
| **2M PHY(当前固件)** | **2 Mbps** | **~200-350 KB/s** | **~1.5-2.5s** |
|
||||
|
||||
### 8.3 兼容性
|
||||
|
||||
- 手机支持 BLE 5.0(2017 年后主流机型):自动协商 2M PHY,速度翻倍
|
||||
- 手机不支持 BLE 5.0:自动保持 1M PHY,不报错,功能不受影响
|
||||
- APP 端 FlutterBluePlus 的 `write` / `writeWithoutResponse` 调用方式完全不变
|
||||
|
||||
---
|
||||
|
||||
## 九、【P0 关键问题】Flutter APP 无法连接电子吧唧模式
|
||||
|
||||
### 9.1 问题现象
|
||||
|
||||
Flutter APP 在电子吧唧模式下可以扫描到设备,**BLE 连接成功,但约 3 秒后 APP 主动断开**,无法进行图片传输。而在 AI 对话模式下,同一 APP 可以正常连接和蓝牙配网。
|
||||
|
||||
### 9.2 设备端日志分析(设备端完全正常)
|
||||
|
||||
```
|
||||
I (14509) DZBJ_BLE: Connected, conn_id 0, remote 73:8f:af:0d:36:7a ← 连接成功 ✅
|
||||
I (14539) DZBJ_BLE: PHY update, status 0, tx_phy 1, rx_phy 1 ← PHY 初始化 ✅
|
||||
I (14879) DZBJ_BLE: Connection params update, conn_int 12 ← 参数协商 ✅
|
||||
I (15039) DZBJ_BLE: Connection params update, conn_int 6 ← 参数协商 ✅
|
||||
I (16329) DZBJ_BLE: PHY update, status 0, tx_phy 2, rx_phy 2 ← 2M PHY 切换 ✅
|
||||
W (17429) BT_HCI: hcif disc complete: rsn 0x13 ← APP 主动断开 ❌
|
||||
I (17429) DZBJ_BLE: Disconnected, reason 0x13
|
||||
```
|
||||
|
||||
**设备端没有任何错误**。BLE 连接正常建立,参数协商正常,PHY 成功切换到 2M。是 APP 端在连接后约 3 秒主动断开了连接(reason 0x13 = Remote User Terminated Connection)。
|
||||
|
||||
### 9.3 APP 端日志分析
|
||||
|
||||
```
|
||||
[BLE Transfer] MTU 协商失败,使用默认值: FlutterBluePlusException | requestMtu | fbp-code: 2 | android-only
|
||||
[BLE Transfer] MTU=512, chunkSize=507
|
||||
[BLE Transfer] 服务: 0b00
|
||||
[BLE Transfer] 特征: 0b01 (write + writeWithoutResponse)
|
||||
[BLE Transfer] 特征: 0b02 (write + writeWithoutResponse)
|
||||
[BLE Transfer] JPEG 大小: 533934 字节
|
||||
(以上日志重复出现两次 —— APP 进行了两次连接尝试)
|
||||
```
|
||||
|
||||
APP 日志显示:
|
||||
1. MTU 协商失败(`fbp-code: 2, android-only` 表明 `requestMtu` 在非 Android 平台不可用)
|
||||
2. 服务和特征**已成功发现**(0x0B00 服务、0x0B01/0x0B02 特征)
|
||||
3. 整个流程重复了两次(两次连接尝试都失败)
|
||||
|
||||
### 9.4 根因分析
|
||||
|
||||
APP 连接后能发现服务和特征,但仍然断开,可能的原因:
|
||||
|
||||
#### 原因 1:MTU 协商失败导致后续写入异常
|
||||
|
||||
`requestMtu` 失败后,APP 代码中 `MTU=512, chunkSize=507` 是写死的回退值。如果实际系统 MTU 远小于 512(某些平台默认 MTU=23),每包发送 509 字节(2字节ATT头 + 507 数据)会超出实际 MTU,**导致 BLE 协议栈直接丢包或报错**。
|
||||
|
||||
**修复方案**:MTU 协商失败时,应使用系统默认 MTU 或通过平台 API 获取实际值,而非写死 512。
|
||||
|
||||
```dart
|
||||
try {
|
||||
await device.requestMtu(512);
|
||||
} catch (e) {
|
||||
print('MTU 协商失败: $e');
|
||||
}
|
||||
// 关键:无论 requestMtu 是否成功,都从系统获取实际 MTU
|
||||
final actualMtu = await device.mtu.first; // 获取实际协商的 MTU
|
||||
final chunkSize = actualMtu - 3; // ATT 头部 3 字节
|
||||
print('实际 MTU: $actualMtu, chunkSize: $chunkSize');
|
||||
```
|
||||
|
||||
#### 原因 2:连接后流程异常导致超时断开
|
||||
|
||||
APP 可能在 MTU 协商失败后进入了错误处理分支,没有继续执行图片传输,等待超时后断开。
|
||||
|
||||
**排查方法**:在 Flutter 代码中检查 `requestMtu` 失败后是否有 `return` 或异常抛出中断了后续的 `discoverServices` / `write` 流程。
|
||||
|
||||
**修复方案**:确保 `requestMtu` 失败不会中断主流程。
|
||||
|
||||
```dart
|
||||
Future<void> connectAndTransfer(BluetoothDevice device) async {
|
||||
await device.connect();
|
||||
|
||||
// MTU 协商(失败不影响后续流程)
|
||||
try {
|
||||
await device.requestMtu(512);
|
||||
} catch (e) {
|
||||
print('MTU 协商失败,使用默认值: $e');
|
||||
// ✅ 不要 return 或 throw,继续执行
|
||||
}
|
||||
|
||||
// 服务发现(必须执行)
|
||||
final services = await device.discoverServices();
|
||||
final imageService = services.firstWhere(
|
||||
(s) => s.uuid.toString().contains('0b00'),
|
||||
orElse: () => throw Exception('未找到图传服务 0x0B00'),
|
||||
);
|
||||
|
||||
// 获取特征
|
||||
final writeChar = imageService.characteristics.firstWhere(
|
||||
(c) => c.uuid.toString().contains('0b01'),
|
||||
);
|
||||
|
||||
// 开始传输...
|
||||
await transferImage(writeChar, imageData);
|
||||
}
|
||||
```
|
||||
|
||||
#### 原因 3:APP 连接了两次
|
||||
|
||||
日志显示完整的连接流程重复出现两次。第一次连接可能在写入数据时失败,APP 重试了一次但结果相同。
|
||||
|
||||
**排查方法**:检查 APP 中是否有自动重连/重试逻辑,以及第一次连接失败时的具体错误信息。
|
||||
|
||||
### 9.5 两种模式 BLE 服务对比
|
||||
|
||||
APP 需要支持连接两种模式的 BLE 服务,它们的差异:
|
||||
|
||||
| 维度 | AI 对话模式(配网) | 电子吧唧模式(图传) |
|
||||
|------|-------------------|-------------------|
|
||||
| 服务 UUID | `0xABF0` | `0x0B00` |
|
||||
| 写入特征 | `0xABF1` (Write) | `0x0B01` (Write + WriteNoResponse) |
|
||||
| 通知特征 | `0xABF2` (Notify) | `0x0B02` (Write,非 Notify) |
|
||||
| 设备名称 | `Airhub_xx:xx:xx:xx:xx:xx` | `Airhub_xx:xx:xx:xx:xx:xx`(相同) |
|
||||
| 广播标识 | 扫描响应含 `ABF0` UUID | 扫描响应含厂商数据 `LDdzbj` + `0B00` UUID |
|
||||
| 协议格式 | 二进制命令(1字节CMD + payload) | 二进制帧(前序帧 + 数据帧,见第五章) |
|
||||
|
||||
**APP 端区分两种模式的方法**:
|
||||
- 扫描响应(Scan Response)中的厂商数据包含 ASCII `"dzbj"` → 电子吧唧模式
|
||||
- 连接后发现服务 `0x0B00` → 图传模式;发现服务 `0xABF0` → 配网模式
|
||||
- 两种模式不会同时存在(设备重启切换),APP 只需按发现的服务 UUID 走对应流程
|
||||
|
||||
### 9.6 APP 端自查清单
|
||||
|
||||
请 Flutter APP 开发者按以下顺序排查:
|
||||
|
||||
- [ ] `requestMtu(512)` 失败后,是否 `return` / `throw` 中断了后续流程?
|
||||
- [ ] `requestMtu` 失败后,`chunkSize` 是否仍为 507?实际 MTU 是否支持这个大小?
|
||||
- [ ] `discoverServices()` 是否在 `requestMtu` 之后执行?是否能找到 `0x0B00` 服务?
|
||||
- [ ] 写入特征时使用 `writeWithoutResponse` 还是 `write`?是否有流控/节流机制?
|
||||
- [ ] 连接断开时是否有更详细的错误日志(FlutterBluePlus 的 `onConnectionStateChanged`)?
|
||||
- [ ] 两次连接尝试之间是否有足够的间隔(建议 2 秒以上)?
|
||||
|
||||
---
|
||||
|
||||
## 十、UniApp 成功 vs Flutter 失败——对比分析
|
||||
|
||||
UniApp 测试 APP 可以正常连接电子吧唧模式并成功传输图片,而 Flutter 正式 APP 连接后约 3 秒断开。以下是两者 BLE 实现的关键差异分析。
|
||||
|
||||
### 10.1 连接流程对比
|
||||
|
||||
| 步骤 | UniApp(成功) | Flutter(失败) |
|
||||
|------|--------------|----------------|
|
||||
| **BLE 连接** | `uni.createBLEConnection()` 原生 API | `device.connect()` FlutterBluePlus |
|
||||
| **MTU 协商** | `uni.setBLEMTU({mtu:512})`,失败仅 log 不中断 | `device.requestMtu(512)` 抛异常 `android-only` |
|
||||
| **MTU 失败处理** | 成功 → `getBleService()`;失败 → 仅打印日志,**不中断流程** | 异常后 `chunkSize` 写死 507,**可能中断后续流程** |
|
||||
| **服务发现** | `uni.getBLEDeviceServices()` → `findByUuid16()` 灵活匹配 | `device.discoverServices()` → UUID 字符串匹配 |
|
||||
| **特征发现** | `uni.getBLEDeviceCharacteristics()` → 同样灵活匹配 | 从服务对象直接获取 |
|
||||
|
||||
### 10.2 UniApp 成功的 5 个关键因素
|
||||
|
||||
#### 因素 1:MTU 协商失败不阻塞主流程
|
||||
|
||||
```javascript
|
||||
// UniApp connect.vue:426
|
||||
setBleMtu() {
|
||||
uni.setBLEMTU({
|
||||
deviceId: this.deviceId,
|
||||
mtu: 512,
|
||||
success() {
|
||||
that.isConnected = true;
|
||||
that.getBleService(); // ✅ 成功后继续
|
||||
},
|
||||
fail() {
|
||||
console.log('MTU设置失败'); // ✅ 仅打印,不阻塞
|
||||
}
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
**注意**:UniApp 的 `fail` 回调中确实**没有**调用 `getBleService()`,但在原生 APP 环境下 `setBLEMTU` 通常会成功。如果 MTU 设置失败,UniApp 也无法继续——但它运行在原生环境中,所以 MTU 协商基本都成功。
|
||||
|
||||
**Flutter 问题**:`requestMtu` 在非 Android 平台(iOS/Web)直接抛异常,如果异常处理不当(catch 中 return/throw),后续服务发现和传输都不会执行。
|
||||
|
||||
#### 因素 2:UUID 灵活匹配(兼容多种格式)
|
||||
|
||||
```javascript
|
||||
// UniApp connect.vue:358
|
||||
findByUuid16(list, uuid16) {
|
||||
const hex4 = uuid16.toString(16).padStart(4, '0').toLowerCase();
|
||||
const fullTarget = '0000' + hex4 + '-0000-1000-8000-00805f9b34fb';
|
||||
return list.find(item => {
|
||||
const uuid = item.uuid.toLowerCase();
|
||||
if (uuid === fullTarget) return true; // 128-bit 完整格式
|
||||
if (uuid === hex4 || uuid === '0000' + hex4) return true; // 短格式
|
||||
if (uuid.startsWith('0000' + hex4 + '-')) return true; // 前缀匹配
|
||||
return false;
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
UniApp 同时匹配 `"0b00"`、`"00000b00"`、`"00000b00-0000-1000-8000-00805f9b34fb"` 三种格式。**不同平台/不同 BLE 库返回的 UUID 格式不统一**,灵活匹配避免了因格式不匹配导致"找不到服务"的问题。
|
||||
|
||||
**Flutter 建议**:检查 `discoverServices()` 返回的 UUID 格式,确保匹配逻辑兼容短 UUID 和完整 128-bit UUID。
|
||||
|
||||
#### 因素 3:每包 5ms 延迟 + 重试机制(基础流控)
|
||||
|
||||
```javascript
|
||||
// UniApp connect.vue:308 writeBleImage()
|
||||
while (offset < len) {
|
||||
await this.bleWrite(this.imageWriteuuid, packet.buffer);
|
||||
await this.delay(5); // ✅ 每包 5ms 延迟,防止 BLE 缓冲区溢出
|
||||
offset += chunkLen;
|
||||
packetNo++;
|
||||
}
|
||||
|
||||
// UniApp connect.vue:237 bleWrite()(带重试)
|
||||
async bleWrite(characteristicId, buffer) {
|
||||
const MAX_RETRY = 3;
|
||||
for (let i = 0; i < MAX_RETRY; i++) {
|
||||
try {
|
||||
await this._bleWriteOnce(characteristicId, buffer, 'writeNoResponse');
|
||||
return;
|
||||
} catch (err) {
|
||||
if (i < MAX_RETRY - 1) {
|
||||
await this.delay(20 * (i + 1)); // ✅ 退避递增:20ms, 40ms, 60ms
|
||||
} else {
|
||||
// ✅ 最后一次尝试降级为 write(带应答)
|
||||
await this._bleWriteOnce(characteristicId, buffer, 'write');
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
这是 UniApp 传输成功的**最核心因素**:
|
||||
- **每包 5ms 延迟**:给 ESP32 BLE 协议栈缓冲区消化时间
|
||||
- **3 次重试**:写入失败不立即放弃
|
||||
- **退避递增**:重试间隔 20ms → 40ms → 60ms,给系统更多恢复时间
|
||||
- **降级机制**:最终尝试用 `write`(带 ACK 应答),天然起到流控作用
|
||||
|
||||
#### 因素 4:前序帧发送后等待 50ms
|
||||
|
||||
```javascript
|
||||
// UniApp connect.vue:323
|
||||
await this.bleWrite(this.imageWriteuuid, header.buffer);
|
||||
await this.delay(50); // ✅ 等待设备端处理前序帧(malloc内存、创建文件等)
|
||||
```
|
||||
|
||||
设备端收到前序帧后需要执行 `malloc()`、`fopen()` 等操作,50ms 的等待确保设备端准备好接收数据帧。
|
||||
|
||||
#### 因素 5:原生运行环境(非 Web)
|
||||
|
||||
UniApp 编译为原生 APP 运行(Android/iOS),BLE API 直接调用系统原生接口:
|
||||
- MTU 协商通过原生 API 实现,成功率高
|
||||
- BLE 写入性能接近原生(无浏览器 Web Bluetooth 的限制)
|
||||
- 无 Web Bluetooth 的隐式超时和安全限制
|
||||
|
||||
### 10.3 Flutter APP 需要修复的差异点
|
||||
|
||||
| 序号 | 差异项 | UniApp 做法 | Flutter 当前问题 | 修复优先级 |
|
||||
|------|--------|------------|-----------------|-----------|
|
||||
| 1 | **MTU 失败处理** | fail 仅 log,不阻断 | 异常可能中断后续流程 | **P0** |
|
||||
| 2 | **发送流控** | 每包 5ms 延迟 | 无延迟,全速发送 | **P0** |
|
||||
| 3 | **写入重试** | 3 次重试 + 退避递增 + 降级为 write | 无重试机制 | **P0** |
|
||||
| 4 | **前序帧等待** | header 后 50ms | 未知(需检查) | **P1** |
|
||||
| 5 | **UUID 匹配** | 兼容短/长/前缀三种格式 | 可能只匹配一种格式 | **P1** |
|
||||
| 6 | **运行环境** | 原生 APP | 可能运行在 Web 环境 | **P1** |
|
||||
|
||||
### 10.4 Flutter 参考实现(对标 UniApp)
|
||||
|
||||
```dart
|
||||
/// 发送单包数据(带重试 + 降级机制,对标 UniApp bleWrite)
|
||||
Future<void> bleWriteWithRetry(
|
||||
BluetoothCharacteristic char,
|
||||
List<int> data, {
|
||||
int maxRetry = 3,
|
||||
}) async {
|
||||
for (var i = 0; i < maxRetry; i++) {
|
||||
try {
|
||||
await char.write(data, withoutResponse: true);
|
||||
return;
|
||||
} catch (e) {
|
||||
if (i < maxRetry - 1) {
|
||||
// 退避递增:20ms, 40ms, 60ms
|
||||
await Future.delayed(Duration(milliseconds: 20 * (i + 1)));
|
||||
} else {
|
||||
// 最后一次降级为 write(带应答)
|
||||
await char.write(data, withoutResponse: false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 图片分包传输(对标 UniApp writeBleImage)
|
||||
Future<void> transferImage(
|
||||
BluetoothCharacteristic writeChar,
|
||||
List<int> imageData,
|
||||
String filename, {
|
||||
void Function(double)? onProgress,
|
||||
}) async {
|
||||
// 1. 发送前序帧
|
||||
final header = buildHeader(filename, imageData.length); // 26 字节
|
||||
await bleWriteWithRetry(writeChar, header);
|
||||
await Future.delayed(Duration(milliseconds: 50)); // ← 关键:等待设备端准备
|
||||
|
||||
// 2. 分包发送数据
|
||||
final chunkSize = 507; // MTU(512) - ATT(3) - Handle(2)
|
||||
var offset = 0;
|
||||
var packetNo = 0;
|
||||
|
||||
while (offset < imageData.length) {
|
||||
final remaining = imageData.length - offset;
|
||||
final chunkLen = remaining < chunkSize ? remaining : chunkSize;
|
||||
final isEnd = (offset + chunkLen >= imageData.length) ? 0x01 : 0x00;
|
||||
|
||||
final packet = <int>[packetNo & 0xFF, isEnd, ...imageData.sublist(offset, offset + chunkLen)];
|
||||
await bleWriteWithRetry(writeChar, packet);
|
||||
await Future.delayed(Duration(milliseconds: 5)); // ← 关键:每包 5ms 延迟
|
||||
|
||||
offset += chunkLen;
|
||||
packetNo++;
|
||||
|
||||
if (packetNo % 10 == 0 || isEnd == 1) {
|
||||
onProgress?.call(offset / imageData.length);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 10.5 总结
|
||||
|
||||
**UniApp 能成功而 Flutter 失败的核心原因是:UniApp 实现了基础的 BLE 流控机制(每包延迟 + 重试 + 降级),而 Flutter APP 缺少这些关键防护。**
|
||||
|
||||
BLE `WriteWithoutResponse` 是"发后不管"模式,ESP32 的 Bluedroid 协议栈缓冲区有限(约 8-10 个包),不加延迟的全速发送会导致缓冲区溢出 → 协议栈断开连接。UniApp 的 5ms/包延迟虽然简单,但足以让缓冲区不积压。
|
||||
|
||||
---
|
||||
|
||||
## 十一、联系方式
|
||||
|
||||
如有疑问请联系固件端开发。设备端调试可提供串口日志(115200 波特率)配合定位问题。
|
||||
@ -354,10 +354,9 @@ menu "蓝牙配网 (Bluetooth Provisioning)"
|
||||
default y
|
||||
select BT_ENABLED
|
||||
select BLUEDROID_ENABLED
|
||||
select BT_BLUFI_ENABLE
|
||||
help
|
||||
启用蓝牙配网功能,允许通过蓝牙BLE连接配置WiFi网络。
|
||||
需要ESP-IDF的蓝牙和BLUFI组件支持。
|
||||
使用自定义 GATT Server 实现,不依赖 BluFi 组件。
|
||||
|
||||
config BLUETOOTH_PROVISIONING_SECURITY
|
||||
bool "启用安全模式"
|
||||
|
||||
@ -196,9 +196,7 @@ extern "C" {
|
||||
#warning "蓝牙配网需要启用CONFIG_BLUEDROID_ENABLED"
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_BT_BLUFI_ENABLE
|
||||
#warning "蓝牙配网需要启用CONFIG_BT_BLUFI_ENABLE"
|
||||
#endif
|
||||
// BluFi 组件未使用 — 配网采用自定义 GATT Server 实现
|
||||
|
||||
#ifndef CONFIG_ESP32_WIFI_ENABLED
|
||||
#warning "蓝牙配网需要启用WiFi功能"
|
||||
|
||||
@ -267,6 +267,13 @@ static void esp_gap_cb(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *par
|
||||
param->update_conn_params.latency,
|
||||
param->update_conn_params.timeout);
|
||||
break;
|
||||
case ESP_GAP_BLE_PHY_UPDATE_COMPLETE_EVT:
|
||||
ESP_LOGI(CONN_TAG, "PHY update, status %d, tx_phy %d, rx_phy %d",
|
||||
param->phy_update.status,
|
||||
param->phy_update.tx_phy,
|
||||
param->phy_update.rx_phy);
|
||||
// tx_phy/rx_phy: 1=1M, 2=2M, 3=Coded
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -397,11 +404,27 @@ static void gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_
|
||||
ESP_LOGI(CONN_TAG, "Connected, conn_id %u, remote "ESP_BD_ADDR_STR"",
|
||||
param->connect.conn_id, ESP_BD_ADDR_HEX(param->connect.remote_bda));
|
||||
esp_ble_gap_update_conn_params(&conn_params);
|
||||
// 请求 2M PHY 提升传输速度(对端不支持时自动回退 1M,不影响兼容性)
|
||||
esp_ble_gap_set_preferred_phy(param->connect.remote_bda,
|
||||
ESP_BLE_GAP_NO_PREFER_TRANSMIT_PHY | ESP_BLE_GAP_NO_PREFER_RECEIVE_PHY,
|
||||
ESP_BLE_GAP_PHY_2M_PREF_MASK,
|
||||
ESP_BLE_GAP_PHY_2M_PREF_MASK,
|
||||
ESP_BLE_GAP_PHY_OPTIONS_NO_PREF);
|
||||
break;
|
||||
}
|
||||
case ESP_GATTS_DISCONNECT_EVT:
|
||||
ESP_LOGI(CONN_TAG, "Disconnected, remote "ESP_BD_ADDR_STR", reason 0x%02x",
|
||||
ESP_BD_ADDR_HEX(param->disconnect.remote_bda), param->disconnect.reason);
|
||||
// 清理未完成的传输,防止内存泄漏
|
||||
if (SendStatus.isSend) {
|
||||
ESP_LOGW(CONN_TAG, "传输中断,已接收 %d/%d 字节",
|
||||
(int)SendStatus.port, (int)firstMeg.len);
|
||||
SendStatus.isSend = false;
|
||||
SendStatus.port = 0;
|
||||
if (img_data) { free(img_data); img_data = NULL; }
|
||||
if (filepath) { free(filepath); filepath = NULL; }
|
||||
if (file_img) { fclose(file_img); file_img = NULL; }
|
||||
}
|
||||
esp_ble_gap_start_advertising(&adv_params);
|
||||
break;
|
||||
default:
|
||||
|
||||
30
sdkconfig
30
sdkconfig
@ -14,7 +14,6 @@ CONFIG_SOC_GDMA_SUPPORTED=y
|
||||
CONFIG_SOC_AHB_GDMA_SUPPORTED=y
|
||||
CONFIG_SOC_GPTIMER_SUPPORTED=y
|
||||
CONFIG_SOC_LCDCAM_SUPPORTED=y
|
||||
CONFIG_SOC_LCDCAM_CAM_SUPPORTED=y
|
||||
CONFIG_SOC_LCDCAM_I80_LCD_SUPPORTED=y
|
||||
CONFIG_SOC_LCDCAM_RGB_LCD_SUPPORTED=y
|
||||
CONFIG_SOC_MCPWM_SUPPORTED=y
|
||||
@ -102,7 +101,7 @@ CONFIG_SOC_CPU_HAS_FPU=y
|
||||
CONFIG_SOC_HP_CPU_HAS_MULTIPLE_CORES=y
|
||||
CONFIG_SOC_CPU_BREAKPOINTS_NUM=2
|
||||
CONFIG_SOC_CPU_WATCHPOINTS_NUM=2
|
||||
CONFIG_SOC_CPU_WATCHPOINT_MAX_REGION_SIZE=0x40
|
||||
CONFIG_SOC_CPU_WATCHPOINT_MAX_REGION_SIZE=64
|
||||
CONFIG_SOC_SIMD_PREFERRED_DATA_ALIGNMENT=16
|
||||
CONFIG_SOC_DS_SIGNATURE_MAX_BIT_LEN=4096
|
||||
CONFIG_SOC_DS_KEY_PARAM_MD_IV_LENGTH=16
|
||||
@ -209,7 +208,7 @@ CONFIG_SOC_RTCIO_INPUT_OUTPUT_SUPPORTED=y
|
||||
CONFIG_SOC_RTCIO_HOLD_SUPPORTED=y
|
||||
CONFIG_SOC_RTCIO_WAKE_SUPPORTED=y
|
||||
CONFIG_SOC_LP_IO_CLOCK_IS_INDEPENDENT=y
|
||||
CONFIG_SOC_SDM_GROUPS=1
|
||||
CONFIG_SOC_SDM_GROUPS=y
|
||||
CONFIG_SOC_SDM_CHANNELS_PER_GROUP=8
|
||||
CONFIG_SOC_SDM_CLK_SUPPORT_APB=y
|
||||
CONFIG_SOC_SPI_PERIPH_NUM=3
|
||||
@ -370,9 +369,6 @@ CONFIG_SOC_BLE_DEVICE_PRIVACY_SUPPORTED=y
|
||||
CONFIG_SOC_BLUFI_SUPPORTED=y
|
||||
CONFIG_SOC_ULP_HAS_ADC=y
|
||||
CONFIG_SOC_PHY_COMBO_MODULE=y
|
||||
CONFIG_SOC_LCDCAM_CAM_SUPPORT_RGB_YUV_CONV=y
|
||||
CONFIG_SOC_LCDCAM_CAM_PERIPH_NUM=1
|
||||
CONFIG_SOC_LCDCAM_CAM_DATA_WIDTH_MAX=16
|
||||
CONFIG_IDF_CMAKE=y
|
||||
CONFIG_IDF_TOOLCHAIN="gcc"
|
||||
CONFIG_IDF_TOOLCHAIN_GCC=y
|
||||
@ -829,7 +825,7 @@ CONFIG_BT_BLUEDROID_ESP_COEX_VSC=y
|
||||
CONFIG_BT_BLE_ENABLED=y
|
||||
CONFIG_BT_GATTS_ENABLE=y
|
||||
# CONFIG_BT_GATTS_PPCP_CHAR_GAP is not set
|
||||
CONFIG_BT_BLE_BLUFI_ENABLE=y
|
||||
# CONFIG_BT_BLE_BLUFI_ENABLE is not set
|
||||
CONFIG_BT_GATT_MAX_SR_PROFILES=8
|
||||
CONFIG_BT_GATT_MAX_SR_ATTRIBUTES=100
|
||||
# CONFIG_BT_GATTS_SEND_SERVICE_CHANGE_MANUAL is not set
|
||||
@ -1032,12 +1028,16 @@ CONFIG_BT_SMP_MAX_BONDS=15
|
||||
# CONFIG_BT_BLE_ACT_SCAN_REP_ADV_SCAN is not set
|
||||
CONFIG_BT_MAX_DEVICE_NAME_LEN=32
|
||||
CONFIG_BT_BLE_RPA_TIMEOUT=900
|
||||
# CONFIG_BT_BLE_50_FEATURES_SUPPORTED is not set
|
||||
CONFIG_BT_BLE_50_FEATURES_SUPPORTED=y
|
||||
CONFIG_BT_BLE_50_EXTEND_ADV_EN=y
|
||||
CONFIG_BT_BLE_50_PERIODIC_ADV_EN=y
|
||||
CONFIG_BT_BLE_50_EXTEND_SCAN_EN=y
|
||||
CONFIG_BT_BLE_50_EXTEND_SYNC_EN=y
|
||||
CONFIG_BT_BLE_50_DTM_TEST_EN=y
|
||||
CONFIG_BT_BLE_42_FEATURES_SUPPORTED=y
|
||||
CONFIG_BT_BLE_42_DTM_TEST_EN=y
|
||||
CONFIG_BT_BLE_42_ADV_EN=y
|
||||
CONFIG_BT_BLE_42_SCAN_EN=y
|
||||
CONFIG_BT_BLE_VENDOR_HCI_EN=y
|
||||
# CONFIG_BT_BLE_HIGH_DUTY_ADV_INTERVAL is not set
|
||||
# CONFIG_BT_ABORT_WHEN_ALLOCATION_FAILS is not set
|
||||
# end of Bluedroid Options
|
||||
@ -1259,7 +1259,6 @@ CONFIG_ESP_TLS_USE_DS_PERIPHERAL=y
|
||||
# CONFIG_ESP_TLS_SERVER_MIN_AUTH_MODE_OPTIONAL is not set
|
||||
# CONFIG_ESP_TLS_PSK_VERIFICATION is not set
|
||||
# CONFIG_ESP_TLS_INSECURE is not set
|
||||
CONFIG_ESP_TLS_DYN_BUF_STRATEGY_SUPPORTED=y
|
||||
# end of ESP-TLS
|
||||
|
||||
#
|
||||
@ -1287,12 +1286,6 @@ CONFIG_ESP_ERR_TO_NAME_LOOKUP=y
|
||||
CONFIG_ESP_ALLOW_BSS_SEG_EXTERNAL_MEMORY=y
|
||||
# end of Common ESP-related
|
||||
|
||||
#
|
||||
# ESP-Driver:Camera Controller Configurations
|
||||
#
|
||||
# CONFIG_CAM_CTLR_DVP_CAM_ISR_CACHE_SAFE is not set
|
||||
# end of ESP-Driver:Camera Controller Configurations
|
||||
|
||||
#
|
||||
# ESP-Driver:GPIO Configurations
|
||||
#
|
||||
@ -1610,11 +1603,8 @@ CONFIG_ESP_PHY_RF_CAL_PARTIAL=y
|
||||
# CONFIG_ESP_PHY_RF_CAL_NONE is not set
|
||||
# CONFIG_ESP_PHY_RF_CAL_FULL is not set
|
||||
CONFIG_ESP_PHY_CALIBRATION_MODE=0
|
||||
CONFIG_ESP_PHY_PLL_TRACK_PERIOD_MS=1000
|
||||
# CONFIG_ESP_PHY_PLL_TRACK_DEBUG is not set
|
||||
# CONFIG_ESP_PHY_RECORD_USED_TIME is not set
|
||||
CONFIG_ESP_PHY_IRAM_OPT=y
|
||||
# CONFIG_ESP_PHY_DEBUG is not set
|
||||
# end of PHY
|
||||
|
||||
#
|
||||
@ -2285,7 +2275,6 @@ CONFIG_MBEDTLS_DYNAMIC_BUFFER=y
|
||||
# CONFIG_MBEDTLS_X509_TRUSTED_CERT_CALLBACK is not set
|
||||
# CONFIG_MBEDTLS_SSL_CONTEXT_SERIALIZATION is not set
|
||||
# CONFIG_MBEDTLS_SSL_KEEP_PEER_CERTIFICATE is not set
|
||||
# CONFIG_MBEDTLS_SSL_KEYING_MATERIAL_EXPORT is not set
|
||||
CONFIG_MBEDTLS_PKCS7_C=y
|
||||
# end of mbedTLS v3.x related
|
||||
|
||||
@ -3314,7 +3303,6 @@ CONFIG_BT_NIMBLE_COEX_PHY_CODED_TX_RX_TLIM_DIS=y
|
||||
CONFIG_SW_COEXIST_ENABLE=y
|
||||
CONFIG_ESP32_WIFI_SW_COEXIST_ENABLE=y
|
||||
CONFIG_ESP_WIFI_SW_COEXIST_ENABLE=y
|
||||
# CONFIG_CAM_CTLR_DVP_CAM_ISR_IRAM_SAFE is not set
|
||||
# CONFIG_MCPWM_ISR_IN_IRAM is not set
|
||||
# CONFIG_EVENT_LOOP_PROFILING is not set
|
||||
CONFIG_POST_EVENTS_FROM_ISR=y
|
||||
|
||||
@ -163,12 +163,13 @@ CONFIG_BT_ALLOCATION_FROM_SPIRAM_FIRST=n
|
||||
CONFIG_BT_BLE_DYNAMIC_ENV_MEMORY=n
|
||||
CONFIG_BT_RESERVE_DRAM=0x10000
|
||||
|
||||
# BluFi Configuration
|
||||
CONFIG_BT_BLUFI_ENABLED=y
|
||||
CONFIG_BT_BLE_BLUFI_ENABLE=y
|
||||
# Disable BLE 5.0 features for BluFi compatibility
|
||||
CONFIG_BT_BLE_50_FEATURES_SUPPORTED=n
|
||||
CONFIG_BT_BLUFI_MAX_CONN=1
|
||||
# BluFi 未被代码使用(两种模式均用自定义 GATT Server),关闭以兼容 BLE 5.0
|
||||
CONFIG_BT_BLUFI_ENABLED=n
|
||||
CONFIG_BT_BLE_BLUFI_ENABLE=n
|
||||
# BLE 5.0 启用 2M PHY 支持(图传速度翻倍)
|
||||
CONFIG_BT_BLE_50_FEATURES_SUPPORTED=y
|
||||
# 同时保留 BLE 4.2 legacy advertising(两种模式的广播和 GATT 都依赖)
|
||||
CONFIG_BT_BLE_42_FEATURES_SUPPORTED=y
|
||||
|
||||
# Bluetooth and WiFi Coexistence
|
||||
CONFIG_ESP_COEX_SW_COEXIST_ENABLE=y
|
||||
|
||||
@ -151,12 +151,13 @@ CONFIG_BT_ALLOCATION_FROM_SPIRAM_FIRST=n
|
||||
CONFIG_BT_BLE_DYNAMIC_ENV_MEMORY=n
|
||||
CONFIG_BT_RESERVE_DRAM=0x10000
|
||||
|
||||
# BluFi Configuration
|
||||
CONFIG_BT_BLUFI_ENABLED=y
|
||||
CONFIG_BT_BLE_BLUFI_ENABLE=y
|
||||
# Disable BLE 5.0 features for BluFi compatibility
|
||||
CONFIG_BT_BLE_50_FEATURES_SUPPORTED=n
|
||||
CONFIG_BT_BLUFI_MAX_CONN=1
|
||||
# BluFi 未被代码使用(两种模式均用自定义 GATT Server),关闭以兼容 BLE 5.0
|
||||
CONFIG_BT_BLUFI_ENABLED=n
|
||||
CONFIG_BT_BLE_BLUFI_ENABLE=n
|
||||
# BLE 5.0 启用 2M PHY 支持(图传速度翻倍)
|
||||
CONFIG_BT_BLE_50_FEATURES_SUPPORTED=y
|
||||
# 同时保留 BLE 4.2 legacy advertising(两种模式的广播和 GATT 都依赖)
|
||||
CONFIG_BT_BLE_42_FEATURES_SUPPORTED=y
|
||||
|
||||
# Bluetooth and WiFi Coexistence
|
||||
CONFIG_ESP_COEX_SW_COEXIST_ENABLE=y
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user