// usb_serial.h // Bidirektionale Kommunikation zwischen Board und Windows-App über CDC Serial. // // Das Board erscheint als COM-Port unter Windows (kein Treiber nötig). // Alle Pakete haben feste Größe (SERIAL_PKT_SIZE = 8 Bytes) – kein // Längen-Header nötig, vereinfacht Parsing auf beiden Seiten. // // Byte-Layout aller Pakete: // [0] Command/Event-ID // [1] key_id (Button 0–24 oder Encoder 0–3) // [2] r / Daten-Byte A // [3] g / Daten-Byte B // [4] b // [5..7] reserviert (0x00) // // Richtungen: // PC → Board (Commands, 0x01–0x7F): poll_vendor() in CMainController // Board → PC (Events, 0x81–0xFF): usb_serial_send() in processEvents() #pragma once #include #define SERIAL_PKT_SIZE 8 // ── Commands: PC → Board ────────────────────────────────────────────────────── #define USB_CMD_SET_LED_OVERRIDE 0x01 // key_id, r, g, b → Override-LED setzen #define USB_CMD_CLEAR_LED_OVERRIDE 0x02 // key_id → Override löschen, zurück zu base #define USB_CMD_SET_LED_BASE 0x03 // key_id, r, g, b → Base-LED dauerhaft ändern // Config-Übertragung (mehrteilig, 6 Nutzbytes pro Paket): // BEGIN: Data[1] = Anzahl Chunks die folgen // DATA: Data[1] = Chunk-Index (0-based), Data[2..7] = 6 Bytes Nutzdaten // COMMIT: CRC prüfen + NVM schreiben + Buttons neu laden #define USB_CMD_PING 0x05 // Board antwortet sofort mit USB_EVT_PONG #define USB_CMD_CONFIG_BEGIN 0x10 #define USB_CMD_CONFIG_DATA 0x11 #define USB_CMD_CONFIG_COMMIT 0x12 #define USB_CMD_CONFIG_READ 0x13 // Board sendet aktuelle NVM-Config zurück // Makro-Tabelle übertragen (gleiche Chunk-Struktur wie Config): #define USB_CMD_MACRO_BEGIN 0x20 // Data[1] = Chunk-Anzahl #define USB_CMD_MACRO_DATA 0x21 // Data[1] = Chunk-Index, Data[2..7] = 6B #define USB_CMD_MACRO_COMMIT 0x22 // NVM schreiben + ACK zurück #define USB_CMD_MACRO_READ 0x23 // Board sendet aktuelle Makro-Tabelle zurück // ── Events: Board → PC ──────────────────────────────────────────────────────── #define USB_EVT_KEY_DOWN 0x81 // key_id → HOST_COMMAND-Button gedrückt #define USB_EVT_KEY_UP 0x82 // key_id → HOST_COMMAND-Button losgelassen #define USB_EVT_ENC_CW 0x83 // enc_id → Encoder Schritt CW (HOST_COMMAND) #define USB_EVT_ENC_CCW 0x84 // enc_id → Encoder Schritt CCW (HOST_COMMAND) #define USB_EVT_PONG 0x85 // Antwort auf USB_CMD_PING #define USB_EVT_CONFIG_ACK 0x90 // Config erfolgreich in NVM geschrieben #define USB_EVT_CONFIG_NACK 0x91 // Config CRC/Magic ungültig – nicht geschrieben #define USB_EVT_CONFIG_BEGIN 0x92 // Beginn Config-Dump: Data[1] = Chunk-Anzahl #define USB_EVT_CONFIG_DATA 0x93 // Config-Chunk: Data[1] = Index, Data[2..7] = 6B #define USB_EVT_CONFIG_END 0x94 // Config-Dump abgeschlossen #define USB_EVT_MACRO_ACK 0x95 // Makro-Tabelle erfolgreich gespeichert #define USB_EVT_MACRO_NACK 0x99 // Makro-Tabelle: NVM-Fehler – nicht geschrieben #define USB_EVT_MACRO_BEGIN 0x96 // Beginn Makro-Dump: Data[1] = Chunk-Anzahl #define USB_EVT_MACRO_DATA 0x97 // Makro-Chunk: Data[1] = Index, Data[2..7] = 6B #define USB_EVT_MACRO_END 0x98 // Makro-Dump abgeschlossen // Paket-Struct mit Accessor-Methoden für lesbareren Code struct SerialPacket { uint8_t data[SERIAL_PKT_SIZE]; uint8_t command() const { return data[0]; } uint8_t key_id() const { return data[1]; } uint8_t r() const { return data[2]; } uint8_t g() const { return data[3]; } uint8_t b() const { return data[4]; } }; void usb_serial_init(); // Board → PC: 8-Byte-Event-Paket senden (nur wenn SerialUSB verbunden) void usb_serial_send(uint8_t event_type, uint8_t key_id, uint8_t a = 0, uint8_t b = 0); // PC → Board: nächstes vollständiges Paket abholen. // Gibt true zurück wenn ein Paket verfügbar war. bool usb_serial_poll(SerialPacket& out);