# PC 工程:0x5A 授权流程说明
本文档**以 Unity PC 工程 `smart-bow-pc` 为主**,说明应用侧何时发起 `0x5A` 授权轮询、如何写特征、如何解析 Notify。
7 字节组包、累加和与加解密算法在 **`BluetoothDecryptor`** 中实现(源码位于同仓库 **`smart-bow-sdk-dll`**,PC 端通过程序集或同步脚本引用同一逻辑)。
---
## 是否有此行为(结论)
**有。** 在 PC 端当 **`CommonConfig.EnableDecryption`** 与 **`NeedDecryption`** 同时为真时,连接成功后会启动 **`PollingCoroutine`**,约每秒调用 **`SendEncrypt` → `WriteByteData`**,向外设下发 **`0x5A`~`0x5D` 的 7 字节授权请求**;收到首字节为 **`0x5a`** 的 Notify 后走 **`AUTHOR_Decrypt`**,成功后 **`StopEncrypt()`** 并 **`InitWhenConenct()`** 进入业务数据。
---
## PC 端简要流程(用户可读)
1. 用户在 PC 用户端发起蓝牙连接并成功。
2. 若未开启上述两个配置,则直接 **`InitWhenConenct()`**,**不发送**授权帧。
3. 若已开启:PC 端约 **每 1 秒** 向写特征写入 **7 字节**(`0x5A` + 4 字节密文 + 校验 + `0x5D`)。
4. 外设解密后通过 Notify 回 **7 字节**(`0x5A` + 4 字节明文 + 校验 + `0x5D`),算法与规范附件 1、2 一致。
5. PC 校验通过后停止轮询,进入后续业务;失败时按 **`BluetoothAim`** 内逻辑可能重连。
```mermaid
sequenceDiagram
participant PC as PC 用户端 Unity
participant D as 蓝牙外设
PC->>D: BLE 连接成功
alt EnableDecryption && NeedDecryption
loop 约每秒,直至授权成功
PC->>D: Write 7 字节授权请求
end
D->>PC: Notify 7 字节应答
PC->>PC: StopEncrypt,InitWhenConenct
else 未开启授权
PC->>PC: 直接 InitWhenConenct
end
```
---
## PC 工程代码路径与职责
| 职责 | PC 工程内路径 |
|------|----------------|
| 连接成功是否进入授权 | `Assets/BowArrow/Scripts/Bluetooth/BluetoothAim.cs`:`OnConnected`(约 399~404 行)、`OnConnected_windows1`(约 1595~1600 行)、`OnCMDBLEReady`(约 1970~1974 行) |
| 每秒轮询与下发 | 同上:`PollingCoroutine`、`SendEncrypt`、`StopEncrypt` |
| 收到 Notify 后校验授权 | 同上:`OnCharacteristicChanged`(约 1625~1659 行),首字节 `0x5a` 时调用 `BluetoothDecryptor.AUTHOR_Decrypt` |
| Win 单路 BLE 回调绑定 | 同上:`firstBluetoothWindows.OnConnected = OnConnected_windows1` 等(搜索 `OnConnected_windows1`) |
| SmartBow CMD 通道 Notify | 同上:`OnCMDBLENotify` → `OnCharacteristicChanged` |
---
## PC 端关键代码节选
**入口:连接成功后启动轮询(通用 BluetoothHelper)**
```399:404:Assets/BowArrow/Scripts/Bluetooth/BluetoothAim.cs
if (CommonConfig.EnableDecryption && NeedDecryption)
{
// 这里验证指令,开始请求授权
// 启动轮询协程
StartCoroutine(PollingCoroutine());
}
```
**入口:Windows 单路 BLE 连接成功**
```1595:1600:Assets/BowArrow/Scripts/Bluetooth/BluetoothAim.cs
if (CommonConfig.EnableDecryption && NeedDecryption)
{
// 这里验证指令,开始请求授权
// 启动轮询协程
StartCoroutine(PollingCoroutine());
}
```
**入口:SmartBow CMD BLE 特征就绪**
```1970:1974:Assets/BowArrow/Scripts/Bluetooth/BluetoothAim.cs
if (CommonConfig.EnableDecryption && NeedDecryption)
{
// 这里验证指令,开始请求授权
// 启动轮询协程
StartCoroutine(PollingCoroutine());
}
```
**轮询与写入写特征**
```553:580:Assets/BowArrow/Scripts/Bluetooth/BluetoothAim.cs
private IEnumerator PollingCoroutine()
{
// 发送请求
// SendEncrypt();
// 设置轮询标志
isPolling = true;
PollingCoroutineCount = 4;
uint systemTick = (uint)DateTime.Now.Ticks;
while (isPolling)
{
// 等待一秒
yield return new WaitForSeconds(1f);
SendEncrypt(systemTick);
PollingCoroutineCount--;
}
}
///
/// 1、加密字节由系统生成的随机码加密而成;
/// 2、蓝牙每次断开并重新连接后,会重新生成随机加密值;
/// 3、当设备未发送正确的解密信息时,APP会每秒发送1次请求,直到解密成功。
///
///
private void SendEncrypt(uint systemTick)
{
byte[] sendByte = BluetoothDecryptor.AUTHOR_SendReq(systemTick);
Debug.Log("请求sendByte:" + BitConverter.ToString(sendByte));
WriteByteData(sendByte);
}
```
**Notify:授权未通过时只处理 `0x5a` 帧**
```1625:1659:Assets/BowArrow/Scripts/Bluetooth/BluetoothAim.cs
if (CommonConfig.EnableDecryption && NeedDecryption)
{
//Pc 版本先走校验流程
if (!BluetoothDecryptor.AUTHOR_IsDecrypt())
{
if (value[0] == 0x5a)
{
// 从硬件读取数据
if (value != null && value.Length > 0)
{
Debug.Log("接收到数据:" + BitConverter.ToString(value));
BluetoothDecryptor.AUTHOR_Decrypt(value);
if (BluetoothDecryptor.AUTHOR_IsDecrypt())
{
Debug.Log("解密成功!");
//解密成功后
StopEncrypt();
//开始连接其他信息
InitWhenConenct();
}
else
{
Debug.Log("解密失败!");
//SideTipView.ShowTip("设备通信失败,断开连接", Color.yellow);
//断开连接等操作
if (PollingCoroutineCount <= 0)
{
StopEncrypt();
DoConnect();
}
}
}
}
return;
}
}
```
---
## 与 SDK 的对应关系(供对照)
PC 端仅调用 **`BluetoothDecryptor.AUTHOR_SendReq` / `AUTHOR_Decrypt` / `AUTHOR_IsDecrypt`**,具体算法与 7 字节布局见:
`smart-bow-sdk-dll/SmartBowSDK/BluetoothDecryptor.cs`(`AUTHOR_SendReq`、`AUTHOR_Decrypt`、`CheckSum`、`AUTHOR_ImprovedEncrypt`、`AUTHOR_ImprovedDecrypt`)。
---
*详细帧格式与附件 1、2 以《蓝牙 BLE 外设设计与通信规范》为准;本文档路径:`smart-bow-pc/docs/0x5A与BLE规范对照说明.md`。*