Сниффер RS-232 на Linux: практическое руководство

1. Введение
Несмотря на то, что COM-порт на компьютерах и ноутбуках ушел в прошлое чуть ли не в начале этого века, сам протокол RS-232 до сих пор живет и здравствует. По большому счету, ни один микроконтроллер, ни одно встраиваемое решение не лишено хотя бы одного UART/USART интерфейса. А если его и нет, то его делают программно. В повседневной жизни про USART вспоминают, например, после окирпичивания роутера, да и прошивку зачастую можно перезалить только с его помощью.

Бывают и другие задачи: например, вы купили USB-датчик, а программа с ним не хочет работать. Да еще и выдает максимально «информативную» ошибку вроде «ошибка 41, нет связи с устройством». При этом лампочка на устройстве моргает, как бы намекая, что связь-то есть... Вот было бы здорово узнать, что за пакеты улетели, а главное, отреагировала ли на них наша USB-железка.

2. Ложка дегтя
Если вы знакомы с сетевыми снифферами (будь то гуишный wireshark или консольный tcpdump), то вы, конечно, знаете, насколько просто прослушивать трафик (разумеется, если он не зашифрован). Для этого достаточно подключиться к нужному интерфейсу и дальше наблюдать за байтиками.

Так вот. Для UART это невозможно. От слова совсем. Вот выжимка из вольного перевода FAQ сниффера jpnevulator, который мы как раз и будем использовать далее:

Сначала плохие новости: два процесса GNU/Linux не могут одновременно открыть один и тот же последовательный порт. Если это происходит, результаты могут быть непредсказуемыми.

Сожалею, но Jpnevulator не создавался для работы в режиме «посредника» между ядром и вашим приложением.

Я обычно использовал Jpnevulator в паре с устройством, которое сидело как бы в разрыве последовательного кабеля. На выходе из устройства дублировалось всё, что поступало на вход. Получалось что-то вроде «человека посередине» (man in the middle).

3. Бочка меда
Продолжаем читать FAQ:

Теперь, как кажется, хорошие новости: некоторое время назад Эрик Шатоу (Eric Shattow) предложил использовать псевдотерминальные устройства для реализации работы «посредника» между ядром и вашим приложением. Поддержка псевдотерминальных устройств пока что недостаточно тестировалась, но это работает. 

То есть, логика проста: к последовательному порту устройства подключается тулза jpnevulator, которая открывает «виртуальный» порт, на который уже будет цепляться оригинальная программа. Как будет показано далее, работает такая связка, прямо скажем, не очень стабильно, да и о высоких скоростях (вроде baudrate 115200) придется по-видимому забыть. Однако, это явно лучше, чем ничего.

4. Установка софта и первые тесты
Для дальнейших экспериментов вам нужен будет любой USB-USART преобразователь. Предполагается, что вы знаете, что это такое и как с ним работать в Linux, иначе зачем вообще вам эта статья :-)

Так же установим необходимый софт: jpnevulator и cutecom. Первое — это уже упомянутый сниффер, а второй — обычный последовательный терминал с графическим интерфейсом.

sudo apt-get install jpnevulator minicom

Ну и весьма желательно, чтобы текущий пользователь входил в группу dialout, чтобы иметь права на чтение-запись в последовательный порт без необходимости заходить под рута.

Теперь откройте cutecom. Далее подключитесь к вашему USB-USART и замкните RX и TX на нем. Проверьте, что всё работает как надо: при отправке текста в поле input, этот текст должен одновременно появиться в верхнем и нижнем окне:

Получилось? Тогда закрывайте порт и пока выйдите из программы.

Дело в том что cutecom не позволяет прописывать «виртуальные» порты в самом интерфейсе. Это можно сделать в конфиге, который автоматом создается в домашней директории при первом открытии ~/.config/CuteCom/CuteCom5.conf. К конфигу вернемся позже, а пока зайдите в консоль и введите команду:

jpnevulator --read --tty=/dev/ttyUSB1 --pty --pass --ascii

Кратко по параметрам:

  • читать трафик (есть еще --write для записи)
  • путь к девайсу
  • открыть «виртуальный» порт (псевдотерминальное устройство)
  • выводить не только hex, но и символы ascii

После запуска команда выведет что-то вроде

jpnevulator: slave pts device is /dev/pts/12.

То есть открылся порт /dev/pts/12. Далее, отредактируйте файл ~/.config/CuteCom/CuteCom5.conf и замените в Device порт ttyUSB на /dev/pts/12 (у вас будет свой).

Теперь можно запустить cutecom: там будет ваш псевдодевайс. Нажимайте open, вводите в поле input слово test и смело нажимайте Enter... Ааааа! Что происходит?!

В консоли как-будто что-то взбесилось. Ну а что вы хотели? Порт-то мы не настроили. Да, в саму программу настройку порта не завезли, его нужно настраивать предварительно самому. Закрываем порт, стопаем jpnevulator и перетыкаем заново USB-USART. Теперь в консоли набираем:

stty 9600 ignbrk -brkint -onlcr -icrnl -imaxbel -opost -isig00icanon -iexten -echo noflsh </dev/ttyUSB1

