Skip to content

Commit

Permalink
idf_monitor: Small fixes (baud rate, EOL, /dev/tty.X on macOS, Ctrl-T…
Browse files Browse the repository at this point in the history
… on failure)

* "make monitor" not passed the configured baud rate
  Closes #436 #436
* Pass toolchain prefix from sdkconfig into monitor tool
* Allow setting EOL in idf_monitor.py, use CRLF by default
* Detect if /dev/tty.X is used on macOS, warn and replace with /dev/cu.X
* If a build fails or gdb exits, ignore Ctrl-T (allowing Ctrl-T Ctrl-A/F to be same key sequence everywhere)
* Add a note about winpty on Windows
  Ref 02fdf82#commitcomment-21369196
  • Loading branch information
projectgus committed Mar 21, 2017
1 parent 57486a1 commit e477ce9
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 7 deletions.
4 changes: 3 additions & 1 deletion components/esptool_py/Makefile.projbuild
Expand Up @@ -83,12 +83,14 @@ endif
simple_monitor: $(call prereq_if_explicit,%flash)
$(MONITOR_PYTHON) -m serial.tools.miniterm --rts 0 --dtr 0 --raw $(ESPPORT) $(MONITORBAUD)

MONITOR_OPTS := --baud $(MONITORBAUD) --port $(ESPPORT) --toolchain-prefix $(CONFIG_TOOLPREFIX) --make "$(MAKE)"

monitor: $(call prereq_if_explicit,%flash)
$(summary) MONITOR
[ -f $(APP_ELF) ] || echo "*** 'make monitor' target requires an app to be compiled and flashed first."
[ -f $(APP_ELF) ] || echo "*** Run 'make flash monitor' to build, flash and monitor"
[ -f $(APP_ELF) ] || echo "*** Or alternatively 'make simple_monitor' to view the serial port as-is."
[ -f $(APP_ELF) ] || exit 1
$(MONITOR_PYTHON) $(IDF_PATH)/tools/idf_monitor.py --port $(ESPPORT) --make "$(MAKE)" $(APP_ELF)
$(MONITOR_PYTHON) $(IDF_PATH)/tools/idf_monitor.py $(MONITOR_OPTS) $(APP_ELF)

.PHONY: erase_flash
1 change: 1 addition & 0 deletions docs/idf-monitor.rst
Expand Up @@ -102,6 +102,7 @@ Known Issues with idf_monitor
Issues Observed on Windows
~~~~~~~~~~~~~~~~~~~~~~~~~~

- If you are using the supported Windows environment and receive the error "winpty: command not found" then run ``pacman -S winpty`` to fix.
- Arrow keys and some other special keys in gdb don't work, due to Windows Console limitations.
- Occasionally when "make" exits, it may stall for up to 30 seconds before idf_monitor resumes.
- Occasionally when "gdb" is run, it may stall for a short time before it begins communicating with the gdbstub.
Expand Down
41 changes: 35 additions & 6 deletions tools/idf_monitor.py
Expand Up @@ -70,6 +70,8 @@
# regex matches an potential PC value (0x4xxxxxxx)
MATCH_PCADDR = re.compile(r'0x4[0-9a-f]{7}', re.IGNORECASE)

DEFAULT_TOOLCHAIN_PREFIX = "xtensa-esp32-elf-"

class StoppableThread(object):
"""
Provide a Thread-like class which can be 'cancelled' via a subclass-provided
Expand Down Expand Up @@ -193,7 +195,7 @@ class Monitor(object):
Main difference is that all event processing happens in the main thread, not the worker threads.
"""
def __init__(self, serial_instance, elf_file, make="make"):
def __init__(self, serial_instance, elf_file, make="make", toolchain_prefix=DEFAULT_TOOLCHAIN_PREFIX, eol="CRLF"):
super(Monitor, self).__init__()
self.event_queue = queue.Queue()
self.console = miniterm.Console()
Expand All @@ -207,9 +209,16 @@ def __init__(self, serial_instance, elf_file, make="make"):
self.serial_reader = SerialReader(self.serial, self.event_queue)
self.elf_file = elf_file
self.make = make
self.toolchain_prefix = DEFAULT_TOOLCHAIN_PREFIX
self.menu_key = CTRL_T
self.exit_key = CTRL_RBRACKET

