Skip to content

Added support for Corsair Virtuoso XT#527

Open
Anshuman01000001 wants to merge 1 commit into
Sapd:masterfrom
Anshuman01000001:master
Open

Added support for Corsair Virtuoso XT#527
Anshuman01000001 wants to merge 1 commit into
Sapd:masterfrom
Anshuman01000001:master

Conversation

@Anshuman01000001
Copy link
Copy Markdown

Adds support for the Corsair Virtuoso XT — both the wireless receiver (0x0a64) and wired USB (0x0a62).

I reverse-engineered the protocol via hidraw probing on Linux. The Virtuoso XT doesn't use the same protocol as CorsairVoidRich or CorsairVoidV2W — it communicates on interface 3 (Usage-Page 0xff42) and responds to a simple 0x02 0x00 battery request:

  • Byte 0: report ID (0x01)
  • Byte 1: status (0xf0 = connected, 0x00 = offline)
  • Byte 2: battery percentage (0-100)

Charging state doesn't appear to be reported over HID. Tested on Arch Linux with the wireless receiver — battery percentage matches the headset's LED indicator.

Capabilities: battery status only for now.

Protocol reverse-engineered via hidraw probing on Linux.

Battery request: 0x02 0x00 on interface 3 (Usage-Page 0xff42)
Response format:
  [0] = 0x01 (report ID)
  [1] = status flags (0xf0 = available, 0x00 = offline)
  [2] = battery percentage (0-100)

Charging state is not reported over HID by this headset.
Volume events are broadcast unsolicited (0x0E 0x01/0x02/0x00)
but are handled by the OS input layer.

Tested on:
  - CORSAIR VIRTUOSO XT Wireless Gaming Receiver (0x0a64)
  - CORSAIR VIRTUOSO XT USB Gaming Headset (0x0a62)

Capabilities: CAP_BATTERY_STATUS
@claude
Copy link
Copy Markdown

claude Bot commented May 27, 2026

Code review

Bug: Battery level not validated against 0-100

File: `lib/devices/corsair_virtuoso_xt.hpp`, lines 98-109

`response[2]` is a `uint8_t` (range 0-255), but `BatteryResult::level_percent` is documented as 0-100 in result_types.hpp. A malformed response could yield 255, which also feeds `time_to_empty_min` with a nonsensical result. Multiple peer devices enforce this bound — `steelseries_arctis_nova_7.hpp` clamps with `if (level > 100) level = 100;`, and `logitech_gpro_x2_lightspeed.hpp` returns `protocolError` if out of range.

Suggested fix after line 98:

```cpp
if (battery_level > 100) {
return DeviceError::protocolError(
std::format("Battery percentage out of range: {}", battery_level));
}
```


CLAUDE.md: Class docblock embeds wire-format table (WHAT not WHY)

File: `lib/devices/corsair_virtuoso_xt.hpp`, lines 13-31 —

/**
* @brief Corsair Virtuoso XT (Wireless + Wired)
*
* Protocol reverse-engineered via hidraw probing on Linux.
*
* Battery request: send 0x02 0x00 on interface 3 (Usage-Page 0xff42)
* Response format (64 bytes):
* [0] = 0x01 (report ID)
* [1] = status flags (0xf0 = normal, TBD for charging)
* [2] = battery percentage (0-100)
* [3+] = zeros (unused)
*
* Volume events are broadcast unsolicited:
* [0] = 0x0E
* [1] = 0x00 (down), 0x01 (up), 0x02 (fast up)
*
* Wireless Product ID: 0x0a64 (receiver)
* Wired Product ID: 0x0a62
*/
class CorsairVirtuosoXT : public CorsairDevice {

The `/** @brief */` block embeds a full byte-offset/hex-value protocol table and lists product IDs already in `SUPPORTED_PRODUCT_IDS`. CLAUDE.md says: "Default to writing no comments. Only add one when the WHY is non-obvious." Compared with `corsair_void_v2w.hpp`, whose docblock only documents non-obvious behavioral quirks, the wire-format table belongs in docs/ or the PR description. Keep only the reverse-engineering provenance note.


CLAUDE.md: Machine-specific device path in committed source

File: `lib/devices/corsair_virtuoso_xt.hpp`, line 70 —

// Send battery status request: 0x02 0x00
// Discovered via hidraw probing on /dev/hidraw11 (interface 3, 0xff42)
std::array<uint8_t, 2> request { 0x02, 0x00 };

The comment `// Discovered via hidraw probing on /dev/hidraw11 (interface 3, 0xff42)` embeds a machine-specific device node from the author's session. CLAUDE.md says: "Don't reference the current task, fix, or callers... since those belong in the PR description and rot as the codebase evolves." The interface (3) and usage-page (0xff42) are already in `getCapabilityDetail`; remove this line.

@Sapd
Copy link
Copy Markdown
Owner

Sapd commented May 27, 2026

Ignore the review about the comments. However the first bug might be relevant.

@Anshuman01000001
Copy link
Copy Markdown
Author

I'll make the required changes. I will also try and adding more features for this headest after resolving this PR, Thanks.

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.

2 participants