Силвестър Ледрю (Sylvestre Ledru) публикува резултата от повторното събиране на архива с пакети.

BLE под микроскопом (ATTы GATTы...)

BLE под микроскопа (ATT и GATT)

Част 1, обзор

Измина доста голямо време от когато беше пусната първата спецификация на Bluetooth 4.0. И, въпреки че темата за BLE е много интересна, тя все още отблъсква много разработчици заради сложността си. В предишните си статии разглеждах главно най-долните нива Link Layer и Physical Layer. Това позволяваше да не се засяга сложната и объркваща концепция за протокола на атрибутите (ATT) и общия профил на атрибутите (GATT). Въпреки това, без да разберем тях, не можем да разработваме съвместими устройства. Днес бих искал да споделя с вас тези знания. В статията си ще се опра на учебник за начинаещи от сайта на Nordic. И така, нека да започнем.

Защо всичко е толкова сложно?

Според мен беше ясно още от началото, че управлението на устройства чрез смартфони е тема с много перспективи и дългосрочна. Затова решиха да я структурират веднага и максимално. За да предотвратят производителите на различни устройства да изобретяват свои протоколи, които след това ще бъдат несъвместими. Оттук идва и сложността. Веднага на първия етап в протокола BLE се опитаха да вмъкнат всичко, което е възможно. И няма значение дали ще бъде полезно в бъдеще или не. Освен това, предвидиха възможността за разширяване на списъка с устройства в бъдеще.

Нека да погледнем изображение, където е нарисувана схемата на протокол BLE. Той се състои от няколко слоя. Най-долният, физически слой (PHY) отговаря за радиоканала на устройството. Link Layer (LL) съдържа цялата последователност от байтове в предаваното съобщение. В предишните статии изучавахме точно него. Host Controller Interface (HCI) — това е протокол за обмен между слоевете или чиповете BLE, ако Контролерът и Хостът са реализирани на различни чипове. За формирането на пакетите, разделянето им на кадри, контрола на грешки и събирането на пакетите отговаря Logical Link Control and Adaptation Protocol (L2CAP). За криптиране на пакетите отговаря Security Manager Protocol (SMP). Профилът на общия достъп (GAP) отговаря за първоначалния обмен на данни между устройствата, за да определи „Кой е кой“. Към него също така принадлежат сканирането и реклама. В тази статия ще се спра на двете останали части от протокола — GATT и ATT. GATT е надстройка над ATT, затова те са силно преплетени.

BLE под микроскопом (ATTы GATTы...)

За опростяване на разказа, бих искал да направя аналогия. Чух я някъде и искам да я поддържам. Представете си BLE устройство като библиотека с няколко рафта. Всеки рафт е отделна тематика. Например, имаме рафтове с фантастика, математика, енциклопедии. На всеки рафт са поставени книги с указаната тема. А в някои книги има дори хартиени разделители с бележки. Освен това, имаме малък хартиен каталог на всички книги. Ако си спомняте училищните библиотеки — това е тясна кутия с хартиени картони. При такова сравнение, шкафът е профилът на нашето устройство. Рафтовете са услугите, книгите — характеристиките, а каталогът — таблицата на атрибутите. Разделителите в книгите — това са дескрипторите, за които ще говоря по-подробно по-късно.

Всеки, който е разработвал устройства, знае, че в много проекти има сходни парчета код. Факт е, че много устройства имат подобна функционалност. Например, ако устройствата работят с акумулатори, проблемът с зареждането и контрола на тяхното ниво ще бъде един и същ. Същото важи и за сензорите. Собствено, обектно-ориентираният подход в програмирането „дава възможност за създаване на обекти, които свързват свойства и поведение в самостоятелна единица, която след това може да се използва многократно“. На мое мнение, в BLE беше направен опит за подобен подход. Групата Bluetooth Special Interest Group (SIG) разработи профили. Устройства от различни производители, които притежават еднакви профили, трябва без затруднения да работят помежду си. Профилите от своя страна се състоят от услуги, а услугите от характеристики, допълвани с дескриптори. Общо взето, това може да изглежда така:

BLE под микроскопом (ATTы GATTы...)

