Esempio n. 1
0
    def fullclean(action: str, ctx: Context, args: PropertyDict) -> None:
        build_dir = args.build_dir
        if not os.path.isdir(build_dir):
            print("Build directory '%s' not found. Nothing to clean." % build_dir)
            return
        if len(os.listdir(build_dir)) == 0:
            print("Build directory '%s' is empty. Nothing to clean." % build_dir)
            return

        if not os.path.exists(os.path.join(build_dir, 'CMakeCache.txt')):
            raise FatalError(
                "Directory '%s' doesn't seem to be a CMake build directory. Refusing to automatically "
                "delete files in this directory. Delete the directory manually to 'clean' it." % build_dir)
        red_flags = ['CMakeLists.txt', '.git', '.svn']
        for red in red_flags:
            red = os.path.join(build_dir, red)
            if os.path.exists(red):
                raise FatalError(
                    "Refusing to automatically delete files in directory containing '%s'. Delete files manually if you're sure."
                    % red)
        if args.verbose and len(build_dir) > 1:
            print('The following symlinks were identified and removed:\n%s' % '\n'.join(build_dir))
        for f in os.listdir(build_dir):  # TODO: once we are Python 3 only, this can be os.scandir()
            f = os.path.join(build_dir, f)
            if args.verbose:
                print('Removing: %s' % f)
            if os.path.isdir(f):
                shutil.rmtree(f)
            else:
                os.remove(f)
Esempio n. 2
0
    def openocd(action, ctx, args, openocd_scripts, openocd_commands):
        """
        Execute openocd as external tool
        """
        if os.getenv("OPENOCD_SCRIPTS") is None:
            raise FatalError("OPENOCD_SCRIPTS not found in the environment: Please run export.sh/export.bin", ctx)
        openocd_arguments = os.getenv("OPENOCD_COMMANDS") if openocd_commands is None else openocd_commands
        project_desc = get_project_desc(args, ctx)
        if openocd_arguments is None:
            # use default value if commands not defined in the environment nor command line
            if project_desc["target"] == "esp32":
                openocd_arguments = "-f board/esp32-wrover-kit-3.3v.cfg"
            else:
                openocd_arguments = "-f interface/ftdi/esp32_devkitj_v1.cfg -f target/{}.cfg".format(project_desc["target"])
            print('Note: OpenOCD cfg not found (via env variable OPENOCD_COMMANDS nor as a --openocd-commands argument)\n'
                  'OpenOCD arguments default to: "{}"'.format(openocd_arguments))
        # script directory is taken from the environment by OpenOCD, update only if command line arguments to override
        if openocd_scripts is not None:
            openocd_arguments += " -s {}".format(openocd_scripts)
        local_dir = project_desc["build_dir"]
        args = ["openocd"] + shlex.split(openocd_arguments)
        openocd_out_name = os.path.join(local_dir, OPENOCD_OUT_FILE)
        openocd_out = open(openocd_out_name, "a+")
        try:
            process = subprocess.Popen(args, stdout=openocd_out, stderr=subprocess.STDOUT, bufsize=1)
        except Exception as e:
            print(e)
            raise FatalError("Error starting openocd. Please make sure it is installed and is present in executable paths", ctx)

        processes["openocd"] = process
        processes["openocd_outfile"] = openocd_out
        processes["openocd_outfile_name"] = openocd_out_name
        print("OpenOCD started as a background task {}".format(process.pid))
