ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

【HIDS】规范精讲[3]:把连接间隔压到极限——SCI 四档调速的底层机制

【HIDS】规范精讲[3]:把连接间隔压到极限——SCI 四档调速的底层机制

前两篇把 HID Service 的特征表拆了个底朝天,这篇收尾 SCI 特性。BLE 传统连接间隔的下限是 7.5 毫秒,这对键盘鼠标够用,对游戏手柄和触控笔就嫌慢了。HIDS v1.1 引入的 SCI 特性,就是给 HID 设备开了一个后门,让连接间隔能突破 7.5 毫秒地板,最低压到 375 微秒。别小看这一个改动,它背后是一套完整的档位协商、链路层参数集和主机控制流程。这篇把这套机制从头到尾捋清楚,顺便用一份真实抓包里的连接参数动态切换来作对照。


目录

一、SCI 要解决什么问题

二、四档调速:Default、Fast、Low Power、Full Range

三、链路层参数集:不只是连接间隔

四、HCI 侧的支撑:Connection Rate Request

五、声明与强制:HID Information 里的两个比特

六、空口:连接参数的动态切换

七、代码视角:档位切换的骨架

八、SCI 的设计哲学

九、测验


一、SCI 要解决什么问题

BLE 连接建立后,主从双方约定一个连接间隔,每隔这个时间唤醒一次射频收发数据。7.5 毫秒是蓝牙核心规范为 LE 连接设定的最低间隔。对键盘来说,7.5 毫秒意味着按键到主机最迟 7.5 毫秒能到,人几乎感觉不到。但对游戏手柄,7.5 毫秒等于约 133 帧/秒的采样率,高速场景下还是能察觉到拖拽感。触控笔更敏感,笔尖移动和屏幕响应之间哪怕差几毫秒都会影响书写体验。

规范对 SCI 的定位只有一句:

This section describes the SCI feature, which allows the connection intervals to be shorter than 7.5 ms.

SCI 的核心价值就是把间隔地板往下推,让 HID 设备在需要时跑出比 7.5 毫秒更低的延迟。但规范同时限定了它的适用范围:

The SCI feature only applies to LE ACL connections.

只在 LE ACL 连接上有效, iso 流、广播数据通道都不在 SCI 覆盖范围内。这个限定让 SCI 的实现可以专注优化 LE ACL 的连接参数协商流程,不用考虑其他传输模式。

二、四档调速:Default、Fast、Low Power、Full Range

SCI 不只是简单地把间隔改小,它设计了一套分档机制,让主机按场景挑档位:

四个档位的定位各有不同,值得逐个体会。

SCI Default mode 的延迟表现与连接间隔 7.5 毫秒或更长的传统 HID 设备类似。它不是为极限性能设计的,而是为不需要超低延迟的普通键盘鼠标准备的安全档——切到这个档,设备的行为和没有 SCI 时几乎一样,兼容性最好。

SCI Fast mode 是真正的低延迟档。它通过把连接间隔压到 7.5 毫秒以下来降低传输延迟。这是游戏手柄、触控笔等高灵敏度设备的核心档位。实际能压到多低取决于设备硬件能力,规范把这个范围留给了 SCI Information 特征去声明。

SCI Low Power mode 是唯一标注为 optional 的档。它不追求低延迟,而是追求低功耗——设备静置时切到这个档,拉长连接间隔、提高 peripheral latency,让射频尽量少醒。规范不强制实现这个档,但一旦实现,就要在 HID Information 里设 SCI Low Power mode supported 比特。

SCI Full Range mode 接受从最短到最长连接间隔的配置范围。这是一个宽频档,主机可以在这个档位下从极短间隔连续调到极长间隔,不需要切换档位。它的价值在于灵活——一些设备的使用场景在低延迟和高吞吐之间频繁切换,Full Range 让主机一次配置就覆盖全域。

三、链路层参数集:不只是连接间隔

主机切档时,实际在调的链路层参数有四组:

