你的蓝牙驱动负责收发字节,SDK 负责解析和认证。下面按“广播 → 连接 → 收发 → 配对”的顺序接入。
创建服务并广播
在开发板上创建一个 GATT 服务,也就是供手机读写的蓝牙服务:
| 对象 | UUID | 属性 |
|---|---|---|
| 主服务 | 6d4d0001-5239-4f5e-9ca0-941181196587 |
Primary |
| RX:手机发给开发板 | 6d4d0002-5239-4f5e-9ca0-941181196587 |
Write With Response |
| TX:开发板发给手机 | 6d4d0003-5239-4f5e-9ca0-941181196587 |
Notify + CCCD |
SDK 创建成功后取得广播数据,交给蓝牙栈的原始广播接口:
uint8_t advertising[31];
moto_result rc = moto_terminal_advertising(terminal, advertising);
// rc == MOTO_OK 时,发送完整的 31 字节。
这 31 字节已包含 Flags,不再追加。设备名称放在扫描响应里。手机应能在 APP 添加设备页面发现开发板。
记录每次连接的编号
手机连上时调用:
uint64_t connection = 0;
moto_result rc = moto_terminal_connected(terminal, &connection);
// 成功后,把 connection 保存到这条蓝牙连接的上下文中。
connection 是 SDK 为本次连接生成的编号。后续收包、断连都带上它;重连时重新申请,不能拿蓝牙栈自己的句柄代替。
该连接断开时调用:
moto_terminal_disconnected(terminal, connection);
先成功启动 SDK,再允许手机连接。标准 FreeRTOS 接口一次处理一个手机连接。
把手机数据交给 SDK
在 RX 特征值的收包回调里调用:
moto_result rc = moto_terminal_receive(
terminal, connection, received_bytes, received_size);
每次提交 1–512 字节,大于 512 字节时按顺序分段。
| 返回值 | 下一步 |
|---|---|
MOTO_OK |
SDK 已复制整段数据,继续下一段 |
MOTO_FULL |
SDK 暂时放不下,保存这一段,稍后重试;后续段先等待 |
MOTO_STATE |
当前连接已失效,停止提交它的数据 |
不能丢掉一段后继续发送;缓存也放不下时断开连接。以上接口从任务调用,不在硬件中断中直接调用。
实现 SDK 的发送函数
SDK 有数据要发给手机时,会调用你填写的 ble_send:
int ble_send(void *user, uint64_t connection,
const uint8_t *bytes, size_t size);
先把数据复制到自己的发送队列,再返回实际接收的字节数。队列暂满或手机尚未订阅 TX 通知时返回 0;连接不可用时返回负数。SDK 会重试剩余字节。
真正发送时按蓝牙栈允许的单包长度(ATT MTU)分段。不要只保存 bytes 指针,它在函数返回后可能失效。
ble_close 只需通知蓝牙栈关闭指定连接,无需等待关闭完成。
显示配对码并验证
| 收到的事件 | 仪表处理 |
|---|---|
MOTO_EVENT_PAIRING_PIN |
将 e.value 显示成四位数字,例如 0042;e.target 是有效秒数 |
MOTO_EVENT_PAIRING_CLEARED |
清除配对码 |
MOTO_EVENT_AUTHENTICATED |
已绑定用户认证通过 |
MOTO_EVENT_CLOSED |
清除临时界面和待处理的旧连接工作 |
MOTO_EVENT_READY 仅表示加密通道建立,还不是用户认证成功。配对码不写入日志或存储。
最后测试:首次配对、输错 PIN、断开后重连、开发板重启。重启后应保留绑定,不要求用户每次重新配对。
