В наше время, из-за санкций одноплатники стали стоить каких-то «конских» денег. Даже б/у RaspberryPi Zero стоит 2-3 тысячи рублей на барахолках, что, мягко скажем, не совсем лояльная цена для «самого дешевого одноплатного компьютера в мире». Конечно, Orange Pi Zero всё ещё можно купить в пределах 1.500-2.000 рублей, но как по мне и эта цена не слишком лояльна за те характеристики, который предлагает такой одноплатник. С другой стороны, Android-планшеты 10-летней давности продаются на барахолках по 100-300 рублей, что выглядит гораздо привлекательнее, причём на некоторые устройства практически без костылей можно установить полноценный дистрибутив Linux! Вероятно, многие читатели скажут мол «автор бомж» и будут правы: ведь в рамках этой статьи, я хочу рассказать о том, как использовать полурабочий древний планшет в качестве полноценного одноплатника путём подключения его к микроконтроллеру и выводу GPIO! Сегодня мы с вами: узнаем, как подключить микроконтроллер к шине UART в планшете и научимся работать с последовательной шиной в Android прямо из Java и нативных программ. Интересна моя концепция антикризисного одноплатника? Тогда добро пожаловать под кат!
❯ Зачем это нужно?
Пожалуй, нельзя сказать, что подобная концепция пристраивания старых планшетов — вопрос исключительно цены. 2-3 тысячи рублей не такие уж и большие деньги и при желании можно купить хотя бы Б/У, но всё таки полноценный одноплатник с нормальной GPIO-гребенкой. Однако здесь стоит вопрос не столько дешевизны, сколько E-Waste: зачем выкидывать в помойку потенциально рабочие планшеты с живым процессором, если их можно пристроить куда-то ещё?
На самом деле, планшеты с ROOT-доступом уже из коробки могут выполнять весьма полезные задачи, как, например,
Преимуществ у такого подхода много: у «пожилого» планшета уже есть большой, достаточно качественный (хороший TN, либо даже IPS) дисплей с тачскрином, который поддерживает мультитач, GPU для вывода 3D-графики, 3.5мм для вывода звука + встроенные динамики, а также весьма неплохое, по сравнению с дешевыми одноплатниками, железо. Звучит весьма вкусно для цены в 300 рублей: собрать хоть немного похожую конфигурацию на базе RPi выйдет в 10-15 тысяч рублей (учитывая дороговизну MIPI-матриц с тачскринами + цену самой «малинки» и обвязки для аудиотракта).
Но при всех перечисленных достоинствах, атрибутом любого полноценного одноплатника является наличие GPIO — и даже здесь мы сможем с вами выкрутится! Первый способ, о котором я чуть выше вскользь рассказал, позволяет реализовать общение с МК и «ногодрыг» через BT-радиоканал, но минусы такого подхода очевидны (МК с BT дороже, радиоканал потребляет дополнительную энергию, некоторые могут посчитать BT небезопасным). Однако есть и второй подход, который заключается в использовании диагностических пятачков UART на плате устройства для наших личных целей!
❯ Подготовка
Как я уже говорил выше — в рамках данной статьи мы рассмотрим использование UART в планшете для наших собственных целей. UART — это двунаправленная полнодуплексная цифровая шина, которая позволяет обеспечить стабильную передачу данных при относительно невысокой скорости, измеряемой в бодах. То есть, быстро стримить картинку с её помощью вы не сможете, но сможете, например, получить состояние входов МК, прочитать что-то на шине I2C, используя мост UART -> I2C или, например, прочитать показания датчиков, которые МК предварительно опросил.
Сама по себе концепция очень простая: многие китайские производители планшетов и смартфонов не только разводят UART в виде отдельного пятачка на плате, но и подписывают его, задействуя UART-канал как вывод для логов ядра, а иногда и предоставляя доступ к рутовой консоли! В свою очередь, из юзерспейса мы можем получить доступ к UART с помощью устройства /dev/ttyS<x> на подавляющем числе чипсетов и /dev/ttyMT<x> на MediaTek. Однако учтите, что в некоторых случаях придется патчить загрузчик, дабы редиректнуть логи ядра в /dev/null.
Однако наличие UART на плате — не всегда признак того, что он сконфигурирован в системе верно. Например, на смартфонах с чипсетами SC6820 нормально завести UART я так и не смог, а на некоторых устройствах на базе MT657x нужно патчить загрузчик, дабы он «увидел» нужный канал UART! В моём случае, героем статьи стал планшет Prestigio, у которого отказал тачскрин, но был доступен UART:
Конкретно в моём случае, после установки последней официальной прошивки планшет перестал слать логи на UART и устройство /dev/ttyMT3 оказалось доступным для наших операций, в вашем же случае может потребоваться настройка devicetree, или просто патчинг загрузчика, дабы редиректнуть консоль на другой вывод UART. Кроме того, необходимо обязательно получить root-доступ хотя бы к adb shell, поскольку доступ к /dev/tty устройствам возможен только от имени суперпользователя. Как же проверить UART на возможность чтения/записи? Сначала нам необходимо взять ESP32 или любой UART-USB преобразователь, припаять сигнальные линии RX/TX и использовать любую программу для работы с последовательным портом, например Putty. Заходим в adb shell, и пишем что-нибудь в консоль:
Вуаля! Всё работает :)
Работает? Замечательно, значит мы сможем использовать планшет вместе с микроконтроллером! Переходим к практической реализации нашего приложения!
❯ Используем из Java
Я специально решил выделить для Java-подхода отдельный раздел, поскольку просто взять и открыть /dev/ttyMT3 с помощью FileInputStream не выйдет. Дело в том, что даже несмотря на наличие root-доступа, по факту ни одно Android-приложение его не имеет (за исключением подписанных системных в папке /system/app/) и для всех операций, требующих повышенных привилегий, либо распаковывают и запускают внешнюю нативную программу из под суперпользователя, либо с помощью специального костыля с запуском sh-программ читают/пишут нужные блочные устройства сами. Связано это с тем, что все Android-приложения работают в хост-процессе app_process, который форкается (отпочковывается) от «главного» процесса, который запущен из под «простого» пользователя, который не находится в группе system.
Здесь концепция также очень простая: su имеет аргумент -c, который позволяет запустить команду от имени root-пользователя и возвращает объект процесса, дабы мы потом могли перехватить stdout:
private Process runAsRoot(String cmd)
{
try {
return Runtime.getRuntime().exec(new String[] { "su", "-c", cmd });
}
catch (IOException e)
{
e.printStackTrace();
return null;
}
Таким образом, для чтения текстовых данных из UART'а нам достаточно лишь периодически «слушать» stdout команды cat и обрабатывать данные:
Process proc = runAsRoot("cat /dev/ttyMT" + tty);
BufferedReader reader = new BufferedReader(new InputStreamReader(proc.getInputStream()));
while(true)
{
try {
String line = reader.readLine();
if(line != null && line.length() > 0) {
processCommand(line);
}
}
catch(IOException e)
{
e.printStackTrace();
}
/*try {
Thread.sleep(1000 / 30);
} catch (InterruptedException e) {
e.printStackTrace();
}*/
}
Костыль, но со вкусом :) Если вас не устраивает такой подход или ваше приложение значительно более комплексное, вы можете использовать UART и из под нативных программ.
❯ Используем из C
Работа с последовательными портами в Linux не отличается от работы с любыми другими файлами и устройствами: вызовов open, read, write и close обычно хватает и лишь иногда к ним в довесок нужен ioctl.
int fd = open("/dev/ttyMT3", O_RDWR);
int result = write(fd, command, strlen(command));
Для работы с терминалом необходимо использовать модуль termio который предоставляет все необходимые структуры для настройки режима работы терминала, в т.ч и бодрейт. Дело в том, что изначально последовательное устройство настроено на режим работы в качестве терминала, т.е драйвер отдаст данные только после того, как устройство на UART пошлёт n, или превысит размер внутреннего буфера для сообщения. Если вам нужно работать с бинарными данными и получать их «на лету» — необходимо настроить последовательный порт в «binary» режим:
tcgetattr(modemFd, &tio);
tio.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
tio.c_oflag &= ~(OPOST);
tio.c_cflag |= (CS8);
tio.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
tcsetattr(modemFd, TCSAFLUSH, &tio);
Если же вам достаточно текстового терминального режима, то можно продолжить как есть и использовать fgets, fscanf и прочие удобные функции из libc! О том, как собрать нативную программу для смартфона и как вообще выбросить Android из него, читайте в моей отдельной статье.
❯ Заключение
Вот таким образом можно использовать проводную шину в планшете для собственных нужд! Как видите, совершенно ничего сложного и используя эти наработки, я реализовал уже не один проект!
Надеюсь, материал вам был интересен и полезен :) Пишите своё мнение, можно ли использовать дешевые планшеты по 300 рублей в качестве одноплатников? Также у меня есть свой Telegram-канал, куда я выкладываю свои мысли, советы по ремонту и моддингу разных девайсов, бэкстейджи статей и вовремя выкладываю ссылки на новые материалы!
Автор: Богдан