跳转至
文档版本: dev

OpenZilo BLE 协议参考

适用设备

本文档适用于 OpenZilo Q。

连接要求

电脑需要支持低功耗蓝牙(BLE)。SDK 使用 NUS 服务与戒指通信,支持协议 v4。

1. 文档范围

本文记录 SDK 使用的协议 v4 封包格式、命令和字段。不同固件可能只实现其中一部分命令,可通过功能查询接口确认;设备按键与灯光说明见使用指南。

函数调用见 API 索引,收包和录音处理见 架构与数据流。

2. BLE 服务

当前协议使用标准 Nordic UART Service(NUS):

用途 UUID 数据方向
Service 6E400001-B5A3-F393-E0A9-E50E24DCCA9E 服务标识
TX Characteristic 6E400003-B5A3-F393-E0A9-E50E24DCCA9E 戒指通知 SDK
RX Characteristic 6E400002-B5A3-F393-E0A9-E50E24DCCA9E SDK 写入戒指

SDK 按扫描得到的设备地址连接设备(macOS 使用 UUID),不依赖广播设备名。

SDK 写入 RX Characteristic 时固定按 20 字节分片,最后一片按实际剩余长度发送。该分片是 SDK 的 BLE 发送策略,不是 v4 协议包边界,也不会关闭系统蓝牙栈的 MTU 协商。戒指发送的 TX Characteristic 通知可采用其他分片长度,调用方应交由 OpenZiloClient 或 PacketStream 重组。

3. v4 协议包

协议头固定为 11 字节:

偏移 字段 类型 字节数 说明
0 magic_number u8 1 固定为 0x3F
1 version u16 2 当前版本为 4
3 command u16 2 命令号
5 body_length u32 4 包体字节数
9 body_crc u16 2 包体 CRC16;空包体时为 0
11 body bytes 可变 命令包体

协议头及包体中的数值字段均使用网络字节序(大端序),字符串和 data 原始字节不做字节序转换。CRC 只覆盖包体,算法与 SDK 的 crc16_compute() 一致,初始值为 0xFFFF。

BLE 通知可能拆分一个协议包,也可能连续携带多个包。调用方必须先根据固定包头和 body_length 重组完整数据,再解析包体;OpenZiloClient 和 PacketStream 已负责此过程。

4. 命令列表

功能 请求/上报 响应 SDK 接口
系统信息 0x0101 0x0102 get_system_info()
查询支持功能 0x0105 0x0106 get_device_capabilities()
命令错误 0x01FF 设备响应 无 DeviceError
日志存储信息 0x0301 0x0302 get_log_storage()
日志数据 0x0303 0x0304 read_log_chunk()
校时 0x0401 戒指请求 0x0402 SDK 应答 enable_time_sync()、send_time_response()
录音数量 0x0501 0x0502 get_audio_file_count()
普通录音提取 0x0503 0x0504 get_audio_file_info()
录音数据 0x0506 0x0505 read_audio_frame()
结束普通提取 0x0507 0x0508 end_audio_extract()
快速录音提取 0x0509 0x0504、连续 0x0505 download_audio_file(..., quick=True)
V2.001.0002.0000 保存后自动上报 连续 0x0505 戒指上报 主动阶段无 0x0504;恢复时查询元数据 receive_auto_audio_file()
V2.001.0002.0001 保存结果 0x050A 戒指上报 无 wait_audio_record_result()、receive_auto_audio_file()
实时录音订阅 0x050D 0x050E set_live_audio_subscription()
实时录音数据 0x050F、0x0510、0x0511 戒指上报 无 receive_live_audio_file()
清空录音 0x050B 0x050C clear_audio_files()
开始录音 0x0512 0x0513 start_audio_recording()
停止录音 0x0514 0x0515 stop_audio_recording()
录音状态 0x0516 0x0517 get_audio_recording_status()
读取录音设置 0x0518 0x0519 get_audio_recording_config()
修改录音设置 0x051A 0x051B set_audio_recording_config()
开启实时 IMU 0x0601 0x0602 start_sensor_report()
停止实时 IMU 0x0603 0x0604 stop_sensor_report()
批量 IMU 数据 0x0605 戒指上报 无 wait_sensor_data()
普通双击 0x0701 戒指上报 无 wait_sensor_double_tap_event()
按键双击 0x0703 戒指上报 无 wait_sensor_key_double_press_event()
按键单击 0x0704 戒指上报 无 wait_sensor_key_single_press_event()

5. 包体定义

以下 u16、i16 和 u32 均为大端序。响应中的 error_code 非 0 时,后续字段无效,并且设备可能只返回 error_code。当前固件部分录音错误路径不返回响应,此时 SDK 只能报告超时,不能推断具体错误。

5.1 系统信息

0x0101 获取系统信息

包体为空。

0x0102 系统信息响应

字段 类型 字节数 说明
error_code u16 2 错误码
firmware_version_len u16 2 固件版本字符串长度
firmware_version UTF-8 可变 固件版本字符串
system_time u32 4 Unix 时间戳,单位秒
audio_storage_total u32 4 录音存储总字节数
audio_storage_available u32 4 录音存储可用字节数
battery_percent u16 2 电量百分比
battery_charging u8 1 0 未充电,1 充电中
sn_len u16 2 SN 字符串长度
sn UTF-8 可变 设备 SN
cpuid_len u16 2 CPUID 字符串长度
cpuid UTF-8 可变 设备 CPUID
model_len u16 2 型号字符串长度
model UTF-8 可变 设备型号

5.2 日志

0x0301 获取日志存储信息

包体为空。

0x0302 日志存储信息响应

字段 类型 字节数 说明
error_code u16 2 错误码
page_size u32 4 日志页大小或设备当前返回的分页单位
total_len u32 4 日志数据总长度

0x0303 读取日志

字段 类型 字节数 说明
index u32 4 日志索引
offset u32 4 读取起始偏移
size u32 4 请求字节数

0x0304 日志数据响应

字段 类型 字节数 说明
error_code u16 2 错误码
data_len u32 4 实际数据长度
data bytes data_len 日志数据

5.3 校时

0x0401 戒指请求校时

字段 类型 字节数 说明
request_time u32 4 请求打包时间戳 T1

0x0402 SDK 校时应答

字段 类型 字节数 说明
request_time u32 4 原请求时间戳 T1
response_time u32 4 请求到达时间戳 T2
send_time u32 4 应答发送时间戳 T3

5.4 录音

0x0501 获取录音数量

包体为空。

0x0502 录音数量响应

字段 类型 字节数 说明
error_code u16 2 错误码
file_count u32 4 录音文件数量

0x0503 开始普通提取

字段 类型 字节数 说明
error_code u16 2 固定填写 0
file_index u32 4 录音文件索引

0x0509 开始快速提取

包体与 0x0503 相同。设备先返回 0x0504,随后连续上报 0x0505,直至 is_end=1。

0x0504 录音文件信息

字段 类型 字节数 说明
error_code u16 2 错误码
file_index u32 4 录音文件索引
record_time u32 4 录音时间戳,单位秒
data_size u32 4 编码数据区总字节数

0x0505 录音数据帧

字段 类型 字节数 说明
error_code u16 2 错误码
file_index u32 4 录音文件索引
frame_offset u32 4 本帧在录音数据区中的字节偏移
frame_size u32 4 本帧数据字节数,当前最大 4096
is_end u8 1 0 非末帧,1 末帧
data bytes frame_size 录音编码数据

data 是原始文件片段:V2.001.0002.0001 为 OP2C 文件;V2.001.0002.0000 为连续“2 字节小端 Speex 长度 + Speex payload”片段。两种布局见录音文件格式。这里的小端长度属于录音文件内部格式,不改变 v4 协议字段使用大端序的规则。

固件 V2.001.0002.0000录音保存成功后,设备会主动连续发送同一格式的 0x0505,但不会预先发送 0x0504。SDK 的 receive_auto_audio_file() 以第一帧的 file_index 确定文件,按 frame_offset 拼接数据,并以 is_end=1 判断连续传输结束。该函数只返回 (file_index, raw_audio),不返回 AudioFileInfo。

自动链路正常连续时 SDK 不发送提取命令。发现偏移缺口、等待后续帧超时或收到损坏帧时,SDK 先通过 0x0503 -> 0x0504 获取并校验文件索引和 data_size,再使用 0x0506 请求当前期望偏移,最多补传 3 次。最终结果以 data_size 为边界;应用必须在录音结束和主动上报期间保持 BLE 连接。如果连接建立过晚而错过数据,应查询录音数量并使用 download_audio_file() 重新下载。

0x0506 请求指定录音偏移

字段 类型 字节数 说明
error_code u16 2 固定填写 0
file_index u32 4 录音文件索引
frame_offset u32 4 需要读取或补传的字节偏移
reserved u16 2 当前固件长度检查需要的保留填充,固定填写 0

SDK 根据 frame_offset 请求普通链路的下一帧,也使用该命令补取快速下载或自动上报链路中的缺失位置。

0x0507 结束普通提取

字段 类型 字节数 说明
error_code u16 2 固定填写 0
file_index u32 4 录音文件索引

0x0508 结束提取响应

字段 类型 字节数 说明
error_code u16 2 错误码
file_index u32 4 录音文件索引

0x050A 录音保存结果

字段 类型 字节数 说明
error_code u16 2 错误码
file_index u32 4 新保存的录音文件索引

固件 V2.001.0002.0001 保存录音后发送该包,不再主动上报 0x0505。应用需要用 0x0503 普通提取文件,并以 0x0507 结束。保存失败时包体可能只有 error_code。

0x050B 清空所有录音

包体为空。该命令会删除设备中的全部录音,属于破坏性操作。

0x050C 清空录音响应

字段 类型 字节数 说明
error_code u16 2 错误码

0x050D 实时录音订阅

固件版本

此用法需要固件 V2.001.0002.0001 或更新版本。

字段 类型 字节数 说明
enabled u8 1 1 开启,0 关闭

订阅不会启动录音;V2.001.0002.0001 可由按键长按或远程录音命令启动。仅实时发送时不写入 Flash,也可配置同时保存。断线后清除订阅,关闭订阅会中止实时发送。

0x050E 实时录音订阅响应

字段 类型 字节数 说明
error_code u16 2 错误码;通知未开启或 ATT MTU 小于 128 时返回错误
enabled u8 1 设备当前订阅状态

0x050F 实时录音开始

字段 类型 字节数 说明
session_id u32 4 本次录音会话,非 0
reserved u32 4 固定为 0
record_time u32 4 录音时间戳,单位秒
reserved u32 4 固定为 0
sample_rate u16 2 固定为 16000
channels u8 1 1 或 2,与录音设置一致
codec u8 1 固定为 3,表示 Opus

0x0510 实时录音数据

字段 类型 字节数 说明
session_id u32 4 与 0x050F 相同
sequence u32 4 包序号,从 0 开始
byte_offset u32 4 已发送 Opus 数据的字节偏移,从 0 开始
length u16 2 Opus 包长度,1~100
data bytes length 一个 20 ms Opus 包,声道数与开始事件一致

byte_offset 只累计 Opus 数据本身,不包含 OP2C 文件中的长度前缀。

0x0511 实时录音结束

字段 类型 字节数 说明
error_code u16 2 错误码
session_id u32 4 与 0x050F 相同
reserved u32 4 固定为 0
produced_bytes u32 4 设备编码产生的 Opus 字节数
sent_bytes u32 4 设备已发送的 Opus 字节数
dropped_frames u32 4 设备丢弃的帧数

