Import legacy Super X RGB findings
This commit is contained in:
parent
6417226ac6
commit
b76769d03c
4 changed files with 264 additions and 0 deletions
|
|
@ -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.
|
||||
|
|
|
|||
101
docs/onexplayer-superxcontrol-import-notes.md
Normal file
101
docs/onexplayer-superxcontrol-import-notes.md
Normal 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
|
||||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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)")
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue