Linux 的虚拟串行端口
Posted
技术标签:
【中文标题】Linux 的虚拟串行端口【英文标题】:Virtual Serial Port for Linux 【发布时间】:2010-09-08 07:22:42 【问题描述】:我需要在 Linux 上测试一个串口应用程序,但是我的测试机只有一个串口。
有没有办法向 Linux 添加虚拟串行端口并通过 shell 或脚本模拟设备来测试我的应用程序?
注意:我无法重新映射端口,它在 ttys2 上硬编码,我需要在编写应用程序时对其进行测试。
【问题讨论】:
【参考方案1】:您可以使用 USB->RS232 适配器吗?我有几个,他们只使用 FTDI 驱动程序。然后,您应该能够将 /dev/ttyUSB0 (或创建的任何内容)重命名为 /dev/ttyS2 。
【讨论】:
【参考方案2】:我能想到三个选项:
实施 RFC 2217
RFC 2217 涵盖了 TCP/IP 标准的 com 端口,允许一个系统上的客户端模拟本地程序的串行端口,同时透明地向另一个系统上的服务器发送和接收数据和控制信号,该服务器实际上具有串口。这是high-level overview。
您要做的是找到或实现一个客户端 com 端口驱动程序,该驱动程序将在您的 PC 上实现系统的客户端 - 看起来是一个真正的串行端口,但实际上将所有东西都传送到服务器。您也许可以从 Digi、Lantronix 等公司免费获得此驱动程序,以支持他们真正的独立串行端口服务器。
然后,您将在另一个程序中本地实现连接的服务器端 - 允许客户端根据需要进行连接并发出数据和控制命令。
这可能不简单,但 RFC 已经存在,您或许可以找到一个实现连接的一侧或两侧的开源项目。
修改linux串口驱动
另外,Linux 的串行端口驱动程序源也很容易获得。拿那个,拆掉硬件控制部分,让一个驱动程序运行两个 /dev/ttySx 端口,作为一个简单的环回。然后将您的真实程序连接到 ttyS2,将您的模拟器连接到另一个 ttySx。
使用两个 USB串行电缆环回
但是现在最容易做的事情是什么?花 40 美元购买两个串行端口 USB 设备,将它们连接在一起(零调制解调器),实际上有两个真正的串行端口 - 一个用于您正在测试的程序,一个用于您的模拟器。
-亚当
【讨论】:
实际上,零调制解调器 USB UART 电缆对我来说似乎是一个非常优雅的解决方案,因为它支持本地测试(如果端口不足,请使用 USB 集线器)和远程调试。 我还没有审查它的质量,但是ttynvt 通过 Linux FUSE 实现了 RFC 2217【参考方案3】:您可以为此使用 pty(“伪电传打字机”,其中串行端口是“真正的电传打字机”)。从一端打开/dev/ptyp5
,然后将你的程序附加到/dev/ttyp5
; ttyp5
就像一个串行端口,但会通过 /dev/ptyp5 发送/接收它所做的一切。
如果您确实需要它来与名为 /dev/ttys2
的文件通信,那么只需将旧的 /dev/ttys2
移开,并创建一个从 ptyp5
到 ttys2
的符号链接。
当然,您可以使用ptyp5
以外的其他号码。也许选择一个数字大的以避免重复,因为您所有的登录终端也将使用 ptys。
***有更多关于 ptys 的信息:http://en.wikipedia.org/wiki/Pseudo_terminal
【讨论】:
在 linux 上你可以使用 openpty / forkpty 系统调用。见man page 如何使用命令行工具创建虚拟串口对? 注意很多串口参数,例如波特率、奇偶校验、硬件流控制、字符大小 (?) 未在 pty 中实现,因此无法在存在串行传输错误的情况下测试您的应用程序。 这很有帮助,但它描述了“旧式”BSD 伪终端。 “新型” UNIX 98 伪终端的操作方式略有不同——详情请参阅pts
man page。
@LaszloPapp 对不起,我一直在撒谎【参考方案4】:
您可能想查看Tibbo VSPDL 使用内核驱动程序创建 linux 虚拟串行端口——它看起来很新,现在可以下载(测试版)。目前不确定许可证,或者他们是否希望仅在未来将其商业化。
还有其他商业替代品,例如http://www.ttyredirector.com/。
在开源中,Remserial (GPL) 也可以使用 Unix PTY 做你想做的事。它将“原始形式”的串行数据传输到网络套接字;在创建端口时必须完成类似 STTY 的终端参数设置,稍后像 RFC 2217 中描述的那样更改它们似乎不受支持。您应该能够运行两个 remserial 实例来创建像 com0com 这样的虚拟 nullmodem,但您需要提前设置端口速度等。
Socat(也是 GPL)就像 Remserial 的扩展变体,具有更多选项,包括用于将 PTY 重定向到其他东西的“PTY”方法,它可以是 Socat 的另一个实例。对于 Unit tets,socat 可能比 remserial 更好,因为您可以直接将文件 cat 放入 PTY。请参阅联机帮助页上的 PTY example。 “contrib”下的patch exists 为协商串行线路设置提供RFC2217 支持。
【讨论】:
【参考方案5】:使用先前答案中发布的链接,我使用虚拟串行端口在 C++ 中编写了一个小示例。我将代码推送到了 GitHub:https://github.com/cymait/virtual-serial-port-example。
代码很容易解释。首先,您通过运行 ./main master 创建主进程,它将打印到设备正在使用的 stderr。之后,调用 ./main slave device,其中 device 是第一个命令中打印的设备。
就是这样。您在这两个进程之间建立了双向链接。
使用此示例,您可以通过发送各种数据来测试您的应用程序,并查看它是否正常工作。
此外,您始终可以对设备进行符号链接,因此您无需重新编译正在测试的应用程序。
【讨论】:
while (read(fd, &inputbyte, 1) == 1) ... read 在您的代码中未定义。写是未定义的。关闭未定义。 @MattisAsp 有一点,你至少应该包括<unistd.h>
。另外还有一堆不应该忽略的警告可修复的东西,但我喜欢整体简单的代码。【参考方案6】:
为此使用 socat:
例如:
socat PTY,link=/dev/ttyS10 PTY,link=/dev/ttyS11
【讨论】:
这对我来说效果很好,用 minicom 测试过!似乎一个终端的输入会回显到两个终端(因此它也会重新出现在输入终端上)。 我没有相同的回显行为... minicom 具有“本地回显”功能...但是当它被禁用时,它的工作方式与真正的串行端口完全相同。感谢您的提示。 如果没有特殊权限,这似乎不起作用:``` 2021/12/10 16:08:47 socat[90013] E unlink("/dev/ttyS10"): Permission denied ` ``【参考方案7】:还有 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 不起作用。该代码似乎是从一些“小 tty”示例代码中复制而来的。 TIOCMIWAIT 的处理似乎到位,但它永远不会唤醒,因为缺少对 wake_up_interruptible() 的相应调用。
编辑:
办公室的车祸确实是司机的错。缺少初始化,完全未经测试的 TIOCMIWAIT 代码导致机器崩溃。
我昨天和今天都在重写驱动程序。有很多问题,但现在对我来说效果很好。驱动程序管理的硬件流控制仍然缺少代码,但我不需要它,因为我将使用用户模式代码中的 TIOCMGET/TIOCMSET/TIOCMIWAIT 自己管理引脚。
如果有人对我的代码版本感兴趣,请给我发消息,我会发给你。
【讨论】:
我很想看看你的代码。你能把它贡献回 tty0tty 项目吗?但是,我更希望看到人们改进 Linux 内核中的伪终端代码。例如。添加硬件握手支持和 TIOCMIWAIT。 "如果有人对我的代码版本感兴趣,请给我发消息,我会发给你。"是的,我很感兴趣!你能在某个地方指出它吗,例如在 GitHub 上? 我把驱动上传到:github.com/pitti98/nullmodem 抱歉这么久才回复。我在 *** 上不是很活跃,忽略了你的评论! 不,我写它是因为我需要它,一旦它足够好,可以做我想做的事,我就停止了。现在它是公开的,我希望它对其他人有用,也许有人会在我离开的地方捡起它。【参考方案8】:补充@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 端口文件,并且不会回显。 如果您想要可重现的文件名,请在每个设备声明之后(在 echo=0 之后)使用link=/path/to/link
。因此,它可以用于自动化测试。 (正如 slonik 在他们的回答中所做的那样)
创建一个链接到真实串行端口的 pty:socat -d -d pty,raw,echo=0 /dev/ttyUSB5,raw,echo=0
。
我可以创建一个名称为/dev/ttyS0
而不是/dev/pts/1
的串行端口吗?
我试过这个,但我只能打开一次,(使用 c# SerialPort)即使我在尝试连接新实例之前处理它总是在打开时崩溃【参考方案9】:
$ socat -d -d pty,link=/tmp/vserial1,raw,echo=0 pty,link=/tmp/vserial2,raw,echo=0
将为/dev/pts/*
中生成的虚拟串口生成/tmp/vserial1
和/tmp/vserial2
的符号链接
Resource
【讨论】:
以上是关于Linux 的虚拟串行端口的主要内容,如果未能解决你的问题,请参考以下文章
使用 node.js 访问虚拟串行端口会给出错误或没有打开事件