Search code examples
pythonpyserialuart

Read from two serial ports asynchronously


I'd like to read from two (or more) serial ports (/dev/ttyUSB0 etc) at the same time in python on Linux. I want to read complete lines from each port (whichever has data) and process the results in the order received (without race conditions). As a simple example could just write the lines to a single merged file.

I assume the way to do this is based on pyserial, but I can't quite figure out how to do it. Pyserial has non-blocking reads using asyncio and using threads. Asyncio is marked as experimental. I assume there wouldn't be any race conditions if the processing is done in asyncio.Protocol.data_received(). In the case of threads, the processing would probably have to be protected by a mutex.

Perhaps this can also be done not in pyserial. The two serial ports can be opened as files and then read from when data is available using select().


Solution

  • As suggested by @AlexHall in a comment, here is a solution that uses one thread for each serial port and a queue to synchronize access:

    import serial
    import Queue
    import threading
    
    queue = Queue.Queue(1000)
    
    def serial_read(s):
        while True:
            line = s.readline()
            queue.put(line)
    
    serial0 = serial.Serial('/dev/ttyUSB0')
    serial1 = serial.Serial('/dev/ttyUSB1')
    
    thread1 = threading.Thread(target=serial_read, args=(serial0,),).start()
    thread2 = threading.Thread(target=serial_read, args=(serial1,),).start()
    
    while True:
        line = queue.get(True, 1)
        print line
    

    It may be possible to write this more elegantly, but it works.