В блоге:

2016-01-15

Об Android и Bluetooth

Программирование работы с Bluetooth для Android - это не особо веселое занятие. Я с этим столкнулся, когда начал развивать свою диагностическую программу SZ Viewer.

Концептуально все выглядит красиво. Bluetooth-устройства бывают разные (гарнитуры, внешние GPS, адаптеры ELM327 и т.д). Их возможности определяются при помощи профилей. Это информация о том, как и какие протоколы поддерживаются для выполнения той или иной задачи.

Например, Bluetooth-адаптеры ELM327 поддерживают профиль SPP (Serial Port Profile - профиль последовательного порта). Это возможность последовательной передачи/приема данных поверх заданного канала RFCOMM.

Теоретически, должен использоваться протокол SDP (Service Discovery Protocol - протокол обнаружения сервиса), который по идентификатору сервиса (вида профиля) должен выдать информацию о способе взаимодействия.

Например, при помощи SDP просим ELM327-адаптер выдать данные о профиле SPP (его идентификатор 00001101-0000-1000-8000-00805F9B34FB) и получаем информацию о том, что используется протокол RFCOMM с конкретным номером канала. Для этого в Android есть метод: createRfcommSocketToServiceRecord(UUID), который должен вернуть сокет для взаимодействия с ELM327-адаптером, далее происходит процесс соединения и работы с потоками.

В первых Android-версиях SZ Viewer (2014 года) был использован именно такой (официальный!) метод Bluetooth-подключения. Но на практике все оказалось весьма печально. Кто использовал ту версию, помнит, какие шаманские пляски были с Bluetooth. Процесс соединения медленный и нестабильный. Это наблюдалось и на моих устройствах. Более того, есть у меня один телефон, где такой способ соединения вообще не работает (выдается исключение с текстом service discovery failed на любые попытки соединения).


Небольшое изучение вопроса показало, что есть обходной, но неофициальный путь. Это использование метода createRfcommSocket(int), который позволяет без использования медленного и ненадежного SDP сразу создавать RFCOMM-соединение с указанным в качестве параметра каналом. Все хорошо, но проблемы две: этот метод отсутствует в официальном API и он требует явного указания канала. Первое решается использованием reflection во время исполнения  (это пока еще работает на всех нынешних версиях Android). А в качестве номера канала по опыту указывается 1.

Способ подключения с прямым использованием RFCOMM реализован в SZ Viewer A1-2015-12-19. В большинстве случаев он работает отлично, гораздо лучше, чем официальный метод через SDP.


Но вдруг возникла ситуация, когда один ELM327-адаптер работал с SZ Viewer версиями 2014 года, но перестал работать с этой версией (не может открыть Bluetooth-соединение) . Сперва я подумал, что проблема в Android 5.x, поэтому в недавней версии A1-2016-01-10 сделал разделение: для Android 5.x и новее используется официальный способ (через SDP), а для более старых - неофициальный (сразу через RFCOMM с указанием канал 1).

Не угадал! Проблема повторилась, но теперь уже под Android 4.4.2. Точно такая же история. Но причина нашлась быстро. Китайский адаптер в обоих случаях одной модели с адресом 00:0D:18:00:00:01:




Более глубокий поиск по интернету сразу навел на причину. В этом адаптере для профиля SPP используется не 1 RFCOMM-канал (как принято указывать), а другой (предположительно канал 16).

Теперь вы понимаете, какой зоопарк приходится поддерживать, чтобы это все работало на разных устройствах с Android от 2.2 до 6.0. Можно, конечно, свалить вопрос выбора способа и параметров соединения на пользователя. Надежный (практически всегда можно вручную настроить соединение), не люблю такие вопрос перекладывать на плечи пользователя. Не должны они заниматься такой ерундой. Буду продолжать искать компромиссные варианты (с автовыбором способа подключения).


Поэтому прошу сообщать мне о случаях, когда стабильность установления Bluetooth-соединения ухудшается при выходе новых версий SZ Viewer. Можно попробовать найти решение.


А еще есть проблема передачи больших пакетов (особенность использования сузуковских протоколов в отличие от стандартного протокола OBD2 с короткими пакетами данных), но это отдельная история. :-)


Еще по этой теме:
Изображения из альбомов:

0 коммент.:

Отправить комментарий

Архив блога