CGM(Continuous Glucose Monitoring,连续血糖监测)是近年最火的医疗可穿戴场景:一片贴在上臂的传感器持续测组织间液葡萄糖,通过 BLE 把数据推到手机或接收器。SIG 专门为它定义了 Continuous Glucose Monitoring Service(CGMS,0x181F)。本文讲清它的 7 个特性、数据格式和会话流程,并区分它和旧的"单次血糖"服务。
一、CGM 在 BLE 里的角色
- CGM Sensor(传感器端):GATT Server、Peripheral,持续测量并被动推送。
- Collector(手机/接收器):GATT Client、Central,连接后读特性、下发控制、订阅通知。
CGMS 是纯 GATT 服务,UUID 0x181F,不依赖任何私有协议。
二、CGM Service(0x181F)的 7 个特性
| 特性 |
UUID |
属性 |
作用 |
| CGM Measurement |
0x2AA7 |
Notify |
实时/周期血糖值 |
| CGM Feature |
0x2A8 |
Read |
能力标志 + 采样位置 |
| CGM Status |
0x2A9 |
Read / Notify |
当前状态与告警 |
| CGM Session Start Time |
0x2AAA |
Read / Write |
会话起始绝对时间 |
| CGM Session Run Time |
0x2AAB |
Read |
会话已运行分钟数 |
| Record Access Control Point |
0x2A52 |
Write / Indicate |
历史记录存取(标准 RACP) |
| CGM Specific Ops Control Point |
0x2AAC |
Write / Indicate |
CGM 专属控制(开始/停止会话等) |
注:表中 0x2A8 是 0x2AA8 的简写,下文同;完整 16 位 UUID 为 0x2AA8。
三、CGM Measurement(0x2AA7,Notify)
每次测量上报一帧,结构随 Flags 可变:
- Flags(1 字节):bit0 = 单位(0 = mg/dL,1 = mol/L);bit1 = Time Offset 存在(CGM 恒为 1);bit2 = 含 CGM Trend Information;bit3 = 含 CGM Quality;bit4 = 含 Sensor Status Annunciation;其余保留。
- Glucose Concentration(SFLOAT,2 字节):血糖浓度。
- Time Offset(UINT16,2 字节):距会话开始的相对秒数(不是绝对时间)。
- 若 Flags 置位,依次跟 Trend(SFLOAT)、Quality(SFLOAT)。
- 若 bit4 置位,跟 Sensor Status Annunciation(3 字节:状态/告警位域)。
- 若设备支持 E2E-CRC,末尾加 2 字节 CRC。
SFLOAT 不是 C 的 float:它是 IEEE-11073 的 16 位格式——12 位尾数(补码)+ 4 位指数(补码),值 = 尾数 × 10^指数。保留值:0x07FF = NaN,0x0800 = NRes(当前分辨率下无有效值)。解析时务必按 10 进制指数计算,别当 IEEE 754 浮点读。
四、CGM Feature(0x2AA8,Read)
- CGM Feature(24 位 / 3 字节):能力标志,常见位:支持校准(Calibration)、支持告警(Alert)、支持多绑定(Multiple Bond)、支持 Trend、支持 Quality、支持 E2E-CRC、支持多会话等。
- Type-Sample Location(1 字节):高 4 位 = Sample Location(采样位置,如手臂/腹部),低 4 位 = Type(类型,如针刺/连续)。静态值,连接时读一次即可。
两字段共 4 字节,支持 E2E-CRC 时再加 2 字节。
五、CGM Status(0x2A9,Read / Notify)
- Time Offset(UINT16):相对会话起点的秒数。
- CGM Status(3 字节):结构与 Measurement 里的 Sensor Status Annunciation 一致(设备状态、会话同步需求、会话停止等告警位)。
当测量没在跑、状态无法随测量回传时,主机主动读它来拿当前状态。
六、CGM Session Start Time(0x2AAA,Read / Write)
7 字节(含 E2E-CRC 则更多):
- Session Start Time(7 字节 DateTime):年(2) + 月 + 日 + 时 + 分 + 秒。
- Time Zone(int8):时区,未知填 -128。
- DST Offset(uint8):夏令时偏移,未知填 255。
连接后客户端写入自己的当前时间,服务器端结合自身的相对时间算出绝对会话起点。注意:写 Session Start Time 会清空测量数据库,所以要在开始会话前写。
七、CGM Session Run Time(0x2AAB,Read)
UINT16,单位是分钟,表示当前会话已运行了多久。配合 Session Start Time 可推算绝对时刻。
八、Record Access Control Point(0x2A52,Write / Indicate)
标准 RACP(Record Access Control Point),用来按筛选条件数记录 / 传记录 / 清记录:
- Op Codes:0x01 Report stored records,0x02 Delete,0x03 Abort,0x04 Report number of stored records,0x05 Number response,0x06 Response code。
- Operator:0x01 = All records(传全部),也可以用 First/Last/按范围等。
- 写请求后,设备通过 Indicate 回 Response Code / Number response。
想一次性导出历史记录时走它(不是走 0x2AA7 的实时 Notify)。
九、CGM Specific Ops Control Point(0x2AAC,Write / Indicate)
这是 CGM 专属 控制通道,会话和参数都靠它:
- 0x1A Start Session:开始会话,之后传感器持续向 0x2AA7 Notify 测量值。
- 0x1B Stop Session:停止会话,Notify 停止。
- 0x10 / 0x11:Set / Get CGM Communication Interval(推送间隔)。
- 0x12 / 0x13:Set Calibration Value(Type 1 / Type 2 校准值)。
- 0x16 / 0x17:Set / Get Patient High Alert Level(高血糖告警阈值)。
- 0x18 / 0x19:Set / Get Patient Low Alert Level(低血糖告警阈值)。
- 0x1C:Reset Device。
写 opcode 后,设备通过 Indicate 回执行结果(成功/错误码)。
十、典型会话流程
- 连接,读 CGM Feature(0x2AA8) 了解能力,读 CGM Status(0x2A9) 看当前状态。
- 给 Session Start Time(0x2AAA) 写入客户端当前时间(清库,定基准)。
- 订阅 0x2AA7 的 Notify、0x2A52 / 0x2AAC 的 Indicate。
- 写 0x1A 到 0x2AAC 开始会话 → 持续收到血糖 Notify。
- 需要历史时,用 RACP(0x2A52)按条件导出。
- 结束写 0x1B 停止会话。
十一、CGM(0x181F)vs 旧 Glucose Service(0x1808)
别把两者混用:
- 旧 Glucose Service(0x1808):单次指尖血 式测量。特性:Glucose Measurement(0x2A18)、Glucose Measurement Context(0x2A34)、Glucose Feature(0x2A51)、RACP(0x2A52)。一次测一个值。
- CGMS(0x181F):连续 监测,带会话(Start/Stop Session)、带 Trend/Quality、带 E2E-CRC、用 Specific Ops Control Point 管会话。数据模型完全不同。
做 CGM 产品就只用 0x181F 那一套,不要往 0x1808 上套。
十二、实战坑提醒
- 单位必须按 Flags bit0 解析:mg/dL 与 mol/L 差一个数量级,错读会差 18 倍。
- SFLOAT 不是 float:按 尾数×10^指数 解析,保留值 0x07FF=NaN、0x0800=NRes 要特殊处理。
- Time Offset 是相对秒数,不是绝对时间,要靠 Session Start Time 反推绝对时刻。
- 写 Session Start Time 会清空测量库,顺序要对:先写时间再 Start Session。
- 不 Start Session(0x1A)就没有持续 Notify,很多联调"收不到数据"是因为漏了这一步。
- 三个订阅都要开:0x2AA7 用 Notify(CCCD),0x2A52 / 0x2AAC 用 Indicate。
- E2E-CRC 要么全开要么全关:一旦 Feature 里声明支持,Measurement/Status/Session Start Time/Session Run Time/Specific Ops 都要带 CRC 字段。
- 校准值分 Type 1 / Type 2,写入 opcode 不同,按 Feature 支持情况选。
- Multiple Bond:若声明支持,要允许多个手机绑定并各自访问,否则换手机就读不到。
- 新旧服务别混:连续监测用 0x181F,单次指尖血才用 0x1808。
一句话总结:CGMS(0x181F)是连续血糖的 SIG 标准服务,核心在 CGM Measurement(0x2AA7)实时推 + Specific Ops Control Point(0x2AAC)管会话(0x1A 开始 / 0x1B 停止)+ RACP(0x2A52)取历史;单位是 mg/dL 还是 mol/L、SFLOAT 怎么解、Session 何时开,是三个最容易出错的点。