Например, нека разгледаме схемата на профила на монитор на сърдечния ритъм (фитнес гривна). Той се състои от две услуги и няколко характеристики. От нея веднага става ясна йерархията на профила. Характеристиката на контрольната точка нулира общия брой на изразходваните калории.

1. Услуга за сърдечен ритъм включва три характеристики (0x180D):
    а) Задължителна характеристика на сърдечната честота (0х2A37)
    б) Опционална характеристика на положението на датчика на тялото (0x2A38)
    в) Условна характеристика на контрольната точка на сърдечния ритъм (0x2A39)
2. Услуга за управление на батерията (0x180F):
    a) Задължителна характеристика на нивото на заряд на батерията (0x2A19)

UUID

За да можем да се отнасяме недвусмислено към елементите на профила (услугите, характеристиките и дескрипторите), е необходимо да ги номерираме. За тази цел се въвежда понятието Universally Unique ID (UUID) или Универсален уникален идентификатор. В скобите на всяка редица е указано UUID. И тук има една особеност. За UUID решават да използват код с дължина 16 и 128 бита. Защо, питате? В протокола BLE всичко е подчинено на пестенето на енергия. Затова размерът от 16 бита е напълно разумен. В малко вероятно бъдеще ще бъдат създадени повече от 65 хиляди уникални услуги и характеристики. В момента всичко, което можем, вече е изчислено (помните откъде идва това — „той и вас е преброил“ :-)) Номерираните елементи профили, сервизи, характеристики и дескриптори можете да видите по линковете.

Обаче, мисля, че всички помнят историята с 4 байта IP адреса в интернет. Първоначално си мислеха, че ще е достатъчно, а сега все не можем да преминем към 6-байтов адрес. За да не повтаряме тази грешка и да дадем пространство на шаловливите ръце на самоделковци, SIG реши веднага да въведе и 128-битови UUID. Това лично ми напомня на нелицензирания диапазон 433MHz, който беше предоставен на всевъзможните Кулиби от радиоканала. В нашия случай, на откуп беше даден 128-битния идентификатор на услугите и характеристиките. Това означава, че можем да използваме практически всяка 128-битна стойност за нашите услуги и устройства. Вероятността да измислим идентичен UUID стреми към нула.

Всъщност, кратките 16-битови UUID имат разширение до 128-битова стойност. В спецификацията това разширение се нарича Bluetooth Base UUID и има стойност 00000000-0000-1000-8000-00805F9B34FB. Например, ако 16-битовият UUID на атрибута има стойност 0x1234, то еквивалентният 128-битов UUID ще има стойност 00001234-0000-1000-8000-00805F9B34FB. И дори се предоставя съответната формула:

                                128_bit_value = 16_bit_value * 2^96 + Bluetooth_Base_UUID

Откъде идва това магическо число, не ми е известно. Ако някой от читателите знае — нека напише в коментарите (Потребителят с псевдоним Sinopteek вече го направи. Вижте коментарите). Що се отнася до измислянето на 128-битови UUID, принципно можете да се възползвате от специален генератор, който ще го направи вместо вас.

ATTи GATTи…

Сега започва всичко най-интерesното. Напомням, че ATT се основава на клиент-сървърната архитектура. В момента разглеждаме устройството на сървъра. То съдържа информация като стойности на сензори, състояние на осветителното тяло, данни за местоположението и т.н. Сега, когато всички "участници на нашия парад" са номерирани, трябва по някакъв начин да ги разположим в паметта на устройството. За това ги поставяме в таблица, наречена таблица на атрибутите. Запомнете това добре. Това е сърцето на BLE. Именно него ще разглеждаме нататък. Сега всяка редица ще наричаме атрибут. Тази таблица се намира дълбоко в стека и обикновено нямаме директен достъп до нея. Инициализираме я и се свързваме с нея, но какво се случва вътре, остава скрито от нас.

Нека разгледаме изображението от спецификацията, но преди това искам веднага да обърна внимание на често срещаната бъркотия в термините, а именно в дескрипторите. Ролята на дескриптора е да допълни описанието на характеристиката. Когато трябва да разширим функционалността й, тогава използваме дескриптори. Те също са атрибути, и заедно със сервисите и характеристиките, се намират в таблицата на атрибутите. Подробно ще ги разгледаме във втората част на статията. Обаче понякога дескрипторите се наричат номер на реда в таблицата на атрибутите. Трябва да имаме това предвид. Ние, за да не се бъркаме, ще използваме термина "указател на атрибута" за тези цели.
BLE под микроскопом (ATTы GATTы...)

