Skip to content

feat(cli): report feature flags and firmware entities in diag features - #690

Open
yuzi-co wants to merge 1 commit into
AprilNEA:masterfrom
yuzi-co:feat/diag-feature-flags-and-firmware
Open

feat(cli): report feature flags and firmware entities in diag features#690
yuzi-co wants to merge 1 commit into
AprilNEA:masterfrom
yuzi-co:feat/diag-feature-flags-and-firmware

Conversation

@yuzi-co

@yuzi-co yuzi-co commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

Summary

openlogi diag features printed a feature's ID and version and threw away
everything else the device said. Two things were missing, and both are what a
device report needs to be actionable.

Feature type flags. The feature table carries obsolete / hidden /
engineering flags that FeatureEntry was discarding. On a G502 LIGHTSPEED, 16
of its 30 features are flagged hidden or engineering, and the old dump gave no
way to tell those from the ones configuration software is meant to drive.

Firmware entities. A device lists its firmware through 0x0003 function 1:
the running application, the bootloader, and on many models a separate radio
stack. That version is what explains why two people with the same model see
different behaviour, and it was not reachable from the CLI at all.

Read-only throughout. Nothing here writes to a device.

Before / after

Same device, same command, wired G502 LIGHTSPEED:

 before                          after
    12  0x2201  v1                  12  0x2201  v1
    13  0x00c2  v0                  13  0x00c2  v0
    14  0x1802  v0                  14  0x1802  v0    hidden,engineering
    ...                             ...
    26  0x1e00  v0                  26  0x1e00  v0    hidden
  (30 feature entries)            (30 feature entries)

                                  fw 0: Bootloader BOT92.00_B0008 pid=aaef
                                  fw 1: MainApplication MPM17.00_B0008 pid=c08d [active]
                                  fw 2: unreadable (UnsupportedResponse)

Unreadable entities are reported, not dropped

The G502 declares three entities and its third fails to decode. Dropping the
row would claim the device has two firmware images when it says it has three,
so the entry carries the reason instead.

That third entity is the radio stack, and the decode failure is a real gap in
the vendored hidpp parser rather than a device quirk. Raw payload:

entity 2 = [05, 00, 00, 00, 00, 00, 00, a9, 00, ...]
            ^^ entity_type 5 = Softdevice
                                    ^^ build = 0x00a9, not valid BCD

get_fw_info runs the build field through bcd::convert_packed_u8, which
rejects a9. Filed separately rather than fixed here, since it belongs in the
vendored crate and has its own blast radius.

Changes

crates/openlogi-hid

  • FeatureEntry gains typ, the flags the device already sends alongside each
    feature; dump_features stops discarding them
  • new FirmwareEntityEntry and dump_firmware_entities, reading every entity
    the device declares and recording per-entity read failures rather than
    aborting the whole call
  • re-export FeatureType and DeviceEntityType. FeatureEntry::typ is a
    hidpp type in the public API and a consumer previously had no way to name
    it, which left the CLI testing raw bits

crates/openlogi-cli

  • diag features prints a flags column and the firmware entity lines
  • format_firmware_entity is a pure formatter with unit tests

Testing

  • cargo fmt --all -- --check — clean
  • cargo clippy --workspace --all-targets -- -D warnings — clean
  • cargo test --workspace — clean, including 5 new tests for
    format_firmware_entity
  • RUSTDOCFLAGS="-D warnings" cargo doc -p openlogi-hid -p openlogi-hidpp -p openlogi-hidpp-derive --no-deps --document-private-items — fails on the
    pre-existing AsyncHidChannel::supports_short_long_hidpp link in
    openlogi-hid/src/transport.rs, which this PR does not touch and docs(hid): stop linking a cfg-gated type so rustdoc passes on Windows #661 fixes.
    Windows-local: the type is cfg(not(windows)), so CI's Linux run passes
  • Hardware: verified on Windows 11 against a G502 LIGHTSPEED, both on its
    Lightspeed receiver and cabled. Output above is real, not constructed

Incidentally confirms #660 from the other direction: the same mouse gains
0x00c2 and loses 0x2121 when you plug the cable in, 30 features either way.

`openlogi diag features` printed a feature's ID and version and dropped
everything else the device said about it. Two things were missing, and
both are what a device report needs.

The feature table carries type flags that `FeatureEntry` discarded. A
G502 LIGHTSPEED reports 30 features, 16 of them flagged hidden or
engineering, and the dump gave no way to tell those apart from the ones
configuration software is meant to drive. When someone asks why OpenLogi
does not expose `0x1890`, the answer is in a flag we were not showing.

The device also lists its firmware entities through `0x0003` function 1:
the running application, the bootloader, and on many models a separate
radio stack. That is the version that explains why two people with the
same model see different behaviour, and it was not reachable from the
CLI at all.

An entity that does not parse is reported rather than dropped. The G502
declares three and its radio stack fails to decode, and a device that
cannot describe one of its own firmware images is worth seeing:

    fw 0: Bootloader BOT92.00_B0008 pid=aaef
    fw 1: MainApplication MPM17.00_B0008 pid=c08d [active]
    fw 2: unreadable (UnsupportedResponse)

`FeatureType` and `DeviceEntityType` are now re-exported from
`openlogi-hid`. `FeatureEntry::typ` was already a `hidpp` type in the
public API with no way for a consumer to name it, so the CLI had been
reduced to testing raw bits.

Read-only throughout. Nothing here writes to a device.
@yuzi-co
yuzi-co requested a review from AprilNEA as a code owner August 19, 2026 20:01
@greptile-apps

greptile-apps Bot commented Aug 19, 2026

Copy link
Copy Markdown

Greptile Summary

This PR expands openlogi diag features with feature-type flags and per-entity firmware details while preserving unreadable firmware records.

  • Retains obsolete, hidden, and engineering flags in FeatureEntry and displays them in the CLI.
  • Adds a read-only firmware-entity diagnostics API backed by HID++ DeviceInformation.
  • Re-exports the protocol types needed to consume the expanded public API.
  • Adds focused formatter tests for active, dormant, PID-less, and unreadable firmware entities.

Confidence Score: 5/5

The PR appears safe to merge, with no concrete changed-code defect identified.

The new diagnostic reads are sequential, use the established route and feature-opening paths, iterate exactly the declared firmware entities, preserve per-entity failures, and have no incompatible repository consumer.

Important Files Changed

Filename Overview
crates/openlogi-cli/src/cmd/diag/features.rs Displays feature flags and firmware entities, with formatter tests covering the newly introduced output states.
crates/openlogi-hid/src/write/diagnostics.rs Preserves feature-type metadata and adds bounded, per-entity firmware reads that retain individual parsing failures.
crates/openlogi-hid/src/lib.rs Re-exports the new diagnostic API and the HID++ types exposed by its public structures.
crates/openlogi-hid/src/write.rs Publishes the firmware diagnostics types and function through the existing write-module API surface.

Sequence Diagram

sequenceDiagram
  participant CLI as openlogi diag features
  participant HID as openlogi-hid
  participant Device as HID++ device
  CLI->>HID: dump_features(route)
  HID->>Device: Read FeatureSet entries
  Device-->>HID: IDs, versions, type flags
  HID-->>CLI: "Vec<FeatureEntry>"
  CLI->>HID: dump_firmware_entities(route)
  HID->>Device: Read DeviceInformation
  Device-->>HID: entity_count
  loop Every declared entity
    HID->>Device: get_fw_info(index)
    Device-->>HID: firmware record or error
  end
  HID-->>CLI: "Vec<FirmwareEntityEntry>"
  CLI-->>CLI: Render flags and firmware lines
Loading

Reviews (1): Last reviewed commit: "feat(cli): report feature flags and firm..." | Re-trigger Greptile

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant