Skip to content

tools/mpremote: Poll for friendly REPL prompt before raw mode entry.#48

Draft
andrewleech wants to merge 1 commit into
masterfrom
mpremote_raw_repl_retry
Draft

tools/mpremote: Poll for friendly REPL prompt before raw mode entry.#48
andrewleech wants to merge 1 commit into
masterfrom
mpremote_raw_repl_retry

Conversation

@andrewleech

Copy link
Copy Markdown
Owner

Summary

Issue micropython#13504 has been open since 2023 and affects users primarily on macOS: mpremote fails with TransportError: could not enter raw repl on the first invocation after plugging in a device. The thread has accumulated a workaround (a 2-second sleep inside enter_raw_repl), confirmations across boards and Python versions, and a comment from @pavelrevak noting his mpytool does not hit it because of a different polling strategy.

The root cause is that opening the serial port toggles DTR/RTS on common USB-serial converters, which resets ESP32-class boards. enter_raw_repl then sends a single Ctrl-C, flushes input, sends Ctrl-A, and blocks waiting for the raw banner. If the device is still booting, the banner never arrives and the call times out. The time.sleep(2) workaround works only because the device finishes booting in that window.

This change replaces the single Ctrl-C + flush with _wait_for_friendly_prompt, which polls for \r\n>>> with a 0.2s interval, alternating Ctrl-C (interrupt program) and Ctrl-B (exit raw REPL, every third attempt). After four unsuccessful attempts it also sends the VFS-hook ACK byte (0x18) to unblock a fs_hook agent stuck on a host read. Once the friendly prompt is confirmed, Ctrl-A is sent and the existing banner-read logic runs unchanged. The prompt-confirmation phase is capped at min(3, timeout_overall), so existing callers see at most a small additional delay before the original failure mode is reported, and successful connections on already-responsive devices are not slowed.

Approach is modelled on the polling pattern in mpytool that @pavelrevak described in micropython#13504, adapted to mpremote's existing read_until and serial abstractions.

Testing

Not yet tested on hardware. The change needs to be validated against the macOS + ESP32 + CP2102/CP210x configuration that reproduces micropython#13504, and against a representative set of other ports (STM32, RP2, nRF) to confirm no regression in the fast path where devices respond to the first Ctrl-C. I'm planning to do this before this PR is ready for merge; flagging it now so the approach can be reviewed in parallel.

Trade-offs and Alternatives

The friendly-prompt phase adds up to 3 seconds of wall time on a device that never responds, before the same TransportError is raised. In practice this replaces the 10s banner-read timeout that previously fired in the same scenario, so the failure path is faster, not slower.

An alternative would be to keep the current code path and add time.sleep(2) as the issue thread suggests. That works around the macOS case but does not address devices stuck in raw REPL or with a stalled fs_hook agent, and it penalises every invocation rather than only the ones that need it.

Generative AI

I used generative AI tools when creating this PR, but a human has checked the code and is responsible for the description above.

@andrewleech andrewleech force-pushed the mpremote_raw_repl_retry branch from d640931 to 74fa650 Compare May 28, 2026 13:52
@codecov-commenter

codecov-commenter commented May 28, 2026

Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 98.48%. Comparing base (1c63211) to head (4bcb03f).
⚠️ Report is 148 commits behind head on master.
❗ Your organization needs to install the Codecov GitHub app to enable full functionality.

Additional details and impacted files
@@           Coverage Diff            @@
##           master      #48    +/-   ##
========================================
  Coverage   98.47%   98.48%            
========================================
  Files         176      176            
  Lines       22845    23328   +483     
========================================
+ Hits        22497    22974   +477     
- Misses        348      354     +6     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

enter_raw_repl previously sent a single Ctrl-C, flushed the input
buffer, then sent Ctrl-A and waited up to 10s for the raw REPL banner.
This fails on devices that are still booting (e.g. after DTR/RTS
toggling on macOS USB-serial converters resets the board on port open),
or that are stuck in raw REPL, or that have a fs_hook agent stalled on
a VFS read; the banner never arrives because the device is not in a
state where Ctrl-A is meaningful.

Add _wait_for_friendly_prompt which polls for `\r\n>>> ` with short
0.2s timeouts, alternating Ctrl-C and Ctrl-B and (after a few attempts)
also sending the VFS-hook ACK byte (0x18). enter_raw_repl now confirms
the device is in friendly REPL before sending Ctrl-A.

Approach matches the polling pattern used successfully by mpytool to
work around the same DTR/RTS reset issue on macOS, discussed in micropython#13504.
@andrewleech andrewleech force-pushed the mpremote_raw_repl_retry branch from 74fa650 to 4bcb03f Compare June 15, 2026 04:07
@github-actions

Copy link
Copy Markdown

Code size report:

Reference:  unix/README: Update the supported targets list. [d901e98]
Comparison: tools/mpremote: poll for friendly REPL prompt before entering raw mode [merge of 4bcb03f]
  mpy-cross:    +0 +0.000% 
   bare-arm:    +0 +0.000% 
minimal x86:    +0 +0.000% 
   unix x64:    +0 +0.000% standard
      stm32:    +0 +0.000% PYBV10
      esp32:    +0 +0.000% ESP32_GENERIC
     mimxrt:    +0 +0.000% TEENSY40
        rp2:    +0 +0.000% RPI_PICO_W
       samd:    +0 +0.000% ADAFRUIT_ITSYBITSY_M4_EXPRESS
  qemu rv32:    +0 +0.000% VIRT_RV32

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants