From aa6b7a8ec91139d7f56fde81c0856406ca7409ff Mon Sep 17 00:00:00 2001 From: Julian Appel Date: Sun, 19 Apr 2026 11:59:32 +0200 Subject: [PATCH] Fully working Delphi GUI --- README.md | 264 ++++++++++++---------------------------- doc/02_device_config.md | 178 +++++++++++++-------------- doc/INDEX.md | 34 +++--- 3 files changed, 184 insertions(+), 292 deletions(-) diff --git a/README.md b/README.md index 38d02a8..6e7303f 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,18 @@ # VersaGUI -Windows-Tray-App zur Konfiguration und Steuerung des VersaPad v2. -Geschrieben in **C# / .NET 7 / WinForms**. +Windows-Tray-App zur Konfiguration des VersaPad v2. +Geschrieben in C# mit WinForms. + +Hinweis: +Diese GUI ist weiterhin die Referenzimplementierung fuer Protokoll und Datenlayout. +Parallel existiert mit `VersaGUIDelphi` ein Delphi/VCL-Port unter dem Namen `VersaGUI Delphi`. ## Voraussetzungen - Windows 10/11 -- [.NET 7 SDK](https://dotnet.microsoft.com/download/dotnet/7.0) (zum Bauen) -- VersaMCU-Firmware auf dem Board geflasht -- Board per USB verbunden (erscheint als CDC COM-Port, kein Treiber nötig) +- .NET SDK +- geflashte `VersaMCU`-Firmware +- Board per USB als CDC-Device verbunden ## Starten @@ -16,194 +20,86 @@ Geschrieben in **C# / .NET 7 / WinForms**. dotnet run ``` -Oder als Release-Build: +## Was die App macht -```bash -dotnet publish -c Release -r win-x64 --self-contained +- erkennt das Board automatisch per VID/PID +- oeffnet den CDC-COM-Port mit aktivem DTR +- liest beim Verbinden zuerst die Config und danach die Makros +- zeigt MX-Buttons und Encoder-Aktionen an +- schreibt Config und Makros getrennt, aber in einem UI-Vorgang auf das Board + +## Aktueller Datenstand + +### DeviceConfig + +- Magic `0x56503203` +- Version `3` +- `740` Byte +- 3 Profile +- globale Helligkeit +- per-LED-Helligkeit + +### MacroTable + +- 32 Slots +- 8 Steps pro Slot +- `512` Byte + +## Uebertragungsformat + +Es wird dasselbe 8-Byte-Protokoll wie in der Firmware verwendet. + +Aktuelle Chunk-Zahlen: + +- Config: `124` +- Makros: `86` + +Speicherablauf: + +```text +CONFIG_BEGIN +CONFIG_DATA x124 +CONFIG_COMMIT +wait for ACK/NACK + +MACRO_BEGIN +MACRO_DATA x86 +MACRO_COMMIT +wait for ACK/NACK ``` -Die App erscheint als Icon in der Windows-Taskleiste (System Tray). Kein Hauptfenster. +## GUI-Funktionen -## Bedienung +- HID-Key-Zuweisung inklusive Modifier +- Consumer-Keys +- Host-Commands +- Makros mit bis zu 8 Steps +- Profilwechsel als ActionType +- LED-Farbe, Animation und Periode pro MX-Button +- JSON Import/Export -1. **Board verbinden** – App erkennt das Board automatisch per VID/PID (`0x239A / 0x0042`) via WMI -2. **Rechtsklick** auf das Tray-Icon → **Konfiguration...** -3. Taste/Encoder anklicken → Aktion auswählen: - - **HID Tastatur**: Großen Button klicken, dann gewünschte Taste drücken (Strg+C, F5, …) - - **HID Consumer**: Dropdown – Play/Pause, Lautstärke, etc. - - **Host Command**: Numerische Command-ID (zukünftig: URL/Programm) - - **LED-Farbe**: Farbpicker für die Idle-LED des Buttons -4. **Auf Board speichern** – überträgt Config in den NVM des Boards -5. Beim nächsten Verbinden wird die Config automatisch vom Board geladen +## Projektstruktur ---- - -## Funktionsumfang (Anforderungskatalog) - -### 1 Verbindung & Geräteerkennung - -| # | Anforderung | Status | -|---|-------------|--------| -| 1.1 | App läuft als **Windows Tray-Anwendung** ohne sichtbares Hauptfenster | ✅ | -| 1.2 | Automatische Board-Erkennung per **WMI / VID+PID** (`0x239A / 0x0042`) | ✅ | -| 1.3 | **Automatischer Reconnect** alle 3 s; 5 s Backoff nach Verbindungsverlust | ✅ | -| 1.4 | Verbindungsstatus im Tray-Icon (Symbol + Tooltip) sichtbar | ✅ | -| 1.5 | Beim Verbinden wird die gespeicherte Config **automatisch vom Board gelesen** | ✅ | -| 1.6 | Beim Verbinden wird die **Makro-Tabelle automatisch vom Board gelesen** | ✅ | - -### 2 Tastenbelegung – HID Tastatur - -| # | Anforderung | Status | -|---|-------------|--------| -| 2.1 | Taste durch **Drücken erfassen** (kein manuelles HID-ID-Eingeben) | ✅ | -| 2.2 | Modifier-Kombination: **Strg / Shift / Alt / Win** einzeln oder kombiniert | ✅ | -| 2.3 | **Pfeiltasten, Enter, Escape, F1–F12, Numpad** erfassbar | ✅ | -| 2.4 | **Layout-unabhängige Erfassung** via PS/2-Scan-Code → HID-Usage; Ö/Ä/Ü auf QWERTZ korrekt | ✅ | -| 2.5 | Taste-Name wird laut **aktivem Windows-Layout** angezeigt (`GetKeyNameText`) | ✅ | -| 2.6 | Board führt Tastendruck als **USB-HID-Tastatureingabe** aus (funktioniert ohne laufende App) | ✅ | -| 2.7 | **Hold-Semantik**: Taste bleibt gedrückt solange physisch gehalten (OS initiiert Repeat nach ~500ms) | ✅ | - -### 3 Tastenbelegung – HID Consumer / Medientasten - -| # | Anforderung | Status | -|---|-------------|--------| -| 3.1 | Auswahl per **Dropdown** mit Klartext-Namen | ✅ | -| 3.2 | Unterstützte Aktionen: Play/Pause, Nächster/Vorheriger Titel, Stop, Lauter/Leiser, Mute, Taschenrechner, Browser Zurück/Vor | ✅ | -| 3.3 | **Hold-Semantik**: Media-Control bleibt aktiv solange Taste gehalten wird (z.B. Lautstärke-Wiederholung) | ✅ | - -### 4 Tastenbelegung – Makros - -| # | Anforderung | Status | -|---|-------------|--------| -| 4.1 | Bis zu **4 Schritte** pro Makro (je 1 Taste + Modifier) | ✅ | -| 4.2 | Jeder Schritt per **Taste drücken** erfassen, inkl. Sondertasten | ✅ | -| 4.3 | Leere Schritte werden übersprungen (kürzere Makros möglich) | ✅ | -| 4.4 | **32 Makro-Slots** – je ein Slot pro MX-Button (0–19) und Encoder-Aktion (20–31) | ✅ | -| 4.5 | Makro-Tabelle wird **separat** vom Board gelesen und geschrieben (NVM Row 1) | ✅ | -| 4.6 | Board führt Makro-Schritte mit 10 ms Key-Down + 20 ms Pause **ohne laufende App** aus | ✅ | - -### 5 Encoder-Belegung - -| # | Anforderung | Status | -|---|-------------|--------| -| 5.1 | **4 Encoder**, je 3 Aktionen: SW (Drücken), CW (Rechts), CCW (Links) | ✅ | -| 5.2 | Gleiche Aktionstypen wie Tasten (HID Key, Consumer, Makro, Host Command) | ✅ | -| 5.3 | **Encoder-SW**: Hold-Semantik wie normale Tasten (Taste bleibt gedrückt) | ✅ | -| 5.4 | **Encoder-CW/CCW**: Tap-Modell (diskrete Ereignisse, atomare down+delay+up Sequenzen, kein Hold möglich) | ✅ | - -### 6 LED-Konfiguration - -| # | Anforderung | Status | -|---|-------------|--------| -| 6.1 | **Basis-LED-Farbe** pro MX-Button via Farbpicker (RGB) | ✅ | -| 6.2 | **Animationsmodus** pro Button wählbar: Statisch, Blinken, Pulsieren, Regenbogen | ✅ | -| 6.3 | **Animations-Tempo**: Schnell (0,5 s) / Mittel (1 s) / Langsam (2 s) / Sehr langsam (4 s) | ✅ | -| 6.4 | Regenbogen-Modus: Board berechnet Hue-Sweep lokal, gleichmäßige Phasenverteilung | ✅ | -| 6.5 | LED-Config und Aktionstyp im **gleichen Dialog** bearbeitbar | ✅ | - -### 7 Konfiguration speichern & laden - -| # | Anforderung | Status | -|---|-------------|--------| -| 7.1 | Config und Makros werden gleichzeitig per **„Auf Board speichern"** übertragen | ✅ | -| 7.2 | Board validiert Config mit **CRC16-CCITT + Magic + Version**; NACK bei Fehler | ✅ | -| 7.3 | Config bleibt nach Stromverlust im **NVM** erhalten (kein Flash-Verschleiß bei nur Lesen) | ✅ | -| 7.4 | **JSON-Export** der gesamten Config (Aktionen + LED) in Datei | ✅ | -| 7.5 | **JSON-Import** mit Versionscheck; ungültige Dateien werden abgelehnt | ✅ | - -### 8 Verbindungsprotokoll - -| # | Anforderung | Status | -|---|-------------|--------| -| 8.1 | **8-Byte-Festlängen-Pakete** über CDC Serial (kein Treiber nötig) | ✅ | -| 8.2 | **Ping/Pong** zur manuellen Verbindungsdiagnose im Konfigurations-Fenster | ✅ | -| 8.3 | Config-Transfer: BEGIN → n×DATA(6 Byte) → COMMIT → ACK/NACK | ✅ | -| 8.4 | Makro-Transfer: gleiche Struktur, 43 Chunks à 6 Byte (256 Byte Tabelle) | ✅ | -| 8.5 | Debug-Logging aller RX-Pakete in `%TEMP%\versapad_rx.txt` | ✅ | - -### 9 Nicht implementiert / Roadmap - -| # | Anforderung | Status | -|---|-------------|--------| -| 9.1 | **Host Command**: URL/Programm öffnen wenn Board-Taste gedrückt | 🔲 TODO | -| 9.2 | Eigenes **Tray-Icon** (aktuell: Windows-Standard-Icon) | 🔲 TODO | -| 9.3 | **Fader/Potentiometer**-Unterstützung (3× ADC-Achsen auf Board vorhanden) | 🔲 TODO | -| 9.4 | **Profile**: mehrere Tastenbelegungen speichern und wechseln | 🔲 TODO | - ---- - -## Projekt-Struktur - -``` +```text VersaGUI/ -├── VersaGUI.csproj – .NET 7 WinForms Projekt -├── Program.cs – Einstiegspunkt, startet TrayApp -├── TrayApp.cs – ApplicationContext: Tray-Icon, Menü, Paket-Routing -├── ConfigForm.cs – Konfigurations-Fenster (4×5 Grid + Encoder-Panel) -├── ActionDialog.cs – Dialog: Taste erfassen / Consumer / Makro / LED-Animation -├── DeviceConfig.cs – C#-Spiegel von SDeviceConfig (223 B, Version 2) + MacroTable (256 B) -├── ConfigJson.cs – JSON-Export/Import der DeviceConfig -├── Protocol.cs – Protokoll-Konstanten (Commands + Events) -└── SerialManager.cs – COM-Port-Erkennung, Read-Loop, Config + Makros senden/empfangen +`-- src/ + |-- Program.cs + |-- TrayApp.cs + |-- SerialManager.cs + |-- DeviceConfig.cs + |-- ConfigForm.cs + |-- ActionDialog.cs + |-- ConfigJson.cs + `-- Protocol.cs ``` -## Architektur +## Grenzen / Status -``` -TrayApp - ├── SerialManager – Hintergrund-Thread: COM-Port-Verbindung + Leseloop - │ ├── Connected-Event → Config vom Board anfordern (CMD_CONFIG_READ) - │ └── PacketReceived → TrayApp.OnPacket() - ├── DeviceConfig – In-Memory-Modell der Board-Config - └── ConfigForm (optional) – Öffnet sich auf Benutzeranfrage - └── ActionDialog – Modaler Dialog pro Taste/Encoder -``` +- Host-Commands sind protokollseitig vorhanden, aber appseitig noch nicht voll ausgebaut +- die App ist Windows-only +- fuer eine alternative GUI ist `VersaGUIDelphi` der aktuelle Delphi/VCL-Port -### SerialManager +## Weiterfuehrende Doku -- Erkennt das Board per **WMI** (`Win32_PnPEntity`, VID/PID-Filter) → COM-Port-Name -- Lese-Loop im Hintergrund-Thread: sammelt 8-Byte-Pakete, feuert `PacketReceived`-Event auf dem UI-Thread -- **Reconnect-Timer**: versucht alle 3 Sekunden neu zu verbinden; nach Disconnect 5 Sekunden Backoff -- Wichtig: `DtrEnable = true` muss **vor** `Open()` gesetzt werden – der SAMD21 prüft die DTR-Leitung in `if (!SerialUSB)` und verwirft sonst alle ausgehenden Pakete - -### DeviceConfig / Serialisierung - -`DeviceConfig.ToBytes()` erzeugt den exakt **223-Byte**-Puffer der `SDeviceConfig`-Struct (Version 2, little-endian, packed). `CRC16-CCITT` (Poly 0x1021, Init 0xFFFF) über Bytes 7–222 – identisch zur Firmware-Implementierung. - -`MacroTable.ToBytes()` erzeugt **256 Byte** (32 Slots × 4 Steps × 2 Byte). - -Config-Übertragung Board→PC (Lesen): -``` -PC sendet: CMD_CONFIG_READ (0x13) -Board sendet: EVT_CONFIG_BEGIN (Chunk-Anzahl = 38) - EVT_CONFIG_DATA × 38 (je 6 Nutzbytes) - EVT_CONFIG_END -``` - -Config-Übertragung PC→Board (Schreiben): -``` -PC sendet: CMD_CONFIG_BEGIN (0x10, Chunk-Anzahl) - CMD_CONFIG_DATA × 38 - CMD_CONFIG_COMMIT (0x12) -Board sendet: EVT_CONFIG_ACK (0x90) oder EVT_CONFIG_NACK (0x91) -``` - -Makro-Übertragung (analog, separate Kommandos 0x20–0x23): -``` -PC sendet: CMD_MACRO_BEGIN (0x20, Chunk-Anzahl = 43) - CMD_MACRO_DATA × 43 - CMD_MACRO_COMMIT (0x22) -Board sendet: EVT_MACRO_ACK (0x95) -``` - -### Kommunikationsprotokoll - -Das vollständige Protokoll (alle Command- und Event-IDs, NVM-Layout, Paketformat) ist in [VersaMCU/README.md](../VersaMCU/README.md#serial-protokoll-8-bytes-fixed) dokumentiert. - -### Bekannte .NET-Eigenheiten - -| Problem | Lösung | -|---|---| -| `.NET 7 SerialPort.ReadByte()` wirft `IOException` statt `TimeoutException` auf Timeout | `catch (IOException)` → nur als Fehler behandeln wenn Port nicht mehr offen ist | -| `DtrEnable = false` (Standard) → Board sendet nichts | `DtrEnable = true` im SerialPort-Konstruktor setzen, **vor** `Open()` | -| DTR-Zustandswechsel nach `Open()` löst CDC-Disconnect auf dem Board aus | DTR vor `Open()` setzen → kein Zustandswechsel | +- [doc/02_device_config.md](doc/02_device_config.md) +- [../VersaMCU/doc/07_serial_protocol.md](../VersaMCU/doc/07_serial_protocol.md) diff --git a/doc/02_device_config.md b/doc/02_device_config.md index d8dc081..b00ff89 100644 --- a/doc/02_device_config.md +++ b/doc/02_device_config.md @@ -1,120 +1,120 @@ -# DeviceConfig & MacroTable +# DeviceConfig und MacroTable -**Datei:** `DeviceConfig.cs` +Datei: -## Überblick +- `src/DeviceConfig.cs` -C#-Spiegel der Firmware-Structs. Muss byte-kompatibel mit `SDeviceConfig` (nvm_config.h) und `SMacroTable` (macro_config.h) sein. +## Zweck ---- +Die C#-Klassen spiegeln das aktuelle Firmware-Layout bytegenau. +Sie muessen deshalb synchron zu `VersaMCU/src/config/nvm_config.h` und `macro_config.h` bleiben. ## DeviceConfig -### Felder +### Globaler Stand -| Feld | Typ | Inhalt | -|---|---|---| -| `ActiveProfileIndex` | `byte` | Aktives Profil (0–2) | -| `GlobalBrightness` | `byte` | Globale LED-Helligkeit (0–255) | -| `MxActions[20]` | `DeviceAction[]` | Aktionen für MX-Buttons 0–19 (aus aktivem Profil) | -| `EncActions[4,3]` | `DeviceAction[,]` | Encoder [0–3][SW=0/CW=1/CCW=2] (aus aktivem Profil) | -| `LedBase[20]` | `Color[]` | RGB-Basis-LED-Farbe je Button (aus aktivem Profil) | -| `LedAnim[20]` | `LedAnimType[]` | Animation je Button (aus aktivem Profil) | -| `LedPeriod[20]` | `ushort[]` | Animationsperiode in ms (aus aktivem Profil) | +- Magic `0x56503203` +- Version `3` +- Groesse `740` Byte +- 3 Profile -### Serialisierungs-Layout (ToBytes / FromBytes, 740 B) +### Wichtige Felder -``` -Offset 0 4B Magic 0x56503203 (little-endian) -Offset 4 1B Version = 3 -Offset 5 2B CRC16-CCITT über Bytes 7–739 (little-endian) -Offset 7 1B active_profile (0–2) -Offset 8 1B global_brightness -Offset 9 4B enc_sensitivity[4] -Offset 13 19B Reserve (_reserve) +| Feld | Bedeutung | +|---|---| +| `ActiveProfileIndex` | aktives Profil 0..2 | +| `GlobalBrightness` | globale LED-Helligkeit | +| `Profiles[3]` | komplette Profil-Daten | -Profil 0 (Offset 32, 236 B): - Offset 32 60B MxActions[20] je 3B: type(1) + data_lo(1) + data_hi(1) - Offset 92 36B EncActions[4][3] je 3B - Offset 128 20B LedBase[i].R - Offset 148 20B LedBase[i].G - Offset 168 20B LedBase[i].B - Offset 188 20B LedBrightness[i] - Offset 208 20B LedAnim[i] als byte - Offset 228 40B LedPeriod[i] als uint16 little-endian +Fuer die GUI gibt es zusaetzlich Komfortzugriffe auf das aktive Profil: -Profil 1 (Offset 268, 236 B): identisches Layout -Profil 2 (Offset 504, 236 B): identisches Layout +- `MxActions[20]` +- `EncActions[4,3]` +- `LedBase[20]` +- `LedAnim[20]` +- `LedPeriod[20]` + +### Layout + +```text +Offset 0 4B magic +Offset 4 1B version +Offset 5 2B crc +Offset 7 1B active_profile +Offset 8 1B global_brightness +Offset 9 4B enc_sensitivity[4] +Offset 13 19B reserve +Offset 32 profile 0 +Offset 268 profile 1 +Offset 504 profile 2 ``` -### CRC16-CCITT +Jedes Profil belegt 236 Byte: -Polynom `0x1021`, Init `0xFFFF`, über Bytes 7–739 (nach dem CRC-Feld selbst, einschließlich `active_profile`). Muss identisch mit Firmware-Implementierung sein. `DeviceConfig.Crc16()` ist statisch und direkt testbar. - -### Defaults (entspricht Firmware-Defaults) - -- Alle Aktionen: `None` -- LEDs: warm-weiß (R=80, G=40, B=0), Helligkeit 255 -- Animation: `ColorCycle` (Regenbogen), Period 4000 ms -- `active_profile = 0`, `global_brightness = 255` - ---- - -## DeviceAction - -```csharp -public enum ActionType : byte { - None=0, HidKey=1, HidConsumer=2, HostCommand=3, Macro=4, ProfileSwitch=5 -} - -public class DeviceAction { - public ActionType Type { get; set; } - public ushort Data { get; set; } - // HidKey: Low-Byte = HID Keycode, High-Byte = Modifier - // HidConsumer: Consumer Usage ID - // HostCommand: Command-ID - // Macro: Slot-Index 0–31 - // ProfileSwitch: 0–2 = Ziel-Profil, 0xFFFF = nächstes Profil (Zyklus) -} +```text +20 x mx_actions +12 x enc_actions +20 x led_r +20 x led_g +20 x led_b +20 x led_brightness +20 x led_anim +20 x led_period_ms ``` -`DeviceAction.Display` gibt einen lesbaren String zurück (z.B. `"Strg+C"`, `"Play/Pause"`, `"→ Profil 2"`, `"→ Nächstes Profil"`). +## CRC ---- +CRC16-CCITT: + +- Polynom `0x1021` +- Init `0xFFFF` +- Bereich `7..739` + +Die CRC muss exakt zur Firmware passen. + +## Defaults + +Firmware-Defaults: + +- alle Actions `None` +- `GlobalBrightness = 255` +- `enc_sensitivity = 1` +- Base-Farbe `R=80, G=40, B=0` +- Animation `ColorCycle` +- Periode `4000 ms` + +Sichtbarer Effekt auf dem Board: + +- alle MX-LEDs laufen im Regenbogenmodus ## MacroTable -```csharp -public class MacroTable { - public const int Slots = 32; - public const int MaxSteps = 8; - public MacroStep[,] Steps { get; } // [slot][step] -} -public class MacroStep { - public byte Keycode { get; set; } // 0 = leer - public byte Modifier { get; set; } -} -``` +### Stand + +- 32 Slots +- 8 Steps pro Slot +- 512 Byte gesamt ### Slot-Konvention -| Slots | Verwendung | +| Slots | Bedeutung | |---|---| -| 0–19 | MX-Button `mxIdx` (`MacroTable.SlotForMx(mxIdx)`) | -| 20–31 | Encoder: `20 + enc * 3 + actIdx` (`MacroTable.SlotForEncoder(enc, actIdx)`) | +| `0..19` | MX-Buttons | +| `20..31` | Encoder-Aktionen | -### Serialisierung (512 B) +### Serialisierung -32 Slots × 8 Steps × 2 B = 512 B. Keycode zuerst, dann Modifier. Kein Magic/CRC (Board akzeptiert jeden Inhalt). +Ein Step besteht aus: ---- +- `keycode` +- `modifier` -## LedAnimType +Es gibt kein Magic und keine CRC fuer die Makrotabelle. -```csharp -public enum LedAnimType : byte { - Static=0, Blink=1, Pulse=2, ColorCycle=5 -} -``` +## Wichtig fuer Aenderungen -Werte entsprechen `LEDAnim` in der Firmware. `FADE_IN` (3) und `FADE_OUT` (4) existieren in der Firmware aber nicht in der GUI (nicht konfigurierbar). +Wenn sich Firmware-Layout, Magic, Version, Profilzahl oder Makrogroesse aendern, muessen mindestens diese Stellen zusammen angepasst werden: + +- `VersaMCU` +- `VersaGUI` +- `VersaGUIDelphi` diff --git a/doc/INDEX.md b/doc/INDEX.md index 1b71d11..9a10cc9 100644 --- a/doc/INDEX.md +++ b/doc/INDEX.md @@ -1,25 +1,21 @@ -# VersaGUI – Dokumentations-Index +# VersaGUI - Dokumentationsindex -Jede Datei deckt eine GUI-Komponente ab. Für Claude: die relevante(n) Dateien zu Beginn einer Aufgabe lesen statt die gesamten Quelldateien zu scannen. +Die Dateien hier beschreiben die aktuelle C#-Referenz-GUI fuer Config v3 und 32x8 Makros. | Datei | Inhalt | |---|---| -| [00_architecture.md](00_architecture.md) | Threading-Modell, Datenfluss, Verbindungslebenszyklus, globale Constraints (DTR, IOException, Packed-Layout) | -| [01_serial_manager.md](01_serial_manager.md) | WMI-Erkennung, TryConnect, ReadLoop, Sende-Methoden, Reconnect-Backoff | -| [02_device_config.md](02_device_config.md) | DeviceConfig + MacroTable: Felder, Byte-Layout (223/256 B), CRC16, LedAnimType | -| [03_tray_app.md](03_tray_app.md) | ApplicationContext, Tray-Icon, Board-Event-Routing, Config/Makro-Dump-Empfang, TODOs | -| [04_config_form.md](04_config_form.md) | Grid-Layout, mx_idx-Formel, RefreshMxButton, OnSave (Task.Run), Import/Export | -| [05_action_dialog.md](05_action_dialog.md) | Panels je Typ, ProcessCmdKey-Capture, layout-unabhängiger Scan-Code-Lookup, Consumer-Liste | -| [06_config_json.md](06_config_json.md) | JSON-Format, Serialize/Deserialize, Einschränkungen | +| [00_architecture.md](00_architecture.md) | Threading-Modell, Datenfluss, Verbindungslebenszyklus | +| [01_serial_manager.md](01_serial_manager.md) | Port-Erkennung, Connect, ReadLoop, Sende-Pfad | +| [02_device_config.md](02_device_config.md) | `DeviceConfig`, `MacroTable`, aktuelles Byte-Layout, CRC | +| [03_tray_app.md](03_tray_app.md) | TrayApp, Packet-Routing, Dump-Empfang, UI-Zustand | +| [04_config_form.md](04_config_form.md) | Grid, Speichern, Import/Export | +| [05_action_dialog.md](05_action_dialog.md) | Key-Capture, Action-Auswahl, LED-Einstellungen | +| [06_config_json.md](06_config_json.md) | JSON-Format und Grenzen | -## Schnell-Referenz: Was steht wo? +## Schnellreferenz -- **DtrEnable-Problem** → [00_architecture.md](00_architecture.md), [01_serial_manager.md](01_serial_manager.md) -- **IOException ≠ Disconnect (.NET 7)** → [00_architecture.md](00_architecture.md), [01_serial_manager.md](01_serial_manager.md) -- **Byte-Layout der 223-Byte-Config** → [02_device_config.md](02_device_config.md) -- **Warum ProcessCmdKey statt OnKeyDown?** → [05_action_dialog.md](05_action_dialog.md) -- **Warum Scan-Codes statt VK-Codes (Umlaut-Problem)?** → [05_action_dialog.md](05_action_dialog.md) -- **mx_idx ↔ key_id-Umrechnung** → [04_config_form.md](04_config_form.md) -- **Makro-Slot-Konvention** → [02_device_config.md](02_device_config.md) -- **HOST_COMMAND noch nicht implementiert** → [03_tray_app.md](03_tray_app.md) -- **Task.Run beim Speichern** → [04_config_form.md](04_config_form.md) +- aktuelles Config-Layout `740` Byte -> [02_device_config.md](02_device_config.md) +- aktuelle Makrotabelle `512` Byte -> [02_device_config.md](02_device_config.md) +- DTR und Connect-Pfad -> [00_architecture.md](00_architecture.md), [01_serial_manager.md](01_serial_manager.md) +- Makro-Slot-Konvention -> [02_device_config.md](02_device_config.md) +- Host-Command-Status -> [03_tray_app.md](03_tray_app.md)