fix(hid): surface the 0xc539 dongle as a Lightspeed receiver, not Unifying - #665
Open
yuzi-co wants to merge 1 commit into
Open
fix(hid): surface the 0xc539 dongle as a Lightspeed receiver, not Unifying#665yuzi-co wants to merge 1 commit into
yuzi-co wants to merge 1 commit into
Conversation
…fying 0xc539 is the receiver bundled with the G502 LIGHTSPEED and the G Pro Wireless. It sat in UNIFYING_PIDS, so receiver_display_name() labelled it "Unifying Receiver" in the inventory — even though its own doc comment called it "the Lightspeed gaming receiver", and the device's USB product string is literally "LIGHTSPEED Receiver". The split between UNIFYING_PIDS and LIGHTSPEED_PIDS exists only to pick that label: LIGHTSPEED_PIDS' doc says "only the user-facing receiver name differs". So having 0xc539 on the Unifying side defeated the one purpose the split has, for exactly the PID whose doc already identified it. Move it to LIGHTSPEED_PIDS. Routing is unaffected: every consumer of the two lists uses their union — speaks_unifying_protocol() ORs them, is_receiver_pid() builds on that, and transport.rs chains them — so receiver_display_name() is the only behaviour that changes. Both device_route_for_* tests keep asserting a Unifying route; 0xc539 just moves from one loop to the other. The existing test covered 0xc53f, 0xc547 and 0xc52b but never 0xc539, which is why the mismatch survived. Add it, plus 0xc532 for the other side. Reverting the constant alone now fails the test with left: "Unifying Receiver".
Greptile SummaryThis PR correctly reclassifies receiver PID
Confidence Score: 5/5The PR appears safe to merge with no actionable defects identified. The receiver remains in the union used by every routing, enumeration, and pairing consumer, while the changed list membership only corrects its user-facing display name and is covered by regression tests.
|
| Filename | Overview |
|---|---|
| crates/openlogi-core/src/hid/route.rs | Reclassifies PID 0xc539 for display naming without changing protocol detection, routing, enumeration, or pairing behavior. |
Reviews (1): Last reviewed commit: "fix(hid): surface the 0xc539 dongle as a..." | Re-trigger Greptile
|
@pyr02k1 I have same mouse, I can help as well |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

The bug
receiver_display_name(0xc539)returns"Unifying Receiver". It should return"Lightspeed Receiver".0xc539is the receiver bundled with the G502 LIGHTSPEED and the G Pro Wireless. It was listed inUNIFYING_PIDS, so theelsebranch ofreceiver_display_namecaught it.Three things in the repo already disagreed with that placement:
UNIFYING_PIDS' own doc comment called it "the Lightspeed gaming receiver: a distinct product line".LIGHTSPEED_PIDS' doc comment states the split's entire purpose: "only the user-facing receiver name (seereceiver_display_name) differs." Both lists route identically — the label is the only thing the split decides. So putting0xc539on the Unifying side defeated the one job the split has, for exactly the PID whose doc already identified it as Lightspeed.The device itself. Its USB product string is
LIGHTSPEED Receiver:OpenLogi enumerated a dongle that names itself
LIGHTSPEED Receiverand relabelled itUnifying Receiver.Reproduced on real hardware: G502 LIGHTSPEED on a
046d:c539receiver, Windows 11.The fix
Move
0xc539fromUNIFYING_PIDStoLIGHTSPEED_PIDS.Why this is behaviour-safe
Every consumer of the two lists uses their union, never one alone:
speaks_unifying_protocol()UNIFYING_PIDS ∪ LIGHTSPEED_PIDSis_receiver_pid()BOLT_PIDS ∪ speaks_unifying_protocol()DeviceRoute::for_inventoryspeaks_unifying_protocol()openlogi-hid/src/transport.rs:243.chain(UNIFYING_PIDS).chain(LIGHTSPEED_PIDS)(Confirmed by
grep -rn "UNIFYING_PIDS\|LIGHTSPEED_PIDS" --include=*.rs— every other hit is a re-export.)So
0xc539still routes asDeviceRoute::Unifying, still enumerates and pairs through the Unifying HID++ 1.0 register path, and is still recognised as a receiver.receiver_display_nameis the only behaviour that changes.The two routing tests both keep passing unchanged —
device_route_for_unifying_pids_create_unifying_routeanddevice_route_for_lightspeed_pids_create_unifying_routeboth assert a Unifying route, so0xc539simply moves from one loop to the other.receiver_display_nameis called from exactly one place (inventory/probe.rs:257, insideprobe_unifying_receiver). Bolt never reaches it —assemble_bolt_probehardcodes"Logi Bolt Receiver"at line 120 — so theelsebranch stays correct as the Unifying default.Why it survived
The existing test enumerated
0xc53f,0xc547and0xc52b, but never0xc539— the one PID sitting on the wrong side. Added, along with0xc532for symmetry on the Unifying side.The added assertion is a real regression test. Reverting only the constant change and rerunning:
Local gate
Per AGENTS.md, on Windows 11 / x86_64-pc-windows-msvc:
cargo fmt --all -- --checkcargo clippy --workspace --all-targets -- -D warningscargo test --workspaceRUSTDOCFLAGS="-D warnings" cargo doc -p openlogi-hid …The rustdoc failure is not from this change and does not touch these files:
It reproduces on a clean
masteron Windows and is fixed by #661. CI does not see it because the docs job runs on ubuntu, whereAsyncHidChannelis notcfg-ed out.How it happened
Traced through
git logon the file.0xc539was not misfiled — it was stranded:0xc539toUNIFYING_PIDS. Correct at the time —LIGHTSPEED_PIDSandreceiver_display_namedid not exist yet, so there was only one list to put it in. This PR also wrote the comment that still says "the Lightspeed gaming receiver: a distinct product line".LIGHTSPEED_PIDS = [0xc53f]andreceiver_display_name, inventing the "Lightspeed receivers get their own name" concept — and wrote the test asserting0xc53f→ Lightspeed,0xc52b→ Unifying. It did not move0xc539.0xc547to the new list.So the naming concept was introduced after
0xc539had already been filed under Unifying, and nothing migrated it. The test hole follows from the same order: #388's test enumerated the PIDs #388 itself added, plus one Unifying control —0xc539was in neither group.This PR completes the migration #388 started.
Relationship to #351
#351 (
feat(hid): support LIGHTSPEED receivers and RGB effects) already does this, as part of a much larger change — it definesLIGHTSPEED_PIDSas[0xc539, 0xc53a, 0xc53d, 0xc53f, 0xc541, 0xc545, 0xc547, 0xc54d]. Flagging it explicitly so this isn't reviewed as if it were novel.If #351 lands, close this as superseded — it is a strict subset. Offered separately because #351 is currently
CONFLICTINGat +1523/−267 across 42 files and has been open since 2026-07-04, while this is a one-constant fix with a regression test that can land independently and be trivially reverted. The two touch the same lines, so whichever merges second will need a trivial conflict resolution.Related tracking issue: #512.