12.3. Paketformatet

Varje byte som korsar tråden mellan kameran och värden är en del av ett paket. Ett paket börjar med ett 10 bytes stort huvud, följs av en nyttolast med variabel längd, och slutar med en 4 bytes stor avslutande CRC. Inga andra bytes förekommer på tråden – när väl värden har sett det 2 bytes stora synkordet är de nästa bytena ett huvud i exakt denna sekvens.

En horisontell layout av ett protokollpaket som visar det 10 bytes stora huvudet (synkord, sekvensnummer, kanal-ID, flaggor, opcode, nyttolastlängd, huvud-CRC) följt av nyttolasten med variabel längd och en 4 bytes stor nyttolast-CRC.

12.3.1. Huvudet

Tio bytes, packade utan utfyllnad. Varje fält:

  • sync – det 16-bitars ordet 0xD5AA i little-endian-ordning. Byte 0 på tråden är 0xAA, byte 1 är 0xD5. En mottagare som skannar bytes kan hitta början på ett paket genom att söka efter paret AA D5; allt före det behandlas som skräp. Valet av värde är medvetet: 0xAA och 0xD5 förekommer sällan i utskrivbar text, och paret är osannolikt att inträffa av misstag mitt i en nyttolast.

  • seq – en byte. En räknare som ökar med ett för varje paket som skickas i en given riktning. Mottagaren kontrollerar att nästa pakets sekvensnummer är det förväntade; om inte ber tillförlitlighetslagret om en omsändning.

  • chan – en byte. Kanal-ID:t som detta paket tillhör. Kanalerna 0..31 är användbara; de inbyggda kanalerna stdin, stdout, stream och (valfritt) profile tar fasta ID:n som kameran reserverar.

  • flags – en byte. Ett bitfält som talar om för mottagaren hur paketet ska tolkas:

    • bit 0 ACK – detta paket är en bekräftelse på ett tidigare.

    • bit 1 NAK – detta paket avvisar ett tidigare.

    • bit 2 RTX – detta paket är en omsändning.

    • bit 3 ACK_REQ – avsändaren vill ha detta paket bekräftat.

    • bit 4 FRAGMENT – fler fragment följer efter detta i ett större meddelande.

    • bit 5 EVENT – detta paket bär en kanalhändelse snarare än data.

    • bitarna 6 och 7 är reserverade.

  • opcode – en byte. Kommando- eller svarskoden. Protokollbiblioteket reserverar opcode-intervall efter syfte:

    • 0x00..0x0F – protokollkommandon (SYNC, GET_CAPS, SET_CAPS, STATS, VERSION).

    • 0x10..0x1F – systemkommandon (RESET, BOOT, INFO, EVENT, MEMORY).

    • 0x20..0x2F – kanalkommandon (LIST, POLL, LOCK, UNLOCK, SHAPE, SIZE, READ, WRITE, IOCTL, EVENT).

  • len – två bytes, little-endian. Antalet nyttolastbytes som följer efter huvudet. En längd på noll är tillåten – många bekräftelser och små kommandon bär ingen nyttolast.

  • crc – två bytes. En CRC-16 över de föregående åtta huvudbytena. En mottagare som får ett huvud med felaktig CRC förkastar hela paketet utan att ens titta på nyttolasten.

12.3.2. Nyttolasten

Noll eller fler bytes, behandlade som ogenomskinliga av inramningslagret. Vad som finns i nyttolasten beror på opcode:n: för ett CHANNEL_READ-svar är det den faktiska kanaldatan; för ett GET_CAPS-svar är det en liten fast struktur; för en kanalskrivning är det vad värden än skickade.

Den maximala nyttolaststorleken beror på kamerans protokollbuffertstorlek (se tabellen per kort i protocol.init()). Meddelanden längre än taket delas upp i fragment med FRAGMENT-flaggan satt på alla utom det sista.

12.3.3. Den avslutande CRC:n

Fyra bytes, en CRC-32 över nyttolasten. Fångar korruption som huvud-CRC:n inte kan se, särskilt på långa nyttolaster där ett enbitsfel mitt i ramen annars skulle slinka igenom.

Att dela upp integritetskontrollen över två CRC:er är medvetet. Huvud-CRC:n skyddar inramningsfälten själva – särskilt nyttolastlängden. Utan en separat huvud-CRC skulle en enda bitvändning i längdbyten få mottagaren att läsa fel antal bytes för nyttolasten och helt tappa synken med byteströmmen; med en sådan förkastas ett skadat huvud direkt och mottagaren skannar om efter nästa synkord. Nyttolast-CRC:n skyddar sedan meddelandekroppen som en separat angelägenhet, så att en bitvändning i datan rapporteras som en korrupt nyttolast snarare än misstas för ett inramningsfel.

Formatet är litet nog att gå igenom byte för byte, och det faktum att varje paket har samma layout – synk, sedan huvud, sedan nyttolast, sedan CRC – innebär att en handskriven parser ryms på en skärm med kod. Det är därför en liten värdimplementation i C, Python eller Rust är ett helgprojekt; protokollbiblioteket är den underhållna Python-versionen på varje sida.