只有 error_code=0、dropped_frames=0,且两个字节计数都等于实际收到的数据量时,录音才完整。实时录音期间请求下载,0x0504 可能返回设备忙碌。

5.5 实时 IMU

固件 V2.001.0002.0000 需先进入手势模式;固件 V2.001.0002.0001 取消模式切换,改为由 0x0601 直接启动采集。两版均沿用下列命令号。

0x0601 开启实时上报

包体为空。以下直接启动采集的用法需要固件 V2.001.0002.0001 或更新版本;V2.001.0002.0000 需先进入手势模式。从停止状态开启上报时重置 sequence_start;已在上报时重复请求不会重置序号。

实时 IMU 的正常调用顺序必须是:

固件 V2.001.0002.0001:无需切换模式
-> 发送 0x0601
-> 收到 error_code=0 的 0x0602
-> 接收批量 0x0605

在 V2.001.0002.0000 的录音模式下,0x0601 返回设备忙碌;V2.001.0002.0001 没有该模式限制。wait_sensor_data() 只等待数据,不会自动发送 0x0601。

0x0602 开启实时上报响应

字段 类型 字节数 说明
error_code u16 2 错误码
sample_rate_hz u16 2 当前采样率,调用方应以该值为准
accel_range_g u16 2 加速度计量程
gyro_range_dps u16 2 陀螺仪量程

0x0603 停止实时上报

包体为空。V2.001.0002.0001 同时停止 BLE 上报和 IMU 采集;V2.001.0002.0000 只停止 BLE 上报,手势模式下的本地采集仍可继续。

0x0604 停止实时上报响应

字段 类型 字节数 说明
error_code u16 2 错误码

0x0605 单点与批量 IMU 数据

单点固件成功包体为 error_code:u16 + sequence:u32 + timestamp_ms:u32 + accel_x/y/z:i16 + gyro_x/y/z:i16,固定 22 字节,全大端。SDK 将其转为只有一个样本的 SensorDataBatch。

以下是批量格式(成功包体长度为 10 + 16*N,与单点格式不重叠):

字段 类型 字节数 说明
error_code u16 2 错误码
sequence_start u32 4 本批第一个采样点序号
frame_count u16 2 本批采样点数量
sample_size u16 2 单个采样点字节数,当前固定为 16
samples bytes frame_count * sample_size 连续采样点

每个 16 字节采样点格式如下:

字段 类型 字节数 说明
timestamp_ms u32 4 设备采集时间戳,单位毫秒
accel_x i16 2 X 轴加速度原始值
accel_y i16 2 Y 轴加速度原始值
accel_z i16 2 Z 轴加速度原始值
gyro_x i16 2 X 轴陀螺仪原始值
gyro_y i16 2 Y 轴陀螺仪原始值
gyro_z i16 2 Z 轴陀螺仪原始值

成功包体长度必须等于:

2 + 4 + 2 + 2 + frame_count * sample_size

每批最多 32 个采样点,实际数量以 frame_count 为准。下一批序号为 sequence_start + frame_count。V2.001.0002.0001 在断线后停止采集,重连后需重新发送 0x0601;V2.001.0002.0000 可在手势模式重连后恢复本地检测,上报仍需重新开启。

5.6 动作事件

以下事件消息格式在 V2.001.0002.0000 与 V2.001.0002.0001 中保留,采集条件与单击行为的变化见相应小节。

0x0701 普通双击

字段 类型 字节数 说明
timestamp_ms u32 4 事件时间戳,单位毫秒

V2.001.0002.0001 需要先发送 0x0601 开启 IMU 采集,再检测敲击;V2.001.0002.0000 在手势模式下检测,无需开启 BLE 数据上报。时间戳是开机后毫秒数,与按键事件的秒级设备时间不同。

