настройка hid для андроид

Работаем с USB Custom HID на Android


В современных Android — приложениях для взаимодействия с другими устройствами чаще всего используются беспроводные протоколы передачи данных, как например Bluetooth. В годы, когда часть устройств имеют беспроводную зарядку, сложно представить себе связку Android устройства и периферийного модуля, в которой необходимо использование проводных интерфейсов. Однако когда такая необходимость возникает, на ум сразу же приходит USB.

Давайте разберем с вами гипотетический кейс. Представьте, что к вам приходит заказчик и говорит: “Мне нужно Android приложение для управления устройством сбора данных и вывода этих самых данных на экран. Есть одно НО — приложение надо написать на одноплатный компьютер с операционной системой Android, а периферийное устройство подключено по USB”

Звучит фантастически, но и такое иногда случается. И тут как нельзя кстати пригодится глубокое знание USB стека и его протоколов, но данная статья не об этом. В данной статье мы рассмотрим, как управлять периферийным устройством по протоколу USB Custom HID с Android устройства. Для простоты напишем Android-приложение (HOST), которое будет управлять светодиодом на периферийным устройством (DEVICE) и получать состояние кнопки (нажатия). Код для периферийной платы приводить не буду, кому интересно — пишите в комментариях.

Итак, приступим.

Теория. Максимально коротко

Для начала немного теории, максимально коротко. Это упрощенный минимум, достаточный для понимания кода, но для большего понимания советую ознакомиться с этим ресурсом.

Для общения по USB на периферийном устройстве необходимо реализовать интерфейс взаимодействия. Разные функции (например, USB HID, USB Mass Strorage или USB CDC) будут реализовывать свои интерфейсы, а некоторые будут иметь несколько интерфейсов. Каждый интерфейс содержит в себе конечные точки — специальные каналы связи, своего рода буферы обмена.

На моем периферийном устройстве реализован Custom HID с одним интерфейсом и с двумя конечными точками, одной для приёма, другой для передачи. Обычно информация с существующими на устройстве интерфейсами и конечными точками написана в спецификации на устройство, в противном случае определить их можно через специальные программы, к примеру USBlyzer.

Устройства в USB HID общаются через репорты. Что такое репорты? Так как данные передаются через конечные точки, то нам надо как-то идентифицировать, а также распарсить в соответствие с протоколом. Устройства не просто кидают друг другу байты данных, а обмениваются пакетами, имеющими четко определенную структуру, которая описывается на устройстве в специальном дескрипторе репорта. Таким образом, по дескриптору репорта, мы можем точно определить, какой идентификатор, структуру, размер и частоту передачи имеют те или иные данные. Идентификация пакета происходит по первому байту, который представляет из себя ID репорта. Например данные о состоянии кнопки, идут в репорта с а светодиодом мы управляем через репорт с >

Подальше от железа, поближе к Android

В Android поддержка USB устройств появилась начиная с API версии 12 (Android 3.1) Для работы с периферийным устройством нам необходимо реализовать режим USB host. Работа с USB достаточно неплохо описана в документации.

Для начала необходимо идентифицировать ваше подключаемое устройство, среди всего разнообразия USB девайсов. USB девайсы идентифицируются по сочетанию vid (vendor id) и pid (product id). Создадим в папке xml файл device_filter.xml со следующим содержимым:

Теперь необходимо внести соответствующие разрешения и action (если вам они необходимы) в манифест приложения:

В android:resource мы указываем файл с необходимыми фильтрами для устройств. Также, как я уже говорил ранее, можно назначить intent фильтры, для запуска приложения, к примеру, в результате подключения вашего устройства.

Для начала необходимо получить UsbManager, найти устройство, интерфейс и конечные точки устройства. Это необходимо делать при каждом подключении устройства.

Здесь мы видим те самые интерфейсы и конечные точки, речь о которых шла в прошлом разделе. Зная номер интерфейса, мы находим обе конечные точки, на прием и передачу, и инициируем usb соединение. На этом все, теперь можно читать данные.

Как я уже говорил ранее, устройства общаются через репорты.

В метод sendReport мы передаем массив байт, в котором нулевым байтом является репорт ID, берем текущее USB подключение к устройству и выполняем передачу. В качестве параметров в метод BulkTransfer передаем номер конечной точки, данные, их размер и таймаут передачи. Стоит отметить, что класс UsbDeviceConnection имеет методы для реализации обмена данными с устройством USB — методы bulkTransfer и controlTransfer. Их использование зависит от типа передачи, который поддерживает та или иная конечная точка. В данном случае используем bulkTransfer, хотя для HID чаще всего характерно использование конечных точек с типом control. Но у нас Custom HID, так что делаем что хотим. Про тип передачи советую почитать отдельно, так как от него зависит объем и частота передаваемых данных.

