From 4ee00623a3116316dda505e36ebc699f1e77b5a4 Mon Sep 17 00:00:00 2001 From: Frantisek Hrbata Date: Wed, 1 Feb 2023 14:28:23 +0100 Subject: [PATCH 1/3] tools: allow to use hints for debug targets The debug targets are currently not utilizing hints, because they are not using RunTool() helper from tools.py to spawn sub-processes. Adjusting debug targets to use RunTool() would require some significant changes to debug targets and RunTool() as well. Since debug targets are already storing their output in logs, we can use these and process them for hints. Signed-off-by: Frantisek Hrbata --- tools/idf_py_actions/debug_ext.py | 48 +++++++++++++++---------------- 1 file changed, 23 insertions(+), 25 deletions(-) diff --git a/tools/idf_py_actions/debug_ext.py b/tools/idf_py_actions/debug_ext.py index 5e00d02fd5..ab4d90d879 100644 --- a/tools/idf_py_actions/debug_ext.py +++ b/tools/idf_py_actions/debug_ext.py @@ -20,7 +20,8 @@ from esp_coredump import CoreDump from idf_py_actions.constants import OPENOCD_TAGET_CONFIG, OPENOCD_TAGET_CONFIG_DEFAULT from idf_py_actions.errors import FatalError from idf_py_actions.serial_ext import BAUD_RATE, PORT -from idf_py_actions.tools import PropertyDict, ensure_build_directory, get_default_serial_port, get_sdkconfig_value +from idf_py_actions.tools import (PropertyDict, ensure_build_directory, generate_hints, get_default_serial_port, + get_sdkconfig_value, yellow_print) PYTHON = sys.executable ESP_ROM_INFO_FILE = 'roms.json' @@ -73,23 +74,19 @@ def action_extensions(base_actions: Dict, project_path: str) -> Dict: OPENOCD_OUT_FILE = 'openocd_out.txt' GDBGUI_OUT_FILE = 'gdbgui_out.txt' # Internal dictionary of currently active processes, threads and their output files - processes: Dict = {'threads_to_join': [], 'openocd_issues': None} + processes: Dict = {'threads_to_join': [], 'allow_hints': True} - def _check_for_common_openocd_issues(file_name: str, print_all: bool=True) -> Any: - if processes['openocd_issues'] is not None: - return processes['openocd_issues'] - try: - message = 'Please check JTAG connection!' - with open(file_name, 'r') as f: - content = f.read() - if print_all: - print(content) - if re.search(r'Address already in use', content): - message = ('Please check if another process uses the mentioned ports. OpenOCD already running, perhaps in the background?\n' - 'Please list all processes to check if OpenOCD is already running; if so, terminate it before starting OpenOCD from idf.py') - finally: - processes['openocd_issues'] = message - return message + def _print_hints(file_name: str) -> None: + if not processes['allow_hints']: + return + + for hint in generate_hints(file_name): + if sys.stderr.isatty(): + yellow_print(hint) + else: + # Hints go to stderr. Flush stdout, so hints are printed last. + sys.stdout.flush() + print(hint, file=sys.stderr) def _check_openocd_errors(fail_if_openocd_failed: Dict, target: str, ctx: Context) -> None: if fail_if_openocd_failed: @@ -103,16 +100,16 @@ def action_extensions(base_actions: Dict, project_path: str) -> Dict: break with open(name, 'r') as f: content = f.read() - if re.search(r'no device found', content): - break if re.search(r'Listening on port \d+ for gdb connections', content): # expect OpenOCD has started successfully - stop watching return time.sleep(0.5) - else: - return - # OpenOCD exited or error message detected -> print possible output and terminate - raise FatalError('Action "{}" failed due to errors in OpenOCD:\n{}'.format(target, _check_for_common_openocd_issues(name)), ctx) + + # OpenOCD exited or is not listening -> print full log and terminate + with open(name, 'r') as f: + print(f.read()) + + raise FatalError('Action "{}" failed due to errors in OpenOCD'.format(target), ctx) def _terminate_async_target(target: str) -> None: if target in processes and processes[target] is not None: @@ -129,8 +126,8 @@ def action_extensions(base_actions: Dict, project_path: str) -> Dict: time.sleep(0.1) else: p.kill() - if target + '_outfile_name' in processes and target == 'openocd': - print(_check_for_common_openocd_issues(processes[target + '_outfile_name'], print_all=False)) + if target + '_outfile_name' in processes: + _print_hints(processes[target + '_outfile_name']) except Exception as e: print(e) print('Failed to close/kill {}'.format(target)) @@ -456,6 +453,7 @@ def action_extensions(base_actions: Dict, project_path: str) -> Dict: tasks.insert(0, tasks.pop(index)) break + processes['allow_hints'] = not ctx.params['no_hints'] debug_targets = any([task.name in ('openocd', 'gdbgui') for task in tasks]) if debug_targets: # Register the meta cleanup callback -> called on FatalError From dc580bdc97180db3e60afcbef95a4f230a564a14 Mon Sep 17 00:00:00 2001 From: Frantisek Hrbata Date: Wed, 1 Feb 2023 14:37:17 +0100 Subject: [PATCH 2/3] tools: add hints for openocd This moves one hint, which was hardcoded in debug_ext.py to hints.yml and adds a new one when openocd process does not have permissions to the USB JTAG/serial device. Also hint replacing the original 'Please check JTAG connection!' hardcoded message is added. Suggested-by: Alexey Lapshin Signed-off-by: Frantisek Hrbata --- tools/idf_py_actions/hints.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tools/idf_py_actions/hints.yml b/tools/idf_py_actions/hints.yml index 802c356203..dabe8da0ff 100644 --- a/tools/idf_py_actions/hints.yml +++ b/tools/idf_py_actions/hints.yml @@ -278,3 +278,15 @@ re: "fatal error: esp_partition.h: No such file or directory" hint: "All the Partition APIs have been moved to the new component 'esp_partition' - please, update your project dependencies. See Storage migration guide 5.x for more details." match_to_output: True + +- + re: "esp_usb_jtag: could not find or open device!" + hint: "Please check the wire connection to debugging device or access rights to a serial port." + +- + re: "Error: couldn't bind [^:]+: Address already in use" + hint: "Please check if another process uses the mentioned ports. OpenOCD already running, perhaps in the background?\nPlease list all processes to check if OpenOCD is already running; if so, terminate it before starting OpenOCD from idf.py" + +- + re: "Error: libusb_open\\(\\) failed with LIBUSB_ERROR_ACCESS" + hint: "OpenOCD process does not have permissions to access the USB JTAG/serial device. Please use 'LIBUSB_DEBUG=1 idf.py openocd' to find out the device name and check its access rights." From 4b5e56e08ca1a6dc00209ad45521de7a4645ec3e Mon Sep 17 00:00:00 2001 From: Frantisek Hrbata Date: Wed, 1 Feb 2023 15:41:30 +0100 Subject: [PATCH 3/3] docs: hints are supported for gdbui and openocd Hints should be now working for gdbui and openocd. They are not produced via RunTool(), but the hints are used directly. Signed-off-by: Frantisek Hrbata --- docs/en/api-guides/tools/idf-py.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/api-guides/tools/idf-py.rst b/docs/en/api-guides/tools/idf-py.rst index fd02b2eeec..8f8e284b45 100644 --- a/docs/en/api-guides/tools/idf-py.rst +++ b/docs/en/api-guides/tools/idf-py.rst @@ -146,7 +146,7 @@ or partition table as applicable. Hints on how to resolve errors ============================== -``idf.py`` will try to suggest hints on how to resolve errors. It works with a database of hints stored in :idf_file:`tools/idf_py_actions/hints.yml` and the hints will be printed if a match is found for the given error. The monitor, menuconfig, gdb and openocd targets are not supported at the moment by automatic hints on resolving errors. +``idf.py`` will try to suggest hints on how to resolve errors. It works with a database of hints stored in :idf_file:`tools/idf_py_actions/hints.yml` and the hints will be printed if a match is found for the given error. The monitor and menuconfig targets are not supported at the moment by automatic hints on resolving errors. The ``--no-hints`` argument of ``idf.py`` can be used to turn the hints off in case they are not desired.