Connection Interval min 和 max 是连接间隔的上下限。min 决定了设备能达到的最低延迟,max 决定了空闲时的最大间隔。两者分开设定,让设备在一个档位内也有动态调度的空间。

Peripheral latency 是从机的睡眠许可——从机可以跳过最多这么多连接事件不醒。latency 越大越省电,但数据到达延迟也越大。它和连接间隔配合使用:间隔 15 毫秒加 latency 7,意味着从机最多可以连续跳过 7 个事件,等效睡眠 105 毫秒。

Subrate min 和 max 是 v1.1 引入的新概念。子速率是连接事件的细分调度粒度,允许在连接间隔内进一步安排子事件。min 和 max 界定了子速率可调范围,设备据此决定每个连接事件内的射频唤醒节奏。

Continuation number 是续传编号,用于在子速率调度中标识续传序列。规范没展开它的详细语义,只列了它的存在——实现时需要参照核心规范对 connection subrating 的定义。

四组参数的协同关系是:连接间隔控制宏观节奏,latency 控制睡眠深度,subrate 控制微观节奏,continuation 控制续传顺序。主机挑档位时选的是这四组参数的预设组合,而不是单个参数。

规范同时留了一条灵活的口子:

The values of the connection parameters of the HID Device, for each HID SCI mode, may be defined in a higher-level profile.

具体每个档位的参数值不在 HIDS 里写死,交给上层 Profile 定义。这意味着未来的专用 HID Profile 可以为特定设备类型(比如 VR 手柄)定制参数预设,而不需要修改 HIDS 本身。

四、HCI侧的支撑:Connection Rate Request

规范提到设备侧可以实现一条 HCI 命令:

The HID Device implementing the SCI feature may implement the HCI command, HCI_LE_Connection_Rate_Request.

这条命令对应核心规范 Volume 4, Part E, Section 7.8.154。它的作用是让主机协议栈向控制器发起连接速率请求,把 SCI 档位对应的参数集下发到链路层执行。

注意这里的 may 而非 shall——SCI 的实现不强制要求 HCI 层支持这条命令。如果控制器自身已有连接子速率管理机制,应用层可以直接走控制器内部接口。但大多数标准协议栈实现走 HCI 这条路,它是应用层到链路层的标准桥梁。

五、声明与强制:HIDInformation 里的两个比特

SCI 的支持声明在 HID Information 特征的 Flags 字段里:

If the HID Device supports HID SCI modes, then the HID Device shall set the SCI Supported bit to 1 in the HID Information characteristic value.

If the HID Device supports the SCI Low Power mode, then the HID Device shall set the SCI Low Power mode supported bit in the HID Information characteristic value.

两个比特分别声明 SCI 特性和 SCI 低功耗档。设了 SCI Supported bit 就必须实现 Default、Fast、Full Range 三个档位,Low Power 是可选的。设了 SCI Low Power mode supported bit 才需要实现 Low Power 档。这两条声明是主机判断设备能力的第一入口——主机在读到 HID Information 之前不会发 SCI 相关指令。

六、空口:连接参数的动态切换

虽然这份抓包的设备未启用 SCI(所有连接间隔均大于等于 7.5 毫秒),但它的连接参数动态切换模式与 SCI 四档调度的设计思路高度一致。下图从抓包中提取了五次连接参数请求,绘制了连接间隔和 peripheral latency 随时间的变化:

五次切换构成了一条清晰的工作模式轨迹。连接建立后初始间隔 45 毫秒、latency 0,约 16 秒后切到 15 毫秒 latency 0——这是为数据传输做的提速准备。约 11 秒后切到 60 毫秒 latency 7,进入低功耗静默期,射频每 480 毫秒才醒一次(60 × 7 + 60),这对应 SCI Low Power 或 Default 档的典型形态。

约 141 秒时参数再次切到 15 毫秒 latency 0,图中橙色阴影标注了这段时间的高吞吐突发期。约 14 秒的突发结束后,参数回到 60 毫秒 latency 7 的省电模式。这个 15ms/Lat0 ↔ 60ms/Lat7 的来回切换,本质上就是 SCI Fast ↔ SCI Low Power 档位切换在非 SCI 场景下的翻版。SCI 的设计不过是在协议层把这套行为标准化、档位化,让主机不用自己猜参数。

