Corrupt characters received if timeout changed during reception
Brought to you by:
cliechti
I need to send commands to a remote device and then receive responses. But the timeout allowed for each response is different. This means I send using serial.write, then change the timeout using serial.timeout and then get the response using serial.readline. Mostly this works, but if the response is already being received when I change the timeout, I get a corrupt character in the middle of the string.
As a workaround, I have kept a fixed (short) timeout and just loop around the readline checking for an empty string and counting the fixed timeout intervals until I get to the desired timeout. This works fine.
My guess is that you're using Windows. This is caused by setTimeout() calling _reconfigurePort() which does more than just change the timeout (i.e., it sets the baudrate and configures flow control and other things). Somewhere in all that other stuff Windows sends (what I can only imagine is) flow control character on the line.
The fix for this is simple: don't reconfigure other stuff when timeouts are changed. If you don't want to modify pyserial to fix this (as I didn't) then you can copy the calls to win32.SetCommTimeouts() into your own code instead of using the setter.
I confirm this problem, as I had exactly the same one (with Windows 8.1 and Python 2.7.8):
com = Serial(xxx)
com.writeTimeout = None
com.write(big_string)
com.flush()
com.timeout = whatever
The data received on the remote side will then be corrupted (well, most of the time). I try a few modifications in the lib source code, and this is definitively win32.SetCommState() in _reconfigurePort() which is the culprit, as you guessed.
What is also strange here is that the flush is not really flushing anything.
If you do not plan to correct this, please at least add a warning in the doc saying that, on Windows, changing any setting during a communication might corrupt it. I spent many days trying to understand what was ging on.
Another workaround is to use com.writeTimeout = 0 and let the flush work for real... but unfortunately there is another bug in flush! I will open a ticket for that.
Thanks Trent and Antoine. This is really helpful info. I have worked around my problem now (but like Antoine spent several days trying to find out what was wrong). I agree it would be good to have this warning in the documentation somewhere.
Cheers,
Mike.