Arduino Leonardo vs. Linux

Когда-то давно я натолкнулся на проблему с прошивкой Arduino Leonardo/Micro (в общем, всего, что основано на ATmega32U4 и использует Caterina Bootloader) с моего Debian-лаптопа. Сегодня она наконец-то встала мне поперёк горла и я стал разбираться.

Исходные данные: Arduino IDE неважно какой версии, Debian (вероятно, та же проблема будет с конфигурациями любого линукса) , клон Arduino Leonardo (Iskra Neo).

Симптом: при нажатии кнопки «Upload» в IDE происходит перезагрука платы, при этом вываливается примерно следующий текст:

На девственно чистой Ubuntu и Debian такой проблемы не возникает.

Немного странно. Перезагрузка произошла, а это значит, что у нас были права на доступ к /dev/ttyACM0 перед началом процесса. (Если не было, добавьте себя в группу dialout: «$ sudo usermod -a -G dialout username» и перелогиньтесь).

Начинаем копаться. Смотрим, что творится в /dev и видим очень странное:

Права на месте! Но ведь до чего-то avrdude докопался.

Пробуем новую тактику: проверяем вывод этой команды циклически и нажимаем в это время на кнопку Upload.

Упс. Момент, когда мы потеряли устройство из вида, понятен: контроллер перезагрузился. Но почему потом почти секунду мы наблюдаем неправильные права на устройство?

Чтобы понять, что происходит, пришлось применить магию udev (который и отвечает за всё происходящее безобразие) и разбираться в правилах.

Сначала включаем полное логгирование в udev:

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

(Это будет работать на всех относительно свежих дистрибутивах, где уже внедрили всеми горячо обсуждаемый systemd. Для остального мира — открываем логи syslog).

Пробуем подключить плату к USB:

(На месте многоточий — много всего другого. Жирным выделены строчки, в районе которых были ощутимые задержки вывода лога).

Итак, в моём случае — две наводки. Обе — запуск какого-то внешнего бинарника, который работает какое-то ощутимое время. В первом случае — что-то, связанное с OBEX, второе — TLP.

OBEX — это замороченная служба обмена данными об объектах по последовательным интерфейсам, в т.ч. Bluetooth. Потому используется в bluez, причём в Debian bluez явно зависит от bluez-obex. Синезубом я пользуюсь, так что придётся оставить.

TLP — небольшой набор утилит для контроля железок и попыток продлить жизнь ноутбучной батареи. Для ThinkPad она умеет выводить также дополнительную информацию об аккумуляторе. В общем, я периодически пользуюсь этой штукой, так что она тоже остаётся.

Однако, если прямо сейчас залезть в /lib/udev/rules.d и переименовать/переместить виновников торжества (60-openobex.rules и 85-tlp.rules) туда, где udev до них не дотянется, с Arduino всё резко станет хорошо. (А, нет, не резко. Забыли перезагрузить правила udev: «$ sudo udevadm control —reload»). Лаг пропадёт, прошивка спокойно загрузится и краски вокруг внезапно обретут былую яркость. Но этот путь выглядит жутко грязно, это даже не /etc — в /lib лучше ничего не трогать в обход пакетного менеджера. (Спойлер: конечный вариант решения всё равно портит /lib, но это уже можно попытаться завернуть в пакет.)

В общем, надо как-то сделать так, чтобы толстые правила из вышеуказанных файлов не выполнялись. Udev, начиная с какой-то уже неактуальной версии, разучился делать «OPTIONS+=»last_rule»», что позволяло сказать обработчику «выполни вот это правило и больше ничего не трогай». GOTO работает только в пределах одного файла, то есть, не получится просто пропустить часть файлов. Что ж, придётся патчить то, что есть.

Не сильно много раздумывая, были дописаны оборачивающие правила, которые заставляли игнорировать всю толстоту в случае, если подключенный девайс является ардуинкой с Caterina bootloader. Что-то вроде того:

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

В общем, если вдруг у вас вылезла такая проблема, можете попробовать воспользоваться моими патчами: 60-openobex.rules.patch и 85-tlp.rules.patch. Применять их надо как-то вот так:

Если вдруг понадобилось вернуть всё как было, делаем почти так же, как раньше, но добавляем ключ -R к patch:

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

Оффтопик: этот бутлоадер в принципе один из самых странных USB-бутлодеров, которых я видел. Во-первых, он не влезает целиком в область для хранения загрузчика на AVR, и его часть влинковывается прямо в пользовательский бинарник (насколько я это понимаю). Во-вторых, процедура перезагрузки выглядит забавно: чтобы перезагрузить контроллер с этим загрузчиком, надо попытаться подключиться к его последовательному порту на скорости 1200 бод (что и делает среда Arduino). После этого плата снова определяется как последовательный порт, но за ним висит привычный многим serial-загрузчик на базе AVR109. В общем, процесс замороченный и неторопливый, и я откровенно не понимаю, что мешало ребятам из Arduino вкорячить туда православный DFU, благо, он даже существует в природе. В итоге, получившийся монстр много весит, странно работает и может испортить вам нервы (например, как в моём случае. А ещё попробуйте нажать на кнопку Upload до того, как контроллер начнёт выполнять пользовательский скетч — получите зависший avrdude, который будет долго и упорно грызть ваш процессор, заставляя ноут раскаляться и свистеть кулерами со всей силы). Однако, со своей задачей он как-то справляется, так что оставим всё это на совести итальянцев (или американцев? …)

Оставить комментарий