Import legacy Super X RGB findings

This commit is contained in:
Kay Türtscher 2026-05-25 11:43:37 +02:00
parent 6417226ac6
commit b76769d03c
4 changed files with 264 additions and 0 deletions

View file

@ -14,6 +14,8 @@ Aktueller Stand
- Fan-/EC-Themen sind teils schon im Kernel/hhd-Land sichtbar.
- Für Frostbay gibt es sehr frische Community-Arbeit.
- Für Super-X-RGB/Keyboard ist noch viel Nebel da. Da müssen wir ziemlich sicher selbst reverse engineeren.
- Das alte Repo `onexplayer-superxcontrol` wurde inzwischen als Referenzquelle gegengeprüft; relevante Legacy-HID-Pakete und Statusnotizen wurden in dieses Repo übernommen.
- In `~/Downloads` liegen zusätzlich OEM-Artefakte wie `frostbay firmware.zip` und `HH-GA25-SUPERX-Devices_V1.0.zip`, die wir weiter ausschlachten können.
Wichtige Hinweise
- Deine ersetzten RGB-Stripes sind WS2812B. Das ist hilfreich, aber nicht die eigentliche Linux-Baustelle.

View file

@ -0,0 +1,101 @@
# Import-Notizen aus `onexplayer-superxcontrol`
Stand: 2026-05-26
Quelle: `https://git.nepharius.at/nepharius/onexplayer-superxcontrol`
Lokal gespiegelt nach: `/home/nepharius/.cache/onexplayer-superxcontrol-old`
## Kurzfazit
Ja, das alte Repo ist brauchbar.
Nicht als fertige Wahrheit, aber als ziemlich gute Spurensammlung.
Am wertvollsten für `SuperX-goes-Arch` sind daraus gerade vier Blöcke:
1. alte konservative HID-Paketfamilie für `1a86:1305` Interface `02`
2. klare Trennung zwischen funktionierendem Keyboard-/internem RGB-Pfad und blockiertem Deckel-/Logo-Pfad
3. Frostbay-Tooling und BLE-/Status-Skripte als Referenzbasis
4. WMI/CMS/EC-Testwerkzeuge für den Fall, dass wir den proprietären OEM-Pfad weiter einkreisen müssen
## Was das alte Repo explizit behauptet
### 1) RGB-Hauptkandidat
- USB VID:PID `1a86:1305`
- Interface `02`
- typischer Linux-Pfad: `/dev/hidraw2`
- udev-Regel im alten Repo erlaubt genau diese Kombination
Quelle:
- `oxp-rgb-hid.py`
- `oxp-rgb-hid.rules`
### 2) Konservative Legacy-Paketfamilie
Im alten Repo dokumentiert bzw. implementiert:
- enable: `07 ff 05 00`
- level off: `07 ff fd 00 05 01`
- level 1: `07 ff fd 01 05 01`
- level 2: `07 ff fd 01 05 03`
- level 3: `07 ff fd 01 05 04`
- static mode: `07 ff fd 00 05 04`
- rainbow mode: `07 ff fd 01 05 04`
- preset range: `0x00..0x16`
- static color family: `07 ff fe RR GG BB ...`
Diese Familie wurde jetzt in `tools/superx_hidraw_rgb.py` als referenzierbare Legacy-Hilfe übernommen.
### 3) Blockierter Deckel-/Logo-RGB-Pfad
`DECKEL_RGB_STATUS.md` sagt ziemlich klar:
- Frostbay funktioniert
- Keyboard-/internes RGB funktioniert laut damaligem Stand
- Deckel-/Logo-RGB bleibt ungelöst
- erfolglos getestet wurden:
- HID-Route
- WMI EC-Memory / `WMBB method 6`
- WMI CMS / `WMBB method 4`
Das ist wichtig, weil es die Theorie stärkt:
- Nicht alles RGB hängt am gleichen Pfad.
- Ein proprietärer Init-/Unlock-/Handshake-Schritt ist realistisch.
### 4) Frostbay-Reverse-Engineering ist weiter als nur ein vager Plan
Das alte Repo enthält bereits:
- `tools/frostbay-ble-control.py`
- `tools/frostbay-ble-dump.py`
- `tools/frostbay-native-test.sh`
- `tools/oxp-frostbay-status.py`
- zusätzliche Diagnose-/Vergleichswerkzeuge
Das heißt: für Frostbay starten wir nicht bei null.
## Einordnung für dein Gerät mit WS2812B-Ersatzstripes
Bekannte lokale Fakten:
- Ersatzstripes sind WS2812B
- du vermutest Anschluss `RGB2`
Das alte Repo hilft hier so:
- Es bestätigt, dass ein OEM-/Vendor-RGB-Pfad auf dem Super X existiert.
- Es liefert konkrete kleine Testframes statt blindem Raten.
- Es beweist aber nicht, dass dein umgebauter Strip logisch 1:1 wie der damalige Zielpfad reagiert.
Darum bleibt die sichere Arbeitsregel:
- alte Pakete erst dry-run / katalogisieren
- nur kleine reversible Tests
- Beobachtung mitloggen
- OEM-Helper-/CompatLayerCT-Semantik weiter parallel auswerten
## Konkrete Übernahmen in `SuperX-goes-Arch`
Bereits übernommen:
- `docs/safe-test-frames.md` erweitert
- `tools/superx_hidraw_rgb.py` kann Legacy-Pakete jetzt katalogisieren und dry-run erzeugen
Noch sinnvoll für später:
- Frostbay-Tooling gezielt sichten und in ein eigenes `tools/frostbay/`-Layout überführen
- udev-Regel-Entwurf für `1a86:1305` Interface `02`
- Vergleichsmatrix alt vs. neu: `hidraw1`, `hidraw2`, CompatLayerCT, Frostbay
## Offene Vorsichtspunkte
- "funktioniert" im alten Repo heißt nicht automatisch "funktioniert identisch auf deinem reparierten Strip"
- das alte Repo trennt Keyboard-/internes RGB nicht immer perfekt sprachlich vom Deckel-/Logo-Pfad
- für Repo-Erstellung auf `git.nepharius.at` fehlt hier aktuell gültige Authentifizierung; HTTPS-lesen geht, SSH-Schreiben gerade nicht
## Nächster sinnvoller Schritt
1. Legacy-Pakete nur lokal dry-run prüfen
2. Frostbay-ZIP in `~/Downloads` auswerten und mit altem Frostbay-Tooling abgleichen
3. dann ein sauber strukturiertes Repo-Layout für `SuperX-goes-Arch` weiter ausbauen

