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

313 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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)
```c
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:
```c
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:
```c
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:
```c
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:
```c
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:
```c
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:
```c
// 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:
```c
// 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:
```c
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:
```c
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
```