12.3. Das Paketformat¶
Jedes Byte, das über die Leitung zwischen Kamera und Host geht, ist Teil eines Pakets. Ein Paket beginnt mit einem 10-Byte-Header, führt eine Nutzlast variabler Länge und endet mit einer nachgestellten 4-Byte-CRC. Keine anderen Bytes erscheinen auf der Leitung – sobald der Host das 2-Byte-Sync-Wort gesehen hat, sind die nächsten Bytes ein Header in genau dieser Reihenfolge.
12.3.1. Der Header¶
Zehn Bytes, ohne Padding gepackt. Jedes Feld:
sync– das 16-Bit-Wort0xD5AAin Little-Endian-Reihenfolge. Byte 0 auf der Leitung ist0xAA, Byte 1 ist0xD5. Ein Empfänger, der Bytes durchsucht, kann den Beginn eines Pakets finden, indem er nach dem PaarAA D5sucht; alles davor wird als Müll behandelt. Die Wahl des Werts ist bewusst:0xAAund0xD5kommen selten in druckbarem Text vor, und das Paar tritt unwahrscheinlich zufällig mitten in einer Nutzlast auf.seq– ein Byte. Ein Zähler, der für jedes in einer bestimmten Richtung gesendete Paket um eins erhöht wird. Der Empfänger prüft, ob die Sequenznummer des nächsten Pakets die erwartete ist; falls nicht, fordert die Zuverlässigkeitsschicht eine erneute Übertragung an.chan– ein Byte. Die Kanal-ID, zu der dieses Paket gehört. Die Kanäle 0..31 sind nutzbar; die eingebauten Kanälestdin,stdout,streamund (optional)profilebelegen feste IDs, die die Kamera reserviert.flags– ein Byte. Ein Bitfeld, das dem Empfänger mitteilt, wie das Paket zu interpretieren ist:Bit 0
ACK– dieses Paket ist eine Bestätigung eines vorherigen.Bit 1
NAK– dieses Paket weist ein vorheriges zurück.Bit 2
RTX– dieses Paket ist eine erneute Übertragung.Bit 3
ACK_REQ– der Sender möchte, dass dieses Paket bestätigt wird.Bit 4
FRAGMENT– diesem folgen weitere Fragmente in einer größeren Nachricht.Bit 5
EVENT– dieses Paket trägt ein Kanalereignis statt Daten.Die Bits 6 und 7 sind reserviert.
opcode– ein Byte. Der Befehls- oder Antwortcode. Die Protokollbibliothek reserviert Opcode-Bereiche nach Zweck:0x00..0x0F– Protokollbefehle (SYNC, GET_CAPS, SET_CAPS, STATS, VERSION).0x10..0x1F– Systembefehle (RESET, BOOT, INFO, EVENT, MEMORY).0x20..0x2F– Kanalbefehle (LIST, POLL, LOCK, UNLOCK, SHAPE, SIZE, READ, WRITE, IOCTL, EVENT).
len– zwei Bytes, Little-Endian. Die Anzahl der Nutzlast-Bytes, die dem Header folgen. Eine Länge von null ist zulässig – viele Bestätigungen und kleine Befehle tragen keine Nutzlast.crc– zwei Bytes. Eine CRC-16 über die vorhergehenden acht Header-Bytes. Ein Empfänger, der einen Header mit einer fehlerhaften CRC erhält, verwirft das gesamte Paket, ohne überhaupt die Nutzlast anzusehen.
12.3.2. Die Nutzlast¶
Null oder mehr Bytes, die von der Framing-Schicht als undurchsichtig behandelt werden. Was in der Nutzlast steht, hängt vom Opcode ab: bei einer CHANNEL_READ-Antwort sind es die eigentlichen Kanaldaten; bei einer GET_CAPS-Antwort ist es eine kleine feste Struktur; bei einem Kanal-Schreibvorgang ist es das, was der Host gesendet hat.
Die maximale Nutzlastgröße hängt von der Größe des Protokollpuffers der Kamera ab (siehe die platinenspezifische Tabelle in protocol.init()). Nachrichten, die länger als die Obergrenze sind, werden in Fragmente aufgeteilt, wobei das FRAGMENT-Flag auf allen außer dem letzten gesetzt ist.
12.3.3. Die nachgestellte CRC¶
Vier Bytes, eine CRC-32 über die Nutzlast. Sie fängt Beschädigungen ab, die die Header-CRC nicht sehen kann, insbesondere bei langen Nutzlasten, bei denen ein Ein-Bit-Fehler mitten im Frame sonst durchschlüpfen würde.
Die Aufteilung der Integritätsprüfung auf zwei CRCs ist bewusst gewählt. Die Header-CRC schützt die Framing-Felder selbst – insbesondere die Nutzlastlänge. Ohne eine separate Header-CRC würde ein einziges gekipptes Bit im Längen-Byte dazu führen, dass der Empfänger die falsche Anzahl von Bytes für die Nutzlast liest und vollständig die Synchronisation mit dem Byte-Stream verliert; mit ihr wird ein beschädigter Header umgehend zurückgewiesen und der Empfänger sucht erneut nach dem nächsten Sync-Wort. Die Nutzlast-CRC schützt dann den Nachrichtenkörper als separaten Belang, sodass ein gekipptes Bit in den Daten als beschädigte Nutzlast gemeldet wird, statt für einen Framing-Fehler gehalten zu werden.
Das Format ist klein genug, um Byte für Byte durchzugehen, und die Tatsache, dass jedes Paket dasselbe Layout hat – Sync, dann Header, dann Nutzlast, dann CRC – bedeutet, dass ein selbstgeschriebener Parser in einen Bildschirm voll Code passt. Deshalb ist eine winzige Host-Implementierung in C, Python oder Rust ein Wochenendprojekt; die Protokollbibliothek ist die gepflegte Python-Version auf jeder Seite.