BR 开发指南
本文以 /samples/native_samples/br 为对象,介绍如何使用两块 HiDiTing V100 完成 BR/EDR 设备发现、配对、SPP 连接和双向数传验证。协议选型和更多 Profile 场景见蓝牙开发指南。
BR 驱动背景知识
Demo 在同一份固件中同时注册 SPP Client 和 SPP Server 命令。测试时一块板只执行客户端命令,另一块板只执行服务端命令。
| 角色 | 本地名称 | 本地地址 | App ID | SPP 参数 |
|---|---|---|---|---|
| Client | demo_device_1 |
01:01:01:01:01:01 |
1 |
UUID {0x11, 0x22},通道 10,Port ID 6414 |
| Server | demo_device_2 |
02:02:02:02:02:02 |
2 |
UUID {0x11, 0x22},通道 10,Port ID 初值 6414 |
Client 扫描回调将地址为 02:02:02:02:02:02 的设备识别为目标并发起配对。连接和配对属于设备层,SPP Port 连接属于 Profile 层;设备连接成功不代表 SPP Port 已可发送数据。
快速跑通 BR Demo
准备条件
- 两块 HiDiTing V100 开发板,分别作为 SPP Client 和 SPP Server。
- 两个可独立操作的串口,波特率为
750000。 - 一站式 CLI 开发环境;环境安装和串口监视见一站式 CLI 开发环境使用指南。
编译与烧录
完成一站式 CLI 环境配置后执行:
使用一站式 CLI 烧写固件并打开 UART2 串口监视器。以下为 Windows USB DFU 示例;将 COM3 替换为实际日志串口,其他平台和串口烧写参数参见一站式 CLI 开发环境使用指南。
fbb flash -f "$env:FBB_SDK_DIR\output\3322\fwpkg\diting-community.fwpkg" --chip 3322 -d --timeout 180
fbb monitor --port COM3 --baud 750000
启动服务端
在服务端开发板依次输入:
BRSERVERINIT注册设备层回调,配置地址、名称和 Class of Device。BRSERVERSTACKENABLE使能 BR/EDR 协议栈。BRSPPSERVERINIT使能 Port 服务,创建服务端口并注册 SPP 回调。BRSTACKBROADCAST将设备设为可发现。


启动客户端并配对
在客户端开发板依次输入:
扫描日志会输出设备名、地址和 Class of Device。发现目标地址后 Demo 自动发起配对,配对回调中停止扫描。


建立 SPP 连接
从配对和连接回调日志中确认对端 dev_id。首次联调时通常为 0,但产品代码不应写死。在客户端输入:
服务端的连接请求回调会自动接受,双方的 Port 状态回调应上报 BR_PROFILE_STATE_CONNECTED。同时记录回调中的 Port ID,后续收发以该运行时值为准。


双向数传
当两端的 Port 均为已连接状态时,客户端发送:
服务端发送:
命令的 data_len 不得大于字符串实际长度,Demo 单次最多接受 64 字节。两端接收回调应输出对端发送的数据。



