I am trying to implement serial communication, following this advice.
Basically I will have a separate thread, that blocks, listening to the port, and when a complete line is received, push it to a global queue.
However, this warning in the documentation is confusing to me:
readlines() only works with a timeout
What does it mean? How do I implement what I intend. I would hate to have to
while True:
a = self.ser.read(1)
if a == '/n':
blqblq()
elif a == '/r'
b = self.ser.read(1)
if b == '/n':
nana()
readlines must be given a timeout because otherwise it would never finish, since there is no way to detect the end of the serial data stream (EOF).
readline blocks indefinitely when no data is being sent (or the data doesn't contain a newline), but so does your application. It's perfectly fine to write something like
def read(ser, queue):
while True:
queue.put(ser.readline())
threading.Thread(target=read, args=(ser, queue)).start()
or the more modern equivalent
def read(ser, queue):
for line in ser:
queue.put(line)
threading.Thread(target=read, args=(ser, queue)).start()
However, you should be aware that the reading thread will never finish. So if your program should ever end in a non-exceptional way (i.e. the user can somehow quit it), you need to have a mechanism to signal the reading thread to stop. To make sure that this signal is ever received, you need to use a timeout - otherwise, the thread could block indefinitely in the absence of serial data. For example, this could look like:
def read(ser, queue):
buf = b''
ser.timeout = 1 # 1 second. Modify according to latency requirements
while not should_stop.is_set():
buf += ser.readline()
if buf.endswith('\n'):
queue.put(line)
buf = b''
# else: Interrupted by timeout
should_stop = threading.Event()
threading.Thread(target=read, args=(ser, queue)).start()
# ... somewhat later
should_stop.set() # Reading thread will exit within the next second
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With