# versapad-viewer Eigenes kleines Tool (Grovy311-Kontext, nicht Teil der fremden jappel-Repos VersaGUI/VersaMCU). Zeigt die Steuermatrix (4x5 Button-Grid + 4 Encoder) als Browser-Live-Seite oder natives Tkinter-Fenster. Inzwischen mehr als ein reiner Viewer: der Tkinter-Desktop-Viewer hat einen vollen Programmiermodus (Action-Editor, Serial-Schreibzugriff aufs Board, Makro-Editor) bekommen — faktisch ein schlankes Python-Pendant zu VersaGUI. Der Browser-Server (`server.py`) blieb bewusst read-only/einfach. ## Architektur **Read-only-Schicht (JSON, beide Frontends):** - `versapad_data.py` — Decoding fuer Anzeige: JSON laden, HID-Keycode/ Consumer-Usage/Modifier → lesbarer Text, Grid-Geometrie (index = spalte*5+reihe), `hid_key_choices()`/`consumer_choices()` fuer Dropdowns. - `server.py` — stdlib `http.server`, generiert HTML bei jedem Request neu, Profil-Wechsel über `?profile=0|1|2`, Auto-Reload alle 4s. Rein lesend, kein Programmiermodus (bewusst einfach gehalten). **Binaer-/Serial-Schicht (fuer den Programmiermodus):** - `versapad_protocol.py` — pack/unpack fuer `SDeviceConfig`(740B, alle 3 Profile) und `SMacroTable`(512B, 32 Slots) + CRC16 (Poly 0x1021, Init 0xFFFF), 1:1 aus den Firmware-Structs (`nvm_config.h`, `action.h`, `macro_config.h`, `CButton.h`-LEDAnim-Enum, `nvm_config.cpp`-CRC). **Gegen echtes Board validiert:** read → unpack → pack → byte-identisch zum Original, inkl. CRC — siehe Git-Historie dieser Datei / Sessionlog. - `versapad_serial.py` — `VersaPadLink`: liest/schreibt komplette Config + Makros per 8-Byte-Paket-Protokoll (`CmdConfigRead/Begin/Data/Commit`, `CmdMacroRead/Begin/Data/Commit`), Board-Identifikation per VID/PID `239A:0042`. Schreiben ist sicher im Sinne von "kann NVM nicht zerlegen" — Firmware prueft Magic/CRC/Keycode-Bereich vor jedem Save und antwortet sonst nur mit NACK (kein Datenmuell moeglich). - `versapad_combined.py` — kombiniertes Ein-Datei-Format (alle 3 Profile + Makros + **nur lokal gespeicherte** Profilnamen) statt der 3 Einzel-JSONs. Passt besser zum Wire-Protokoll: `CONFIG_BEGIN/COMMIT` ueberträgt ohnehin immer den kompletten 740B-Block auf einmal, nie nur ein Profil. Default-Pfad: `~\OneDrive\Desktop\versapad_config_all.json`. **UI:** - `desktop_viewer.py` — Tkinter, flaches Design (Label-Flächen, keine Canvas-Formen/Anti-Aliasing). Zellen nutzen `.place()` mit festen Pixel-Positionen statt `.pack()` (mit pack sah das Grid je nach leerer/ belegter Zelle ungleichmäßig aus). Drei unabhängige Modi: - **Nur lesen** (Default): pollt die 3 JSONs alle 1.5s. - **Live-Sync**: pollt per Serial das aktive Profil vom Board, schaltet Tabs automatisch mit. Laeuft in einem Hintergrundthread, der NUR ueber eine `queue.Queue` mit dem Main-Thread kommuniziert (`self.after()` direkt aus einem Fremdthread aufrufen ist in Tkinter nicht threadsicher und hat den Prozess in einer frueheren Version lautlos abstuerzen lassen — `pyw` hat kein Konsolenfenster, der Crash war unsichtbar). - **Programmiermodus**: Zellen anklicken → `action_dialog.py` (`ActionEditDialog`/`MacroStepsDialog`) bearbeitet Action-Typ, HID-Taste (Dropdown statt Tastendruck-Capture — kein WinAPI-Hook, um nicht wieder einen AV-Fehlalarm wie bei den Fensterverstecktricks zu riskieren), Consumer, Makro-Slot+Schritte, ProfileSwitch, LED-Farbe/Animation. "Vom Board laden"/"Zum Board übertragen" nutzen die Binaer-Schicht. Schaltet Live-Sync automatisch aus (ein `VersaPadLink` kann nicht von zwei Konsumenten gleichzeitig genutzt werden). - `action_dialog.py` — die beiden Bearbeiten-Dialoge, importiert nur `versapad_data` (fuer Dropdown-Inhalte). ## Quelle der Wahrheit — nicht raten Bei Aenderungen am Schema/Decoding/Binaerformat immer gegen die Firmware- und GUI-Quellen abgleichen, nie aus dem Gedaechtnis rekonstruieren: - `VersaGUI/src/ActionDialog.cs` (HidKeyName, s_consumer, Modifier-Bits) - `VersaGUI/src/Protocol.cs` (Paket-IDs, Chunk-Groessen) - `VersaMCU/src/config/nvm_config.h` + `.cpp` (SDeviceConfig-Layout, CRC) - `VersaMCU/src/config/action.h` (SAction, ActionType-Enum-Werte) - `VersaMCU/src/config/macro_config.h` + `.cpp` (SMacroTable-Layout) - `VersaMCU/src/CButton.h` (LEDAnim-Enum-Werte) - `VersaMCU/src/CMainController.cpp` (welche Commands die Firmware tatsaechlich behandelt — Protocol.cs definiert mehr Konstanten als die Firmware zwingend implementiert, immer hier gegenchecken) Zeichentasten (A-Z, Ziffern, Satzzeichen) zeigen US-Layout-Näherung, da die echte GUI das über `GetKeyNameText()` layoutabhängig auflöst — das bilden wir ohne WinAPI-Call nicht nach. **Korrektur einer frueheren Annahme:** Anders als zuerst notiert, kann die Firmware Makros sehr wohl per normaler USB-Verbindung schreiben (`USB_CMD_MACRO_BEGIN/DATA/COMMIT` in `CMainController.cpp` sind implementiert) — kein SWD/JTAG noetig. Der VersaPad-Skill (`~/.claude/skills/versapad/SKILL.md`) behauptet noch das Gegenteil und sollte bei Gelegenheit korrigiert werden. ## Start ``` py server.py # Browser, http://127.0.0.1:8765 pyw desktop_viewer.py # natives Fenster, kein Konsolenfenster ``` Oder `run_browser.bat` / `run_desktop.bat` per Doppelklick, oder die Desktop-Verknuepfungen "VersaPad Viewer (Browser)" / "VersaPad Viewer (Fenster)". **Wichtig:** `pyw`/`py` benutzen, nicht bare `pythonw`/`python` — auf hal9001 liegt in PATH zuerst eine Hermes-Agent-venv (`...\hermes\hermes-agent\venv\ Scripts\pythonw.exe`) ohne pyserial. `pyw`/`py` (Python Launcher) lösen zuverlässig zur echten Python313-Installation auf. ## Dateien/Pfade (hardcoded, hal9001-spezifisch) - Einzel-JSONs (Read-only-Modus): `~\OneDrive\Desktop\versapad_config{1,2,3}.json` — Profil 0 Windows / 1 Fusion 360 / 2 BricsCAD, siehe `versapad_data.CONFIG_PATHS`. - Kombinierte Datei (Programmiermodus-Export): `~\OneDrive\Desktop\ versapad_config_all.json` (Default, siehe `versapad_combined.DEFAULT_PATH`). ## Offene Punkte - Kein automatischer Windows-Start/Tray-Icon — bewusst einfach gehalten, bei Bedarf nachrüstbar. - Live-Sync und VersaGUI (bzw. Programmiermodus) können den COM-Port nicht gleichzeitig halten (exklusiver Zugriff) — zeigt dann "Port belegt", kein Crash. VersaGUI läuft als Tray-App dauerhaft im Hintergrund weiter, auch wenn nur das Konfigurationsfenster geschlossen wird — für Programmiermodus/ Live-Sync muss es über das Tray-Icon → "Beenden" wirklich beendet werden. Live-Sync wird beim Aktivieren des Programmiermodus automatisch ausgeschaltet. Innerhalb des Programmiermodus selbst laufen "Vom Board laden"/"Zum Board übertragen" synchron im UI-Thread (kurzzeitiges Einfrieren möglich, v.a. bei Timeout) — bislang nicht als Hintergrund-Thread ausgelagert. Der Browser-Server (`server.py`) hat keinen Programmiermodus. - HID-Tasten-Auswahl im Programmiermodus ist ein Dropdown, kein Tastendruck-Capture (bewusst, um WinAPI-Hooks/AV-Fehlalarme zu vermeiden). - Macro-Editor erlaubt nur Strg/Shift/Alt pro Schritt (kein Win), passend zum Original-`ActionDialog.cs`-Verhalten fuer Makro-Steps.