数据上还能看到一个细节:参数切换不是瞬间完成的,Peripheral Connection Parameter Request 发出后要等一段 instant 才生效,图中 48.6 秒的请求实际生效在 90 毫秒后。这段缓冲是链路层为了确保双方都能在约定时刻切换参数而设计的安全窗口。SCI 档位切换同样有这个时序约束——主机发 Enable SCI Fast mode 后,实际参数生效要等链路层协商完成,这正是前文 SCI Mode 特征值变化必须发生在切换完成之后的由来。

七、代码视角:档位切换的骨架

把 SCI 档位切换的逻辑落到代码上,大致流程是这样的:

import struct # SCI Mode 取值(对应 Table 2.19) SCI_MODE_NONE = 0x00 SCI_MODE_DEFAULT = 0x02 SCI_MODE_FAST = 0x03 SCI_MODE_LOW_POWER = 0x04 SCI_MODE_FULL_RANGE = 0x05 # Control Point 指令值(对应 Table 2.17) CMD_SCI_DEFAULT = 0x02 CMD_SCI_FAST = 0x03 CMD_SCI_LOW_POWER = 0x04 CMD_SCI_FULL_RANGE = 0x05 def host_request_sci_mode(sci_info_raw: bytes, target_mode: int) -> dict: # 1. 解析 SCI Information,确认目标档位在设备能力范围内 min_interval = sci_info_raw[0] # 单位 125us num_groups = sci_info_raw[1] groups = [] offset = 2 for _ in range(num_groups): g_min = struct.unpack_from('<H', sci_info_raw, offset)[0] g_max = struct.unpack_from('<H', sci_info_raw, offset + 2)[0] g_stride = struct.unpack_from('<H', sci_info_raw, offset + 4)[0] groups.append((g_min, g_max, g_stride)) offset += 6 # 2. 根据档位选择连接参数集(上层 Profile 定义具体值) mode_params = { SCI_MODE_FAST: {'interval_min': min_interval, 'interval_max': min_interval * 4, 'latency': 0}, SCI_MODE_DEFAULT: {'interval_min': 60, 'interval_max': 90, 'latency': 0}, SCI_MODE_LOW_POWER: {'interval_min': 240, 'interval_max': 480, 'latency': 7}, SCI_MODE_FULL_RANGE: {'interval_min': min_interval, 'interval_max': 480, 'latency': 0}, } params = mode_params.get(target_mode) if params is None: return {'ok': False, 'reason': 'unsupported mode'} # 3. 校验目标参数是否落在设备声明的任一组内 target_iv = params['interval_min'] supported = any(g[0] <= target_iv <= g[1] for g in groups) if not supported: return {'ok': False, 'reason': 'interval not in any supported group'} # 4. 通过 Control Point 下发指令(Write Without Response) # 实际通过 GATT Write 写入 CMD 值 cmd_value = {SCI_MODE_DEFAULT: CMD_SCI_DEFAULT, SCI_MODE_FAST: CMD_SCI_FAST, SCI_MODE_LOW_POWER: CMD_SCI_LOW_POWER, SCI_MODE_FULL_RANGE: CMD_SCI_FULL_RANGE}[target_mode] write_without_response(handle=CTRL_POINT_HANDLE, value=bytes([cmd_value])) # 5. 等待 SCI Mode 特征通知确认(若已订阅) # 通知值 = 切换后的新档位,收到即表示切换成功 return {'ok': True, 'expected_mode': target_mode, 'params': params} def device_on_sci_mode_change(new_mode: int, old_mode: int): # 设备侧:链路层参数切换完成后才更新特征值 if ll_param_update_success(): update_characteristic_value(SCI_MODE_HANDLE, bytes([new_mode])) if cccd_subscribed(SCI_MODE_HANDLE): send_notification(SCI_MODE_HANDLE, bytes([new_mode])) # 切换失败:特征值保持 old_mode 不变,不通知

