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

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, якщо Controller і Host реалізовані різних чіпах. За формування пакетів, поділ на кадри, контролем помилок та збирання пакетів відповідає Logical Link Control and Adaptation Protocol (L2CAP). За шифрування пакетів відповідає Security Manager Protocol (SMP). Профіль загального доступу (GAP) відповідає за початковий обмін даними між пристроями для визначення Who is who. До нього також відносяться scanning і advertising. У цій статті я зупинюся на двох частинах протоколу, що залишилися, — GATT і ATT. GATT є надбудовою над ATT, тому вони сильно переплетені.

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

Для спрощення оповіді, я хотів би звернутися до аналогії. Я її десь чув і хотів би підтримати. Уявіть собі BLE пристрій як книжкову шафу з кількома полицями. Кожна полиця – це окрема тематика. Наприклад, ми маємо полиці з фантастикою, математикою, енциклопедіями. На кожній полиці стоять книги із зазначеною темою. А в деяких книгах є навіть паперові закладки із записами. Крім того, ми маємо невеликий паперовий каталог всіх книг. Якщо пам'ятаєте шкільні бібліотеки – це вузька скринька з паперовими картками. При такій аналогії шафа – це профіль нашого пристрою. Полиці – це сервіси, книги – характеристики, а каталог – це таблиця атрибутів. Закладки в книгах — це дескриптори, про які я розповім пізніше, більш докладно.

Усі, хто розробляв устрою, знає, що у багатьох проектах є схожі шматки коду. Справа в тому, що багато пристроїв мають схожий функціонал. Наприклад, якщо пристрої працюють від акумуляторів, то проблема зарядки та контролю їхнього рівня буде однаковою. Те саме стосується і датчиків. Власне, об'єктно-орієнтований підхід у програмуванні «надає можливість створювати об'єкти, які поєднують властивості та поведінки в самостійний союз, який потім можна багаторазово використовувати». На мій погляд, в BLE була спроба схожого підходу. Групою Bluetooth Special Interest Group (SIG) було розроблено профілі. Пристрої від різних виробників, що мають однакові профілі, повинні легко працювати один з одним. Профілі у свою чергу складаються з сервісів, а послуги з характеристик, що доповнюються дескрипторами. Загалом це може виглядати так:

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

Наприклад, розглянемо схему профілю heart rate monitor (фітнес браслет). Він складається з двох сервісів та кількох характеристик. З неї відразу стає зрозумілою ієрархія профілю. Характеристика контрольної точки скидає загальний підрахунок витрат калорій на нуль.

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

UUID

