- Sleep vor HID-Reads entfernt — read_timeout reicht als Synchronisation, spart ~300ms pro Aufruf - udev-Regel: MODE 0660 + GROUP plugdev statt world-writable 0666 - Eigener CorsairError::SidetoneNotFound für fehlende ALSA-Controls - Response-Validierung vorbereitet (parse_response_validated), Korrelation noch deaktiviert da Response-Format andere Endpoint-IDs nutzt als das Request-Format (0x00/0x01 vs 0x08/0x09) - Protokoll-Doku zum Response-Format korrigiert - 18 neue Tests für output.rs (Waybar-JSON Formatierung + Grenzwerte)
5.1 KiB
Bragi-Protokoll — Reverse-Engineerte Dokumentation
Dieses Dokument beschreibt das Corsair Bragi HID-Protokoll, wie es von neueren
Corsair-Wireless-Geräten (HS80 RGB Wireless, etc.) verwendet wird. Reverse-Engineered
aus USB-Traces und den Python-Probes in ~/Projects/hs80-battery/.
Übersicht
Bragi kommuniziert über HID Feature Reports auf Interface 3 des USB-Receivers. Jedes Paket ist 65 Bytes (1 Byte Report ID + 64 Bytes Daten).
Paketformat
Request (Host → Gerät)
Byte 0: 0x00 — HID Report ID
Byte 1: 0x02 — Protokoll-Marker (immer 0x02)
Byte 2: Endpoint — 0x08 = Receiver, 0x09 = Headset (via Receiver)
Byte 3: Command — 0x01 = SET, 0x02 = GET
Byte 4: Property — Property-ID (siehe unten)
Byte 5+: Daten — Bei SET: die zu setzenden Werte
Rest: 0x00-gepaddet auf 65 Bytes
Response (Gerät → Host)
Byte 0: 0x01 — Report-Typ (immer 0x01, NICHT 0x02 wie im Request)
Byte 1: Endpoint — 0x00 = Receiver, 0x01 = Headset (andere IDs als im Request!)
Bei Fehler: 0xF0/0xF1 = Error/Not Supported
Byte 2: Command — Echo: 0x01 = SET, 0x02 = GET
Byte 3: Status — 0x00 = OK
Byte 4+: Daten — Property-Wert (typisch uint16 Little-Endian in Bytes 4-5)
Achtung: Das Response-Format weicht vom Request-Format ab:
- Byte 0 ist
0x01(nicht0x02wie der Request-Marker) - Endpoint-IDs sind
0x00/0x01(nicht0x08/0x09wie im Request)
Fehler-Erkennung: Byte 1 == 0xF0 oder 0xF1 bedeutet, dass die Property nicht unterstützt wird oder der Request ungültig war.
Endpoints
| ID | Name | Beschreibung |
|---|---|---|
| 0x08 | Receiver | Der USB-Dongle selbst |
| 0x09 | Headset | Das verbundene Wireless-Gerät |
Commands
| ID | Name | Beschreibung |
|---|---|---|
| 0x01 | SET | Property-Wert setzen |
| 0x02 | GET | Property-Wert lesen |
Properties
| ID | Name | Typ | Beschreibung |
|---|---|---|---|
| 0x01 | Polling Rate | uint16 | Polling-Rate in Hz |
| 0x02 | Brightness | uint16 | LED-Helligkeit (0-1000) |
| 0x03 | Mode | uint8 | 0x01 = Hardware, 0x02 = Software |
| 0x09 | Sidetone | uint16 | Sidetone-Level |
| 0x0F | Battery Level | uint16 | Batterie in Promille (0-1000, /10 = Prozent) |
| 0x10 | Battery Status | uint8 | Lade-/Entladestatus (siehe unten) |
| 0x11 | Vendor ID | uint16 | USB Vendor ID |
| 0x12 | Product ID | uint16 | USB Product ID |
| 0x13 | App Firmware | uint16 | Applikations-Firmware-Version |
| 0x14 | Build Firmware | uint16 | Build-Firmware-Version |
| 0x15 | Radio App FW | uint16 | Radio-Applikations-Firmware |
| 0x16 | Radio Build FW | uint16 | Radio-Build-Firmware |
Battery Status Werte
Empirisch ermittelt am HS80 RGB Wireless (2026-03-27). Weicht von ckb-next-Quellen ab — dort sind die Werte anders zugeordnet.
| Wert | Bedeutung |
|---|---|
| 0x00 | Offline |
| 0x01 | Laden |
| 0x02 | Entladen |
| 0x03 | Niedrig |
| 0x04 | Voll geladen |
Initialisierungssequenz
Das Gerät muss in den Software-Modus versetzt werden, bevor Properties gelesen werden können. Die vollständige Sequenz:
Phase 1: Receiver initialisieren
- Wake-Up:
GET App Firmwarean Receiver (0x08)- Weckt den Receiver auf und bestätigt Kommunikation
- Software-Modus:
SET Mode = 0x02an Receiver (0x08)- Schaltet Receiver in Software-Modus
- Heartbeat:
GET Product IDan Receiver (0x08)- Bestätigt dass Receiver im Software-Modus antwortet
Phase 2: Headset initialisieren
- Software-Modus:
SET Mode = 0x02an Headset (0x09)- Schaltet Headset in Software-Modus (via Receiver)
- Flush: HID-Puffer leeren (nonblocking reads bis leer)
- Heartbeat:
GET Product IDan Headset (0x09)- Bestätigt dass Headset erreichbar ist und antwortet
- Keine Antwort = Headset ausgeschaltet/nicht verbunden
Cleanup
Nach allen Abfragen müssen beide Geräte zurück in den Hardware-Modus:
SET Mode = 0x01an Headset (0x09)SET Mode = 0x01an Receiver (0x08)
Wichtig: Ohne Cleanup bleibt das Gerät im Software-Modus und verhält sich möglicherweise nicht normal (z.B. keine automatische Abschaltung).
Wert-Extraktion
Für uint16-Werte: Little-Endian aus Response-Bytes 4 und 5:
value = response[4] | (response[5] << 8)
Für Batterie: Wert ist in Promille (0-1000), Division durch 10 ergibt Prozent.
USB-Identifikation
- Vendor ID: 0x1B1C (Corsair)
- Product ID: 0x0A6B (HS80 RGB Wireless)
- Interface: 3 (HID Control Interface)
Andere Bragi-Geräte verwenden dasselbe Protokoll mit unterschiedlichen Product IDs.