Вместо /dev/ttyUSB1, разумеется, свой порт. Снова запускаем jpnevulator, открываем псевдотерминал в cutecom и пишем test. Теперь всё прошло гладко:

В выводе jpnevulator можно видеть два блока: после /dev/pts/12 идет то, что мы послали на устройство, а после /dev/ttyUSB1 — то, что устройство ответило. Теперь посмотрим, как можно посниффить прошивку микроконтроллера.

5. Практика: подключаемся по JTAG
Для прошивки и отладки микроконтроллеров AVR по JTAG-интерфейсу существует внутрисхемный отладчик JTAG ICE, который хотя и считается устаревшим, продолжает быть популярным: как по причине низкой цены, так и по причине того, что его достаточно несложно собрать «на коленке». А еще проще — сжечь. Потому что он не прощает даже секундной переполюсовки, что и произошло с одним моим экземпляром на новогодних праздниках.

Собственно, это и послужило главным поводом раскурить работу снифферов в линуксе. По итогу подтвердилось, что отладчик мертв (хотя и не совсем — через раз нужные байты частично прилетали), что делает его не особо интересным для дальнейшего разбора (ну что вы, в самом деле, рандомных байтов не видели?). Так что достаем из кармана еще один «Эмулятор льда usb AVR JTAG» и начинаем эксперименты.

Как уже упоминалось, через сниффер не получается гнать большие скорости. К счастью, в avrdude кроме режима jtag1 (скорость 115200 бод) предусмотрен еще jtag1slow со скоростью 19200 бод.

Сначала настраиваем интерфейс (делается при каждой перезагрузке, либо повторном втыкании отладчика в usb порт).

stty 19200 ignbrk -brkint -onlcr -icrnl -imaxbel -opost -isig -icanon -iexten -echo noflsh </dev/ttyUSB2

Обратите внимание, интерфейс в данном случае /dev/ttyUSB2 (у вас будет свой).

Так же предварительно проверим, что отладчик всё еще работает как надо и успешно определяет микроконтроллер.

avrdude -F -c jtag1slow -P /dev/ttyUSB2 -p m16

Видим заветное Fuses OK (E:FF, H:19, L:E4). Теперь запускаем сниффер.
jpnevulator --read --tty=/dev/ttyUSB2 --pty --pass --ascii

Далее снова запускаем avrdude, но теперь в качестве интерфейса указываем /dev/pts/1 (у вас он будет другой, в зависимости от вывода команды выше).

avrdude -F -c jtag1slow -P /dev/pts/1 -p m16

Для того, чтобы понять, что в сниффере означают те или иные байты, следует ознакомиться с протоколом JTAG ICE — см. appnote AVR060 в архиве ниже, либо его краткий перевод (зеркало).

1705618033_AVR060.pdf

Красным на скриншоте ниже отмечено то, что посылает программа avrdude, а желтым — ответ jtag ice устройство.

  • 1 — засинхрониться с устройством (0x20), 2 —устройство ответило ОК (0x41)
  • 3 — «Ты эмулятор?», 4 — устройство ответило «ага, ОК, AVRNOCD, ОК»
  • 5 — остановить программу, 6 — ок, попытались, получили точку останова 0x54

Смотрим дальше:

  • 1 — посылаем на отладчик дескриптор девайса (отладчика?), как я понял он универсален; 2 — ОК, всё норм
  • 3 — установить размер страницы ОЗУ (младший байт, 0x80); 4 — OK
  • 5 — установить размер страницы ОЗУ (старший байт, 0x00); 6 — OK
  • 7 — установить размер страницы EEPROM (старший байт, 0x04); 8 — OK

Таким образом, мы установили параметры для отладчика: размер страницы ОЗУ 128 байт (0x80), размер страницы EEPROM — 4 байта. Что полностью соответствует документации на Atmega16.

В заключение, приведу еще небольшой отрывок — во время записи прошивки.

Вывод самой программы:

Видно, что прошивка прошла успешно (1), а вот проверка (чтение прошивки) — неудачно. С чем это связано сказать довольно сложно, скорее всего нужно подстраивать параметры порта. Но уже это дает возможность увидеть через сниффер, как идет заливка прошивки на микроконтроллер.

  • 1 — Указываем, что сейчас будем заливать на микроконтроллер прошивку (0x57), далее идет указание на тип памяти, количество слов в пакете и т.д. Отладчик должен ответить ОК (2)
  • 3 — как только получили ОК от отладчика (в предыдущем шаге), начинаем записывать непосредственно данные. По завершению записи отладчик должен ответить ОК (4)
  • 5 — команда записи следующего блок данных, после ответа ОК (6) идут сами данные (7).

Заключение
Мы рассмотрели далеко не все возможности сниффера jpnevulator, но этого уже достаточно для того, чтобы заглянуть «под капот» любого протокола или программы, работающей по RS-232 интерфейсу. Тулза более чем адекватно справляется с поставленной задачей — особенно с учетом того, что она бесплатная.

#микроконтроллер #atmega16a #linux #uart #usart #сниффер #sniffer #rs-232 #avr