2021-02-01 05:40:03 -05:00
|
|
|
# Copyright 2015-2021 Espressif Systems (Shanghai) CO LTD
|
|
|
|
#
|
|
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
# you may not use this file except in compliance with the License.
|
|
|
|
# You may obtain a copy of the License at
|
|
|
|
#
|
|
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
#
|
|
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
# See the License for the specific language governing permissions and
|
|
|
|
# limitations under the License.
|
|
|
|
|
|
|
|
import textwrap
|
2021-04-25 15:07:49 -04:00
|
|
|
|
|
|
|
try:
|
|
|
|
from typing import Optional
|
|
|
|
except ImportError:
|
|
|
|
pass
|
2021-02-01 05:40:03 -05:00
|
|
|
|
2021-05-14 05:20:38 -04:00
|
|
|
|
|
|
|
import queue
|
|
|
|
|
2021-05-14 05:20:38 -04:00
|
|
|
from serial.tools import miniterm
|
2021-02-01 05:40:03 -05:00
|
|
|
|
|
|
|
from .constants import (CMD_APP_FLASH, CMD_ENTER_BOOT, CMD_MAKE, CMD_OUTPUT_TOGGLE, CMD_RESET, CMD_STOP,
|
2021-05-27 10:14:55 -04:00
|
|
|
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__)
|
2021-02-01 05:40:03 -05:00
|
|
|
from .output_helpers import red_print, yellow_print
|
|
|
|
|
|
|
|
key_description = miniterm.key_description
|
|
|
|
|
|
|
|
|
2021-05-14 05:20:38 -04:00
|
|
|
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)
|
|
|
|
|
|
|
|
|
2021-02-01 05:40:03 -05:00
|
|
|
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)
|
2021-05-27 10:14:55 -04:00
|
|
|
elif c in [CTRL_I, 'i', 'I']: # Toggle printing timestamps
|
|
|
|
ret = (TAG_CMD, CMD_TOGGLE_TIMESTAMPS)
|
2021-02-01 05:40:03 -05:00
|
|
|
elif c == CTRL_P:
|
|
|
|
yellow_print('Pause app (enter bootloader mode), press Ctrl-T Ctrl-R to restart')
|
|
|
|
# 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
|
2021-05-27 10:14:55 -04:00
|
|
|
--- {timestamps:14} Toggle printing timestamps
|
2021-02-01 05:40:03 -05:00
|
|
|
--- {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),
|
2021-05-27 10:14:55 -04:00
|
|
|
timestamps=key_description(CTRL_I) + ' (or I)',
|
2021-02-01 05:40:03 -05:00
|
|
|
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
|