Die Raspberry Pi Pico 2 ist ausschließlich USB-Device am Zielrechner. Sie präsentiert drei HID-Schnittstellen: Boot-Tastatur, absolute Maus und relative Boot-Maus. Der Controller kommuniziert ausschließlich über UART0 mit der Pico. Es gibt weder USB-CDC noch eine Netzwerkschnittstelle auf der Pico. Die Firmware führt keine Textkonvertierung und keine gespeicherten Makros aus.
Verdrahtung und lokale Freigabe
| Pico-Pin | Funktion |
|---|---|
| GP0, physisch Pin 1 | UART0 TX → RX des Controllers |
| GP1, physisch Pin 2 | UART0 RX ← TX des Controllers |
| GND, beispielsweise Pin 3 | Gemeinsame UART-Masse |
| GP14, physisch Pin 19 | Lokaler Freigabetaster, normalerweise offen, beim Drücken nach GND |
| GP15, physisch Pin 20 | Not-Aus-Kontakt, normalerweise geschlossen nach GND |
| USB-Buchse der Pico 2 | Ausschließlich zum autorisierten Zielrechner |
UART: 115200 Baud, 8 Datenbits, keine Parität, 1 Stoppbit, keine Flusssteuerung; 3,3-V-Logik. Kein RS-232 und keine 5-V-Signale an GPIO. Die Tabelle beschreibt die direkte Laborverbindung mit gekreuztem TX/RX und gemeinsamer Masse. Für die isolierte Box gemäß HARDWARE.md liegen Controller- und Pico-Masse auf getrennten Seiten des digitalen Isolators: keine GND-Brücke über die Isolation. Der Zielrechner versorgt die Pico über USB; keine zusätzliche Versorgung über den 3,3-V- oder 5-V-Pin des Controllers.
GP14 und GP15 verwenden interne Pull-ups. GP15 HIGH beziehungsweise ein geöffneter Kontakt oder eine unterbrochene Leitung setzt den Not-Aus-Latch sofort über GPIO-Interrupt und zusätzlich durch zyklisches Abfragen. Der Kontakt wird nicht entprellt: Schon eine erkannte steigende Flanke löst aus. Ein beim Start offener Kontakt löst ebenfalls aus.
Ein frischer, mindestens 30 ms entprellter Druck auf GP14 gibt im disarmed-Zustand ein einmaliges Zeitfenster von 10 Sekunden für ARM. Beim Einschalten gedrückt gehaltenes GP14 gibt keine Freigabe; zuerst loslassen und erneut drücken. Ein erfolgreicher ARM verbraucht das Fenster. GP14 hebt den Not-Aus-Latch nicht auf. Nach Not-Aus muss der Kontakt geschlossen und die Pico bewusst neu gestartet werden; danach bleibt sie disarmed und benötigt erneut die lokale Freigabe. Auch ein Hardware-Watchdog-Neustart setzt nur in den disarmed-Startzustand zurück.
Die Pico-LED leuchtet bei ARM dauerhaft, blinkt langsam während des Freigabefensters und schnell bei gelatchtem Not-Aus. Im normalen disarmed-Zustand ist sie aus.
Framing
HB1 <seq> <OP> [dezimal_argumente] *<CRC16HEX>\n
Antworten verwenden dasselbe Framing:
HB1 <seq> OK [dezimal_argumente] *<CRC16HEX>\n
HB1 <seq> ERR <FEHLERCODE> *<CRC16HEX>\n
- Ausschließlich druckbares ASCII und abschließend genau LF (
0x0A); CRLF wird verworfen. - Genau ein Leerzeichen zwischen Tokens. Keine führenden oder abschließenden Leerzeichen, Tabs oder zusätzlichen Tokens.
- Maximal 159 Bytes ohne LF, also 160 Bytes auf der Leitung. Eine unvollständige Zeile verfällt nach 250 ms ab ihrem ersten Byte; danach werden Bytes bis zum nächsten LF verworfen.
<seq>ist eine vorzeichenlose dezimale 32-Bit-Zahl von 0 bis 4294967295. Argumente sind dezimale, vorzeichenbehaftete 32-Bit-Zahlen; ein führendes Minus ist erlaubt, ein Plus nicht. Führende Nullen sind zulässig, ändern aber die Byteidentität eines Requests.- Operationsnamen und Fehlercodes sind Großbuchstaben beziehungsweise Großbuchstaben mit Unterstrichen. CRC-Eingaben dürfen Groß- oder Kleinbuchstaben enthalten; Antworten verwenden Großbuchstaben.
- CRC-16/CCITT-FALSE: Polynom
0x1021, Initialwert0xFFFF, kein Reflektieren, kein abschließendes XOR. Prüfsummen-Testvektor: ASCII123456789→29B1. - Die CRC umfasst exakt die Bytes von
HinHB1bis zum letzten Zeichen vor*. Das Leerzeichen vor dem Stern, der Stern, die vier Hexziffern und LF sind ausgeschlossen.
CRC erkennt beschädigte Übertragungen; sie ist keine Authentifizierung. UART-Zugriff ist physisch auf den vertrauenswürdigen Controller zu begrenzen.
Die UART-Verbindung arbeitet als Stop-and-wait: Der Controller sendet genau einen Request und wartet auf dessen Antwort, bevor er den nächsten sendet. Auch der Heartbeat benutzt denselben seriellen Zugriff. Die Pico verwendet feste Puffer ohne Heap. UART-Framing-, Paritäts-, Break- oder FIFO-Overrun-Fehler verwerfen die ganze betroffene Zeile. Ungültige oder beschädigte Frames lösen keine HID-Aktion aus.
Sequenzen und Antworten
Normalerweise muss jede neue gültige Anfrage eine größere Sequenznummer als die zuletzt konsumierte Anfrage haben. Lücken sind erlaubt. Kein Wrap-around: Bei Erreichen des Maximums zuerst disarmen, dann mit HELLO neu beginnen.
Ein syntaktisch gültiger, CRC-geprüfter Request mit neuer Sequenz wird konsumiert, auch wenn die Operation mit einem Zustands-, Argument- oder Wertefehler endet. Die Firmware speichert die letzte vollständige Request-Zeile und deren Antwort:
- Eine unmittelbar wiederholte, byteidentische letzte Anfrage bekommt die gespeicherte Antwort. Die Aktion wird nicht erneut ausgeführt. Ein wiederholtes
PINGaktualisiert den Watchdog nicht. - Dieselbe Sequenz mit anderen Bytes erzeugt
ERR SEQ_CONFLICT; eine ältere Sequenz erzeugtERR SEQ_OLD. Beide ändern den Cache nicht. - Neustart-Ausnahme: Ein argumentloses, gültiges
HELLOdarf bei disarmed eine beliebige Sequenz verwenden und setzt die Reihenfolge neu. Auch eine zuvor anders verwendete gleiche Sequenz ist dann erlaubt. Eine exakte Wiederholung des letzten Requests wird weiterhin zuerst aus dem Cache beantwortet. Bei armed istHELLOan die normale Reihenfolge gebunden. - Parser-, CRC- und Sequenzfehler konsumieren keine Sequenznummer. Wenn der Parser die Sequenz nicht zuverlässig lesen kann, meldet er Fehler mit Sequenz 0; bei einer lesbaren Sequenz verwendet er diese.
Eine gecachte ARM-Antwort beschreibt die ursprüngliche Anfrage. Sie schaltet nach Watchdog oder Not-Aus nicht erneut frei. Der Controller soll eine ausbleibende Aktionsantwort als unklaren Ausgang behandeln, den Ablauf stoppen und eine neue, gültige STOP-Anfrage senden, statt die Aktion als neuen Request zu wiederholen. Bereits ausgeführte Eingaben lassen sich nicht rückgängig machen.
OK bei ABS, REL und KEY bedeutet, dass TinyUSB den USB-Transfer erfolgreich abgeschlossen hat. Es bestätigt keine Wirkung in der Anwendung des Zielrechners. STOP OK bestätigt die lokale Deaktivierung und die vorgemerkten Release-Reports; es wartet nicht auf einen möglicherweise abgetrennten USB-Host. RELEASE OK bestätigt abgeschlossene Release-Transfers.
Operationen
| Operation | Argumente | Wirkung und Voraussetzung |
|---|---|---|
HELLO |
keine | OK 1: Protokollversion 1; keine Freigabe und kein Heartbeat. Bei disarmed ist ein Sequenz-Neustart erlaubt. |
ARM |
keine | Nur mit geschlossenem, nicht gelatchtem Interlock, gültigem lokalen Freigabefenster und betriebsbereitem USB. Wartet auf ausstehende Release-Reports. Startet den 750-ms-Heartbeat-Watchdog und verbraucht die lokale Freigabe. |
PING |
keine | Nur bei armed; erneuert ausschließlich den Heartbeat. Ein neues PING kann niemals selbst armen. |
STOP |
keine | In jedem Zustand zulässig: disarmt, verwirft das lokale Freigabefenster und merkt Release aller Tasten und Maustasten vor. |
RELEASE |
keine | Lässt Tasten und beide Maus-Schnittstellen los. Bleibt bei zuvor armed normalerweise armed; ein USB-Timeout oder ein Sicherheitsereignis disarmt. Auch bei disarmed zulässig. |
ABS |
x y buttons |
X/Y jeweils 0…32767; Buttonmaske 0…7. Setzt absolute Position und gehaltene Buttons. Nur bei armed. |
REL |
dx dy wheel pan buttons |
Deltas und Scrollwerte jeweils −127…127; Buttonmaske 0…7. Bewegungen und Scrollwerte sind einmalige Ereignisse, Buttons sind gehaltene Zustände. Nur bei armed. |
KEY |
mods k1 k2 k3 k4 k5 k6 |
Modifiermaske und alle sechs HID-Usages jeweils 0…255. Ersetzt den gehaltenen Tastaturzustand. 0 bedeutet leeren Key-Slot. Nur bei armed. |
Buttonmaske: Bit 0 = links, Bit 1 = rechts, Bit 2 = Mitte. Ein Klick besteht aus einem Report mit gedrücktem Button und einem nachfolgenden Report mit Buttonmaske 0 oder RELEASE. Bei Wechsel zwischen absoluter und relativer Maus werden zunächst eventuell gehaltene Buttons der anderen Maus-Schnittstelle losgelassen.
Modifiermaske: 1 linker Ctrl, 2 linker Shift, 4 linker Alt, 8 linker GUI, 16 rechter Ctrl, 32 rechter Shift, 64 rechter Alt, 128 rechter GUI. Werte lassen sich bitweise kombinieren. Die Firmware interpretiert Usages roh und akzeptiert technisch den ganzen 8-Bit-Bereich. Der Controller muss sinnvolle Usages, erlaubte Tastenkombinationen und die passende Tastaturbelegung wählen.
KEY enthält keinen Text und keine Unicode-Codepoints. Sprachlayout, Shift/AltGr und Textumsetzung gehören in den Controller; das aktive Layout des Zielrechners muss dazu passen. Die Tastatur ist ein echtes Boot-Keyboard mit 8-Byte-Report: Modifier, reserviertes Nullbyte und sechs Key-Slots.
USB- und Sicherheitsverhalten
- Der Zielrechner sieht drei unabhängige HID-IN-Interfaces, ohne Report-IDs: Keyboard (Endpoint
0x81, 8 Byte), absolute Generic-Desktop-Mouse (Endpoint0x82, 5 Byte) und relative Maus (Endpoint0x83, 5 Byte im Report-Modus, 3 Byte im Boot-Modus). Poll-Intervall jeweils 1 ms. - Die absolute Maus überträgt Buttons sowie X/Y als zwei Little-Endian-16-Bit-Werte. Beim Release bleiben die zuletzt gesendeten Koordinaten erhalten. Vor dem ersten
ABSsendet die Firmware keine unaufgeforderten absoluten Positionsreports. - Die relative Maus benutzt im Report-Modus Buttons, signed 8-Bit X/Y, vertikales Wheel und Consumer
AC Pan. Im Boot-Modus sind ausschließlich Buttons und X/Y verfügbar. Nicht-null Wheel oder Pan erzeugt dannERR BOOT_SCROLL_UNAVAILABLE, statt Scrollen stillschweigend zu bestätigen. - Boot-Tastatur und relative Boot-Maus können grundsätzlich ohne installierten OS-Agenten verwendet werden. Die tatsächliche BIOS/UEFI-, KVM-, Betriebssystem- und Mehrschirm-Kompatibilität muss am Ziel geprüft werden. Absolute HID-Koordinaten garantieren keine Pixel- oder Mehrschirm-Zuordnung.
- Nur neue gültige
PING-Requests verlängern den Watchdog.ARMstartet ihn einmal. Nach 750 ms ohne solches PING disarmt die Firmware und merkt Release vor. Der mitgelieferte Controller verwendet ein Heartbeat-Intervall von 100 ms und maximal 350 ms Wartezeit auf eine UART-Antwort; keine Anfrage-Pipeline. - USB-Trennung, Suspend, Resume, neue Enumeration oder ein Wechsel des HID-Protokolls disarmen. Nach Wiederverbindung werden Nullzustände geliefert; jede erneute Freigabe benötigt wieder GP14 und
ARM. - Warten auf USB-Bereitschaft, Release oder Report-Abschluss ist pro Operation insgesamt auf 100 ms begrenzt; beim Senden teilen sich vorherige Releases und der eigentliche Report dieselbe Frist. Währenddessen laufen TinyUSB, GPIO-Sicherheitsprüfung, Heartbeat-Prüfung und UART-Ausgabe weiter. Empfangene UART-Requests werden anschließend verarbeitet; ein UART-
STOPkann deshalb hinter einem laufenden Report-Warten bis zu 100 ms warten. Der physische Not-Aus wird auch währenddessen geprüft. - Ein zusätzlicher RP2350-Hardware-Watchdog startet die MCU bei einem blockierten Hauptablauf nach ungefähr 1 Sekunde neu. Der Startzustand ist immer disarmed.
- Alle Sicherheitsstopps setzen den gespeicherten Tastatur- und Buttonzustand auf null und senden Release-Reports, sobald USB sie transportieren kann. Bei einem abgetrennten, suspendierten oder nicht reagierenden Ziel ist die Übertragung nicht garantierbar. Bereits gesendete oder gerade laufende USB-Reports sind nicht rückholbar. Der GPIO-Interlock ist eine Software-Sicherheitsfunktion, kein zertifizierter physischer USB-/Stromtrenner.
Fehlercodes
| Code | Bedeutung |
|---|---|
BAD_FRAME |
Syntax, Länge, Nicht-ASCII, RX-Timeout oder UART-Übertragungsfehler |
CRC |
Prüfsumme falsch; keinerlei HID-Aktion |
SEQ_OLD / SEQ_CONFLICT |
Veraltete Sequenz beziehungsweise andere Anfrage mit letzter Sequenz |
UNKNOWN_OP |
Unbekannte Operation |
ARG_COUNT / RANGE |
Falsche Anzahl beziehungsweise Werte außerhalb des Operationsbereichs |
LOCAL_ARM_REQUIRED |
Kein gültiges lokales GP14-Freigabefenster |
ALREADY_ARMED / NOT_ARMED |
Operation im falschen Freigabezustand |
ESTOP |
Not-Aus ist gelatcht |
WATCHDOG |
Heartbeat lief während der USB-Operation ab |
USB_NOT_READY |
USB nicht verbunden, suspendiert oder nicht nutzbar |
USB_TIMEOUT / USB_FAILED |
USB-Operation überschritt die Frist beziehungsweise TinyUSB meldete einen fehlgeschlagenen Transfer |
BOOT_SCROLL_UNAVAILABLE |
Boot-Maus kann Wheel/Pan nicht transportieren |
Prüfsummenbeispiele
Jede folgende Zeile ist mit LF abzuschließen. Vor ARM ist die lokale Freigabe notwendig; während eines längeren Ablaufs müssen zusätzlich neue PING-Anfragen mit steigender Sequenz eingefügt werden.
→ HB1 1 HELLO *76B3
← HB1 1 OK 1 *3A0D
→ HB1 2 ARM *67CC
← HB1 2 OK *A5B9
→ HB1 3 ABS 16384 16384 0 *8651
→ HB1 4 KEY 2 4 0 0 0 0 0 *03AF
→ HB1 5 RELEASE *C666
→ HB1 6 PING *6511
→ HB1 7 STOP *EBB8
Firmware bauen und prüfen
Benötigt werden CMake, ein Arm-GCC-Toolchain mit arm-none-eabi-gcc und ein Raspberry Pi Pico SDK ab 2.1 mit initialisiertem lib/tinyusb-Submodul. Aus dem Verzeichnis hardware-box:
cmake -S pico -B pico/build -DPICO_BOARD=pico2 -DPICO_SDK_PATH=/absoluter/pfad/pico-sdk
cmake --build pico/build --parallel
Das erwartete Ergebnis ist pico/build/hardware_box_pico.uf2. BOOTSEL beim Anstecken gedrückt halten und die UF2-Datei auf das RP2350-Laufwerk kopieren. Der USB-Vendor/Product-Wert CAFE:B001 ist ausschließlich ein Entwicklungswert; für eine verteilte Hardware sind eigene zugeteilte IDs erforderlich. Diese Konstanten stehen in pico/usb_descriptors.c.
Die nativen Protokoll- und Firmware-Simulationstests benötigen keinen Pico SDK:
./pico/tests/run_native.sh
Das Skript benutzt Clang beziehungsweise einen vorhandenen C-Compiler, aktiviert bei Verfügbarkeit AddressSanitizer/UndefinedBehaviorSanitizer und meldet einen Fallback ohne Sanitizer ausdrücklich. Mit HB_SANITIZE=1 werden verfügbare Sanitizer zwingend verlangt, mit HB_SANITIZE=0 deaktiviert. Alternativ mit CMake:
cmake -S pico -B pico/build-native -DHB_NATIVE_TESTS=ON
cmake --build pico/build-native
ctest --test-dir pico/build-native --output-on-failure
Ohne CMake lassen sie sich beispielsweise mit Clang einschließlich AddressSanitizer/UndefinedBehaviorSanitizer bauen. Aus hardware-box/pico:
clang -std=c11 -Wall -Wextra -Werror -fsanitize=address,undefined -g -I . protocol.c tests/protocol_test.c -o /tmp/hb-protocol-test
/tmp/hb-protocol-test
clang -std=c11 -Wall -Wextra -Werror -fsanitize=address,undefined -g -I tests/fake_pico -I . protocol.c tests/firmware_test.c -o /tmp/hb-firmware-test
/tmp/hb-firmware-test
Die Tests prüfen CRC, begrenztes Parsing, 20.000 deterministische Fuzz-Inputs, Sequenz-/Duplikatregeln sowie den echten Firmware-Kontrollpfad gegen simulierte GPIO-, UART- und USB-Funktionen: lokale Freigabe, Release, Boot-Reports, Watchdog, Not-Aus während USB-Warten, USB-Timeout, Reconnect/Suspend und beschädigte beziehungsweise zu lange UART-Zeilen. Sie ersetzen weder einen vollständigen RP2350-Crossbuild noch einen Hardwaretest am Zielrechner.
Optional prüft HB_TINYUSB_PATH=/pfad/zum/pico-sdk/lib/tinyusb ./pico/tests/run_native.sh die echten USB-Descriptor-Makros gegen die Header dieses TinyUSB-Checkouts, einschließlich Interface-Protokollen, Endpoints, Reportlängen und Seriennummern. Diese Integration wurde mit TinyUSB 0.18.0 sowie dem exakten SDK-Submodul geprüft. Zusätzlich wurden ein vollständiger RP2350-Crossbuild und die UF2-Erzeugung erfolgreich ausgeführt: Pico SDK 2.1.1, Arm GNU Toolchain 14.2.Rel1 / GCC 14.2.1 und CMake 3.31.6. Details stehen in BUILD_VALIDATION.md. Flashen, physische USB-/UART-Tests und Zielrechner-Kompatibilität bleiben mangels angeschlossener Hardware unbestätigt.
Offizielle Referenzen: Raspberry Pi C/C++ SDK, Pico SDK Hardware APIs, TinyUSB HID Device API, USB HID Specification.