12 KiB
Buzzer Protocol (Wire Specification)
1. Zweck und Geltungsbereich
Das Buzzer Protocol definiert ein transportunabhaengiges, binaeres Frame-Format fuer die Kommunikation zwischen Host und Device. Unterstuetzte Transporte sind aktuell BLE und USB CDC ACM/UART.
Das Protokoll spezifiziert:
- Frame-Struktur (Header + Payload)
- Frametypen
- Datentypen fuer Request/Response
- Semantik fuer Stream-Transfers (Verzeichnisliste, Datei, Firmware)
2. Transport- und Codierungsregeln
- Alle ganzzahligen Felder werden in Little Endian uebertragen.
- Die im Header angegebene
payload_lengthbezieht sich ausschliesslich auf die Nutzdaten ohne Header. - Bei UART kann optional eine Synchronisationssequenz
BUZZ(0x42 0x55 0x5A 0x5A) vor einem Frame verwendet werden, um Framing nach Leitungsstoerungen zu resynchronisieren.
3. Frame-Format
3.1 Header (3 Byte)
uint8_t frame_type
uint16_t payload_length // Little Endian
3.2 Gesamtframe
+------------------+-------------------------+
| Header (3 Byte) | Payload (optional) |
| frame_type (1B) | payload_length Byte |
| payload_len (2B) | |
+------------------+-------------------------+
4. Frametypen
4.1 Steuer- und Anfrageframes
| Wert | Name | Richtung | Beschreibung |
|---|---|---|---|
0x00 |
REQUEST |
Host → Device | Abfrage eines Datentyps |
0x10 |
RESPONSE |
Device → Host | Antwort auf REQUEST |
0x11 |
ACK |
Host ↔ Device | Flusskontrolle bei Stream-Transfers |
0x12 |
ERROR |
Device → Host | Fehlerantwort mit Fehlercode |
0x13 |
SUCCESS |
Device → Host | Bestaetigung einer Operation |
4.2 Datei-Transfer
| Wert | Name | Richtung | Beschreibung |
|---|---|---|---|
0x20 |
FILE_START |
Host ↔ Device | Beginn eines Dateitransfers |
0x21 |
FILE_CHUNK |
Host ↔ Device | Ein Datenblock des Dateitransfers |
0x22 |
FILE_END |
Host ↔ Device | Abschluss des Dateitransfers inkl. CRC32 |
4.3 Firmware-Transfer (reserviert, noch nicht implementiert)
| Wert | Name |
|---|---|
0x30 |
FW_START |
0x31 |
FW_CHUNK |
0x32 |
FW_END |
4.4 Verzeichnisliste
| Wert | Name | Richtung | Beschreibung |
|---|---|---|---|
0x40 |
LS_START |
Device → Host | Beginn des Listing-Streams |
0x41 |
LS_ENTRY |
Device → Host | Ein Verzeichniseintrag |
0x42 |
LS_END |
Device → Host | Ende des Listing-Streams |
5. Request/Response-Schema
5.1 Request (frame_type = 0x00)
Payload-Mindestformat:
uint8_t data_type // Nutzt enum buzz_data_type
// optional: datentypspezifische Parameter
Wire-Format:
[0x00][payload_length LE][data_type][optional parameters]
5.2 Response (frame_type = 0x10)
Payload-Mindestformat:
uint8_t data_type // Echo des angefragten data_type
// danach: datentypspezifische Response-Daten
Wire-Format:
[0x10][payload_length LE][data_type][response payload]
6. Datentypen (Request/Response)
Definierte data_type-Werte:
| Wert | Name | Beschreibung |
|---|---|---|
0x01 |
PROTO_INFO |
Protokollversion und Chunk-Groesse |
0x02 |
DEVICE_INFO |
Geraeteinformationen (TBD) |
0x03 |
FS_INFO |
Dateisystem-Statistik und Pfadnamen |
0x20 |
FILE_GET |
Datei vom Device anfordern |
0x21 |
FILE_PUT |
Datei auf das Device hochladen |
0x22 |
TAGS_GET |
Metadaten-Tags anfordern |
0x23 |
TAGS_PUT |
Metadaten-Tags schreiben |
0x24 |
RM_FILE |
Datei loeschen |
0x25 |
RENAME_FILE |
Datei umbenennen |
0x30 |
FW_UPDATE |
Firmware-Update starten |
0x40 |
LS |
Verzeichnisliste starten |
6.1 PROTO_INFO (0x01)
Request-Parameter: keine
Response-Payload:
uint8_t data_type; // 0x01
uint16_t version; // Protokollversion (LE)
uint16_t max_chunk_size; // max. Nutzdaten pro Frame ohne Header (LE)
Hinweis: max_chunk_size ergibt sich aus der internen Slab-Konfiguration (CONFIG_BUZZ_PROTO_SLAB_SIZE - 3).
6.2 DEVICE_INFO (0x02)
TBD
6.3 FS_INFO (0x03)
Request-Parameter: keine
Response-Payload:
uint8_t data_type; // 0x03
uint32_t total_size; // Gesamtgroesse Flash in Bytes (LE)
uint32_t free_size; // Freier Speicher in Bytes (LE)
uint8_t max_path_length; // Maximal erlaubte Pfadlaenge
uint8_t sys_path_length; // Laenge des System-Pfades (ohne 0-Terminator)
uint8_t audio_path_length; // Laenge des Audio-Pfades (ohne 0-Terminator)
uint8_t data[]; // sys_path gefolgt von audio_path, nicht nullterminiert
6.4 LS (0x40) — Verzeichnisliste anfordern
Startet einen LS-Stream fuer den angegebenen Pfad.
Request-Payload:
uint8_t data_type; // 0x40
char path[]; // Pfad ohne 0-Terminator, Laenge ergibt sich aus payload_length - 1
Wire-Format (Beispiel fuer Pfad /a):
[0x00][0x03 0x00][0x40][0x2F 0x61]
Das Device antwortet mit dem LS-Stream (siehe Abschnitt 8).
6.5 RM_FILE (0x24) — Datei loeschen
Request-Payload:
uint8_t data_type; // 0x24
uint8_t path_length; // Laenge des Pfads
char path[]; // Pfad ohne 0-Terminator
6.6 RENAME_FILE (0x25) — Datei umbenennen
Request-Payload:
uint8_t data_type; // 0x25
uint8_t old_path_length; // Laenge des alten Pfads
uint8_t new_path_length; // Laenge des neuen Pfads
char paths[]; // Alter Pfad, direkt gefolgt vom neuen Pfad (beide ohne 0-Terminator)
6.7 FILE_PUT (0x21) / TAGS_PUT (0x23) — Upload initiieren
Request-Payload:
uint8_t data_type; // 0x21 (Datei) oder 0x23 (Tags)
uint32_t total_size; // Dateigroesse in Bytes (LE)
char path[]; // Zielpfad ohne 0-Terminator
7. ACK-, ERROR- und SUCCESS-Frames
7.1 ACK (frame_type = 0x11) — Host ↔ Device
Wird waehrend eines laufenden Stream-Transfers gesendet, um der sendenden Seite Credits (Sendeerlaubnisse) zu erteilen.
Bei einem Download (LS oder FILE_GET) sendet der Host das ACK. Bei einem Upload (FILE_PUT oder TAGS_PUT) sendet das Device das ACK.
Format:
// Header:
uint8_t frame_type; // 0x11
uint16_t payload_length; // 0x0002
// Payload:
uint16_t credits; // Anzahl der Entries, die das Device senden darf (LE)
Wire-Format (Beispiel: 64 Credits):
[0x11][0x02 0x00][0x40 0x00]
Semantik:
- Der Host sendet nach Empfang von
LS_STARTinitial Credits (typisch 64). - Das Device dekrementiert seinen internen Credit-Zaehler mit jeder gesendeten
LS_ENTRY. - Bei 0 Credits wartet das Device auf ein weiteres ACK (Timeout: 5 × 500 ms, danach Abbruch).
- Der Host soll bei Bedarf weitere Credits nachsenden, bevor die bisherigen aufgebraucht sind.
7.2 ERROR (frame_type = 0x12) — Device → Host
Format:
// Header:
uint8_t frame_type; // 0x12
uint16_t payload_length; // 0x0002
// Payload:
uint16_t error_code; // Positiver Zephyr-errno-Wert (LE)
Wire-Format (Beispiel: ENOENT = 2):
[0x12][0x02 0x00][0x02 0x00]
ERROR kann jederzeit als Antwort auf einen REQUEST oder waehrend eines Streams gesendet werden. Ein ERROR-Frame waehrend eines aktiven LS-Streams beendet diesen implizit.
Fehlercode-Tabelle (Zephyr errno, positiver Wert):
| Code | Zephyr-Name | Bedeutung |
|---|---|---|
| 1 | EPERM |
Fehlende Berechtigung |
| 2 | ENOENT |
Datei oder Verzeichnis nicht gefunden |
| 5 | EIO |
Ein-/Ausgabefehler auf dem Flash |
| 12 | ENOMEM |
Nicht genuegend Speicher frei |
| 16 | EBUSY |
Geraet oder Ressource belegt |
| 22 | EINVAL |
Ungültiges Argument oder Parameter |
| 24 | EMFILE |
Zu viele offene Dateien |
| 28 | ENOSPC |
Kein freier Speicherplatz mehr |
| 36 | ENAMETOOLONG |
Dateiname oder Pfad zu lang |
| 88 | ENOSYS |
Funktion nicht implementiert |
| 134 | ENOTSUP |
Operation nicht unterstuetzt |
7.3 SUCCESS (frame_type = 0x13) — Device → Host
Bestaetigt den erfolgreichen Abschluss einer Operation, z. B. nach Beendigung eines Uploads oder einer Dateioperation (Loeschen, Umbenennen).
Format:
// Header:
uint8_t frame_type; // 0x13
uint16_t payload_length; // 0x0001
// Payload:
uint8_t data_type; // Der Befehl, der erfolgreich war (z.B. 0x21 fuer FILE_PUT)
Wire-Format (Beispiel: Erfolg bei RM_FILE):
[0x13][0x01 0x00][0x24]
8. LS-Stream (Verzeichnisliste)
Der LS-Stream wird durch einen REQUEST mit data_type = 0x40 ausgeloest und laeuft wie folgt ab:
Host Device
| |
|-- REQUEST (data_type=LS, path) -->|
| | (oeffnet Verzeichnis)
|<--------- LS_START (leer) --------|
| |
|------ ACK (credits=64) ---------->|
| |
|<-- LS_ENTRY (entry 1) ------------|
|<-- LS_ENTRY (entry 2) ------------|
| ... |
|<-- LS_ENTRY (entry 64) -----------| (credits = 0, Device wartet)
| |
|------ ACK (credits=64) ---------->|
| |
|<-- LS_ENTRY (entry 65) -----------|
| ... |
|<--------- LS_END -----------------|
8.1 LS_START (0x40) — Device → Host
Signalisiert den Beginn des Streams. Keine Payload.
[0x40][0x00 0x00]
8.2 LS_ENTRY (0x41) — Device → Host
Ein Eintrag pro Verzeichniselement.
Payload:
uint8_t type; // 0x00 = Datei, 0x01 = Verzeichnis (buzz_fs_entry_type)
uint32_t size; // Dateigroesse in Bytes (LE); bei Verzeichnissen 0
uint8_t name_length; // Laenge des Namens (ohne 0-Terminator)
char name[]; // Datei-/Verzeichnisname, nicht nullterminiert
type-Werte:
| Wert | Bedeutung |
|---|---|
0x00 |
Datei (FILE) |
0x01 |
Verzeichnis (DIR) |
8.3 LS_END (0x42) — Device → Host
Signalisiert das Ende des Streams.
Payload:
uint32_t total_entries; // Gesamtzahl gesendeter Eintraege (LE)
Der Host kann total_entries mit der empfangenen Anzahl von LS_ENTRY-Frames vergleichen, um Vollstaendigkeit zu pruefen.
8.4 Fehler- und Timeoutbehandlung
- Tritt ein Fehler beim Lesen auf, sendet das Device einen
ERROR-Frame und beendet den Stream. - Empfaengt das Device 5 Mal in Folge keine Credits innerhalb von je 500 ms (2,5 s gesamt), bricht es den Stream intern ab (kein ERROR-Frame, Stream wird still verworfen).
- Der Host sollte einen eigenen Watchdog implementieren; empfohlener Timeout: 3 s ohne empfangenen Frame.
9. Beispiele
9.1 PROTO_INFO abfragen
Request:
00 01 00 01
00:REQUEST01 00:payload_length = 101:data_type = PROTO_INFO
Response (Beispielwerte):
10 05 00 01 01 00 FD 00
10:RESPONSE05 00:payload_length = 501:data_type = PROTO_INFO01 00:version = 1FD 00:max_chunk_size = 253
9.2 Verzeichnisliste /a anfordern
Request:
00 03 00 40 2F 61
00:REQUEST03 00:payload_length = 340:data_type = LS2F 61: Pfad/a
Antwort (Sequenz):
40 00 00 // LS_START, keine Payload
// Host sendet ACK mit Credits
11 02 00 40 00 // ACK, 64 Credits
// Device sendet Eintraege
41 0A 00 00 00 00 00 00 06 73 6F 75 6E 64 31 // LS_ENTRY: FILE, size=0, name="sound1" (gekuerzt)
// ... weitere Eintraege ...
42 04 00 01 00 00 00 // LS_END, total_entries = 1