我有一个应用程序,我想在其中模拟设备和“调制解调器”之间的连接。该设备将连接到串行端口,并通过该端口与软件调制解调器通信。
出于测试目的,我希望能够使用模拟软件设备来测试发送和接收数据。
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 错误消息。
更新
评论向我指出了SO问题 Linux 中是否有像 COM0COM 这样的程序? 使用 socat
设置虚拟串行连接。
我这样使用它:
socat PTY,link=$HOME/COM1 PTY,link=$HOME/COM2
对于你们其他人,谢谢你们给我提供了宝贵的信息。
我选择接受 Vinay Sajips 的回答,因为这是我在 socat 建议出现之前寻求的解决方案。看起来效果很好。
I have an application where I want to simulate the connection between a device and a "modem". The device will be connected to a serial port and will talk to the software modem through that.
For testing purposes I want to be able to use a mock software device to test send and receive data.
Example Python code
device = Device()
modem = Modem()
device.connect(modem)
device.write("Hello")
modem_reply = device.read()
Now, in my final app I will just pass /dev/ttyS1 or COM1 or whatever for the application to use.
But how can I do this in software? I am running Linux and application is written in Python.
I have tried making a FIFO (mkfifo ~/my_fifo
) and that does work, but then I'll need one FIFO for writing and one for reading. What I want is to open ~/my_fake_serial_port
and read and write to that.
I have also lpayed with the pty
module, but can't get that to work either. I can get a master and slave file descriptor from pty.openpty()
but trying to read or write to them only causes IOError Bad File Descriptor
error message.
Update
Comments pointed me to the SO question Are there some program like COM0COM in linux? which uses socat
to setup a virtual serial connection.
I used it like this:
socat PTY,link=$HOME/COM1 PTY,link=$HOME/COM2
To the rest of you, thank you for giving me valuable information.
I chose to accept Vinay Sajips's answer since that is the solution which I went for before the socat suggestion showed up. It seems to work well enough.
发布评论
评论(4)
最好使用 pyserial 与串行端口通信,并且您可以创建一个模拟版本
serial.Serial
类实现了read
、readline
、write
以及您需要的任何其他方法。It's probably best to use pyserial to communicate with the serial port, and you can just create a mock version of the
serial.Serial
class which implementsread
,readline
,write
and any other methods you need.使用伪终端,您走在正确的轨道上。为此,您的模拟软件设备需要首先打开一个伪终端主机 - 这是当它与您正在测试的串行软件通信时将读取和写入的文件描述符。然后需要授予对伪终端从机的访问权限和解锁,并获取从机设备的名称。然后它应该在某处打印出从属设备的名称,以便您可以告诉其他软件打开它,因为它是串行端口(即该软件将打开类似
/dev/pts/0 而不是
/dev/ttyS1
)。然后,模拟器软件仅从伪终端的主端进行读取和写入。在 C 语言中,它看起来像这样:
希望这很容易转换为 Python。
You are on the right track with pseudo-terminals. To do this, your mock software device needs to first open a pseudo-terminal master - this is the file descriptor it will read from and write to, when it is talking to the serial software that you're testing. It then needs to grant access to and unlock the pseudo-terminal slave, and obtain the name of the slave device. It should then print out the name of the slave device somewhere, so that you can tell the other software to open that as it's serial port (ie. that software will be opening a name like
/dev/pts/0
instead of/dev/ttyS1
).The simulator software then just reads and writes from the master side of the pseudoterminal. In C, it would look like this:
Hopefully that is easy enough to convert to Python.
这是一些对我有用的代码(Python 3.10.9 和 pySerial 3.5),使用 posix.openpty() 。它将一端作为文件打开,另一端作为 pySerial 端口打开。
两端都打开作为串口好像不行。我可以将
write()
数据发送到一端,但read()
永远不会在另一端返回。直到我看到这个 pySerial 测试将一端作为文件打开:
https://github.com/pyserial/pyserial/blob/master/test/test_pty.py
Here's some code that worked for me (Python 3.10.9 and pySerial 3.5), using
posix.openpty()
. It opens one end as a file and another as a pySerial port.Opening both ends as a serial port doesn't seem to work. I could
write()
data to one end, butread()
would never return on the other end.I didn't find a workaround until I saw this pySerial test which opens one end as a file:
https://github.com/pyserial/pyserial/blob/master/test/test_pty.py
这是 pts 模拟(caf)串行通信的 pythonic 版本:
它比模拟串行有一些优点,即使用串行代码并执行一些串行端口工件。
如果要测试串口的打开情况,可以交换主从,并使用 os.ttyname(salve_fd) 作为串口名称。不过,我不能保证交换主设备和从设备会产生副作用。最值得注意的是,您可以关闭并重新打开从属设备,但是如果您关闭主从设备也会死亡。
如果您的测试代码在同一进程中运行,这就像一个魅力。我还没有解决多个/单独进程的问题。
Here's pythonic version of pts-emulated (caf's) serial communication:
It has some advantages over mocking Serial, namely that Serial code is used and some serial port artefacts are exercised.
If you want to test opening of serial ports, you could swap master and slave around and use
os.ttyname(salve_fd)
as serial port name. I can't vouch for side-effects of swapping master and slave around though. Most notable is that you can close and reopen slave, but fi you close master slave dies too.This works like a charm if your test code runs within same process. I didn't iron out the kinks with multiple/separate processes yet.