Linux下的虚拟串行通信
我有一个应用程序,想要模拟一个设备和“调制解调器”之间的连接。这个设备会连接到一个串口,通过这个串口和软件调制解调器进行通信。
为了测试,我希望能使用一个虚拟的软件设备来测试发送和接收数据。
下面是一个示例的Python代码
device = Device()
modem = Modem()
device.connect(modem)
device.write("Hello")
modem_reply = device.read()
在我的最终应用中,我只需要传递 /dev/ttyS1 或 COM1 之类的路径供应用使用。但我该如何在软件中实现这个呢?我正在使用Linux,而应用是用Python编写的。
我尝试过创建一个FIFO(mkfifo ~/my_fifo
),这个方法是有效的,但我需要一个FIFO用于写入,一个用于读取。我想要的是打开~/my_fake_serial_port
,然后可以在里面读写。
我也试过pty
模块,但也没能成功。我可以通过pty.openpty()
获得一个主文件描述符和一个从文件描述符,但尝试读取或写入时总是出现IOError Bad File Descriptor
的错误信息。
更新
有评论提醒我去看一个StackOverflow的问题 在Linux中有没有类似COM0COM的程序?,这个问题提到使用socat
来设置一个虚拟串口连接。我是这样使用的:
socat PTY,link=$HOME/COM1 PTY,link=$HOME/COM2
感谢其他人提供的宝贵信息。我选择接受Vinay Sajips的回答,因为这是我在看到socat建议之前就已经尝试过的解决方案。看起来效果还不错。
4 个回答
这里有一个用Python写的pts-emulated(caf的)串口通信的版本:
from serial import Serial
driver = MyDriver() # what I want to test
peer = serial.Serial()
driver.port.fd, peer.fd = posix.openpty()
driver.port._reconfigurePort()
peer.setTimeout(timeout=0.1)
peer._reconfigurePort()
driver.start()
# peer.write("something")
# driver.get_data_from_serial()
这个方法比模拟串口的方式有一些好处,主要是它使用了真实的串口代码,并且能测试一些串口的特性。
如果你想测试打开串口的功能,可以把主设备和从设备的位置调换,然后用os.ttyname(salve_fd)
来作为串口的名称。不过,我不能保证调换主从设备会有什么副作用。最明显的一点是,你可以关闭并重新打开从设备,但如果你关闭了主设备,从设备也会随之失效。
如果你的测试代码在同一个进程中运行,这个方法效果很好。不过,我还没有解决在多个或独立进程中运行时可能出现的问题。
你现在的方向是对的,关于伪终端的使用。要做到这一点,你的模拟软件设备首先需要打开一个伪终端主设备——这就像是一个文件通道,它会用来和你正在测试的串口软件进行读写交流。接下来,它需要给伪终端从设备授权并解锁,然后获取从设备的名称。之后,它应该把这个从设备的名称打印出来,这样你就可以告诉其他软件去把它当作串口来打开(也就是说,那个软件会打开像 /dev/pts/0
这样的名称,而不是 /dev/ttyS1
)。
然后,模拟软件就可以在伪终端的主设备那边进行读写操作。在C语言中,它的写法大概是这样的:
#define _XOPEN_SOURCE
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
int main(int argc, char *argv[])
{
int pt;
pt = open("/dev/ptmx", O_RDWR | O_NOCTTY);
if (pt < 0)
{
perror("open /dev/ptmx");
return 1;
}
grantpt(pt);
unlockpt(pt);
fprintf(stderr, "Slave device: %s\n", ptsname(pt));
/* Now start pretending to be a modem, reading and writing "pt" */
/* ... */
return 0;
}
希望这个内容转换成Python会比较简单。
最好使用 pyserial 来和串口进行通信。你可以创建一个模拟版本的 serial.Serial
类,这个类可以实现 read
、readline
、write
以及你需要的其他方法。