Pull to refresh

Comments 49

:) это случайно не я ваш "заказчик"? прям про меня написано :)

Хах, насколько мне известно нет, проект был — проект успешно завершен. Но я уверен, что не Вы один сталкиваетесь с подобными задачами) Но я все таки считаю, что это не совсем правильное архитектурное решение. Вероятно использование Linux было бы более приемлемым решением. Хотя, опять же, зависит от конкретной задачи и конечной цели

Два, точнее три вопроса:


  1. Насколько это решение применимо к телефонам/планшетам на Андроиде с заделом на будущее?
  2. Если да, то каковы шансы провести приложение в Google Play?
  3. А что с Apple?
Возможно не совсем правильно понимаю суть всех трех вопросов, но попробую ответить:
1. Решение прекрасно ложиться на телефоны/планшеты на android, так как нет никаких видимых причин на изменение поведения. Работа с USB хорошо документирована, поддерживается (возникают новые методы, устаревают старые) гуглом и нет предпосылок к изменению этого в будущем.

2. Опять же не вижу причин не попасть в Google Play. Политика гугл в этом отношении сейчас достаточно жесткая, но конкретно к работе с USB, каких-то особых требований я не видел. К тому же, как правило, все что Вам нужно сделать, это в манифесте задекларировать uses-feature, остальное Google Play сделает за Вас. Вероятно у Вас возникают сомнения, когда вы видите слово Custom. Но это напрямую относится к периферийному устройству, но даже с его сертификацией, проблем не возникнет (если вы приобрели свой VID и PID). С точки зрения Android, каких то отклонений от нормы нет.

3. Не могу Вам ответить на этот вопрос, не смотрел. Но опять же повторю, протокол достаточно стандартизирован, и если у Apple есть возможность дотянуться до USB из вашего application, Вы с большой вероятностью сможете легко подружить его с Вашим периферийным устройством.

Повторюсь, основная магия все равно идет в железе на периферийном устройстве, по причине того, что в данном случае Android используется, как host. Вероятно, если вы захотите использовать Android в качестве device, то Вам придется пережить все танцы с бубном, связанные с дескрипторами, но это уже немного другой уровень погружения в usb стек, хоть и тоже весьма поверхностный
  1. Тут вопрос в том, что не идет ли предпосылка в телефонах/планшетах к отказу от USB вообще? Т.е. в Apple, например, USB вообще нет, а всякие Lightning, что вынуждает делать отдельную версию устройства под них, да еще и с чипом. В андроидах сейчас идет Type C и может быть в конце-концов тоже уйдет, как и разъем для наушников, или придумают такую же фигню, как Apple с чипом "Certified for Android"?


  2. "если вы приобрели свой VID и PID" — вот это уже начинает напрягать. Т.е. прикинуться чайником (или FTDI каким-нибудь) может уже не получиться? Просто кастомизация все больше и больше не в почете у гигантов.


1. Мне на самом деле сложно предположить. Если говорить в контексте этой статьи, то как я уже говорил считаю использование USB HID, да в общем и остальных классов для взаимодействия с периферийным устройством с телефона/планшета архитектурнй ошибкой проекта, в котором все это используется. С однопланиками все понятно, там вероятно есть смысл, но в таком случае туда сам собой напрашивается Linux. Но опять же подчеркну, все зависит от задачи.

Что касается использования USB в смартфонах в отрыве от статьи, прогнозировать сложно, но мне на данный момент сложно предположить подобное развитие событий именно для android смартфонов. USB протокол прост в реализации на уровне железа, программный стек достаточно хорошо подходит почти для всех задач и прекрасно отработан и документирован. Изменение типа разъема, спецификации и прочего это одно, а вот убрать разъем целиком, это совсем другое дело. Согласен, большую часть стандартных вещей можно и без USB провернуть, даже дебажить можно по Wi-Fi. Но боюсь закрыть все дыры таким образом не получится. К тому же я не по совсем понимаю, зачем его убирать. С разъемом наушников все понятно, а вот USB… Чип USB стоит немного, небольшой по размеру, если его убрать, места на плате не сильно уменьшится. К тому же текущая тенденция увеличения размера экрана, позволяет об этом не париться. Если речь идет о размере разъема, то если уже и он мешает, то я не знаю, насколько тонкие телефоны нужны человечеству)

2. Кастомизация происходит на уровне периферийного устройства, к Android отношения не имеет, если речь идет о host. VID и PID придется приобрести, правда не во всех случаях)) FDTI — это не к USB. Сам протокол он не реализует, а является лишь преобразователем интерфейса. К слову о FTDI, USART на Android, насколько мне известно, тоже можно потрогать из Вашего Application
fun sendReport(data: ByteArray) {
usbConnection?.bulkTransfer(usbOutEndpoint, data, data.size, 0)
}

собственно Вы уже привели тут единственный метод.
FTDI, USART на чистой яве? это фантастика. Вам придется
работать через оберку с двоичной либой.
github.com/chzhong/serial-android
У UsbDeviceConnection есть еще метод controlTransfer, который тоже может использоваться, но насколько мне известно только для передачи управляющих команд через нулевую конечную точку, через которую идет энумерация. Насчёт USART, как я уже говорил, не уверен, возможно и через либу. Видел в сети варианты использования, так что в случае необходимости решение найти можно
Кстати, в качестве Device устройства на Android можно использовать через Bluetooth, начиная с Android Pie для этого есть стандартный API (почему-то выключенный на телефонах Nokia и OnePlus, но тем не менее).

Я так понимаю Вы говорите именно про Bluetooth, безотносительно к USB.
Насколько мне известно Android смартфон мог играть роль Device достаточно давно по крайней мере в Bluetooth Low Energy. В классическом Bluetooth это вероятно является нововведением, к сожалению не знаю, так как при разработке чаще пользовался BLE — стабильнее работает, по крайней мере со стороны embedded железки (точнее соотношение цена/стабильность получше)

Да, про Bluetooth, но там, по сути, используются те же самые дескрипторы, меняется только физический транспорт, а протокол более-менее тот же.
Играть роль Device (например, мышь) через BLE мне его стабильно заставить так и не удалось, что-то в стеке всё-таки реализовано странно, по крайней мере в последних версиях: где-то на Marshmallow-Nougat это ещё работало, но дальше практически перестало нормально работать. Ну а Device через Bluetooth Classic — это действительно нововведение.

Извините, но я с Вами не согласен. Да, с одной стороны характеристики и сервисы в bluetooth low energy действительно напоминают usb hid report, но только по структуре разве что. На этом сходства заканчиваются. Работают они абсолютно по разному. Я хотел даже привести здесь пример различий, но понял, что привести его достаточно сложно, потому что отличается все кроме этой самой структуры.

Я говорил всё-таки о дескрипторах и репортах в Bluetooth Classic, а не BLE. :)
BLE действительно не похож ни разу.
Если честно не понимаю о каких дескрипторах и репортах классического Bluetooth идет речь. Впервые слышу о подобных вещах.

Если речь идет про протокол HID натянутый поверх Bluetooth, то это просто протокол HID, который по идее спецификой USB не является. можно пользовать где угодно. Вот только отношения к Bluetooth я так и не просек)
Речь о стандартном профиле Bluetooth, таком же стандартном, как A2DP, см. википедию:
Bluetooth HID is a lightweight wrapper of the human interface device protocol defined for USB. The use of the HID protocol simplifies host implementation (ex: support by operating systems) by enabling the re-use of some of the existing support for USB HID to also support Bluetooth HID.

Все Bluetooth Classic устройства ввода (а это разнообразные мыши, клавиатуры, джойстики, и т.п.) по сути общаются по тому же самому USB HID протоколу, сообщая хосту те же самые дескрипторы и репорты.
Ну а BLE — это уже другой профиль, известный как GATT…
Согласен, я не совсем корректно вас понял, поэтому никак не мог осознать о каких дескрипторах в классическом Bluetooth идет речь)
У STM есть VirualComPort тогда, по идее, не надо свой VID PID получать.
Если речь идет о USB классе VCP, то свои VID и PID там не нужны, можно использовать те, которые предоставляет STM для устройств на базе их контроллеров. STM также предоставляет драйвера под ОС для работы с подобными устройствами. Но если ваш проект планирует развиваться на рынке, VID и PID приобрести рано или поздно придется, а также написать свой драйвер для ОС.
Для коммерческих продуктов стандартный драйвер не всегда хорошая идея. К примеру драйвер VCP под Windows просто ужасный. Позволяет все прекрасно запустить на малых скоростях и небольших объёмах данных, но шаг вправо, шаг влево и драйвер выдает удивительные вещи. Попробуйте предавать по VCP с STM большой объем данных и при этом щелкать мышкой на ПК (знаю, звучит глупо), на котором вы принимаете данные. Уверяю Вас, часть данных вы не получите.
На телефонах с андроидом работа с usb больше зависит от железа.
например. флайчик. все программные тесты говорят юсб поддерживается, а железки нет.
Поэтому простой тест. Берем мышку. Берем флешку. Втыкаем через отг кабель.

Вместо конкретных vid&tid в хмл для фильтрации можно просто классы написать.
Просто работать с устройствами, которые поддерживают булк на ендпоинтах.
Эмуляция COM порта гиморой.

Согласен, к тому же я заметил, что android работает и с interrupt конечными точками через булк методы. Подробное поведение нигде не описано, так что можно схватить не логичное поведение

что еще очень раздражает.
Каждый раз после коннекта устройство считается новым и идет запрос пермишинов.
Единственное юзабельное решение.
Становится слушателем на все подключения. Тогда у пользователя появиться
вариант «открывать ваше приложение при подключении всегда».
Активити слушатель этого может быть пустышкой. Нужно только для автополучения
разрешения. Ну а я в своей проге меняю настроки в этом случае так (транспорт-usb,vid,pid).
Еще в андроиде не получиться подключить два устройства с одинаковыми vid&pid одновременно, так как смотри выше обход дерева требуется, чтобы найти устройство.
А uri адрес устройства при каждом конекте новый.

А где можно найти расшифровку кодов ошибок. Например, если
usbConnection?.bulkTransfer(usbOutEndpoint, data, data.size, 0), выполнилось неправильно.
Данный метод возвращает размер переданных данных либо ошибку (Возвращает -1). Ошибка не имеет различных кодов, есть только факт возникновения.
В res/xml/device_filter.xml (наверное и в статье стоит этот путь прописать), кроме
<usb-device vendor-id="1155" product-id="22352" /> 
приписал также и
<usb-device vendor-id="1240" product-id="63"/>  // Microchip USB HID
    


Также изменил
  const val VENDOR_ID =  1240//1155
     const val PRODUCT_ID = 63//22352


При втыкания устройства в USB-порт ожидалось, что как только я подключу устройство он предложит запустить программу (не предложил, в списке остались только ранее написанный мною программы).
Не совсем понимаю что вы хотите этим сказать. У Вас другое USB устройство с другими VID и PID. Естественно вы должны заменить их в коде. Код представленный в статье является демонстрационным и работает с usb устройством на базе STM32F429. Вам не нужно вставлять вашу строку в дополнение к моей. Вы можете удалить мою и вставить свою. Что касается предложения Вашей программы при подключении, то необходимо указать соответствующие интент фильтры в манифесте
Ну так я изменил константы VENDOR_ID и PRODUCT_ID на свои. Я должен ещё что-то изменить, чтобы программа с другим устройством работала?

Поменять VID и PID в res/xml/device_filter.xml на свои.
Для дальнейшего взаимодействия изменить CUSTOM_HID_INTERFACE на тот, с которым вы работаете, ну и репорты привести в соответствие с вашими.
Если хотите, чтобы ваше приложение реагировало на подключение устройства, надо добавить интент фильтр в манифест.


< intent-filter >
    < action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
< /intent-filter >
мой res/xml/device_filter.xml
_?xml version="1.0" encoding="utf-8"?_
_resources_
_usb-device class="02" /_
_usb-device class="07" /_
<usb-device class="255" />
_/resources_


а vid & pid через сеттинги приложения

Можно и так, правда в таком случае вы скорее всего интент на подключение не получите от конкретно вашего устройстаа

rawbt в гугл плее. Подключаешь принтер по usb.
говоришь. открывать всегда c помощью приложения.
в манифесте
uses-permission android:name=«android.permission.USB_PERMISSION»
uses-feature android:name=«android.hardware.usb» android:required=«false»

< activity
android:name=".activity.UsbKnownActivity"
android:excludeFromRecents=«true»
android:noHistory=«true»
android:theme="@android:style/Theme.NoDisplay"
< intent-filter >
< action android:name=«android.hardware.usb.action.USB_DEVICE_ATTACHED» / >
< /intent-filter >

< meta-data
android:name=«android.hardware.usb.action.USB_DEVICE_ATTACHED»
android:resource="@xml/device_filter" / >


в активити запоминаю в сеттингах vid & pid

Да, но при таком раскладе, ваше приложение будет реагировать на любое устройство с тем классом, который вы описали в device_filter. В данном случае вы будете реагировать на любое устройство реализующее интерфейс 07h, к примеру, т.е. Printer
Если вы хотите реагировать на интент при подключении конкретного устройства (или серии устройств), то надо прописывать VID и PID в device_filter

классы 2 — все что может работать как порт для передачи данных,
7 — представляется принтером, 255 — прочие.
например китайский шнурок для старых принтеров.
photos.app.goo.gl/zzkndEFGscHbtF2dA