Для того, щоб ми могли однозначно звертатися до елементів профілю (сервісів, характеристик і дескрипторів), потрібно всі їх якось пронумерувати. Для цього вводять таке поняття як Universally Unique ID (UUID) або Універсальний унікальний ідентифікатор. У дужках кожного рядка якраз і вказано UUID. І тут є одна особливість. Для UUID вирішили використовувати код довжиною 16 та 128 біт. Навіщо, спитаєте ви? У протоколі BLE все підпорядковане збереженню енергії. Тому розмірність 16 біт цілком розумна. Навряд чи в найближчому майбутньому буде створено більше 65тис. унікальних сервісів та характеристик. На даний момент все, що могли, вже порахували (пам'ятаєте звідки це — «він і вас порахував» :-)) Пронумеровані елементи профілів, сервісів, характеристик и дескрипторів ви можете переглянути за посиланнями.

Однак, я думаю, всі пам'ятають історію з чотирма байтами IP адреси в інтернеті. Спочатку думали що вистачить, а тепер все ніяк не перейдемо на 4-байтну адресу. Що б не повторювати цієї помилки і дати простір пустотливим ручкам саморобників, SIG відразу вирішила ввести ще й 6 бітні UUID. Це особисто мені нагадує неліцензійний діапазон 128МГц, який був дано на відкуп усіляким Кулібіним від радіоканалу. У нашому випадку, на відкуп було віддано 433 бітний ідентифікатор сервісів і характеристик. Це означає, що ми, для своїх сервісів та пристроїв, можемо використовувати практично будь-яке 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и ...

Власне далі починається найцікавіше. Я нагадаю, що ATT базується на клієнтсько-серверному відношенні. Зараз ми розглядаємо пристрій сервера. Він містить таку інформацію, як значення датчиків, стан вимикача світла, дані про місцезнаходження тощо. Тепер, коли всі «учасники нашого параду» пронумеровані, треба якось їх розміщувати в пам'яті пристрою. Для цього ми поміщаємо їх у таблицю, що називається таблицею атрибутів. Запам'ятайте це добре. Це серце BLE. Саме його ми й розглядатимемо надалі. Тепер кожен рядок ми називатимемо аттрибутом. Ця таблиця перебуває у глибині стека і, зазвичай, ми маємо до неї прямого доступу. Ми її ініціалізуємо і до неї звертаємось, але що там відбувається всередині, від нас приховано за сімома печатками.

Розглянемо картинку зі специфікації, проте перед цим хочу відразу звернути увагу на часту плутанину в термінах, а саме в дескрипторах. Роль дескриптора – доповнити опис характеристики. Коли треба розширити її можливості, тоді застосовують дескриптори. Вони так само є аттрибутами, і так само, нарівні з сервісами та характеристиками, розташовуються у таблиці аттрибутів. Ми докладно розберемо їх у другій частині статті. Однак іноді дескрипторами називають номер рядка таблиці аттрибутів. Це треба мати на увазі. Ми ж, щоб не плутатися, використовуватимемо для цих цілей термін «покажчик атрибута».
BLE під мікроскопом (ATTи GATTи...)

Отже атрибут - це дискретне значення, яке має такі властивості, пов'язані з ним:
1. Вказівник атрибута (Attribute Handle) - це індекс таблиці, що відповідає атрибуту
2. Тип атрибута (Attribute Type) - це UUID, який описує його тип
3. Значення атрибута (Attribute Value) - це дані, що індексуються покажчиком атрибута
4. Дозволи атрибутів (Attribute Permissions) - це частина атрибуту, дозволи, які не можуть бути прочитані або записані з використанням протоколу атрибутів

Як це все розуміти? Вказівник атрибута — це, умовно кажучи, його номер у таблиці.
Він дозволяє клієнту посилатися на атрибут у запитах читання чи запису. Ми можемо нумерувати наші рядки (атрибути) від 0x0001 до 0xFFFF. У нашій асоціації з книжковою шафою це номер картки в паперовому каталозі. Аналогічно, як у каталозі бібліотеки, картки розміщуються у порядку збільшення номера. Номер кожного наступного рядка повинен бути більшим за попередній. Як і в бібліотеці, іноді губляться деякі картки, так і в нас — у нумерації рядків можуть бути проміжки. Це дозволяється. Головне, щоб вони йшли по наростаючій.

Тип атрибута визначає, що являє собою даний атрибут. За аналогією з мовою Сі,
де є булеві, числові змінні та рядки, так і тут. За типом атрибута ми дізнаємося
з чим ми маємо справу та як нам далі з цим атрибутом працювати. Нижче ми розглянемо деякі специфічні типи атрибутів. Наприклад, «сервісна декларація» (0х2800), «декларація характеристики» (0х2803), «декларація дескриптора» (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и...)

Як бачите, тут також є поля, що дають можливості читання та запису. Ви можете поставити запитання, чому у нас є дозволи на читання/запис для атрибуту та властивості
читання/запису для значення характеристики? Хіба вони не повинні завжди бути однаковими? Справа в тому, що властивості для значення характеристики фактично є лише рекомендаціями для клієнта, що використовуються в ГАТТ і прикладних шарах. Це просто підказки про те, що клієнт може очікувати від атрибуту оголошення характеристики. Давайте з цим розберемося докладніше. Які види дозволів існують у атрибута?

1. Дозволи доступу:
     - читання
     - Запис
     - Читання та запис
2. Дозвіл аутентифікації:
     - Аутентифікація потрібна
     — автентифікація не потрібна
3. Дозвіл авторизації:
     - авторизація потрібна
     - авторизація не потрібна

Головна відмінність дозволу аттрибутів від властивостей характеристик у тому, перші ставляться до серверам, а другі до клієнтам. Сервер може дозволити читати значення характеристики, але при цьому стояти вимога автентифікації або авторизації. Тому при запиті клієнтом властивостей характеристики ми отримаємо, що читання дозволено. Але при спробі читання отримаємо помилку. Тому можна сміливо говорити про пріоритет дозволів над властивостями. Знання про те, які дозволи є у атрибута, ми з боку клієнта отримати не можемо.

Дескриптор

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

У разі характеристики вимірювання частоти серцевих скорочень у нашій таблиці оголошення значення характеристики супроводжується оголошенням дескриптора. Дескриптор – це атрибут із додатковою інформацією про характеристику. Існує кілька видів дескрипторів. Про них ми докладно поговоримо у другій частині цієї статті. Зараз ми торкнемося лише дескриптора конфігурації параметрів клієнта (Client Characteristic Configuration Descriptor - CCCD). Він має UUID рівну 0х2902. За допомогою цього дескриптора клієнт може включити на сервері індикацію або нотифікацію. Різниця між ними невелика, але таки є. Нотифікація не вимагає підтвердження отримання з боку клієнта. Індикація цього вимагає, хоча вона відбувається на рівні GATT, не доходячи до рівня докладання. Навіщо так, спитаєте ви? На жаль, це мені не відомо. Скажу лише, що фахівці Nordic рекомендують використовувати нотифікацію. Тим більше, що перевірка цілісності пакета (за допомогою CRC) відбувається в обох випадках.

Висновок

Наприкінці статті я хотів би сказати ось про що. Остання таблиця дещо заплутана. Однак я зупинився на ній через те, що вона наводиться в статтіна яку я спираюся. У другій частині своєї статті я маю намір заглибитись у специфікацію BlueTooth 4.0. Там на нас чекають коректніші схеми та малюнки. У третій частині, я хотів би розібрати балку, отриману за допомогою програми Wireshark від одного з гаджетів і побачити «в живу» всю ту теорію, яку ми з вами вивчаємо.

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

Джерело: habr.com

Додати коментар або відгук