From 2771b20d29569bf51ea841a804a66048efde1593 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 11 May 2023 13:24:14 +1000 Subject: [PATCH] tools/mpremote: Add repl option to escape non-printable characters. This commit adds the "--escape-non-printable" option to the repl command. When specified the REPL console will escape non-printable characters, printing them as their hex value in square brackets. This escaping behaviour was previously the default and only behaviour, but it is now opt-in. As part of this change, the speed of echoing device data to the console is improved by by reading and writing in chunks. Signed-off-by: Damien George --- docs/reference/mpremote.rst | 1 + tools/mpremote/mpremote/main.py | 1 + tools/mpremote/mpremote/repl.py | 27 +++++++++++++++++++-------- 3 files changed, 21 insertions(+), 8 deletions(-) diff --git a/docs/reference/mpremote.rst b/docs/reference/mpremote.rst index 3225fc5f24..e96b32cbbe 100644 --- a/docs/reference/mpremote.rst +++ b/docs/reference/mpremote.rst @@ -92,6 +92,7 @@ The full list of supported commands are: Options are: + - ``--escape-non-printable``, to print non-printable bytes/characters as their hex code - ``--capture ``, to capture output of the REPL session to the given file - ``--inject-code ``, to specify characters to inject at the REPL when diff --git a/tools/mpremote/mpremote/main.py b/tools/mpremote/mpremote/main.py index 988ffe8f60..eafa5b97e3 100644 --- a/tools/mpremote/mpremote/main.py +++ b/tools/mpremote/mpremote/main.py @@ -119,6 +119,7 @@ def argparse_mount(): def argparse_repl(): cmd_parser = argparse.ArgumentParser(description="connect to given device") + _bool_flag(cmd_parser, "escape-non-printable", "e", False, "escape non-printable characters") cmd_parser.add_argument( "--capture", type=str, diff --git a/tools/mpremote/mpremote/repl.py b/tools/mpremote/mpremote/repl.py index d5eb2b8712..239e267d75 100644 --- a/tools/mpremote/mpremote/repl.py +++ b/tools/mpremote/mpremote/repl.py @@ -3,7 +3,9 @@ from .console import Console, ConsolePosix from . import pyboardextended as pyboard -def do_repl_main_loop(state, console_in, console_out_write, *, code_to_inject, file_to_inject): +def do_repl_main_loop( + state, console_in, console_out_write, *, escape_non_printable, code_to_inject, file_to_inject +): while True: console_in.waitchar(state.pyb.serial) c = console_in.readchar() @@ -37,26 +39,34 @@ def do_repl_main_loop(state, console_in, console_out_write, *, code_to_inject, f break if n > 0: - c = state.pyb.serial.read(1) - if c is not None: - # pass character through to the console - oc = ord(c) - if oc in (8, 9, 10, 13, 27) or 32 <= oc <= 126: - console_out_write(c) + dev_data_in = state.pyb.serial.read(n) + if dev_data_in is not None: + if escape_non_printable: + # Pass data through to the console, with escaping of non-printables. + console_data_out = bytearray() + for c in dev_data_in: + if c in (8, 9, 10, 13, 27) or 32 <= c <= 126: + console_data_out.append(c) + else: + console_data_out.extend(b"[%02x]" % c) else: - console_out_write(b"[%02x]" % ord(c)) + console_data_out = dev_data_in + console_out_write(console_data_out) def do_repl(state, args): state.ensure_friendly_repl() state.did_action() + escape_non_printable = args.escape_non_printable capture_file = args.capture code_to_inject = args.inject_code file_to_inject = args.inject_file print("Connected to MicroPython at %s" % state.pyb.device_name) print("Use Ctrl-] or Ctrl-x to exit this shell") + if escape_non_printable: + print("Escaping non-printable bytes/characters by printing their hex code") if capture_file is not None: print('Capturing session to file "%s"' % capture_file) capture_file = open(capture_file, "wb") @@ -80,6 +90,7 @@ def do_repl(state, args): state, console, console_out_write, + escape_non_printable=escape_non_printable, code_to_inject=code_to_inject, file_to_inject=file_to_inject, )