Виртуальный последовательный порт для Linux

128

Мне нужно протестировать приложение последовательного порта в Linux, однако моя тестовая машина имеет только один последовательный порт.

Есть ли способ добавить виртуальный последовательный порт в Linux и протестировать мое приложение, эмулируя устройство через оболочку или скрипт?

Примечание: я не могу переназначить порт, он жестко запрограммирован на ttys2, и мне нужно протестировать приложение, как оно написано.

JeffV
источник

Ответы:

75

Для этого вы можете использовать pty («псевдотелетайп», где последовательный порт является «настоящим телетайпом»). С одного конца откройте /dev/ptyp5, а затем прикрепите свою программу к /dev/ttyp5; ttyp5будет действовать так же, как последовательный порт, но будет отправлять / получать все, что он делает, через / dev / ptyp5.

Если вам действительно нужно, чтобы он разговаривал с файлом с именем /dev/ttys2, просто уберите старый /dev/ttys2и создайте символическую ссылку с ptyp5на ttys2.

Конечно, вы можете использовать другое число, кроме ptyp5. Возможно, выберите один с большим числом, чтобы избежать дублирования, поскольку все ваши терминалы входа также будут использовать ptys.

В Википедии есть дополнительная информация о ptys: http://en.wikipedia.org/wiki/Pseudo_terminal

apenwarr
источник
8
В Linux вы можете использовать системные вызовы openpty / forkpty. См. Справочную страницу
Мэтью Смит,
8
как создать пару виртуальных последовательных портов с помощью инструмента командной строки?
linjunhalida
8
обратите внимание, что многие параметры последовательного порта, например скорость передачи, четность, управление потоком hw, размер символа (?), не реализованы в pty, поэтому невозможно протестировать ваше приложение на наличие ошибок последовательной передачи.
Дима Тиснек 03
10
Это полезно, но описывает псевдотерминалы BSD «старого стиля». Псевдотерминалы UNIX 98 «нового стиля» работают немного иначе - подробности см. На ptsстранице руководства.
Craig McQueen
3
@LaszloPapp: Прошу прощения, я все время лгал
Мэтью Смит,
160

Дополняя ответ @ slonik.

Вы можете протестировать socat для создания виртуального последовательного порта, выполнив следующую процедуру (проверено на Ubuntu 12.04):

Откройте терминал (назовем его Terminal 0) и запустите его:

socat -d -d pty,raw,echo=0 pty,raw,echo=0

Приведенный выше код возвращает:

2013/11/01 13:47:27 socat[2506] N PTY is /dev/pts/2
2013/11/01 13:47:27 socat[2506] N PTY is /dev/pts/3
2013/11/01 13:47:27 socat[2506] N starting data transfer loop with FDs [3,3] and [5,5]

Откройте другой терминал и напишите (Терминал 1):

cat < /dev/pts/2

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

2013/11/01 13:47:27 socat[2506] N PTY is /dev/pts/**2**
2013/11/01 13:47:27 socat[2506] N PTY is /dev/pts/**3**
2013/11/01 13:47:27 socat[2506] N starting data transfer loop with FDs 

вы должны использовать номер, доступный в выделенной области.

Откройте другой терминал и напишите (Терминал 2):

echo "Test" > /dev/pts/3

Теперь вернитесь в Терминал 1, и вы увидите строку «Тест».

Кантони
источник
Это сработало для меня лучше, чем ответ slonik, потому что он автоматически назначается файлам виртуального COM-порта и не выводится.
gbmhunter 08
7
Если вы хотите, чтобы воспроизводимое имя файла использовалось link=/path/to/linkпосле каждого объявления устройства (после echo = 0). Таким образом, его можно использовать в автоматизированных тестах. (как это делает слоник в своем ответе)
Патрик Б.
Это сработало именно так, как упоминалось. Мне помогло спасибо.
nim118
1
Чтобы создать псевдотерминал, ссылки на реальный последовательный порт: socat -d -d pty,raw,echo=0 /dev/ttyUSB5,raw,echo=0.
Penghe Geng
Могу ли я создать последовательный порт с именами вроде /dev/ttyS0вместо /dev/pts/1?
mrid
48

Для этого используйте socat:

Например:

socat PTY,link=/dev/ttyS10 PTY,link=/dev/ttyS11
Слоник
источник
У меня это сработало, протестировано с minicom! Похоже, что вход в один терминал отражается на обоих (так что он снова появится на входном терминале).
gbmhunter 08
1
У меня нет такого же поведения эха ... minicom имеет функцию "локального эха" ... но когда она отключена, она работает точно так же, как настоящий последовательный порт. Спасибо за чаевые.
cptHammer 09
16

Также существует tty0tty http://sourceforge.net/projects/tty0tty/, который является настоящим эмулятором нуль-модема для Linux.

Это простой модуль ядра - небольшой исходный файл. Я не знаю, почему он получил отрицательные отзывы на sourceforge, но мне он подходит. Самое лучшее в нем то, что он также эмулирует аппаратные контакты (RTC / CTS DSR / DTR). Он даже реализует команды TIOCMGET / TIOCMSET и TIOCMIWAIT iotcl!

В недавнем ядре вы можете получить ошибки компиляции. Это легко исправить. Просто вставьте несколько строк вверху источника module / tty0tty.c (после включений):

#ifndef init_MUTEX
#define init_MUTEX(x) sema_init((x),1)
#endif

Когда модуль загружен, он создает 4 пары последовательных портов. Устройства: от / dev / tnt0 до / dev / tnt7, где tnt0 подключен к tnt1, tnt2 подключен к tnt3 и т. Д. Вам может потребоваться исправить права доступа к файлам, чтобы иметь возможность использовать устройства.

редактировать:

Думаю, я немного поторопился со своим энтузиазмом. Хотя драйвер выглядит многообещающе, он кажется нестабильным. Я не знаю наверняка, но думаю, что это разбило машину в офисе, над которым я работал из дома. Я не могу проверить, пока не вернусь в офис в понедельник.

Во-вторых, TIOCMIWAIT не работает. Код, кажется, скопирован из какого-то примера кода "крошечного терминала". Обработка TIOCMIWAIT кажется на месте, но она никогда не просыпается, потому что соответствующий вызов wake_up_interruptible () отсутствует.

редактировать:

Авария в офисе действительно произошла по вине водителя. Отсутствовала инициализация, и полностью непроверенный код TIOCMIWAIT вызвал сбой машины.

Вчера и сегодня потратил на переписывание драйвера. Было много проблем, но теперь у меня все хорошо. По-прежнему отсутствует код для аппаратного управления потоком данных, управляемого драйвером, но он мне не нужен, потому что я сам буду управлять контактами, используя TIOCMGET / TIOCMSET / TIOCMIWAIT из кода пользовательского режима.

Если кому-то интересна моя версия кода, напишите мне, и я отправлю его вам.

Питер Реммерс
источник
2
Мне было бы интересно увидеть ваш код. Можете ли вы внести свой вклад в проект tty0tty? Однако я бы предпочел, чтобы люди улучшали код псевдотерминала в ядре Linux. Например, добавьте поддержку аппаратного квитирования и TIOCMIWAIT.
Craig McQueen
3
«Если кого-то заинтересует моя версия кода, отправьте мне сообщение, и я отправлю его вам». Да, мне интересно! Можете ли вы указать на него где-нибудь, например, на GitHub?
Craig McQueen
7
Я загрузил драйвер по адресу : github.com/pitti98/nullmodem. К сожалению, на ответ ушло так много времени. Я не очень активен в stackoverflow и пропустил ваш комментарий!
Peter Remmers
Нет, я написал это, потому что мне это было нужно, и остановился, как только он стал достаточно хорошим, чтобы делать то, что я хотел. Теперь, когда он общедоступен, я надеюсь, что он будет полезен для кого-то еще, и, возможно, кто-то подберет, где я его оставил.
Питер Реммерс
8

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

Существуют и другие коммерческие альтернативы, например http://www.ttyredirector.com/ .

В Open Source Remserial (GPL) также может делать то, что вы хотите, используя Unix PTY. Он передает последовательные данные в «сыром виде» в сетевой сокет; При создании порта необходимо выполнить настройку параметров терминала в стиле STTY, изменение их позже, как описано в RFC 2217, похоже, не поддерживается. У вас должна быть возможность запустить два экземпляра remserial для создания виртуального нульмодема, такого как com0com, за исключением того, что вам нужно заранее настроить скорость порта и т. Д.

Socat (также GPL) похож на расширенный вариант Remserial со многими другими опциями, включая метод «PTY» для перенаправления PTY на что-то другое, которое может быть другим экземпляром Socat. Для Unit tets socat, вероятно, лучше, чем remserial, потому что вы можете напрямую cat файлы в PTY. См. Пример PTY на странице руководства. В разделе «contrib» существует патч, обеспечивающий поддержку RFC2217 для согласования настроек последовательной линии.


источник
6

Используя ссылки, опубликованные в предыдущих ответах, я написал небольшой пример на C ++ с использованием виртуального последовательного порта. Я поместил код в GitHub: https://github.com/cymait/virtual-serial-port-example .

Код довольно понятен. Сначала вы создаете главный процесс, запустив ./main master, и он будет печатать на stderr, используемом устройством. После этого вы вызываете ./main slave device, где device - это устройство, напечатанное в первой команде.

И это все. Между этими двумя процессами существует двунаправленная связь.

Используя этот пример, вы можете протестировать приложение, отправив все виды данных, и посмотреть, правильно ли оно работает.

Кроме того, вы всегда можете создать символическую ссылку на устройство, поэтому вам не нужно повторно компилировать тестируемое приложение.

Мауро Чианчио
источник
1
while (read (fd, & inputbyte, 1) == 1) {...} чтение не определено в вашем коде. запись не определена. close не определено.
Мэттис Асп,
4

Сможете ли вы использовать адаптер USB-> RS232? У меня их несколько, и они просто используют драйвер FTDI. Затем вы сможете переименовать / dev / ttyUSB0 (или все, что будет создано) как / dev / ttyS2.

ревун
источник
4

Я могу придумать три варианта:

Реализовать RFC 2217

RFC 2217 охватывает COM-порт по стандарту TCP / IP, который позволяет клиенту в одной системе имитировать последовательный порт для локальных программ, при этом прозрачно отправляя и получая данные и управляющие сигналы на сервер в другой системе, которая фактически имеет последовательный порт. Вот общий обзор .

Что вам нужно сделать, так это найти или реализовать драйвер клиентского COM-порта, который будет реализовывать клиентскую часть системы на вашем ПК - он выглядит как настоящий последовательный порт, но на самом деле передает все на сервер. Вы можете получить этот драйвер бесплатно от Digi, Lantronix и т. Д. Для поддержки их реальных автономных серверов с последовательным портом.

Затем вы могли бы реализовать серверную часть соединения локально в другой программе, что позволило бы клиенту подключаться и выдавать данные и команды управления по мере необходимости.

Это, вероятно, нетривиально, но RFC уже существует, и вы можете найти проект с открытым исходным кодом, который реализует одну или обе стороны соединения.

Измените драйвер последовательного порта linux

В качестве альтернативы доступен исходный код драйвера последовательного порта для Linux. Возьмите это, выпотрошите элементы управления оборудованием и пусть один драйвер запускает два порта / dev / ttySx в качестве простой обратной связи. Затем подключите свою реальную программу к ttyS2, а симулятор - к другому ttySx.

Используйте два USB <--> последовательных кабеля в петле

Но что проще сделать прямо сейчас? Потратьте 40 долларов на два USB-устройства с последовательным портом, соедините их вместе (нуль-модем) и получите два реальных последовательных порта - один для программы, которую вы тестируете, другой для вашего симулятора.

-Адам

Адам Дэвис
источник
1
На самом деле нуль-модемные USB-кабели UART кажутся мне довольно элегантным решением, поскольку они поддерживают как локальное тестирование (получите USB-концентратор, если у вас мало портов), так и удаленную отладку.
Макстон Чан
Я не проверял его качество, но ttynvt реализует RFC 2217 через Linux FUSE
Даниэль Сантос,