HID++ 参考
Logitech 用于鼠标、键盘和接收器的厂商协议,以及 OpenLogi 的实现方式:消息格式、错误码、功能发现,以及如何阅读各功能页。
HID++ 是 Logitech 的厂商协议,用来配置鼠标、键盘、灯具和接收器。它运行在 USB HID
和蓝牙 HID 之上。OpenLogi 通过 openlogi-hidpp 直接使用这个协议。openlogi-hidpp
是 hidpp Rust crate 的硬分叉,库名仍是
hidpp,所以各页的代码示例写作 use hidpp::...。
两个代际
- HID++ 1.0 使用一组固定编号的寄存器。Unifying 和 Bolt 接收器至今仍用它完成 配对和设备枚举。
- HID++ 2.0 使用一组可发现的功能(feature)。每个功能由一个 16 位 ID 标识,
写作
0xZZZZ,例如0x2201。现代设备的所有设置都走这一代协议。
消息格式
每条 HID++ 消息都是一个短报告或长报告。OpenLogi 的 HID++ 通信只使用这两种报告。
| 报告 | 报告 ID | 长度 | 参数字节数 |
|---|---|---|---|
| 短报告 | 0x10 | 7 字节 | 3 |
| 长报告 | 0x11 | 20 字节 | 16 |
两种报告的前四个字节含义相同:
| 字节 | HID++ 2.0 | HID++ 1.0 |
|---|---|---|
| 0 | 报告 ID(0x10 或 0x11) | 报告 ID |
| 1 | 设备索引 | 设备索引 |
| 2 | 功能索引 | 子 ID(寄存器访问为 0x80–0x83) |
| 3 | 函数 ID(高 4 位)和软件 ID(低 4 位) | 寄存器地址 |
| 4… | 参数 | 寄存器数据 |
设备索引选择目标设备。0xFF 寻址接收器本身,或直连设备(蓝牙或 USB 线缆)
自身的功能。配对到接收器上的设备用槽位号寻址,从 1 开始。详见
接收器。
功能索引是每台设备在运行时分配的编号,不是功能 ID。主机通过
0x0000 root 解析一次即可。函数 ID 选择该功能的
某个函数,各功能页写作 fn 0、fn 1 等。
软件 ID
主机用软件 ID 把回复和请求对应起来。请求携带 1–15。设备主动发出的通知携带
0,所以软件 ID 为 0 的报告是事件,不是回复。OpenLogi 按通道分配软件 ID:固定
ID、轮换 ID,或在通道存续期间租用的 ID。租用 ID 保证同一个 HID 节点被并发打开时,
各方不会共用同一个 ID。
回复会原样带回请求的第 1–3 字节。OpenLogi 把回复匹配到这三个字节相同的最早一个 待处理请求。OpenLogi 不会同时发出两个这三个字节相同的请求,因为无线接收器可能乱序 送回它们的回复。
寄存器访问(HID++ 1.0)
| 子 ID | 请求 |
|---|---|
0x80 | 写短寄存器(3 个数据字节) |
0x81 | 读短寄存器 |
0x82 | 写长寄存器(16 个数据字节) |
0x83 | 读长寄存器 |
0x8F | 错误回复 |
错误码
HID++ 2.0 错误回复的功能索引为 0xFF。第 3 字节重复失败请求的功能索引,第 4 字节
重复它的函数 ID 与软件 ID 字节,第 5 字节是错误码。OpenLogi 把错误码返回为
Hidpp20Error::Feature(ErrorType)。未知错误码会变成
Hidpp20Error::UnsupportedResponse。
| 错误码 | ErrorType | 含义 |
|---|---|---|
0 | NoError | 无错误 |
1 | Unknown | 未知错误 |
2 | InvalidArgument | 参数无效 |
3 | OutOfRange | 参数超出范围 |
4 | HwError | 硬件错误 |
5 | LogitechInternal | 固件内部错误 |
6 | InvalidFeatureIndex | 该索引上没有功能 |
7 | InvalidFunctionId | 该功能没有这个函数 |
8 | Busy | 设备忙 |
9 | Unsupported | 不支持该操作 |
HID++ 1.0 错误回复的子 ID 为 0x8F。第 3、4 字节重复请求的子 ID 和寄存器地址,
第 5 字节是错误码。OpenLogi 把它返回为 Hidpp10Error::RegisterAccess(ErrorType)。
| 错误码 | ErrorType(1.0) | 错误码 | ErrorType(1.0) |
|---|---|---|---|
0x00 | Success | 0x07 | Busy |
0x01 | InvalidSubId | 0x08 | UnknownDevice |
0x02 | InvalidAddress | 0x09 | ResourceError |
0x03 | InvalidValue | 0x0A | RequestUnavailable |
0x04 | ConnectFail | 0x0B | InvalidParamValue |
0x05 | TooManyDevices | 0x0C | WrongPinCode |
0x06 | AlreadyExists |
功能发现
2.0 设备通过两个根功能暴露自己的能力:
0x0000root 把功能 ID 解析为运行时的功能索引。0x0001featureSet 枚举设备实现的全部功能。
OpenLogi 探测设备时会枚举它的功能集,然后查询自己支持的功能:设备信息、电量、 DPI、SmartShift 等。功能索引列出所有已收录的功能及其在 OpenLogi 中的状态。
身份标识
线路上有两种标识。接收器有 USB 厂商 ID 和产品 ID,见接收器。
设备通过 0x0003 deviceInformation
报告 model ID。model ID 索引列出所有已知的 model ID。
如何阅读功能页
每个已实现的功能都有一页,章节相同:
- 规格行:布局的来源,以及用到该功能的 OpenLogi 页面。
- 函数参考:OpenLogi v0.8.15 中
openlogi-hidpp封装的方法、类型和事件。 - 线格式:每个函数和事件的请求、回复字节。多字节字段都注明字节序(
BE或LE)。 - OpenLogi 的用法:设备层的行为,例如先读后写、写后回读校验。
- 未确认的细节:各来源说法不一致,或尚无硬件抓包的地方。
有些功能或字段没有公开的 Logitech 规格。这些内容来自对 Logitech 自家软件的静态分析, 目的是实现互操作。此时备注栏会带一个来源标签:
| 标签 | 来源 |
|---|---|
Options+ 2.8 | 对 Logi Options+ 2.8 的静态分析。它说明这款软件发送和读取什么,不说明固件怎么做。 |
G HUB | 对 Logitech G HUB 的静态分析。局限同上。 |
Solaar | 开源实现 Solaar。 |
没有标签的事实来自 Logitech 的 HID++ 文档,或 OpenLogi 自身经过测试的代码。
归属与版权
本 HID++ 参考是为 OpenLogi 项目原创整理的摘要。它依据公开资料、
hidpp 实现、Solaar,以及为互操作而对 Logitech
软件所做的静态分析,描述 Logitech 的 HID++ 1.0 / 2.0 协议,未复制任何 Logitech
文档或代码。“Logitech”“Unifying”“Logi Bolt”“Options+”“G HUB”为 Logitech 的商标。
OpenLogi 是独立项目,与 Logitech 无关联,亦未获其授权或认可。内容按“现状”提供,
不含任何形式的担保。