断开与释放
在客户端依次输入:
AT+BRSPPCLIENTDISCONNECT=<dev_id>,<port>
AT+BRCLIENTREMOVEPAIR=<dev_id>
AT+BRSPPCLIENTDISABLE
AT+BRCLIENTSTACKDISABLE
在服务端确认 Port 断开后输入:
如果只是临时断线并希望后续快速重连,可保留配对记录,不执行 REMOVEPAIR。
文件结构与代码走读
文件结构
/samples/native_samples/br
├── CMakeLists.txt # 组件、源文件和编译定义
├── br_client.c # 客户端设备层、SPP Port 和数传流程
├── br_client.h # 客户端 AT 入参结构、校验规则和命令表
├── br_server.c # 服务端设备层、SPP Port 和数传流程
├── br_server.h # 服务端 AT 入参结构、校验规则和命令表
└── README.md # Demo 命令与编译入口
设备层回调
客户端和服务端都通过 bs_br_callbacks_t 注册协议栈、连接和配对回调,客户端额外注册扫描结果回调:
bs_br_callbacks_t callbacks = {
.stack_state_cb = demo_stack_state_cb,
.connect_state_cb = demo_connect_state_cb,
.pair_complete_cb = demo_pair_complete_cb,
.discovery_result_cb = demo_discovery_result_cb,
};
connect_state_cb 的实际签名包含 dev_id、连接状态、加密状态和原因码:
static void demo_connect_state_cb(uint16_t dev_id,
uint8_t conn_state, uint8_t encrypt_state, uint32_t reason);
回调函数类型必须与 SDK 完全一致,不能用 Port 回调的参数形式代替设备层回调。
客户端扫描和配对
Client 在初始化时保存目标地址,扫描回调先校验指针,再只比较地址数组:
if (discover_result == NULL) {
return;
}
if (memcmp(discover_result->addr.addr,
g_target_device_addr.addr,
sizeof(g_target_device_addr.addr)) == 0) {
(void)bs_br_spp_client_start_pair(&discover_result->addr);
}
设备名字段的容量为 BS_BR_DEVICE_NAME_MAX_LEN,打印时限制最大长度,不假设输入一定以 \0 结尾。
SPP Port 初始化
服务端的核心是创建服务端口,客户端创建相同 UUID 和通道的远端端口描述:
bt_uuid_t spp_uuid = {
.uuid_len = 0x02,
.uuid = {0x11, 0x22},
};
ret = bs_br_port_enable();
ret = bs_br_port_create_remote_port(&spp_uuid, 10, 6414);
ret = bs_br_port_register_callbacks(&spp_uuid, &port_callbacks);
服务端将 conn_req_cbk 设为非空,在连接请求回调中调用 bs_br_port_send_conn_rsp() 接受连接;客户端不接收入站连接,该回调为空。
Port 状态和数据安全
demo_conn_state_cbk() 维护 g_spp_con_status,发送前必须为 BR_PROFILE_STATE_CONNECTED。AT 字符串最长 64 字节,发送函数同时检查入参指针、声明长度、实际字符串长度和最大长度:
size_t actual_len = strnlen((const char *)args->data,
BR_SEND_DATA_LEN_MAX);
if (args->data_len > actual_len ||
args->data_len > BR_SEND_DATA_LEN_MAX) {
return AT_RET_SYNTAX_ERROR;
}
接收回调中的 data 是字节数组,只能在 data_len 范围内访问。实际产品应将数据交给带缓冲和分帧能力的业务任务,避免在回调中长时间处理。
AT 命令编号与注册
at_cmd_entry_t.cmd_id 要求全局不重复。Demo 为 BLE、BR Client 和 BR Server 分配独立区间,BR Client 使用 0x2310~0x2319,BR Server 使用 0x2320~0x2327。注册函数检查 uapi_at_cmd_table_register() 返回值,便于在日志中发现名称或编号冲突。
BR 设备层和 Port 结构体、枚举、入参及返回值见 BR/EDR 连接接口 和 Port 接口。
基于 BR Demo 开发自己的应用
- 在 /samples/native_samples 下建立独立目录,从
br组件复用与产品角色一致的 Client 或 Server 源文件。 - 为产品配置合法的本地地址、设备名和 Class of Device,不使用 Demo 的重复地址。
- 为 SPP 服务定义正式 UUID、通道和业务帧格式,发送前检查 Port 连接状态。
- 将目标设备过滤从固定地址替换为产品策略,同时校验地址、设备名和服务信息。
- 将连接、配对和 Port 回调转换为业务状态机事件,为扫描、连接和收发增加超时、重试和资源回收。
- 为业务层提供明确的初始化、扫描、连接、收发和释放入口,从应用任务、服务或 UI 事件调用,并对业务参数定义长度和取值范围。
- 将组件加入目标配置,用
fbb set-target pack_diting_community和fbb build --clean做全量编译,并通过业务入口验证 SPP 生命周期和异常恢复。
如需保留板端串口回归,可再为同一组业务入口增加独立 AT 命令并分配不重复的 cmd_id。AT 层只负责参数校验和调用转发,不参与 BR 连接与 SPP 数据通路的生命周期。
注意事项
dev_id和 Port ID 是运行时值,回调参数优先于 Demo 中的预设值和文档示例。- 客户端和服务端的 UUID、通道必须一致;只建立设备链路不能代替 SPP Port 连接。
- 断开时先停止数据生产,再断开 Port、按需移除配对、去使能 Port 和协议栈。
- Demo 的接收日志按字符显示;处理二进制业务数据时应使用十六进制日志,避免误判控制字节。
常见错误
| 现象 | 原因与处理 |
|---|---|
| Client 扫描不到 Server | 确认 Server 已执行 BRSTACKBROADCAST,本地地址为 02:02:02:02:02:02,扫描未被其他业务停止 |
| 发现 Server 但没有配对 | 检查扫描回调地址比较长度是否为地址数组长度,并查看 bs_br_start_pair() 错误码 |
BRSPPCLIENTCONNECT 失败 |
确认使用当次连接的 dev_id,双方 Port 服务已使能,UUID 和通道一致 |
| 发送提示未连接 | 等待 Port 状态回调上报 BR_PROFILE_STATE_CONNECTED,不要仅以设备连接回调为准 |
| 发送命令返回语法错误 | data_len 必须大于 0、不大于字符串实际长度且不超过 64 |
| 断开后重连失败 | 确认 Port 断开回调已完成;如已移除配对,重新扫描和配对 |