Esempio n. 3
0
    def fullclean(action, ctx, args):
        build_dir = args.build_dir
        if not os.path.isdir(build_dir):
            print("Build directory '%s' not found. Nothing to clean." % build_dir)
            return
        if len(os.listdir(build_dir)) == 0:
            print("Build directory '%s' is empty. Nothing to clean." % build_dir)
            return

        if not os.path.exists(os.path.join(build_dir, "CMakeCache.txt")):
            raise FatalError(
                "Directory '%s' doesn't seem to be a CMake build directory. Refusing to automatically "
                "delete files in this directory. Delete the directory manually to 'clean' it." % build_dir)
        red_flags = ["CMakeLists.txt", ".git", ".svn"]
        for red in red_flags:
            red = os.path.join(build_dir, red)
            if os.path.exists(red):
                raise FatalError(
                    "Refusing to automatically delete files in directory containing '%s'. Delete files manually if you're sure."
                    % red)
        # OK, delete everything in the build directory...
        # Note: Python 2.7 doesn't detect symlinks on Windows (it is supported form 3.2). Tools promising to not
        # follow symlinks will actually follow them. Deleting the build directory with symlinks deletes also items
        # outside of this directory.
        deleted_symlinks = _delete_windows_symlinks(build_dir)
        if args.verbose and len(deleted_symlinks) > 1:
            print("The following symlinks were identified and removed:\n%s" % "\n".join(deleted_symlinks))
        for f in os.listdir(build_dir):  # TODO: once we are Python 3 only, this can be os.scandir()
            f = os.path.join(build_dir, f)
            if args.verbose:
                print("Removing: %s" % f)
            if os.path.isdir(f):
                shutil.rmtree(f)
            else:
                os.remove(f)
Esempio n. 4
0
def check_environment():
    """
    Verify the environment contains the top-level tools we need to operate

    (cmake will check a lot of other things)
    """
    checks_output = []

    if not executable_exists(['cmake', '--version']):
        debug_print_idf_version()
        raise FatalError("'cmake' must be available on the PATH to use %s" %
                         PROG)

    # verify that IDF_PATH env variable is set
    # find the directory idf.py is in, then the parent directory of this, and assume this is IDF_PATH
    detected_idf_path = realpath(os.path.join(os.path.dirname(__file__), '..'))
    if 'IDF_PATH' in os.environ:
        set_idf_path = realpath(os.environ['IDF_PATH'])
        if set_idf_path != detected_idf_path:
            print_warning(
                'WARNING: IDF_PATH environment variable is set to %s but %s path indicates IDF directory %s. '
                'Using the environment variable directory, but results may be unexpected...'
                % (set_idf_path, PROG, detected_idf_path))
    else:
        print_warning('Setting IDF_PATH environment variable: %s' %
                      detected_idf_path)
        os.environ['IDF_PATH'] = detected_idf_path

    try:
        # The Python compatibility check could have been done earlier (tools/detect_python.{sh,fish}) but PATH is
        # not set for import at that time. Even if the check would be done before, the same check needs to be done
        # here as well (for example one can call idf.py from a not properly set-up environment).
        python_version_checker.check()
    except RuntimeError as e:
        raise FatalError(e)

    # check Python dependencies
    checks_output.append('Checking Python dependencies...')
    try:
        out = subprocess.check_output(
            [
                os.environ['PYTHON'],
                os.path.join(os.environ['IDF_PATH'], 'tools',
                             'check_python_dependencies.py'),
            ],
            env=os.environ,
        )

        checks_output.append(out.decode('utf-8', 'ignore').strip())
    except subprocess.CalledProcessError as e:
        print_warning(e.output.decode('utf-8', 'ignore'), stream=sys.stderr)
        debug_print_idf_version()
        raise SystemExit(1)

    return checks_output
