OpenLogi

0x0003 · deviceInformation

读取固件实体、单元与型号标识符、传输标志和可选序列号。

deviceInformation 提供静态身份元数据和固件记录。功能版本会增加单元 ID、传输 PID、扩展型号 ID 和可选序列号能力。OpenLogi 在探测在线设备时使用这些数据。

**规格:**Logitech HID++ 2.0 —— x0003 deviceInformation(v4)。**交叉核对:**Logi Options+ 2.8(静态分析)、Solaar。用于:受支持的设备和 openlogi diag features。

函数参考

DeviceInformationFeature 实现功能版本 0,并读取较高功能版本引入的字段。

方法

函数HID++ fn签名返回值
get_device_info0()DeviceInformation
get_fw_info1(entity_index: u8)DeviceEntityFirmwareInfo
get_serial_number2()String

所有方法都是异步方法,并返回 Result<…, Hidpp20Error>。调用 get_serial_number 前,调用方应该检查 capabilities.serial_number。

类型

DeviceInformation

字段类型说明
entity_countu8可通过 get_fw_info 读取的固件实体数量。
unit_id[u8; 4]每台设备的标识符。功能版本低于 1 时为零。
transportDeviceTransport受支持的传输协议。功能版本低于 1 时为零。
model_id[u16; 3]最多 3 个应用 PID。功能版本低于 1 时为零。
extended_model_idu8型号的生产线属性,例如颜色。功能版本低于 2 时为零。
capabilitiesDeviceInformationCapabilities功能能力。功能版本低于 4 时为 false。

DeviceTransport

字段位说明
usb3USB 传输协议。
e_quad2eQuad 传输协议,Unifying 接收器使用此协议。
btle1Bluetooth Low Energy 传输协议,Bolt 接收器使用此协议。
bluetooth0Bluetooth 传输协议。

DeviceInformationCapabilities

字段位说明
serial_number0可以调用 get_serial_number。

DeviceEntityFirmwareInfo

字段类型说明
entity_typeDeviceEntityType固件实体类型,包括未命名的原始值。
firmware_prefixString3-byte UTF-8 固件前缀。无效 UTF-8 返回 UnsupportedResponse。
firmware_numberu8解码后版本字段的前两个十进制数字。
revisionu8解码后版本字段的后两个十进制数字。
buildu16解码后的 4 位 build 值。
activeboolactive byte 的位 0。
transport_pidu16OpenLogi 对传输特定字节 9–10 的 BE 解释。
extra_version[u8; 5]OpenLogi 对传输特定字节 11–15 的解释。

版本和 build 字段首先按 packed BCD 解码。遇到 non-BCD 字段时,OpenLogi 将 BE 值作为二进制读取,并将其限制为 9999。它将解码后的版本拆为 firmware_number = value / 100 和 revision = value % 100。

DeviceEntityType

变体值说明
MainApplication0主应用程序固件。
Bootloader1引导程序固件。
Hardware2硬件实体。
Touchpad3触摸板实体。
OpticalSensor4光学传感器实体。
Softdevice5Bluetooth SoftDevice 实体。
RfCompanionMcu6RF 协同 MCU 实体。
FactoryApplication7工厂应用程序实体。
RgbCustomEffect8RGB 自定义效果实体。
MotorDrive9电机驱动实体。
Other(u8)其他值没有具名 OpenLogi 变体的原始实体类型。包括协议值 10–15。

事件

此功能没有定义事件。

线格式

每个函数都发送 3-byte short payload。OpenLogi 通过 extend_payload() 解析响应,并获得 16-byte payload。

get_device_info(fn 0)

请求:[0x00, 0x00, 0x00]

字节字段说明
0entity_count固件实体数量。
1–4unit_id4-byte 单元 ID。
5保留OpenLogi 忽略此字节。
6transport位 3–0 依次为 USB、eQuad、BTLE 和 Bluetooth。
7–8model_id[0]应用 PID,BE。
9–10model_id[1]应用 PID,BE。
11–12model_id[2]应用 PID,BE。
13extended_model_id扩展型号属性。
14capabilities位 0 为 serial_number。
15尾部 payloadOpenLogi 忽略此字节。

三个 PID 槽位按已启用的 Bluetooth、BTLE、eQuad、USB 位顺序排列。设备最多报告 3 个 PID。Solaar。

get_fw_info(fn 1)

请求:[entity_index, 0x00, 0x00]

字节字段说明
0entity_type0 是主应用程序,1 是引导程序,2 是硬件,3–15 是 Other。OpenLogi 将未命名值保留为 Other(u8)。
1–3firmware_prefix3 个 UTF-8 字节。
4–5version4 位版本字段,BE。标准使用 packed BCD。OpenLogi 接受 non-BCD 二进制值,并限制为 9999。
6–7build4 位 build 字段,BE。标准使用 packed BCD。OpenLogi 接受 non-BCD 二进制值,并限制为 9999。
8active位 0 是 active 标志。OpenLogi 忽略位 1–7。
9–15transportLayer_Specific_info7 个传输特定字节。协议没有在此处定义通用 PID 字段。Options+ 2.8 和 Solaar 将此区域作为原始数据保留。

OpenLogi 仅通过拆分字段保留字节 9–15。它将字节 9–10 标为 transport_pid(BE),并将字节 11–15 标为 extra_version。它不提供一个原始 7-byte 字段。

get_serial_number(fn 2)

请求:[0x00, 0x00, 0x00]

字节字段说明
0–11serial number12 个 UTF-8 字节,作为 String 返回。无效 UTF-8 返回 UnsupportedResponse。
12–15尾部 payloadOpenLogi 忽略这些字节。

get_serial_number 在功能版本 4 中引入。封装不强制此版本门控。库存探测会在调用前检查能力位 0。

OpenLogi 的用法

库存探测在功能枚举后读取 get_device_info()。它将 unit ID、传输标志、3 个 PID 和 extended model ID 存入 DeviceModelInfo。它只在能力位 0 已设置时读取序列号。

openlogi diag features 从 0..entity_count 读取每个实体。被拒绝的实体或带无效 UTF-8 前缀的实体会变成 Unreadable 诊断行。通道错误会停止诊断操作。

身份读取失败会将探测标记为不完整。若存在较早的完整缓存条目,OpenLogi 会恢复其型号信息或序列号。这些函数不写入设备状态。

未确认的细节

协议将字节 9–15 称为 transport-layer-specific information。协议没有确认字节 9–10 始终构成 PID。Options+ 2.8 和 Solaar 将该区域作为原始数据保留,而 OpenLogi 使用 transport_pid 和 extra_version 字段。

硬件抓包尚未确认每种实体和传输协议中该区域的含义。因此,本参考分别显示协议字段和当前 OpenLogi API 视图。

Rust 用法

use hidpp::{
    device::Device,
    feature::device_information::DeviceInformationFeature,
    protocol::v20::Hidpp20Error,
};

async fn read_identity(device: &mut Device) -> Result<(), Hidpp20Error> {
    device.enumerate_features().await?;
    let Some(feature) = device.get_feature::<DeviceInformationFeature>() else {
        return Ok(());
    };

    let info = feature.get_device_info().await?;
    println!("unit ID: {:02x?}", info.unit_id);

    for entity in 0..info.entity_count {
        let firmware = feature.get_fw_info(entity).await?;
        println!("{entity}: {:?}, build {}", firmware.entity_type, firmware.build);
    }

    if info.capabilities.serial_number {
        println!("serial: {}", feature.get_serial_number().await?);
    }
    Ok(())
}

本页目录