corsairctl/docs/bragi-protocol.md
nevaforget a9d526023d fix: Audit-Findings behoben (Perf, Security, Quality)
- 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)
2026-03-27 23:11:50 +01:00

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 (nicht 0x02 wie der Request-Marker)
  • Endpoint-IDs sind 0x00/0x01 (nicht 0x08/0x09 wie 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

  1. Wake-Up: GET App Firmware an Receiver (0x08)
    • Weckt den Receiver auf und bestätigt Kommunikation
  2. Software-Modus: SET Mode = 0x02 an Receiver (0x08)
    • Schaltet Receiver in Software-Modus
  3. Heartbeat: GET Product ID an Receiver (0x08)
    • Bestätigt dass Receiver im Software-Modus antwortet

Phase 2: Headset initialisieren

  1. Software-Modus: SET Mode = 0x02 an Headset (0x09)
    • Schaltet Headset in Software-Modus (via Receiver)
  2. Flush: HID-Puffer leeren (nonblocking reads bis leer)
  3. Heartbeat: GET Product ID an 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:

  1. SET Mode = 0x01 an Headset (0x09)
  2. SET Mode = 0x01 an 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.