| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249 |
- import json
- import os
- import sys
- import click
- from idf_py_actions.errors import FatalError
- from idf_py_actions.global_options import global_options
- from idf_py_actions.tools import ensure_build_directory, run_tool, run_target, get_sdkconfig_value
- PYTHON = sys.executable
- def action_extensions(base_actions, project_path):
- def _get_default_serial_port():
- """ Return a default serial port. esptool can do this (smarter), but it can create
- inconsistencies where esptool.py uses one port and idf_monitor uses another.
- Same logic as esptool.py search order, reverse sort by name and choose the first port.
- """
- # Import is done here in order to move it after the check_environment() ensured that pyserial has been installed
- import serial.tools.list_ports
- ports = list(reversed(sorted(p.device for p in serial.tools.list_ports.comports())))
- try:
- print("Choosing default port %s (use '-p PORT' option to set a specific serial port)" %
- ports[0].encode("ascii", "ignore"))
- return ports[0]
- except IndexError:
- raise FatalError(
- "No serial ports found. Connect a device, or use '-p PORT' option to set a specific port.")
- def _get_esptool_args(args):
- esptool_path = os.path.join(os.environ["IDF_PATH"], "components/esptool_py/esptool/esptool.py")
- if args.port is None:
- args.port = _get_default_serial_port()
- result = [PYTHON, esptool_path]
- result += ["-p", args.port]
- result += ["-b", str(args.baud)]
- with open(os.path.join(args.build_dir, "flasher_args.json")) as f:
- flasher_args = json.load(f)
- extra_esptool_args = flasher_args["extra_esptool_args"]
- result += ["--before", extra_esptool_args["before"]]
- result += ["--after", extra_esptool_args["after"]]
- result += ["--chip", extra_esptool_args["chip"]]
- if not extra_esptool_args["stub"]:
- result += ["--no-stub"]
- return result
- def _get_commandline_options(ctx):
- """ Return all the command line options up to first action """
- # This approach ignores argument parsing done Click
- result = []
- for arg in sys.argv:
- if arg in ctx.command.commands_with_aliases:
- break
- result.append(arg)
- return result
- def monitor(action, ctx, args, print_filter, monitor_baud, encrypted):
- """
- Run idf_monitor.py to watch build output
- """
- if args.port is None:
- args.port = _get_default_serial_port()
- desc_path = os.path.join(args.build_dir, "project_description.json")
- if not os.path.exists(desc_path):
- ensure_build_directory(args, ctx.info_name)
- with open(desc_path, "r") as f:
- project_desc = json.load(f)
- elf_file = os.path.join(args.build_dir, project_desc["app_elf"])
- if not os.path.exists(elf_file):
- raise FatalError("ELF file '%s' not found. You need to build & flash the project before running 'monitor', "
- "and the binary on the device must match the one in the build directory exactly. "
- "Try '%s flash monitor'." % (elf_file, ctx.info_name), ctx)
- idf_monitor = os.path.join(os.environ["IDF_PATH"], "tools/idf_monitor.py")
- monitor_args = [PYTHON, idf_monitor]
- if args.port is not None:
- monitor_args += ["-p", args.port]
- if not monitor_baud:
- if os.getenv("IDF_MONITOR_BAUD"):
- monitor_baud = os.getenv("IDF_MONITOR_BAUD", None)
- elif os.getenv("MONITORBAUD"):
- monitor_baud = os.getenv("MONITORBAUD", None)
- else:
- monitor_baud = project_desc["monitor_baud"]
- monitor_args += ["-b", monitor_baud]
- monitor_args += ["--toolchain-prefix", project_desc["monitor_toolprefix"]]
- coredump_decode = get_sdkconfig_value(project_desc["config_file"], "CONFIG_ESP32_CORE_DUMP_DECODE")
- if coredump_decode is not None:
- monitor_args += ["--decode-coredumps", coredump_decode]
- if print_filter is not None:
- monitor_args += ["--print_filter", print_filter]
- monitor_args += [elf_file]
- if encrypted:
- monitor_args += ['--encrypted']
- idf_py = [PYTHON] + _get_commandline_options(ctx) # commands to re-run idf.py
- monitor_args += ["-m", " ".join("'%s'" % a for a in idf_py)]
- if "MSYSTEM" in os.environ:
- monitor_args = ["winpty"] + monitor_args
- run_tool("idf_monitor", monitor_args, args.project_dir)
- def flash(action, ctx, args):
- """
- Run esptool to flash the entire project, from an argfile generated by the build system
- """
- ensure_build_directory(args, ctx.info_name)
- if args.port is None:
- args.port = _get_default_serial_port()
- run_target(action, args, {"ESPPORT": args.port,
- "ESPBAUD": str(args.baud)})
- def erase_flash(action, ctx, args):
- ensure_build_directory(args, ctx.info_name)
- esptool_args = _get_esptool_args(args)
- esptool_args += ["erase_flash"]
- run_tool("esptool.py", esptool_args, args.build_dir)
- def global_callback(ctx, global_args, tasks):
- encryption = any([task.name in ("encrypted-flash", "encrypted-app-flash") for task in tasks])
- if encryption:
- for task in tasks:
- if task.name == "monitor":
- task.action_args["encrypted"] = True
- break
- baud_rate = {
- "names": ["-b", "--baud"],
- "help": "Baud rate for flashing. The default value can be set with the ESPBAUD environment variable.",
- "scope": "global",
- "envvar": "ESPBAUD",
- "default": 460800,
- }
- port = {
- "names": ["-p", "--port"],
- "help": "Serial port. The default value can be set with the ESPPORT environment variable.",
- "scope": "global",
- "envvar": "ESPPORT",
- "default": None,
- }
- serial_actions = {
- "global_action_callbacks": [global_callback],
- "actions": {
- "flash": {
- "callback": flash,
- "help": "Flash the project.",
- "options": global_options + [baud_rate, port],
- "order_dependencies": ["all", "erase_flash"],
- },
- "erase_flash": {
- "callback": erase_flash,
- "help": "Erase entire flash chip.",
- "options": [baud_rate, port],
- },
- "monitor": {
- "callback":
- monitor,
- "help":
- "Display serial output.",
- "options": [
- port, {
- "names": ["--print-filter", "--print_filter"],
- "help":
- ("Filter monitor output.\n"
- "Restrictions on what to print can be specified as a series of <tag>:<log_level> items "
- "where <tag> is the tag string and <log_level> is a character from the set "
- "{N, E, W, I, D, V, *} referring to a level. "
- 'For example, "tag1:W" matches and prints only the outputs written with '
- 'ESP_LOGW("tag1", ...) or at lower verbosity level, i.e. ESP_LOGE("tag1", ...). '
- 'Not specifying a <log_level> or using "*" defaults to Verbose level.\n'
- 'Please see the IDF Monitor section of the ESP-IDF documentation '
- 'for a more detailed description and further examples.'),
- "default":
- None,
- }, {
- "names": ["--monitor-baud", "-B"],
- "type":
- click.INT,
- "help": ("Baud rate for monitor.\n"
- "If this option is not provided IDF_MONITOR_BAUD and MONITORBAUD "
- "environment variables and project_description.json in build directory "
- "(generated by CMake from project's sdkconfig) "
- "will be checked for default value."),
- }, {
- "names": ["--encrypted", "-E"],
- "is_flag": True,
- "help": ("Enable encrypted flash targets.\n"
- "IDF Monitor will invoke encrypted-flash and encrypted-app-flash targets "
- "if this option is set. This option is set by default if IDF Monitor was invoked "
- "together with encrypted-flash or encrypted-app-flash target."),
- }
- ],
- "order_dependencies": [
- "flash",
- "encrypted-flash",
- "partition_table-flash",
- "bootloader-flash",
- "app-flash",
- "encrypted-app-flash",
- ],
- },
- "partition_table-flash": {
- "callback": flash,
- "help": "Flash partition table only.",
- "options": [baud_rate, port],
- "order_dependencies": ["partition_table", "erase_flash"],
- },
- "bootloader-flash": {
- "callback": flash,
- "help": "Flash bootloader only.",
- "options": [baud_rate, port],
- "order_dependencies": ["bootloader", "erase_flash"],
- },
- "app-flash": {
- "callback": flash,
- "help": "Flash the app only.",
- "options": [baud_rate, port],
- "order_dependencies": ["app", "erase_flash"],
- },
- "encrypted-app-flash": {
- "callback": flash,
- "help": "Flash the encrypted app only.",
- "order_dependencies": ["app", "erase_flash"],
- },
- "encrypted-flash": {
- "callback": flash,
- "help": "Flash the encrypted project.",
- "order_dependencies": ["all", "erase_flash"],
- },
- },
- }
- return serial_actions
|