Bluetooth это популярная технология радиообмена данными на коротких дистанциях, обладающая надежной связью, пониженным энергопотреблением и невысокой стоимостью реализации. Системы Bluetooth можно поделить на 2 категории Classic Bluetooth и Bluetooth Low Energy (BLE). ESP32 поддерживает оба этих режима одновременно (dual-mode Bluetooth).
Примечание: незнакомые термины и сокращения см. в Словарике [3].
Стек протоколов Bluetooth делится на 2 части: стек контроллера (controller stack) и стек хоста (host stack). Стек контроллера используется для управления аппаратным интерфейсом и соединением, и содержит в себе PHY, Baseband, Link Controller, Link Manager, Device Manager, HCI и другие модули. Стек хоста содержит L2CAP, SMP, SDP, ATT, GATT, GAP, различные профили и функции в качестве интерфейса для слоя приложения, что упрощает слою приложения доступ к системе Bluetooth. Bluetooth Host может быть реализован в том же устройстве, что и Bluetooth Controller, или может быть реализован на разных устройствах. И то и другое поддерживается ESP32. Рис. 1-1 описывает некоторые типовые структуры приложения:
Рис. 1-1. Архитектура библиотек хоста и контроллера Bluetooth в системе разработки ESP-IDP [2].
Примеры возможных сценариев использования:
1. Настройки ESP-IDF по умолчанию: BLUEDROID выбран в качестве Bluetooth Host, и VHCI (программно реализованный виртуальный интерфейс HCI) используется для обмена между Bluetooth Host и Bluetooth Controller. В этом сценарии и BLUEDROID, и Controller, оба реализованы в одном устройстве (например в чипе ESP32), устраняя необходимость в отдельном PC или других устройствах хоста, на которых работает Bluetooth Host.
2. ESP32 используется только как Bluetooth Controller, и для доступа к нему требуется дополнительное устройство, на котором работает Bluetooth Host (это может быть Linux PC, на котором работает BlueZ, или Android, на котором работает BLUEDROID, и т. п.). Это часто используемый сценарий для периферийных устройств Bluetooth (клавиатуры, мыши, носимые медицинские системы и т. д.).
3. Этот сценарий подобен сценарию 2. Отличие в тесте контроллера BQB (или других сертификациях), когда ESP32 может быть проверен путем подключения его к утилитам тестирования, когда UART разрешен в качестве интерфейса ввода/вывода.
Выбор интерфейсов HCI. В системе ESP32 для HCI одновременно может использоваться только один интерфейс ввода/вывода (IO interface). Это значит, что если разрешен UART, то такие интерфейсы, как VHCI и SDIO, будут запрещены. В ESP-IDF (V2.1 или более свежих версий), можно сконфигурировать интерфейс ввода/вывода Bluetooth как VHCI или UART в menuconfig.
Рис. 1-3. Экран конфигурирования опций Bluedroid.
Здесь можно сконфигурировать следующие опции.
• Bluetooth Bluedroid Host Stack task stack size: установит размер стека задачи хоста. • Bluedroid memory debug: разрешает отладочные сообщения, касающиеся памяти BLUEDROID. • Classic Bluetooth: разрешает режим Classic Bluetooth. • Include GATT server module (GATTS): подключает модуль GATTS. • Include GATT client module (GATTC): подключает модуль GATTC. • Include BLE security module (SMP): подключает модуль SMP. • BT/BLE MAX ACL CONNECTIONS (1~7): установит максимальное количество соединений ACL.
Когда выбрана опция HCI use UART as IO, отобразится следующий экран:
Рис. 1-4. Конфигурация UART.
Пользователи могут здесь сконфигурировать "UART Number for HCI (NEW)" (номер используемого порта UART) и "UART Baudrate for HCI (NEW)" (скорость UART). Следует упомянуть, что должны также поддерживаться сигналы квитирования CTS/RTS, чтобы разрешить UART в качестве интерфейса HCI IO.
Bluetooth Operating Environment. В ESP-IDF по умолчанию в качестве рабочего окружения используется двухядерная конфигурация приложения (dual-core FreeRTOS). ESP32 Bluetooth может назначить основанное на функциях задач различные приоритеты этим задачам. Задачи с самым высоким приоритетом работают для Controller. Задачи Controller с самыми высокими требованиями к реалтайму получают в системе FreeRTOS самый высокий приоритет, за исключением задач IPC (Inter-Processor Call), которые используются в основном для обмена данными между двумя ядрами CPU [4]. BLUEDROID (по умолчанию ESP-IDF Bluetooth Host) содержит всего 4 задачи, на которых работают BTC, BTU, HCI UPWARD и HCI DOWNWARD.
[Архитектура]
Bluetooth Controller. Для контроллера ESP32 поддерживает и Classic BT, и BLE (V4.2). Controller интегрирует в себе различные функции, включая протокол H4, HCI, Link Manager, Link Controller, Device Manager и аппаратный интерфейс (HWI). Эти функции предоставлены разработчику в виде библиотек, также предоставлены некоторые из API-функции для доступа к контроллеру. Для дополнительной информации см. [5].
Рис. 1-5. Архитектура контроллера Classic BT и BLE (из SIG BT CORE 4.2).
[BLUEDROID]
BLUEDROID изначально довольно сложный, поскольку включает в себя полный набор функций и поддерживает большинство часто используемых стандартов и архитектурных разработок. ESP-IDF реализует значительно модифицированный BLUEDROID используется в качестве Bluetooth Host (Classic BT + BLE). В этой реализации сохранено большинство кода ниже слоя BTA, и почти полностью удален слоя BTIF, с использованием более линейного слоя BTC в качестве встроенной спецификации и общего слоя управления (Misc control layer). Архитектура модифицированного BLUEDROID и взаимоотношения с контроллером показаны на рисунке ниже:
Рис. 1-6. Диаграмма ESP32 BLUEDROID.
Примечание: эта диаграмма описывает главным образом иерархию BLUEDROID, не вдаваясь в такие подробности, как HCI TASK. Более подробную информацию по каждому слою см. далее.
Как показано на рис. 1-6, BLUEDROID в основном можно поделить на 2 слоя, которые соответствуют BTU и BTC (кроме HCI). Каждый слой отвечает за свои соответствующие задачи (см. Словарик). Рисунок также не описывает подробно слой HCI. Фактически на слое HCI имеется 2 задачи, которые обрабатывают уходящие данные (Downward Data) и входящие данные (Upward Data), как это реализовано в дизайнах ESP-IDF V2.1 и более старых версий.
Логика дизайна этой архитектуры состоит в том, чтобы минимизировать задачи пользователя (User Tasks) и оптимизации структуры Bluetooth путем переноса связанных с Bluetooth задач на слой BTC.
По соображениям совместимости со старыми версиями библиотек и по реальным запросам некоторые профили Classic Bluetooth, такие как RFCOMM и A2DP, а также другие протоколы нижнего уровня реализованы на слое BTU, в то время как некоторые протоколы, связанные с процедурными средствами управления, или требующие ESP-API, реализованы в слое BTC.
Некоторые профили и низкоуровневые функции Bluetooth Low Energy, такие как 6LowPan или Dynamic L2CAP Channel, будут реализованы на слое BTU, предоставляя слой приложения с ESP API через BTC.
Адаптация, связанная с OS. Некоторые интерфейсы, относящиеся к системе BLUEDROID, требуют адаптации OSI (Operation System Interface, интерфейс операционной системы (семафоры, таймеры, потоки, и все, что относится к возможностям FreeRTOS). Функции используют Timer (Alarm), Task (Thread), Future Await/Ready (Semaphore) и Allocator/GKI (malloc/free).
FreeRTOS Timer d BLUEDROID упакован как Alarm, и используется для запуска таймера, который вызывает обработку определенных задач.
В BLUEDROID потоки POSIX Thread заменены на задачи FreeRTOS, и используется очередь (FreeRTOS Queue) для запуска задач (например пробуждение, wake up).
В BLUEDROID функция Future Await/Ready используется для достижения блокировки (Blocking). Пакеты блокировки (Future Lock) в виде xSemphoreTake FreeRTOS работают в качестве функции future_await, и пакеты xSemphoreGive в качестве функции future_ready. Следует отметить, что функции future_await и future_ready нельзя вызывать в контексте одной и той же задачи.
В BLUEDROID стандартные библиотечные функции malloc/free упакованы в функцию Allocator, которая резервирует или освобождает память. Кроме того, функция GKI также использует malloc/free в качестве основной функции GKI_getbuf/GKI_freebuf.
[Структура каталогов Bluetooth]
Если заглянуть в каталог component/bt, находящийся в директории установки ESP-IDF, то мы увидим примерно следующее:
/components/bt/ ├── common │ ├── api │ │ ├── include │ │ └── esp_blufi_api.c │ ├── btc │ │ ├── core │ │ ├── include │ │ └── profile │ ├── include │ └── osi ├── controller │ ├── esp32 │ │ ├── bt.c │ │ ... │ ├── esp32c3 │ │ ├── bt.c │ │ ... │ ├── esp32s2 │ │ ├── bt.c │ │ ... │ ├── lib_esp32 │ └── lib_esp32c3_family ├── esp_ble_mesh ├── host │ ├── bluedroid │ │ ├── api │ │ ├── bta │ │ ├── btc │ │ ├── device │ │ ├── external │ │ ├── hci │ │ ├── main │ │ ├── stack │ │ └── Kconfig.in │ └── nimble ├── include │ ├── bt.h │ ... ├── test ├── CMakeLists.txt ├── component.mk ├── Kconfig ├── linker.lf └── sdkconfig.rename
Kconfig - файл для menuconfig.
component.mk - makefile для make.exe.
CMakeLists.txt - конфигурационный файл для CMake.exe.
bluedroid - домашний каталог BLUEDROID.
/api - модули всех API-функций, кроме относящихся к Controller. /bta - слой адаптации для интерфейса с некоторыми низкоуровневыми протоколами хоста. /btc - слой управления высокоуровневыми протоколами (включая профили) и другими функциями хоста. /device - относится к управлению устройством Controller, например базовый набор процессов контроллера HCI CMD. /external - код, который не относится явно к Bluetooth, но все еще используется, например программное обеспечение кодека SBC. /hci - протоколы слоя HCI. /main - основная программа (запуск или приостановка процесса). /stack - стеки протоколов нижнего уровня Host (GAP, ATT, GATT, SDP, SMP, и т. д.).
common
/osi - интерфейс с операционной системой (semaphore, timer, thread).
controller
/lib_esp32 - библиотека для контроллера ESP32. /lib_esp32c3_family - библиотека для контроллера ESP32-С3.
esp32xxx
/bt.c - файл управления, относящийся к определенной модели чипа.
include
/bt.h - заголовочный файл, относящийся к определенной модели чипа.
[Classic Bluetooth]
Стек Bluetooth Host в ESP-IDF произошел от BLUEDROID, и был адаптирован для встраиваемых приложений. На слое низкого уровня стек Bluetooth Host Stack обменивается с Bluetooth dual-mode Controller через виртуальный интерфейс HCI (VHCI). На слое верхнего уровня стек Bluetooth Host предоставляет профили и API-функции для управления стеком со стороны приложений пользователя.
Протоколы определяют форматы сообщений и процедуры, предназначенные для специфических функций, например транспорт данных, управление соединением (link control), служба безопасности (security service) и обмен служебной информацией (service information exchange). Профили Bluetooth, с другой стороны, определяют функции и возможности, требуемые на каждом слое системы Bluetooth, от PHY до L2CAP, и любые другие протоколы вне спецификации ядра.
Ниже показаны профили Classic BT и протоколы, поддерживаемые в настоящий момент стеком хоста.
• Профили: GAP, A2DP(SNK), AVRCP(CT). • Протоколы: L2CAP, SDP, AVDTP, AVCTP.
Модель протоколов показана на рис. 2-1.
Рис. 2-1. Модель протоколов.
Показанные на рис. 2-1 протоколы L2CAP и SDP необходимы в минимальной конфигурации стека хоста для Classic Bluetooth. AVDTP, AV/C и AVCTP выходят за рамки основной спецификации и используются определенными профилями.
L2CAP. Протокол управления логикой соединения и адаптации (Logical Link Control and Adaptation Protocol) поддерживает мультиплексирование протоколов верхнего уровня, сегментацию и пересборку пакетов, а также качество предоставления сервисной информации. L2CAP дает возможность разным приложениям совместно использовать один и тот же логический линк ACL-U. Приложения и интерфейс службы протоколов вместе с L2CAP используют интерфейс каналов для создания соединений с эквивалентными элементами на других устройствах.
Каналы L2CAP могут работать в одном из 6 режимов, выбранном через процедуру конфигурирования канала L2CAP. Рабочие режимы различаются по QoS, которое они могут предоставить, и разные режимы применяются в разных условиях работы приложений. Вот эти режимы:
• Basic L2CAP Mode • Flow Control Mode • Retransmission Mode • Enhanced Retransmission Mode • Streaming Mode • LE Credit-Based Flow Control Mode
Для логических линков ACL-U поддерживаются рабочие режимы: Basic L2CAP Mode, Enhanced Retransmission Mode и Streaming Mode. Для другого функционала канал сигнализации L2CAP поддерживает фиксированный канал, в то время как Frame Check Sequence (FCS) является также поддерживаемой опцией.
SDP. Протокол определения служб (Service Discovery Protocol, SDP) предоставляет для приложений способ узнать, какие сервисы предоставляет доступное по радио устройство Bluetooth, а также определить характеристики этих доступных служб. SDP использует обмен между сервером SDP и клиентом SDP. Сервер содержит список записей с описаниями характеристик служб, работающих на сервере. Клиент может запросит эту информацию путем выдачи запроса SDP.
И клиент, и сервер SDP реализованы в стеке хоста, и этот модуль используется только такими профилями, как A2DP и AVRCP, и в настоящий момент не предоставляется API для приложений пользователя.
GAP. Generic Access Profile (GAP) предоставляет описание режимов и процедур в контексте нахождения устройства в сети (discoverability), подключения к нему и безопасности.
В настоящее время стек хоста Classic Bluetooth предоставляет только ограниченный набор GAP API. Приложение, которое может использовать эти API-функции, как если бы они были "пассивным устройством", которое может быть обнаружено внешними, подключенными к ним пирами Bluetooth. Однако API-функции, используемые для инициирования процедуры запроса, в настоящее время не предоставляются для приложений пользователя.
Что касается аспекта безопасности, то возможность ввода/вывода жестко закодирована как "No Input, No Output”. Поэтому в Secure Simple Pairing поддерживается только модель ассоциации "Just Works". Хранение ключа линка выполняется на хосте автоматически.
Позже появятся дополнительные интерфейсы GAP API для Classic Bluetooth. Также в ближайшем будущем будут предоставлены более мощные функции Security API, поддерживающие другие модели ассоциации. API для обнаружения устройств и политики линка будут добавлены на более позднем этапе разработки библиотек.
A2DP и AVRCP. Advanced Audio Distribution Profile (A2DP) определяет протоколы и процедуры, которые реализуют передачу высококачественного звукового контента mono или stereo на каналах ACL. A2DP обрабатывает передачу потока звуковых данных (audio streaming), и часто используется совместно с Audio/Video Remote Control Profile (AVRCP), который в свою очередь включает функции управления audio/video. Рис. 2-2 показывает структуру и зависимости профилей (в соответствии с "Advanced Audio Distribution Profile Specification, Revision 1.3.1"):
Рис. 2-2. Зависимости профиля.
Как показано на рис. 2-2, A2DP зависит от GAP, а также от Generic Audio/Video Distribution Profile (GAVDP), который определяет необходимые процедуры для настройки audio/video стриминга.
В A2DP определены 2 роли: источника (Source, SRC) и получателя (Sink, SNK). SRC выступает как источник цифровых аудиоданных, а SNK работает в качестве их приемника.
В AVRCP определены 2 роли: Controller (CT) и Target (TG). CT это устройство, которое инициирует транзакцию отправкой фрейма команды в TG. В качестве CT могут выступать компьютеры, PDA и мобильные телефоны (смартфоны). TG это устройство, которое принимает фрейм управления и в соответствии с ним генерирует фрейм ответа. Аудиоплееры или головные телефоны могут служить примерами устройств TG. В настоящее время A2DP (SRC) и AVRCP (CT) поддерживаются, и устройство может работать как беспроводный динамик, который также может посылать сообщения дистанционного управления на источник аудиоданных.
В текущих библиотеках A2DP поддерживается только аудиокодек SBC, который обязателен по спецификации A2DP. Реализованы A2DP Version 1.2 и AVDTP Version 1.2.
Audio/Video Distribution Transport Protocol (AVDTP) определяет двоичные транзакции между устройствами Bluetooth для настройки стриминга и передачи медиапотока данных для audio и video с использованием L2CAP. В качестве базового протокола для A2DP, AVDTP используется слой L2CAP, и это состоит из объекта сигнализации, необходимого для согласования параметров потоковой передачи и объекта транспорта, который поддерживает сам стриминг.
Базовое обслуживание возможностей транспорта AVDTP предусмотрено спецификацией A2DP. В соответствии с конфигурацией текущих возможностей сервиса предоставляются базовые Media Transport и Media Codec.
AVRCP определяет требования, необходимые для поддержки сценария дистанционного управления Audio/Video.
Команды, используемые в AVRCP, попадают в 3 основные категории. Первая из них это набор команд AV/C Digital Interface, который применяется только в определенных случаях, и транспортируется через Audio/Video Control Transport Protocol (AVCTP). Команды браузинга включены во вторую категорию, передаваемые через другой канал AVCTP. Третья категория Cover Art Commands, она используется для передачи изображений, связанных с медиаресурсами, и передается через протокол OBEX, определенный в Bluetooth Basic Imaging Profile (BIP).
В AVRCP используется 2 набора команд AV/C. Первый включает команды PASS THROUGH, UNIT INFO и SUBUNIT INFO, которые определены спецификацией AV/C. Второй набор включает специальные AV/C команды, определенные как расширение производителя (Bluetooth SIG Vendor-Dependent). Команды AV/C посылаются через канал управления AVCTP. Команда PASS THROUGH используется для передачи пользовательской операции от кнопки из Controller в суб-юнит панели, что предоставляет простой и общедоступный механизм по управлению целевым устройством. Например, ID операции в команде PASS THROUGH включает такие общие инструкции, как Play, Pause, Stop, Volume Up и Volume down.
Для обеспечения совместимости AVRCP распределяет функции A/V по 4 категориям:
• Player/Recorder • Monitor/Amplifier • Tuner • Menu
В текущей реализации библиотек предоставляются AVRCP Version 1.3 и AVCTP Version 1.4. Конфигурация по умолчанию для AVRCP поддерживает функции категории 2: Monitor/Amplifier. Также предоставлены API-функции для передачи команд PASS THROUGH.
A2DP и AVRCP часто используются вместе. В текущем решении стек хоста нижнего уровня реализует логику AVDTP и AVCTP, предоставляя при этом независимо интерфейсы для A2DP и AVRCP. Однако на верхнем уровне стека, однако вместе два профиля составляют модуль "AV". Слой BTA, например, предоставляет унифицированный интерфейс "AV", и в слое BTC имеется машина состояний, которая обрабатывает события для обоих профилей. Однако API-функции предоставлены отдельно для A2DP и AVRCP.
[Bluetooth Low Energy (BLE)]
GAP. В этой секции представлена информация по реализации и использованию BLE GAP API в ESP32. GAP (Generic Access Profile) определяет процесс распознавания устройств в сети, управление устройством и установкой соединения между устройствами BLE.
BLE GAP реализован в виде API-вызовов и возвращаемого события (Event), где происходит обработка результата API-вызова. Когда устройство пира инициирует запрос, статус этого устройства также возвращается событием Event.
Для устройства BLE определены 4 роли GAP:
• Broadcaster: это устройство, которые посылает широковещательные пакеты оповещения (advertising), чтобы его можно было обнаружить в сети другими прослушивающими радиоэфир устройствами (observer). • Observer: это устройство, которое сканирует эфир с целью обнаружения broadcaster-ов, и информация о них возвращается приложению. Это устройство может только отправлять запросы сканирования, но подключаться к устройствам не может. • Peripheral: это устройство, которое посылает оповещения о себе advertising-пакетами с обозначением возможности подключения, и становится подчиненным устройством, когда к нему кто-то подключается. • Central: это устройство, которое инициирует соединения с периферийными устройствами (Peripheral), и становится главным устройством, когда установлен физический линк с устройством Peripheral.
Рис. 3-1. Переходы состояний между ролями GAP.
Примечание: в этой статье устройство Central называется хостом (Bluetooth Host).
[Процедура широковещания BLE]
Broadcast public address. Широковещание (broadcast) использует общедоступный адрес (public address). Когда для широковещания (broadcast) используется общедоступный адрес (public address), поле own_addr_type структуры esp_ble_adv_params_t должно быть установлено в BLE_ADDR_TYPE_PUBLIC.
Рис. 3-2. Broadcast с использованием public address.
Broadcast resolvable address. Когда для широковещания используется разрешимый адрес (resolvable address) нижележащий стек протоколов обновляет адрес широковещания каждые 15 минут. Для этого поле own_addr_type структуры esp_ble_adv_params_t должно быть установлено в BLE_ADDR_TYPE_RANDOM.
Рис. 3-3. Broadcast с использованием resolvable address.
Примечание: в этом случае широковещание начинается только после возврата события esp_ble_gap_config_local_privacy, и поле own_addr_type в параметре широковещания должно быть установлено в BLE_ADDR_TYPE_RANDOM.
Broadcast static random address. Когда для широковещания используется статический случайный адрес (static random address), поле own_addr_type структуры esp_ble_adv_params_t должно быть установлено в BLE_ADDR_TYPE_RANDOM, также как в случае широковещания с использованием resolvable address.
Рис. 3-4. Broadcast с использованием static random address.
Режимы BLE. Для широковещания BLE определены 5 режимов: Connectable Scannable Undirected, High Duty Cycle Directed, Scannable Undirected, Non-connectable Undirected и Connectable Low Duty Cycle Directed.
Connectable Scannable Undirected. В этом режиме устройство может быть обнаружено, и к нему можно осуществить подключение любым Central-устройством. Scannable показывает, что локальному устройству нужно ответить пакетом scan response, когда Central отправляет scan request.
Таблица 3-1. Структура пакета.
Полезная нагрузка
|
AdvA (6 байт) |
AdvData (0 .. 31 байт) |
Как показано в таблице 3-1, пакет Connectable Scannable Undirected включает 6 байт broadcast-адреса, и от 0 до 31 байт данных broadcast-пакета. Когда для широковещания используется static random address, адрес широковещания указывается вызовом esp_ble_gap_set_rand_addr. Когда для широковещания используется public address или resolvable address, адрес широковещания генерируется стеком протоколов автоматически.
High Duty Cycle Directed и Connectable Low Duty Cycle Directed. Направленные широковещания (IP directed broadcasts) могут быть обнаружены только назначенными устройствами, и только назначенные устройства могут к ним подключиться.
Таблица 3-2. Структура пакета.
Полезная нагрузка
|
AdvA (6 байт) |
InitA (0 .. 31 байт) |
Как показано в таблице 3-2, пакет High Duty Cycle Directed Broadcast включает 6 байт адреса широковещающего устройства и 6 байт адреса принимающего устройства. В этом режиме параметры широковещания adv_int_min и adv_int_max игнорируются.
В режиме Connectable Low Duty Cycle Directed параметры широковещания adv_int_min и adv_int_max должны быть больше 100 мс (0xA0).
Примечание: направленные широковещания (IP directed broadcasts) не переносят данные (Adv Data).
Scannable Undirected. В этом режиме устройство может быть обнаружено любым Central-устройством, но устройству подключиться нельзя.
Таблица 3-3. Структура пакета.
Полезная нагрузка
|
AdvA (6 байт) |
AdvData (0 .. 31 байт) |
Как показано в таблице 3-3, пакет Scannable Undirected включает 6 широковещательного адреса и от 0 до 31 байт данных (broadcast packet data), с такой же структурой, как и пакет Connectable Scannable Undirected. В этом режиме устройство может быть просканировано любым Central-устройством, но подключиться к нему нельзя.
Non-connectable Undirected. В этом режиме устройство может быть обнаружено любым устройством, но его нельзя ни сканировать, ни подключиться к нему. Не сканируемые устройства это те, которые не отвечают на пакетом scan response, когда Central-устройство посылает scan request. Не подключаемые устройства это те, с которыми Central-устройство не может установить соединение.
Таблица 3-4. Структура пакета.
Полезная нагрузка
|
AdvA (6 байт) |
AdvData (0 .. 31 байт) |
Как показано в таблице 3-4, пакет широковещания Non-connectable Undirected также включает 6 байт широковещательного адреса, и от 0 до 31 байт данных (broadcast packet data). В этом режиме устройство может быть обнаружено и могут быть прочитаны передаваемые им данные, но его нельзя ни сканировать, ни подключиться к нему.
BLE Broadcast Filtering Policy. В архитектуре ESP32 BLE политика фильтрации широковещания (broadcast filtering policy) реализована установкой типа перечисления adv_filter_policy, которое может быть одним из четырех следующих значений:
• ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY • ADV_FILTER_ALLOW_SCAN_WLST_CON_ANY • ADV_FILTER_ALLOW_SCAN_ANY_CON_WLST • ADV_FILTER_ALLOW_SCAN_WLST_CON_WLST
Эти 4 значения соответствуют 4 случаям:
ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY. Можно сканировать и подключаться со стороны любого Central (нет белого списка).
ADV_FILTER_ALLOW_SCAN_WLST_CON_ANY. Обрабатываются все запросы соединения, но запросы сканирования (scan requests) обрабатываются только по белому списку (whitelist).
ADV_FILTER_ALLOW_SCAN_ANY_CON_WLST. Обрабатываются все scan requests, но подключения возможны только по белому списку.
ADV_FILTER_ALLOW_SCAN_WLST_CON_WLST. Белый список используется и для обработки scan requests, и для подключений.
BLE Scanning Procedure. В ESP32, сканирующее устройство устанавливает параметры сканирования вызовом esp_ble_gap_set_scan_params, и затем запускает сканирование вызовом esp_ble_gap_start_scanning. Информация сканируемого устройства будет возвращена по событию ESP_GAP_BLE_SCAN_RESULT_EVT, или будет сгенерировано событие ESP_GAP_SEARCH_INQ_CMPL_EVT, когда произошел таймаут.
Примечание: когда значение длительности установлено в 0, устройство будет сканироваться постоянно, без таймаута.
Механизм реализации BLE GAP. ESP32 вызывает API-функции BLE GAP, регистрирует BLE GAP Callback и получает статус текущего устройства по возвращаемому из события значению.
[GATT]
ATT. Данные внутри архитектуры BLE существуют в форме атрибутов, состоящих из 4 базовых элементов:
Attribute Handle(*): дескриптор атрибута, который может помочь нам найти определенный атрибут. Дескриптор подобен уникальному адресу, по которому обращаются к данным в памяти. Например, дескриптор первого атрибута 0x0001, второго 0x0002, и так далее, вплоть до 0xFFFF.
Attribute Type: каждый набор данных представляет определенный тип информации (например температура, мощность передатчика, напряжение батареи и т. д.). Здесь эту функцию выполняет атрибут типа. Для идентификации типа атрибута используется 16-битное или 128-битное число, также известное как UUID. Для стандартных типов атрибута имеется публичный справочник 16-битных идентификаторов [6]. Например UUID 0x2A09 это уровень напряжения батареи (Battery Level), и UUID 0x2A6E это температура.
Attribute Value: значение атрибута это ключевая информация для каждого атрибута, в то время как другие 3 элемента (дескриптор, тип и разрешения доступа) являются дополнительной информацией, позволяющей лучше понять, что атрибут обозначает, и как с ним работать. Длина значения атрибута может быть фиксированной или переменной. Например, длина значения для Battery Level только 1 байт, что вполне достаточно для выражения всех возможных значений уровня напряжения батареи (например 0 .. 100), в то время как у BLE-enabled pass-through module длина переменная.
Attribute Permission: каждый атрибут содержит информацию о том, можно ли его читать или записывать, для чего служит Attribute Permission (разрешение на доступ).
Примечание (*): в этом переводе я старался придерживаться следующих значений для терминов handle и descriptor. Handle это просто уникальное число, в пределах некоторого объекта однозначно идентифицирующее что-либо (дословный перевод "ручка"), и этот термин я перевел как дескриптор. Descriptor перевел как описатель (обычно это набор байт в виде текстовой строки).
Таблица 3-5. Структура атрибута.
Attribute Handle |
Attribute Type |
Attribute Value |
Attribute Permission |
0x0001 |
- |
- |
- |
0x0002 |
- |
- |
- |
... |
- |
- |
- |
0xFFFE |
- |
- |
- |
0xFFFF |
- |
- |
- |
Устройство, которое хранит данные (т. е. атрибуты) определено как сервер (это устройство Peripheral), и устройство которое к ним обращается, определено как клиент (это устройство Central). Ниже перечислены операции между сервером и клиентом:
• Клиент посылает на сервер записываемые данные. Для записи значения атрибута могут использоваться как Write Request (запрос записи), так и Write Command (команда записи). Однако ответ (Write Response) посылается только при использовании запроса (Write Request).
• Сервер посылает данные клиенту либо индикацией (Indication), либо оповещением (Notification). Различие между Indication и Notification только в том, что подтверждение (Confirmation) предлагается только при использовании индикации. Это похоже на различия между Write Request и Write Command.
• Клиент также может получить данные сервера инициированием запроса чтения (Read Request).
Рис. 3-5. Общие операции между сервером и клиентом.
Примечание: для получения подробной информации по общим операциям между сервером и клиентом см. Core_V5.0, Vol3. Part F, Chapter 3.4 "Attribute Protocol PDUs".
Общие операции между сервером и клиентом реализуются с использованием ATT PDU. Каждое устройство может указать свой поддерживаемый MTU, что задает максимальную длину сообщения ATT. В ESP32 IDF значение MTU может быть 23 - 517 байт, и общая длина значения атрибута не ограничена.
Если длина пакета пользователя больше (MTU-3), то для записи необходим подготовительный запрос (Prepare Write Request). Подобным образом, если длина пакета больше (MTU-1), то для чтения остальных данных требуется запрос на чтение большого блока (Read Blob Request).
GATT Profile. ATT задает минимальную единицу хранения данных в архитектуре BLE, в то время как GATT определяет, как представлен набор данных в виде значений атрибутов и дескрипторов, как объединяются подобные данные в службе, и как определить, какими службами обладает устройство и какие данные эти службы могут предоставить.
GATT вводит концепцию характеристик (Characteristics), которые касаются информации необязательно числовой:
• Единица представленного значения. Например, вес измеряется в килограммах (kg), температура в градусах Цельсия (C°), и так далее. • Имя представленного значения. Для характеристик с определенным UUID, например атрибута температуры, имя значения информирует Central-устройство, что это значение соответствует "the temperature in the master bedroom" (температуре в главной спальне), в то время как другое значение может соответствовать "the temperature in the living room" (температура в гостиной). • Экспонента для больших чисел, таких как 230000 и 460000. Если указана экспонента 10^4, то достаточно передать только "23" и "46" для представления 230000 и 460000.
Это всего лишь несколько примеров требований представления описания данных, в реальных приложениях может быть множество вариантов требований к данным. Чтобы предоставить более подробную информацию, может понадобиться зарезервировать больше места для информации по каждой характеристике. Однако во многих случаях большинство дополнительно зарезервированного пространства не будет использоваться. Подобные разработки не будут удовлетворять требованиям протоколов BLE. Для таких случаев спецификация GATT вводит концепцию описателей (descriptors) для дополнительной информации. Следует отметить, что каждый элемент данных и descriptor не имеют соответствия один-к-одному, т. е. у сложных данных может быть несколько описателей, в то время как простые данные могут вообще не иметь описателя.
Характеристика составлена из 3 базовых элементов:
Characteristic Declaration: декларация это начало характеристики, информирующее о том, что дальше идет значение характеристики. Все, что находится между двумя декларациями, относится к полной характеристике. В декларации также включены свойства чтения и записи. Characteristic Value: значение это основная часть характеристики, где находится наиболее значимая информация. Descriptor(*): описатель может дополнительно пояснить назначение характеристики (например предоставить информацию конфигурации), и у характеристики может быть несколько описателей.
Примечание (*): в этом переводе я старался придерживаться следующих значений для терминов handle и descriptor. Handle это просто уникальное число, в пределах некоторого объекта однозначно идентифицирующее что-либо (дословный перевод "ручка"), и этот термин я перевел как дескриптор. Descriptor перевел как описатель (обычно это набор байт в виде текстовой строки).
В BLE концепция GAP группирует подобные функции друг с другом. формируя службы (Services). Например, все характеристики и поведение, относящиеся к батарее, могут быть определены как Battery Service; все характеристики и поведение устройства, относящиеся к проверке частоты сердцебиения, могут быть определены как Heart Rate Service; все характеристики и поведение, относящиеся к шкале веса, можно определить как Weight Scale Service, и так далее.
Service обычно включает в себя одну или большее количество характеристик, и каждая характеристика включает ноль или большее количество описателей. Пользователи могут выбрать необходимые им службы на основе своих требований, формируя конечное приложение.
Таблица 3-6. Определение служб.
Attribute Handle |
Attribute Type |
0x0001 |
Service 1 (служба 1) |
0x0002 |
Characteristic Declaration 1 (декларация характеристики 1) |
0x0003 |
Characteristic Value 1 (значение характеристики 1) |
0x0004 |
Descriptor 1 (описатель 1) |
0x0005 |
Characteristic Declaration 2 (декларация характеристики 2) |
0x0006 |
Characteristic Value 2 (значение характеристики 2) |
0x0007 |
Descriptor 2 (описатель 2) |
0x0008 |
Descriptor 3 (описатель 3) |
0x0009 |
Service 2 (служба 2) |
... |
... |
Примечания: другое описание понятий служб, характеристик и описателей см. в следующих источниках:
• Chapter 3 “Service Interoperability Requirements”, Part G, Vol3., Core_V5.0; • https://www.bluetooth.com/zh-cn/specifications/gatt.
Gatt Services в среде ESP32 IDF. В ESP-IDF Release 1.0 пользователи могут добавить службы и характеристики вручную, по одному, с использованием событий. Все операции чтения-записи достигают слоя приложения через события, и пользователи могут пакетами отвечать на события. Такой подход подвержен ошибкам пользователей, не знакомых с протоколом BLE, особенно когда добавляются службы в большой базе данных GATT. Поэтому добавлять службы вручную по одной не рекомендуется.
Примечание: интерфейс и примеры добавления службы и характеристик вручную все еще сохранены в ESP IDF (см. пример gatt_service).
В ESP-IDF Release 2.0 представлено добавление служб и характеристик с помощью таблицы атрибутов. Пользователи могут добавить новые службы и характеристики просто путем ввода их в конец таблицы и последующего вызова esp_ble_gatts_create_attr_tab. Дополнительно также поддерживается ответ более низкого уровня, т. е. более низкий уровень может ответить на некоторые запросы и идентифицировать ошибки автоматически, так что пользователи могут сконцентрироваться на приеме и отправке данных.
Таким образом, пользователи могут легко переносить профили на платформу ESP32 с других платформ без необходимости повторно внедрять спецификации BLE.
Примечание: рекомендуется добавлять службы и характеристики через таблицу атрибутов, что проще, меньше подвержено ошибкам, и обеспечивает ответ со стороны нижнего уровня обработки (см. примеры gatt_server_service_table).
Через структуру esp_gatts_attr_db_t определяются все параметры таблицы атрибутов:
Таблица 3-7. Структура параметров таблицы атрибутов в ESP32 IDF.
Параметр |
Описание |
uint8_t attr_control |
Определяет некоторые ответы, такие как write_response, которые автоматически выдаются более низким уровнем, или передаются уровню приложения, чтоы пользователи могли отвечать вручную. Рекомендуется применять автоматический режим ответа ESP_GATT_AUTO_RSP. |
uint16_t uuid_length |
Показывает длину UUID, равную 16, 32 или 128 бит. Поскольку UUID атрибута передается через указатели, должна быть указана длина UUID. |
uint8_t *uuid_p |
Предоставляет указатель UUID текущего атрибута. Пользователи могут прочитать значение UUID определенной длины, основываясь на его длине, указанной в параметре uuid_lenght. |
uint16_t perm |
Показывает разрешения на запись и чтение (write / read permissions) текущего атрибута. Этот оператор представлен в виде бит. Каждый бит представляет определенное разрешение записи и чтения. Функционал определенного бита может поменять разрешение на запись и чтение соответствующего атрибута. Например значение PERM_READ | PERM_WRITE означает, что атрибут можно читать и записывать. |
uint16_t max_length |
Показывает максимальную длину значения текущего атрибута. Стек протоколов выделяет память для атрибута, основываясь на этом параметре. Если длина значения атрибута, которое устройство пира должно записать, превышает максимальную длину, определенную в этом параметре, то будет возвращена ошибка записи. Эта ошибка показывает, что операция записи превысила максимальную разрешенную длину данных. |
uint16_t length |
Показывает реальную длину текущего атрибута. Например, в случае максимальной длины атрибута 512 бит, если устройство пира хочет записать 0x1122 в этот атрибут, то текущая длина атрибута будет установлена в 2. Когда устройство пира прочитает этот атрибут, то оно может получить реальную длину этого атрибута, используя только часть буфера с реальными данными, вместо того, чтобы передавать все 512 бит. |
uint8_t *value |
Показывает инициализированные значения текущего атрибута. Поскольку формат этого параметра указатель, реальная длина этого параметра должна быть получена сначала из параметра length, чтобы получить корректную длину данных по этому указателю. |
Обнаружение служб периферийного устройства в ESP32 IDF (GATT Client). Discovering Service может помочь устройстdу Central (клиенту GATT) распознать службы и характеристики BLE-устройства (Peripheral, или GATT Server). Процедура обнаружения служб может отличаться для разных устройств. Здесь показана процедура обнаружения ESP32 IDF вместе с примером, как распознать службу GATT устройства.
• Сначала распознается вся информация о службах устройства, включая UUID службы и дескриптор атрибута.
- GATT Service, UUID 0x1801, дескрипторы 0x0001 .. 0x0005. - GAP Service, UUID 0x1800, дескрипторы 0x0014 .. 0x001C.
• Затем распознаются все характеристики устройства по диапазону дескрипторов GATT service (0x0001 .. 0x0005).
- Ищется "Service Change Characteristic", дескрипторы 0x0002 .. 0x0003. - 0x0002 представляет декларацию характеристики. - 0x0003 представляет значение характеристики. - Таким образом, каждая характеристика имеет атрибуты как минимум двух дескрипторов.
• С учетом того, что дескрипторы GATT Service лежать в диапазоне 0x0001 .. 0x0005, к примеру 0x0003 должен идти за соответствующим описателем. Все описатели тогда должны быть до 0x0004.
- 0x0004 представляет описатель Client Characteristic Configuration. - 0x0005 в настоящий момент не имеет никакой информации, может быть дескриптором, зарезервированным для этой службы.
• В этой точке процедура распознания GATT Service завершена.
[SMP]
API, связанное с SMP, упаковано в модуль ESP32 BLE GAP.
SMP генерирует ключи шифрования и ключи идентификации, определяет удобный протокол для процедуры установки взаимодействия (pairing) и распространения ключей, что позволяет другим слоям в стеке протоколов безопасно соединять устройства друг с другом и обмениваться данными. В этом процессе требуется соединение на слое data link и следование определенным стандартам безопасности. GAP SMP позволяет двум устройствам зашифровать data link layer своего соединения, как это обозначено в главе стандарта Bluetooth Core Specification, посвященной SMP. Перед обсуждением реализации GAP SMP следует прояснить смысл следующих концепций:
• Pairing показывает, что два устройства договорились установить соединение с определенными уровнями безопасности.
• Bonding показывает, что как минимум одно устройство отправило другому устройству некий вид индикации или информацию по безопасности, которая может быть LTK, CSRK или IRK, для организации будущих соединений. Если эти два устройства могут сделать привязку (bond) друг к другу, то во время pairing происходит обмен ключами шифрования, иначе не произойдет обмен информацией привязки (bonding information). Bonding не является обязательным условием для pairing. Однако во время pairing два устройства обмениваются своими характеристиками, чтобы определить, открыто ли устройство для bonding. Если ни одно из устройств в соединяющейся паре не открыто для bonding, то не должна сохраняться никакая информация безопасности.
• Authentication показывает защиту линка. Однако деаутентификация канала не обязательно означает, что канал вообще не защищен. Когда у ключа для шифрования линка есть атрибуты, которые подтверждены обоими устройствами, эти два устройства считают аутентифицированными. Когда для аутентификации используется STK, во время pairing генерируется ключевое слово. Для устройств с вводом/выводом и функциями OOB все генерируемые ключи, которыми произошел обмен, имеют атрибуты MITM (используются PIN / увеличенные ключи OOB, которые принудительно применяют защиту). Если используется Just Works, то все сгенерированные ключи, которыми произошел обмен, имеют атрибуты No MITM.
• Authorization определена как назначение разрешения на выполнение операции слоя приложения. Некоторые приложения могут потребовать авторизации, в таких случаях приложение должно дать разрешение перед использованием операций. Если разрешение не предоставлено, то весь процесс будет неудачным.
[Safety Management Controller]
BLE Encryption. Шифрование в устройстве BLE может быть достигнуто двумя базовыми методами:
• Когда между двумя устройствами BLE не была установлена привязка (no bonding), то эти устройства шифруются через процедуру pairing, в то время как bonding (или not bonding) определяется в соответствии со специфической pairing-информацией этих устройств BLE. • Два bonded-устройства: шифрование инициируется через процедуру bonding. Когда два устройства уже имеют bond-привязку, шифрование инициируется одним из устройств, обращающемуся к оригинальному bonding-процессу.
Способ, по которому master инициирует запрос шифрования в режиме Just Works:
Рис. 3-6. Алгоритм установки шифрования в режиме Just Works.
Способ, по которому master инициирует запрос шифрования в режиме Passkey Notify:
Рис. 3-7. Алгоритм установки шифрования в режиме Passkey Notify.
BLE Bonding. Установка привязки (bonding) между двумя устройствами BLE достигается вызовами GAP API. В соответствии с описанием в Bluetooth Core Specification, назначение bonding состоит в том, чтобы два устройства BLE, которые установили шифрования с помощью SMP, могли использовать одни и те же ключи для шифрования линка, когда они повторно устанавливают соединение, упрощая (и ускоряя) процесс соединения. Эти два устройства BLE обмениваются ключами шифрования во время своего pairing, и сохраняют их в энергонезависимой памяти для долговременного использования. Процесс bonding-а можно увидеть на следующей диаграмме:
Рис. 3-8. Алгоритм процесса BLE bonding.
Примечание: во время соединения процесс bonding-а должен инициироваться устройством master.
Реализация SMP. BLE SMP вызывает API-функции шифрования в BLE GAP, регистрирует BLE GAP callback-и, и получает текущий статус шифрования через значения, возвращенные из событий.
[Ссылки]
1. ESP32 Bluetooth Architecture site:espressif.com. 2. Установка среды разработки ESP-IDF для ESP32. 3. Bluetooth: аббревиатуры и термины. 4. ESP32 Inter-Processor Call. 5. ESP32 GAP API. 6. 16-bit UUID Numbers Document site:bluetooth.com. |