self.translate_eol = {
"CRLF": lambda c: c.replace(b"\n", b"\r\n"),
"CR": lambda c: c.replace(b"\n", b"\r"),
"LF": lambda c: c.replace(b"\r", b"\n"),
}[eol]

# internal state
self._pressed_menu_key = False
self._read_line = b""
Expand Down Expand Up @@ -246,6 +255,7 @@ def handle_key(self, key):
self.serial_reader.stop()
else:
try:
key = self.translate_eol(key)
self.serial.write(codecs.encode(key))
except serial.SerialException:
pass # this shouldn't happen, but sometimes port has closed in serial thread
Expand Down Expand Up @@ -327,7 +337,9 @@ def prompt_next_action(self, reason):
.format(key_description(CTRL_A)))
sys.stderr.write("--- Press any other key to resume monitor (resets target).\n")
sys.stderr.write(ANSI_NORMAL)
k = self.console.getkey()
k = CTRL_T # ignore CTRL-T here, so people can muscle-memory Ctrl-T Ctrl-F, etc.
while k == CTRL_T:
k = self.console.getkey()
finally:
self.console.cleanup()
if k == self.exit_key:
Expand All @@ -350,8 +362,8 @@ def run_make(self, target):

def lookup_pc_address(self, pc_addr):
translation = subprocess.check_output(
["xtensa-esp32-elf-addr2line", "-pfia",
"-e", self.elf_file, pc_addr],
["%saddr2line" % self.toolchain_prefix,
"-pfia", "-e", self.elf_file, pc_addr],
cwd=".")
if not "?? ??:0" in translation:
sys.stderr.write(ANSI_YELLOW + translation + ANSI_NORMAL)
Expand All @@ -375,7 +387,7 @@ def run_gdb(self):
with self: # disable console control
sys.stderr.write(ANSI_NORMAL)
try:
subprocess.call(["xtensa-esp32-elf-gdb",
subprocess.call(["%sgdb" % self.toolchain_prefix,
"-ex", "set serial baud %d" % self.serial.baudrate,
"-ex", "target remote %s" % self.serial.port,
"-ex", "interrupt", # monitor has already parsed the first 'reason' command, need a second
Expand Down Expand Up @@ -404,12 +416,29 @@ def main():
help='Command to run make',
type=str, default='make')

parser.add_argument(
'--toolchain-prefix',
help="Triplet prefix to add before cross-toolchain names",
default=DEFAULT_TOOLCHAIN_PREFIX)

parser.add_argument(
"--eol",
choices=['CR', 'LF', 'CRLF'],
type=lambda c: c.upper(),
help="End of line to use when sending to the serial port",
default='CRLF')

parser.add_argument(
'elf_file', help='ELF file of application',
type=argparse.FileType('r'))

args = parser.parse_args()

if args.port.startswith("/dev/tty."):
args.port = args.port.replace("/dev/tty.", "/dev/cu.")
sys.stderr.write("WARNING: Serial ports accessed as /dev/tty.* will hang gdb if launched. ")
sys.stderr.write("Using %s instead...\n" % args.port)

serial_instance = serial.serial_for_url(args.port, args.baud,
do_not_open=True)
serial_instance.dtr = False
Expand All @@ -428,7 +457,7 @@ def main():
except KeyError:
pass # not running a make jobserver

monitor = Monitor(serial_instance, args.elf_file.name, args.make)
monitor = Monitor(serial_instance, args.elf_file.name, args.make, args.eol)

sys.stderr.write('--- idf_monitor on {p.name} {p.baudrate} ---\n'.format(
p=serial_instance))
Expand Down

0 comments on commit e477ce9

Please sign in to comment.