Refresh GUI documentation and profile synchronization
This commit is contained in:
@@ -16,7 +16,8 @@ als Referenz oder Ziel verwendet werden.
|
||||
1. `README.md`
|
||||
2. `doc/INDEX.md`
|
||||
3. `doc/00_architecture.md`
|
||||
4. bei Protokoll-/Layoutänderungen zusätzlich:
|
||||
4. `doc/07_known_limitations.md`
|
||||
5. bei Protokoll-/Layoutänderungen zusätzlich:
|
||||
- `src/Protocol.cs`
|
||||
- `src/DeviceConfig.cs`
|
||||
- `../VersaMCU/AGENTS.md`
|
||||
@@ -33,6 +34,10 @@ als Referenz oder Ziel verwendet werden.
|
||||
bauen und getrennt committen.
|
||||
- Host-Command-IDs niemals ungeprüft als Shellkommando ausführen. Eine spätere
|
||||
Host-Aktionsfunktion benötigt ein explizites sicheres Mapping.
|
||||
- Das Binärmodell akzeptiert alle Firmware-Animationen `0..6`; der aktuelle
|
||||
`ActionDialog` bietet davon nur Static, Blink, Pulse und ColorCycle an.
|
||||
Bestehende, im Dialog nicht angebotene Werte nicht stillschweigend
|
||||
überschreiben.
|
||||
|
||||
## Threading und Transfers
|
||||
|
||||
|
||||
@@ -10,9 +10,10 @@ nicht zum aktuellen Scope.
|
||||
## Voraussetzungen
|
||||
|
||||
- Windows 10/11
|
||||
- .NET SDK
|
||||
- .NET 7 SDK mit Windows-Desktop-Unterstützung
|
||||
- geflashte `VersaMCU`-Firmware
|
||||
- Board per USB als CDC-Device verbunden
|
||||
- Board per USB als Composite Device (Keyboard-HID, Consumer-HID und CDC)
|
||||
verbunden
|
||||
|
||||
## Starten
|
||||
|
||||
@@ -27,7 +28,9 @@ dotnet run --project src/VersaGUI.csproj
|
||||
- liest beim Verbinden zuerst die Config und danach die Makros
|
||||
- validiert Chunkzahl, eindeutige Indizes, Vollständigkeit, CRC und Feldwerte
|
||||
- zeigt MX-Buttons und Encoder-Aktionen an
|
||||
- bearbeitet alle drei Profile über die Profilauswahl
|
||||
- schreibt Config und Makros getrennt, aber in einem UI-Vorgang auf das Board
|
||||
- sendet einen Protokoll-Ping und zeigt die Antwort an
|
||||
|
||||
## Aktueller Datenstand
|
||||
|
||||
@@ -40,6 +43,10 @@ dotnet run --project src/VersaGUI.csproj
|
||||
- globale Helligkeit
|
||||
- per-LED-Helligkeit
|
||||
|
||||
Globale Helligkeit und Encoder-Sensitivität werden bytegenau erhalten, besitzen
|
||||
aber derzeit keine eigenen Bedienelemente. Per-LED-Helligkeit kann über JSON
|
||||
gesetzt werden.
|
||||
|
||||
### MacroTable
|
||||
|
||||
- 32 Slots
|
||||
@@ -73,7 +80,8 @@ wait for ACK/NACK
|
||||
|
||||
- HID-Key-Zuweisung inklusive Modifier
|
||||
- Consumer-Keys
|
||||
- Host-Commands
|
||||
- Host-Command-IDs konfigurieren und empfangen; Desktop-Aktionen werden noch
|
||||
nicht ausgeführt
|
||||
- Makros mit bis zu 8 Steps
|
||||
- Profilwechsel als ActionType
|
||||
- LED-Farbe, Animation und Periode pro MX-Button
|
||||
@@ -90,6 +98,7 @@ VersaGUI/
|
||||
|-- Program.cs
|
||||
|-- TrayApp.cs
|
||||
|-- SerialManager.cs
|
||||
|-- ChunkTransferBuffer.cs
|
||||
|-- DeviceConfig.cs
|
||||
|-- ConfigForm.cs
|
||||
|-- ActionDialog.cs
|
||||
@@ -109,13 +118,21 @@ dotnet run --project tests/VersaGUI.ContractTests/VersaGUI.ContractTests.csproj
|
||||
- die App ist Windows-only
|
||||
- Host-Command-Events enthalten Command-ID, Key-/Encoder-ID und Richtung; ein
|
||||
sicheres Mapping auf konkrete Desktop-Aktionen ist noch nicht implementiert
|
||||
- der ActionDialog bietet aktuell vier der sieben vom Binärformat unterstützten
|
||||
LED-Animationen an
|
||||
- ein vollständig ausbleibendes Dump-Ende besitzt noch keinen Empfangs-Timeout
|
||||
|
||||
Die vollständige Liste steht in
|
||||
[`doc/07_known_limitations.md`](doc/07_known_limitations.md).
|
||||
|
||||
## Einstieg für Coding-LLMs
|
||||
|
||||
Repository-Anweisungen, gemeinsame Binärverträge und Verifikation stehen in
|
||||
[`AGENTS.md`](AGENTS.md).
|
||||
|
||||
## Weiterfuehrende Doku
|
||||
## Weiterführende Doku
|
||||
|
||||
- [doc/02_device_config.md](doc/02_device_config.md)
|
||||
- [Dokumentationsindex](doc/INDEX.md)
|
||||
- [Datenlayout](doc/02_device_config.md)
|
||||
- [Bekannte Einschränkungen](doc/07_known_limitations.md)
|
||||
- [../VersaMCU/doc/07_serial_protocol.md](../VersaMCU/doc/07_serial_protocol.md)
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|---|---|
|
||||
| `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 |
|
||||
| `ConfigForm` | Hauptfenster (Profilauswahl, Grid, Encoder-Panel und 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) |
|
||||
@@ -46,7 +46,7 @@ Benutzer → ConfigForm → ActionDialog
|
||||
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)
|
||||
Sende-Task : ConfigForm.OnSave() → Task.Run() (blockiert bis ACK/NACK oder Timeout)
|
||||
```
|
||||
|
||||
Alle Board-Events werden per `SynchronizationContext.Post` auf den UI-Thread gepostet. Controls dürfen nie vom BG-Thread angefasst werden.
|
||||
@@ -75,3 +75,8 @@ Disconnect → ReadLoop bricht ab → Disconnected-Event → 5 s Backoff → Tim
|
||||
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.
|
||||
- **UI-Modell-Grenze**: Das Binärmodell kann alle sieben Firmware-Animationen
|
||||
lesen und schreiben. Der ActionDialog bietet aktuell vier davon zur Auswahl.
|
||||
|
||||
Bewusst offene Punkte stehen gesammelt in
|
||||
[`07_known_limitations.md`](07_known_limitations.md).
|
||||
|
||||
@@ -84,7 +84,10 @@ _configAckOk / _macroAckOk – volatile bool (true = ACK, false = NACK)
|
||||
| `SendConfig(cfg)` | bool | BEGIN(0x10) → 124×DATA(0x11) → COMMIT(0x12), 5 ms zwischen Chunks, wartet auf ACK/NACK |
|
||||
| `SendMacros(macros)` | bool | BEGIN(0x20) → 86×DATA(0x21) → COMMIT(0x22), 5 ms zwischen Chunks, wartet auf ACK/NACK |
|
||||
|
||||
`SendConfig` und `SendMacros` blockieren ~1,5 s (Chunks + NVM-Zeit) → werden in `Task.Run()` aus `ConfigForm.OnSave()` aufgerufen.
|
||||
Die reine Chunk-Pausierung beträgt nominal etwa 640 ms für Config und 450 ms
|
||||
für Makros, jeweils zuzüglich Port-, NVM- und ACK-Zeit. Nach jedem COMMIT wird
|
||||
höchstens 3 s auf ACK/NACK gewartet. Deshalb laufen beide Methoden aus
|
||||
`ConfigForm.OnSave()` in `Task.Run()` und niemals auf dem UI-Thread.
|
||||
|
||||
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
|
||||
|
||||
@@ -25,6 +25,7 @@ Sie muessen deshalb synchron zu `VersaMCU/src/config/nvm_config.h` und `macro_co
|
||||
| `ActiveProfileIndex` | aktives Profil 0..2 |
|
||||
| `GlobalBrightness` | globale LED-Helligkeit |
|
||||
| `Profiles[3]` | komplette Profil-Daten |
|
||||
| `EncSensitivity[4]` | im Vertrag enthalten; Firmware nutzt den Wert derzeit nicht |
|
||||
|
||||
Fuer die GUI gibt es zusaetzlich Komfortzugriffe auf das aktive Profil:
|
||||
|
||||
@@ -62,6 +63,32 @@ Jedes Profil belegt 236 Byte:
|
||||
20 x led_period_ms
|
||||
```
|
||||
|
||||
### Action-Daten
|
||||
|
||||
| Typ | Datenbereich |
|
||||
|---|---|
|
||||
| `None` | Daten werden ignoriert |
|
||||
| `HidKey` | Low-Byte Keycode `0x00..0x65`, High-Byte Modifier |
|
||||
| `HidConsumer` | Usage `0x0000..0x03FF` |
|
||||
| `HostCommand` | frei definierte Command-ID `0x0000..0xFFFF` |
|
||||
| `Macro` | Slot `0..31` |
|
||||
| `ProfileSwitch` | Profil `0..2`; `0x00FF` oder `0xFFFF` bedeuten „nächstes Profil“ |
|
||||
|
||||
### LED-Animationen im Binärformat
|
||||
|
||||
| Wert | Enum |
|
||||
|---|---|
|
||||
| `0` | `Static` |
|
||||
| `1` | `Blink` |
|
||||
| `2` | `Pulse` |
|
||||
| `3` | `FadeIn` |
|
||||
| `4` | `FadeOut` |
|
||||
| `5` | `ColorCycle` |
|
||||
| `6` | `ColorFade` |
|
||||
|
||||
`DeviceConfig` akzeptiert alle Werte `0..6`. Der aktuelle ActionDialog bietet
|
||||
nur `Static`, `Blink`, `Pulse` und `ColorCycle` an.
|
||||
|
||||
## CRC
|
||||
|
||||
CRC16-CCITT:
|
||||
@@ -109,10 +136,20 @@ Ein Step besteht aus:
|
||||
- `keycode`
|
||||
- `modifier`
|
||||
|
||||
`keycode == 0` beendet die Ausführung des Slots. Belegte Steps nach der ersten
|
||||
Lücke werden daher zwar serialisiert, von der Firmware aber nicht ausgeführt.
|
||||
|
||||
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.
|
||||
|
||||
## Validierung
|
||||
|
||||
`ToBytes()` verweigert ungültige Objektzustände. `FromBytes()` verändert das
|
||||
bestehende Objekt erst, nachdem Größe, Magic, Version, CRC, aktives Profil,
|
||||
Action-Werte, LED-Enums und die Mindestperiode von 2 ms für `Pulse` geprüft
|
||||
wurden. Für die Makrotabelle gelten exakte 512 Byte und Keycodes bis `0x65`.
|
||||
|
||||
## Wichtig fuer Aenderungen
|
||||
|
||||
Wenn sich Firmware-Layout, Magic, Version, Profilzahl oder Makrogroesse aendern, muessen mindestens diese Stellen zusammen angepasst werden:
|
||||
|
||||
+10
-4
@@ -38,8 +38,11 @@ Icon und Tooltip spiegeln den Verbindungsstatus:
|
||||
| `EvtMacroAck` | `serial.SignalMacroAck()` — gibt SendMacros()-Thread frei |
|
||||
| `EvtMacroNack` | `serial.SignalMacroNack()` — gibt SendMacros()-Thread frei (Fehler) |
|
||||
| `EvtPong` | MessageBox "Ping OK" |
|
||||
| `EvtKeyDown/Up` | Command-ID in Byte 2/3 empfangen |
|
||||
| `EvtEncCw/Ccw` | Command-ID und Encoderrichtung empfangen |
|
||||
| `EvtKeyDown/Up` | Host-Command-ID in Byte 2/3 empfangen |
|
||||
| `EvtEncCw/Ccw` | Host-Command-ID und Encoderrichtung empfangen |
|
||||
|
||||
Diese vier Host-Events sendet die Firmware nur für Actions vom Typ
|
||||
`HostCommand`. `TrayApp` dekodiert die 16-Bit-ID, führt sie aber noch nicht aus.
|
||||
|
||||
ACK/NACK-Events zeigen keine eigene MessageBox mehr — das Ergebnis wird nach Abschluss beider Transfers gebündelt in `ConfigForm.OnSave()` angezeigt.
|
||||
|
||||
@@ -56,8 +59,11 @@ OnDisconnected():
|
||||
Icon + Text + Menü-Item aktualisieren
|
||||
```
|
||||
|
||||
Ein unvollständiger oder ungültiger Dump wird einmal wiederholt. Schlägt auch
|
||||
der zweite Versuch fehl, zeigt das Tray-Icon eine Warnung.
|
||||
Ein mit `END` abgeschlossener, aber unvollständiger oder ungültiger Dump wird
|
||||
einmal wiederholt. Schlägt auch der zweite Versuch fehl, zeigt das Tray-Icon
|
||||
eine Warnung. Bleibt `END` vollständig aus, gibt es derzeit keinen
|
||||
Empfangs-Timeout; siehe
|
||||
[`07_known_limitations.md`](07_known_limitations.md).
|
||||
|
||||
## Offene Punkte
|
||||
|
||||
|
||||
+19
-5
@@ -4,7 +4,11 @@
|
||||
|
||||
## Verantwortung
|
||||
|
||||
Hauptkonfigurationsfenster: zeigt alle 20 MX-Buttons und 4 Encoder, öffnet `ActionDialog` bei Klick, speichert Config + Makros auf das Board.
|
||||
Hauptkonfigurationsfenster: wählt eines von drei Profilen, zeigt dessen 20
|
||||
MX-Buttons und 4 Encoder, öffnet `ActionDialog` bei Klick und speichert Config
|
||||
plus Makros auf das Board.
|
||||
|
||||
Oberhalb des Tasten-Grids befindet sich die Profilauswahl für Profil 1 bis 3.
|
||||
|
||||
## Layout
|
||||
|
||||
@@ -45,15 +49,23 @@ Entspricht `key_id - 5` in der Firmware. Im TableLayoutPanel: Spalte=col, Zeile=
|
||||
|
||||
```csharp
|
||||
Task.Run(() => {
|
||||
_serial.SendConfig(_config); // ~300 ms
|
||||
Thread.Sleep(50);
|
||||
_serial.SendMacros(_macros); // ~250 ms
|
||||
bool cfgOk = _serial.SendConfig(_config); // wartet auf ACK/NACK
|
||||
bool macroOk = _serial.SendMacros(_macros);
|
||||
InvokeOnUi(() => { /* Button-Text + Enabled zurücksetzen */ });
|
||||
});
|
||||
```
|
||||
|
||||
Save-Button wird während der Übertragung deaktiviert, Text wechselt zu "Wird gesendet...".
|
||||
Save-Button ist nur aktiviert wenn Board verbunden (`_serial.IsConnected`).
|
||||
Config und Makros werden sequenziell gesendet; ein gemeinsamer Transfer-Lock
|
||||
verhindert parallele Blob-Transfers.
|
||||
|
||||
## Profile
|
||||
|
||||
Die Profilauswahl setzt `ActiveProfileIndex` und schaltet alle Komfortzugriffe
|
||||
von `DeviceConfig` auf das gewählte Profil um. `RefreshAll()` synchronisiert
|
||||
die Auswahl nach Board-Reload oder JSON-Import und zeichnet anschließend die
|
||||
20 MX- und 12 Encoder-Schaltflächen neu.
|
||||
|
||||
## Import / Export
|
||||
|
||||
@@ -64,7 +76,9 @@ Fehler (IO, JSON-Parse, falsche Version) werden per `MessageBox` angezeigt.
|
||||
|
||||
## RefreshAll
|
||||
|
||||
Wird von `TrayApp` nach erfolgreicher Config vom Board aufgerufen (über `_configForm?.RefreshAll()`). Aktualisiert alle 20 MX-Buttons und 12 Encoder-Buttons ohne Dialog.
|
||||
Wird von `TrayApp` nach erfolgreicher Config oder Makrotabelle vom Board sowie
|
||||
nach JSON-Import aufgerufen. Aktualisiert Profilauswahl, alle 20 MX-Buttons und
|
||||
12 Encoder-Buttons ohne Dialog.
|
||||
|
||||
## Extensions (in derselben Datei)
|
||||
|
||||
|
||||
+19
-5
@@ -39,8 +39,9 @@ LED-Panels (`_colorPanel`, `_animPanel`) erscheinen zusätzlich wenn `showColor=
|
||||
// Index 2: "Profil 2" → Data = 1
|
||||
// Index 3: "Profil 3" → Data = 2
|
||||
|
||||
// Initialbelegung:
|
||||
_profileCombo.SelectedIndex = action.Data == 0xFFFF ? 0 : action.Data + 1;
|
||||
// Initialbelegung: beide von der Firmware akzeptierten Zykluswerte erkennen
|
||||
_profileCombo.SelectedIndex =
|
||||
action.Data is 0x00FF or 0xFFFF ? 0 : action.Data + 1;
|
||||
|
||||
// In OnOk():
|
||||
data = _profileCombo.SelectedIndex == 0
|
||||
@@ -48,7 +49,9 @@ data = _profileCombo.SelectedIndex == 0
|
||||
: (ushort)(_profileCombo.SelectedIndex - 1);
|
||||
```
|
||||
|
||||
Im Board wird `0xFFFF` als `(uint8_t)0xFF` gespeichert und in der Firmware als "nächstes Profil" interpretiert.
|
||||
`SAction.data` ist ein 16-Bit-Feld. Die GUI schreibt für „nächstes Profil“
|
||||
kanonisch `0xFFFF`; Firmware und Deserialisierung akzeptieren zusätzlich den
|
||||
älteren Wert `0x00FF`.
|
||||
|
||||
## Tasten-Capture (HID-Modus)
|
||||
|
||||
@@ -62,7 +65,10 @@ WinForms behandelt Pfeil- und Enter-Tasten als "Dialog Keys" in `ProcessDialogKe
|
||||
|
||||
## Makro-Capture
|
||||
|
||||
Jeder der 8 Steps hat einen eigenen Capture-Button. `_captureStep` (0–7, -1 = inaktiv) zeigt welcher Step gerade aufnimmt. Capture-Logik identisch mit HID-Modus, schreibt in `_stepKeycodes[captureStep]`.
|
||||
Jeder der 8 Steps hat einen eigenen Capture-Button. `_captureStep` (0–7,
|
||||
-1 = inaktiv) zeigt, welcher Step gerade aufnimmt. Capture-Logik identisch mit
|
||||
HID-Modus, schreibt in `_stepKeycodes[captureStep]`. Der erste leere Step
|
||||
beendet die Makrosequenz; deshalb dürfen belegte Steps keine Lücke enthalten.
|
||||
|
||||
## Schlüssellookup (layout-unabhängig)
|
||||
|
||||
@@ -107,6 +113,14 @@ Scan-Code → HID Usage via s_scanToHid[sc]
|
||||
Nur wenn `showColor=true` (MX-Buttons). Enthält:
|
||||
- **Farbpicker**: `ColorDialog` → `_colorBtn.BackColor`
|
||||
- **Animations-Dropdown**: Statisch / Blinken / Pulsieren / Regenbogen
|
||||
- **Periode-Dropdown**: Presets von "Sehr langsam (8 s)" bis "Sehr schnell (250 ms)"
|
||||
- **Periode-Dropdown**: 500 ms, 1 s, 2 s oder 4 s
|
||||
|
||||
Bei "Regenbogen" wird der Farbpicker ausgeblendet (Farbe irrelevant).
|
||||
|
||||
Das Binärmodell kennt außerdem `FadeIn`, `FadeOut` und `ColorFade`; diese drei
|
||||
Werte sind im Dialog noch nicht auswählbar. Per-LED-Helligkeit wird im
|
||||
Binärformat und JSON erhalten, besitzt hier aber ebenfalls kein Bedienelement.
|
||||
Beim Öffnen einer nicht angebotenen Animation fällt die Auswahl derzeit auf
|
||||
`Static` zurück. Unbekannte, aber formal gültige Consumer-Usages fallen auf
|
||||
„Play / Pause“ zurück. Details stehen in
|
||||
[`07_known_limitations.md`](07_known_limitations.md).
|
||||
|
||||
+14
-2
@@ -14,7 +14,14 @@ Menschenlesbares JSON mit `System.Text.Json` (`WriteIndented=true`, Enums als St
|
||||
{
|
||||
"index": 0,
|
||||
"action": { "type": "HidKey", "data": 260 },
|
||||
"led": { "r": 80, "g": 40, "b": 0, "anim": "ColorCycle", "period_ms": 4000 }
|
||||
"led": {
|
||||
"r": 80,
|
||||
"g": 40,
|
||||
"b": 0,
|
||||
"brightness": 255,
|
||||
"anim": "ColorCycle",
|
||||
"period_ms": 4000
|
||||
}
|
||||
},
|
||||
...
|
||||
],
|
||||
@@ -32,7 +39,9 @@ Menschenlesbares JSON mit `System.Text.Json` (`WriteIndented=true`, Enums als St
|
||||
|
||||
## Serialisierung
|
||||
|
||||
`ConfigJson.Serialize(cfg)` → JSON-String. Exportiert alle 20 Buttons + 4 Encoder vollständig.
|
||||
`ConfigJson.Serialize(cfg)` → JSON-String. Exportiert alle 20 Buttons und vier
|
||||
Encoder des aktuell aktiven Profils vollständig, einschließlich
|
||||
Per-LED-Helligkeit.
|
||||
|
||||
## Deserialisierung
|
||||
|
||||
@@ -47,6 +56,9 @@ Menschenlesbares JSON mit `System.Text.Json` (`WriteIndented=true`, Enums als St
|
||||
## Anmerkungen
|
||||
|
||||
- `MacroTable` wird **nicht** exportiert (kein JSON-Format für Makros definiert)
|
||||
- globale Helligkeit und Encoder-Sensitivität werden nicht exportiert
|
||||
- `profile` wählt das Zielprofil aus und macht es gleichzeitig zum aktiven
|
||||
Profil; die beiden anderen Profile bleiben unverändert
|
||||
- `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`
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
# Bekannte Einschränkungen
|
||||
|
||||
Diese Seite trennt bewusst offene Punkte von bereits implementierten
|
||||
Verträgen. Sie ist vor Änderungen an Verbindungslogik, ActionDialog oder
|
||||
Binärformat zu lesen.
|
||||
|
||||
## Host-Commands
|
||||
|
||||
Firmware und GUI übertragen für `HostCommand`:
|
||||
|
||||
- Key- beziehungsweise Encoder-ID
|
||||
- Richtung über die Event-ID
|
||||
- 16-Bit-Command-ID in Byte 2/3
|
||||
|
||||
`TrayApp` führt die Command-ID noch nicht als Desktop-Aktion aus. Eine spätere
|
||||
Implementierung benötigt ein explizites Allowlist-Mapping; beliebige
|
||||
Shellbefehle aus Config-Daten sind nicht zulässig.
|
||||
|
||||
## LED- und globale Einstellungen
|
||||
|
||||
Das Binärformat und `DeviceConfig` unterstützen sieben Animationen:
|
||||
`Static`, `Blink`, `Pulse`, `FadeIn`, `FadeOut`, `ColorCycle` und `ColorFade`.
|
||||
Der `ActionDialog` bietet aktuell nur die ersten drei sowie `ColorCycle` an.
|
||||
Beim Öffnen einer nicht angebotenen Animation fällt die Auswahl auf `Static`
|
||||
zurück und würde beim Bestätigen entsprechend gespeichert.
|
||||
|
||||
Per-LED-Helligkeit wird binär und im JSON erhalten, besitzt aber kein
|
||||
Bedienelement. Globale Helligkeit und Encoder-Sensitivität werden binär
|
||||
erhalten, sind weder im Hauptfenster editierbar noch Teil des JSON-Exports.
|
||||
Die Firmware verwendet Encoder-Sensitivität derzeit ebenfalls nicht.
|
||||
|
||||
## ActionDialog
|
||||
|
||||
- Die Consumer-Liste enthält zwölf vordefinierte Usages. Andere formal gültige
|
||||
Usages bis `0x03FF` können aus dem Board gelesen werden, fallen beim Öffnen
|
||||
des Dialogs aber auf „Play / Pause“ zurück.
|
||||
- Das Periodenfeld bietet nur 500, 1000, 2000 und 4000 ms. Andere geladene
|
||||
Perioden fallen im Dialog auf 4000 ms zurück.
|
||||
- Ein Makro endet am ersten Step mit `keycode == 0`; Lücken vor späteren
|
||||
belegten Steps werden nicht ausgeführt.
|
||||
|
||||
## Transfers und Verbindung
|
||||
|
||||
- Das CDC-Protokoll besitzt kein Byte-Framing, keine Paket-CRC und keine
|
||||
Transfer-ID. Verliert der Stream ein Byte, kann die 8-Byte-Grenze bis zum
|
||||
Reconnect verschoben bleiben.
|
||||
- Chunkzahl, eindeutige Indizes, Vollständigkeit und END-Metadaten werden
|
||||
geprüft. Bleibt ein Dump jedoch ohne `END`, existiert noch kein
|
||||
Empfangs-Timeout oder Watchdog; die automatische Wiederholung startet nur
|
||||
nach einem als ungültig erkannten `END`.
|
||||
- `RequestConfig()` und `RequestMacros()` melden einen unmittelbar
|
||||
fehlgeschlagenen `Send()` nicht an `TrayApp`.
|
||||
- Während `SendConfig()` und `SendMacros()` ist nur die Speichern-Schaltfläche
|
||||
deaktiviert. Andere Editoraktionen werden nicht global gesperrt.
|
||||
|
||||
## Testabdeckung
|
||||
|
||||
Die Console-Contract-Tests prüfen:
|
||||
|
||||
- Configgröße, CRC und Roundtrip
|
||||
- ausgewählte ungültige Configfelder
|
||||
- Makrogröße und HID-Keycode-Grenze
|
||||
- Chunkvollständigkeit und doppelte Chunks
|
||||
- 16-Bit-Host-Command-Payload
|
||||
|
||||
Nicht automatisiert geprüft werden WinForms-Interaktionen, WMI-Porterkennung,
|
||||
echte SerialPort-Fehler, Reconnects, NVM-Schreibzeiten, HID-Ausgabe und
|
||||
Hardwareverhalten. Dafür ist weiterhin ein Test mit angeschlossenem VersaPad
|
||||
erforderlich.
|
||||
+3
-1
@@ -15,6 +15,7 @@ gegen `../../VersaMCU` geprüft werden.
|
||||
| [04_config_form.md](04_config_form.md) | Grid, Speichern, Import/Export |
|
||||
| [05_action_dialog.md](05_action_dialog.md) | Key-Capture, Action-Auswahl, LED-Einstellungen |
|
||||
| [06_config_json.md](06_config_json.md) | JSON-Format und Grenzen |
|
||||
| [07_known_limitations.md](07_known_limitations.md) | Bewusst offene GUI-, Protokoll- und Testgrenzen |
|
||||
|
||||
## Schnellreferenz
|
||||
|
||||
@@ -23,5 +24,6 @@ gegen `../../VersaMCU` geprüft werden.
|
||||
- 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)
|
||||
- bekannte Einschränkungen -> [07_known_limitations.md](07_known_limitations.md)
|
||||
- automatisierte Binär-/Transferverträge ->
|
||||
`../tests/VersaGUI.ContractTests/`
|
||||
[`../tests/VersaGUI.ContractTests/`](../tests/VersaGUI.ContractTests/)
|
||||
|
||||
+5
-2
@@ -5,9 +5,12 @@
|
||||
// HID Tastatur → Capture-Button (Klicken + Taste drücken) + Modifier-Checkboxen
|
||||
// HID Consumer → Dropdown mit benannten Medien-/Lautstärke-Aktionen
|
||||
// Host Command → Zahlen-Eingabe (Command-ID)
|
||||
// Makro → acht HID-Key-Steps
|
||||
// Profilwechsel → Zielprofil oder zyklisch nächstes Profil
|
||||
// Keine Aktion → nichts
|
||||
//
|
||||
// Optional (nur MX-Buttons): LED-Basisfarbe + LED-Animation + Geschwindigkeit
|
||||
// Optional (nur MX-Buttons): LED-Basisfarbe + vier auswählbare Animationen +
|
||||
// Geschwindigkeit. Das Binärmodell akzeptiert zusätzlich drei Animationen.
|
||||
|
||||
namespace VersaGUI;
|
||||
|
||||
@@ -405,7 +408,7 @@ public class ActionDialog : Form
|
||||
|
||||
var macroHint = new Label
|
||||
{
|
||||
Text = "Klicke einen Step, dann Taste drücken. Leere Steps werden übersprungen.",
|
||||
Text = "Klicke einen Step, dann Taste drücken. Der erste leere Step beendet das Makro.",
|
||||
Location = new Point(0, 0),
|
||||
Size = new Size(396, 28),
|
||||
ForeColor = SystemColors.GrayText,
|
||||
|
||||
+6
-2
@@ -2,6 +2,7 @@
|
||||
// Hauptfenster der VersaPad-Konfiguration.
|
||||
//
|
||||
// Layout:
|
||||
// Profil-Auswahl (Profil 1–3)
|
||||
// ┌── Tasten (4 × 5 Grid) ──────────────────────────────────────────────┐
|
||||
// │ Jede Taste = Button mit Hintergrundfarbe (= LED-Base) und │
|
||||
// │ Aktionsbeschriftung. Klick öffnet ActionDialog. │
|
||||
@@ -9,7 +10,7 @@
|
||||
// ┌── Encoder ─────────────────────────────────────────────────────────┐
|
||||
// │ 4 Zeilen à [SW][CW][CCW] – ohne LED-Farbe │
|
||||
// └────────────────────────────────────────────────────────────────────┘
|
||||
// [Auf Board speichern] [Schließen]
|
||||
// [Auf Board speichern] [Ping] [Exportieren] [Importieren] [Schließen]
|
||||
//
|
||||
// "Auf Board speichern" sendet Config und Makros in 6-Byte-Chunks über CDC.
|
||||
// Die Schaltfläche ist deaktiviert, wenn das Board nicht verbunden ist.
|
||||
@@ -287,7 +288,7 @@ public class ConfigForm : Form
|
||||
_saveBtn.Enabled = false;
|
||||
_saveBtn.Text = "Wird gesendet...";
|
||||
|
||||
// SendConfig + SendMacros blockieren ~400ms → Background-Thread
|
||||
// SendConfig + SendMacros warten auf ACK/NACK → Background-Thread
|
||||
Task.Run(() =>
|
||||
{
|
||||
bool cfgOk = _serial.SendConfig(_config); // wartet intern auf CONFIG_ACK/NACK
|
||||
@@ -318,6 +319,9 @@ public class ConfigForm : Form
|
||||
// Alle Buttons neu zeichnen (z.B. nach Config-Laden vom Board)
|
||||
public void RefreshAll()
|
||||
{
|
||||
if (_profileCombo.SelectedIndex != _config.ActiveProfileIndex)
|
||||
_profileCombo.SelectedIndex = _config.ActiveProfileIndex;
|
||||
|
||||
for (int i = 0; i < 20; i++) RefreshMxButton(i);
|
||||
for (int enc = 0; enc < 4; enc++)
|
||||
for (int act = 0; act < 3; act++)
|
||||
|
||||
+1
-1
@@ -39,7 +39,7 @@ public enum ActionType : byte
|
||||
HidConsumer = 2, // data = HID Consumer Usage ID
|
||||
HostCommand = 3, // data = Command-ID für ein sicheres App-Mapping
|
||||
Macro = 4, // data = Makro-Slot-Index (0–31)
|
||||
ProfileSwitch = 5, // data = Profil 0–2 oder 0xFFFF für nächstes Profil
|
||||
ProfileSwitch = 5, // data = Profil 0–2 oder 0x00FF/0xFFFF für nächstes Profil
|
||||
}
|
||||
|
||||
// Ein Step in einem Makro (keycode=0 → leerer/letzter Step)
|
||||
|
||||
+4
-4
@@ -39,10 +39,10 @@ public static class Protocol
|
||||
|
||||
// ── Events: Board → App (0x81–0xFF) ──────────────────────────────────────
|
||||
// Host-Events übertragen die Command-ID little-endian in Data[2..3].
|
||||
public const byte EvtKeyDown = 0x81; // key_id → Button gedrückt
|
||||
public const byte EvtKeyUp = 0x82; // key_id → Button losgelassen
|
||||
public const byte EvtEncCw = 0x83; // enc_id → Schritt CW
|
||||
public const byte EvtEncCcw = 0x84; // enc_id → Schritt CCW
|
||||
public const byte EvtKeyDown = 0x81; // Host-Action: key_id → gedrückt
|
||||
public const byte EvtKeyUp = 0x82; // Host-Action: key_id → losgelassen
|
||||
public const byte EvtEncCw = 0x83; // Host-Action: enc_id → Schritt CW
|
||||
public const byte EvtEncCcw = 0x84; // Host-Action: enc_id → Schritt CCW
|
||||
public const byte EvtPong = 0x85; // Antwort auf CmdPing
|
||||
public const byte EvtConfigAck = 0x90; // Config erfolgreich in NVM geschrieben
|
||||
public const byte EvtConfigNack = 0x91; // Config CRC/Magic ungültig
|
||||
|
||||
Reference in New Issue
Block a user