Skip to content

Commit aaedd59

Browse files
committed
tools/pyboard.py: Avoid initial blocking read in read_until().
This applies the mpremote commit 0d46e45 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>
1 parent f5d10c3 commit aaedd59

File tree

1 file changed

+27
-10
lines changed

1 file changed

+27
-10
lines changed

tools/pyboard.py

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,14 @@ def inWaiting(self):
267267

268268
class Pyboard:
269269
def __init__(
270-
self, device, baudrate=115200, user="micro", password="python", wait=0, exclusive=True
270+
self,
271+
device,
272+
baudrate=115200,
273+
user="micro",
274+
password="python",
275+
wait=0,
276+
exclusive=True,
277+
timeout=None,
271278
):
272279
self.in_raw_repl = False
273280
self.use_raw_paste = True
@@ -283,7 +290,11 @@ def __init__(
283290
import serial.tools.list_ports
284291

285292
# Set options, and exclusive if pyserial supports it
286-
serial_kwargs = {"baudrate": baudrate, "interCharTimeout": 1}
293+
serial_kwargs = {
294+
"baudrate": baudrate,
295+
"timeout": timeout,
296+
"interCharTimeout": 1,
297+
}
287298
if serial.__version__ >= "3.3":
288299
serial_kwargs["exclusive"] = exclusive
289300

@@ -324,13 +335,20 @@ def close(self):
324335
self.serial.close()
325336

326337
def read_until(self, min_num_bytes, ending, timeout=10, data_consumer=None):
327-
# if data_consumer is used then data is not accumulated and the ending must be 1 byte long
338+
"""
339+
min_num_bytes: Obsolete.
340+
ending: Return if 'ending' matches.
341+
timeout [s]: Return if timeout between characters. None: Infinite timeout.
342+
data_consumer: Use callback for incoming characters.
343+
If data_consumer is used then data is not accumulated and the ending must be 1 byte long
344+
345+
It is not visible to the caller why the function returned. It could be ending or timeout.
346+
"""
328347
assert data_consumer is None or len(ending) == 1
348+
assert isinstance(timeout, (type(None), int, float))
329349

330-
data = self.serial.read(min_num_bytes)
331-
if data_consumer:
332-
data_consumer(data)
333-
timeout_count = 0
350+
data = b""
351+
begin_char_s = time.monotonic()
334352
while True:
335353
if data.endswith(ending):
336354
break
@@ -341,10 +359,9 @@ def read_until(self, min_num_bytes, ending, timeout=10, data_consumer=None):
341359
data = new_data
342360
else:
343361
data = data + new_data
344-
timeout_count = 0
362+
begin_char_s = time.monotonic()
345363
else:
346-
timeout_count += 1
347-
if timeout is not None and timeout_count >= 100 * timeout:
364+
if timeout is not None and time.monotonic() >= begin_char_s + timeout:
348365
break
349366
time.sleep(0.01)
350367
return data

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy