BLE pod mikroskopem (ATTы GATTы…)

BLE pod mikroskopem (ATTы GATTы...)

BLE pod mikroskopem (ATTы GATTы…)

Część 1, przegląd

Od udostępnienia pierwszej specyfikacji Bluetooth 4.0 minęło już sporo czasu. I chociaż temat BLE jest bardzo interesujący, nadal odstrasza wielu programistów ze względu na jego złożoność. W moich poprzednich artykułach zajmowałem się głównie najniższym poziomem, warstwą łącza i warstwą fizyczną. Pozwoliło nam to uniknąć konieczności uciekania się do tak złożonych i mylących koncepcji, jak protokół atrybutów (ATT) i ogólny profil atrybutów (GATT). Jednak nie ma dokąd pójść, bez ich zrozumienia nie da się opracować kompatybilnych urządzeń. Dziś tą wiedzą chcę się z Wami podzielić. W moim artykule będę się opierać podręcznik dla początkujących ze strony Nordic. Więc zacznijmy.

Dlaczego wszystko jest takie trudne?

Moim zdaniem od razu stało się jasne, że zarządzanie urządzeniami za pomocą smartfonów to temat bardzo obiecujący i długotrwały. Dlatego postanowili ustrukturyzować go natychmiast i maksymalnie. Aby producenci różnych gadżetów nie wymyślili własnych protokołów, które wówczas będą niekompatybilne. Stąd trudność. Już na pierwszym etapie próbowano wcisnąć do protokołu BLE wszystko, co możliwe. I nie ma znaczenia, czy będzie to przydatne później, czy nie. Ponadto przewidzieli możliwość rozszerzenia listy urządzeń na przyszłość.

Przyjrzyjmy się obrazowi, na którym narysowany jest schemat protokołu BLE. Składa się z kilku warstw. Najniższa warstwa fizyczna (PHY) odpowiada za kanał radiowy urządzenia. Link Layer (LL) zawiera całą sekwencję bajtów w przesyłanej wiadomości. W poprzednich artykułach dokładnie to badaliśmy. Interfejs kontrolera hosta (HCI) to protokół wymiany między warstwami BLE lub chipami, jeśli kontroler i host są zaimplementowane na różnych chipach. Protokół kontroli łącza logicznego i adaptacji (L2CAP) jest odpowiedzialny za tworzenie pakietów, ramkowanie, kontrolę błędów i składanie pakietów. Za szyfrowanie pakietów odpowiada protokół Security Manager Protocol (SMP). General Access Profile (GAP) odpowiada za wstępną wymianę danych pomiędzy urządzeniami w celu ustalenia „Kto jest kim”. Obejmuje to również skanowanie i reklamę. W tym artykule skupię się na dwóch pozostałych częściach protokołu – GATT i ATT. GATT jest nadbudową ATT, więc są ze sobą ściśle powiązane.

BLE pod mikroskopem (ATTы GATTы...)

Aby uprościć historię, posłużę się analogią. Gdzieś to słyszałem i chciałbym to poprzeć. Pomyśl o urządzeniu BLE jak o regale z kilkoma półkami. Każda półka to osobny motyw. Mamy na przykład półki z science fiction, matematyką i encyklopediami. Na każdej półce znajdują się książki o określonej tematyce. Niektóre książki mają nawet papierowe zakładki z notatkami. Ponadto posiadamy mały katalog papierowy wszystkich książek. Jeśli pamiętasz, biblioteki szkolne to wąskie pudełko z papierowymi kartami. W tej analogii szafka jest profilem naszego urządzenia. Półki to usługi, książki to cechy, a katalog to tabela atrybutów. Zakładki w książkach są deskryptorami, o których również opowiem później bardziej szczegółowo.

Każdy, kto opracował urządzenia, wie, że wiele projektów ma podobne fragmenty kodu. Faktem jest, że wiele urządzeń ma podobną funkcjonalność. Przykładowo, jeśli urządzenia zasilane są z akumulatorów, to problem ładowania i monitorowania ich poziomu będzie taki sam. To samo tyczy się czujników. Właściwie obiektowe podejście do programowania „zapewnia możliwość tworzenia obiektów, które łączą właściwości i zachowania w samodzielną całość, którą można następnie ponownie wykorzystać”. Moim zdaniem BLE próbowało zastosować podobne podejście. Profile zostały opracowane przez Bluetooth Special Interest Group (SIG). Urządzenia różnych producentów posiadające te same profile powinny ze sobą bez problemu współpracować. Profile z kolei składają się z usług i usług o cechach, uzupełnionych deskryptorami. Ogólnie mogłoby to wyglądać tak:

BLE pod mikroskopem (ATTы GATTы...)