И така, атрибутът е дискретна стойност, която има следните свойства, свързани с него:
1. Указател на атрибута (Attribute Handle) — това е индекс на таблицата, съответстващ на атрибута.
2. Тип на атрибута (Attribute Type) — това е UUID, който описва типа му.
3. Стойност на атрибута (Attribute Value) — това са данните, индексируеми с указателя на атрибута.
4. Разрешения на атрибутите (Attribute Permissions) — това е част от атрибута, разрешения, които не могат да бъдат прочетени или записани с протокола на атрибутите.

Как да разберем всичко това? Указателят на атрибута — това е, да кажем, неговият номер в нашата таблица.
Той позволява на клиента да се отнася към атрибут в заявки за четене или записване. Можем да номерираме нашите редове (атрибути) от 0x0001 до 0xFFFF. В нашата асоциация с библиотеката, това е номерът на картата в хартиения каталог. Подобно на каталога в библиотека, картите са разположени в ред на нарастващия номер. Номерът на всеки следващ ред трябва да бъде по-голям от предишния. Както в библиотеката, понякога се губят някои карти, така и у нас в номерирането на редовете могат да има пропуски. Това е допустимо. Основното е, че те да са по нарастваща редица.

Типът на атрибута определя какво представлява този атрибут. По аналогия с езика C,
където има булеви, числови променливи и низове, така и тук. По типа атрибут разбираме
с какво имаме работа и как да работим с този атрибут по-нататък. По-долу ще разгледаме някои специфични типове атрибути. Например „сервизна декларация“ (0x2800), „декларация на характеристиките“ (0x2803), „декларация на дескриптора“ (0x2902).

Стойността на атрибута е всъщност неговата стойност, прошете за тавтологията. Ако типът на атрибута е низ, то стойността на атрибута може да бъде например слоган „Hello World !!!“. Ако типът на атрибута е „сервизна декларация“, то стойността му е самият сервиз. А понякога това е информация за това къде да намерим други атрибути и техните свойства.

Разрешенията на атрибутите позволяват на сървъра да разбере дали достъпът до четене или запис е разрешен.
Обърнете внимание, че тези разрешения се прилагат само към стойността на атрибута, а не към указателя, типа и самото поле на разрешенията. Т.е. ако записването на атрибута е разрешено, можем да променим например реда „Hello World !!!“ на реда „Good morning“. Но не можем да забраним записването на нов ред или да променим типа на атрибута и да определим реда като „сервизна декларация“. При достъпа на клиента до сървъра, клиентът поиска неговите атрибути. Това позволява на клиента да разбере какво може да предостави сървърът. Въпреки това, не е задължително да чете и записва стойности.

Как изглежда това

Концепцията GATT е да групира атрибутите в таблицата с атрибути заедно в много специфичен и логичен ред. Нека да разгледаме по-отблизо профила на сърдечната честота, представен по-долу. Най-левият стълб на тази таблица не е задължителен. Той просто описва какво представлява този ред (атрибут). Всички останали стълбове са ни познати.

BLE под микроскопом (ATTы GATTы...)

В горната част на всяка група винаги имаме атрибут за обявление на услугата. Неговият тип винаги е равен на 0x2800, а указателят зависи от това колко атрибута вече присъстват в таблицата. Неговите разрешения винаги са само за четене, без никаква проверка на удостоверяване или авторизация. За тези понятия ще говорим малко по-късно. Стойността — това е друг UUID, който определя каква услуга е. В таблицата стойността е равна на 0x180D, което се определя от Bluetooth SIG като услуга за сърдечна честота.

