diff options
author | Damien George <damien@micropython.org> | 2025-05-20 16:48:38 +1000 |
---|---|---|
committer | Damien George <damien@micropython.org> | 2025-06-02 17:02:30 +1000 |
commit | aaedd59b7ce68ac0b445960584fc58f657c835ad (patch) | |
tree | b18fb27b0a5353b99e7deaa2d90790cb005ebc16 /tools/pyboard.py | |
parent | f5d10c322ecacc6be208388fa93adba5bee6eb0c (diff) |
tools/pyboard.py: Avoid initial blocking read in read_until().
This applies the mpremote commit 0d46e45a1f72ee61a153c41aaaf6c63818ccffb0
to pyboard.py.
If the target does not return any data then `read_until()` will block
indefinitely. Fix this by making the initial read part of the general read
look, which always checks `inWaiting() > 0` before reading from the serial
device.
Also added the UART timeout to the constructor. This is not currently used
but may be used as an additional safeguard.
Signed-off-by: Damien George <damien@micropython.org>
Diffstat (limited to 'tools/pyboard.py')
-rwxr-xr-x | tools/pyboard.py | 37 |
1 files changed, 27 insertions, 10 deletions
diff --git a/tools/pyboard.py b/tools/pyboard.py index d49365f61..950a6568f 100755 --- a/tools/pyboard.py +++ b/tools/pyboard.py @@ -267,7 +267,14 @@ class ProcessPtyToTerminal: class Pyboard: def __init__( - self, device, baudrate=115200, user="micro", password="python", wait=0, exclusive=True + self, + device, + baudrate=115200, + user="micro", + password="python", + wait=0, + exclusive=True, + timeout=None, ): self.in_raw_repl = False self.use_raw_paste = True @@ -283,7 +290,11 @@ class Pyboard: import serial.tools.list_ports # Set options, and exclusive if pyserial supports it - serial_kwargs = {"baudrate": baudrate, "interCharTimeout": 1} + serial_kwargs = { + "baudrate": baudrate, + "timeout": timeout, + "interCharTimeout": 1, + } if serial.__version__ >= "3.3": serial_kwargs["exclusive"] = exclusive @@ -324,13 +335,20 @@ class Pyboard: self.serial.close() def read_until(self, min_num_bytes, ending, timeout=10, data_consumer=None): - # if data_consumer is used then data is not accumulated and the ending must be 1 byte long + """ + min_num_bytes: Obsolete. + ending: Return if 'ending' matches. + timeout [s]: Return if timeout between characters. None: Infinite timeout. + data_consumer: Use callback for incoming characters. + If data_consumer is used then data is not accumulated and the ending must be 1 byte long + + It is not visible to the caller why the function returned. It could be ending or timeout. + """ assert data_consumer is None or len(ending) == 1 + assert isinstance(timeout, (type(None), int, float)) - data = self.serial.read(min_num_bytes) - if data_consumer: - data_consumer(data) - timeout_count = 0 + data = b"" + begin_char_s = time.monotonic() while True: if data.endswith(ending): break @@ -341,10 +359,9 @@ class Pyboard: data = new_data else: data = data + new_data - timeout_count = 0 + begin_char_s = time.monotonic() else: - timeout_count += 1 - if timeout is not None and timeout_count >= 100 * timeout: + if timeout is not None and time.monotonic() >= begin_char_s + timeout: break time.sleep(0.01) return data |