Rozważmy na przykład diagram profilu czujnika tętna (bransoletki fitness). Składa się z dwóch usług i kilku cech. Z tego powodu hierarchia profili natychmiast staje się jasna. Charakterystyka punktu kontrolnego resetuje licznik całkowitego wydatku kalorii do zera.

1. Usługa pomiaru tętna obejmuje trzy cechy (0x180D):
    a) Obowiązkowa charakterystyka tętna (0x2A37)
    b) Opcjonalna charakterystyka położenia czujnika ciała (0x2A38)
    c) Charakterystyka warunkowa punktu kontroli tętna (0x2A39)
2. Serwis konserwacji baterii (0x180F):
    a) Obowiązkowa charakterystyka poziomu naładowania akumulatora (0x2A19)

UUID

Abyśmy mieli jednoznaczny dostęp do elementów profilu (usług, cech i deskryptorów), musimy je wszystkie w jakiś sposób ponumerować. W tym celu wprowadza się pojęcie takie jak Uniwersalny Unikalny Identyfikator (UUID) lub Uniwersalnie Unikalny Identyfikator. Identyfikator UUID jest podany w nawiasach każdego wiersza. I jest tu jedna osobliwość. W przypadku UUID zdecydowaliśmy się użyć kodu o długości 16 i 128 bitów. Dlaczego pytasz? W protokole BLE wszystko skupia się na oszczędzaniu energii. Dlatego wymiar 16 bitów jest całkiem rozsądny. Jest mało prawdopodobne, aby w najbliższej przyszłości powstało ich więcej niż 65 tys. unikalne usługi i cechy. W tej chwili wszystko, co można było już policzyć (pamiętajcie, skąd to się wzięło - „on też cię policzył” :-)) Elementy ponumerowane profile, usług, charakterystyka и deskryptory możesz zajrzeć do linków.

Myślę jednak, że wszyscy pamiętają historię z 4 bajtami adresów IP w Internecie. Na początku myśleliśmy, że to wystarczy, ale teraz nadal nie możemy przejść na adres 6-bajtowy. Aby nie powtórzyć tego błędu i dać upust zabawnym rękom majsterkowiczów, SIG od razu zdecydował się na wprowadzenie 128-bitowych identyfikatorów UUID. Mnie to osobiście przypomina nielicencjonowane pasmo 433 MHz, które z kanału radiowego nadawane było wszelkiego rodzaju Kulibinom. W naszym przypadku wyhodowano 128-bitowy identyfikator usług i cech. Oznacza to, że w naszych usługach i urządzeniach możemy używać niemal dowolnej wartości 128-bitowej. Mimo to prawdopodobieństwo znalezienia tego samego UUID dąży do zera.

W rzeczywistości krótkie 16-bitowe identyfikatory UUID mają rozszerzenie do wartości 128-bitowej. W specyfikacji rozszerzenie to nosi nazwę Bluetooth Base UUID i ma wartość 00000000-0000-1000-8000-00805F9B34FB. Jeśli na przykład 16-bitowy atrybut UUID ma wartość 0x1234, wówczas równoważny 128-bitowy identyfikator UUID będzie miał wartość 00001234-0000-1000-8000-00805F9B34FB. Podano nawet odpowiednią formułę:

                                128_bit_value = 16_bit_value * 2^96 + Bluetooth_Base_UUID

Nie wiem skąd wzięła się ta magiczna liczba. Jeśli ktoś z czytelników wie, niech napisze w komentarzach (użytkownik o pseudonimie Sinopteek już to zrobił. Zobacz komentarze). Jeśli chodzi o wymyślanie 128-bitowych identyfikatorów UUID, w zasadzie możesz użyć specjalnego generatorkto zrobi to za Ciebie.

ATTY GATTy...

Właściwie wtedy zaczyna się zabawa. Przypomnę, że ATT opiera się na relacji klient-serwer. Teraz patrzymy na urządzenie serwerowe. Zawiera informacje, takie jak wartości czujników, stan włącznika światła, dane o lokalizacji itp. Teraz, gdy wszyscy „uczestnicy naszej parady” są już ponumerowani, musimy ich jakoś umieścić w pamięci urządzenia. Aby to zrobić, umieszczamy je w tabeli zwanej tabelą atrybutów. Zapamiętaj to dobrze. To jest samo serce BLE. To właśnie rozważymy dalej. Teraz każdą linię nazwiemy atrybutem. Tabela ta znajduje się głęboko w stosie i z reguły nie mamy do niej bezpośredniego dostępu. Inicjujemy go i uzyskujemy do niego dostęp, ale to, co dzieje się w środku, jest przed nami ukryte za siedmioma pieczęciami.

