diff --git a/docs/bragi-protocol.md b/docs/bragi-protocol.md index c1b01a1..c7fd715 100644 --- a/docs/bragi-protocol.md +++ b/docs/bragi-protocol.md @@ -1,136 +1,136 @@ -# Bragi-Protokoll — Reverse-Engineerte Dokumentation +# Bragi Protocol — Reverse-Engineered Documentation -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/`. +This document describes the Corsair Bragi HID protocol used by newer Corsair +wireless devices (HS80 RGB Wireless, HS65, Virtuoso SE, etc.). Reverse-engineered +from USB traces and protocol analysis. -## Übersicht +## Overview -Bragi kommuniziert über HID Feature Reports auf **Interface 3** des USB-Receivers. -Jedes Paket ist 65 Bytes (1 Byte Report ID + 64 Bytes Daten). +Bragi communicates via HID Feature Reports on **Interface 3** of the USB receiver. +Each packet is 65 bytes (1 byte Report ID + 64 bytes data). -## Paketformat +## Packet Format -### Request (Host → Gerät) +### Request (Host → Device) ``` Byte 0: 0x00 — HID Report ID -Byte 1: 0x02 — Protokoll-Marker (immer 0x02) +Byte 1: 0x02 — Protocol marker (always 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 +Byte 4: Property — Property ID (see below) +Byte 5+: Data — For SET: the values to write +Rest: 0x00-padded to 65 bytes ``` -### Response (Gerät → Host) +### Response (Device → 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 0: 0x01 — Report type (always 0x01, NOT 0x02 like the request marker) +Byte 1: Endpoint — 0x00 = Receiver, 0x01 = Headset (different IDs than request!) + On error: 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) +Byte 4+: Data — Property value (typically 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) +**Note:** The response format differs from the request format: +- Byte 0 is `0x01` (not `0x02` like the request marker) +- Endpoint IDs are `0x00`/`0x01` (not `0x08`/`0x09` like in the request) -**Fehler-Erkennung:** Byte 1 == 0xF0 oder 0xF1 bedeutet, dass die Property nicht -unterstützt wird oder der Request ungültig war. +**Error detection:** Byte 1 == 0xF0 or 0xF1 indicates that the property is not +supported or the request was invalid. ## Endpoints -| ID | Name | Beschreibung | +| ID | Name | Description | |------|----------|---------------------------------| -| 0x08 | Receiver | Der USB-Dongle selbst | -| 0x09 | Headset | Das verbundene Wireless-Gerät | +| 0x08 | Receiver | The USB dongle itself | +| 0x09 | Headset | The connected wireless device | ## Commands -| ID | Name | Beschreibung | +| ID | Name | Description | |------|------|-----------------------| -| 0x01 | SET | Property-Wert setzen | -| 0x02 | GET | Property-Wert lesen | +| 0x01 | SET | Set a property value | +| 0x02 | GET | Read a property value | ## Properties -| ID | Name | Typ | Beschreibung | +| ID | Name | Type | Description | |------|-------------------|---------|-----------------------------------------------| -| 0x01 | Polling Rate | uint16 | Polling-Rate in Hz | -| 0x02 | Brightness | uint16 | LED-Helligkeit (0-1000) | +| 0x01 | Polling Rate | uint16 | Polling rate in Hz | +| 0x02 | Brightness | uint16 | LED brightness (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) | +| 0x09 | Sidetone | uint16 | Sidetone level | +| 0x0F | Battery Level | uint16 | Battery in per-mille (0-1000, /10 = percent) | +| 0x10 | Battery Status | uint8 | Charging/discharging status (see below) | | 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 | +| 0x13 | App Firmware | uint16 | Application firmware version | +| 0x14 | Build Firmware | uint16 | Build firmware version | +| 0x15 | Radio App FW | uint16 | Radio application firmware | +| 0x16 | Radio Build FW | uint16 | Radio build firmware | -## Battery Status Werte +## Battery Status Values -Empirisch ermittelt am HS80 RGB Wireless (2026-03-27). -Weicht von ckb-next-Quellen ab — dort sind die Werte anders zugeordnet. +Empirically determined on the HS80 RGB Wireless. +Differs from ckb-next sources where values are mapped differently. -| Wert | Bedeutung | -|------|---------------| -| 0x00 | Offline | -| 0x01 | Laden | -| 0x02 | Entladen | -| 0x03 | Niedrig | -| 0x04 | Voll geladen | +| Value | Meaning | +|-------|---------------| +| 0x00 | Offline | +| 0x01 | Charging | +| 0x02 | Discharging | +| 0x03 | Low | +| 0x04 | Fully charged | -## Initialisierungssequenz +## Initialization Sequence -Das Gerät muss in den Software-Modus versetzt werden, bevor Properties gelesen werden -können. Die vollständige Sequenz: +The device must be switched to software mode before properties can be read. +Full sequence: -### Phase 1: Receiver initialisieren +### Phase 1: Initialize Receiver -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 +1. **Wake-up:** `GET App Firmware` to Receiver (0x08) + - Wakes the receiver and confirms communication +2. **Software mode:** `SET Mode = 0x02` to Receiver (0x08) + - Switches receiver to software mode +3. **Heartbeat:** `GET Product ID` to Receiver (0x08) + - Confirms receiver responds in software mode -### Phase 2: Headset initialisieren +### Phase 2: Initialize Headset -4. **Software-Modus:** `SET Mode = 0x02` an Headset (0x09) - - Schaltet Headset in Software-Modus (via Receiver) -5. **Flush:** HID-Puffer leeren (nonblocking reads bis leer) -6. **Heartbeat:** `GET Product ID` an Headset (0x09) - - Bestätigt dass Headset erreichbar ist und antwortet - - Keine Antwort = Headset ausgeschaltet/nicht verbunden +4. **Software mode:** `SET Mode = 0x02` to Headset (0x09) + - Switches headset to software mode (via receiver) +5. **Flush:** Clear HID buffer (non-blocking reads until empty) +6. **Heartbeat:** `GET Product ID` to Headset (0x09) + - Confirms headset is reachable and responding + - No response = headset powered off / not connected ### Cleanup -Nach allen Abfragen **müssen** beide Geräte zurück in den Hardware-Modus: +After all queries, both devices **must** be switched back to hardware mode: -7. `SET Mode = 0x01` an Headset (0x09) -8. `SET Mode = 0x01` an Receiver (0x08) +7. `SET Mode = 0x01` to Headset (0x09) +8. `SET Mode = 0x01` to 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). +**Important:** Without cleanup the device stays in software mode and may not +behave normally (e.g. no automatic power-off). -## Wert-Extraktion +## Value Extraction -Für uint16-Werte: Little-Endian aus Response-Bytes 4 und 5: +For uint16 values: Little-Endian from response bytes 4 and 5: ``` value = response[4] | (response[5] << 8) ``` -Für Batterie: Wert ist in Promille (0-1000), Division durch 10 ergibt Prozent. +For battery: value is in per-mille (0-1000), divide by 10 for percent. -## USB-Identifikation +## USB Identification - **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. +Other Bragi devices use the same protocol with different Product IDs.