Skip to content

feat(steelseries): add Rival 3 Gen 1 driver (write-only protocol) - #36

Open
simply-justin wants to merge 1 commit into
OpenMouse-Project:mainfrom
simply-justin:steelseries-protocol
Open

feat(steelseries): add Rival 3 Gen 1 driver (write-only protocol)#36
simply-justin wants to merge 1 commit into
OpenMouse-Project:mainfrom
simply-justin:steelseries-protocol

Conversation

@simply-justin

Copy link
Copy Markdown

Adds a codec and WebHID driver for the SteelSeries Rival 3 Gen 1: 1038:1824, plus 1038:184C, which is the same mouse after the v0.37.0.0 firmware update (rivalcfg lists both against one profile, OpenRGB labels 0x1824 "Old Firmware"). Both catalog entries ship verified: false — I don't own the hardware yet, so this is a transcription of public sources, not a tested driver.

Sources: rivalcfg (devices/rival3.py, handlers/multidpi_range_choice.py, devices/dpi/truemove_core.py, mouse.py, usbhid.py) for the command set and the TrueMove Core DPI table, cross-checked against libratbag's driver-steelseries.c and OpenRGB's Rival 3 controller where they overlap (polling values, save id, firmware query, interface 3, unnumbered reports).

The awkward thing about this mouse is that it's write-only. rivalcfg keeps a local JSON mirror because the device can't be asked for its settings, and libratbag flags its SteelSeries profiles RATBAG_PROFILE_CAP_WRITE_ONLY. The only read anywhere is a two-byte firmware query (10 00). So the driver leans on that:

  • the firmware query doubles as the connectivity probe — the config channel is hidapi interface 3, and since I don't know how Chrome presents that collection yet, the filters request the whole device per PID and a wrong interface just times out with a "close SteelSeries GG / pick another entry" error
  • readStatus() reports last-written values (or rivalcfg's defaults before any write) flagged valuesVerified: false, with a note explaining why — it never pretends to have read the mouse
  • setters follow each write with the save command (09 00) like the rivalcfg CLI does, with its 50 ms inter-command delay, and are never retried: with no ack there's no telling "lost" from "applied"
  • setDpi replaces the whole on-device preset table with one preset; read-modify-write isn't possible here, so that's documented rather than worked around

In scope: detection, firmware read, DPI presets (200–8500 in 100 steps, table-encoded), polling rate (125/250/500/1000), save. Not in scope: lighting and buttons (the commands are documented in the codec docblock but no encoders ship), battery, and every other 0x1038 product — filters are PID-scoped because SteelSeries puts keyboards and headsets on the same VID. The Rival 3 Wireless (1830/1872) and Gen 2 (1870) are deliberately not claimed: rivalcfg shows they use different command sets, and the tests pin their rejection so they can land later as their own family modules.

Known unknowns, listed instead of guessed:

  • the WebHID collection shape of interface 3 — first hardware report should include the device.collections dump so the filters can be narrowed
  • firmware byte order — libratbag, rivalcfg and OpenRGB disagree; the decoder returns both bytes, and a 184C unit (known v0.37.x) will settle it
  • whether settings really apply immediately with 09 00 only committing to flash — inferred from rivalcfg's --no-save, not confirmed
  • whether a single-preset DPI write (count = 1) is accepted; rivalcfg allows 1–5 but the two-preset default is what's widely exercised

One deliberate divergence from rivalcfg: it rounds a requested DPI to the nearest table entry, this codec rejects off-grid values, matching how the rest of the package validates.

Tested: npm run check passes (536 tests, including the registry overlap matrix); OpenMouse builds and its test suite passes with the local package installed per CONTRIBUTING, so no matching OpenMouse PR is needed — the only app-visible change is the new "SteelSeries" brand union member. docs/steelseries-testing.md has the hardware checklist for promoting either PID to verified: true; everything on it is physical verification (pointer speed, external rate meter), since there's nothing to read back.

Adds SteelSeries support for the Rival 3 Gen 1 (1038:1824 and its post-0.37
firmware enumeration 1038:184C), transcribed from the public rivalcfg project
and corroborated against libratbag and OpenRGB. The device is write-only: the
codec builds unnumbered output-report frames for DPI presets (TrueMove Core
byte table, 200-8500 in 100 DPI steps), polling rate, and the save command,
and the only read is the two-byte firmware query, which the driver uses as its
connectivity probe. readStatus reports last-written values flagged as
unverified rather than pretending to read them.

Both catalog entries ship verified: false; docs/steelseries-testing.md is the
promotion path. Filters are PID-scoped (never VID-only - 0x1038 also covers
keyboards and headsets), and the different-protocol siblings (Rival 3
Wireless 0x1830/0x1872, Gen 2 0x1870) are deliberately not claimed.
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