Читайте также:  explay tv280 сброс до заводских настроек

Для получения данных необходимо знать размер получаемых данных, который можно, как знать заранее, так и получить из конечной точки.

Метод получения данных по USB HID является синхронным и блокирующим и выполнять его необходимо в другом потоке, кроме того, репорты от устройства могут приходить постоянно, либо в любое время, поэтому необходимо реализовать постоянный опрос репорта, чтобы не пропустить данные. Сделаем это при помощи RxJava:

Получив массив байт, мы должны проверить нулевой байт, так как он является report ID и в соответствии с ним парсить полученные данные.

По завершении всех действий с USB нужно закрыть соединение. Можно выполнять это в onDestroy activity или в onCleared во ViewModel.

Заключение

В статье рассмотрен очень небольшой и примитивный, исключительно демонстративный код с реализацией для конкретного устройства. Конечно, классов USB существует много, не только HID и для них естественно реализация будет иная. Однако все методы достаточно неплохо документированы и имея хорошее представление о USB стеке можно легко разобраться в том, как их применять.

источник

Доступ к HID-устройствам из программы на Qt под Android

Введение

Первые трудности

С самого начала для общения с устройством используется библиотека HIDAPI. Она мультиплатформенная и ее легко использовать.
Первая трудность, с которой пришлось столкнуться заключалась в том что под Android нет hidraw, который использовался для доступа к устройствам под десктопный Linux. Для обхода пришлось перейти на использование библиотеки libusb и ее интерфейса к ней в HIDAPI.
Первый запуск показал, что работает перечисление устройств, но открыть файл устройства нельзя, из-за отсутствия прав у приложения.
В файл README libusb/android есть описание возможных путей обхода этой проблемы: либо менять права у файла устройств, либо воспользоваться интерфейсом android.hardware.usb.UsbDevice, для открытия устройств.

Простая смена маски доступа к файлу на 777 на рутованом устройстве подтвердила работоспособность выбранной схемы, но и привела к пониманию того, что это не совсем верный путь, т.к. он работоспособен на очень маленьком круге устройств. Поэтому пришлось лезть в дебри API Android.

Чтение документации показало что есть два пути доступа к устройству: использование intent filter и простое перечисление устройств.
Первый способ заставить работать не удалось, никаких событий при появлении устройства в системе программе не приходило. Собственно этот путь тоже тупиковый, т.к. подразумевает, что программа должна быть запущена раньше, чем подключено устройство, и это значит что нам следует в полной мере воспользоваться предоставляемым API для доступа к USB.

Что бы обойтись минимумом переделок в существующем коде было решено вынести в Java-часть только код связанный с запросом разрешения доступа к устройству у пользователя и собственно открытие устройства. Всю остальную работу по перечислению устройств и обмена данными выполняет связка HIDAPI-libusb.

Реализация.

Первое, что пришлось сделать, это запрос разрешения у пользователя на открытие устройства.
Опять же, подстраиваясь под существующий алгоритм получилось следующее: при нахождении устройства, путь к его файлу передается в функцию в класса Activity программы посредством JNI-интерфейса:

Здесь хочется сделать некоторое отступление: в силу каких-то причин Qt интерфейс к JNI может вызывать только статические методы класса. Поэтому мы создаем фактически сингелтон. Ниже приведены конструктор и onCreate класса Activity:

Функция tryOpenDevice, вызываемая из нативного кода выглядит следующим образом:

deviceCache выполняет роль промежуточного хранилища состояния процесса открытия устройства. Такой вариант был выбран потому, что алгоритм нативного кода пытается с некоторой периодичностью открыть каждое найденное, но еще не открытое устройство.

Далее в работу вступает механизм разрешений Android и для получения результатов служит эта функция:

Как из нее видно, если разрешение получено, то вызывается функция открытия устройства:

Которая сохраняет полученный файловый дескриптор в deviceCache.

После прохождения всех этих этапов мы получаем файловый дескриптор открытого устройства. Но тут появляется другая проблема: HIDAPI и libusb не умеют принимать дескрипторы в качестве указателя на устройство.

Читайте также:  где находится панель настроек в яндексе

К счастью, эта проблема решилась просто. Существует форк libusb, принимающий в качестве аргумента файловый дескриптор открытого устройства.

Заключение

Вот так, достаточно просто, можно получить доступ к USB из нативного кода.

К сожалению, данный подход работает не на всех устройствах. Многие производители не включают разрешение
android.hardware.usb.host в свои прошивки, что приводит к ситуации, когда физически планшет может работать в качестве хоста для флешек или мышей, но другие устройства не работают. При этом файл USB-устройства ядром создается, но даже UsbManager их не видит.

В данном случае, это ограничение возможно обойти на устройствах с работоспособным root, меняя права доступа на файл, т.к. libusb способен видеть подключенные устройства. Но пока что это только теория.

источник

Обучаем HID устройство (читай BT-клавиатуру) работать правильно

Приветствую, хабралюди!
На ДР, мне друзья подарили BT-клавиатуру. Маленькая, беленькая, симпатичная, Удобная!
Подключил ее к своему Android 2.3.5 (SGSII), стал с ее помощью лазить по меню, запускать программы, дошел до Вконтакте и решил написать сообщение… а вот переключить на русский язык не смог, но как оказалось позже, это еще были только цветочки! Но кое-что мне удалось. Интересно как?

Сейчас я уже многое понял, и не знаю с чего начать свой рассказ. Поэтому будет долго и скучно, но игра стоит свеч!

Имеем:
Первые шаги

Начал я с того, что написал письмо в техподдержку клавиатуры, с вопросом: а не могли бы вы посодействовать с настройкой клавиатуры для Андроида? Получил, как и ожидалось, ласковый отказ: «Эта клавиатура сделана специально для iPad».

Пока ждал от них ответа, стал «прогугливать» тему взаимодействия HID устройств и Android. И среди массы хлама нашел две полезнейшие статьи:

  • Про устройства ввода
  • и Про файлы конфигурации этих устройств

Изучение этих статей дало понимание, что для правильной работы устройства, нужно отредактировать как минимум .kl-файл, содержащий назначения клавиш.

Кому лень было читать статьи, кратко поясню:
На Вашем Android устройстве есть папка (кстати зависит от устройства, подробности есть в статье выше)
/system/usr
где расположены нужные нам каталоги
keylayout и keychars
в них размещаются файлы типа имя_клавиатуры.kl и имя_клавиатуры.kcm.bin соответственно.

Первый (обычный текстовый) отвечает за соответствие сигналов клавиатуры (Linux key code) сигналам Android (Android key code name) и выглядит как список из таких команд:

key 30 A WAKE
Расшифровка: key [scancode] [Android key] [Flags]
По-русски: если на клавиатуре нажали кнопку с кодом 30, то системе будет послана клавиша А, при этом устройство проснется.

Флаг WAKE заставляет устройство проснуться и отреагировать на нажатие буквой А.
А флаг WAKE_DROPPED заставляет только проснуться, т.е. чтобы нажать А, надо будет нажать ее снова.
В статье есть описание и других флагов.

Второй (скомпилированный из исходника бинарник) отвечает за комбинации клавиш вместе с Shift, Alt и т.п. Здесь уже идет таблица из разных вариантов, описывающих действия над Android key. В исходном виде он выглядит как:

key A <
label: ‘A’
base: ‘a’
shift, capslock: ‘A’
ctrl, alt, meta: none
>

А скомпилирован он для ускорения работы и загрузки устройства.

Решаем что делать

Я написал в техподдержку клавиатуры снова, описав свои наблюдения. Но поддержки от них никакой не добился. Им это не интересно. Придется все делать самому.

Что, опять нужен root?

Для доступа в папку /system нужны права root. Значит нужно его получить и не потерять гарантию. Я долго искал способ и для себя один нашел. Ничего не нужно прошивать. Все можно вернуть назад. ИСПОЛЬЗУЙТЕ НА СВОЙ СТРАХ И РИСК! ВСЕ ТОЛЬКО ДЛЯ ОЗНАКОМЛЕНИЯ! НИКАКОЙ ОТВЕТСТВЕННОСТИ! Но для меня все сработало как надо.

Готовим файл

Чтобы туда что-то положить, нужно подготовить наш файл имя_клавиатуры.kl. И начать стоит с того, чтобы скачать исходный образец. В папку /system/usr/keylayout/ можно попасть и без root, скопировав оттуда нужный нам файл при помощи файлового менеджера. Я воспользовался ASTRO. Но можно воспользоваться консольным приложением adb.exe, поставляемом с Samsung KIES.
Команда adb pull remote local — copy file/dir from device

Первые грабли:
Определить имя нужного файла может быть затруднительно. Общий принцип названия файлов, согласно статье — Vendor_XXXX_Product_XXXX_Version_XXXX.kl или DEVICE_NAME.kl

