Skip to content

fix: detect wired battery-less devices and resolve registry-absent images#281

Draft
davidbudnick wants to merge 2 commits into
AprilNEA:masterfrom
davidbudnick:fix/wired-direct-device-fixes
Draft

fix: detect wired battery-less devices and resolve registry-absent images#281
davidbudnick wants to merge 2 commits into
AprilNEA:masterfrom
davidbudnick:fix/wired-direct-device-fixes

Conversation

@davidbudnick

@davidbudnick davidbudnick commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

Context

  • wired battery-less devices got dropped when the hid++ feature walk didn't complete
  • now fall back to a cheap root.getFeature probe so they stay listed
  • helps the wider class of wired g-series, not just one model — e.g. g402, g102, g303, g302, g513, g512
  • alias registry-absent devices to a sibling depot's render so they aren't blank

Testing

  • openlogi-hid + openlogi-gui tests and clippy pass
  • added resolver tests incl. one guarding the alias from over-matching

@davidbudnick davidbudnick changed the title fix: detect wired battery-less mice and resolve the G502 HERO image fix: detect wired battery-less devices and resolve registry-absent images Jun 16, 2026
@davidbudnick davidbudnick marked this pull request as draft June 16, 2026 15:24
@greptile-apps

greptile-apps Bot commented Jun 16, 2026

Copy link
Copy Markdown

Greptile Summary

This PR fixes two issues with directly-connected (wired, battery-less) Logitech devices: a HID++ inventory path that dropped real peripherals when their feature-table walk failed, and a missing image for the G502 HERO in the GUI asset resolver.

  • openlogi-hid: When probe_direct's full FeatureSet walk doesn't complete, a new peripheral_caps_via_root fallback issues individual root.getFeature round-trips for a fixed set of driving feature IDs; if any respond the device is admitted as a peripheral rather than silently dropped. PERIPHERAL_FEATURE_IDS is missing 0x8070 (ColorLedEffects), which Capabilities::from_feature_ids counts as a lighting capability \u2014 a keyboard with only that feature and a failing walk would still be dropped.
  • openlogi-gui: A curated aliased_depot function maps the G502 HERO's PID (c08b) and codename substring to the g502_core render depot, while the resolve call-site overrides display_name with the device's own codename so it isn't relabelled "G502". Three new unit tests cover PID match, codename fallback, and the guard against over-matching.

Confidence Score: 3/5

Safe to merge for the GUI change; the HID fallback has a gap that could leave certain wired keyboards undetected.

The PERIPHERAL_FEATURE_IDS constant in inventory.rs omits 0x8070 (ColorLedEffects), a feature that Capabilities::from_feature_ids recognises as driving the lighting panel. A wired keyboard that advertises only 0x8070 and whose feature-table walk fails would pass through peripheral_caps_via_root with an empty hit list and be dropped from the device list — the same failure mode the PR intends to fix. The GUI alias logic is well-constructed and well-tested.

crates/openlogi-hid/src/inventory.rs — specifically the PERIPHERAL_FEATURE_IDS constant and its coverage of lighting feature IDs.

Important Files Changed

Filename Overview
crates/openlogi-hid/src/inventory.rs Adds peripheral_caps_via_root fallback for wired battery-less mice whose feature-table walk fails; PERIPHERAL_FEATURE_IDS is missing 0x8070 (ColorLedEffects), so a keyboard with only that lighting feature and a failing walk would still be dropped.
crates/openlogi-gui/src/asset/mod.rs Adds curated PID/codename alias resolving G502 HERO to g502_core render with correct identity preservation; logic is sound and well-tested, minor style note on substring matching for codename aliases.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[probe_direct called] --> B[probe_or_reuse: full FeatureSet walk]
    B --> C{walk_succeeded?\nprobe.capabilities.is_some}
    C -- Yes --> D[effective_caps = probe.capabilities]
    C -- No --> E[peripheral_caps_via_root fallback\n8x root.getFeature round-trips]
    E --> F{any PERIPHERAL_FEATURE_IDS\nresponded?}
    F -- Yes --> G[fallback_caps = Some caps]
    F -- No --> H[fallback_caps = None]
    G --> I[effective_caps = fallback_caps]
    H --> J[effective_caps = None\ncaps = default]
    D --> K{is_peripheral?\nbattery OR buttons OR pointer OR lighting}
    I --> K
    J --> L[Rejected — not a peripheral\nhealthy = walk_succeeded = false\nreplay last inventory]
    K -- No --> L
    K -- Yes --> M[Admitted as PairedDevice\ncapabilities = effective_caps\nhealthy = true]
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    A[probe_direct called] --> B[probe_or_reuse: full FeatureSet walk]
    B --> C{walk_succeeded?\nprobe.capabilities.is_some}
    C -- Yes --> D[effective_caps = probe.capabilities]
    C -- No --> E[peripheral_caps_via_root fallback\n8x root.getFeature round-trips]
    E --> F{any PERIPHERAL_FEATURE_IDS\nresponded?}
    F -- Yes --> G[fallback_caps = Some caps]
    F -- No --> H[fallback_caps = None]
    G --> I[effective_caps = fallback_caps]
    H --> J[effective_caps = None\ncaps = default]
    D --> K{is_peripheral?\nbattery OR buttons OR pointer OR lighting}
    I --> K
    J --> L[Rejected — not a peripheral\nhealthy = walk_succeeded = false\nreplay last inventory]
    K -- No --> L
    K -- Yes --> M[Admitted as PairedDevice\ncapabilities = effective_caps\nhealthy = true]
Loading

Fix All in Codex Fix All in Claude Code

Reviews (1): Last reviewed commit: "fix(gui): alias the G502 HERO to the g50..." | Re-trigger Greptile

Comment on lines +984 to +986
const PERIPHERAL_FEATURE_IDS: [u16; 8] = [
0x1b00, 0x1b01, 0x1b02, 0x1b03, 0x1b04, 0x2201, 0x2202, 0x8080,
];

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 PERIPHERAL_FEATURE_IDS is missing 0x8070 (ColorLedEffects), which Capabilities::from_feature_ids recognises as a driving lighting feature alongside 0x8080. A wired keyboard that exposes only 0x8070 and whose feature-table walk fails would have an empty present list after the fallback probe, causing peripheral_caps_via_root to return None and the device to be dropped — the exact failure mode this PR is designed to fix.

Suggested change
const PERIPHERAL_FEATURE_IDS: [u16; 8] = [
0x1b00, 0x1b01, 0x1b02, 0x1b03, 0x1b04, 0x2201, 0x2202, 0x8080,
];
const PERIPHERAL_FEATURE_IDS: [u16; 9] = [
0x1b00, 0x1b01, 0x1b02, 0x1b03, 0x1b04, 0x2201, 0x2202, 0x8070, 0x8080,
];

Fix in Codex Fix in Claude Code

Comment on lines +401 to +404
NAME_ALIASES
.iter()
.find(|(needle, _)| name.contains(needle))
.map(|&(_, depot)| depot)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Codename alias uses substring matchname.contains(needle) means any future device whose OS product string happens to contain "g502 hero" (e.g. a hypothetical "G502 HERO SE" with a different chassis) would borrow the wrong render without any explicit entry. Since the PID path is authoritative and takes priority, the risk is low today, but as the alias table grows, an exact-match or anchored check would be safer and communicate intent more clearly.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Fix in Codex Fix in Claude Code

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