pySerial inWaiting devuelve un número incorrecto de bytes

Tengo un progtwig simple para probar la funcionalidad serial. Mi dispositivo serial reactjs a dos entradas. Si el usuario ingresa ‘a’, responde con ‘fg’. Si el usuario ingresa cualquier otro carácter / byte, responde con ‘z’. Si envío ‘b’ al dispositivo serie, devolverá ‘z’ muy bien. Cuando envío ‘a’, debería devolver tanto ‘f’ como ‘g’, así que dos bytes en lugar de uno.

Ver código a continuación.

#!/usr/bin/env python import serial ser = serial.Serial( port = '/dev/ttyUSB0', baudrate = 9600, parity = serial.PARITY_NONE, stopbits = serial.STOPBITS_ONE, bytesize = serial.EIGHTBITS ) ser.write('a') byteData = ser.read(1) # read one, blocking moreBytes = ser.inWaiting() if moreBytes: byteData = byteData + ser.read(moreBytes) print byteData print byteData ser.close() 

La salida es:

 user@ubuntu:~/code/native$ ./serialTesting.py f 

inWaiting () da el valor de 0, por lo que nunca lee el segundo byte. Si hago un pequeño cambio en el código y leo manualmente los dos bytes esperados, funciona bien.

 #!/usr/bin/env python import serial ser = serial.Serial( port = '/dev/ttyUSB0', baudrate = 9600, parity = serial.PARITY_NONE, stopbits = serial.STOPBITS_ONE, bytesize = serial.EIGHTBITS ) ser.write('a') byteData = ser.read(2) # read two expected bytes for the result 'fg' print byteData ser.close() 

La salida es la esperada:

 user@ubuntu:~/code/native$ ./serialTesting.py fg 

Hay dos soluciones decentes para esto. Para cualquiera de los dos, deberás establecer un tiempo de espera como jramirez ya sugerido:

 ser = serial.Serial( port = '/dev/ttyUSB0', baudrate = 9600, parity = serial.PARITY_NONE, stopbits = serial.STOPBITS_ONE, bytesize = serial.EIGHTBITS, timeout=0.5, # IMPORTANT, can be lower or higher inter_byte_timeout=0.1 # Alternative ) 

Solución 1: Simple y eficaz.

 byteData = ser.read(size=800) #Set size to something high 

Esto leerá hasta 800 bytes y no tomará más tiempo que el timeout establecido. Si, en cambio, ha establecido un inter_byte_timeout , read() esperará hasta esa cantidad de tiempo para cada byte.

Esta es una solución rápida que funcionará en los casos en que solo reciba una parte de los datos de tamaño máximo conocido.

Solución 2: El camino correcto.

 def read_all(port, chunk_size=200): """Read all characters on the serial port and return them.""" if not port.timeout: raise TypeError('Port needs to have a timeout set!') read_buffer = b'' while True: # Read in chunks. Each chunk will wait as long as specified by # timeout. Increase chunk_size to fail quicker byte_chunk = port.read(size=chunk_size) read_buffer += byte_chunk if not len(byte_chunk) == chunk_size: break return read_buffer 

El fragmento de código anterior está licenciado bajo CC0 1.0 .

Y luego, para leer:

 byteData = read_all(ser) 

Básicamente, esto leerá sus datos en trozos y esperará cada vez para ver si aparecen nuevos caracteres. Si se leyeron menos caracteres en el tiempo establecido por el timeout de timeout , la transmisión se considera finalizada.

Esta solución siempre funcionará, incluso cuando reciba una gran cantidad de datos o si la recibe muy lentamente.

Podría ser porque la velocidad en baudios es muy lenta. Usted está procesando la llamada inwaiting () antes de que el segundo byte llegue al búfer. Cuando hace ser.read (2), espera (bloquea) hasta que se hayan recibido 2 bytes, por lo que funciona. Intente establecer un tiempo de espera de 1 segundo, eso debería solucionar su problema.

 ser = serial.Serial( port = '/dev/ttyUSB0', baudrate = 9600, parity = serial.PARITY_NONE, stopbits = serial.STOPBITS_ONE, bytesize = serial.EIGHTBITS, timeout=1 # add this ) ser.write('a') byteData = ser.read(1) # read one, blocking byteData += ser.read(ser.inWaiting()) print byteData ser.close()