View file

@ -35,6 +35,35 @@ Passend zu:
- `/programhandle/rgb/setColor/16/16/16`
- später erst `assignSetColor`
## Importierte Legacy-HID-Familie aus `onexplayer-superxcontrol`
Die alte public tree behauptet für den Super X eine konservative Paketfamilie auf
`1a86:1305` Interface `02` / typischerweise `hidraw2`.
Konkret importiert in `tools/superx_hidraw_rgb.py`:
- Mode `enable`: `07 ff 05 00`
- Level `off`: `07 ff fd 00 05 01`
- Level `1`: `07 ff fd 01 05 01`
- Level `2`: `07 ff fd 01 05 03`
- Level `3`: `07 ff fd 01 05 04`
- Mode `static`: `07 ff fd 00 05 04`
- Mode `rainbow`: `07 ff fd 01 05 04`
- Preset safe range: `0x00..0x16`
- Static color family: `07 ff fe RR GG BB ...`
Wichtig:
- Das sind jetzt Referenzframes, keine Wahrheitsgarantie.
- Sie sind wertvoll, weil sie aus älteren Super-X-Artefakten kommen und nicht
komplett geraten sind.
- Trotzdem zuerst dry-run und Beobachtungsprotokoll, weil unklar bleibt, ob dein
aktueller WS2812B-Ersatzpfad exakt gleich reagiert.
## Praktische Dry-Run-Beispiele
- `python tools/superx_hidraw_rgb.py legacy-catalog`
- `python tools/superx_hidraw_rgb.py legacy-packet mode enable --dry-run`
- `python tools/superx_hidraw_rgb.py legacy-packet level 3 --dry-run`
- `python tools/superx_hidraw_rgb.py legacy-packet preset 0x03 --dry-run`
- `python tools/superx_hidraw_rgb.py legacy-packet static probe 16 8 4 --dry-run`
## Aktueller Arbeitsgrundsatz
CompatLayerCT ist jetzt klar genug, dass wir die OEM-Semantik zuerst festhalten.
Dann machen wir lieber 3 gute Proben als 300 dumme.

View file

