Harden protocol transfers and config validation
This commit is contained in:
+17
-9
@@ -18,8 +18,9 @@
|
||||
| `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`; Serialisierung/Deserialisierung (223 B) |
|
||||
| `MacroTable` | C#-Spiegel von `SMacroTable`; Serialisierung/Deserialisierung (256 B) |
|
||||
| `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`) |
|
||||
|
||||
@@ -29,9 +30,9 @@
|
||||
Board → SerialManager (ReadLoop, BG-Thread)
|
||||
→ SynchronizationContext.Post (→ UI-Thread)
|
||||
→ TrayApp.OnPacket()
|
||||
├── Config-Dump: _rxConfigBuf aufbauen → DeviceConfig.FromBytes()
|
||||
├── Makro-Dump: _rxMacroBuf aufbauen → MacroTable.FromBytes()
|
||||
└── HOST_COMMAND-Events: (TODO: Aktion ausführen)
|
||||
├── 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)
|
||||
@@ -55,7 +56,8 @@ Alle Board-Events werden per `SynchronizationContext.Post` auf den UI-Thread gep
|
||||
```
|
||||
Start → Timer feuert → TryConnect() → WMI-Suche (VID 0x239A / PID 0x0042)
|
||||
→ SerialPort öffnen (DtrEnable=true VOR Open()!)
|
||||
→ 200 ms warten → ReadLoop starten → Connected-Event → RequestConfig() + RequestMacros()
|
||||
→ 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
|
||||
```
|
||||
@@ -64,6 +66,12 @@ Disconnect → ReadLoop bricht ab → Disconnected-Event → 5 s Backoff → Tim
|
||||
|
||||
- **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()` muss exakt 223 B in derselben Reihenfolge wie `SDeviceConfig` (packed C++) erzeugen. Jede Änderung am Firmware-Layout muss hier gespiegelt werden.
|
||||
- **Config-Version**: `DeviceConfig.Version == 2`. `FromBytes()` prüft Magic + Version + CRC; schlägt einer fehl → Methode gibt `false` zurück, Config bleibt unverändert.
|
||||
- **Debug-Log**: `versapad_rx.txt` in `%TEMP%` – vor Release-Nutzung entfernen (TODO).
|
||||
- **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.
|
||||
|
||||
@@ -75,7 +75,7 @@ _configAckOk / _macroAckOk – volatile bool (true = ACK, false = NACK)
|
||||
|
||||
| Methode | Rückgabe | Funktion |
|
||||
|---|---|---|
|
||||
| `Send(pkt)` | void | Rohe 8-Byte-Übertragung (fire-and-forget) |
|
||||
| `Send(pkt)` | bool | Rohe, unter Write-Lock atomare 8-Byte-Übertragung |
|
||||
| `SetLedOverride(keyId, r, g, b)` | void | CMD 0x01 |
|
||||
| `ClearLedOverride(keyId)` | void | CMD 0x02 |
|
||||
| `SetLedBase(keyId, r, g, b)` | void | CMD 0x03 |
|
||||
@@ -86,6 +86,11 @@ _configAckOk / _macroAckOk – volatile bool (true = ACK, false = NACK)
|
||||
|
||||
`SendConfig` und `SendMacros` blockieren ~1,5 s (Chunks + NVM-Zeit) → werden in `Task.Run()` aus `ConfigForm.OnSave()` aufgerufen.
|
||||
|
||||
Vor `BEGIN` wird das zugehörige ACK-Gate geleert. Beide Blob-Sender teilen
|
||||
einen Transfer-Lock, prüfen jeden `Send()`-Rückgabewert und brechen bei
|
||||
Disconnect sofort ab. Ein Disconnect gibt wartende ACK-Gates mit Fehlerstatus
|
||||
frei.
|
||||
|
||||
## Events
|
||||
|
||||
| Event | Gefeuert wenn |
|
||||
|
||||
@@ -110,6 +110,8 @@ Ein Step besteht aus:
|
||||
- `modifier`
|
||||
|
||||
Es gibt kein Magic und keine CRC fuer die Makrotabelle.
|
||||
Beim Transfer prüft die GUI trotzdem exakte Größe und alle HID-Keycodes; die
|
||||
Firmware prüft zusätzlich die vollständige Chunkmenge.
|
||||
|
||||
## Wichtig fuer Aenderungen
|
||||
|
||||
@@ -117,4 +119,6 @@ Wenn sich Firmware-Layout, Magic, Version, Profilzahl oder Makrogroesse aendern,
|
||||
|
||||
- `VersaMCU`
|
||||
- `VersaGUI`
|
||||
- `VersaGUIDelphi`
|
||||
|
||||
Beide sind eigenständige Git-Repositories und werden getrennt gebaut und
|
||||
committed. Andere GUI-Ports gehören nicht zum gepflegten Scope.
|
||||
|
||||
+12
-13
@@ -7,7 +7,7 @@
|
||||
- App-Lebenszyklus als `ApplicationContext` (kein Hauptfenster)
|
||||
- Tray-Icon mit Verbindungsstatus und Kontextmenü
|
||||
- Empfang und Routing aller Board-Events (via `SerialManager.PacketReceived`)
|
||||
- Config/Makro-Dump-Empfang (chunked, via `_rxConfigBuf` / `_rxMacroBuf`)
|
||||
- sequenzieller Config-/Makro-Dump-Empfang über `ChunkTransferBuffer`
|
||||
- ACK/NACK-Weiterleitung an SerialManager
|
||||
- Öffnen des `ConfigForm` (nur eine Instanz gleichzeitig)
|
||||
|
||||
@@ -31,19 +31,15 @@ Icon und Tooltip spiegeln den Verbindungsstatus:
|
||||
|
||||
| Event-ID | Aktion |
|
||||
|---|---|
|
||||
| `EvtConfigBegin` | `_rxConfigBuf = new byte[740]` |
|
||||
| `EvtConfigData` | Chunk in `_rxConfigBuf` eintragen (`KeyId * 6` = Byte-Offset) |
|
||||
| `EvtConfigEnd` | `DeviceConfig.FromBytes()` → `ConfigForm.RefreshAll()` |
|
||||
| `EvtConfigBegin/Data/End` | Chunkzahl, Indizes und Vollständigkeit prüfen; danach `DeviceConfig.FromBytes()` |
|
||||
| `EvtConfigAck` | `serial.SignalConfigAck()` — gibt SendConfig()-Thread frei |
|
||||
| `EvtConfigNack` | `serial.SignalConfigNack()` — gibt SendConfig()-Thread frei (Fehler) |
|
||||
| `EvtMacroBegin` | `_rxMacroBuf = new byte[512]` |
|
||||
| `EvtMacroData` | Chunk in `_rxMacroBuf` eintragen |
|
||||
| `EvtMacroEnd` | `MacroTable.FromBytes()` |
|
||||
| `EvtMacroBegin/Data/End` | vollständigen 512-Byte-Dump prüfen; danach `MacroTable.FromBytes()` |
|
||||
| `EvtMacroAck` | `serial.SignalMacroAck()` — gibt SendMacros()-Thread frei |
|
||||
| `EvtMacroNack` | `serial.SignalMacroNack()` — gibt SendMacros()-Thread frei (Fehler) |
|
||||
| `EvtPong` | MessageBox "Ping OK" |
|
||||
| `EvtKeyDown` | TODO: HOST_COMMAND-Aktion ausführen |
|
||||
| `EvtEncCw/Ccw` | TODO: Encoder HOST_COMMAND |
|
||||
| `EvtKeyDown/Up` | Command-ID in Byte 2/3 empfangen |
|
||||
| `EvtEncCw/Ccw` | Command-ID und Encoderrichtung empfangen |
|
||||
|
||||
ACK/NACK-Events zeigen keine eigene MessageBox mehr — das Ergebnis wird nach Abschluss beider Transfers gebündelt in `ConfigForm.OnSave()` angezeigt.
|
||||
|
||||
@@ -53,14 +49,17 @@ ACK/NACK-Events zeigen keine eigene MessageBox mehr — das Ergebnis wird nach A
|
||||
OnConnected():
|
||||
Icon + Text + Menü-Item aktualisieren
|
||||
serial.RequestConfig() → Config-Dump vom Board
|
||||
serial.RequestMacros() → Makro-Dump vom Board
|
||||
nach gültigem Config-End:
|
||||
serial.RequestMacros() → Makro-Dump vom Board
|
||||
|
||||
OnDisconnected():
|
||||
Icon + Text + Menü-Item aktualisieren
|
||||
```
|
||||
|
||||
## TODOs in dieser Klasse
|
||||
Ein unvollständiger oder ungültiger Dump wird einmal wiederholt. Schlägt auch
|
||||
der zweite Versuch fehl, zeigt das Tray-Icon eine Warnung.
|
||||
|
||||
- HOST_COMMAND-Ausführung: `EvtKeyDown` empfangen → Aktion aus Config laden → URL/Programm starten
|
||||
## Offene Punkte
|
||||
|
||||
- sichere Zuordnung von Command-IDs zu explizit erlaubten Desktop-Aktionen
|
||||
- Eigenes Tray-Icon statt `SystemIcons.Application`
|
||||
- Debug-Log (`versapad_rx.txt`) entfernen
|
||||
|
||||
@@ -8,7 +8,8 @@ Menschenlesbares JSON mit `System.Text.Json` (`WriteIndented=true`, Enums als St
|
||||
|
||||
```json
|
||||
{
|
||||
"version": 2,
|
||||
"version": 3,
|
||||
"profile": 0,
|
||||
"buttons": [
|
||||
{
|
||||
"index": 0,
|
||||
@@ -37,6 +38,8 @@ Menschenlesbares JSON mit `System.Text.Json` (`WriteIndented=true`, Enums als St
|
||||
|
||||
`ConfigJson.Deserialize(json, cfg)`:
|
||||
- Prüft `version` – wirft `InvalidDataException` bei Mismatch
|
||||
- prüft und übernimmt `profile` im Bereich `0..2`
|
||||
- validiert Actions, LED-Enums und die Mindestperiode für `Pulse`
|
||||
- Schreibt in bestehendes `DeviceConfig`-Objekt (kein `new`)
|
||||
- Fehlende `buttons`/`encoders`-Arrays werden ignoriert (partial import möglich)
|
||||
- Ungültige `index`-Werte werden übersprungen
|
||||
@@ -46,3 +49,5 @@ Menschenlesbares JSON mit `System.Text.Json` (`WriteIndented=true`, Enums als St
|
||||
- `MacroTable` wird **nicht** exportiert (kein JSON-Format für Makros definiert)
|
||||
- `data` enthält den `ushort`-Wert direkt (für HidKey z.B. `Keycode | (Modifier << 8)`)
|
||||
- Die Datei ist kein Binärformat und kann manuell bearbeitet werden
|
||||
- Ein ungültiger Wert wird vor dem Anwenden mit `InvalidDataException`
|
||||
abgelehnt
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
|
||||
Die Dateien hier beschreiben die aktuelle C#-Referenz-GUI fuer Config v3 und 32x8 Makros.
|
||||
|
||||
Repository-weite LLM-/Agent-Richtlinien stehen in
|
||||
[`../AGENTS.md`](../AGENTS.md). Gemeinsame Firmwareverträge müssen zusätzlich
|
||||
gegen `../../VersaMCU` geprüft werden.
|
||||
|
||||
| Datei | Inhalt |
|
||||
|---|---|
|
||||
| [00_architecture.md](00_architecture.md) | Threading-Modell, Datenfluss, Verbindungslebenszyklus |
|
||||
@@ -19,3 +23,5 @@ Die Dateien hier beschreiben die aktuelle C#-Referenz-GUI fuer Config v3 und 32x
|
||||
- DTR und Connect-Pfad -> [00_architecture.md](00_architecture.md), [01_serial_manager.md](01_serial_manager.md)
|
||||
- Makro-Slot-Konvention -> [02_device_config.md](02_device_config.md)
|
||||
- Host-Command-Status -> [03_tray_app.md](03_tray_app.md)
|
||||
- automatisierte Binär-/Transferverträge ->
|
||||
`../tests/VersaGUI.ContractTests/`
|
||||
|
||||
Reference in New Issue
Block a user