Sfoglia il codice sorgente

Merge branch 'bugfix/dbg_target_hints' into 'master'

tools: enable hints for debug targets

Closes IDF-5795

See merge request espressif/esp-idf!22198
Roland Dobai 3 anni fa
parent
commit
648b1a41c6

+ 1 - 1
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.
 

+ 23 - 25
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

+ 12 - 0
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."