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/.