6

我知道还有其他问题与我的非常相似,但没有一个能解决我遇到的问题。

我想pyserial用来访问串行端口(/dev/tty...),但前提是另一个进程尚未打开它。

以下片段在运行一次时返回我的 Ubuntu 12.04 机器上的四个可用端口。如果我第二次运行它,我希望没有可用的端口。可悲的是,返回了相同的端口列表。似乎pyserial无法识别另一个进程已经打开了该端口。

我希望 aSerialException被抛出,或者该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 ...
4

2 回答 2

9

正如@VooDooNOFX 所说,阻止其他进程打开同一端口(设备)没有技术限制。但是,在 Linux 上,您可以锁定文件以防止您的应用程序多次使用同一个端口。

import fcntl, serial

s = serial.Serial(0)
fcntl.flock(s.fileno(), fcntl.LOCK_EX | fcntl.LOCK_NB)

在这种情况下,您的应用程序将尝试获取LOCK_EX串行端口上的排他锁 ( )。多亏了LOCK_NB,如果任何其他进程已经通过引发IOError(或BlockingIOErrorPython 3.3 中的子异常)锁定了串行端口,调用将立即失败。

与其他解决方案相比,这有两个优点:

  1. 您没有引入任何非标准文件,而是使用系统提供的方法,带来更好的互操作性,
  2. 当您的进程退出时,锁会立即释放,因此您不必担心过时的锁。

所以,你的函数看起来像:

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)
于 2013-11-06T21:24:04.300 回答
3

Linux 中没有任何东西可以阻止多个进程打开同一个串行端口。因此,为什么 pyserial 库能够做到这一点。然而,有一个标准的约定,在其他地方有很好的记录:https ://superuser.com/questions/488908/sharing-a-serial-port-between-two-processes

通用过程要求您打开设备,然后在包含您的 PID的一个/tmp或多个目录中创建一个文本文件。/var/lock第二个脚本会搜索这个文件的存在,并拒绝打开它存在的端口。

有关更多信息,请参阅:http ://www.tldp.org/HOWTO/Serial-HOWTO-13.html

于 2013-11-06T20:59:52.690 回答