0x0703 按键双击

字段 类型 字节数 说明
timestamp_ms u32 4 设备时间戳,单位秒;SDK 字段仍名为 timestamp_ms

按键双击成立时只上报 0x0703,不再触发对应单击和模式切换。

0x0704 按键单击

字段 类型 字节数 说明
timestamp_ms u32 4 设备时间戳,单位秒;SDK 字段仍名为 timestamp_ms

V2.001.0002.0001 确认单击后只上报 0x0704,不切换模式;V2.001.0002.0000 同时尝试切换录音/手势模式。事件需等待双击判定窗口结束,包体不包含模式字段。

按键事件的秒级时间在校时后对应设备的 Unix 时间;未校时时不可当作有效日历时间。不要将其与 IMU/敲击的开机后毫秒数直接比较。

5.7 远程录音与录音设置

固件版本

此用法需要固件 V2.001.0002.0001 或更新版本。

以下命令对应录音控制接口第 1 版。开始、查询状态和读取设置的请求包体为空,数值字段均为大端序。应用调用示例见远程录音。

0x0512 / 0x0513 开始录音

请求包体为空。成功响应为 error_code:u16, session_id:u32,共 6 字节。录音编号非 0,响应表示设备已接受开始请求;最终状态通过 0x0516 查询。开始请求超时后先查状态,不自动重发。

0x0514 / 0x0515 停止录音

请求为 session_id:u32, cancel:u8。cancel=0 结束并按输出设置处理录音,cancel=1 丢弃尚未保存的录音。成功响应为 error_code:u16, session_id:u32。响应中的编号必须与请求一致;收到响应后仍需等待最终状态。

0x0516 / 0x0517 查询录音状态

请求包体为空。成功响应共 14 字节:

字段 类型 说明
error_code u16 查询操作的错误码
session_id u32 录音编号;空闲时为 0
state u8 0 空闲、1 已排队、2 录音中、3 保存中、4 完成、5 失败、6 已取消
saved u8 1 表示设备已有保存文件,0 表示没有
recording_error u16 该次录音的错误码,与查询错误码分开
file_index u32 已保存文件的索引;未保存时为 0

SDK 用 saved 判断文件索引是否有效;没有文件时,返回对象的 file_index 为 None。

0x0518 / 0x0519 读取录音设置

请求包体为空,响应以 error_code:u16 开头。成功时后接下表中的 14 字节设置,再接采样率、帧时长和固定编码参数。

字段 类型 说明
version u8 设置结构版本,当前为 1
output u8 0 自动、1 保存到设备、2 实时发送、3 同时发送和保存
disconnect_policy u8 0 停止录音、1 继续保存在设备
channels u8 1 或 2
bitrate u32 码率,单位 bit/s
gain_left_q8、gain_right_q8 各 u16 左右数字增益,256 表示 1 倍
max_duration_ms u16 最长录音时间,单位毫秒

成功响应固定为 34 字节。设置字段后依次为 sample_rate:u16、frame_duration_ms:u16,以及编码参数 codec:u8、complexity:u8、vbr:u8、constrained_vbr:u8、dtx:u8、fec:u8、packet_loss_percent:u8、signal:u16、bit_depth:u8、max_packet_size:u16、application:u16。这些参数由设备返回,不能通过修改设置命令写入。

0x051A / 0x051B 修改录音设置

请求仅包含上表的 14 字节设置。响应与读取设置相同,返回设备接受后的完整设置。仅空闲时可修改;断线后继续保存只允许用于设备存储或同时保存模式。

6. 错误码

值 名称 说明
0 SUCCESS 成功
1 UNKNOWN 未知错误
2 DEVICE_BUSY 设备忙碌
3 FILE_NOT_EXIST 文件不存在
4 CMD_GROUP_NOT_EXIST 命令组不存在
5 CMD_NOT_EXIST 命令不存在
6 TIMEOUT 操作超时
7 PARAM_INVALID 参数异常
8 COMMUNICATION 通信异常
9 UNSUPPORTED_SCHEMA 不支持的消息结构版本

用户升级说明见固件升级指南。SDK 提供 update_firmware() 与 ota-update 命令,调用方式见 SDK 固件升级。

功能查询消息格式

固件 V2.001.0002.0000 与 V2.001.0002.0001 的发行标签均未实现下列功能查询命令。这里记录 SDK 对功能查询扩展的解析格式,不表示该扩展已随 V2.001.0002.0001 发布。

保留通信协议 v4,现有 GET_INFO、录音配置 v1 等布局不变。所有整数均为大端。

命令 方向 消息体
0x0105 主机 → 设备 空
0x0106 设备 → 主机 error:u16, 成功时 schema:u8=1,随后 TLV
0x01FF 设备 → 主机 original_command:u16, error:u16,固定 4 字节

错误码含义如下:2 忙碌,5 未实现命令,7 参数非法,新增 9 为不支持的结构版本。未知命令返回 5;能力查询非空请求返回 7;14 字节录音配置请求使用未知版本时返回 9。现有命令的已有错误响应继续有效;未将全部旧错误路径迁移到通用回复。收到错误包不再回错误包。

TLV 为 tag:u16, length:u16, value:length bytes,总长受 v4 的 5120 字节上限约束;当前固件使用最多 512 字节的缓冲区生成响应。重复 tag、截断、非法 UTF-8、缺失必要的设备信息字段会报协议错误;未知的可选 tag 跳过,最高位为 1 的未知 tag 要求升级 SDK,不能静默忽略。

Tag 内容
1 完整固件版本,UTF-8
2 产品型号,UTF-8
3 固件编译目标,UTF-8
4 本次启动的 8 字节随机 boot_id
5 固件构建 ID,UTF-8
6 支持的通信协议列表,连续 u16;当前为 4
0x0100 + feature_id 功能接口版本 major:u8, minor:u8
0x0204 录音限制,见下表

功能 ID:1 system/1,2 time_sync/1,3 audio_files/1,4 recording_control/1,5 live_audio/1,6 imu/2,7 key_events/1,8 double_tap/1,9 ota/1,10 gesture/1。其中斜杠后是本 SDK 支持的主版本。当前固件不声明 gesture。IMU/2 表示订阅直接启动采集;需要额外手势模式的实现不能声明该接口版本。

固件按完整命令组是否注册声明能力;按键及双击事件只在连接了相应生产者的产品构建中声明。声明表示实现支持,不保证当前硬件初始化成功、连接条件满足或设备不忙。

录音限制固定 26 字节:

顺序 类型 含义
1–2 u16, u16 采样率、帧时长 ms
3–6 u8 × 4 声道位图、输出模式位图、允许继续保存的输出模式位图、保留=0
7–8 u32 × 2 码率下限、上限,闭区间
9–10 u16 × 2 数字增益 Q8 下限、上限
11–13 u16 × 3 时长下限、上限、整除步长 ms

位图按枚举数值设置位;如声道 1/2 对应 0x06,CONTINUE_SAVING 允许 FLASH=1/BOTH=3 对应 0x0A。录音接口 v1 必须同时提供该限制。当前固定 Opus 编码配置仍通过既有配置读回接口获取。

接口变更规则

增加字段时可使用可选 TLV,旧客户端可以跳过。不兼容的字段或行为变化应提高接口主版本,并提供新命令或消息结构;需要客户端理解的字段使用必需标记。写入请求包含不支持的字段时,应返回错误。录音文件按内容识别格式,不依赖设备当前固件版本。

请求中没有事务编号,重试录音开始命令前应先查询录音状态。OTA 升级包的适用条件由发行说明提供,SDK 不自动判断所有起始版本组合,也不提供自动回滚。应用固件和引导程序的安全版本独立管理。