Ну вот, нашли файл, скачали, сделали копию, открыли текстовым редактором типа notepad.
У меня файл назывался Broadcom_Bluetooth_HID.kl

Читайте также:  эксплей вега сброс до заводских настроек
Тааааак, и что тут у нас?

Все понятно, какие-то коды, какие-то кнопки, что к чему не особо понятно, но мы уже готовы к этому, потому что внимательно читали эту статью с начала и до сюда. А как же определить коды клавиш?

Вторые грабли:
Чтобы определить коды клавиш понадобится средство отладки или.

Просто заходим на маркет и находим то что нужно, не с первой попытки конечно. Я перепробовал 3-4 программы. Не все могли похвастаться нужной функцией — многие отображали только Android коды, которые уже прописаны в нашем файле. А нам нужны scancod’ы!

Получаем scancod’ы

Я «отксерил» свою клавиатуру на копире и ручкой стал подписывать коды, которые мне давала программа KeyEvent Display. Так я получил набор кодов, осталось переписать их в файл и назначить им правильные функции.

Редактируем файл

Открываем первую статью по клавиатурам и методично назначаем новые значения нашим кнопкам.
Получается что-то вроде этого:

Третьи грабли:
Не все кнопки будут работать с Вашей версией Android OS! Обратите внимание на колонку Version в первой статье про клавиатуры. Если вы используете те коду, которые предназначены для версий больше вашей, тогда с этого места клавиатура не будет работать.

Все кнопки, указанные после неправильной не будут функционировать.

Поэтому, для будущей совместимости, я в своем файле, клавиши предназначенные не для моей версии Android OS, перенес в конец. Как показала практика, в этом случае все работает и файл готов к переносу на другие версии ОС.

Закидываем файл в систему

Здесь не обойтись без консольной утилиты. Подключаем девайс по USB в режиме отладки и выполняем последовательно команды в консоли cmd.exe:

Четвертые грабли:
Папка /system находится на файловой системе в режиме только для чтения. Для того, чтобы туда писать, нужно перемонтировать систему в режиме RW. Но для этого, нужно определить точку монтирования и тип файловой системы при помощи простой команды mount.

После перезагрузки устройства, файловая система снова станет «только для чтения».

Пояснения к командам:

D:\android-sdks\platform-tools — это папка, в которой у меня находится adb.exe из SDK (у кого установлен только KIES — ищите в Program Files)
adb push Broadcom_Bluetooth_HID.kl. — это команда закачивает файл в папку. Папка /data/local/ выбрана не случайно. Это одна из немногих папок, в которую можно что-то положить, и из которой можно скопировать файл в другую файловую систему.
mount -o remount,rw -t ext4 /dev/block/mmcblk0p9 /system — перемонтирование системы. В интернете полно примеров как это делать, но там почему-то указаны совсем не те диски и файловая система. Пришлось подкорректировать.
остальное — удаление старого, копирование нашего файла и назначение ему правильных прав. Назначение прав очень важно!

Проверяем

Теперь нужно отсоединить USB (из-за него иногда выключается Bluetooth) и перезапустить соединение с клавиатурой:

  • Если клавиатура не хочет подсоединяться — значит вы забыли установить права, неправильно заполнили файл или положили файл не в ту папку (повторюсь, у каждого устройства они разнятся, читайте первую статью). В общем что-то с файлом.
  • Если клавиатура подключилась, но половина клавиш не работает, значит с того места, где она не работает, вы вставили неподдерживаемый вашей версией код. Переместите его в конец файла.
Заработало!

Поздравляю! По-другому и быть не могло! Вы молодец! Только… как же на русский-то перейти?
Не долго гугля, я нашел простой ответ — нужна софтварная клавиатура, поддерживающая аппаратную. Таких немного. Идеальная, на мой взглад, на сегодня — ruKeybord
Устанавливаем, настраиваем, в раскладках устанавливаем аппаратную клавиатуру вместо qwerty и т.п.
Теперь можно переключать раскладку через Alt+Shift (UPD: или Shift+Space). И флажок показывается.

Кто еще не в курсе, чтобы быстро переключаться между клавиатурами, подержите палец на любом поле ввода и выберите из выпавшего меню «Режим ввода».

Итоги

Как ни старался, но заставить заработать все кнопки, подобно компьютеру, на 2.3.5 невозможно. Но скоро я обновлюсь до Android OS 4 и новые кнопки заработают. На первой фотографии я сижу в putty и редактирую сайт. Очень не хватает кнопки Ctrl. Очень жду обновления ОС. Доволен результатом.

источник

Добавить комментарий

Adblock
detector