| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148 |
- # SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
- # SPDX-License-Identifier: Apache-2.0
- import queue
- import textwrap
- from typing import Optional
- from serial.tools import miniterm
- from .constants import (CMD_APP_FLASH, CMD_ENTER_BOOT, CMD_MAKE, CMD_OUTPUT_TOGGLE, CMD_RESET, CMD_STOP,
- CMD_TOGGLE_LOGGING, CMD_TOGGLE_TIMESTAMPS, CTRL_A, CTRL_F, CTRL_H, CTRL_I, CTRL_L, CTRL_P,
- CTRL_R, CTRL_RBRACKET, CTRL_T, CTRL_X, CTRL_Y, TAG_CMD, TAG_KEY, __version__)
- from .output_helpers import red_print
- key_description = miniterm.key_description
- def prompt_next_action(reason, console, console_parser, event_queue, cmd_queue):
- # type: (str, miniterm.Console, ConsoleParser, queue.Queue, queue.Queue) -> None
- console.setup() # set up console to trap input characters
- try:
- red_print('--- {}'.format(reason))
- red_print(console_parser.get_next_action_text())
- k = CTRL_T # ignore CTRL-T here, so people can muscle-memory Ctrl-T Ctrl-F, etc.
- while k == CTRL_T:
- k = console.getkey()
- finally:
- console.cleanup()
- ret = console_parser.parse_next_action_key(k)
- if ret is not None:
- cmd = ret[1]
- if cmd == CMD_STOP:
- # the stop command should be handled last
- event_queue.put(ret)
- else:
- cmd_queue.put(ret)
- class ConsoleParser(object):
- def __init__(self, eol='CRLF'): # type: (str) -> None
- self.translate_eol = {
- 'CRLF': lambda c: c.replace('\n', '\r\n'),
- 'CR': lambda c: c.replace('\n', '\r'),
- 'LF': lambda c: c.replace('\r', '\n'),
- }[eol]
- self.menu_key = CTRL_T
- self.exit_key = CTRL_RBRACKET
- self._pressed_menu_key = False
- def parse(self, key): # type: (str) -> Optional[tuple]
- ret = None
- if self._pressed_menu_key:
- ret = self._handle_menu_key(key)
- elif key == self.menu_key:
- self._pressed_menu_key = True
- elif key == self.exit_key:
- ret = (TAG_CMD, CMD_STOP)
- else:
- key = self.translate_eol(key)
- ret = (TAG_KEY, key)
- return ret
- def _handle_menu_key(self, c): # type: (str) -> Optional[tuple]
- ret = None
- if c == self.exit_key or c == self.menu_key: # send verbatim
- ret = (TAG_KEY, c)
- elif c in [CTRL_H, 'h', 'H', '?']:
- red_print(self.get_help_text())
- elif c == CTRL_R: # Reset device via RTS
- ret = (TAG_CMD, CMD_RESET)
- elif c == CTRL_F: # Recompile & upload
- ret = (TAG_CMD, CMD_MAKE)
- elif c in [CTRL_A, 'a', 'A']: # Recompile & upload app only
- # "CTRL-A" cannot be captured with the default settings of the Windows command line, therefore, "A" can be used
- # instead
- ret = (TAG_CMD, CMD_APP_FLASH)
- elif c == CTRL_Y: # Toggle output display
- ret = (TAG_CMD, CMD_OUTPUT_TOGGLE)
- elif c == CTRL_L: # Toggle saving output into file
- ret = (TAG_CMD, CMD_TOGGLE_LOGGING)
- elif c in [CTRL_I, 'i', 'I']: # Toggle printing timestamps
- ret = (TAG_CMD, CMD_TOGGLE_TIMESTAMPS)
- elif c == CTRL_P:
- # to fast trigger pause without press menu key
- ret = (TAG_CMD, CMD_ENTER_BOOT)
- elif c in [CTRL_X, 'x', 'X']: # Exiting from within the menu
- ret = (TAG_CMD, CMD_STOP)
- else:
- red_print('--- unknown menu character {} --'.format(key_description(c)))
- self._pressed_menu_key = False
- return ret
- def get_help_text(self): # type: () -> str
- text = """\
- --- idf_monitor ({version}) - ESP-IDF monitor tool
- --- based on miniterm from pySerial
- ---
- --- {exit:8} Exit program
- --- {menu:8} Menu escape key, followed by:
- --- Menu keys:
- --- {menu:14} Send the menu character itself to remote
- --- {exit:14} Send the exit character itself to remote
- --- {reset:14} Reset target board via RTS line
- --- {makecmd:14} Build & flash project
- --- {appmake:14} Build & flash app only
- --- {output:14} Toggle output display
- --- {log:14} Toggle saving output into file
- --- {timestamps:14} Toggle printing timestamps
- --- {pause:14} Reset target into bootloader to pause app via RTS line
- --- {menuexit:14} Exit program
- """.format(version=__version__,
- exit=key_description(self.exit_key),
- menu=key_description(self.menu_key),
- reset=key_description(CTRL_R),
- makecmd=key_description(CTRL_F),
- appmake=key_description(CTRL_A) + ' (or A)',
- output=key_description(CTRL_Y),
- log=key_description(CTRL_L),
- timestamps=key_description(CTRL_I) + ' (or I)',
- pause=key_description(CTRL_P),
- menuexit=key_description(CTRL_X) + ' (or X)')
- return textwrap.dedent(text)
- def get_next_action_text(self): # type: () -> str
- text = """\
- --- Press {} to exit monitor.
- --- Press {} to build & flash project.
- --- Press {} to build & flash app.
- --- Press any other key to resume monitor (resets target).
- """.format(key_description(self.exit_key),
- key_description(CTRL_F),
- key_description(CTRL_A))
- return textwrap.dedent(text)
- def parse_next_action_key(self, c): # type: (str) -> Optional[tuple]
- ret = None
- if c == self.exit_key:
- ret = (TAG_CMD, CMD_STOP)
- elif c == CTRL_F: # Recompile & upload
- ret = (TAG_CMD, CMD_MAKE)
- elif c in [CTRL_A, 'a', 'A']: # Recompile & upload app only
- # "CTRL-A" cannot be captured with the default settings of the Windows command line, therefore, "A" can be used
- # instead
- ret = (TAG_CMD, CMD_APP_FLASH)
- return ret
|