在另一个线程中中断 pySerial readline

Interrupt a pySerial readline in another thread

我正在使用 pySerial 通过 USB 与微控制器通信,大部分通信由桌面 python 脚本启动,该脚本发送命令包并等待回复。

但也有一个警报数据包可能由微控制器发送,而无需来自 python 脚本的命令。在这种情况下,我需要监视读取流是否有任何警报。

为了处理警报,我专门使用一个单独的进程来调用 readline() 并围绕它循环,如下所示:

    def serialMonitor(self):

        while not self.stopMonitor:
            self.lock.acquire()
            message = self.stream.readline()
            self.lock.release()
            self.callback(message)
  

里面一个class。然后通过

在单独的进程中启动该功能
self.monitor = multiprocessing.Process(target = SerialManager.serialMonitor, args = [self])

无论何时发送命令包,命令函数都需要收回对流的控制,为此它必须中断处于阻塞状态的 readline() 调用。如何中断 readline() 呼叫?有什么方法可以安全地终止进程吗?

您可以使用 .terminate() 终止多处理进程。这安全吗?对于 readline 案例来说可能没问题。

但是,这不是我在这里处理事情的方式。当我阅读你的场景时,有两种可能性:

  • MCU 启动警报包
  • 计算机向 MCU 发送数据(MCU 可能会响应)

我假设在计算机发起的交换正在进行时,MCU 不会发送警报包。

所以我会用一个小超时启动串行对象,并在我不使用它时将其留在循环中。我的整体流程是这样的:

ser = Serial(PORT, timeout=1)
response = None
command_to_send = None
running = True
while running: # event loop
    while running and not command_to_send and not line:
        try:
            line = ser.readline()
        except SerialTimeoutException:
            pass

    if not command_to_send:
        process_mcu_alert(line)

    else:
        send_command(command_to_send)
        command_to_send = None
        response = ser.readline()

这只是一个草图,因为它需要在线程或子进程中 运行,因为 readline() 确实是阻塞的,所以你需要一些线程安全的方式来设置 command_to_sendrunning(用于正常退出)并获得 response,您可能希望将所有这些状态包装在 class 中。具体实现取决于你在做什么,但原理是一样的---有一个循环处理串口的读写,让它超时响应快速(如果需要,您可以设置更小的超时),并让它公开一些您可以处理的接口。

很遗憾,据我所知,python 没有与 asyncio 兼容的串行库,否则这种方法看起来会更整洁。