Аудитория:Мобильные разработчики, ведущие инженеры встроенного ПО и владельцы SDK со стороны бренда, которые должны интегрировать BLE GATT-схему считывающего пера в свое хост-приложение, а также должны понимать, какие характеристики представляют собой принятые SIG 16-битные UUID (готовые к взаимодействию), а какие — определённые поставщиком 128-битные UUID (проприетарные), и как схема развивается между версиями прошивки, не нарушая работу существующих приложений в полевых условиях.
Каждое считывающее перо, отгружаемое с наших двух фабрик с 2023 года, рекламирует одну и ту же сигнатуру BLE-сервиса: 16-битный принятый SIG сервис Human Interface Device с UUID 0x1812, а также определённый поставщиком 128-битный сервисный UUID, который хост-приложение использует для идентификации пера как устройства Smart Reading Pen. Внутри этих сервисов находятся 11 характеристик, из которых 6 приняты SIG и 5 определены поставщиком. Общая база данных GATT занимает 1,8 КБ ПЗУ на прошивке Q6/Q8 3.3.1 и 1,4 КБ на прошивке F8 3.1.2.
В этой статье рассматриваются все UUID в схеме, объясняется, почему каждый из них является принятым SIG или определённым поставщиком, и документируются правила, которым мы следуем при расширении схемы для нового OEM-клиента, чтобы существующие приложения 230+ дистрибьюторов не вышли из строя.
1. Почему схема GATT вообще важна
BLE-периферия без документированной схемы GATT — это чёрный ящик. Хост-приложение должно угадывать, какая характеристика что делает. В индустрии потребительской электроники это является причиной №1 обращений «приложение не может найти перо». По всему нашему парку из 47 000+ отгруженных устройств обращения, связанные со схемой, снизились с 4,2% от всех обращений в 2023 году до 0,7% в 2026 году, в основном потому, что теперь мы поставляем зафиксированную схему с версионируемыми расширениями.
Схема, которую мы используем на прошивке Q6/Q8 3.3.1, — Схема GATT v3.0, последний раз пересмотренная в ноябре 2025 года. Предыдущая схема v2.x поставлялась на прошивке K7/KF1 1.9.5. Приложения, написанные для v2.x, продолжают работать с v3.0, потому что мы только добавляем характеристики, никогда не удаляем их, и никогда не меняем UUID характеристики.
2. Структура сервисов верхнего уровня
Перо рекламирует три сервиса в своём списке основных сервисов:
| Сервис | UUID | Тип | Обязательный |
|---|---|---|---|
| Общий доступ | 0x1800 | SIG 16-бит | Да |
| Общий атрибут | 0x1801 | SIG 16-бит | Да |
| Устройство HID | 0x1812 | SIG 16-бит | Да |
| Сервис производителя умной ручки для чтения | 8E0C0001-7B3C-4F8E-9F4D-2C8B5A1E0001 | Поставщик 128-бит | Да |
| Сервис батареи | 0x180F | SIG 16-бит | Да |
| Информация об устройстве | 0x180A | SIG 16-бит | Да |
Generic Access (0x1800) и Generic Attribute (0x1801) являются обязательными на каждом BLE-периферийном устройстве. Они предоставляют имя устройства, внешний вид и индикацию изменения сервиса. Human Interface Device (0x1812) — это сервис HOGP, который передаёт отчёты о касаниях OID. Поставщикский сервис — это место, где живут наши проприетарные характеристики. Battery (0x180F) и Device Information (0x180A) — это стандартные принятые SIG сервисы, которые ожидает каждая хост-платформа.
Перо рекламирует полный список основных сервисов в одном AD-пакете, когда MTU позволяет. На F8 (BLE 5.1, MTU 247) помещаются все шесть. На более старых радиомодулях K7/KF1 (MTU 23) в AD-пакете помещаются только два, остальные обнаруживаются хостом через обнаружение сервисов.
3. Характеристики HID-сервиса (0x1812)
HID-сервис предоставляет шесть характеристик:
| Характеристика | UUID | Свойства | Примечания |
|---|---|---|---|
| Информация HID | 0x2A4A | Чтение | bcdHID, bCountryCode, flags |
| Карта отчётов | 0x2A4B | Чтение | Блоб дескриптора из TC-058 |
| Режим протокола | 0x2A4E | Чтение, Запись | Отчёт против загрузки |
| Точка управления HID | 0x2A4C | WriteWithoutResponse | Приостановка / Возобновление |
| Отчёт (Ссылка 1) | 0x2A4D | Notify, Write, WriteWithoutResponse | Отчёт о касании OID |
| Отчёт (Ссылка 2) | 0x2A4D | Уведомление | VU-измеритель аудио |
Единственный UUID 0x2A4D повторно используется для двух отчётов, поскольку HID-сервис допускает несколько характеристик Report, идентифицируемых дескриптором ссылки на отчёт. На Q6/Q8 мы используем две характеристики Report: первая — это отчёт о касании OID, описанный в TC-058, вторая — VU-измеритель аудио (используется хост-приложением для отображения небольшого индикатора VU во время воспроизведения TTS).
4. Характеристики сервиса производителя
UUID сервиса производителя — 8E0C0001-7B3C-4F8E-9F4D-2C8B5A1E0001. 128-битный UUID был сгенерирован с использованием SHA-1 от названия нашей компании и фиксированного префикса. Внутри сервиса производителя находятся пять характеристик:
| Характеристика | UUID | Свойства | Назначение |
|---|---|---|---|
| ID бренда | 8E0C0002-7B3C-4F8E-9F4D-2C8B5A1E0001 | Чтение | Замороженный 4-байтный идентификатор бренда |
| Статус словаря | 8E0C0003-7B3C-4F8E-9F4D-2C8B5A1E0001 | Чтение, Уведомление | Текущий загруженный языковой пакет |
| Управление аудио | 8E0C0004-7B3C-4F8E-9F4D-2C8B5A1E0001 | Запись | Громкость, отключение звука, предустановка эквалайзера |
| Телеметрия | 8E0C0005-7B3C-4F8E-9F4D-2C8B5A1E0001 | Уведомление, Indicate | Логи, коды ошибок |
| Управление OTA | 8E0C0006-7B3C-4F8E-9F4D-2C8B5A1E0001 | Write, Indicate | Триггер обновления прошивки |
Каждая характеристика соответствует соглашению SIG: 128-битный UUID с общим префиксом (8E0C0000-7B3C-4F8E-9F4D-2C8B5A1E0000) и 16-битный идентификатор экземпляра. Последние 4 байта идентификатора экземпляра кодируют номер характеристики. Это делает UUID визуально легко находимыми в приложении BLE-сканера.
5. Сервис батареи (0x180F)
Сервис батареи предоставляет одну характеристику:
| Характеристика | UUID | Свойства | Назначение |
|---|---|---|---|
| Уровень заряда | 0x2A19 | Чтение, Уведомление | Заряд 0–100% |
Ручка передаёт уровень заряда батареи на частоте 1 Гц в прошивке Q6/Q8 версии 3.3.1. Отсчёт АЦП усредняется по 4 выборкам для устранения шума. Изменение более чем на 5% вызывает немедленное уведомление; меньшие отклонения объединяются в периодическое уведомление с частотой 1 Гц. Хост-приложение также может выполнить ручное считывание.
Важный момент: значение характеристики батареи выражено в процентах, а не в милливольтах, согласно спецификации SIG. Показания в милливольтах предоставляются через отдельную характеристику производителя 8E0C0010-7B3C-4F8E-9F4D-2C8B5A1E0001 для инженерной диагностики.
6. Сервис информации об устройстве (0x180A)
Сервис информации об устройстве предоставляет:
| Характеристика | UUID | Свойства | Значение на Q6/Q8 |
|---|---|---|---|
| Название производителя | 0x2A29 | Чтение | "Умная ручка для чтения Произв.Ко." |
| Номер модели | 0x2A24 | Чтение | "Q8" |
| Серийный номер | 0x2A25 | Чтение | 12-символьный ASCII на устройство |
| Версия аппаратного обеспечения | 0x2A26 | Чтение | "Версия D" |
| Версия прошивки | 0x2A26 | Чтение | "3.3.1" |
| Версия программного обеспечения | 0x2A28 | Чтение | "Сборка 8642" |
| Идентификатор системы | 0x2A23 | Чтение | OUI + UUID на устройство |
Характеристика номера модели используется хост-приложением для загрузки соответствующей обложки интерфейса. Мы не размещаем здесь персональные данные (MAC-адрес не указывается в системном идентификаторе; системный идентификатор — это OUI компании плюс случайный UUID на устройство).
7. Процедура обнаружения, которой должно следовать хост-приложение
Корректное хост-приложение выполняет данную последовательность:
- Сканировать рекламный пакет, содержащий 0x1812 в списке UUID сервисов.
- Подключиться с интервалом подключения 15 мс, латентностью подчиненного устройства 0 мс, таймаутом контроля 4 с.
- Запросить обмен MTU; принять до 247.
- Обнаружить все первичные сервисы.
- Для каждого сервиса обнаружить все характеристики.
- Для каждой характеристики прочитать дескриптор формата представления характеристики.
- Подписаться на уведомления для 0x2A4D (касание OID) и 8E0C0005 (телеметрия).
- Прочитать уровень заряда батареи (0x2A19) и информацию об устройстве.
Некорректное приложение подключается с параметрами по умолчанию и сразу пытается записать данные. Мы наблюдаем это в 14% приложений от производителей. В результате время подключения составляет ~3 с вместо ~300 мс. Наша система оценки QA поощряет приложения, следующие данной процедуре.
8. Политика расширения схемы
Мы расширяем схему GATT следуя трём правилам:
- Никогда не удалять характеристику. После того как UUID отгружен в производственной прошивке, этот UUID остаётся в схеме на протяжении всего срока существования платформы. Старые приложения продолжают его читать и игнорируют значение.
- Никогда не изменять UUID. UUID — это 128-битный идентификатор. Его изменение нарушает работу каждого приложения, которое его сохранило.
- Добавлять новые характеристики по следующему свободному идентификатору экземпляра. Для сервиса вендора зарезервировано 256 идентификаторов экземпляров (0x0001–0x0100). При добавлении новой характеристики мы выбираем следующий свободный и увеличиваем минорную версию схемы.
Схема v3.0 (текущая) использует идентификаторы экземпляров 0x0001–0x0010. Схема v4.0 (запланирована для прошивки L5 версии 4.3.0) будет использовать идентификаторы экземпляров 0x0011–0x0020 для новых характеристик, связанных с телеметрией режима класса.
9. Производительность: время обнаружения
| Шаг | Время на Q6/Q8 | Время на F8 | Время на K7/KF1 |
|---|---|---|---|
| Подключение к первому сервису | 95 мс | 110 мс | 145 мс |
| Все сервисы обнаружены | 280 мс | 330 мс | 520 мс |
| Все характеристики обнаружены | 410 мс | 490 мс | 880 мс |
| Чтение дескрипторов CCCD | 220 мс | 280 мс | 480 мс |
| Обмен MTU | 38 мс | 42 мс | 65 мс |
| Всего первое сопряжение | 1,04 с | 1,25 с | 2,1 с |
Приложение хоста, выполняющее всё это менее чем за 1 с — это «быстро»; 1,5 с — «нормально»; более 2 с — «медленно». Все 38 наших встроенных эталонных приложений iOS/Android/Windows укладываются менее чем в 1,5 с.
10. Различия схем между моделями
| Характеристика | Q6/Q8 | F8 | K7/KF1 | L5 | T2/Y6 | P2 |
|---|---|---|---|---|---|---|
| HID 0x2A4D (OID) | Да | Да | Да | Да | Да | Да |
| HID 0x2A4D (VU) | Да | Нет | Нет | Да | Да | Нет |
| Батарея 0x2A19 | Да | Да | Да | Да | Да | Да |
| Идентификатор бренда 8E0C0002 | Да | Да | Да | Да | Да | Да |
| Статус словаря 8E0C0003 | Да | Да | Да | Да | Да | Да |
| Аудио управление 8E0C0004 | Да | Нет | Нет | Да | Да | Нет |
| Телеметрия 8E0C0005 | Да | Да | Да | Да | Да | Да |
| Управление OTA 8E0C0006 | Да | Да | Да | Да | Да | Да |
| Аудио поставщика VU 8E0C0007 | Да | Нет | Нет | Да | Да | Нет |
| Тестовый режим поставщика 8E0C0008 | Да | Да | Нет | Да | Да | Нет |
| Режим класса поставщика 8E0C0009 | Нет | Нет | Нет | Да | Да | Нет |
Только модели L5, T2 и Y6 обладают характеристиками режима класса, так как именно эти модели продаются в образовательный канал. K7/KF1 — это ручка для домашнего использования одним пользователем, поэтому характеристики режима класса отсутствуют.
11. Сравнение схем между версиями прошивки
| Прошивка | Версия схемы | Добавление | Удаление | Совместимость с |
|---|---|---|---|---|
| K7 1.9.0 | 2.0 | — | — | Схема 2.0 |
| K7 1.9.5 | 2.1 | 8E0C0006 OTA | — | Схема 2.0, 2.1 |
| F8 3.1.0 | 2.5 | 8E0C0007 VU | — | Схема 2.5 |
| F8 3.1.2 | 2.5.1 | — | — | Схема 2.5 |
| Q6/Q8 3.3.0 | 3.0 | 8E0C0008 Тест | — | Схема 3.0 |
| Q6/Q8 3.3.1 | 3.0 | — | — | Схема 3.0 |
| L5 4.2.0 | 3.1 | 8E0C0009 Аудитория | — | Схема 3.1 |
| T2/Y6 2.6.4 | 3.1 | — | — | Схема 3.1 |
Схема обратно совместима: приложение, написанное для Схемы 2.0, может подключиться к ручке с прошивкой Схемы 3.1 и считать все характеристики Схемы 2.0; новые характеристики будут просто пропущены.
12. Как выделить бренд-специфичные UUID
Заказчик ODM может запросить бренд-специфичные характеристики. Мы выделяем диапазон от 0x0100 до 0x01FF. Заказчик выбирает 16 ID экземпляров из этого диапазона, и мы регистрируем их в манифесте схемы GATT. Манифест — это YAML-файл в репозитории прошивки; в нём перечислены все ID экземпляров, имя характеристики, маска свойств, размер и начальное значение. CI не пройдёт, если два заказчика запросят один и тот же ID экземпляра.
В манифесте прошивки Q6/Q8 3.3.1 указано 38 текущих выделенных бренд-специфичных диапазонов. Мы можем разместить ещё 13, прежде чем исчерпаем пространство от 0x0100 до 0x01FF и потребуется расширение до 0x0200.
13. Приём сжатия базы данных GATT
База данных GATT может быть уплощена в блоб размером 1,8 КБ в ПЗУ. Используемый нами формат:
[uint16 service_count]
для каждого сервиса:
[uint16 service_uuid_type] [128-bit UUID]
[uint16 characteristic_count]
для каждой характеристики:
[uint16 char_uuid_type] [128-bit UUID]
[uint8 properties]
[uint8 value_size]
[uint8 descriptor_count]
для каждого дескриптора:
[uint16 desc_uuid_type] [128-bit UUID]
[uint8 payload_size] [payload]
Блоб генерируется при сборке прошивки Python-скриптом, который читает YAML-манифест. Общая стоимость в ПЗУ составляет 1824 байта на прошивке Q6/Q8 3.3.1. F8 экономит 384 байта путём объединения HID-сервиса в 5 характеристик вместо 6 (без Audio VU).
14. Набор проверок, выполняемый для каждой схемы
| Проверка | Инструмент | Критерий прохождения |
|---|---|---|
| Уникальность UUID | Скрипт Python CI | Нет дубликатов UUID в манифесте |
| Прямая совместимость схемы | Собственный Python-стенд | Схема N+1 может быть разобрана как Схема N |
| Время обнаружения | Saleae + Wireshark | Менее 1,5 с на Q6/Q8 |
| Частота уведомлений о батарее | Логический анализатор | Ровно 1 Гц ±5% |
| OTA-характеристика | CI-скрипт | OTA-характеристика присутствует на всей производственной прошивке |
Схема, не прошедшая любую из этих проверок, отклоняется. За 86 релизов прошивки с 2023 года на этом этапе было отклонено 4.
16. Дополнительное чтение
- USB HID ручки для чтения и HID через GATT
- Ручка-сканер HID-дескриптор отчёта и страница использования
- Сопряжение ручки для чтения по Bluetooth SSP Secure Simple Pairing
- Ручка-сканер GATT-сервер и механизм уведомлений
- Ручка-сканер Bluetooth 5.0 против 5.2 против 5.3
- Ручка-сканер механизм обновления прошивки OTA
- Ручка-сканер частота выборки телеметрии
- Ручка-сканер криптография и TrustZone