@ -11,6 +11,19 @@ from pathlib import Path
DEFAULT_DEVICE = "/dev/hidraw2"
DEFAULT_REPORT_LEN = 64
LEGACY_BRIGHTNESS_LEVELS = {
"off": [0x07, 0xFF, 0xFD, 0x00, 0x05, 0x01],
"1": [0x07, 0xFF, 0xFD, 0x01, 0x05, 0x01],
"2": [0x07, 0xFF, 0xFD, 0x01, 0x05, 0x03],
"3": [0x07, 0xFF, 0xFD, 0x01, 0x05, 0x04],
}
LEGACY_MODE_PACKETS = {
"enable": [0x07, 0xFF, 0x05, 0x00],
"static": [0x07, 0xFF, 0xFD, 0x00, 0x05, 0x04],
"rainbow": [0x07, 0xFF, 0xFD, 0x01, 0x05, 0x04],
"alt-static": [0x07, 0xFF, 0xFD, 0x01, 0x05, 0x04],
}
LEGACY_SAFE_PRESET_IDS = set(range(0x00, 0x17))
def eprint(*args, **kwargs):
@ -75,6 +88,36 @@ def pad_payload(data: bytes, length: int, exact: bool) -> bytes:
return data + bytes(length - len(data))
def build_legacy_static(red: int, green: int, blue: int) -> bytes:
for value in (red, green, blue):
if value < 0 or value > 255:
raise ValueError("RGB values must be in range 0-255")
payload = [0x07, 0xFF, 0xFE]
payload.extend([red, green, blue] * 20)
payload.append(0x00)
return bytes(payload)
def build_legacy_mode(mode: str) -> bytes:
try:
return bytes(LEGACY_MODE_PACKETS[mode])
except KeyError as exc:
raise ValueError(f"unsupported legacy mode: {mode}") from exc
def build_legacy_level(level: str) -> bytes:
try:
return bytes(LEGACY_BRIGHTNESS_LEVELS[level])
except KeyError as exc:
raise ValueError(f"unsupported legacy level: {level}") from exc
def build_legacy_preset(preset_id: int) -> bytes:
if preset_id not in LEGACY_SAFE_PRESET_IDS:
raise ValueError("legacy preset id must be in safe range 0x00..0x16")
return bytes([0x07, 0xFF, preset_id, 0x00, 0x00])
def open_for_write(device: str):
return os.open(device, os.O_RDWR | os.O_NONBLOCK)
@ -136,6 +179,78 @@ def cmd_info(args):
return 0
def cmd_legacy_catalog(args):
items = [
{
"kind": "mode",
"name": name,
"hex": bytes(values).hex(),
"why": "übernommene konservative Paketfamilie aus altem onexplayer-superxcontrol-Repo",
}
for name, values in LEGACY_MODE_PACKETS.items()
]
items.extend(
{
"kind": "level",
"name": name,
"hex": bytes(values).hex(),
"why": "übernommene konservative Brightness-/OnOff-Pakete aus altem onexplayer-superxcontrol-Repo",
}
for name, values in LEGACY_BRIGHTNESS_LEVELS.items()
)
if args.json:
import json
print(json.dumps(items, indent=2))
else:
for item in items:
print(f"{item['kind']} {item['name']}: {item['hex']} | {item['why']}")
return 0
def cmd_legacy_packet(args):
if args.kind == "mode":
payload = build_legacy_mode(args.value)
elif args.kind == "level":
payload = build_legacy_level(args.value)
elif args.kind == "preset":
payload = build_legacy_preset(int(args.value, 0))
elif args.kind == "static":
if len(args.rgb) != 3:
raise ValueError("static braucht drei RGB-Werte")
payload = build_legacy_static(args.rgb[0], args.rgb[1], args.rgb[2])
else:
raise ValueError(f"unsupported legacy kind: {args.kind}")
final = pad_payload(payload, args.length, args.exact_length)
print(f"legacy_kind: {args.kind}")
print(f"legacy_value: {args.value}")
if args.kind == "static":
print(f"legacy_rgb: {args.rgb}")
print(f"write_len: {len(final)}")
print(f"write_hex: {final.hex()}")
if args.dry_run:
print("dry-run: no bytes written")
return 0
try:
fd = open_for_write(args.device)
except OSError as exc:
eprint(f"open failed: {exc}")
return 2
try:
written = os.write(fd, final)
print(f"written: {written}")
if args.read_reply_ms > 0:
wait_for_reply(fd, args.read_reply_ms)
except OSError as exc:
eprint(f"write failed: {exc}")
return 3
finally:
os.close(fd)
return 0
def cmd_write_hex(args):
payload = parse_hex(args.hex_payload)
final = pad_payload(payload, args.length, args.exact_length)
@ -268,6 +383,9 @@ def build_parser():
"""
Examples:
superx_hidraw_rgb.py info
superx_hidraw_rgb.py legacy-catalog
superx_hidraw_rgb.py legacy-packet mode enable --dry-run
superx_hidraw_rgb.py legacy-packet static hold 16 8 4 --dry-run
superx_hidraw_rgb.py write-hex 00 --dry-run
superx_hidraw_rgb.py write-hex '00 01 02 03' --length 64
superx_hidraw_rgb.py read --timeout-ms 500
@ -286,6 +404,20 @@ def build_parser():
info = sub.add_parser("info", help="show access + descriptor info")
info.set_defaults(func=cmd_info)
lc = sub.add_parser("legacy-catalog", help="print imported legacy packet families from the old repo")
lc.add_argument("--json", action="store_true", help="emit JSON instead of plain text")
lc.set_defaults(func=cmd_legacy_catalog)
lp = sub.add_parser("legacy-packet", help="build or send one imported legacy packet family")
lp.add_argument("kind", choices=["mode", "level", "preset", "static"], help="legacy packet family")
lp.add_argument("value", help="mode/level name, preset id, or free label for static")
lp.add_argument("rgb", nargs="*", type=int, help="RGB values for kind=static")
lp.add_argument("--length", type=int, default=DEFAULT_REPORT_LEN, help="pad target length (default: 64)")
lp.add_argument("--exact-length", action="store_true", help="require exact payload length instead of padding")
lp.add_argument("--dry-run", action="store_true", help="print final frame only")
lp.add_argument("--read-reply-ms", type=int, default=0, help="optionally wait for one reply after write")
lp.set_defaults(func=cmd_legacy_packet)
wh = sub.add_parser("write-hex", help="write a raw output report")
wh.add_argument("hex_payload", help="hex bytes, e.g. '00 ff 12 34'")
wh.add_argument("--length", type=int, default=DEFAULT_REPORT_LEN, help="pad target length (default: 64)")