BLE Dongle (产线测试)¶
重要
此例程仅存在于特殊版本的SDK中,如有需要请联系Panchip。
1 功能概述¶
此sample为pan107/pan101上演示BLE快连产线测试Dongle的功能,用于生产线快速测试BLE HID设备(鼠标、键盘等)。
核心特性:
智能过滤: 支持多种过滤条件组合(设备名称前缀、UUID、RSSI、厂商数据等)
自动识别: 通过解析Report Map自动识别设备类型(键盘/鼠标/复合设备)
长度解析: 根据BLE通知数据包长度自动区分不同类型的HID报告
快速连接: 连接完成后自动还原初始配置,准备下一次测试
多接口USB: 支持3个USB HID接口(标准键盘+复合设备+自定义)
2 环境要求¶
board:
pan107QFN32核心板/pan101MSOP10核心板 + evb底板uart0: 设置P16,P17作为默认的LOG输出端口,波特率921600
USB: 需要使用MPC版本之后USB修复后的芯片(早期版本USB不稳定)
BLE设备: 需要配对的BLE HID设备(鼠标/键盘/复合设备)
3 编译和烧录¶
例程位置:<home>\nimble\samples\solutions_hid\ble_dongle\keil_107x
打开Keil工程文件
ble_dongle.uvprojx选择目标芯片型号(PAN1070/PAN1010)
点击”Rebuild”编译工程
使用J-Link或其他调试器烧录固件
烧录完成后,Dongle自动进入扫描状态
注意:
首次使用前建议全擦除芯片
如需合并Bootloader,请参考Boot相关文档
FLM文件需根据实际芯片型号移植
4 演示说明¶
4.1 产线测试流程¶
典型应用场景:
产线工位 → BLE Dongle插入PC → BLE设备开机 → 自动配对 → 数据传输测试 → 断开重连
详细步骤:
Dongle启动:
上电后等待3秒(USB枚举稳定)
初始化BLE协议栈和过滤器
开始BLE扫描
设备发现与过滤:
// 默认过滤配置(app_ble.c) #define APP_FILT_MATCH_MODE BLE_DEV_FILT_MODE_ALL // 所有条件必须满足 #define APP_FILT_DEV_NAME_PREFIX_EN 1 // 启用名称前缀过滤 #define APP_FILT_DEV_NAME_PREFIX "Pan" // 匹配"Pan"开头的设备 #define APP_FILT_RSSI_THRESHOLD -50 // RSSI阈值:-50dBm
Dongle只接收满足以下条件的设备:
设备名称以”Pan”开头
RSSI信号强度 > -50dBm(近距离,减少干扰)
所有条件必须同时满足(
BLE_DEV_FILT_MODE_ALL)
自动连接:
发现符合条件的设备后,立即发起连接
连接成功后停止扫描
启动SMP配对(加密连接)
服务发现(SDP):
发现HID Service(0x1812)
读取所有Characteristic
订阅所有Report类型的Notify
设备类型识别:
读取Report Map描述符(可选,默认关闭)
解析Usage Page判断设备类型:
0x01 + 0x02: Mouse0x07或0x06: Keyboard0x0C: Consumer Control
日志输出识别结果
数据传输:
BLE设备发送HID报告(Notify)
Dongle接收后根据数据长度判断类型:
8字节 → 标准键盘(EP1)
2字节 → Consumer控制(EP2)
7字节 → 鼠标数据(EP2)
15字节 → NKRO键盘(EP2)
1字节 → Power键(EP2)
转发到对应的USB端点
断开重连:
设备断开或测试完成后
Dongle立即重新开始扫描
无需手动复位,可连续测试多个设备
4.2 过滤模式配置¶
两种过滤模式:
模式 |
宏定义 |
说明 |
适用场景 |
|---|---|---|---|
ALL(默认) |
|
所有条件必须同时满足 |
产线精确匹配,避免误连 |
SINGLE |
|
满足任一条件即可 |
宽松测试,兼容多种设备 |
修改方法:
// 在 app_ble.c 中修改
#define APP_FILT_MATCH_MODE BLE_DEV_FILT_MODE_SINGLE // 改为SINGLE模式
可用过滤条件:
条件 |
宏定义 |
默认值 |
说明 |
|---|---|---|---|
设备名称前缀 |
|
1 (启用) |
匹配”Pan”开头 |
UUID16 |
|
0 (禁用) |
匹配HID Service(0x1812) |
厂商数据 |
|
0 (禁用) |
匹配特定Company ID |
RSSI阈值 |
|
-50 dBm |
信号强度下限 |
配置示例:
// 示例1: 只按名称过滤(产线常用)
#define APP_FILT_MATCH_MODE BLE_DEV_FILT_MODE_ALL
#define APP_FILT_DEV_NAME_PREFIX_EN 1
#define APP_FILT_DEV_NAME_PREFIX "TestMouse"
#define APP_FILT_RSSI_THRESHOLD -60
// 示例2: 按UUID+RSSI过滤(通用测试)
#define APP_FILT_MATCH_MODE BLE_DEV_FILT_MODE_ALL
#define APP_FILT_DEV_NAME_PREFIX_EN 0
#define APP_FILT_UUID16_EN 1
#define APP_FILT_UUID16 0x1812
#define APP_FILT_RSSI_THRESHOLD -70
// 示例3: 宽松模式(任一条件满足)
#define APP_FILT_MATCH_MODE BLE_DEV_FILT_MODE_SINGLE
#define APP_FILT_DEV_NAME_PREFIX_EN 1
#define APP_FILT_DEV_NAME_PREFIX "Pan"
#define APP_FILT_RSSI_THRESHOLD -80
4.3 设备类型识别¶
Report Map解析(可选):
默认关闭(APP_ENABLE_REPORT_MAP_READ=0),开启后可自动识别设备类型。
识别逻辑:
// 解析Report Map中的Usage Page
for (uint16_t i = 0; i < len - 1; i++) {
// Usage Page 0x01 + Usage 0x02 = Mouse
if (buf[i] == 0x05 && buf[i+1] == 0x01 &&
buf[i+2] == 0x09 && buf[i+3] == 0x02) {
is_mouse = true;
}
// Usage Page 0x07 = Keyboard
if (buf[i] == 0x05 && buf[i+1] == 0x07) {
is_keyboard = true;
}
// Usage Page 0x0C = Consumer
if (buf[i] == 0x05 && buf[i+1] == 0x0C) {
is_consumer = true;
}
}
识别结果示例:
Summary: Report IDs=5, Keyboard=2, Mouse=1, Consumer=1, Vendor=NO
>>> Device Type: COMBO (Keyboard + Mouse + Consumer) <<<
4.4 数据长度解析¶
核心机制: Dongle根据BLE Notify数据包长度自动判断数据类型并转发到对应USB端点。
长度映射表:
数据长度 |
设备类型 |
Report ID |
USB端点 |
说明 |
|---|---|---|---|---|
8字节 |
标准键盘 |
无(隐含) |
EP1 (0x81) |
8字节键盘报告(Modifier+Reserved+Key1-6) |
2字节 |
Consumer控制 |
0x03 |
EP2 (0x82) |
2字节Consumer键值 |
7字节 |
鼠标 |
0x05 |
EP2 (0x82) |
7字节鼠标报告(Buttons+X+Y+Wheel+AC Pan) |
15字节 |
NKRO键盘 |
0x02 |
EP2 (0x82) |
15字节N-Key Rollover键盘 |
1字节 |
Power键 |
0x04 |
EP2 (0x82) |
1字节Power键状态 |
代码实现:
case BLE_GAP_EVENT_NOTIFY_RX:
{
uint8_t data_len = OS_MBUF_PKTLEN(event->notify_rx.om);
if (data_len == 8) {
// 标准键盘数据 → EP1
uint8_t trans_data[8];
memcpy(&trans_data[0], event->notify_rx.om->om_data, 8);
usbd_ep_start_write(0, STAND_KB_ENDPOINT, trans_data, 8);
} else if (data_len == 7) {
// 鼠标数据 → EP2
uint8_t trans_data[8];
trans_data[0] = 0x05; // Mouse Report ID
memcpy(&trans_data[1], event->notify_rx.om->om_data, 7);
trans_data[7] = 0x00; // AC Pan default
usbd_ep_start_write(0, COMPOSITE_ENDPOINT, trans_data, 8);
} else if (data_len == 2) {
// Consumer控制 → EP2
uint8_t trans_data[3];
trans_data[0] = 0x03; // Consumer Report ID
memcpy(&trans_data[1], event->notify_rx.om->om_data, 2);
usbd_ep_start_write(0, COMPOSITE_ENDPOINT, trans_data, 3);
} else if (data_len == 15) {
// NKRO键盘 → EP2
uint8_t trans_data[17];
trans_data[0] = 0x02; // NKRO Report ID
memcpy(&trans_data[1], event->notify_rx.om->om_data, 15);
usbd_ep_start_write(0, COMPOSITE_ENDPOINT, trans_data, 16);
}
}
优势:
无需预先知道设备类型,自动适配
支持混合设备(键鼠一体)
简化产线测试流程
5 开发说明¶
5.1 Flash配置¶
Flash分区布局:
分区 |
起始地址 |
大小 |
用途 |
|---|---|---|---|
Bootloader |
0x00000000 |
40 KB |
引导程序(可选) |
App |
0x0000A000 |
220 KB |
应用程序 |
Backup |
0x00040800 |
220 KB |
OTA备份(未使用) |
KV Store |
0x00077000 |
16 KB |
键值存储(未使用) |
User |
0x0007B000 |
12 KB |
用户数据(未使用) |
注意:
CONFIG_ENABLE_BOOTLOADER=0(库上默认): 不使用Bootloader,直接运行App如需DFU升级,需使能Bootloader并配置相应分区
5.2 BLE配置¶
5.2.0 关键配置宏¶
过滤相关宏(app_ble.c):
// 过滤模式
#define APP_FILT_MATCH_MODE BLE_DEV_FILT_MODE_ALL
// 设备名称前缀过滤
#define APP_FILT_DEV_NAME_PREFIX_EN 1
#define APP_FILT_DEV_NAME_PREFIX "Pan"
// UUID过滤(禁用)
#define APP_FILT_UUID16_EN 0
#define APP_FILT_UUID16 0x1812
// 厂商数据过滤(禁用)
#define APP_FILT_MFG_DATA_EN 0
// RSSI阈值
#define APP_FILT_RSSI_THRESHOLD -50
// MTU交换(禁用)
#define APP_ENABLE_MTU_EXCHANGE 0
// Report Map读取(禁用)
#define APP_ENABLE_REPORT_MAP_READ 0
连接参数(sdk_config.h):
宏定义 |
默认值 |
说明 |
|---|---|---|
|
1 |
最大中心设备数量(单连接) |
|
48 MHz |
系统时钟频率 |
|
10240 字节 |
FreeRTOS堆大小 |
重要说明:
单连接模式:
CONFIG_BT_MAX_NUM_OF_CENTRAL=1,每次只连接一个设备自动重扫: 断开后立即重新扫描,无需人工干预
RPA支持: 可使用Resolvable Private Address(
APP_USE_RPA=1)
5.2.1 初始化流程¶
void setup(void)
{
// 1. 初始化消息队列
app_msg_queue_init();
// 2. 初始化BLE设备过滤器
ble_dev_filt_init();
ble_dev_filt_set_match_mode(APP_FILT_MATCH_MODE);
ble_dev_filt_set_rssi(APP_FILT_RSSI_THRESHOLD);
// 3. 配置过滤条件
#if APP_FILT_DEV_NAME_PREFIX_EN
ble_dev_filt_set_device_name_prefix(APP_FILT_DEV_NAME_PREFIX,
strlen(APP_FILT_DEV_NAME_PREFIX));
#endif
#if APP_FILT_UUID16_EN
ble_dev_filt_set_uuid16(APP_FILT_UUID16);
#endif
#if APP_FILT_MFG_DATA_EN
uint8_t mfg_data[] = { APP_FILT_MFG_DATA };
ble_dev_filt_set_manu_data(mfg_data, APP_FILT_MFG_DATA_LEN);
#endif
// 4. 初始化BLE协议栈
app_ble_init();
// 5. 启动BLE任务
app_ble_task_start();
// 6. 开始扫描
app_ble_scan_start();
}
5.2.2 连接流程¶
扫描 → 发现设备 → 过滤检查 → 发起连接 → SMP配对 → SDP → 订阅Notify → 数据传输
↑ |
└──────────────────── 断开 ←──────────────────────────────────────────┘
关键事件处理:
BLE_GAP_EVENT_DISC: 发现设备,调用
ble_dev_filt_is_match()检查过滤条件BLE_GAP_EVENT_CONNECT: 连接建立,记录conn_handle
BLE_GAP_EVENT_ENC_CHANGE: 加密状态改变,配对成功后进行SDP
BLE_GAP_EVENT_DISCONNECT: 断开连接,立即重启扫描
BLE_GAP_EVENT_NOTIFY_RX: 收到Notify,根据长度转发到USB
5.3 USB配置¶
USB HID描述符:
Dongle虚拟出3个USB HID接口:
接口 |
端点 |
类型 |
Report描述符大小 |
用途 |
|---|---|---|---|---|
Interface 0 |
EP1 (0x81) |
Input |
63字节 |
标准键盘(8字节) |
Interface 1 |
EP2 (0x82) IN/OUT |
Input/Output |
214字节 |
复合设备(鼠标+Consumer+NKRO) |
Interface 2 |
EP3 (0x83) IN/OUT |
Input/Output |
33字节 |
自定义设备 |
VID/PID配置:
#define USBD_VID 0x07D1
#define USBD_PID 0x0015
#define USBD_MAX_POWER 100
#define USBD_LANGID_STRING 1033
Ring Buffer:
#define RINGBUFFER_SIZE 1024 // 每个缓冲区1024字节
struct ring_buf ringbuf_raw; // Interface 0 (标准键盘)
struct ring_buf ringbuf_raw2; // Interface 1 (复合设备)
数据转发逻辑:
void usb_report(void)
{
// 处理标准键盘报告(ringbuf_raw) → EP1
if (!ring_buf_is_empty(&ringbuf_raw)) {
ring_buf_get(&ringbuf_raw, cur_data, REPORT_SIZE);
usbd_ep_start_write(0, STAND_KB_ENDPOINT, cur_data, 8);
}
// 处理复合设备报告(ringbuf_raw2) → EP2
if (!ring_buf_is_empty(&ringbuf_raw2)) {
ring_buf_get(&ringbuf_raw2, cur_data, REPORT_SIZE);
usbd_ep_start_write(0, COMPOSITE_ENDPOINT, cur_data, size);
}
}
5.4 日志与调试¶
日志级别:
// app_log.h 中配置
#define APP_LOG_LVL 2 // 0:None, 1:Error, 2:Warning, 3:Info, 4:Debug
关键日志输出:
// 设备发现
Device Found peer_addr_type:1 peer_addr: XX:XX:XX:XX:XX:XX
// 连接建立
Connection established - handle:0
-peer_ota_addr: XX:XX:XX:XX:XX:XX(at: 1)
-peer_id_addr: XX:XX:XX:XX:XX:XX(at: 1)
-conn_itvl: 37500 us
-latency: 0
-timeout: 500 ms
// 服务发现
Service discovery complete; status=0, conn_handle=0
Peer cached for LED control
// 设备类型识别(如果开启)
Summary: Report IDs=5, Keyboard=2, Mouse=1, Consumer=1, Vendor=NO
>>> Device Type: COMBO (Keyboard + Mouse + Consumer) <<<
// 数据传输
received notification; conn_handle=0,attr_handle=XX,attr_len=8
// 断开重连
disconnection complete; reason=19
Restarting scan immediately...
调试建议:
产线环境建议
APP_LOG_LVL=2(只显示Warning以上)开发调试时设置为
APP_LOG_LVL=3(显示Info)可通过UART日志监控整个连接过程
6 RAM/Flash资源使用情况¶
PAN107x资源配置:
Flash Total: 508 KB (0x7F000)
SRAM Total: 48 KB (0xC000)
实际使用情况(当前配置):
Memory Region |
Start Address |
Used Size |
Region Size |
%age Used |
|---|---|---|---|---|
FLASH_TEXT |
0x00000000 |
168,430 B |
480.00 KB |
34.27% |
SRAM_DATA_TEXT |
0x20000000 |
42,744 B |
48.00 KB |
86.96% |
说明:
Flash占用: 168,430字节 ≈ 164.5 KB (BLE协议栈 + USB驱动 + 应用代码)
RAM占用: 42,744字节 ≈ 41.7 KB (FreeRTOS堆 + BLE上下文 + Ring Buffer)
Flash充裕: 使用率仅34.27%,剩余约315KB可用于功能扩展
RAM紧张: SRAM使用率达86.96%,接近上限,需注意内存优化
资源占用分析:
Flash主要占用:
BLE协议栈(NimBLE): ~80KB
USB HID驱动: ~15KB
设备过滤器: ~8KB
Peer管理(SDP): ~12KB
应用层代码: ~49.5KB
RAM主要占用:
2个Ring Buffer: 2 × 1024 = 2048字节
BLE连接上下文: ~4KB
Peer服务发现缓存: ~5KB
FreeRTOS堆(configTOTAL_HEAP_SIZE): 10240字节
系统栈和任务栈: ~20KB
优化建议:
关闭日志:
APP_LOG_LVL=0可节省~3KB Flash关闭Report Map读取: 已默认关闭,节省~2KB Flash
减小Ring Buffer: 如不需要大数据量,可改为512字节
减小FreeRTOS堆:
configTOTAL_HEAP_SIZE=8192可节省2KB RAM关闭MTU交换: 已默认关闭,节省代码空间
资源对比:
配置项 |
Flash占用 |
RAM占用 |
说明 |
|---|---|---|---|
基础BLE Dongle |
164.5 KB |
41.7 KB |
当前配置(实际编译) |
+ Report Map读取 |
~167KB |
~42KB |
增加~2.5KB Flash |
+ MTU交换 |
~170KB |
~43KB |
增加~5.5KB Flash, ~1KB RAM |
最小配置 |
~155KB |
~40KB |
关闭所有可选功能 |
7 常见问题¶
7.1 无法发现设备¶
可能原因:
过滤条件过于严格
RSSI阈值设置过高
设备名称不匹配
解决方法:
// 临时放宽过滤条件
#define APP_FILT_MATCH_MODE BLE_DEV_FILT_MODE_SINGLE
#define APP_FILT_RSSI_THRESHOLD -80
#define APP_FILT_DEV_NAME_PREFIX_EN 0
7.2 连接后立即断开¶
可能原因:
SMP配对失败
设备不支持加密
连接参数不兼容
解决方法:
查看日志中的
encryption change event; status=XXstatus=0表示成功,非0表示失败
代码已处理配对失败情况,会继续尝试GATT操作
7.3 数据长度不符合预期¶
可能原因:
设备Report描述符与标准不符
数据被截断
MTU太小
解决方法:
检查设备的Report Map
开启MTU交换:
APP_ENABLE_MTU_EXCHANGE=1查看日志中的
attr_len值
8 与prf_dongle的对比¶
特性 |
ble_dongle |
prf_dongle |
common_prf_dongle |
|---|---|---|---|
射频协议 |
BLE 5.0 |
2.4G PRF |
2.4G PRF |
连接方式 |
广播扫描+配对 |
固定频点+地址 |
多Pipe并发 |
设备数量 |
1个(单连接) |
1-2个 |
最多3个 |
配对方式 |
自动过滤+连接 |
强制配对按键 |
强制配对按键 |
设备识别 |
Report Map解析 |
配对包类型字段 |
配对包类型字段 |
数据转发 |
按长度解析 |
固定格式 |
Ring Buffer隔离 |
应用场景 |
产线快速测试 |
无线鼠标接收器 |
键鼠套件接收器 |
优势 |
自动化程度高 |
低延迟,高上报率 |
多设备并发 |
劣势 |
依赖BLE协议栈 |
需手动配对 |
代码复杂度高 |
选择建议:
产线测试: 使用
ble_dongle,自动化程度高,无需手动配对高性能鼠标: 使用
prf_dongle,1000Hz上报率,低延迟键鼠套件: 使用
common_prf_dongle,支持多设备并发