如何在Python中使用伪终端模拟串口?

5 投票
3 回答
5515 浏览
提问于 2025-04-17 17:40

我正在用Twisted框架创建一个Python应用程序,这个程序可以从串口读取数据。为了能够测试这个应用,而不需要真的连接一个设备到串口(甚至在没有实际串口的电脑上),我想写一个Python脚本或应用,来设置一个虚拟串口,并向它写入数据。这样,Twisted应用就可以连接到这个虚拟串口的另一端,并从中读取数据。这样我就可以写一些单元测试了。

我发现,在Linux系统中可以通过伪终端实现这个功能。我还找到一个在https://askubuntu.com/questions/9396/virtual-serial-port-for-testing-purpose上的示例脚本,能够正常工作。

我想把那个脚本改成一个类,这样我就可以调用一个写入方法,把数据写入串口,然后测试我的Twisted应用。

这个示例脚本使用了很多我不太理解的东西,比如poll、select和Linux的stty命令。我希望有人能帮我填补这些知识的空白,或者给我一些提示。

谢谢,

Dolf.

3 个回答

0

一个更好的方法可能是使用软件虚拟串口模拟器。

你可以在 github 上找到适用于Linux的版本,在 sourceforge 上找到适用于Windows的版本。

在Linux上,它叫做tty0tty,你只需要输入

make

来构建所有内容。然后你需要输入

sudo insmod module/tty0tty.ko

来安装这个虚拟驱动程序,接着输入

./pts/tty0tty

来启动这个应用程序,这样就会为你打开两个虚拟端口:/dev/pts/4 和 /dev/pts/6。

然后你可以在你的Python单元测试中打开 /dev/pts/4 串口,而在你的应用程序中打开 /dev/pts/6。

在你的Python单元测试中,你只需要输入类似这样的内容:

import serial 
ser = serial.Serial('/dev/pts/4', 19200)
3

除了Jean-Paul Calderone说的那些(他给的答案基本上是对的),我还写了一个用Python做的脚本,使用了socat。

这个脚本可以被导入到一个解释器中,然后你可以用它的writeLine方法向一个(虚拟的)串口写数据。这个串口通过socat连接到另一个(虚拟的)串口,另外一个twisted应用可以在这个串口上监听。不过正如Jean-Paul Calderone所说:如果你只是想做单元测试,其实不需要搞这些。直接看看他提到的文档就行了。

import os, subprocess, serial, time
from ConfigParser import SafeConfigParser


class SerialEmulator(object):
    def __init__(self,configfile):
        config=SafeConfigParser()
        config.readfp(open(configfile,'r'))
        self.inport=os.path.expanduser(config.get('virtualSerialPorts','inport'))
        self.outport=os.path.expanduser(config.get('virtualSerialPorts','outport'))
        cmd=['/usr/bin/socat','-d','-d','PTY,link=%s,raw,echo=1'%self.inport,'PTY,link=%s,raw,echo=1'%self.outport]
        self.proc=subprocess.Popen(cmd,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
        time.sleep(3)
        self.serial=serial.Serial(self.inport)
        self.err=''
        self.out=''
    def writeLine(self,line):
        line=line.strip('\r\n')
        self.serial.write('%s\r\n'%line)
    def __del__(self):
        self.stop()
    def stop(self):
        self.proc.kill()
        self.out,self.err=self.proc.communicate()
1

你并不需要一个伪终端(pty)来测试你的协议。其实你甚至不需要任何类型的文件描述符。可以按照这个链接的指南来做:http://twistedmatrix.com/documents/current/core/howto/trial.html,特别是里面的 测试协议 这一部分。

撰写回答