如何编写Python异步串行异步阅读器?

时间:2020-10-22 23:39:51

标签: python-3.x python-asyncio

我正在将一些C ++代码移植到Python,并且花了一点时间来弄清楚如何为串行字节使用onReceive处理程序。我正在使用

import serial_asyncio
class Arduino: #comms is with an Arduino in serial mode)
    async def connect(self, serial_port):
        (self.serial_reader, self.serial_writer) = await 
        serial_asyncio.open_serial_connection(url=serial_port, baudrate=115200)
        print("serial opened:", serial_port)
        self.buffer = b""

    async def recv(self, data):
        self.buffer += data
        self.process_buffer(self.buffer)

if __name__ == '__main__':
     ardunio = Arduino("/dev/ttyS0")         
     loop = asyncio.get_event_loop()
     loop.run_until_complete(ardunio.connect())
     loop.run_forever()

但是,我无法弄清楚如何将recv处理程序修补到读取中。 我可以,我可以:

connect(&QAbstractSocket::readyRead, &Arduino::handleBytes);

在节点中:

arduino.on('data', line => console.log(line))

在Python中,似乎没有明显的答案?我如何获取到达要传递到Arduino.receive(self,data)的串行端口字节?

1 个答案:

答案 0 :(得分:0)

但是我无法弄清楚如何将recv处理程序修补到读取中。

open_serial_connection不是基于回调的接口,它返回一对,它们通过协程公开内容。这样一来,您就可以像编写阻塞代码一样与串行端口进行通信,即无需使用建立数据的回调和缓冲区。例如(未试用):

async def main():
    reader, writer = await serial_asyncio.connect(url="/dev/ttyS0", baudrate=115200)
    # instead of: arduino.on('data', line => console.log(line))
    # ...we can just read some data from the serial port
    data = await reader.read(1024)
    # ...and print it right here
    print(repr(data))

asyncio.run(main())

StreamReader.read这样的协程似乎会阻止等待数据,但实际上它们只是挂起当前的协程,并让事件循环执行其他操作。这样,您就可以轻松地表示超时或在等待数据从串行端口到达时进行其他处理。

如果仍然需要回调,例如由于需要与C API通信,则有两种选择:

  • 使用较低级别的create_serial_connection函数。它接受一个继承asyncio.Protocol的类型,您可以在其中定义类似data_received的钩子(作为回调,而不是协程),这与您为Arduino类建模的方式很接近。

  • 继续使用协程API,但使用add_done_callback注册一个在协程就绪后运行的回调。

后者的一个例子是:

async def main():
    reader, writer = await serial_asyncio.connect(url="/dev/ttyS0", baudrate=115200)
    # Python equivalent of arduino.on('data', x):
    # 1. call reader.read() but don't await - instead, create a "future"
    # which works like a JavaScript Promise
    future = asyncio.ensure_future(reader.read(1024))
    # register a done callback when the result is available
    future.add_done_callback(future, lambda _: print(repr(future.result())))
    # go do something else - here we wait for an event just so main()
    # doesn't exit immediately and terminate our program
    await asyncio.Event().wait()

asyncio.run(main())

但是,除非您与C进行通信,否则使用这种样式与普通的async / await相比没有任何优势。