4.0 KiB
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 wennSerialUSBaktiv 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