12.2. Cztery warstwy

Biblioteka protokołu jest zbudowana jako stos czterech warstw, z których każda rozwiązuje jeden problem i opiera się na warstwie poniżej. Reszta rozdziału przechodzi przez stos od dołu do góry.

Pionowy stos czterech oznaczonych warstw: transport na dole (USB lub UART), ramkowanie nad nim (nagłówek pakietu z CRC), niezawodność powyżej (numery sekwencyjne, ACK / NAK, retransmisje) oraz kanały na górze (nazwane logiczne strumienie).

12.2.1. Transport

Na dole znajduje się potok bajtów między kamerą a hostem. Biblioteka protokołu nie dba o to, który z nich przenosi bajty:

  • USB-CDC przez port USB, do którego kamera jest podłączona. Domyślna opcja o najwyższej przepustowości dla każdej kamery.

  • UART przez parę pinów GPIO kamery połączonych z adapterem szeregowym po stronie hosta. Przydatne w wdrożeniach bezgłowych, gdzie port USB jest zajęty lub nie jest fizycznie dostępny.

Jedynym zadaniem transportu jest „bajty wchodzą, bajty wychodzą, w kolejności”. Wszystko powyżej tej warstwy zakłada, że transport dostarcza bajty w kolejności, w jakiej zostały zapisane, ale dopuszcza, że same bajty mogą zostać uszkodzone lub że łącze może całkowicie zerwać. Stratne serie (kilka brakujących bajtów) i czyste zerwania (całe łącze nieobecne przez chwilę, a potem z powrotem) są obsługiwane wyżej.

12.2.2. Ramkowanie

Następna warstwa narzuca strukturę na strumień bajtów. Każda wiadomość staje się pakietem – 10-bajtowy nagłówek, po którym następuje ładunek, a po nim 4-bajtowy zwiastun. Nagłówek niesie:

  • 2-bajtowe słowo synchronizacji (0xD5AA), które pozwala odbiorcy ponownie odnaleźć początek pakietu po utracie synchronizacji.

  • 1-bajtowy numer sekwencyjny używany przez warstwę niezawodności.

  • 1-bajtowy identyfikator kanału, który mówi, do którego logicznego strumienia należy pakiet.

  • 1-bajtowe pole flag dla bitów ACK / NAK / fragment / event.

  • 1-bajtowy kod operacji, który odróżnia polecenia protokołu, polecenia systemowe i polecenia kanału.

  • 2-bajtową długość ładunku.

  • 2-bajtowy CRC obliczony z poprzednich ośmiu bajtów nagłówka.

Następnie następuje ładunek, a po nim 4-bajtowy CRC obliczony z samego ładunku. Te dwa CRC niezależnie wychwytują uszkodzenia: odwrócony bit w nagłówku unieważnia CRC nagłówka, a odbiorca może odrzucić pakiet bez konieczności odczytywania ładunku.

12.2.3. Niezawodność

Warstwa niezawodności zamienia „pakiety, które mogą dotrzeć” w „pakiety, które dotarły„. Śledzi numery sekwencyjne w nagłówku, prosi drugą stronę o wysyłanie potwierdzeń dla każdego pakietu, który tego wymaga, i retransmituje, gdy potwierdzenie nie dociera w czasie wyznaczonym przez limit czasu. Domyślnie limit czasu retransmisji zaczyna się od 500 ms i podwaja się przy każdej ponownej próbie, z trzema ponownymi próbami przed poddaniem się.

Każde z tych zachowań można skonfigurować w wywołaniu protocol.init(): ACK można wyłączyć dla jednokierunkowych strumieni, walidację CRC można pominąć na całkowicie czystych transportach, a parametry retransmisji można dostroić do wolnych łączy lub łączy o dużym opóźnieniu.

12.2.4. Kanały

Najwyższa warstwa to to, co widzi kod aplikacji. Kanał to nazwany logiczny strumień identyfikowany przez identyfikator kanału od 0 do 31. Do 32 kanałów może współistnieć na jednym transporcie; każdy z nich jest niezależny od pozostałych, adresowany swoim identyfikatorem w nagłówku każdego pakietu. Kamera uruchamia się z czterema wbudowanymi kanałami – stdin, stdout, stream i profile – a kod aplikacji rejestruje kolejne na wierzchu, wywołując protocol.register() z klasą Pythona.

Cztery warstwy nie mieszają zagadnień. Ramkowanie nie wie nic o kanałach; niezawodność nie wie nic o zawartości pakietów; warstwa kanałów nie wie, jak bajty docierają. To rozdzielenie sprawia, że zamiana transportu (na przykład z USB na UART) nie rozchodzi się w górę do kodu kanałów, i to właśnie pozwala przejść przez resztę rozdziału po jednej warstwie naraz.