78 lines
3.6 KiB
Markdown
78 lines
3.6 KiB
Markdown
# VersaGUI – Architektur-Übersicht
|
||
|
||
## Technologie-Stack
|
||
|
||
| Merkmal | Wert |
|
||
|---|---|
|
||
| Sprache | C# / .NET 7 |
|
||
| UI-Framework | WinForms (`[STAThread]`) |
|
||
| Einstiegspunkt | `Program.cs` → `Application.Run(new TrayApp())` |
|
||
| Laufzeitmodell | `ApplicationContext` (kein `Form` als Hauptfenster) |
|
||
| Threading | UI-Thread + 1 Hintergrund-Lese-Thread + Timer-Thread |
|
||
|
||
## Komponentenübersicht
|
||
|
||
| Datei | Verantwortung |
|
||
|---|---|
|
||
| `TrayApp` | `ApplicationContext`; hält Tray-Icon, öffnet ConfigForm, verarbeitet Board-Events |
|
||
| `SerialManager` | Verbindungsverwaltung, WMI-Erkennung, Lese-Thread, Sende-Methoden |
|
||
| `ConfigForm` | Hauptfenster (Grid + Encoder-Panel + Footer); öffnet ActionDialog |
|
||
| `ActionDialog` | Modaler Dialog zum Bearbeiten einer Aktion + LED-Einstellungen |
|
||
| `DeviceConfig` | C#-Spiegel von `SDeviceConfig`; Validierung und Serialisierung (740 B) |
|
||
| `MacroTable` | C#-Spiegel von `SMacroTable`; Validierung und Serialisierung (512 B) |
|
||
| `ChunkTransferBuffer` | prüft Dump-Chunkzahl, Indizes und Vollständigkeit |
|
||
| `ConfigJson` | JSON-Import/Export für `DeviceConfig` |
|
||
| `Protocol` | Konstanten für alle Command/Event-IDs (spiegelt `usb_serial.h`) |
|
||
|
||
## Datenfluss
|
||
|
||
```
|
||
Board → SerialManager (ReadLoop, BG-Thread)
|
||
→ SynchronizationContext.Post (→ UI-Thread)
|
||
→ TrayApp.OnPacket()
|
||
├── Config-Dump vollständig sammeln → DeviceConfig.FromBytes()
|
||
├── danach Makro-Dump vollständig sammeln → MacroTable.FromBytes()
|
||
└── HOST_COMMAND-Events mit 16-Bit-Command-ID empfangen
|
||
|
||
Benutzer → ConfigForm → ActionDialog
|
||
→ DeviceConfig / MacroTable (in-memory ändern)
|
||
→ SerialManager.SendConfig() + SendMacros() (BG-Task)
|
||
→ Board (chunked, 6 B/Paket)
|
||
```
|
||
|
||
## Threading-Modell
|
||
|
||
```
|
||
UI-Thread : TrayApp, ConfigForm, ActionDialog, alle WinForms-Controls
|
||
BG-Thread : SerialManager.ReadLoop() – blockiert auf ReadByte()
|
||
Timer-Thread : SerialManager._reconnectTimer → TryConnect() alle 3 s
|
||
Sende-Task : ConfigForm.OnSave() → Task.Run() (blockiert ~400 ms für Transfer)
|
||
```
|
||
|
||
Alle Board-Events werden per `SynchronizationContext.Post` auf den UI-Thread gepostet. Controls dürfen nie vom BG-Thread angefasst werden.
|
||
|
||
## Verbindungslebenszyklus
|
||
|
||
```
|
||
Start → Timer feuert → TryConnect() → WMI-Suche (VID 0x239A / PID 0x0042)
|
||
→ SerialPort öffnen (DtrEnable=true VOR Open()!)
|
||
→ 200 ms warten → ReadLoop starten → Connected-Event
|
||
→ RequestConfig() → vollständig validieren → RequestMacros()
|
||
|
||
Disconnect → ReadLoop bricht ab → Disconnected-Event → 5 s Backoff → Timer läuft weiter
|
||
```
|
||
|
||
## Invarianten / Constraints
|
||
|
||
- **DtrEnable=true muss VOR `Open()` gesetzt werden**: SAMD21 prüft DTR für `usb_serial_send()`. Der Default-Wert false würde alle Board→PC-Antworten still verwerfen.
|
||
- **IOException ≠ Disconnect**: .NET 7 wirft `IOException` statt `TimeoutException` bei `ReadByte()`-Timeout. Nur als echten Fehler behandeln wenn `_port.IsOpen == false`.
|
||
- **Packed-kompatible Serialisierung**: `DeviceConfig.ToBytes()` erzeugt exakt
|
||
740 B in derselben Reihenfolge wie `SDeviceConfig`; `MacroTable` exakt 512 B.
|
||
- **Config-Version**: `DeviceConfig.Version == 3`. `FromBytes()` prüft Magic,
|
||
Version, CRC, Profilindex, Actions, LED-Enums und kritische Perioden, bevor
|
||
Objektzustand geändert wird.
|
||
- **Transfer-Synchronisation**: Config- und Makro-Uploads laufen unter einem
|
||
gemeinsamen Transfer-Lock; einzelne Pakete unter einem Write-Lock.
|
||
- **Host-Commands**: Pakete sind vollständig definiert, die Ausführung einer
|
||
Command-ID als Desktop-Aktion ist bewusst noch nicht implementiert.
|