12.3. Formatul pachetului¶
Fiecare octet care traversează linia dintre cameră și gazdă face parte dintr-un pachet. Un pachet începe cu un antet de 10 octeți, conține o sarcină utilă de lungime variabilă și se termină cu un CRC final de 4 octeți. Niciun alt octet nu apare pe linie – odată ce gazda a văzut cuvântul de sincronizare de 2 octeți, octeții următori sunt un antet în această secvență exactă.
12.3.1. Antetul¶
Zece octeți, împachetați fără umplere (padding). Fiecare câmp:
sync– cuvântul pe 16 biți0xD5AAîn ordine little-endian. Octetul 0 pe linie este0xAA, octetul 1 este0xD5. Un receptor care scanează octeții poate găsi începutul unui pachet căutând perecheaAA D5; orice se află înaintea ei este tratat ca gunoi. Alegerea valorii este deliberată:0xAAși0xD5apar rareori în text imprimabil, iar perechea este puțin probabil să apară accidental în mijlocul unei sarcini utile.seq– un octet. Un contor care se incrementează cu unu pentru fiecare pachet trimis pe o direcție dată. Receptorul verifică dacă numărul de secvență al următorului pachet este cel așteptat; dacă nu, stratul de fiabilitate cere o retransmisie.chan– un octet. ID-ul canalului căruia îi aparține acest pachet. Canalele 0..31 sunt utilizabile; canalele încorporatestdin,stdout,streamși (opțional)profilepreiau ID-uri fixe pe care camera le rezervă.flags– un octet. Un câmp de biți care îi spune receptorului cum să interpreteze pachetul:bitul 0
ACK– acest pachet este o confirmare a unuia anterior.bitul 1
NAK– acest pachet respinge unul anterior.bitul 2
RTX– acest pachet este o retransmisie.bitul 3
ACK_REQ– expeditorul dorește ca acest pachet să fie confirmat.bitul 4
FRAGMENT– mai multe fragmente urmează după acesta într-un mesaj mai mare.bitul 5
EVENT– acest pachet transportă un eveniment de canal în loc de date.biții 6 și 7 sunt rezervați.
opcode– un octet. Codul comenzii sau al răspunsului. Biblioteca de protocol rezervă intervale de coduri de operație în funcție de scop:0x00..0x0F– comenzi de protocol (SYNC, GET_CAPS, SET_CAPS, STATS, VERSION).0x10..0x1F– comenzi de sistem (RESET, BOOT, INFO, EVENT, MEMORY).0x20..0x2F– comenzi de canal (LIST, POLL, LOCK, UNLOCK, SHAPE, SIZE, READ, WRITE, IOCTL, EVENT).
len– doi octeți, little-endian. Numărul de octeți de sarcină utilă care urmează după antet. O lungime de zero este legală – multe confirmări și comenzi mici nu transportă nicio sarcină utilă.crc– doi octeți. Un CRC-16 calculat peste cei opt octeți anteriori ai antetului. Un receptor care primește un antet cu un CRC eronat renunță la întregul pachet fără măcar să se uite la sarcina utilă.
12.3.2. Sarcina utilă¶
Zero sau mai mulți octeți, tratați ca opaci de către stratul de încadrare. Ce se află în sarcina utilă depinde de codul de operație: pentru un răspuns CHANNEL_READ sunt datele efective ale canalului; pentru un răspuns GET_CAPS este o mică structură fixă; pentru o scriere pe canal este orice a trimis gazda.
Dimensiunea maximă a sarcinii utile depinde de dimensiunea tamponului de protocol al camerei (consultă tabelul per placă din protocol.init()). Mesajele mai lungi decât plafonul sunt împărțite în fragmente, cu indicatorul FRAGMENT setat pe toate cu excepția ultimului.
12.3.3. CRC-ul final¶
Patru octeți, un CRC-32 calculat peste sarcina utilă. Detectează coruperea pe care CRC-ul de antet nu o poate vedea, în special pe sarcini utile lungi, unde o eroare de un singur bit în mijlocul cadrului ar trece altfel neobservată.
Împărțirea verificării integrității între două CRC-uri este deliberată. CRC-ul de antet protejează câmpurile de încadrare însele – în special lungimea sarcinii utile. Fără un CRC de antet separat, o singură inversare de bit în octetul de lungime ar face ca receptorul să citească un număr greșit de octeți pentru sarcina utilă și să se desincronizeze complet de fluxul de octeți; cu unul, un antet deteriorat este respins direct, iar receptorul rescanează după următorul cuvânt de sincronizare. CRC-ul de sarcină utilă protejează apoi corpul mesajului ca o preocupare separată, astfel încât o inversare de bit în date este raportată ca o sarcină utilă coruptă, în loc să fie confundată cu o eroare de încadrare.
Formatul este suficient de mic pentru a fi parcurs octet cu octet, iar faptul că fiecare pachet are același aranjament – sincronizare, apoi antet, apoi sarcină utilă, apoi CRC – înseamnă că un analizor scris manual încape într-un ecran de cod. De aceea, o implementare minusculă de gazdă în C, Python sau Rust este un proiect de weekend; biblioteca de protocol este versiunea Python întreținută de pe fiecare parte.