Spójrzmy na obrazek ze specyfikacji, ale wcześniej od razu chciałbym zwrócić uwagę na częste zamieszanie terminologiczne, a mianowicie deskryptory. Rolą deskryptora jest uzupełnienie opisu cechy. Gdy zachodzi potrzeba rozszerzenia jego możliwości, stosuje się deskryptory. Są to także atrybuty i podobnie jak usługi i cechy, znajdują się w tabeli atrybutów. Przeanalizujemy je szczegółowo w drugiej części artykułu. Czasami jednak deskryptory odnoszą się do numeru wiersza w tabeli atrybutów. Należy o tym pamiętać. Aby uniknąć nieporozumień, w tym celu będziemy używać terminu „wskaźnik atrybutu”.
BLE pod mikroskopem (ATTы GATTы...)

Zatem atrybut jest wartością dyskretną, z którą powiązane są następujące właściwości:
1. Uchwyt atrybutu to indeks tabeli odpowiadający atrybutowi
2. Typ atrybutu to identyfikator UUID opisujący jego typ
3. Wartość atrybutu to dane indeksowane przez wskaźnik atrybutu
4. Uprawnienia atrybutów to część atrybutu, uprawnienia, których nie można odczytać ani zapisać przy użyciu protokołu atrybutu

Jak to wszystko zrozumieć? Wskaźnik atrybutu to, mówiąc relatywnie, jego numer w naszej tabeli.
Umożliwia klientowi odwoływanie się do atrybutu w żądaniach odczytu lub zapisu. Możemy numerować nasze linie (atrybuty) od 0x0001 do 0xFFFF. W naszym powiązaniu z regałem jest to numer karty w katalogu papierowym. Podobnie jak w katalogu bibliotecznym karty ułożone są w kolejności rosnącej liczby. Numer każdego kolejnego wiersza musi być większy od poprzedniego. Podobnie jak w bibliotece, czasami zdarza się, że niektóre karty się gubią, tak i u nas mogą pojawić się luki w numeracji wierszy. To jest dozwolone. Najważniejsze, że postępują stopniowo.

Typ atrybutu określa, co reprezentuje atrybut. Przez analogię do języka C,
gdzie znajdują się zmienne logiczne, numeryczne i ciągi znaków, więc jest tutaj. Według typu atrybutu rozpoznajemy
z czym mamy do czynienia i jak możemy dalej pracować z tą cechą. Poniżej przyjrzymy się niektórym konkretnym typom atrybutów. Na przykład „deklaracja usługi” (0x2800), „deklaracja charakterystyki” (0x2803), „deklaracja deskryptora” (0x2902).

Wartością atrybutu jest jego rzeczywiste znaczenie, wybaczcie tautologię. Jeżeli typem atrybutu jest string to wartością atrybutu może być np. hasło „Hello World!!!”. Jeżeli typem atrybutu jest „deklaracja usługi”, wówczas jego wartością jest sama usługa. Czasami jest to informacja o tym, gdzie znaleźć inne atrybuty i ich właściwości.

Uprawnienia do atrybutów pozwalają serwerowi sprawdzić, czy dozwolony jest dostęp do odczytu lub zapisu.
Należy pamiętać, że te uprawnienia dotyczą tylko wartości atrybutu, a nie samego wskaźnika, typu czy pola uprawnień. Te. jeśli dozwolone jest zapisywanie atrybutów, możemy zmienić np. linię „Hello World !!!” do wiersza „Dzień dobry”. Nie możemy jednak zabronić pisania nowej linii, zmiany typu atrybutu i oznaczenia linii jako „deklaracji usługi”. Kiedy klient kontaktuje się z serwerem, żąda jego atrybutów. Dzięki temu klient wie, co serwer może zapewnić. Chociaż nie jest konieczne odczytywanie i zapisywanie wartości.

Jak to wygląda

Koncepcja GATT polega na grupowaniu atrybutów w tabeli atrybutów w bardzo specyficznym i logicznym porządku. Przyjrzyjmy się bliżej poniższemu profilowi ​​tętna. Lewa kolumna tej tabeli jest opcjonalna. Opisuje nam po prostu, czym jest ta linia (atrybut). Wszystkie pozostałe kolumny są nam już znane.

BLE pod mikroskopem (ATTы GATTы...)

Na górze każdej grupy zawsze znajduje się atrybut deklaracji usługi. Jego typ to zawsze 0x2800, a wskaźnik zależy od tego, ile atrybutów jest już obecnych w tabeli. Jego uprawnienia są zawsze tylko do odczytu, bez żadnego uwierzytelniania ani autoryzacji. O tych koncepcjach porozmawiamy nieco później. Wartość to kolejny identyfikator UUID identyfikujący usługę. W tabeli wartością jest 0x180D, która jest zdefiniowana przez Bluetooth SIG jako usługa pomiaru tętna.

