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
- Board verbinden – App erkennt das Board automatisch per VID/PID (
0x239A / 0x0042) via WMI - Rechtsklick auf das Tray-Icon → Konfiguration...
- 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
- Auf Board speichern – überträgt Config in den NVM des Boards
- 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 = truemuss vorOpen()gesetzt werden – der SAMD21 prüft die DTR-Leitung inif (!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 7–162 – 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 |
Description
Languages
C#
100%