12.3. Format pakietu

Każdy bajt przechodzący przez przewód między kamerą a hostem jest częścią pakietu. Pakiet zaczyna się od 10-bajtowego nagłówka, zawiera ładunek o zmiennej długości i kończy się 4-bajtowym końcowym CRC. Na przewodzie nie pojawiają się żadne inne bajty – gdy host zobaczy 2-bajtowe słowo synchronizacji, kolejne bajty są nagłówkiem w dokładnie tej kolejności.

Poziomy układ pakietu protokołu pokazujący 10-bajtowy nagłówek (słowo synchronizacji, numer sekwencji, identyfikator kanału, flagi, kod operacji, długość ładunku, CRC nagłówka), po którym następuje ładunek o zmiennej długości oraz 4-bajtowy CRC ładunku.

12.3.1. Nagłówek

Dziesięć bajtów, upakowanych bez dopełnienia. Każde pole:

  • sync – 16-bitowe słowo 0xD5AA w kolejności little-endian. Bajt 0 na przewodzie to 0xAA, bajt 1 to 0xD5. Odbiornik skanujący bajty potrafi znaleźć początek pakietu, wyszukując parę AA D5; wszystko przed nią jest traktowane jako śmieci. Wybór wartości jest celowy: 0xAA i 0xD5 rzadko pojawiają się w tekście drukowalnym, a para ta jest mało prawdopodobna do przypadkowego wystąpienia w środku ładunku.

  • seq – jeden bajt. Licznik, który zwiększa się o jeden dla każdego pakietu wysłanego w danym kierunku. Odbiornik sprawdza, czy numer sekwencji kolejnego pakietu jest oczekiwany; jeśli nie, warstwa niezawodności prosi o retransmisję.

  • chan – jeden bajt. Identyfikator kanału, do którego należy ten pakiet. Kanały 0..31 są dostępne; wbudowane kanały stdin, stdout, stream oraz (opcjonalnie) profile zajmują stałe identyfikatory zarezerwowane przez kamerę.

  • flags – jeden bajt. Pole bitowe informujące odbiornik, jak interpretować pakiet:

    • bit 0 ACK – ten pakiet jest potwierdzeniem poprzedniego.

    • bit 1 NAK – ten pakiet odrzuca poprzedni.

    • bit 2 RTX – ten pakiet jest retransmisją.

    • bit 3 ACK_REQ – nadawca chce, aby ten pakiet został potwierdzony.

    • bit 4 FRAGMENT – po tym pakiecie następują kolejne fragmenty większej wiadomości.

    • bit 5 EVENT – ten pakiet niesie zdarzenie kanału zamiast danych.

    • bity 6 i 7 są zarezerwowane.

  • opcode – jeden bajt. Kod polecenia lub odpowiedzi. Biblioteka protokołu rezerwuje zakresy kodów operacji według przeznaczenia:

    • 0x00..0x0F – polecenia protokołu (SYNC, GET_CAPS, SET_CAPS, STATS, VERSION).

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

    • 0x20..0x2F – polecenia kanałów (LIST, POLL, LOCK, UNLOCK, SHAPE, SIZE, READ, WRITE, IOCTL, EVENT).

  • len – dwa bajty, little-endian. Liczba bajtów ładunku następujących po nagłówku. Długość zero jest dozwolona – wiele potwierdzeń i małych poleceń nie niesie żadnego ładunku.

  • crc – dwa bajty. CRC-16 obliczone z poprzednich ośmiu bajtów nagłówka. Odbiornik, który otrzyma nagłówek z błędnym CRC, odrzuca cały pakiet, nawet nie patrząc na ładunek.

12.3.2. Ładunek

Zero lub więcej bajtów, traktowanych przez warstwę ramkowania jako nieprzezroczyste. Zawartość ładunku zależy od kodu operacji: dla odpowiedzi CHANNEL_READ są to faktyczne dane kanału; dla odpowiedzi GET_CAPS jest to mała struktura o stałym rozmiarze; dla zapisu na kanale jest to cokolwiek, co wysłał host.

Maksymalny rozmiar ładunku zależy od rozmiaru bufora protokołu kamery (zobacz tabelę dla poszczególnych płytek w protocol.init()). Wiadomości dłuższe niż ten limit są dzielone na fragmenty z ustawioną flagą FRAGMENT na wszystkich oprócz ostatniego.

12.3.3. Końcowy CRC

Cztery bajty, CRC-32 obliczone z ładunku. Wychwytuje uszkodzenia, których CRC nagłówka nie jest w stanie zauważyć, szczególnie w przypadku długich ładunków, gdzie błąd pojedynczego bitu w środku ramki w przeciwnym razie przeszedłby niezauważony.

Rozdzielenie kontroli integralności na dwa CRC jest celowe. CRC nagłówka chroni same pola ramkowania – w szczególności długość ładunku. Bez osobnego CRC nagłówka pojedyncze odwrócenie bitu w bajcie długości spowodowałoby, że odbiornik odczytałby błędną liczbę bajtów ładunku i całkowicie rozsynchronizował się ze strumieniem bajtów; przy jego obecności uszkodzony nagłówek jest od razu odrzucany, a odbiornik ponownie skanuje w poszukiwaniu kolejnego słowa synchronizacji. CRC ładunku chroni następnie treść wiadomości jako odrębną kwestię, dzięki czemu odwrócenie bitu w danych jest zgłaszane jako uszkodzony ładunek, a nie mylone z błędem ramkowania.

Format jest na tyle mały, że można go prześledzić bajt po bajcie, a fakt, że każdy pakiet ma ten sam układ – synchronizacja, potem nagłówek, potem ładunek, potem CRC – oznacza, że ręcznie napisany parser mieści się na jednym ekranie kodu. Dlatego niewielka implementacja hosta w C, Pythonie lub Ruście to projekt na weekend; biblioteka protokołu to utrzymywana wersja Pythona po każdej ze stron.