Po ogłoszeniu usługi następuje ogłoszenie charakterystyki. Formą przypomina deklarację usługową. Jego UUID to zawsze 0x2803, a jego uprawnienia są zawsze tylko do odczytu, bez żadnego uwierzytelniania ani autoryzacji. Przyjrzyjmy się polu Wartość atrybutu, które zawiera pewne dane. Zawsze zawiera wskaźnik, identyfikator UUID i zestaw właściwości. Te trzy elementy opisują późniejszą deklarację wartości charakterystycznej. Wskaźnik w naturalny sposób wskazuje lokalizację deklaracji wartości charakterystycznej w tabeli atrybutów. UUID opisuje, jakiego rodzaju informacji lub wartości możemy się spodziewać. Na przykład wartość temperatury, stan włącznika światła lub inna dowolna wartość. I wreszcie właściwości, które opisują, w jaki sposób można oddziaływać na wartość charakterystyczną.

Czeka nas tu kolejna pułapka. Jest to związane z uprawnieniami atrybutów i właściwościami charakterystycznymi. Przyjrzyjmy się obrazowi właściwości pola bitowego ze specyfikacji.

BLE pod mikroskopem (ATTы GATTы...)

Jak widać, znajdują się tu również pola umożliwiające odczyt i zapis. Być może zastanawiasz się, dlaczego mamy uprawnienia do odczytu/zapisu atrybutów i właściwości
odczyt/zapis wartości charakterystycznej? Czy nie powinny być zawsze takie same? Faktem jest, że właściwości wartości charakterystycznej są w rzeczywistości jedynie zaleceniami dla klienta stosowanymi w warstwach GATT i aplikacji. Są to po prostu podpowiedzi, czego klient może się spodziewać po charakterystycznym atrybucie deklaracji. Przyjrzyjmy się temu bardziej szczegółowo. Jakie typy uprawnień ma atrybut?

1. Uprawnienia dostępu:
     - czytanie
     - nagrywać
     - Czytaj i pisz
2. Zezwolenie na uwierzytelnienie:
     - Wymagane uwierzytelnienie
     - nie wymaga uwierzytelnienia
3. Zezwolenie autoryzacyjne:
     - Wymagana Autoryzacja
     - nie wymaga autoryzacji

Główna różnica między rozpoznawaniem atrybutów a właściwościami charakterystycznymi polega na tym, że pierwsza dotyczy serwerów, a druga klientów. Serwer może uzyskać zgodę na odczyt wartości charakterystycznej, ale może wymagać uwierzytelnienia lub autoryzacji. Dlatego też, gdy klient zażąda właściwości cechy, otrzymamy informację, że odczyt jest dozwolony. Ale gdy próbujemy przeczytać, pojawia się błąd. Dlatego śmiało możemy mówić o priorytecie uprawnień nad właściwościami. Po stronie klienta nie możemy uzyskać wiedzy o tym, jakie uprawnienia ma atrybut.

deskryptor

Wróćmy do naszego stołu. Po zadeklarowaniu wartości cechy możliwe są następujące deklaracje atrybutów:
1. Nowa deklaracja cech (usługa może mieć wiele cech)
2. Deklaracja nowej usługi (w tabeli może być ich dużo)
3. Deklarowanie uchwytu

W przypadku charakterystyki pomiaru tętna, w naszej tabeli deklaracji wartości charakterystycznej towarzyszy deklaracja deskryptora. Deskryptor to atrybut zawierający dodatkowe informacje na temat cechy. Istnieje kilka typów deskryptorów. Porozmawiamy o nich szczegółowo w drugiej części tego artykułu. Na razie zajmiemy się tylko deskryptorem konfiguracji charakterystycznej klienta (CCCD). Ma identyfikator UUID równy 0x2902. Korzystając z tego deskryptora, klient ma możliwość włączenia sygnalizacji lub powiadomienia na serwerze. Różnica między nimi jest niewielka, ale jednak istnieje. Zgłoszenie nie wymaga potwierdzenia odbioru od Klienta. Wskazanie tego wymaga, chociaż występuje na poziomie GATT, nie osiągając poziomu aplikacji. Dlaczego tak, pytasz? Niestety, nie wiem tego. Powiem tylko, że nordyccy eksperci zalecają korzystanie z powiadomień. Ponadto w obu przypadkach następuje sprawdzenie integralności pakietu (za pomocą CRC).

wniosek

Na koniec artykułu chciałbym to powiedzieć. Ostatnia tabela jest nieco myląca. Wybrałam go jednak dlatego, że jest dany Artykuł, na którym się opieram. W drugiej części mojego artykułu zamierzam zagłębić się w specyfikację BlueTooth 4.0. Tam czeka na nas więcej poprawnych diagramów i rysunków. W trzeciej części chciałbym przeanalizować log uzyskany za pomocą programu Wireshark z jednego z gadżetów i zobaczyć „na żywo” całą teorię, którą studiujemy.

Pracownik Grupy Spółek „Satelita Cezar”
Włodzimierz Peczerski

Źródło: www.habr.com

Dodaj komentarz