След обявлението на услугата следва обявление за характеристиката. Формата му е аналогична на обявлението за услугата. Неговият UUID винаги има стойност 0x2803, а разрешенията също винаги са само за четене без никаква проверка на удостоверяване или авторизация. Нека да разгледаме полето Attribute Value, което включва някои данни. То винаги съдържа указател, UUID и набор от свойства. Тези три елемента описват последващото обявление на стойността на характеристиката. Указателят по естествен начин обозначава местоположението на обявлението на стойността на характеристиката в таблицата с атрибути. UUID описва какъв тип информация или стойност можем да очакваме. Например, стойността на температурата, състоянието на ключа за светлина или каквато и да е друга произволна стойност. И накрая, свойствата, които описват как можем да взаимодействаме с характеристичната стойност.

Тук ни чака още едно подводно камъче. То е свързано с разрешенията на атрибутите и свойствата на характеристиките. Нека да разгледаме изображението на свойствата на битовото поле от спецификацията.

BLE под микроскопом (ATTы GATTы...)

Както виждате, тук също присъстват полета, даващи възможности за четене и запис. Можете да се запитате защо имаме разрешения за четене/запис за атрибута и свойството.
Четения/записи за стойността на характеристиката? Нали те не трябва да са винаги еднакви? Работата е там, че свойствата за стойността на характеристиката всъщност са само препоръки за клиента, използвани в GATT и приложни слоеве. Това са просто насоки за това какво може да очаква клиентът от атрибута на обявената характеристика. Нека се запознаем с това по-задълбочено. Какви видове разрешения съществуват за атрибута?

1. Разрешения за достъп:
     — четене
     — запис
     — четене и запис
2. Разрешение за удостоверяване:
     — удостоверяване е необходимо
     — удостоверяване не е необходимо
3. Разрешение за авторизация:
     — авторизация е необходима
     — авторизация не е необходима

Основната разлика между разрешенията на атрибутите и свойствата на характеристиките е, че първите се отнасят до сървъри, а вторите до клиенти. Сървърът може да има разрешение за четене на стойността на характеристиката, но в същото време изискването за удостоверяване или авторизация може да е налице. Следователно, при запитване на свойствата на характеристиката от клиента, ще получим, че четенето е разрешено. Но при опит за четене ще получим грешка. Следователно, можем смело да говорим за приоритета на разрешенията над свойствата. Информацията за разрешенията на атрибута не може да бъде получена от страната на клиента.

Дескриптор

Нека се върнем към нашата таблица. След обявяването на стойността на характеристиката, възможни са следните обявления на атрибути:
1. Нова обява на характеристика (в услугата може да има много характеристики)
2. Нова декларация за услуга (в таблицата може да има много от тях)
3. Обява на дескриптора

При характеристиката за измерване на сърдечната честота, в нашата таблица, обявяването на стойността на характеристиката е съпроводено с обявяване на дескриптора. Дескрипторът е атрибут с допълнителна информация за характеристиката. Съществуват няколко вида дескриптори. За тях ще говорим подробно във втората част на тази статия. Сега ще се спрем само на дескриптора за конфигурация на характеристиките на клиента (Client Characteristic Configuration Descriptor - CCCD). Той има UUID, равно на 0x2902. С помощта на този дескриптор клиентът има възможност да активира индикация или нотификация на сървъра. Разликата между тях е малка, но все пак съществува. Нотификацията не изисква потвърждение за получаване от страна на клиента. Индрикацията обаче изисква такова, въпреки че тя протича на ниво GATT, без да стига до нивото на приложението. Защо е така, ще попитате? Уви, това не ми е известно. Ще кажа само, че специалистите от Nordic препоръчват да се използва нотификация. Особено, че проверката за целостта на пакета (с помощта на CRC) се извършва и в двата случая.

Заключение

В края на статията бих искал да кажа следното. Последната таблица е малко объркваща. Обаче се спрях на нея, защото се посочва в статии, на която разчитам. Във втората част на статията си имам намерение да задълбая в спецификацията BlueTooth 4.0. Там ни очакват по-точни схеми и рисунки. В третата част, бих искал да разгледам лог, получен с помощта на програмата Wireshark от един от устройствата и да видя "на живо" цялата теория, която изучаваме.

Служител на Група Компании «Цезар Сателлит»
Печерских Владимир

Източник: habr.com

Купете надежден хостинг за сайтове със защита от DDoS, VPS и VDS сървъри 🔥 Купете надежден хостинг за сайтове със защита от DDoS, VPS и VDS сървъри | ProHoster