12.3. Formát paketu#
Každý bajt, který projde přes vedení mezi kamerou a hostitelem, je součástí paketu. Paket začíná 10bajtovou hlavičkou, pokračuje užitečným obsahem (payload) proměnné délky a končí 4bajtovým koncovým CRC. Na vedení se neobjevují žádné jiné bajty – jakmile hostitel uvidí 2bajtové synchronizační slovo, následující bajty jsou hlavička v přesně tomto pořadí.
12.3.1. Hlavička#
Deset bajtů, sbalených bez vycpávky (padding). Každé pole:
sync– 16bitové slovo0xD5AAv pořadí little-endian. Bajt 0 na vedení je0xAA, bajt 1 je0xD5. Příjemce procházející bajty může najít začátek paketu vyhledáním dvojiceAA D5; vše před ní je považováno za smetí. Volba hodnoty je záměrná:0xAAa0xD5se v tisknutelném textu vyskytují zřídka a je nepravděpodobné, že by se dvojice náhodně objevila uprostřed užitečného obsahu (payload).seq– jeden bajt. Čítač, který se zvyšuje o jedna pro každý paket odeslaný v daném směru. Příjemce kontroluje, že pořadové číslo dalšího paketu je očekávané; pokud ne, vrstva spolehlivosti požádá o opětovné odeslání.chan– jeden bajt. ID kanálu, kterému tento paket patří. Použitelné jsou kanály 0..31; vestavěné kanálystdin,stdout,streama (volitelně)profilezabírají pevná ID, která si kamera rezervuje.flags– jeden bajt. Bitové pole, které příjemci říká, jak paket interpretovat:bit 0
ACK– tento paket je potvrzení (acknowledgement) předchozího.bit 1
NAK– tento paket odmítá předchozí.bit 2
RTX– tento paket je opětovné odeslání.bit 3
ACK_REQ– odesílatel chce, aby byl tento paket potvrzen.bit 4
FRAGMENT– po tomto následují další fragmenty větší zprávy.bit 5
EVENT– tento paket nese událost kanálu, nikoli data.bity 6 a 7 jsou rezervované.
opcode– jeden bajt. Kód příkazu nebo odpovědi. Knihovna protokolu rezervuje rozsahy opcode podle účelu:0x00..0x0F– příkazy protokolu (SYNC, GET_CAPS, SET_CAPS, STATS, VERSION).0x10..0x1F– systémové příkazy (RESET, BOOT, INFO, EVENT, MEMORY).0x20..0x2F– příkazy kanálu (LIST, POLL, LOCK, UNLOCK, SHAPE, SIZE, READ, WRITE, IOCTL, EVENT).
len– dva bajty, little-endian. Počet bajtů užitečného obsahu, které následují po hlavičce. Délka nula je legální – mnoho potvrzení a malých příkazů nenese žádný užitečný obsah (payload).crc– dva bajty. CRC-16 přes předchozích osm bajtů hlavičky. Příjemce, který dostane hlavičku se špatným CRC, zahodí celý paket, aniž by se vůbec podíval na užitečný obsah (payload).
12.3.2. Užitečný obsah (payload)#
Nula nebo více bajtů, vrstvou rámcování považovaných za neprůhledné. Co je v užitečném obsahu, závisí na opcode: pro odpověď CHANNEL_READ jsou to skutečná data kanálu; pro odpověď GET_CAPS je to malá pevná struktura; pro zápis na kanál je to cokoli, co hostitel poslal.
Maximální velikost užitečného obsahu (payload) závisí na velikosti bufferu protokolu kamery (viz tabulka podle desky v protocol.init()). Zprávy delší než limit jsou rozděleny na fragmenty s nastaveným příznakem FRAGMENT u všech kromě posledního.
12.3.3. Koncové CRC#
Čtyři bajty, CRC-32 přes užitečný obsah (payload). Zachytí poškození, které CRC hlavičky nedokáže vidět, zejména u dlouhých užitečných obsahů, kde by jinak jednobitová chyba uprostřed rámce proklouzla.
Rozdělení kontroly integrity mezi dvě CRC je záměrné. CRC hlavičky chrání samotná pole rámcování – zejména délku užitečného obsahu. Bez samostatného CRC hlavičky by jediný překlopený bit v bajtu délky způsobil, že by příjemce přečetl nesprávný počet bajtů užitečného obsahu a zcela se rozsynchronizoval s bajtovým proudem; s ním je poškozená hlavička rovnou odmítnuta a příjemce znovu hledá další synchronizační slovo. CRC užitečného obsahu pak chrání tělo zprávy jako samostatnou záležitost, takže překlopený bit v datech je hlášen jako poškozený užitečný obsah, nikoli zaměněn za chybu rámcování.
Formát je dost malý na to, aby se dal projít bajt po bajtu, a fakt, že každý paket má stejné rozvržení – synchronizace, pak hlavička, pak užitečný obsah, pak CRC – znamená, že ručně napsaný parser se vejde na jednu obrazovku kódu. Proto je drobná hostitelská implementace v C, Pythonu nebo Rustu víkendový projekt; knihovna protokolu je udržovaná verze v Pythonu na každé straně.