3.6 KiB
3.6 KiB
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ürusb_serial_send(). Der Default-Wert false würde alle Board→PC-Antworten still verwerfen. - IOException ≠ Disconnect: .NET 7 wirft
IOExceptionstattTimeoutExceptionbeiReadByte()-Timeout. Nur als echten Fehler behandeln wenn_port.IsOpen == false. - Packed-kompatible Serialisierung:
DeviceConfig.ToBytes()erzeugt exakt 740 B in derselben Reihenfolge wieSDeviceConfig;MacroTableexakt 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.