VersaGUI/README.md
2026-03-29 14:42:20 +02:00

4.0 KiB
Raw Blame History

VersaGUI

Windows-Tray-App zur Konfiguration und Steuerung des VersaPad v2. Geschrieben in C# / .NET 7 / WinForms.

Voraussetzungen

  • Windows 10/11
  • .NET 7 SDK (zum Bauen)
  • VersaMCU-Firmware auf dem Board geflasht
  • Board per USB verbunden (erscheint als CDC COM-Port, kein Treiber nötig)

Starten

dotnet run

Oder als Release-Build:

dotnet publish -c Release -r win-x64 --self-contained

Die App erscheint als Icon in der Windows-Taskleiste (System Tray). Kein Hauptfenster.

Bedienung

  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

Projekt-Struktur

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 auswählen / Host-Command
├── DeviceConfig.cs       C#-Spiegel von SDeviceConfig (163B Serialisierung, CRC16)
├── Protocol.cs           Protokoll-Konstanten (Commands + Events)
└── SerialManager.cs      COM-Port-Erkennung, Read-Loop, Config senden/empfangen

Architektur

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

SerialManager

  • 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 163-Byte-Puffer der SDeviceConfig-Struct in der Firmware entspricht (little-endian, packed). CRC16-CCITT (Poly 0x1021, Init 0xFFFF) über Bytes 7162 identisch zur Firmware-Implementierung.

Config-Übertragung Board→PC (Lesen):

PC sendet:    CMD_CONFIG_READ (0x13)
Board sendet: EVT_CONFIG_BEGIN (Chunk-Anzahl)
              EVT_CONFIG_DATA × 28 (je 6 Nutzbytes)
              EVT_CONFIG_END

Config-Übertragung PC→Board (Schreiben):

PC sendet:    CMD_CONFIG_BEGIN (Chunk-Anzahl)
              CMD_CONFIG_DATA × 28
              CMD_CONFIG_COMMIT
Board sendet: EVT_CONFIG_ACK oder EVT_CONFIG_NACK

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