feat(hid,core): drive solid colour over RgbEffects (0x8071) - #523
feat(hid,core): drive solid colour over RgbEffects (0x8071)#523Abnersouza7 wants to merge 2 commits into
Conversation
G-series wireless mice expose the per-cluster RgbEffects engine (0x8071) instead of ColorLedEffects (0x8070) — a G903 LIGHTSPEED reports 0x8071 and neither 0x8070 nor 0x8080. The 0x8071 wrapper already existed in openlogi-hidpp but had no consumer, so those devices had unreachable LEDs and Capabilities::lighting stayed false, denying them a Lighting tab in the GUI. - hid: set_keyboard_color grows an 0x8071 rung above 0x8070/0x8080. It takes software control of the clusters (required before setRgbClusterEffect), reads the cluster count, and applies the fixed effect to every cluster — a G903's logo and DPI indicator are separate clusters, so writing only the first leaves it half-painted. The fixed effect is located by effectID rather than by a guessed index, since effect indices are per-cluster and firmware-ordered. Volatile like the 0x8070 path, so a colour pick overrides the running onboard effect without spending flash cycles. - core: Capabilities::lighting counts 0x8071, so those devices offer the existing Lighting panel. No IPC or config change — the panel already sends a plain RGB triple. - cli: diag lighting gains --method rgb and picks its device via select_device, so it can reach a mouse behind a receiver instead of only wired keyboards. Verified on a G903 LIGHTSPEED (046d:c539 receiver): cluster_count=2, both clusters driven, red/green/blue all applied via Auto and --method rgb.
A colour write claims RgbEffects software control and must keep it: the claim is what holds the colour, and releasing it hands every cluster back to the device's own effect engine, which resumes its onboard effect and discards the colour (observed on a G903 LIGHTSPEED). The claim is all-or-nothing, so on a device with a cluster this path cannot light it silently extinguishes that cluster. A G903's Primary cluster (the DPI indicator) accepts every write without error and never lights — not with the fixed effect, not with the cycling effect the firmware itself runs there — so claiming control turns it off with no way to take over. Nothing observable distinguishes that cluster beforehand. - hid: dump_rgb_clusters reports the cluster/effect table plus the current software-control state; release_rgb_control hands the clusters back without a power cycle. - cli: diag lighting gains --info (dump and exit) and --release-control (undo and exit); the colour is required unless one of them is given.
Greptile SummaryAdds HID++ 0x8071 per-cluster solid-color support and exposes it through capability detection and lighting diagnostics.
Confidence Score: 3/5The PR should not merge until failed 0x8071 writes release software control and RGB-specific diagnostics select an actually compatible device. A metadata or effect-write failure can leave onboard lighting disabled after returning an error, and mode-specific CLI operations can target a legacy-lighting device despite a compatible 0x8071 device being online. Files Needing Attention: crates/openlogi-hid/src/write/lighting.rs; crates/openlogi-cli/src/cmd/diag/lighting.rs
|
| Filename | Overview |
|---|---|
| crates/openlogi-hid/src/write/lighting.rs | Adds the 0x8071 write and diagnostic implementation, but failure paths can retain software control and effect lookup uses the table position rather than the returned effect index. |
| crates/openlogi-cli/src/cmd/diag/lighting.rs | Adds RGB diagnostics and shared device selection, but 0x8071-only operations can select a legacy-lighting device. |
| crates/openlogi-core/src/device.rs | Correctly extends measured lighting capability detection to devices exposing only feature 0x8071. |
| crates/openlogi-hid/src/lib.rs | Re-exports the new RGB diagnostic and control types and functions. |
| crates/openlogi-hid/src/write.rs | Exposes the new lighting module API without changing write plumbing. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart TD
UI[GUI or diag color request] --> Auto{Lighting method}
Auto -->|0x8071 available| Claim[Claim ALL_CLUSTERS]
Claim --> Metadata[Read clusters and effects]
Metadata --> Write[Apply fixed effect to each cluster]
Auto -->|No 0x8071| E8070[Try 0x8070 zone effects]
E8070 -->|Unavailable| E8080[Try 0x8080 per-key lighting]
Diag[diag --info or --release-control] --> Select[Select lighting device]
Select --> RGBAPI[Invoke 0x8071-specific API]
Reviews (1): Last reviewed commit: "feat(hid,cli): report and undo 0x8071 so..." | Re-trigger Greptile
| feature | ||
| .set_sw_control( | ||
| SwControlFlags::ALL_CLUSTERS, | ||
| EventsNotificationFlags::empty(), | ||
| ) | ||
| .await | ||
| .map_err(classify_rgb_error)?; |
There was a problem hiding this comment.
Failed writes retain cluster control
When cluster metadata validation or a later effect write fails after ALL_CLUSTERS is claimed, the error path returns without releasing software control, causing onboard lighting to remain disabled and leaving the device dark or partially painted until explicit release or a power cycle.
Knowledge Base Used: openlogi-hid: device inventory, pairing, and HID++ feature control
| })?; | ||
| // The three features `set_keyboard_color` can drive — auto-skip devices with | ||
| // no LEDs to paint. | ||
| let (route, name) = select_device(args.device.as_deref(), &[0x8071, 0x8070, 0x8080]).await?; |
There was a problem hiding this comment.
RGB diagnostics select legacy devices
When a 0x8070- or 0x8080-only device precedes the intended 0x8071 device, the union feature filter selects that legacy device for --info, --release-control, or --method rgb, causing the 0x8071-only operation to fail with FeatureUnsupported despite a compatible device being online.
Knowledge Base Used: OpenLogi CLI
| if info.effect_id == RGB_EFFECT_ID_FIXED { | ||
| return Ok(effect); | ||
| } |
There was a problem hiding this comment.
Use firmware-reported effect index
If firmware reports a cluster_effect_index that differs from the effect table position, returning the loop counter passes the wrong identifier to set_rgb_cluster_effect, selecting another effect or causing the write to be rejected.
| if info.effect_id == RGB_EFFECT_ID_FIXED { | |
| return Ok(effect); | |
| } | |
| if info.effect_id == RGB_EFFECT_ID_FIXED { | |
| return Ok(info.cluster_effect_index); | |
| } |
Knowledge Base Used: openlogi-hid: device inventory, pairing, and HID++ feature control
Summary
Adds support for HID++ RgbEffects (feature
0x8071), the per-cluster RGBeffect engine that succeeds
ColorLedEffects(0x8070). G-series wireless miceexpose
0x8071instead of0x8070: a G903 LIGHTSPEED reports0x8071andneither
0x8070nor0x8080, so its LEDs were unreachable,Capabilities::lightingstayed
false, and it was denied a Lighting tab.The
0x8071protocol wrapper already existed inopenlogi-hidpp— fully typed,tested, and with no consumer anywhere outside that crate. This PR wires it into
the write path and the capability gate. No IPC or config change is needed: the
lighting panel already sends a plain RGB triple, so flipping the capability is
enough to give those devices the existing panel.
The trade-off this ships with
setRgbClusterEffectis refused until software claims the clusters, and the claimis what holds the colour — releasing it hands every cluster back to the device's
effect engine, which resumes its onboard effect and discards the colour. So the
claim cannot be scoped to the write; it lasts until the next colour, a power cycle,
or an explicit release.
The claim is all-or-nothing (
SwControlFlags::ALL_CLUSTERS). On a device with acluster this path cannot light, claiming control extinguishes that cluster. That
is the case on a G903: its
Primarycluster (the DPI indicator) accepts everywrite without error and never lights — not with the fixed effect, and not even
with the cycling effect the firmware itself runs on it. Its logo cluster is
unaffected and takes the colour normally.
Nothing observable distinguishes such a cluster beforehand: the device reports it,
lists a fixed effect for it, and acknowledges the write. So this cannot be detected
and skipped.
diag lighting --release-controlis the escape hatch, and thebehaviour is documented on
set_color_rgb_effects.Worth a maintainer decision: this ships the capability for every
0x8071device.Gating it more narrowly would penalise devices whose clusters all respond, but it
does mean a G903 user picking a colour loses the DPI indicator until they release
control or power-cycle. Happy to restrict it if you would rather not take that.
Changes
set_keyboard_colorgrows an0x8071rung above0x8070/0x8080.It claims software control, reads the cluster count, and applies the fixed
effect to every cluster — a G903's logo and DPI indicator are separate clusters,
so writing only the first leaves it half-painted. The fixed effect is located by
effectIDrather than by a guessed index, since effect indices are per-clusterand firmware-ordered. Volatile, like the
0x8070path. Addsdump_rgb_clusters(cluster/effect table plus the current software-control state) and
release_rgb_control(hands the clusters back without a power cycle).Capabilities::lightingcounts0x8071, so those devices offer theexisting Lighting panel.
diag lightinggains--method rgb,--info(dump the cluster/effecttable and exit) and
--release-control(undo the claim and exit); the colour isrequired unless one of those is given. It now picks its device through
select_device, so it reaches a wireless mouse behind a receiver instead of onlywired keyboards.
RGB_EFFECT_ID_FIXEDis marked in the source as a verified observation rather thana documented constant: the
0x8071spec is not public, so the id follows the0x8070effect vocabulary and was confirmed on hardware.Testing
All green (21 suites). Two CLI parser tests were added for the new
colour-optional cases, and one capability test for an
0x8071-only device.Hardware-verified on Linux against a G903 LIGHTSPEED behind a
046d:c539receiver. That receiver is not recognised on
master, so verification used alocal build with the Lightspeed receiver support from #510/#459 applied; the
changes in this PR are independent of both and touch no file either one touches.
diag lighting --inforeports 2 clusters (location=0x0001Primary,location=0x0002Logo), each listing 4 effects with the fixed effect at index 1.--method rgbandAutoboth drive0x8071,cluster_count=2; red, green,blue, cyan and magenta all applied to the logo cluster.
Autoon a wired PRO Gaming Keyboard logsno 0x8071 cluster engine — trying the 0x8070 zone engineand applies via0x8070(zone_count=2) — the existingpath is unchanged.
--release-controldrops the claim (verified by reading it back:all_clusters=false) and the device resumes its own effect.Not verified: macOS and Windows; any
0x8071device other than a G903; andwhether a device whose clusters all respond exists in the wild — the Primary-cluster
behaviour above is a single-device observation, not a claim about the format.