93 lines
4.0 KiB
Markdown
93 lines
4.0 KiB
Markdown
# Serial-Protokoll (CDC USB)
|
||
|
||
**Dateien:** `hal/usb_serial.h`, `hal/usb_serial.cpp`
|
||
|
||
## Grundprinzip
|
||
|
||
Board erscheint unter Windows als CDC Serial-Port (kein Treiber nötig). Alle Pakete haben feste Größe von **8 Byte** – kein Längen-Header, kein Framing, kein Escape.
|
||
|
||
```
|
||
Byte 0: Command / Event-ID
|
||
Byte 1: key_id (Button 0–24 oder Encoder 0–3) / Chunk-Index / Chunk-Count
|
||
Byte 2: r / Daten-Byte A
|
||
Byte 3: g / Daten-Byte B
|
||
Byte 4: b
|
||
Byte 5–7: reserviert (0x00)
|
||
```
|
||
|
||
## Richtungen
|
||
|
||
| Richtung | ID-Bereich | Verarbeitung |
|
||
|---|---|---|
|
||
| PC → Board (Commands) | 0x01–0x7F | `poll_vendor()` in CMainController |
|
||
| Board → PC (Events) | 0x81–0xFF | `usb_serial_send()` in processEvents |
|
||
|
||
## Command-Referenz (PC → Board)
|
||
|
||
| ID | Name | Bedeutung |
|
||
|---|---|---|
|
||
| `0x01` | SET_LED_OVERRIDE | key_id, r, g, b – temporäre Override-Farbe setzen |
|
||
| `0x02` | CLEAR_LED_OVERRIDE | key_id – Override löschen, zurück zu base |
|
||
| `0x03` | SET_LED_BASE | key_id, r, g, b – base-Farbe dauerhaft ändern (kein NVM) |
|
||
| `0x05` | PING | Board antwortet sofort mit PONG (0x85) |
|
||
| `0x10` | CONFIG_BEGIN | Byte[1] = Chunk-Anzahl – neuen Config-Empfang starten |
|
||
| `0x11` | CONFIG_DATA | Byte[1] = Chunk-Index, Byte[2–7] = 6 B Nutzdaten |
|
||
| `0x12` | CONFIG_COMMIT | CRC prüfen → NVM schreiben → Buttons neu laden → ACK/NACK |
|
||
| `0x13` | CONFIG_READ | Board sendet aktuelle NVM-Config zurück (BEGIN/DATA/END) |
|
||
| `0x20` | MACRO_BEGIN | Byte[1] = Chunk-Anzahl – neuen Makro-Empfang starten |
|
||
| `0x21` | MACRO_DATA | Byte[1] = Chunk-Index, Byte[2–7] = 6 B Nutzdaten |
|
||
| `0x22` | MACRO_COMMIT | NVM schreiben → MACRO_ACK oder MACRO_NACK |
|
||
| `0x23` | MACRO_READ | Board sendet aktuelle Makro-Tabelle zurück |
|
||
|
||
## Event-Referenz (Board → PC)
|
||
|
||
| ID | Name | Bedeutung |
|
||
|---|---|---|
|
||
| `0x81` | KEY_DOWN | key_id – HOST_COMMAND-Button gedrückt |
|
||
| `0x82` | KEY_UP | key_id – (derzeit nicht gesendet) |
|
||
| `0x83` | ENC_CW | enc_id – Encoder-Schritt CW (HOST_COMMAND) |
|
||
| `0x84` | ENC_CCW | enc_id – Encoder-Schritt CCW (HOST_COMMAND) |
|
||
| `0x85` | PONG | Antwort auf PING |
|
||
| `0x90` | CONFIG_ACK | Config erfolgreich in NVM geschrieben |
|
||
| `0x91` | CONFIG_NACK | Config CRC/Magic ungültig oder NVM-Timeout – nicht geschrieben |
|
||
| `0x92` | CONFIG_BEGIN | Byte[1] = Chunk-Anzahl (Config-Dump) |
|
||
| `0x93` | CONFIG_DATA | Byte[1] = Index, Byte[2–7] = 6 B (Config-Dump) |
|
||
| `0x94` | CONFIG_END | Config-Dump abgeschlossen |
|
||
| `0x95` | MACRO_ACK | Makro-Tabelle erfolgreich gespeichert |
|
||
| `0x96` | MACRO_BEGIN | Byte[1] = Chunk-Anzahl (Makro-Dump) |
|
||
| `0x97` | MACRO_DATA | Byte[1] = Index, Byte[2–7] = 6 B (Makro-Dump) |
|
||
| `0x98` | MACRO_END | Makro-Dump abgeschlossen |
|
||
| `0x99` | MACRO_NACK | Makro-Tabelle: NVM-Timeout – nicht geschrieben |
|
||
|
||
## Chunked Transfer
|
||
|
||
Config (740 B) und Makro-Tabelle (512 B) werden in 6-Byte-Chunks übertragen:
|
||
|
||
```
|
||
Config: ceil(740 / 6) = 124 Chunks
|
||
Makros: ceil(512 / 6) = 86 Chunks (letzter Chunk hat 2 Nutzbytes)
|
||
```
|
||
|
||
Ablauf (PC → Board):
|
||
```
|
||
BEGIN (chunk_count)
|
||
DATA chunk_0 (Bytes 0–5)
|
||
DATA chunk_1 (Bytes 6–11)
|
||
...
|
||
COMMIT
|
||
```
|
||
|
||
**CONFIG_COMMIT**: Board prüft Magic + Version + CRC. Bei Fehler → `CONFIG_NACK`. Bei NVM-Timeout während Erase/Write → `CONFIG_NACK`. Bei Erfolg → `CONFIG_ACK`.
|
||
|
||
**MACRO_COMMIT**: Kein CRC, Board schreibt direkt. Bei Erfolg → `MACRO_ACK`. Bei NVM-Timeout → `MACRO_NACK`.
|
||
|
||
### ACK-Synchronisation (GUI-Seite)
|
||
|
||
VersaGUI wartet nach COMMIT auf das ACK/NACK via `SemaphoreSlim` (Timeout 3 s). Erst nach Freigabe des Gates startet der nächste Transfer. Dies verhindert, dass Makro-Chunks gesendet werden während das Board noch den Config-NVM schreibt (~750 ms für 3 Rows).
|
||
|
||
## Implementierungsdetails
|
||
|
||
- **Ring-Buffer**: 256 Byte Eingangspuffer (= 32 vollständige Pakete) in `usb_serial.cpp`
|
||
- **DTR-Check**: `usb_serial_send()` sendet nur wenn `SerialUSB` aktiv ist (verhindert stilles Verwerfen wenn VersaGUI nicht verbunden)
|
||
- **SAMD21 CDC**: Nach SWD-Flash braucht Windows eine physische USB-Reinitialisierung (Kabel abziehen/stecken) damit der CDC-Port neu enumeriert
|