12.1. Po co biblioteka protokołu

Para przewodów i szybkość transmisji (baud) wystarczą, aby przenosić bajty z kamery do komputera hosta. Zarówno USB-CDC, jak i UART dają programowi kamery strumień, w którym write wkłada bajty z jednej strony, a read wyjmuje je z drugiej. Co zatem dodaje do tego biblioteka protokołu?

Trzy rzeczy, które musiałbyś napisać samodzielnie, za każdym razem, gdybyś próbował zbudować poważny kanał komunikacji kamera-host bezpośrednio na surowych bajtach:

Ramkowanie. Strumień bajtów nie ma żadnej wewnętrznej struktury. Kamera zapisuje temp=42, a host odczytuje temp= plus przerwanie nadchodzące później, następnie 42 plus kolejna wiadomość zaczynająca się od humid=... już z nią połączona. Bajty nie mają granic. Każde nietrywialne łącze hosta kończy się wymyśleniem jakiegoś znacznika – \n pomiędzy wiadomościami, nagłówków z prefiksem długości, sekwencji ucieczki dla danych binarnych – aby odbiornik wiedział, gdzie kończy się jedna wiadomość, a zaczyna kolejna. Biblioteka protokołu daje jednolity format pakietu ze słowem synchronizacji i polem długości, dzięki czemu odbiornik nigdy nie musi zgadywać.

Niezawodność. USB-CDC nie gubi bajtów po cichu podczas normalnej pracy, ale UART tak (gdy host nie obsługuje portu wystarczająco szybko), a odłączony i ponownie podłączony przewód szeregowy może pozostawić jedną ze stron z niekompletnym pakietem. Właściwym rozwiązaniem jest wykrycie uszkodzenia, poproszenie drugiej strony o retransmisję i przekazywanie kodowi aplikacji wyłącznie wiadomości, które dotarły w całości. Biblioteka protokołu robi to dla każdego pakietu za pomocą CRC oraz potwierdzeń na poziomie pakietu – domyślnie włączonych; aplikacja nie widzi ponownych prób.

Multipleksowanie. Pomiędzy kamerą a hostem jest dokładnie jeden port USB-CDC. Jeśli kamera przesyła strumieniowo obraz oraz host wysyła do niej konfigurację oraz OpenMV IDE odczytuje stdout w poszukiwaniu danych z print, wszystkie trzy wymiany muszą współdzielić ten jeden strumień bajtów. Biblioteka protokołu nadaje każdemu niezależnemu strumieniowi numer kanału, pozwala kamerze zarejestrować klasę Pythona dla każdego z nich i sprawia, że odczyty hosta na każdym kanale nie kolidują z innymi. Z punktu widzenia kodu aplikacji każdy kanał wygląda jak własne, prywatne łącze.

12.1.1. Po co pisać to samodzielnie

Możesz. To kilka tygodni pracy, aby poprawnie zaimplementować wszystkie trzy elementy na łączu szeregowym, i kolejne kilka tygodni, aby ramkowanie czysto obsługiwało odzyskiwanie po podłączeniu na gorąco, retransmisje działały bez marnowania energii na cykle obiegu, a multiplekser przetrwał częściowe odczyty bez mieszania bajtów jednego kanału z innym.

Biblioteka protokołu wykonała już tę pracę, została zweryfikowana na każdej obsługiwanej kamerze i ma odpowiadające jej biblioteki po stronie hosta, które posługują się tym samym formatem przewodowym. Korzystanie z niej oznacza, że kod po stronie kamery to jedna mała klasa na kanał, a kod po stronie hosta to obiekt Camera z metodami channel_read i channel_write. Zaoszczędzona przestrzeń umysłowa trafia na to, co aplikacja faktycznie robi.

Ten rozdział uczy protokołu od podstaw: format przewodowy, reguły ramkowania, mechanizmy niezawodności, model kanałów i wreszcie klasy Pythona po obu stronach. Pod koniec czytelnik potrafi zbudować GUI hosta komunikujące się z kamerą, skrypt strumieniujący dane z sensora z kamery do laptopa oraz interaktywne narzędzie kalibracyjne tego rodzaju, jakie znajduje się w openmv-projects/tools/.