Esempio n. 5
0
    def openocd(action: str, ctx: Context, args: PropertyDict,
                openocd_scripts: Optional[str], openocd_commands: str) -> None:
        """
        Execute openocd as external tool
        """
        OPENOCD_TAGET_CONFIG = {
            'esp32': '-f board/esp32-wrover-kit-3.3v.cfg',
            'esp32s2': '-f board/esp32s2-kaluga-1.cfg',
        }
        if os.getenv('OPENOCD_SCRIPTS') is None:
            raise FatalError(
                'OPENOCD_SCRIPTS not found in the environment: Please run export.sh/export.bat',
                ctx)
        openocd_arguments = os.getenv(
            'OPENOCD_COMMANDS'
        ) if openocd_commands is None else openocd_commands
        project_desc = get_project_desc(args, ctx)
        if openocd_arguments is None:
            # use default value if commands not defined in the environment nor command line
            target = project_desc['target']
            default_args = '-f interface/ftdi/esp32_devkitj_v1.cfg -f target/{}.cfg'.format(
                target)
            openocd_arguments = OPENOCD_TAGET_CONFIG.get(target, default_args)
            print(
                'Note: OpenOCD cfg not found (via env variable OPENOCD_COMMANDS nor as a --openocd-commands argument)\n'
                'OpenOCD arguments default to: "{}"'.format(openocd_arguments))
        # script directory is taken from the environment by OpenOCD, update only if command line arguments to override
        if openocd_scripts is not None:
            openocd_arguments += ' -s {}'.format(openocd_scripts)
        local_dir = project_desc['build_dir']
        args = ['openocd'] + shlex.split(openocd_arguments)
        openocd_out_name = os.path.join(local_dir, OPENOCD_OUT_FILE)
        openocd_out = open(openocd_out_name, 'a+')
        try:
            process = subprocess.Popen(args,
                                       stdout=openocd_out,
                                       stderr=subprocess.STDOUT,
                                       bufsize=1)
        except Exception as e:
            print(e)
            raise FatalError(
                'Error starting openocd. Please make sure it is installed and is present in executable paths',
                ctx)

        processes['openocd'] = process
        processes['openocd_outfile'] = openocd_out
        processes['openocd_outfile_name'] = openocd_out_name
        print('OpenOCD started as a background task {}'.format(process.pid))
Esempio n. 6
0
 def _check_openocd_errors(fail_if_openocd_failed, target, ctx):
     if fail_if_openocd_failed:
         if "openocd" in processes and processes["openocd"] is not None:
             p = processes["openocd"]
             name = processes["openocd_outfile_name"]
             # watch OpenOCD (for 5x500ms) to check if it hasn't terminated or outputs an error
             for _ in range(5):
                 if p.poll() is not None:
                     print("OpenOCD exited with {}".format(p.poll()))
                     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
             with open(name, "r") as f:
                 print(f.read())
             raise FatalError(
                 'Action "{}" failed due to errors in OpenOCD: Please check jtag connection!'
                 .format(target), ctx)
Esempio n. 7
0
def _find_usable_locale():
    try:
        locales = subprocess.Popen(['locale', '-a'], stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0]
    except OSError:
        locales = ''
    if isinstance(locales, bytes):
        locales = locales.decode('ascii', 'replace')

    usable_locales = []
    for line in locales.splitlines():
        locale = line.strip()
        locale_name = locale.lower().replace('-', '')

        # C.UTF-8 is the best option, if supported
        if locale_name == 'c.utf8':
            return locale

        if locale_name.endswith('.utf8'):
            # Make a preference of english locales
            if locale.startswith('en_'):
                usable_locales.insert(0, locale)
            else:
                usable_locales.append(locale)

    if not usable_locales:
        raise FatalError(
            'Support for Unicode filenames is required, but no suitable UTF-8 locale was found on your system.'
            ' Please refer to the manual for your operating system for details on locale reconfiguration.')

    return usable_locales[0]
Esempio n. 8
0
 def _check_openocd_errors(fail_if_openocd_failed, target, ctx):
     if fail_if_openocd_failed:
         if 'openocd' in processes and processes['openocd'] is not None:
             p = processes['openocd']
             name = processes['openocd_outfile_name']
             # watch OpenOCD (for 5x500ms) to check if it hasn't terminated or outputs an error
             for _ in range(5):
                 if p.poll() is not None:
                     print('OpenOCD exited with {}'.format(p.poll()))
                     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)
