Что нужно сделать перед подключением устройства на базе android к программе addappter
Могу точно сказать – это было сложней, чем представлял, мне пришлось приложить немало усилий для стабильной работы под Android. Я изучил много статей в свободном доступе, некоторые оказались ошибочными, многие были очень полезными и помогли в деле. В этой серии статей я хочу описать свои выводы, чтобы вы не тратили уйму времени на поиски как я.
Особенности работы BLE под Android
Google документация по BLE очень общая, в некоторых случаях нет важной информации или она устарела, примеры приложений не показывают, как правильно использовать BLE. Я обнаружил лишь несколько источников, как правильно сделать BLE. Презентация Stuart Kent дает замечательный материал для старта. Для некоторых продвинутых тем есть хорошая статья Nordic.
Android BLE API это низкоуровневые операции, в реальных приложениях нужно использовать несколько слоев абстракции (как например сделано «из коробки» в iOS-CoreBluetooth). Обычно нужно самостоятельно сделать: очередь команд, bonding, обслуживание соединений, обработка ошибок и багов, мультипоточный доступ . Самые известные библиотеки: SweetBlue, RxAndroidBle и Nordic. На мой взгляд самая легкая для изучения - Nordic, см. детали тут.
Производители делают изменения в Android BLE стеке или полностью заменяют на свою реализацию. И надо учитывать разницу поведения для разных устройств в приложении. То что прекрасно работает на одном телефоне, может не работать на других! В целом не все так плохо, например реализация Samsung сделана лучше собственной реализации от Google!
В Android есть несколько известных (и неизвестных) багов которые должны быть обработаны, особенно в версиях 4,5 и 6. Более поздние версии работают намного лучше, но тоже имеют определенные проблемы, такие как случайные сбои соединения с ошибкой 133. Подробнее об этом ниже.
Не претендую на то, что я решил все проблемы, но мне удалось выйти на «приемлемый» уровень. Начнем со сканирования.
Сканирование устройств
Перед подключением к устройству вам нужно его просканировать. Это делается при помощи класса BluetoothLeScanner :
Сканер пытается найти устройства в соответствии с настройками filters и scanSettings , при обнаружении устройства вызывается scanCallback :
В результате сканирования мы получаем экземпляр ScanResult , в котором есть объект BluetoothDevice , его используют для подключения к устройству. Но прежде чем начать подключаться, поговорим о сканировании подробнее, ScanResult содержит несколько полезных сведений об устройстве:
Advertisement data - массив байтов с информацией об устройстве, для большинства устройств это имя и UUID сервисов, можно задать в filters имя устройства и UUID сервисов для поиска конкретных устройств.
RSSI уровень - уровень сигнала (насколько близко устройство).
… дополнительные данные, см. документацию по ScanResult здесь.
Помним про жизненный цикл Activity , onScanResult может вызываться многократно для одних и тех же устройств, при пересоздании Activity сканирование может запускаться повторно, вызываю лавину вызовов onScanResult .
Настраиваем фильтр для сканирования
Вообще можно передать null вместо фильтров и получить все ближайшие устройства, иногда это полезно, но чаще требуются устройства с определенным именем или набором UUID сервисов.
Сканирование устройств по UUID сервиса
Используется если вам необходимо найти устройства определенной категории, например мониторы артериального давления со стандартным сервисным UUID: 1810. При сканировании устройство может содержать в Advertisement data UUID сервис, который характеризует это устройство. На самом деле эти данные ненадежные, фактически сервисы могут не поддерживаться, или подделываться Advertisement data данные, в общем тут есть творческий момент.
Прим. переводчика: одно из моих устройств со специфичной прошивкой, вообще не содержало список UUID сервисов в Advertisement data, хотя все остальные прошивки этого устройства работали ожидаемо.
Пример сканирования службы с артериальным давлением:
Сканирование устройств по имени
Поиск устройств использует точное совпадение имени устройства, обычно это применяется в двух случаях:
поиск конкретного устройства
поиск конкретной модели устройства, например, мой нагрудный напульсник Polar H7 определяется как «Polar H7 391BBB014», первая часть - «Polar H7» общая для всех таких устройств этой модели, а последняя часть «391BBB014» - уникальный серийный номер. Это очень распространенная практика. Если вы хотите найти все устройства «Polar H7», то фильтр по имени вам не поможет, придется искать подстроку у всех отсканированных устройств в ScanResult . Пример с поиском точно по имени:
Сканирование устройств по MAC-адресам.
Обычно применяется для переподключения к уже известным устройствам. Обычно мы не знаем MAC-адрес девайса, если не сканировали его раньше, иногда адрес печатается на коробке или на корпусе самого устройства, особенно это касается медицинских приборов. Существует другой способ повторного подключения, но в некоторых случаях придется еще раз сканировать устройство, например при очистке кеша Bluetooth.
Вероятно вы уже поняли, что можно комбинировать в фильтре UUID, имя и MAC-адрес устройства. Выглядит неплохо, но на практике я не применял такое. Хотя может быть вам это пригодится.
Настройка ScanSettings
ScanSettings объясняют Android как сканировать устройства. Там есть ряд настроек, которые можно задать, ниже полный пример:
ScanMode
Безусловно, это самый важный параметр. Определяет метод и время сканирования в Bluetooth стеке. Такая операция требует много энергии и необходим контроль над этим процессом, чтобы не разрядить батарею телефона быстро. Есть 4 режима работы, в соответствии с руководством Nordics и официальной документацией:
SCAN_MODE_LOW_POWER . В этом режиме Android сканирует 0.5с, потом делает паузу на 4.5с. Поиск может занять относительно длительное время, зависит от того насколько часто устройство посылает пакет advertisement данных.
SCAN_MODE_BALANCED . Время сканирования: 2с, время паузы: 3с, «компромиссный» режим работы.
SCAN_MODE_LOW_LATENCY . В этом случае, Android сканирует непрерывно, что очевидно требует больше энергозатрат, при этом получаются лучшие результаты сканирования. Режим подходит если вы хотите найти свое устройство как можно быстрее. Не стоит использовать для длительного сканирования.
SCAN_MODE_OPPORTUNISTIC . Результаты будут получены, если сканирование выполняется другими приложениями! Строго говоря, это вообще не гарантирует, что обнаружится ваше устройство. Стек Android использует этот режим в случае долгого сканирования, для понижения качества результатов (см. ниже «Непрерывное сканирование»).
Callback Type
Эта настройка контролирует как будет вызываться callback со ScanResult в соответствии с заданными фильтрами, есть 3 варианта:
CALLBACK_TYPE_ALL_MATCHES . Callback будет вызывать каждый раз, при получении advertisement пакета от устройств. На практике - каждые 200-500мс будет срабатывать сallback, в зависимости от частоты отправки advertisement пакетов устройствами.
CALLBACK_TYPE_FIRST_MATCH . Callback сработает один раз для устройства, даже если оно далее будет снова посылать advertisement пакеты.
CALLBACK_TYPE_MATCH_LOST . Callback будет вызван, если получен первый advertisement пакет от устройства и дальнейшие advertisement пакеты не обнаружены. Немного странное поведение.
В практике обычно используются настройка CALLBACK_TYPE_ALL_MATCHES или CALLBACK_TYPE_FIRST_MATCH . Правильный тип зависит от конкретного случая. Если не знаете - используйте CALLBACK_TYPE_ALL_MATCHES , это дает больше контроля при получении callback, если вы останавливаете сканирование после получения нужных результатов - фактически это CALLBACK_TYPE_FIRST_MATCH .
Match mode
Настройка того, как Android определяет «совпадения».
MATCH_MODE_AGGRESSIVE . Агрессивность обуславливается поиском минимального количества advertisement пакетов и устройств даже со слабым сигналом.
MATCH_MODE_STICKY . В противоположность, этот режим требует большего количества advertisement пакетов и хорошего уровня сигнала от устройств.
Я не тестировал эти настройки подробно, но я в основном использую MATCH_MODE_AGGRESSIVE , это помогает быстрее найти устройства.
Number of matches
Параметр определяет сколько advertisement данных необходимо для совпадения.
MATCH_NUM_ONE_ADVERTISEMENT . Одного пакета достаточно.
MATCH_NUM_FEW_ADVERTISEMENT . Несколько пакетов нужно для соответствия.
MATCH_NUM_MAX_ADVERTISEMENT . Максимальное количество advertisement данных, которые устройство может обработать за один временной кадр.
Нет большой необходимости в таком низкоуровневом контроле. Все что вам надо - быстро найти свое устройство, обычно используются первые 2 варианта.
Report delay
Задержка для вызова сallback в миллисекундах. Если она больше нуля, Android будет собирать результаты в течение этого времени и вышлет их сразу все в обработчике onBatchScanResults . Важно понимать что onScanResult не будет вызываться. Обычно применяется, когда есть несколько устройств одного типа и мы хотим дать пользователю выбрать одно из них. Единственная проблема здесь - предоставить информацию пользователю для выбора, это должен быть не только MAC-адрес (например имя устройства).
Важно: есть известный баг для Samsung S6 / Samsung S6 Edge, когда все результаты сканирования имеют один и тот же RSSI (уровень сигнала) при задержке больше нуля.
Кеширование Android Bluetooth стека
В результате процесса сканирования вы получаете список BLE устройств и при этом данные устройств «кешируются» в Bluetooth стеке. Там хранится основная информация: имя, MAC-адрес, тип адреса (публичный, случайный), тип устройства (Classic, Dual, BLE) и т.д. Android нужны эти данные, чтобы подключится к устройству быстрее. Он кеширует все устройства, которые видит при сканировании. Для каждого из них записывается небольшой файл с данными. Когда вы пытаетесь подключиться к устройству, стек Android ищет соответствующий файл, чтобы прочитать данные для подключения. Важный момент - одного MAC-адреса недостаточно для успешного подключения к устройству!
Очистка кеша
Bluetooth кеш, как и любой другой, не существует вечно, есть 3 ситуации, когда он очищается:
Выключение и включение системного переключателя Bluetooth
Очистка данных приложения (в ручном режиме в настройках телефона)
Это достаточно неудобный момент для разработчиков, потому что телефон часто перезагружается, пользователь может включать-выключать самолетный режим. Есть еще различия между производителями телефонов, например на некоторых телефонах Samsung, кеш не очищался при выключении Bluetooth.
Это значит, что нельзя полагаться на данные об устройстве из BT кеша. Есть небольшой трюк, он поможет узнать закешировано ли устройство или нет:
Это важный момент, если нужно подключиться к устройству позже, не сканируя его. Подробнее об этом позже.
Непрерывное сканирование?
Вообще хорошая практика – избегать непрерывного сканирования потому что, это очень энергоемкая операция, а пользователи любят, когда батарея их смартфона работает долго. Если вам действительно нужно постоянное сканирование, например при поиске BLE-маячков, выберите настройки сканирования с низким потреблением и ограничивайте время сканирования, например когда приложение находится только на переднем плане (foreground), либо сканируйте с перерывами.
Плохая новость в том, что Google в последнее время ограничивает (неофициально) непрерывное сканирование:
c Android 8.1 сканирование без фильтров блокируется при выключенном экране. Если у вас нет никаких ScanFilters , Android приостановит сканирование, когда экран выключен и продолжит, когда экран снова будет включен. Комментарии от Google. Это очевидно очередной способ энергосбережения от Google.
c Android 7 вы можете сканировать только в течение 30 минут, после чего Android меняет параметры на SCAN_MODE_OPPORTUNISTIC . Очевидное решение, перезапускать сканирование с периодом менее, чем 30 мин. Посмотрите commit в исходном коде.
с Android 7 запуск и останов сканирования более 5 раз за 30 секунд временно отключает сканирование.
Непрерывное сканирование в фоне
Google значительно усложнил сканирование на переднем плане. Для фонового режима вы столкнетесь с еще большими трудностями! Новые версии Android имеют лимиты на работу служб в фоновом режиме, обычно после 10 минут работы, фоновый сервис прекращает свою работу принудительно. Посмотрите возможные решения этой проблемы:
Проверка разрешений (permissions)
Есть еще несколько важных моментов, прежде чем мы закончим статью. Для начала сканирования нужны системные разрешения (permissions):
Убедитесь, что все разрешения одобрены, или запросите их у пользователя. Разрешение ACCESS_COARSE_LOCATION Google считает «опасным» и для него требуется обязательное согласие пользователя.
Прим. переводчика, в моем проекте для корректной работы с BLE потребовалось еще 2 разрешения: ACCESS_FINE_LOCATION (для API <23) и ACCESS_BACKGROUND_LOCATION обсуждение на Stackoverflow.
В итоге полный список разрешений включая версию Android10:
После получения всех нужный разрешений, нужно проверить включен Bluetooth, если нет - используйте Intent для запуска запроса на включение:
Заключение
Мы научились запускать сканирование BLE устройств с учетом жизненного цикла Activity (Fragment / Service), использовать фильтры и различные настройки сканирования, также узнали все нужные разрешения (permissions) для удачного запуска сканирования и особенности работы Android-Bluetooth кеша. В следующей статье мы погрузимся глубже в процесс подключения и отключения к устройствам.
Сегодня в комментариях мне задали очень интересный вопрос. Можно ли в качестве Wi-Fi адаптера для компьютера использовать телефон на Android. Чтобы телефон, или планшет был подключен к Wi-Fi сети, и в режиме модема по USB кабелю передавал интернет на стационарный компьютер. У которого нет Wi-Fi адаптера и соответственно нет возможности напрямую подключатся к беспроводным сетям. И как оказалось – можно.
У меня почему-то никогда не было такой необходимости, и я не интересовался этим вопросом. Еще вроде со второй версии, на Android появился режим модема. И практически все телефоны и планшеты могут раздавать интернет на другие устройства по Wi-Fi, Bluetooth и по USB кабелю. Но как оказалось, Android устройства могут делится не только мобильным интернетом (EDGE, 3G, 4G) , но и Wi-Fi. А это значит, что с телефона можно сделать полноценный Wi-Fi адаптер для ПК.
Это очень полезная функция. Не редко бывает ситуация, когда после установки роутера, или покупки ПК нет возможности протянуть сетевой кабель к компьютеру. А с помощью этой функции можно подключить его к интернету. Пускай временно, пока вы не купите обычный Wi-Fi адаптер (что это такое я писал здесь, а о том как выбрать адаптер, можете почитать тут).
Я все настроил и проверил на телефоне Samsung Galaxy J5. Нашел только такой. Понимаю, что на других телефонах и планшетах, с другой версией Android и оболочкой, настройки могут немного отличатся. Но, думаю, не критично. Разберетесь. Или спросите в комментариях, если не сможете найти настройки.
Хочу еще добавить, что подключение к Wi-Fi сети через телефон работает очень стабильно и быстро. Интернет на компьютере "летает". В телефонах устанавливают хорошие беспроводные модули (не на всех, конечно) .
Подключаем компьютер к Wi-Fi сети через Android-устройство в роли адаптера
Сначала советую отключить мобильный интернет на своем телефоне. Просто отключите передачу данных через сотовую сеть. Это на всякий случай. Чтобы точно знать, что используется подключение по Wi-Fi.
Конечно же, ваш телефон должен быть подключен к Wi-Fi сети.
С помощью USB кабеля подключаем телефон к компьютеру. Он будет работать не только как адаптер, но еще и будет заражаться.
На телефоне заходим в настройки, в раздел "Подключения", дальше переходим в "Точка доступа и модем" и включаем "USB-модем" (общий доступ к интернет-подключению на этом телефоне) .
На компьютере сразу появится доступ к интернету через телефон.
Появится просто еще один сетевой адаптер. У меня Ethernet 4 (Remote NDIS based Internet Sharing Device) . У вас может быть другой. Это не важно.
Чтобы перестать использовать свой смартфон в качестве Wi-Fi приемника, просто отключите функцию "USB-модем" в настройках, или отключите телефон от компьютера.
Точно так же можно использовать и планшет на Android.
Надеюсь, эта статья вам пригодилась. Обязательно оставляйте в комментариях свои отзывы.
Если вы зашли на эту страницу, то скорее всего у вас уже есть MiraScreen или AnyCast адаптер (возможно, у вас он называется как-то иначе) и вы хотите через него подключить к телевизору свой телефон или планшет на Android, iPhone, iPad, или компьютер для трансляции изображения на телевизор без проводов. Если вы вообще не понимаете о чем идет речь, то рекомендую сначала почитать статью Miracast, AirPlay, DLNA адаптер для телевизора. Что такое MiraScreen и AnyCast? Подключив любой Miracast адаптер к телевизору по HDMI и выполнив несложную настройку самого адаптера (можно обойтись и без нее) у нас появится возможность дублировать экран своих мобильных устройств и даже компьютера на большой экран телевизора по Wi-Fi. Используется технология Miracast (для подключения устройств на Android и Windows) или AirPlay (для iPhone, iPad, MacBook, iMac) .
Подключение MiraScreen/AnyCast адаптера к телевизору
Если вы еще не подключили свой Miracast адаптер к телевизору, то сейчас я быстренько покажу как это сделать и перейдем к подключению устройств. Адаптер подключается в один из HDMI портов на телевизоре. Питание адаптера можно подключить в USB-порт телевизора (если он есть) , или в розетку через любой адаптер питания (желательно 5V/1A) .
Включите телевизор (если он был выключен) . Если на экране телевизора автоматически не появится заставка адаптера, то нужно в настройках телевизора в качестве источника выбрать HDMI вход к которому подключен Miracast адаптер (каждый HDMI порт на телевизоре имеет свой номер) . Обычно это можно сделать через отдельное меню, которое открывается кнопкой SOURCES или INPUT с пульта дистанционного управления телевизором.
На экране телевизора должен появится рабочий стол (если его можно так назвать) нашего адаптера. У меня MiraScreen MX Wireless Display.
Дальше желательно настроить MiraScreen адаптер. Основная настройка – подключение к роутеру по Wi-Fi сети. Это необходимо для работы соединения по DLNA и вывода изображения на телевизор с iPhone, iPad и компьютеров на Mac OS (трансляция по AirPlay) . Вот подробная инструкция по настройке: 192.168.203.1 – настройка Miracast адаптера. Что делать, если не заходит в настройки MiraScreen и AnyCast? Windows и устройства на Android соединяются с адаптером напрямую, не через роутер.
Практически все эти адаптеры имеют два режима работы:
- AirPlay и DLNA (нарисован значок DLNA и логотип Apple) .
- Miracast (логотип Android и Windows) .
Выбранный режим работы выделен на рабочем столе.
Переключаются эти режимы нажатием на единственную кнопку на самом адаптере.
Или через панель управления (ссылка на инструкцию выше) , но кнопкой удобнее. Нажали один раз на кнопку и режим работы изменился. Выбираем нужный режим в зависимости от того, с какого устройства мы хотим транслировать изображение.
Повтор экрана iPhone и iPad на телевизор через MiraScreen адаптер
Мобильные устройства и компьютеры от Apple не поддерживают Miracast. У них своя технология – AirPlay. На данный момент в телевизорах нет встроенной технологии AirPlay (читал, что возможно в новых телевизорах некоторых производителей она появится) . Но китайцы каким-то образом умудрились реализовать поддержку AirPlay в этих MiraScreen и им подобных адаптерах.
Значит наш адаптер подключен, включен и настроен. Он должен быть подключен к той же Wi-Fi сети, что и наш iPhone, или другое устройство, с которого мы будем делать повтор экрана. Если адаптер не подключен к роутеру, или роутера нет, то нужно наше iOS или Mac OS устройство подключить напрямую к Wi-Fi сети самого адаптера. Имя сети (SSID) и пароль (PSK) указаны на экране телевизора (см. фото ниже) .
Адаптер должен быть переключен в режим AirPlay (где иконка Apple) . Как это все подключить, настроить и переключить режим я показывал выше.
На Айфоне или Айпаде открываем центр управления и выбираем "Повтор экрана". Если все подключили правильно, то в списке доступных устройств должна отображаться наша MiraScreen приставка. Просто выбираем ее.
Через несколько секунд экран iPhone или iPad будет дублироваться на экран телевизора.
В горизонтальном режиме тоже все работает.
Чтобы остановить трансляцию, достаточно в меню "Повтор экрана" нажать на "Остановить повтор".
Трансляция экрана с MacBook и других компьютеров на Mac OS через AirPlay
Я все проверил на MacBook Air. В этом случае точно так же необходимо, чтобы компьютер был подключен к той же Wi-Fi сети, что и MiraScreen приемник. Или подключить ноутбук непосредственно к Wi-Fi сети самого адаптера.
Когда Mac OS увидит, что есть возможность подключения к беспроводному дисплею по AirPlay – в статус баре появится соответствующий значок. Нажав на который, нам нужно только выбрать MiraScreen адаптер.
Изображение с MacBook появится на экране телевизора.
По умолчанию на телевизор выводится отдельный дисплей. Но нажав на иконку "AirPlay" можно изменить режим трансляции экрана на беспроводной дисплей. Есть возможность дублировать как отдельный дисплей, так и дисплей AirPlay, или встроенный. Там же можно отключить дублирование экрана.
Думаю, вы найдете для себя подходящий режим.
С iPhone, MacBook и других устройств через эти MiraScreen/AnyCast адаптеры передается не только изображение на телевизор (который в нашем случае выступает в роли беспроводного дисплея) , но и звук.
Как подключить Android через MiraScreen/AnyCast (Miracast) к телевизору?
MiraScreen/AnyCast адаптер для подключения к телевизору устройств на Android нужен только в том случае, когда в вашем телевизоре нет встроенной поддержки Miracast. Поддержка этой технологии есть практически во всех современных телевизорах (которые с Wi-Fi) .
Адаптер нужно переключить в режим Miracast (там где иконка Android и Windows) . Сделать это можно кнопкой на адаптере. Писал об этом в начале статьи.
В зависимости от версии Android, от производителя телефона/планшета, от оболочки – функция Miracast может называться по-разному. "Беспроводной дисплей", "Smart View", просто "Miracast". Ищите пункт в меню, кнопку в настройках или в центре управления. На моем Samsung это функция Smart View.
Запускаем функцию и выбираем нашу приставку. Если на вашем устройстве появится запрос PIN, то он указан на экране телевизора (у меня это 12345670) .
Все работает. Экран телефона дублируется на телевизор через MiraScreen адаптер.
И так тоже работает.
В настройках Miracast на Android можно приостановить трансляцию, или отключить ее. Звук так же передается на телевизор.
Подключение ноутбука/ПК на Windows к телевизору через MiraScreen или AnyCast
В Windows 10 есть функция "Беспроводной дисплей", которая позволяет подключаться к телевизору (в нашем случае через адаптер) по Miracast. Такая же возможность (именно встроенная функция) есть в Windows 8.1. В Windows 7 с этим сложнее, там нужны специальные программы и т. д.
У меня компьютер на Windows 10, так что покажу на примере этой системы. О настройке функции "Беспроводной дисплей" я уже писал отдельную инструкцию: Беспроводной дисплей Miracast (WiDi) в Windows 10. Ее без проблем можно применять для подключения через адаптер.
Сам адаптер должен работать в режиме "Miracast".
На компьютере нужно нажать сочетание клавиш Win + P, затем выбрать "Подключение к беспроводному дисплею" и в списке доступных устройств выбрать свой адаптер.
Если у вас нет пункта "Подключение к беспроводному дисплею", то смотрите статью по ссылке выше (о функции "беспроводной дисплей" в Windows 10) . Причина может быть в видеокарте, Wi-Fi адаптере, драйверах. Нужно проверять.
На телевизоре должен появится рабочей стол нашего компьютера.
По умолчанию он подключается в режиме "Расширить". Но режим можно сменить через меню Win + P уже после подключения. На экране будет отображаться небольшая менюшка с настройками трансляции изображения на беспроводной дисплей.
Звук так же вместе с изображением уходит на телевизор. Все вполне неплохо работает. Но качество и скорость самого соединения напрямую зависит от производительности железа компьютера и качества самого MiraScreen адаптера. Если в телевизоре есть встроенный Miracast, то лучше подключаться напрямую, без адаптера. Задержка в передаче изображения, зависание, отставание звука – частые проблемы при таком соединении. Через HDMI кабель надежнее будет.
Вроде ничего не забыл. Если что, вы всегда можете написать мне в комментариях и дополнить статью, поделиться какой-то полезной информацией по этой теме, или задать вопрос. На связи!
Идея перевести сетевую карту телефона в режим монитора разрушилась по причине собственной наивности и незнания элементарной информации о том, что подавляющее большинство мобильных сетевых карт этот самый режим монитора и не поддерживают.
Идея реализации задумки с помощью внешнего беспроводного Wi-Fi адаптера или «свистка», поддерживающего желанный режим монитора, рушилась десятки раз из-за новых и новых ошибок и потери веры в то, что это вообще возможно, но переросла в данную статью.
Итак, как подключить внешний Wi-Fi адаптер к устройству на Android или бег с препятствиями на дистанции «вставил — netcfg wlan0 up»:
Должно быть в наличии:
- Телефон на Android
- Поддержка OTG и сам OTG
- Terminal Emulator
- ROOT
- Исходники ядра
FAQ — структура выглядит так:
- Samsung GT-P5100 Galaxy Tab 2 10.1, Андроид 4.2.2
- OTG «30-pin — USB»
- ROOT
- Исходники стокового ядра 3.0.31-1919150 с сайта Самсунг
- Адаптер TP-LINK TL-WN722N на чипсете AR9271
- ath9k_htc/htc_9271.fw
- Дистрибутив Ubuntu 15.04 в VMware
- android-tools-adb
I. Старт
Первым делом необходимо добыть фирмварь вашего адаптера. Вставляю адаптер в компьютер и выполняю команду dmesg . Нахожу:
Где слово правее слова driver — искомая информация. У меня это — ath9k_htc. Гуглю для него firmware. Качаю. Закидываю .fw-файл на телефон в /system/etc/firmware
Затем устанавливаю ADB:
apt-get install android-tools-adb
Третьим этапом качаю тулчейн (компилятор под ARM) отсюда. Там большой архив, мне нужна лишь папка android-platform_prebuilt-android-sdk-adt_r20-0-ga4062cc.zip\android-platform_prebuilt-a4062cc\linux-x86\toolchain\arm-eabi-4.4.3, которую я распаковываю в произвольное место.
II. Разгон
Для начала пишу терминале:
Затем перехожу в терминале в каталог с исходниками ядра, загруженными ранее, пишу
make help и получаю тучу информации, среди которой нужно найти нечто, заканчивающееся на _defconfig, у меня это:
И в завершении запускаю графическую конфигурацию ядра:
Появляется вот такое окно:
Продвигаюсь по маршрутам:
-
Networking support → Wireless
Спускаюсь к Generic IEEE 802.11 Networking stack (mac80211) и нажимаю на пробел, наблюдая появление значка М перед этим пунктом
Сохраняю. Возвращаюсь в терминал, а если вы его закрыли, то в и каталог с исходниками тоже, и выполняю сначала make modules_prepare , а следом просто make . Результат потребует ожидания. Мой итоговый набор:
Потребуются модули (.ko-файлы), включающие слово ath и mac80211.ko. Переношу их на телефон.
Можно использовать adb, работая через компьютер, а можно не использовать и работать через терминал телефона, печатая команды пальцами по экрану. Я выбрал adb.
Напомню, как он работает. Подключаю телефон через USB (отладка, естественно, включена) и выполняю:
adb start-server
adb shell
su
Я в телефоне и под рутом.
Смотрю, какие модули уже есть командой lsmod и выгружаю их все, если это возможно, командой rmmod имямодуля
Затем перехожу в каталог с вышеперечисленными модулями:
cd /sdcard/ваш путь/
Можно убедиться в их наличии командой ls .
Загружаю их командой insmod имямодуля в такой и только такой последовательности (иначе просто не загрузится, выдавая ошибку):
ath.ko
ath9k_hw.ko
ath9k_common.ko
mac80211.ko
ath9k_htc.ko
III. Препятствия
В этом и вся соль, без которой статья была бы слишком простой.
1. Версии
Естественно, первая ошибка возникает на первом этапе.
Не совпадают версии. 3.0.31 не есть 3.0.31-1919150.
Открываю тот самый Makefile в исходниках ядра и в самом верху файла нахожу:
И сохраняю.
Заключительный этап пройдет в каталоге /include/config, где в файле kernel.release я поменяю 3.0.31 на 3.0.31-1919150
Снова make modules_prepare , make и далее по предыдущему пункту.
2. ewma
Загружая mac80211.ko снова имею ошибку, о которой dmesg скажет следующее:
Чудом прочитав на одном из англоязычных форумов опасное, но единственное в интернете, «решение», я перехожу в /net/mac80211/ и в файлах rx.c и sta_info.c и просто удаляю [либо комментирую (//)] строки ewma_add(&sta->avg_signal, -status->signal); и ewma_init(&sta->avg_signal, 1024, 8); соответственно.
Опять перекомпилирую модули и двигаюсь дальше.
3. Светодиод
При загрузке ath9k_htc.ko и mac80211.ko очередные ошибки, у mac80211.ko это:
А у ath9k_htc.ko это:
Если ieee80211_-ошибки от ath9k_htc.ko это потому что я пытаюсь его загрузить до mac80211.ko, то led_-ошибки от обоих модулей от того, что телефон не понимает, что делать со светодиодом на моем адаптере. Тут два варианта развития событий.
В первом просто убирается в графической конфигурации ядра значок [*] напротив
Networking support → Wireless → Enable LED triggers и Device Drivers → LED Support.
А во втором этот самый значок заморожен и снять его нельзя. Это значит, что при выборе моего адаптера, автоматически выбирается «поддержка» светодиода, убрать которую нельзя. Конечно же, это мой случай:
Кнопка помощи по Device Drivers → LED Support выводит следующую информацию по разделу:
А значит все настройки хранятся в данном файле. Долго я мучал Kconfig в /drivers/leds/ пока не додумался посмотреть такой же файл в своем /drivers/net/wireless/ath/ath9k, где нашел ответ на свой вопрос:
…
config ATH9K_HTC
tristate «Atheros HTC based wireless cards support»
depends on USB && MAC80211
select ATH9K_HW
select MAC80211_LEDS
select LEDS_CLASS
select NEW_LEDS
select ATH9K_COMMON
.
…
config ATH9K_HTC
tristate «Atheros HTC based wireless cards support»
depends on USB && MAC80211
select ATH9K_HW
select ATH9K_COMMON
.
и сохраняю. Теперь можно снимать галочки:
Здесь и вовсе исчез пункт:
Опять и снова перекомпиляция, новые модули и т.п.
Вуаля. Все модули загружены. Выключаю Wi-Fi на телефоне и подключаю адаптер. Но светодиод на нем, как вы уже догадались, работать не будет. Оно и не нужно.
4. Версия firmware
Если все необходимые модули загрузились, но после подключения адаптера к телефону вы не наблюдаете ничего нового в выводе команды netcfg , то на помощь приходит все тот же dmesg .
Просто качаем другой фирмварь, но уже требуемой версии, и кладем его вместо прошлого.
IV. Финиш
Теперь никаких проблем быть не должно. Выключаю родной Wi-Fi, все модули загружены, фирмварь нужной версии. Вставляю адаптер и netcfg впервые приносит счастье. Устанавливаю для появившегося сетевого интерфейса режим монитора и поднимаю его. Успех!
Ну а как и зачем зачастую используется режим монитора, вы и так все знаете. Спасибо за внимание!
В недавней статье на Geektimes в комментариях возник вопрос о поддержке в ОС Android периферии, подключенной к шине USB. Действительно, большинство вендорского ПО, к примеру, для работы с принтерами и МФУ, поддерживает только подключение по сети. Однако это не означает, что в самой ОС Android нет такой возможности — это означает лишь то, что большинство устройств не имеют полноценного USB хоста, и далеко не все имеют поддержку OTG. По сети же могут работать абсолютно все без исключения.
Большинство устройств на Android при наличии порта OTG поддерживают на уровне системы (ядра Linux или стандартных компонентов Android) следующие классы устройств:
- Устройства ввода — клавиатуры, мыши, джойстики (HID)
- Накопители (Mass Storage)
- Сотовые модемы
- Сетевые адаптеры
- Вебкамеры
Подробнее список устройств, поддерживаемых на уровне ядра Linux, можно получить в sysfs:
$ ls /sys/bus/usb/drivers
Если же модуль в принципе доступен в исходниках ядра Linux, но не включен в Android — не стоит рассчитывать на то, что его получится собрать и расставить на все целевые системы.
Однако, начиная с Android 3.1 (API 12), в системе содержатся средства, достаточные для поддержки на уровне приложения любой USB периферии. Данные средства описаны в разделе USB Host руководства по Android API. Здесь же я хочу привести примеры реальной работы с некоторыми видами устройств.
Права доступа
Как и для прочих действий, Android требует, чтобы приложение получило разрешение на доступ к USB периферии. Существует 2 способа получить такое разрешение:
- Задекларировать список устройств в AndroidManifest
- Явно показать пользователю диалог “разрешить”
Итак, нам необходимо добавить в манифест следующее:
А в res/xml/device_filter.xml вписать следующее:
Отмечу, что хотя общепринято указывать VID:PID в 16-ричной системе счисления, здесь они должны быть указаны в десятичной. В документации заявляется, что возможно указание только класса, без VID и PID, но у меня это не стало работать.
Принтеры
Класс предельно простой. В рамках этого класса устройство должно поддерживать:
- Обязательный bulk out endpoind для отправки данных на принтер
- Опциональный bulk in endpoind для получения статуса принтера
- 3 управляющих запроса
Код, приведенный ниже, предоставляет функциональность, аналогичную устройству /dev/usb/lp в Linux. Далее нам нужен фильтр, преобразующий исходный документ в пакет данных, понятный конкретной модели принтера. Но это тема иной статьи. Как один из вариантов — можно собрать ghostscript с помощью NDK.
Для работы с устройством нам в первую очередь нужно:
1. Найти устройство. В примере для простоты я ищу первый попавшийся:
2. Получить endpoint’ы:
3. Непосредсвенно открыть устройство:
4. После этого мы можем читать и писать в устройство:
5. По завершении работы — закрыть устройство:
Преобразователи USB-Serial
1. Найти и открыть устройство:
2. Установить параметры последовательного порта:
3. Читать и писать в порт:
4. По завершении работы — закрыть порт:
Резюме
Надеюсь, что мне удалось показать, что работа с USB периферией достаточно проста и логична. Безусловно, реализация протоколов некоторых конкретных устройств не блещет простотой — но это проявится в любой системе в одинаковой степени.
Все приведенные примеры я взял из реального проекта, лишь исключил очевидные проверки, оставив только ключевые строки.
Читайте также: