Files
buzzer_2/protocol.md
2026-03-12 07:07:00 +01:00

10 KiB
Raw Blame History

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_length bezieht 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

4.2 Datei-Transfer (reserviert, noch nicht implementiert)

Wert Name
0x20 FILE_START
0x21 FILE_CHUNK
0x22 FILE_END

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
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).

7. ACK- und ERROR-Frames

7.1 ACK (frame_type = 0x11) — Host → Device

Wird waehrend eines laufenden LS-Streams gesendet, um dem Device Credits (Sendeerlaubnisse) zu erteilen.

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_START initial 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

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: REQUEST
  • 01 00: payload_length = 1
  • 01: data_type = PROTO_INFO

Response (Beispielwerte):

10 05 00 01 01 00 FD 00
  • 10: RESPONSE
  • 05 00: payload_length = 5
  • 01: data_type = PROTO_INFO
  • 01 00: version = 1
  • FD 00: max_chunk_size = 253

9.2 Verzeichnisliste /a anfordern

Request:

00 03 00 40 2F 61
  • 00: REQUEST
  • 03 00: payload_length = 3
  • 40: data_type = LS
  • 2F 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