Esempio n. 9
0
    def gdbui(action, ctx, args, gdbgui_port, gdbinit, require_openocd):
        """
        Asynchronous GDB-UI target
        """
        project_desc = get_project_desc(args, ctx)
        local_dir = project_desc['build_dir']
        gdb = project_desc['monitor_toolprefix'] + 'gdb'
        if gdbinit is None:
            gdbinit = os.path.join(local_dir, 'gdbinit')
            create_local_gdbinit(gdbinit, os.path.join(args.build_dir, project_desc['app_elf']))
        args = ['gdbgui', '-g', gdb, '--gdb-args="-x={}"'.format(gdbinit)]
        if gdbgui_port is not None:
            args += ['--port', gdbgui_port]
        gdbgui_out_name = os.path.join(local_dir, GDBGUI_OUT_FILE)
        gdbgui_out = open(gdbgui_out_name, 'a+')
        env = os.environ.copy()
        # The only known solution for https://github.com/cs01/gdbgui/issues/359 is to set the following environment
        # variable. The greenlet package cannot be downgraded for compatibility with other requirements (gdbgui,
        # pygdbmi).
        env['PURE_PYTHON'] = '1'
        try:
            process = subprocess.Popen(args, stdout=gdbgui_out, stderr=subprocess.STDOUT, bufsize=1, env=env)
        except Exception as e:
            print(e)
            raise FatalError('Error starting gdbgui. Please make sure gdbgui can be started', ctx)

        processes['gdbgui'] = process
        processes['gdbgui_outfile'] = gdbgui_out
        processes['gdbgui_outfile_name'] = gdbgui_out_name
        print('gdbgui started as a background task {}'.format(process.pid))
        _check_openocd_errors(fail_if_openocd_failed, action, ctx)
Esempio n. 10
0
    def monitor(action, ctx, args, print_filter, monitor_baud, encrypted, timestamps, timestamp_format):
        """
        Run idf_monitor.py to watch build output
        """

        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]
        esp_port = args.port or _get_default_serial_port(args)
        monitor_args += ['-p', esp_port]

        if not monitor_baud:
            monitor_baud = os.getenv('IDF_MONITOR_BAUD') or os.getenv('MONITORBAUD') or 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_ESP_COREDUMP_DECODE')
        if coredump_decode is not None:
            monitor_args += ['--decode-coredumps', coredump_decode]

        target_arch_riscv = get_sdkconfig_value(project_desc['config_file'], 'CONFIG_IDF_TARGET_ARCH_RISCV')
        monitor_args += ['--target', project_desc['target']]
        revision = project_desc.get('rev')
        if revision:
            monitor_args += ['--revision', revision]

        if target_arch_riscv:
            monitor_args += ['--decode-panic', 'backtrace']

        if print_filter is not None:
            monitor_args += ['--print_filter', print_filter]
        monitor_args += [elf_file]

        if encrypted:
            monitor_args += ['--encrypted']

        if timestamps:
            monitor_args += ['--timestamps']

        if timestamp_format:
            monitor_args += ['--timestamp-format', timestamp_format]

        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)
Esempio n. 11
0
    def gdbui(action, ctx, args, gdbgui_port, gdbinit, require_openocd):
        """
        Asynchronous GDB-UI target
        """
        project_desc = get_project_desc(args, ctx)
        local_dir = project_desc["build_dir"]
        gdb = project_desc["monitor_toolprefix"] + "gdb"
        if gdbinit is None:
            gdbinit = os.path.join(local_dir, 'gdbinit')
            create_local_gdbinit(gdbinit, os.path.join(args.build_dir, project_desc["app_elf"]))
        args = ["gdbgui", "-g", gdb, '--gdb-args="-x={}"'.format(gdbinit)]
        if gdbgui_port is not None:
            args += ["--port", gdbgui_port]
        gdbgui_out_name = os.path.join(local_dir, GDBGUI_OUT_FILE)
        gdbgui_out = open(gdbgui_out_name, "a+")
        try:
            process = subprocess.Popen(args, stdout=gdbgui_out, stderr=subprocess.STDOUT, bufsize=1)
        except Exception as e:
            print(e)
            raise FatalError("Error starting gdbgui. Please make sure gdbgui can be started", ctx)

        processes["gdbgui"] = process
        processes["gdbgui_outfile"] = gdbgui_out
        processes["gdbgui_outfile_name"] = gdbgui_out_name
        print("gdbgui started as a background task {}".format(process.pid))
        _check_openocd_errors(fail_if_openocd_failed, action, ctx)
Esempio n. 12
0
def _find_usable_locale():
    try:
        locales = subprocess.Popen(["locale", "-a"],
                                   stdout=subprocess.PIPE,
                                   stderr=subprocess.PIPE).communicate()[0]
    except OSError:
        locales = ""
    if isinstance(locales, bytes):
        locales = locales.decode("ascii", "replace")

    usable_locales = []
    for line in locales.splitlines():
        locale = line.strip()
        locale_name = locale.lower().replace("-", "")

        # C.UTF-8 is the best option, if supported
        if locale_name == "c.utf8":
            return locale

        if locale_name.endswith(".utf8"):
            # Make a preference of english locales
            if locale.startswith("en_"):
                usable_locales.insert(0, locale)
            else:
                usable_locales.append(locale)

    if not usable_locales:
        raise FatalError(
            "Support for Unicode filenames is required, but no suitable UTF-8 locale was found on your system."
            " Please refer to the manual for your operating system for details on locale reconfiguration."
        )

    return usable_locales[0]
Esempio n. 13
0
    def _get_default_serial_port(args):
        # Import is done here in order to move it after the check_environment() ensured that pyserial has been installed
        try:
            import serial.tools.list_ports
            esptool_path = os.path.join(os.environ['IDF_PATH'],
                                        'components/esptool_py/esptool/')
            sys.path.insert(0, esptool_path)
            import esptool
            ports = list(
                sorted(p.device for p in serial.tools.list_ports.comports()))
            # high baud rate could cause the failure of creation of the connection
            esp = esptool.get_default_connected_device(serial_list=ports,
                                                       port=None,
                                                       connect_attempts=4,
                                                       initial_baud=115200)
            if esp is None:
                raise NoSerialPortFoundError(
                    "No serial ports found. Connect a device, or use '-p PORT' option to set a specific port."
                )

            serial_port = esp.serial_port
            esp._port.close()

            return serial_port
        except NoSerialPortFoundError:
            raise
        except Exception as e:
            raise FatalError(
                'An exception occurred during detection of the serial port: {}'
                .format(e))
