Linux的虚拟串口

Virtual Serial Port for Linux


问题

我需要在Linux上测试一个串口应用,但是,我的测试机器只有一个串口。

有没有办法在Linux上添加一个虚拟串口,通过shell或脚本模拟设备来测试我的应用程序?

注意:我不能重新映射端口,它硬编码在ttys2上,我需要测试应用程序的编写。

答案1

补充一下@slonik的回答。

你可以测试socat来创建虚拟串口,做以下程序(在Ubuntu 12.04上测试)。

打开一个终端(我们称它为终端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,你会看到字符串 "Test"。

这对我来说比slonik的答案更好,因为它自动分配到虚拟COM端口文件,而且没有回音。
如果你想要可重复的文件名,在每个设备声明后使用 link=/path/to/link (在echo=0后)。因此,它可以被用于自动测试。(正如slonik在他们的答案中所做的那样)
这和提到的完全一样。它帮助了我,谢谢。
要创建一个链接到真正的串行端口的pty: socat -d -d pty,raw,echo=0 /dev/ttyUSB5,raw,echo=0 .
我可以创建一个名称为 /dev/ttyS0 而不是 /dev/pts/1 的串口吗?
答案2

你可以使用pty("伪电传",而串口是 "真电传")来做这个。 从一端打开 /dev/ptyp5 ,然后将你的程序连接到 /dev/ttyp5ttyp5 将像串口一样行动,但将通过/dev/ptyp5发送/接收它所做的一切。

如果你真的需要它与一个叫做 /dev/ttys2 的文件对话,那么只要将你原来的 /dev/ttys2 移开,从 ptyp5ttys2 做一个符号链接。

当然,你可以使用 ptyp5 以外的一些数字。

维基百科有更多关于ptys的内容: http://en.wikipedia.org/wiki/Pseudo_terminal

在linux上,你可以使用openpty / forkpty系统调用。 见 man page
如何使用命令行工具创建一个虚拟串口对?
注意许多串口参数,例如波特率、奇偶校验、HW流量控制、字符大小(?)都没有在pty中实现,因此不可能在串口传输错误的情况下测试你的应用程序。
这很有帮助,但它描述的是 "旧式 "BSD伪终端的情况。新式的 "UNIX 98伪终端 "的操作方式有点不同--详见 pts man page
@LaszloPapp 我真的很抱歉,我一直在撒谎
答案3

用socat来做这个:

例如:

socat PTY,link=/dev/ttyS10 PTY,link=/dev/ttyS11
这对我来说效果很好,用minicom进行了测试! 似乎对一个终端的输入会被呼应到两个终端(所以它也会重新出现在输入终端上)。
我没有同样的回声行为......minicom有一个 "本地回声 "功能......但当它被禁用时,它的工作方式与真正的串口完全一样。谢谢你的提示。
答案4

还有tty0tty http://sourceforge.net/projects/tty0tty/ 它是一个真正的linux空调制解调器模拟器。

它是一个简单的内核模块--一个小的源代码文件。我不知道为什么它在sourceforge上只得到了大拇指,但它对我来说很有效。它最好的地方是它也模拟了硬件引脚(RTC/CTS DSR/DTR)。它甚至实现了TIOCMGET/TIOCMSET和TIOCMIWAIT iotcl命令。

在最近的内核上,你可能会出现编译错误。这很容易解决。只要在模块/tty0tty.c源代码的顶部插入几行(在includes之后)。

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

当模块被加载时,它创建了4对串行端口。这些设备是/dev/tnt0到/dev/tnt7,其中tnt0与tnt1相连,tnt2与tnt3相连,等等。 你可能需要修改文件的权限,以便能够使用这些设备。

编辑:

我想我的热情有点快。虽然这个驱动程序看起来很有希望,但它似乎不稳定。我不确定,但我认为它使我在家里工作的办公室里的一台机器崩溃了。在我星期一回到办公室之前,我无法检查。

第二件事是,TIOCMIWAIT不起作用。这段代码似乎是从一些 "tiny tty "的示例代码中复制的。对TIOCMIWAIT的处理似乎到位了,但它从未被唤醒,因为缺少对wake_up_interruptible()的相应调用。

编辑:

办公室里的崩溃确实是驱动程序的错。有一个初始化缺失,完全未经测试的TIOCMIWAIT代码导致了机器的崩溃。

我昨天和今天都在重写驱动程序。有很多问题,但现在它对我来说运行良好。仍然缺少由驱动管理的硬件流控制的代码,但我不需要它,因为我将在用户模式代码中使用TIOCMGET/TIOCMSET/TIOCMIWAIT自己管理引脚。

如果有人对我的代码版本感兴趣,给我发个信息,我就把它发给你。

我很想看看你的代码。你能把它贡献给tty0tty项目吗?然而,我更希望看到人们改进Linux内核中的伪终端代码。例如,增加硬件握手支持和TIOCMIWAIT。
"如果有人对我的代码版本感兴趣,给我发个信息,我就把它发给你。" 是的,我很感兴趣! 你能把它指向某个地方吗,例如GitHub上?
我把驱动程序上传到了。 github.com/pitti98/nullmodem 抱歉这么久才回复。我在stackoverflow上不是很活跃,忽略了你的评论!
不,我写它是因为我需要它,一旦它足够好,可以做我想做的事,就停止了。现在它被公开了,我希望它对其他人有用,也许有人会接上我留下的东西。
答案5

你可能想看看 Tibbo VSPDL ,用内核驱动创建一个Linux虚拟串口 -- 它似乎很新,而且现在可以下载(测试版)。目前还不清楚许可证的情况,也不知道他们是否想在将来把它作为商业用途。

还有其他的商业替代品,比如 http://www.ttyredirector.com/

在开放源码中, Remserial (GPL)也可能做你想做的事,使用Unix PTY的。它将串行数据以 "原始形式 "传输到网络套接字;类似于STTY的终端参数设置必须在创建端口时完成,像RFC 2217中描述的那样随后改变它们似乎并不被支持。你应该能够运行两个remserial实例来创建一个像com0com一样的虚拟空模,只是你需要提前设置端口速度等。

Socat (也是GPL)就像Remserial的一个扩展变体,有很多很多的选项,包括一个将PTY重定向到其他东西的 "PTY "方法,它可以是Socat的另一个实例。对于Unit tets来说,Socat可能比Remserial更好,因为你可以直接把文件猫到PTY中。见manpage上的 PTY例子 。在 "contrib "下有一个 补丁 ,为协商串行线设置提供RFC2217支持。

答案6

利用前面答案中的链接,我用C++编写了一个使用虚拟串口的小例子。我把代码推送到GitHub。 https://github.com/cymait/virtual-serial-port-example .

该代码是不言自明的。首先,你通过运行./main master创建主进程,它将把设备的使用情况打印到stderr。之后,你调用./main slave device,其中device是第一个命令中打印的设备。

就这样了。你在两个进程之间有了一个双向的链接。

使用这个例子,你可以通过发送各种数据来测试你的应用程序,看看它是否工作正常。

另外,你可以随时对设备进行符号连接,所以你不需要重新编译你正在测试的应用程序。

while (read(fd, &inputbyte, 1) == 1) { ... } read在你的代码中是未定义的。 write是未定义的。 close是未定义的。
@MattisAsp说得有道理,你至少应该包括 <unistd.h> 。另外还有一堆不应该忽略的警告,可以修复的东西,但总的来说,我喜欢简单的代码。
答案7

你能不能用一个USB->RS232适配器?我有几个,它们只是使用FTDI的驱动程序。然后,你应该能够将/dev/ttyUSB0(或任何被创建的)重命名为/dev/ttyS2。

答案8

我可以想到三种选择:

实施RFC 2217

RFC 2217 涵盖了一个com port to TCP/IP标准,它允许一个系统上的客户端模拟本地程序的串口,同时透明地发送和接收数据和控制信号到另一个系统上的服务器,该系统实际上拥有串口。 下面是一个 高层次的概述

你要做的是找到或实现一个客户端COM端口驱动程序,它将在你的PC上实现系统的客户端--看起来是一个真正的串行端口,但实际上是把所有东西都传送到服务器上。 你也许能从Digi、Lantronix等公司免费获得这种驱动程序,以支持他们真正的独立串口服务器。

然后你将在另一个程序中实现本地连接的服务器端--允许客户端连接并根据需要发布数据和控制命令。

这可能不是小事,但RFC就在那里,你也许能找到一个开源项目来实现连接的一个或两个方面。

修改Linux的串口驱动

另外,Linux的串口驱动源也很容易得到。 拿着它,去掉硬件控制部分,让这个驱动运行两个/dev/ttySx端口,作为一个简单的环回。 然后把你的真实程序连接到ttyS2上,把你的模拟器连接到另一个ttySx上。

在环回中使用两个USB<-->串行电缆

但现在最容易做的事情是什么? 花40美元买两个串口USB设备,把它们连在一起(null modem),实际上有两个真正的串口--一个用于你测试的程序,一个用于你的模拟器。

-Adam

实际上,对我来说,null modem USB UART电缆似乎是一个相当优雅的解决方案,因为它既支持本地测试(如果你的端口不足,可以买一个USB集线器),又支持远程调试。
我没有评论它的质量,但是 ttynvt 通过Linux FUSE实现了RFC 2217
答案9
$ socat -d -d pty,link=/tmp/vserial1,raw,echo=0 pty,link=/tmp/vserial2,raw,echo=0

将为 /dev/pts/* 中生成的虚拟串行端口生成 /tmp/vserial1/tmp/vserial2 的符号链接

资源

相同问题还可以参考: Virtual Serial Port for Linux