tools/mpremote: Fix disconnect handling on Windows and Linux.

Changes in this commit:
- Handle SerialException on Windows when device disconnects.
- Print clean 'device disconnected' message instead of stack trace.
- Fix terminal formatting issues on Linux after disconnect.
- Return disconnected state after console cleanup to avoid terminal issues.

This ensures proper disconnect messages on both platforms without showing
confusing error traces to users.

Signed-off-by: Andrew Leech <andrew.leech@planetinnovation.com.au>
This commit is contained in:
Andrew Leech
2021-09-27 17:42:50 +10:00
committed by Damien George
parent e33a0f4682
commit 3a97175f5f
2 changed files with 70 additions and 45 deletions

View File

@@ -620,7 +620,11 @@ def main():
# If no commands were "actions" then implicitly finish with the REPL
# using default args.
if state.run_repl_on_completion():
do_repl(state, argparse_repl().parse_args([]))
disconnected = do_repl(state, argparse_repl().parse_args([]))
# Handle disconnection message
if disconnected:
print("\ndevice disconnected")
return 0
except CommandError as e:

View File

@@ -7,6 +7,7 @@ def do_repl_main_loop(
state, console_in, console_out_write, *, escape_non_printable, code_to_inject, file_to_inject
):
while True:
try:
console_in.waitchar(state.transport.serial)
c = console_in.readchar()
if c:
@@ -31,13 +32,7 @@ def do_repl_main_loop(
else:
state.transport.serial.write(c)
try:
n = state.transport.serial.inWaiting()
except OSError as er:
if er.args[0] == 5: # IO error, device disappeared
print("device disconnected")
break
if n > 0:
dev_data_in = state.transport.serial.read(n)
if dev_data_in is not None:
@@ -53,6 +48,13 @@ def do_repl_main_loop(
console_data_out = dev_data_in
console_out_write(console_data_out)
except OSError as er:
if _is_disconnect_exception(er):
return True
else:
raise
return False
def do_repl(state, args):
state.ensure_friendly_repl()
@@ -86,7 +88,7 @@ def do_repl(state, args):
capture_file.flush()
try:
do_repl_main_loop(
return do_repl_main_loop(
state,
console,
console_out_write,
@@ -98,3 +100,22 @@ def do_repl(state, args):
console.exit()
if capture_file is not None:
capture_file.close()
def _is_disconnect_exception(exception):
"""
Check if an exception indicates device disconnect.
Returns True if the exception indicates the device has disconnected,
False otherwise.
"""
if isinstance(exception, OSError):
if hasattr(exception, 'args') and len(exception.args) > 0:
# IO error, device disappeared
if exception.args[0] == 5:
return True
# Check for common disconnect messages in the exception string
exception_str = str(exception)
disconnect_indicators = ["Write timeout", "Device disconnected", "ClearCommError failed"]
return any(indicator in exception_str for indicator in disconnect_indicators)
return False