Привет, читатель!

Ранее я купил телефон на ОС «Аврора» и стал участником программы бета-тестирования. Это дало возможность разрабатывать ПО для мобильных устройств с применением Qt. Но внезапно я столкнулся с проблемой: к смартфону нельзя подключиться через старый-добрый USB. Как оказалось, на девайсе «из коробки» нет нужных драйверов. Если вам интересно, как я решил эту проблему и подключился через телефон, прошу под кат!

Используйте навигацию, если не хотите читать текст полностью:

Проблематика
Анализ
Реализация
Пример приложения
Заключение

Проблематика


При знакомстве с Debian в школе и на первых курсах вуза встретился с интересным кейсом: нужно было собрать модуль из исходников и подписать его. Задача простая и решалась в большинстве случаев получением нужного makefile.Однако сейчас в таких манипуляциях нет необходимости.

Подключая гаджет через USB-разъем, не приходится задумываться об установке драйвера. Различные устройства ввода и хранения, а также интерфейсы связи могут работать с базовым драйвером в операционной системе. Крайне редко возникают ситуации, когда необходимо что-то скачивать и устанавливать для работы с девайсом.

На удивление в 2024 году случилось дежавю. В ядре «Авроры» по умолчанию всего несколько модулей для периферии. А те, что реализуют интерфейс tty для CDC, и вовсе отсутствуют. В попытках собрать и подписать модуль прошла пара вечеров. Казалось, меня тормозит отсутствие mokutil. Однако позже и с помощью keytool в keyring не получилось добавить необходимые файлы в систему. Вот она — максимальная защищенность российского форка финской ОС.

Я не знал решения проблемы и решил обратиться в поддержку «Авроры» в начале июля. Ответ не помог:


Итак, возможности реализовать это подключение нет. Но есть желание — обратимся к работе USB CDC и libusb.

Во время подготовки статьи я выложил исходный код библиотеки на GitHub и поделился ссылкой в чате разработчиков «Авроры». В итоге получил ценную обратную связь по управлению интерфейсом из приложения и по назначению прав и доступов приложений. С этими знаниями планирую доработать библиотеку для повышения удобства использования. Также благодаря участию в программе бета-тестирования удалось связаться с командой разработки и запросить ранний доступ к создаваемым дескрипторам.



Анализ


Во время проверки подключения устройства к интерфейсу USB из стандартного репозитория «Авроры» я установил пакет usbutils. При вводе команды lsusb получаю вывод, который показывает, какие устройства включены, а также дополнительную информацию о них.

[defaultuser@R570E ~]$ devel-su
Password:
[root@R570E defaultuser]# lsusb -v | grep "idVendor\|idProduct\|bEndpointAddress"
  idVendor           0x1a86 QinHeng Electronics
  idProduct          0x7523 HL-340 USB-Serial adapter
        bEndpointAddress     0x82  EP 2 IN
        bEndpointAddress     0x02  EP 2 OUT
        bEndpointAddress     0x81  EP 1 IN

Последней строкой идет как раз подключенное устройство, которое содержит usb-uart преобразователь на базе CH340. Данное устройство представляет собой экземпляр USB CDC, т. е. реализует интерфейсы передачи данных. Из подробного вывода нас интересуют эндпоинты X и Y.

После недолгого поиска нашел на GitHub пару интересных и удобных репозиториев: cdc example и ch340x. Они представляют собой пример того, как можно использовать стандартную библиотеку libusb1.0. Также есть отличная статья на Хабре для погружения в работу USB.

На базе приведенных репозиториев сделал свой небольшой проект для подключения к различным микросхемам usb-uart и выложил в открытый доступ. Если необходима только динамическая библиотека, ее можно скачать из последнего релиза. Для включения в проект репозитория и его изменения выполните в папке src проекта следующие команды:

git clone git@github.com:VORyabchevsky/experimental_1.git lib
curl -o lib/libusb.h https://raw.githubusercontent.com/tenderlove/libusb/refs/heads/master/libusb/libusb.h

Реализация


Исходный код библиотеки доступен в репозитории CDCConnector на GitHub. Актуальную версию собранной библиотеки под ОС «Аврора» можно найти на на странице с релизами.

В первую очередь подготовил makefile, который позволяет собрать динамическую библиотеку. Это нужно делать под целевой системой. Если библиотеку необходимо обновить, например, повысив производительность или добавив новый функционал, то достаточно вызвать make all в папке с проектом.

Теперь перейдем непосредственно к реализации. Для подключения к устройствам через libusb нам необходимо выбрать vid и pid устройства, а для обмена информацией — эндпоинты обмена данными. Для этого подготовил структуру CDCDEV, которая содержит минимально необходимую информацию для работы и справочные поля.

Если нужно добавить свою микросхему с известными эндпоинтами, достаточно объявить переменную типа CDCDEV, например:

CDCDEV ​​PL2303 = {.vid=0x067b, 
.pid=0x2303, 
.devName="PL2303", 
.desc="Prolific Technology, Inc. USB-Serial Controller", 
.bulkReadEndpoint=0x83,
.bulkWriteEndpoint=0x02} ; 

Поля devName и desc нужны только для отображения информации в дальнейшем. В variants.h подготовил несколько вариантов для популярных микросхем.

Для удобства работы и отладки подготовил статичные функции:

  • lsUSB — сканирует и получает пул подключенных USB-устройств, их vid и pid в векторе CDCDEV;
  • lsCDC — сканирует и получает пул подключенных USB CDC устройств, сохраняет также в векторе CDCDEV.

Так как планируется подключать не более одного устройства к телефону, дополнительно сделал функцию firstCDC, которая отдает CDCDEV первого найденного устройства, к которому подключены эндпоинты в variants.h.

Далее необходимо выставить скорость обмена сообщениями, четность битов и размер пакета. Зачастую последние два поля оставляют как есть, однако лучше предусмотреть их изменение. Задал по умолчанию режим 115 200 бод, 8n1. При необходимости можно изменить это вызовом функции setBaudrate. Она нехитрым образом пересчитывает скорость в последовательность байт для передачи их на эндпоинт с помощью libusb_control_transfer:

if (!(110<baud && baud <1000000)) return -1;
for (uint8_t pos=0;pos<4;pos++){
result_array[pos]=baud&0xFF;
baud=baud>>8;
}
return 0;

После выполнения предварительных настроек интерфейса связи можно приступить к открытию порта и обмену информацией. Вот пример подключения к устройству для gcc:

…
CDCDEV variant;
int res = CDCConnector::firstCDC(&variant);
if (res!=1) {
std::cout <<"Device not found!";
return 1;
}
CDCConnector dev(variant);
std::cout << dev.setBaudrate(115200) << std::endl;
std::cout << dev.connect() << std::endl;
while(1) {
len = dev.read_bytes(buf, 64);
if (len > 0){
buf[len] = 0;
fprintf(stdout, "Received: \"%s\"\n", buf);
std::cout << len <<std::endl;
}
sleep(1);
}
…

Пример приложения


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

С применением указанной выше динамической библиотеки разработал простенький пример в Aurora IDE. Приложение определяет наличие подключенного преобразователя USB-COM и выполняет подключение для обмена данными.


Скриншот экранов приложения.

При разработке и отладке библиотеки на устройстве удобно добавить дополнительный шаг в пайплайне сборки приложения.

Что нужно сделать

  1. Зайти в Проекты.
  2. Выбрать вкладку Сборка.
  3. В поле Сборка добавить этап выбрать «Особый этап обработки».
  4. Поднять созданный этап на второе место (после проверки работы Building Engine) и прописать параметры в соответствии с вашими параметрами IDE.

Для наглядности показал пайплайн на картинке:


Пошаговая автоматизация процесса.

Далее, чтобы приложение использовало собранную библиотеку, необходимо подключить ее в *.pro файле:

LIBS += -L$$PWD/lib/ -lcdcc -lusb-1.0
I+=libusb/libusb/

Затем нужно в коде подключить файл заголовков:

#include <libusb/libusb/libusb.h>
#include <lib/cdcc.h>

Чтобы проверить работоспособность после первого включения с помощью модуля QDebug, выведем информацию в консоль телефона или консоль ПК:


При вызове функции в отладке видим, что определились устройства с искомыми VID и PID.

Далее требуется вручную разрешить работу с устройством USB, иначе будет получена ошибка access denided. Для этого в консоли в режиме администратора рекурсивно повышаем уровень привилегий на все в папке /dev/bus/usb:

devel-su
chmod 777 /dev/bus/usb/001/*

После этого можно приступить к тестированию работы и использованию самого приложения.

Заключение


Реализованная библиотека позволяет подключаться и настраивать взаимодействие с широким спектром устройств, реализующих USB CDC: от промышленных контроллеров и коммутаторов до самостоятельных приборов на базе Arduino. Планирую собрать некоторые старые pet-проекты под мобильную операционную систему, сделав их компактнее и практичнее.

Подобная библиотека может использоваться не только для существующих CDC-чипов, но и для других устройств с эндпоинтами для чтения и записи информации. Данную библиотеку буду дорабатывать, добавлением опроса и установки сигналов DTR, RTS и др.

Большой потенциал есть для применения подобных библиотек в «Авроре». Система может применяться для разработки интерфейсов встраиваемой техники. Например, экрана управления умным домом или пульта ввода для станка с ЧПУ. Функционал ограничивается только фантазией автора!

Комментарии (0)