我知道还有其他问题与我的问题非常相似,但没有一个问题可以解决我遇到的问题。
我想使用pyserial
来访问串口(/dev/tty...
),但前提是其他进程尚未打开它。
以下代码段在我的Ubuntu 12.04计算机上返回四个可用端口,运行一次。如果我第二次运行它,我预计没有可用的端口。遗憾的是,返回了相同的端口列表。似乎pyserial
无法识别另一个进程已经打开了端口。
我希望抛出SerialException
,或者isOpen()
方法返回False,但pyserial
会多次打开。
import serial
from serial import tools
from serial.tools import list_ports
def available_ttys():
for tty in serial.tools.list_ports.comports():
try:
port = serial.Serial(port=tty[0])
if port.isOpen():
yield port
except serial.SerialException as ex:
print 'Port {0} is unavailable: {1}'.format(tty, ex)
def main():
ttys = []
for tty in available_ttys():
ttys.append(tty)
print tty
input('waiting ...')
if __name__ == '__main__':
main()
无论我并行运行多少次,这都是输出:
Port ('/dev/ttyS31', 'ttyS31', 'n/a') is unavailable: Could not configure port: (5, 'Input/output error')
...
Port ('/dev/ttyS0', 'ttyS0', 'n/a') is unavailable: Could not configure port: (5, 'Input/output error')
Serial<id=0x7fca9d9f1c90, open=True>(port='/dev/ttyUSB1', baudrate=9600, bytesize=8, parity='N', stopbits=1, timeout=None, xonxoff=False, rtscts=False, dsrdtr=False)
Serial<id=0x7fca9d9f1cd0, open=True>(port='/dev/ttyACM2', baudrate=9600, bytesize=8, parity='N', stopbits=1, timeout=None, xonxoff=False, rtscts=False, dsrdtr=False)
Serial<id=0x7fca9d9f1e50, open=True>(port='/dev/ttyACM1', baudrate=9600, bytesize=8, parity='N', stopbits=1, timeout=None, xonxoff=False, rtscts=False, dsrdtr=False)
Serial<id=0x7fca9d9f1ed0, open=True>(port='/dev/ttyACM0', baudrate=9600, bytesize=8, parity='N', stopbits=1, timeout=None, xonxoff=False, rtscts=False, dsrdtr=False)
waiting ...
答案 0 :(得分:8)
正如@VooDooNOFX所说,防止其他进程打开同一个端口(设备)没有技术限制。但是,在Linux上,您可以锁定该文件以防止您的应用程序多次使用同一端口。
import fcntl, serial
s = serial.Serial(0)
fcntl.flock(s.fileno(), fcntl.LOCK_EX | fcntl.LOCK_NB)
在这种情况下,您的应用程序将尝试在串行端口上获取独占锁(LOCK_EX
)。感谢LOCK_NB
,如果任何其他进程已经锁定了串行端口,则调用将立即失败 - 通过在Python 3.3中引发IOError
(或BlockingIOError
子异常)。
与其他解决方案相比,这有两个优势:
所以,你的功能看起来像是:
def available_ttys():
for tty in serial.tools.list_ports.comports():
try:
port = serial.Serial(port=tty[0])
if port.isOpen():
try:
fcntl.flock(port.fileno(), fcntl.LOCK_EX | fcntl.LOCK_NB)
except IOError:
print 'Port {0} is busy'.format(tty)
else:
yield port
except serial.SerialException as ex:
print 'Port {0} is unavailable: {1}'.format(tty, ex)
答案 1 :(得分:3)
Linux中没有任何内容可以阻止多个进程打开相同的串行端口。因此,为什么pyserial库能够做到这一点。然而,有一个标准的公约在其他地方有很好的记录:https://superuser.com/questions/488908/sharing-a-serial-port-between-two-processes
通用流程要求您打开设备,然后在/tmp
或/var/lock
目录中创建包含PID的文本文件。第二个脚本将搜索此文件的存在,并拒绝打开它存在的端口。