Search code examples
pythonmultithreadingflaskpyserial

PySerial Error: Device reports readiness to read but returned no data (Possible concurrency issue?)


Issue: I am working on a class project to create a Flask project that, among other things, reads from a USB RFID reader. When the Flask app is run and I scan a badge with the reader it throws the exception:

serial.serialutil.SerialException: device reports readiness to read but returned no data (device disconnected or multiple access on port?)

multiple times (the reader is being listened at in a continuous loop).

Environment:
Ubuntu 22.04 Python 3.10.6

Tested: Verified that the card reader is functional and connected via:

sudo cat /dev/ttyUSB0

This produces the expected output to the terminal when badge is scanned. Changed the port permissions using:

sudo chmod a+rw /dev/ttyUSB0

Verified that a test script can access the reader in a loop as expected. Verified that the loop works as expected in the Flask app without threading.

Reviewed: https://realpython.com/intro-to-python-threading/

Python reading from serial (Increasing the timeout gave me "Error reading data from serial port: invalid literal for int() with base 16: ''" instead; other things I tried brought the original error back.

Python SerialException: Device reports readiness to read but returned no data (device disconnected?)

My code:

import serial
import threading

ser_lock = threading.Lock()

# Function for reading from serial port
def serial_data():
    PORT = "/dev/ttyUSB0" # Hardcoded for now - needs to be fixed - menu?
    BAUD = 9600

    ser = None

    try:
        ser = serial.Serial(port=PORT, baudrate=BAUD, timeout=2)         
        while True: 
            try:
                with ser_lock:
                    print("Locked!")
                    data = ser.readline().decode().strip()
                if not data:
                    print("No data read!")
                    continue
                clean = data[2:] # Remove add'l chars '\x'
                clean_int = int(clean, 16) # Convert to base 16 int
                card_number = (clean_int >> 1)  & 0x7FFFF # Bitshift to remove parity and mask to isolate 19 bits
                facility_code = (clean_int >> 20)  & 0xFFFF # Same for facility code
                print(card_number) # Verified when tested with my badge
                print(facility_code) # Not verified - No idea what my facility code should be
            except Exception as e:
                print(f"Error reading data from serial port: {str(e)}")
                continue
            
    except Exception as e:
        print("Error opening port: " + str(e))

The relevant code calling my code from the Flask app:

def start_reader():
    thread = Thread(target=serial_data)
    thread.daemon = True
    thread.start()

start_reader()# Call the above function when the app starts

Expected behavior: When the Flask app is run, with my RFID reader connected on port /dev/ttyUSB0, the app will print the badge information to console.

Actual behavior: While the app is running and no badge is scanned, the Locked! print statement and the No data read! print statements execute as expected. When a badge is scanned, this is the output:

Error reading data from serial port: device reports readiness to read but returned no data (device disconnected or multiple access on port?)
Locked!
Error reading data from serial port: device reports readiness to read but returned no data (device disconnected or multiple access on port?)
Locked!
Error reading data from serial port: device reports readiness to read but returned no data (device disconnected or multiple access on port?)
Locked!
Error reading data from serial port: device reports readiness to read but returned no data (device disconnected or multiple access on port?)
Locked!
Error reading data from serial port: device reports readiness to read but returned no data (device disconnected or multiple access on port?)
Locked!
Error reading data from serial port: device reports readiness to read but returned no data (device disconnected or multiple access on port?)
Locked!
Error reading data from serial port: device reports readiness to read but returned no data (device disconnected or multiple access on port?)
Locked!
Error reading data from serial port: device reports readiness to read but returned no data (device disconnected or multiple access on port?)
Locked!
Error reading data from serial port: invalid literal for int() with base 16: ''
Locked!
No data read!
Locked!
Error reading data from serial port: invalid literal for int() with base 16: ''
Locked! # Here it returns to the earlier expected looping print statements

Additional information: When the app and module are written without threading the reader module works as expected, but blocks the rest of the Flask app from running (hence the need for threading). This tells me that the reader is connected to the computer and in a simple script the app can read from it and strongly suggests that the problem is with threading and concurrency- am I on the right track?


Solution

  • The error was in reference to the print statements, not the serial port. Passing the values back to the main thread via a Queue resolved the error.