4. GATT服务与医疗特征设计
GATT(Generic Attribute Profile)是BLE设备对外暴露数据的核心协议层。在医疗可穿戴场景中,设备通常同时承担两类角色:一类是遵循蓝牙SIG标准定义的医疗健康服务,另一类是厂商为特定算法或私有数据自定义的服务。理解这两类服务的组织方式、特征属性与数据打包规则,是设备互联互通的基础。
服务与特征的层级结构
GATT以属性表(Attribute Table)的形式组织数据,每个属性由句柄(Handle)、类型(UUID)、权限(Permissions)和值(Value)四要素构成。服务(Service)是一组相关特征的容器,特征(Characteristic)是实际承载数据的单元。一个特征至少包含两个属性:特征声明(Characteristic Declaration)和特征值(Characteristic Value);若支持通知或指示,还需附加客户端特征配置描述符(CCCD,UUID 0x2902)。
服务分为主服务(Primary Service)和次要服务(Secondary Service)。医疗设备通常将HRS、BLP等标准服务声明为主服务,供中央设备直接发现;而将一些辅助配置信息放入次要服务,由主服务引用。服务UUID可以是16位标准UUID,也可以是128位自定义UUID。标准医疗服务的16位UUID由蓝牙SIG分配,例如心率服务为0x180D,血压服务为0x1810,健康温度计服务为0x1809,脉搏血氧服务为0x1822。
标准医疗健康服务要点
HRS(心率服务,0x180D)的核心特征是心率测量(0x2A37)。其数据格式由第一个字节的Flags决定:bit0为0表示心率值为uint8,为1表示uint16;bit1~bit2表示传感器接触状态;bit3表示能量消耗是否存在;bit4表示RR间期是否存在。例如Flags=0x06时,表示心率值为uint8、传感器接触良好、无能量消耗和RR间期,后续1字节即为心率值。
BLP(血压服务,0x1810)的血压测量特征(0x2A35)采用Indicate方式传输,确保中央设备确认收到。Flags字节的bit0表示单位(0=mmHg,1=kPa),bit1表示是否有脉搏率,bit2表示是否有用户ID,bit3表示是否有测量状态。收缩压、舒张压、平均动脉压各占2字节(SFLOAT格式),脉搏率占2字节。
HTS(健康温度计服务,0x1809)的温度测量特征(0x2A1C)使用IEEE-11073 32位FLOAT格式,包含Flags、温度值和时间戳。温度值以0.1℃为单位,例如375表示37.5℃。
PLX(脉搏血氧服务,0x1822)的PLX连续测量特征(0x2A5F)包含SpO2和脉搏率,采用SFLOAT格式,同时可携带测量状态和设备状态标志。
特征属性与权限设计
特征的属性(Properties)决定中央设备能执行的操作,权限(Permissions)决定协议栈层面的访问控制。常见属性包括:Read、Write、Write Without Response、Notify、Indicate。医疗数据通常采用Notify或Indicate上报:Notify无需确认,适合高频心率数据;Indicate需要确认,适合血压等关键测量结果。
权限设置需与属性匹配:若特征支持Notify,则CCCD必须可读写;若特征值只读,则权限设为Read;若允许中央设备写入配置参数,则设为Read/Write。注意,权限是协议栈强制执行的安全边界,而属性是应用层的能力声明,两者不可混淆。
医疗数据字段的打包与解析
BLE特征值本质是字节数组,医疗数据的打包需遵循“小端序、紧凑排列、Flags前置”的原则。以自定义运动伪影补偿特征为例,设计如下数据格式:
字节偏移 字段 类型 说明
0 Flags uint8 bit0: 补偿使能; bit1: 置信度有效
1-2 补偿增益 uint16 小端序,单位0.001
3-4 补偿偏移 int16 小端序,单位0.01
5 置信度 uint8 0-100,百分比
6-7 时间戳 uint16 小端序,单位10ms
解析时,中央设备先读取Flags,再根据Flags决定后续字段是否存在。例如Flags=0x03时,全部字段有效;Flags=0x01时,置信度字段无效,应跳过。这种“Flags驱动”的解析方式与标准HRS、BLP一致,可保证向前兼容。
设计检查清单
- 标准服务UUID是否使用蓝牙SIG分配的16位UUID,避免与自定义服务冲突?
- Notify特征是否配置了CCCD,且CCCD权限为Read/Write?
- Indicate特征是否在应用层实现了确认超时重传机制?
- 多字节数值是否统一采用小端序打包?
- Flags字段是否预留了足够的扩展位,以便后续增加字段而不破坏兼容性?
- 自定义128位UUID是否基于厂商基础UUID生成,避免随机碰撞?
在实际工程中,建议先用nRF Connect或LightBlue等工具扫描设备,确认服务与特征的UUID、属性和权限是否符合预期,再编写中央设备解析代码。若发现特征值读取失败,优先检查权限是否设置为Read,以及CCCD是否已正确写入使能值。