myka
myka

Reputation: 13

serial_asyncio: read serial port into a queue and read that queue from main() not working

I have a function do_serial() that reads from the serial port and adds the data to a queue. I want to process that queue on main().

I have read the serial_asyncio docs and have a basic echo type proof that reads serial data and echoes it back from a single async function. What I cannot get to work is updating the queue and reading the queue from main().

Once I have this working I also want to update another queue on main() and have that get written to the serial port. This way do_serial() can run async and process the serial port and main() interacts with the queues.

Here is my code:

import queue
import asyncio
import serial_asyncio

incoming_serial_queue = queue.Queue()

async def do_serial():
    reader, writer = await serial_asyncio.open_serial_connection(url='/dev/ttyS0', baudrate=9600)
    while True:
        # read serial port
        data = await reader.readline()

        # echo back to serial port for verification
        writer.write(incoming_serial_queue.get)

        # add data to queue
        incoming_serial_queue.put(data)        

async def main():
    while True:
        # read queued data from serial port
        await print(incoming_serial_queue.get())

asyncio.run(do_serial())
asyncio.run(main())

Upvotes: 1

Views: 3035

Answers (1)

furas
furas

Reputation: 142859

I'm not specialist for asyncio but I created some working code - so don't ask why something doesn't work :)

I can't run serial_asyncio so I used datetime to generate some data for queue

You can't use run() to start two processes at the same time. run() starts one process and waits for its end - so run(do_serial()) starts function do_serial and waits for its end - and this way it never runs main. If you change order then run(main()) will wait for end of main and it will never run do_serial

So I used run() to start one function which use create_task() for do_serial() and main(). I had to first create task and later use them with await because in other way it didn't start main and I don't know why.

Other problem with asyncio: await can't work with every function - it will not work with standard print(). You would have to create special print() for it. Or maybe you have special print() from serial_asyncio - I don't know.

In both functions I used asyncio.sleep() to have some function with await

Problem with queue: when there is no data in queue then get() may block code and it is better to check first if it is not empty()

import queue
import asyncio
import datetime

incoming_serial_queue = queue.Queue()

async def do_serial():
    print("do serial")
    while True:
        data = str(datetime.datetime.now())
        print('put:', data)

        # add data to queue
        incoming_serial_queue.put(data)

        await asyncio.sleep(2)

async def main():
    print("main")
    while True:
        # read queued data from serial port
        if not incoming_serial_queue.empty():
            data = incoming_serial_queue.get()
            print('get:', data)

        await asyncio.sleep(1) 

async def start():
    print("start")
    #await do_serial()  # doesn't work
    #await main()       # doesn't work

    # I had to create all tasks before running
    task1 = asyncio.create_task(do_serial())
    task2 = asyncio.create_task(main())

    # running task
    await task1
    await task2

asyncio.run(start())

EDIT:

I could run two functions using asyncio.gather()

async def start():
    print("start")
    await asyncio.gather(
        do_serial(),
        main(),
    )

Rest is the same as in my previous code

import queue
import asyncio
import datetime

incoming_serial_queue = queue.Queue()

async def do_serial():
    print("do serial")
    while True:
        data = str(datetime.datetime.now())
        print('put:', data)

        # add data to queue
        incoming_serial_queue.put(data)

        await asyncio.sleep(2)    

async def main():
    print("main")
    while True:
        # read queued data from serial port
        if not incoming_serial_queue.empty():
            data = incoming_serial_queue.get()
            print('get:', data)

        await asyncio.sleep(1) 

async def start():
    print("start")
    await asyncio.gather(
        do_serial(),
        main(),
    )

asyncio.run(start())

Upvotes: 1

Related Questions