USB-OTG кабели тоже могут быть виноваты в том, что устройство не находиться. Через беленькую штучку видится, через короткий кабель нет ;(

Диалог на следующем рисунке может иметь варианты. Если программ
под фильтр окажется несколько, появиться выбор из нескольких вариантов.

поставили галку на себя или другую. Дальше будет молча

Согласен, это действительно так.
Но, насколько мне известно, (возможно я конечно не прав, но все же), если поставить правильные VID и PID в фильтр, то подобные диалоги будут появляться только в случае, если вы подключите ваше устройство. (Вы также можете поставить галочку и больше не получать диалог, а сразу запускать приложение)Во всех остальных случаях, вы диалог получать не будете в принципе. Если я сейчас подключу к телефону мышку, то диалог я не получу и мышка будет спокойно работать.


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

именно. Имхо китайские товарищи сами не знают какой вид и пид будет у следующей партии термопринтеров.

С этим полностью согласен)

1. Уже поменял
2. У меня я проверил в коде другой программы, которая видит устройство тоже CUSTOM_HID_INTERFACE при коннекте.
3. Репорты пока не менял, т.к. у него ошибка на этапе коннекта.
4. Да, после добавления в манифест реагирует, спасибо.

Сейчас какую-нибудь мышку попробую потестировать, может с мышкой законнектится.

Подебажде метод подключения. Находит ли устройство, затем интерфейс

Я извиняюсь за ламерский вопрос, но как отлаживать если USB гнездо планшета занято устройством? С разветвителем?
P.S. Мышка (Logitech) тоже не запустилась.
P.P.S. Я собираю под API 22, может быть в этом проблема?
wifi adb. писать логи самому. А так да не удобно.
Критические ошибки я себе через интент кидаю в errorActivity

Да согласен, с предыдущим комментарием, отлаживать надо через Wi-Fi. Она и не запустится просто так, проверяйте интерфейсы и дебажте функцию коннекта, чтобы понять в чем причина.
Данный пример не панацея, для корректной работы надо описать Ваше конкретное устройство

А вот ещё ламерский вопрос, а можно ли как-то увидеть USB в эмуляторе? Я драйверы установил, но судя по тому, что показывает отладка, из под эмулятора никаких USB устройств не видно(мышки, к примеру).

На эмуляторе никогда не пробовал, не могу посоветовать и если честно, не уверен, что это легко можно провернуть на стандартном эмуляторе. Но опять же, не пробовал и даже не пытался вникать в тему

никто не будет в эмуляторе эмулировать баги реальных устройств.
и 16 гиг оперативы имхо слишком жирно.
Я недавно добил с 4 до 12 свой старенький комп. Стало легче. Но эмулятор все равно медленный. А на 4х нельзя было держать одновременно студию, эмулятор и хотя бы одну вкладку в хроме.

Да, и надо учитывать, что помимо hid, есть еще много стандартных классов, разными типами передачи. К тому же, само api для usb у android весьма скромное, реализует только базовые функции, необходимые для минимальной работоспособности. Сомневаюсь, что при это кто то обратил внимание на эмулятор)

В результате подконнектилось после того, как заменил
idx in 0..usbInterface!!.endpointCount

на
idx in 0..usbInterface!!.endpointCount-1

В модуле UsbHelper.kt
у автора определение нужных ендпоинтов упрощено под его кастомное устройство.
общий принцип.
пройтись по всем
проверить тип и направление ( возможно еще что-то нужное именно Вам)
подходящее запомнить

Ну да, в данной статье рассмотрен конкретный кейс. Цели написать универсальную библиотеку не было) Дело в том, что это custom hid и как правило назначение и номера конечных точек вы должны знать и в моем примере, даже поиск этих точек излишен по идее. Формально получить их по номерам можно, просто задефайниф значения номеров с учётом направления.
Но если вы хотите пройтись по всем, и вывести к примеру информацию, то да, есть смысл этот кусок кода преобразовать по вашему замыслу)

Кусочек если это не входной ендпоинт, то выходной.
Во первых в цикле дает неопределенность (выходной последний найденный).
И есть еще ендпоинты, которые для управления, а не для передачи данных.

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


Что касается цикла, то он перебирает конечные точки по направлению передачи, а не по типу. В данном случае они могут быть либо IN, либо OUT, а тип конечной точки и тип передачи (Bulk, Isoc, Interrupt) в данном случае не рассматриваются.


Из этого проистекает то, что цикл не дает неопределенности, все вполне логично — если точка не имеет направление IN, то она имеет направление OUT. И цель определить это, а не тип точки, тип передачи, размер пакета, частоту опроса и прочие параметры конечной точки, которые имеет место быть и важны в той или иной ситуации. Однако для того, чтобы передавать и принимать данные этого достаточно, а большего в этом примере и не нужно)

Sign up to leave a comment.

Articles

Change theme settings