Skip to content

[Endgame Gear] OP1 RGB (0x1905) wired: no answer to OT profile block 0 — first hardware report against unverified OT driver #237

Open

Description

@snekxs

Hardware report (from Discord bug-report thread)

Mouse: Endgame Gear OP1 RGB (PID 0x1905, VID 0x3367), wired
Firmware: V1.11.166 (reported by user)
Browser: Opera GX (Core 129.0.5823.64, Chromium 145.0.7632.117)
OS: Windows 10
Repro: click "add mouse" → select the OP1 RGB → handshake fails
Error: Connection failed — The mouse did not answer OT profile block 0.
Note: user's other (non-OT) mice connect fine in the same browser, so WebHID itself works. No OpenMouse diagnostics were attached.

Findings from code inspection

  • The error string comes from queryBlock() in src/drivers/endgame/egg-ot-hid.ts. loadProfile() queries the main block (block 0) first, so this failure means the mouse never answered the very first kComQueryProfileData (COMTYPE.queryProfileData = 51) packet — not a later/RGB-specific block.
  • The OT driver (src/endgame-gear/ot.ts, added in feat: add Endgame Gear XM1r/OP1/OP1 RGB protocol, driver, and per-device feature lists #199) is explicitly recognition-grade, never exercised on hardware: "None of this has been exercised on hardware yet." Framing, COMTYPE table, effect layout, and block surgery were all derived from the vendor Electron app sources ("Endgame Gear Configuration Software" v1.6.400), not wire captures. This report is the first hardware data point, and it fails at step one.
  • The web app lists OP1 RGB (0x1905) as supported (supported-devices-data.ts), so users will keep hitting this.
  • Suspects, in rough likelihood order:
    1. ACK/response sequencing mismatch — exchange() requires an ack (20) followed by a second packet; if firmware 1.11.166 answers with a single response (21) or a different COMTYPE, the reply is swallowed and the block times out (OT_READ_RETRIES = 10, 3 s per read).
    2. Query precondition missing — vendor loader may send queryProfile (13) / activateProfile (12) or a light/mouse query before queryProfileData; we go straight to block queries.
    3. Report-length / report-id framing — report id 0 with featurePayloadLength() fallback; Opera GX WebHID may return a different feature-report size than Chrome.
    4. Firmware generation gap — codecs target vendor app v1.6.400; mouse runs fw 1.11.166. Packet-id handling or header echo may differ.

Suggested next steps

  • Ask the reporter for: HID collection string (describeCollections() output), opera://hid-internals (or opera://device-log) entries for VID 3367, whether the vendor config software was running (exclusive HID lock), and a retry in Chrome/Edge to isolate an Opera GX WebHID quirk.
  • Add a debug path that logs the raw reply bytes (or timeout) of the block-0 query so the next report shows what came back instead of just "no answer".
  • Consider downgrading OP1 RGB (and XM1r/OP1) to preview/experimental in the web app until one successful hardware handshake is on record.
  • Capture a vendor-tool session (USB pcap) of a block-0 query against fw 1.11.166 to confirm the expected ACK/response sequence.

No duplicate open issue found in mouse-protocol or openmouse (searched "OP1", "OT", "Endgame").

Activity

  1. added
    bugSomething isn't working
    area: protocolProtocol codecs and shared types
    area: driversDevice drivers and transport integration
    on Oct 17, 2026
  2. snekxs commented on Oct 17, 2026

    @snekxs
    MemberAuthor

    Update from the reporter (Discord thread): in Chrome, the OP1 RGB does not appear in the HID picker at all (only Lamzu dongle, a generic "HID device" entry, and an Alux68). In Opera GX it was selectable and failed at block 0. Notes: the app's HID filter covers the whole Endgame VID (0x3367), so the mouse should be listed if Windows exposes it — the generic "HID device" entry may be the OP1 RGB without a product string. Asked reporter to try selecting that entry, retry in Chrome/Edge, and check whether vendor software holds an exclusive lock.

  3. snekxs commented on Oct 17, 2026

    @snekxs
    MemberAuthor

    Further update: reporter tried connecting in Chrome and got a bare write refusal ("Connection failed — Failed to write the feature report."). Per the driver's own notes (cf. razer/hid.ts, corsair/hid.ts), Chrome surfaces a refused feature-report write as a bare NotAllowedError — typical causes are the control interface being held by another program (vendor config tool / Synapse), the wrong interface picked on a multi-interface device, or the OS refusing writes to mouse-class collections. Asked which picker entry they chose (Alux68 is a keyboard and the Lamzu entry is a different mouse's dongle — neither should be picked for the OP1 RGB) and whether vendor software was running.

  4. snekxs commented on Oct 17, 2026

    @snekxs
    MemberAuthor

    Reporter ran the unplug test: with the OP1 RGB unplugged, the generic "HID device" picker entry no longer appears. So that entry IS the OP1 RGB (it exposes no product string). Selecting it in Chrome yields a bare feature-report write refusal; in Opera GX it was selectable but never answered the block-0 query. Chrome sees the mouse but cannot write to it — consistent with the control interface being held elsewhere or the wrong interface being granted.

  5. snekxs commented on Oct 17, 2026

    @snekxs
    MemberAuthor

    Bridge ruled out: with Bridge v1.0.0-beta.15 fully quit, the bare feature-report write refusal reproduces in BOTH Opera GX and Chrome when the OP1 RGB (confirmed as the generic HID-device entry) is picked. Remaining suspects: vendor config software holding the interface, or an OS-level write refusal on this device/collection.

  6. snekxs commented on Oct 17, 2026

    @snekxs
    MemberAuthor

    Trace arrived: tx payload is byte-correct (0x33 = queryProfileData, packet id 0, block 0, profile 0, zero-padded). sendFeatureReport threw NotAllowedError on the FIRST attempt, so no rx exists and the mouse never saw anything. Conclusion: transport-level write refusal, not a protocol/format problem. open() succeeded, so this is not an exclusive-lock-on-open failure — it points at a write refusal on this collection (protected mouse-class collection?) or a lock acquired after open. Open: log describeCollections() for this device (usage pages will tell whether report-0 lives on a protected collection), confirm vendor tools closed, second-PC test.

  7. snekxs commented on Oct 17, 2026

    @snekxs
    MemberAuthor

    Collections arrived: usage 0xffa1:0xa5, feature 0x0. That is a vendor-defined page, NOT a protected mouse-class collection — so Chrome protected-usage policy is ruled out. open() succeeds, report 0 exists, packet bytes are correct, yet the first sendFeatureReport is refused. Remaining: another process holding the interface (vendor tool still not confirmed closed), or an OS-level write block on this device.

  8. snekxs commented on Oct 18, 2026

    @snekxs
    MemberAuthor

    New trace from reporter, qualitatively different: (1) writes now SUCCEED — the NotAllowedError is gone, so the write refusal is resolved (different granted entry and/or lock released). (2) Granted device now exposes the full composite: 0x0c:0x01, 0x01:0x80, 0x01:0x06, 0x01:0x02 (x2?), plus 0xffa1:0xa5 feature 0x0 — previously only the vendor collection was reported, so a different entry was picked this time. (3) Both the firmware query (tx 0x11) and the profile block-0 query (tx 0x33) get all-zero replies, 10 reads each, repeatedly — the device answers feature-report reads with empty data. Reads-empty (not refused) points at report-0 reads landing on the wrong collection of the composite device, or the mouse stalling (Chrome zero-fills). Next: verify which entry was picked, and consider addressing the control collection explicitly rather than report id 0 on the whole device.

  9. snekxs commented on Oct 18, 2026

    @snekxs
    MemberAuthor

    Latest trace (post-#241, vendor-only entry): password tx (0x13 + static vendor password, as designed) then block-0 tx (0x33), then raw write refusal again. Key contrast now on record: the vendor-only entry (ffa1:a5) REFUSES writes, while the composite entry from the previous attempt ACCEPTED writes but returned all-zero reads. Same physical mouse, opposite failure modes per granted entry. Suggests the two picker entries are different USB interfaces of the OP1, neither fully usable yet: one locked/refused at write, the other writeable but report-0 reads land nowhere (or need per-collection addressing). The static-password bytes in the trace are expected per #241, not a leak.

  10. snekxs commented on Oct 18, 2026

    @snekxs
    MemberAuthor

    Reporter clarifies: the composite-entry trace (writes OK, all-zero reads) was WITH Bridge running; the vendor-only write-refusal trace was with Bridge OFF. So the two failure modes are per-transport, not per-interface: via Bridge shim, writes succeed but feature-report reads come back empty (shim forwarding gap? or device stalls); via raw WebHID, Chrome refuses the write outright. Next: determine whether zero-reads via Bridge are a shim artifact (test another known-good mouse via Bridge reads?) versus the OP1 returning empties.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    area: driversDevice drivers and transport integrationarea: protocolProtocol codecs and shared typesbugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions