Files
VersaGUI/doc/00_architecture.md
T

3.6 KiB
Raw Blame History

VersaGUI Architektur-Übersicht

Technologie-Stack

Merkmal Wert
Sprache C# / .NET 7
UI-Framework WinForms ([STAThread])
Einstiegspunkt Program.csApplication.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.