这段代码体现了 SCI 档位切换的三步核心:读能力、发指令、等通知。第一步防止主机发出设备不支持的档位请求;第二步走 Control Point 的无响应写通道;第三步靠 SCI Mode 的变化通知来确认落地。三步缺一不可,少了第一步会发空包,少了第三步会丢失确认。

八、SCI 的设计哲学

回看整套 SCI 体系,能读出三条设计哲学。

(1)其一,能力声明与参数协商分离。设备通过 HID Information 声明是否支持 SCI,通过 SCI Information 暴露可用参数范围,通过 Control Point 接收档位指令,通过 SCI Mode 反馈当前状态。四个特征各管一段,职责清晰,没有把声明、协商、执行、反馈揉成一个特征。这种分离让主机和设备各自只需关心自己那一段的逻辑,降低了实现和测试的复杂度。

(2)其二,档位预设而非自由参数。主机不直接指定连接间隔和 latency 的具体值,而是选择一个档位。档位背后的参数集交给上层 Profile 或设备自定义。这种设计让 HIDS 不需要了解每个设备类型的最佳参数,避免了规范被参数调优细节淹没。同时档位是有限的四个,主机的决策树简单明了。

(3)其三,确认走数据通道。Control Point 没有响应码,但 SCI Mode 的变化通知可以作为事实确认。这种设计避免了在 GATT 层引入额外的响应机制,复用了已有的通知通道。代价是主机必须订阅 SCI Mode 才能拿到异步确认——不订阅就只能轮询,但轮询在低延迟场景下是反模式的。

这三条设计思路不只适用于 SCI,对任何 GATT 服务的控制面设计都有参考价值。

九、测验

1. SCI Fast mode 和 SCI Low Power mode 在链路层参数上的核心区别是什么?为什么 Low Power 是 optional 而其他三档是 mandatory?

答:

Fast mode 通过把连接间隔压到 7.5 毫秒以下降低延迟,peripheral latency 通常设为 0;Low Power mode 通过拉长连接间隔和提高 peripheral latency 来省电,射频唤醒频率大幅降低。三档中 Default、Fast、Full Range 强制实现是因为它们覆盖了 HID 设备的基本工作场景——日常使用、低延迟、灵活调度;Low Power 是省电优化,不是所有设备都需要——比如供电充裕的游戏手柄就不关心省电。规范把它列为 optional 让实现者按产品定位决定是否投入。

2. 主机发 Enable SCI Fast mode 指令后,如何确认设备已切换成功?如果切换失败,主机会观察到什么现象?

答:

确认路径是订阅 SCI Mode 特征的变化通知。设备在链路层参数切换真正完成后才更新 SCI Mode 值并发出通知,主机收到新值即知切换成功。如果切换失败,SCI Mode 特征值不改变,也不发通知,主机在通知层面什么也收不到。此时主机可以主动读 SCI Mode 特征值,如果读到的仍然是旧值,即可判定切换失败。规范明确要求特征值变化必须在切换成功之后,因此这个值是事实确认而非意图。

3. 抓包中观察到连接参数在 15ms/latency0 和 60ms/latency7 之间来回切换,这种模式与 SCI 的哪两个档位对应?为什么实际连接间隔没有低于 7.5ms?

答:

15ms/latency0 对应 SCI Fast 或 Default 档的典型参数——低延迟、射频频繁唤醒;60ms/latency7 对应 SCI Low Power 档——射频每约 480ms 才有效唤醒一次。实际连接间隔没有低于 7.5ms 是因为该设备未启用 SCI 特性,7.5ms 仍是核心规范为 LE 连接设定的间隔下限。SCI 的作用正是突破这个下限,只有设备在 HID Information 中设置了 SCI Supported bit,并通过 SCI Information 声明了更低的间隔范围,主机才能通过 Control Point 下发 SCI Fast 档指令让连接间隔真正降到 7.5ms 以下。


RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进