Skip to content
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 35 additions & 7 deletions tools/mpremote/mpremote/transport_serial.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,14 +159,42 @@ def read_until(
time.sleep(0.01)
return data

def enter_raw_repl(self, soft_reset=True, timeout_overall=10):
self.serial.write(b"\r\x03") # ctrl-C: interrupt any running program
def _wait_for_friendly_prompt(self, timeout_overall=5):
# Actively poll for the friendly REPL prompt before attempting raw mode
# entry. This handles devices that are still booting (e.g. after DTR/RTS
# toggling on macOS USB-serial converters resets the device on port open),
# devices stuck in raw REPL, and fs_hook agents stuck waiting for a VFS
# response. Returns True if the prompt was seen, False on timeout.
poll_interval = 0.2
begin = time.monotonic()
attempt = 0
while time.monotonic() - begin < timeout_overall:
# Alternate Ctrl-C (interrupt running program) with Ctrl-B
# (exit raw REPL if stuck) every third attempt.
if attempt % 3 == 2:
self.serial.write(b"\r\x02")
else:
self.serial.write(b"\r\x03")
# After a few unsuccessful tries also send the VFS-hook ACK byte
# (0x18) to unblock a fs_hook agent stuck reading from the host.
if attempt >= 4:
self.serial.write(b"\x18")
data = self.read_until(1, b"\r\n>>> ", timeout=poll_interval)
if data.endswith(b"\r\n>>> "):
return True
attempt += 1
return False

# flush input (without relying on serial.flushInput())
n = self.serial.inWaiting()
while n > 0:
self.serial.read(n)
n = self.serial.inWaiting()
def enter_raw_repl(self, soft_reset=True, timeout_overall=10):
# Actively confirm the device is in friendly REPL before sending Ctrl-A.
# The prompt phase is capped at 5s to accommodate boards whose boot.py
# does network init or similar work before the prompt appears, while
# still surfacing genuinely unresponsive devices reasonably quickly.
# timeout_overall governs the post-Ctrl-A banner reads below.
# No explicit input flush is needed: read_until consumes any pending
# bytes up to and including the prompt.
if not self._wait_for_friendly_prompt(timeout_overall=min(5, timeout_overall)):
raise TransportError("could not enter raw repl")

self.serial.write(b"\r\x01") # ctrl-A: enter raw REPL

Expand Down
Loading