Esempio n. 14
0
    def monitor(action, ctx, args, print_filter):
        """
        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))
        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]
        monitor_args += ["-b", project_desc["monitor_baud"]]
        monitor_args += ["--toolchain-prefix", project_desc["monitor_toolprefix"]]

        if print_filter is not None:
            monitor_args += ["--print_filter", print_filter]
        monitor_args += [elf_file]

        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)
Esempio n. 15
0
    def fallback_target(target_name: str, ctx: Context, args: PropertyDict) -> None:
        """
        Execute targets that are not explicitly known to idf.py
        """
        ensure_build_directory(args, ctx.info_name)

        try:
            subprocess.check_output(GENERATORS[args.generator]['dry_run'] + [target_name], cwd=args.build_dir)

        except Exception:
            if target_name in ['clang-check', 'clang-html-report']:
                raise FatalError('command "{}" requires an additional plugin "pyclang". '
                                 'Please install it via "pip install --upgrade pyclang"'.format(target_name))

            raise FatalError(
                'command "%s" is not known to idf.py and is not a %s target' % (target_name, args.generator))

        run_target(target_name, args)
Esempio n. 16
0
 def validate_root_options(ctx: Context, args: PropertyDict, tasks: List) -> None:
     args.project_dir = realpath(args.project_dir)
     if args.build_dir is not None and args.project_dir == realpath(args.build_dir):
         raise FatalError(
             'Setting the build directory to the project directory is not supported. Suggest dropping '
             "--build-dir option, the default is a 'build' subdirectory inside the project directory.")
     if args.build_dir is None:
         args.build_dir = os.path.join(args.project_dir, 'build')
     args.build_dir = realpath(args.build_dir)
Esempio n. 17
0
 def __init__(self, scope=None):
     if scope is None:
         self._scope = 'default'
     elif isinstance(scope, str) and scope in self.SCOPES:
         self._scope = scope
     elif isinstance(scope, Scope):
         self._scope = str(scope)
     else:
         raise FatalError('Unknown scope for option: %s' % scope)
Esempio n. 18
0
 def validate_root_options(ctx, args, tasks):
     args.project_dir = realpath(args.project_dir)
     if args.build_dir is not None and args.project_dir == realpath(args.build_dir):
         raise FatalError(
             "Setting the build directory to the project directory is not supported. Suggest dropping "
             "--build-dir option, the default is a 'build' subdirectory inside the project directory.")
     if args.build_dir is None:
         args.build_dir = os.path.join(args.project_dir, "build")
     args.build_dir = realpath(args.build_dir)
Esempio n. 19
0
    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)
Esempio n. 20
0
def check_environment():
    """
    Verify the environment contains the top-level tools we need to operate

    (cmake will check a lot of other things)
    """
    checks_output = []

    if not executable_exists(['cmake', '--version']):
        debug_print_idf_version()
        raise FatalError("'cmake' must be available on the PATH to use %s" %
                         PROG)

    # verify that IDF_PATH env variable is set
    # find the directory idf.py is in, then the parent directory of this, and assume this is IDF_PATH
    detected_idf_path = realpath(os.path.join(os.path.dirname(__file__), '..'))
    if 'IDF_PATH' in os.environ:
        set_idf_path = realpath(os.environ['IDF_PATH'])
        if set_idf_path != detected_idf_path:
            print_warning(
                'WARNING: IDF_PATH environment variable is set to %s but %s path indicates IDF directory %s. '
                'Using the environment variable directory, but results may be unexpected...'
                % (set_idf_path, PROG, detected_idf_path))
    else:
        print_warning('Setting IDF_PATH environment variable: %s' %
                      detected_idf_path)
        os.environ['IDF_PATH'] = detected_idf_path

    # check Python version
    if sys.version_info[0] < 3:
        print_warning(
            'WARNING: Support for Python 2 is deprecated and will be removed in future versions.'
        )
    elif sys.version_info[0] == 3 and sys.version_info[1] < 6:
        print_warning(
            'WARNING: Python 3 versions older than 3.6 are not supported.')

    # check Python dependencies
    checks_output.append('Checking Python dependencies...')
    try:
        out = subprocess.check_output(
            [
                os.environ['PYTHON'],
                os.path.join(os.environ['IDF_PATH'], 'tools',
                             'check_python_dependencies.py'),
            ],
            env=os.environ,
        )

        checks_output.append(out.decode('utf-8', 'ignore').strip())
    except subprocess.CalledProcessError as e:
        print_warning(e.output.decode('utf-8', 'ignore'), stream=sys.stderr)
        debug_print_idf_version()
        raise SystemExit(1)

    return checks_output
Esempio n. 21
0
 def check_deprecation(ctx):
     """Prints deprecation warnings for arguments in given context"""
     for option in ctx.command.params:
         default = () if option.multiple else option.default
         if isinstance(option, Option) and option.deprecated and ctx.params[option.name] != default:
             deprecation = Deprecation(option.deprecated)
             if deprecation.exit_with_error:
                 raise FatalError('Error: %s' % deprecation.full_message('Option "%s"' % option.name))
             else:
                 print_warning('Warning: %s' % deprecation.full_message('Option "%s"' % option.name))
Esempio n. 22
0
    def idf_version_callback(ctx, param, value):
        if not value or ctx.resilient_parsing:
            return

        version = idf_version()

        if not version:
            raise FatalError("ESP-IDF version cannot be determined")

        print("ESP-IDF %s" % version)
        sys.exit(0)
Esempio n. 23
0
    def idf_version_callback(ctx: Context, param: str, value: str) -> None:
        if not value or ctx.resilient_parsing:
            return

        version = idf_version()

        if not version:
            raise FatalError('ESP-IDF version cannot be determined')

        print('ESP-IDF %s' % version)
        sys.exit(0)
Esempio n. 24
0
    def gdbui(action: str, ctx: Context, args: PropertyDict,
              gdbgui_port: Optional[str], gdbinit: Optional[str],
              require_openocd: bool) -> None:
        """
        Asynchronous GDB-UI target
        """
        project_desc = get_project_desc(args, ctx)
        local_dir = project_desc['build_dir']
        gdb = project_desc['monitor_toolprefix'] + 'gdb'
        if gdbinit is None:
            gdbinit = os.path.join(local_dir, 'gdbinit')
            create_local_gdbinit(
                gdb, gdbinit,
                os.path.join(args.build_dir, project_desc['app_elf']))

        # this is a workaround for gdbgui
        # gdbgui is using shlex.split for the --gdb-args option. When the input is:
        # - '"-x=foo -x=bar"', would return ['foo bar']
        # - '-x=foo', would return ['-x', 'foo'] and mess up the former option '--gdb-args'
        # so for one item, use extra double quotes. for more items, use no extra double quotes.
        gdb_args_list = get_gdb_args(gdbinit, project_desc)
        gdb_args = '"{}"'.format(' '.join(gdb_args_list)) if len(
            gdb_args_list) == 1 else ' '.join(gdb_args_list)
        args = ['gdbgui', '-g', gdb, '--gdb-args', gdb_args]
        print(args)

        if gdbgui_port is not None:
            args += ['--port', gdbgui_port]
        gdbgui_out_name = os.path.join(local_dir, GDBGUI_OUT_FILE)
        gdbgui_out = open(gdbgui_out_name, 'a+')
        env = os.environ.copy()
        # The only known solution for https://github.com/cs01/gdbgui/issues/359 is to set the following environment
        # variable. The greenlet package cannot be downgraded for compatibility with other requirements (gdbgui,
        # pygdbmi).
        env['PURE_PYTHON'] = '1'
        try:
            process = subprocess.Popen(args,
                                       stdout=gdbgui_out,
                                       stderr=subprocess.STDOUT,
                                       bufsize=1,
                                       env=env)
        except Exception as e:
            print(e)
            raise FatalError(
                'Error starting gdbgui. Please make sure gdbgui has been installed with '
                '"install.{sh,bat,ps1,fish} --enable-gdbgui" and can be started.',
                ctx)

        processes['gdbgui'] = process
        processes['gdbgui_outfile'] = gdbgui_out
        processes['gdbgui_outfile_name'] = gdbgui_out_name
        print('gdbgui started as a background task {}'.format(process.pid))
        _check_openocd_errors(fail_if_openocd_failed, action, ctx)
Esempio n. 25
0
    def fallback_target(target_name, ctx, args):
        """
        Execute targets that are not explicitly known to idf.py
        """
        ensure_build_directory(args, ctx.info_name)

        try:
            subprocess.check_output(GENERATORS[args.generator]["dry_run"] + [target_name], cwd=args.build_dir)

        except Exception:
            raise FatalError(
                'command "%s" is not known to idf.py and is not a %s target' % (target_name, args.generator))

        run_target(target_name, args)
Esempio n. 26
0
 def set_target(action: str, ctx: Context, args: PropertyDict, idf_target: str) -> None:
     if (not args['preview'] and idf_target in PREVIEW_TARGETS):
         raise FatalError(
             "%s is still in preview. You have to append '--preview' option after idf.py to use any preview feature."
             % idf_target)
     args.define_cache_entry.append('IDF_TARGET=' + idf_target)
     sdkconfig_path = os.path.join(args.project_dir, 'sdkconfig')
     sdkconfig_old = sdkconfig_path + '.old'
     if os.path.exists(sdkconfig_old):
         os.remove(sdkconfig_old)
     if os.path.exists(sdkconfig_path):
         os.rename(sdkconfig_path, sdkconfig_old)
     print('Set Target to: %s, new sdkconfig created. Existing sdkconfig renamed to sdkconfig.old.' % idf_target)
     ensure_build_directory(args, ctx.info_name, True)
Esempio n. 27
0
 def set_target(action, ctx, args, idf_target):
     if (not args["preview"] and idf_target in PREVIEW_TARGETS):
         raise FatalError(
             "%s is still in preview. You have to append '--preview' option after idf.py to use any preview feature."
             % idf_target)
     args.define_cache_entry.append("IDF_TARGET=" + idf_target)
     sdkconfig_path = os.path.join(args.project_dir, 'sdkconfig')
     sdkconfig_old = sdkconfig_path + ".old"
     if os.path.exists(sdkconfig_old):
         os.remove(sdkconfig_old)
     if os.path.exists(sdkconfig_path):
         os.rename(sdkconfig_path, sdkconfig_old)
     print("Set Target to: %s, new sdkconfig created. Existing sdkconfig renamed to sdkconfig.old." % idf_target)
     ensure_build_directory(args, ctx.info_name, True)
Esempio n. 28
0
    def _get_default_serial_port(args):
        # Import is done here in order to move it after the check_environment() ensured that pyserial has been installed
        try:
            import serial.tools.list_ports
            esptool_path = os.path.join(os.environ["IDF_PATH"], "components/esptool_py/esptool/")
            sys.path.insert(0, esptool_path)
            import esptool
            ports = list(sorted(p.device for p in serial.tools.list_ports.comports()))
            esp = esptool.get_default_connected_device(serial_list=ports, port=None, connect_attempts=3,
                                                       initial_baud=args.baud)

            return esp.serial_port
        except Exception:
            raise FatalError("No serial ports found. Connect a device, or use '-p PORT' option to set a specific port.")
Esempio n. 29
0
        def invoke(self, ctx):
            if self.deprecated:
                deprecation = Deprecation(self.deprecated)
                message = deprecation.full_message('Command "%s"' % self.name)

                if deprecation.exit_with_error:
                    raise FatalError('Error: %s' % message)
                else:
                    print_warning('Warning: %s' % message)

                self.deprecated = False  # disable Click's built-in deprecation handling

            # Print warnings for options
            check_deprecation(ctx)
            return super(Action, self).invoke(ctx)
Esempio n. 30
0
    def gdb(action, ctx, args, gdb_tui, gdbinit, require_openocd):
        """
        Synchronous GDB target
        """
        watch_openocd = Thread(target=_check_openocd_errors,
                               args=(
                                   fail_if_openocd_failed,
                                   action,
                                   ctx,
                               ))
        watch_openocd.start()
        processes['threads_to_join'].append(watch_openocd)
        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 not found. You need to build & flash the project before running debug targets',
                ctx)
        gdb = project_desc['monitor_toolprefix'] + 'gdb'
        local_dir = project_desc['build_dir']
        if gdbinit is None:
            gdbinit = os.path.join(local_dir, 'gdbinit')
            create_local_gdbinit(gdbinit, elf_file)
        args = [gdb, '-x={}'.format(gdbinit)]
        if gdb_tui is not None:
            args += ['-tui']
        t = Thread(target=run_gdb, args=(args, ))
        t.start()
        while True:
            try:
                t.join()
                break
            except KeyboardInterrupt:
                # Catching Keyboard interrupt, as this is used for breaking running program in gdb
                continue
            finally:
                watch_openocd.join()
                try:
                    processes['threads_to_join'].remove(watch_openocd)
                except ValueError:
                    # Valid scenario: watch_openocd task won't be in the list if openocd not started from idf.py
                    pass