コード例 #1
0
    def main_loop(self) -> None:
        self._pre_start()

        try:
            while self.console_reader.alive and self.serial_reader.alive:
                try:
                    self._main_loop()
                except KeyboardInterrupt:
                    yellow_print(
                        'To exit from IDF monitor please use \"Ctrl+]\"')
                    self.serial_write(codecs.encode(CTRL_C))
        except SerialStopException:
            normal_print('Stopping condition has been received\n')
        except KeyboardInterrupt:
            pass
        finally:
            try:
                self.console_reader.stop()
                self.serial_reader.stop()
                self.logger.stop_logging()
                # Cancelling _invoke_processing_last_line_timer is not
                # important here because receiving empty data doesn't matter.
                self._invoke_processing_last_line_timer = None
            except Exception:  # noqa
                pass
            normal_print('\n')
コード例 #2
0
 def start_logging(self):  # type: () -> None
     if not self._log_file:
         name = 'log.{}.{}.txt'.format(
             os.path.splitext(os.path.basename(self.elf_file))[0],
             datetime.datetime.now().strftime('%Y%m%d%H%M%S'))
         try:
             self._log_file = open(name, 'wb+')
             yellow_print('\nLogging is enabled into file {}'.format(name))
         except Exception as e:
             red_print('\nLog file {} cannot be created: {}'.format(
                 name, e))
コード例 #3
0
 def stop_logging(self):  # type: () -> None
     if self._log_file:
         try:
             name = self._log_file.name
             self._log_file.close()
             yellow_print(
                 '\nLogging is disabled and file {} has been closed'.format(
                     name))
         except Exception as e:
             red_print('\nLog file cannot be closed: {}'.format(e))
         finally:
             self._log_file = None
コード例 #4
0
ファイル: serial_ext.py プロジェクト: zhouyq1234/esp-idf
    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)
        project_desc = _get_project_desc(ctx, args)
        if project_desc['target'] == 'linux':
            yellow_print('skipping flash since running on linux...')
            return

        esp_port = args.port or _get_default_serial_port(args)
        run_target(action, args, {'ESPBAUD': str(args.baud), 'ESPPORT': esp_port})
コード例 #5
0
    def process_coredump(self):  # type: () -> None
        if self._decode_coredumps != COREDUMP_DECODE_INFO:
            raise NotImplementedError('process_coredump: %s not implemented' %
                                      self._decode_coredumps)

        coredump_script = os.path.join(os.path.dirname(__file__), '..',
                                       'components', 'espcoredump',
                                       'espcoredump.py')
        coredump_file = None
        try:
            # On Windows, the temporary file can't be read unless it is closed.
            # Set delete=False and delete the file manually later.
            with tempfile.NamedTemporaryFile(mode='wb',
                                             delete=False) as coredump_file:
                coredump_file.write(self._coredump_buffer)
                coredump_file.flush()

            if self.websocket_client:
                self._output_enabled = True
                yellow_print('Communicating through WebSocket')
                self.websocket_client.send({
                    'event': 'coredump',
                    'file': coredump_file.name,
                    'prog': self.elf_file
                })
                yellow_print('Waiting for debug finished event')
                self.websocket_client.wait([('event', 'debug_finished')])
                yellow_print('Communications through WebSocket is finished')
            else:
                cmd = [
                    sys.executable, coredump_script, 'info_corefile', '--core',
                    coredump_file.name, '--core-format', 'b64', self.elf_file
                ]
                output = subprocess.check_output(cmd, stderr=subprocess.STDOUT)
                self._output_enabled = True
                self._print(output)
                self._output_enabled = False  # Will be reenabled in check_coredump_trigger_after_print
        except subprocess.CalledProcessError as e:
            yellow_print('Failed to run espcoredump script: {}\n{}\n\n'.format(
                e, e.output))
            self._output_enabled = True
            self._print(COREDUMP_UART_START + b'\n')
            self._print(self._coredump_buffer)
            # end line will be printed in handle_serial_input
        finally:
            if coredump_file is not None:
                try:
                    os.unlink(coredump_file.name)
                except OSError as e:
                    yellow_print(
                        'Couldn\'t remote temporary core dump file ({})'.
                        format(e))
コード例 #6
0
    def check_coredump_trigger_before_print(self,
                                            line):  # type: (bytes) -> None
        if self._decode_coredumps == COREDUMP_DECODE_DISABLE:
            return

        if COREDUMP_UART_PROMPT in line:
            yellow_print('Initiating core dump!')
            self.event_queue.put((TAG_KEY, '\n'))
            return

        if COREDUMP_UART_START in line:
            yellow_print('Core dump started (further output muted)')
            self._reading_coredump = COREDUMP_READING
            self._coredump_buffer = b''
            self._output_enabled = False
            return

        if COREDUMP_UART_END in line:
            self._reading_coredump = COREDUMP_DONE
            yellow_print('\nCore dump finished!')
            self.process_coredump()
            return

        if self._reading_coredump == COREDUMP_READING:
            kb = 1024
            buffer_len_kb = len(self._coredump_buffer) // kb
            self._coredump_buffer += line.replace(b'\r', b'') + b'\n'
            new_buffer_len_kb = len(self._coredump_buffer) // kb
            if new_buffer_len_kb > buffer_len_kb:
                yellow_print('Received %3d kB...' % (new_buffer_len_kb),
                             newline='\r')
コード例 #7
0
 def run_make(self, target):  # type: (str) -> None
     with self:
         if isinstance(self.make, list):
             popen_args = self.make + [target]
         else:
             popen_args = [self.make, target]
         yellow_print('Running %s...' % ' '.join(popen_args))
         p = subprocess.Popen(popen_args, env=os.environ)
         try:
             p.wait()
         except KeyboardInterrupt:
             p.wait()
         if p.returncode != 0:
             self.prompt_next_action('Build failed')
         else:
             self.output_enable(True)
コード例 #8
0
ファイル: tools.py プロジェクト: jkearins/esp-idf
def print_hints(*filenames: str) -> None:
    """Getting output files and printing hints on how to resolve errors based on the output."""
    with open(os.path.join(os.path.dirname(__file__), 'hints.yml'), 'r') as file:
        hints = yaml.safe_load(file)
    for file_name in filenames:
        with open(file_name, 'r') as file:
            output = ' '.join(line.strip() for line in file if line.strip())
        for hint in hints:
            try:
                match = re.compile(hint['re']).findall(output)
            except KeyError:
                raise KeyError("Argument 're' missing in {}. Check hints.yml file.".format(hint))
            except re.error as e:
                raise re.error('{} from hints.yml have {} problem. Check hints.yml file.'.format(hint['re'], e))
            if match:
                extra_info = ', '.join(match) if hint.get('match_to_output', '') else ''
                try:
                    yellow_print(' '.join(['HINT:', hint['hint'].format(extra_info)]))
                except KeyError:
                    raise KeyError("Argument 'hint' missing in {}. Check hints.yml file.".format(hint))
コード例 #9
0
    def check_panic_decode_trigger(self, line):  # type: (bytes) -> None
        if self._decode_panic == PANIC_DECODE_DISABLE:
            return

        if self._reading_panic == PANIC_IDLE and re.search(
                PANIC_START, line.decode('ascii', errors='ignore')):
            self._reading_panic = PANIC_READING
            yellow_print('Stack dump detected')

        if self._reading_panic == PANIC_READING and PANIC_STACK_DUMP in line:
            self._output_enabled = False

        if self._reading_panic == PANIC_READING:
            self._panic_buffer += line.replace(b'\r', b'') + b'\n'

        if self._reading_panic == PANIC_READING and PANIC_END in line:
            self._reading_panic = PANIC_IDLE
            self._output_enabled = True
            self.process_panic_output(self._panic_buffer)
            self._panic_buffer = b''
コード例 #10
0
 def check_gdbstub_trigger(self, line):  # type: (bytes) -> None
     line = self._gdb_buffer + line
     self._gdb_buffer = b''
     m = re.search(b'\\$(T..)#(..)',
                   line)  # look for a gdb "reason" for a break
     if m is not None:
         try:
             chsum = sum(ord(bytes([p])) for p in m.group(1)) & 0xFF
             calc_chsum = int(m.group(2), 16)
         except ValueError:
             return  # payload wasn't valid hex digits
         if chsum == calc_chsum:
             if self.websocket_client:
                 yellow_print('Communicating through WebSocket')
                 self.websocket_client.send({
                     'event': 'gdb_stub',
                     'port': self.serial.port,
                     'prog': self.elf_file
                 })
                 yellow_print('Waiting for debug finished event')
                 self.websocket_client.wait([('event', 'debug_finished')])
                 yellow_print(
                     'Communications through WebSocket is finished')
             else:
                 self.run_gdb()
         else:
             red_print(
                 'Malformed gdb message... calculated checksum %02x received %02x'
                 % (chsum, calc_chsum))
コード例 #11
0
ファイル: tools.py プロジェクト: jkearins/esp-idf
    async def read_and_write_stream(self, input_stream: asyncio.StreamReader, output_filename: str,
                                    output_stream: TextIO=sys.stdout) -> None:
        """read the output of the `input_stream` and then write it into `output_filename` and `output_stream`"""
        def delete_ansi_escape(text: str) -> str:
            ansi_escape = re.compile(r'\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])')
            return ansi_escape.sub('', text)

        def prepare_for_print(out: bytes) -> str:
            # errors='ignore' is here because some chips produce some garbage bytes
            result = out.decode(errors='ignore')
            if not output_stream.isatty():
                # delete escape sequence if we printing in environments where ANSI coloring is disabled
                return delete_ansi_escape(result)
            return result

        def print_progression(output: str) -> None:
            # Print a new line on top of the previous line
            sys.stdout.write('\x1b[K')
            print('\r', end='')
            print(fit_text_in_terminal(output.strip('\n\r')), end='', file=output_stream)

        try:
            with open(output_filename, 'w') as output_file:
                while True:
                    out = await input_stream.readline()
                    if not out:
                        break
                    output = prepare_for_print(out)
                    output_file.write(output)

                    # print output in progression way but only the progression related (that started with '[') and if verbose flag is not set
                    if self.force_progression and output[0] == '[' and '-v' not in self.args and output_stream.isatty():
                        print_progression(output)
                    else:
                        print(output, end='', file=output_stream)
        except (RuntimeError, EnvironmentError) as e:
            yellow_print('WARNING: The exception {} was raised and we can\'t capture all your {} and '
                         'hints on how to resolve errors can be not accurate.'.format(e, output_stream.name.strip('<>')))
コード例 #12
0
    def process_panic_output(self, panic_output):  # type: (bytes) -> None
        panic_output_decode_script = os.path.join(os.path.dirname(__file__),
                                                  '..', 'tools',
                                                  'gdb_panic_server.py')
        panic_output_file = None
        try:
            # On Windows, the temporary file can't be read unless it is closed.
            # Set delete=False and delete the file manually later.
            with tempfile.NamedTemporaryFile(
                    mode='wb', delete=False) as panic_output_file:
                panic_output_file.write(panic_output)
                panic_output_file.flush()

            cmd = [
                self.toolchain_prefix + 'gdb', '--batch', '-n', self.elf_file,
                '-ex',
                "target remote | \"{python}\" \"{script}\" --target {target} \"{output_file}\""
                .format(python=sys.executable,
                        script=panic_output_decode_script,
                        target=self.target,
                        output_file=panic_output_file.name), '-ex', 'bt'
            ]

            output = subprocess.check_output(cmd, stderr=subprocess.STDOUT)
            yellow_print('\nBacktrace:\n\n')
            self._print(output)
        except subprocess.CalledProcessError as e:
            yellow_print(
                'Failed to run gdb_panic_server.py script: {}\n{}\n\n'.format(
                    e, e.output))
            self._print(panic_output)
        finally:
            if panic_output_file is not None:
                try:
                    os.unlink(panic_output_file.name)
                except OSError as e:
                    yellow_print(
                        'Couldn\'t remove temporary panic output file ({})'.
                        format(e))
コード例 #13
0
def main():  # type: () -> None
    parser = argparse.ArgumentParser(
        'idf_monitor - a serial output monitor for esp-idf')

    parser.add_argument('--port',
                        '-p',
                        help='Serial port device',
                        default=os.environ.get('ESPTOOL_PORT', '/dev/ttyUSB0'))

    parser.add_argument(
        '--disable-address-decoding',
        '-d',
        help=
        "Don't print lines about decoded addresses from the application ELF file",
        action='store_true',
        default=True if os.environ.get('ESP_MONITOR_DECODE') == 0 else False)

    parser.add_argument('--baud',
                        '-b',
                        help='Serial port baud rate',
                        type=int,
                        default=os.getenv('IDF_MONITOR_BAUD',
                                          os.getenv('MONITORBAUD', 115200)))

    parser.add_argument('--make',
                        '-m',
                        help='Command to run make',
                        type=str,
                        default='make')

    parser.add_argument('--encrypted',
                        help='Use encrypted targets while running make',
                        action='store_true')

    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='CR')

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

    parser.add_argument('--print_filter',
                        help='Filtering string',
                        default=DEFAULT_PRINT_FILTER)

    parser.add_argument(
        '--decode-coredumps',
        choices=[COREDUMP_DECODE_INFO, COREDUMP_DECODE_DISABLE],
        default=COREDUMP_DECODE_INFO,
        help='Handling of core dumps found in serial output')

    parser.add_argument(
        '--decode-panic',
        choices=[PANIC_DECODE_BACKTRACE, PANIC_DECODE_DISABLE],
        default=PANIC_DECODE_DISABLE,
        help='Handling of panic handler info found in serial output')

    parser.add_argument(
        '--target',
        help='Target name (used when stack dump decoding is enabled)',
        default=os.environ.get('IDF_TARGET', 'esp32'))

    parser.add_argument('--revision',
                        help='Revision of the target',
                        type=int,
                        default=0)

    parser.add_argument(
        '--ws',
        default=os.environ.get('ESP_IDF_MONITOR_WS', None),
        help=
        'WebSocket URL for communicating with IDE tools for debugging purposes'
    )

    args = parser.parse_args()

    # GDB uses CreateFile to open COM port, which requires the COM name to be r'\\.\COMx' if the COM
    # number is larger than 10
    if os.name == 'nt' and args.port.startswith('COM'):
        args.port = args.port.replace('COM', r'\\.\COM')
        yellow_print(
            '--- WARNING: GDB cannot open serial ports accessed as COMx')
        yellow_print('--- Using %s instead...' % args.port)
    elif args.port.startswith('/dev/tty.') and sys.platform == 'darwin':
        args.port = args.port.replace('/dev/tty.', '/dev/cu.')
        yellow_print(
            '--- WARNING: Serial ports accessed as /dev/tty.* will hang gdb if launched.'
        )
        yellow_print('--- Using %s instead...' % args.port)

    serial_instance = serial.serial_for_url(args.port,
                                            args.baud,
                                            do_not_open=True)
    serial_instance.dtr = False
    serial_instance.rts = False
    args.elf_file.close()  # don't need this as a file

    # remove the parallel jobserver arguments from MAKEFLAGS, as any
    # parent make is only running 1 job (monitor), so we can re-spawn
    # all of the child makes we need (the -j argument remains part of
    # MAKEFLAGS)
    try:
        makeflags = os.environ['MAKEFLAGS']
        makeflags = re.sub(r'--jobserver[^ =]*=[0-9,]+ ?', '', makeflags)
        os.environ['MAKEFLAGS'] = makeflags
    except KeyError:
        pass  # not running a make jobserver

    # Pass the actual used port to callee of idf_monitor (e.g. make) through `ESPPORT` environment
    # variable
    # To make sure the key as well as the value are str type, by the requirements of subprocess
    espport_key = str('ESPPORT')
    espport_val = str(args.port)
    os.environ.update({espport_key: espport_val})

    ws = WebSocketClient(args.ws) if args.ws else None
    try:
        monitor = Monitor(
            serial_instance,
            args.elf_file.name,
            args.print_filter,
            args.make,
            args.encrypted,
            args.toolchain_prefix,
            args.eol,
            args.decode_coredumps,
            args.decode_panic,
            args.target,
            ws,
            enable_address_decoding=not args.disable_address_decoding)

        yellow_print('--- idf_monitor on {p.name} {p.baudrate} ---'.format(
            p=serial_instance))
        yellow_print(
            '--- Quit: {} | Menu: {} | Help: {} followed by {} ---'.format(
                key_description(monitor.console_parser.exit_key),
                key_description(monitor.console_parser.menu_key),
                key_description(monitor.console_parser.menu_key),
                key_description(CTRL_H)))
        if args.print_filter != DEFAULT_PRINT_FILTER:
            yellow_print('--- Print filter: {} ---'.format(args.print_filter))

        monitor.main_loop()
    finally:
        if ws:
            ws.close()
コード例 #14
0
ファイル: serial_ext.py プロジェクト: jkearins/esp-idf
    def monitor(action: str, ctx: click.core.Context, args: PropertyDict,
                print_filter: str, monitor_baud: str, encrypted: bool,
                no_reset: bool, timestamps: bool, timestamp_format: str,
                force_color: bool) -> None:
        """
        Run idf_monitor.py to watch build output
        """
        project_desc = _get_project_desc(ctx, args)
        elf_file = os.path.join(args.build_dir, project_desc['app_elf'])

        idf_monitor = os.path.join(os.environ['IDF_PATH'],
                                   'tools/idf_monitor.py')
        monitor_args = [PYTHON, idf_monitor]

        if project_desc['target'] != 'linux':
            if no_reset and args.port is None:
                msg = (
                    'WARNING: --no-reset is ignored. '
                    'Please specify the port with the --port argument in order to use this option.'
                )
                yellow_print(msg)
                no_reset = False

            esp_port = args.port or _get_default_serial_port(args)
            monitor_args += ['-p', esp_port]

            baud = monitor_baud or os.getenv('IDF_MONITOR_BAUD') or os.getenv(
                'MONITORBAUD')

            if baud is None:
                # Baud hasn't been changed locally (by local baud argument nor by environment variables)
                #
                # Use the global baud rate if it has been changed by the command line.
                # Use project_desc['monitor_baud'] as the last option.

                global_baud_defined = ctx._parameter_source[
                    'baud'] == click.core.ParameterSource.COMMANDLINE
                baud = args.baud if global_baud_defined else project_desc[
                    'monitor_baud']

            monitor_args += ['-b', 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]

        if elf_file:
            monitor_args += [elf_file]

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

        if no_reset:
            monitor_args += ['--no-reset']

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

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

        if force_color or os.name == 'nt':
            monitor_args += ['--force-color']

        idf_py = [PYTHON] + _get_commandline_options(
            ctx)  # commands to re-run idf.py
        monitor_args += ['-m', ' '.join("'%s'" % a for a in idf_py)]
        hints = not args.no_hints

        RunTool('idf_monitor',
                monitor_args,
                args.project_dir,
                build_dir=args.build_dir,
                hints=hints)()
コード例 #15
0
    def main_loop(self):
        # type: () -> None
        self.console_reader.start()
        self.serial_reader.start()
        self.gdb_exit = False
        self.start_cmd_sent = False
        try:
            while self.console_reader.alive and self.serial_reader.alive:
                try:
                    if self.gdb_exit is True:
                        self.gdb_exit = False

                        time.sleep(0.3)
                        try:
                            # Continue the program after exit from the GDB
                            self.serial.write(codecs.encode('+$c#63'))
                            self.start_cmd_sent = True
                        except serial.SerialException:
                            pass  # this shouldn't happen, but sometimes port has closed in serial thread
                        except UnicodeEncodeError:
                            pass  # this can happen if a non-ascii character was passed, ignoring

                    try:
                        item = self.cmd_queue.get_nowait()
                    except queue.Empty:
                        try:
                            item = self.event_queue.get(True, 0.03)
                        except queue.Empty:
                            continue

                    (event_tag, data) = item

                    if event_tag == TAG_CMD:
                        self.handle_commands(data, self.target)
                    elif event_tag == TAG_KEY:
                        try:
                            self.serial.write(codecs.encode(data))
                        except serial.SerialException:
                            pass  # this shouldn't happen, but sometimes port has closed in serial thread
                        except UnicodeEncodeError:
                            pass  # this can happen if a non-ascii character was passed, ignoring
                    elif event_tag == TAG_SERIAL:
                        self.handle_serial_input(data)
                        if self._invoke_processing_last_line_timer is not None:
                            self._invoke_processing_last_line_timer.cancel()
                        self._invoke_processing_last_line_timer = threading.Timer(
                            0.1, self.invoke_processing_last_line)
                        self._invoke_processing_last_line_timer.start()
                        # If no futher data is received in the next short period
                        # of time then the _invoke_processing_last_line_timer
                        # generates an event which will result in the finishing of
                        # the last line. This is fix for handling lines sent
                        # without EOL.
                    elif event_tag == TAG_SERIAL_FLUSH:
                        self.handle_serial_input(data, finalize_line=True)
                    else:
                        raise RuntimeError('Bad event data %r' %
                                           ((event_tag, data), ))
                except KeyboardInterrupt:
                    try:
                        yellow_print(
                            'To exit from IDF monitor please use \"Ctrl+]\"')
                        self.serial.write(codecs.encode('\x03'))
                    except serial.SerialException:
                        pass  # this shouldn't happen, but sometimes port has closed in serial thread
                    except UnicodeEncodeError:
                        pass  # this can happen if a non-ascii character was passed, ignoring
        except SerialStopException:
            normal_print('Stopping condition has been received\n')
        except KeyboardInterrupt:
            pass
        finally:
            try:
                self.console_reader.stop()
                self.serial_reader.stop()
                self.stop_logging()
                # Cancelling _invoke_processing_last_line_timer is not
                # important here because receiving empty data doesn't matter.
                self._invoke_processing_last_line_timer = None
            except Exception:
                pass
            normal_print('\n')
コード例 #16
0
    def output_toggle(self):  # type: () -> None
        self._output_enabled = not self._output_enabled

        yellow_print(
            '\nToggle output display: {}, Type Ctrl-T Ctrl-Y to show/disable output again.'
            .format(self._output_enabled))
コード例 #17
0
ファイル: idf_monitor.py プロジェクト: jkearins/esp-idf
def main() -> None:
    parser = get_parser()
    args = parser.parse_args()

    # The port name is changed in cases described in the following lines. Use a local argument and
    # avoid the modification of args.port.
    port = args.port

    # GDB uses CreateFile to open COM port, which requires the COM name to be r'\\.\COMx' if the COM
    # number is larger than 10
    if os.name == 'nt' and port.startswith('COM'):
        port = port.replace('COM', r'\\.\COM')
        yellow_print(
            '--- WARNING: GDB cannot open serial ports accessed as COMx')
        yellow_print('--- Using %s instead...' % port)
    elif port.startswith('/dev/tty.') and sys.platform == 'darwin':
        port = port.replace('/dev/tty.', '/dev/cu.')
        yellow_print(
            '--- WARNING: Serial ports accessed as /dev/tty.* will hang gdb if launched.'
        )
        yellow_print('--- Using %s instead...' % port)

    if isinstance(args.elf_file, io.BufferedReader):
        elf_file = args.elf_file.name
        args.elf_file.close()  # don't need this as a file
    else:
        elf_file = args.elf_file

    # remove the parallel jobserver arguments from MAKEFLAGS, as any
    # parent make is only running 1 job (monitor), so we can re-spawn
    # all of the child makes we need (the -j argument remains part of
    # MAKEFLAGS)
    try:
        makeflags = os.environ[MAKEFLAGS_ENVIRON]
        makeflags = re.sub(r'--jobserver[^ =]*=[0-9,]+ ?', '', makeflags)
        os.environ[MAKEFLAGS_ENVIRON] = makeflags
    except KeyError:
        pass  # not running a make jobserver

    ws = WebSocketClient(args.ws) if args.ws else None
    try:
        cls: Type[Monitor]
        if args.target == 'linux':
            serial_instance = None
            cls = LinuxMonitor
            yellow_print('--- idf_monitor on linux ---')
        else:
            serial_instance = serial.serial_for_url(port,
                                                    args.baud,
                                                    do_not_open=True)
            serial_instance.dtr = False
            serial_instance.rts = False

            # Pass the actual used port to callee of idf_monitor (e.g. idf.py/cmake) through `ESPPORT` environment
            # variable.
            # Note that the port must be original port argument without any replacement done in IDF Monitor (idf.py
            # has a check for this).
            # To make sure the key as well as the value are str type, by the requirements of subprocess
            espport_val = str(args.port)
            os.environ.update({ESPPORT_ENVIRON: espport_val})

            cls = SerialMonitor
            yellow_print('--- idf_monitor on {p.name} {p.baudrate} ---'.format(
                p=serial_instance))

        monitor = cls(serial_instance, elf_file, args.print_filter, args.make,
                      args.encrypted, not args.no_reset, args.toolchain_prefix,
                      args.eol, args.decode_coredumps, args.decode_panic,
                      args.target, ws, not args.disable_address_decoding,
                      args.timestamps, args.timestamp_format, args.force_color)

        yellow_print(
            '--- Quit: {} | Menu: {} | Help: {} followed by {} ---'.format(
                key_description(monitor.console_parser.exit_key),
                key_description(monitor.console_parser.menu_key),
                key_description(monitor.console_parser.menu_key),
                key_description(CTRL_H)))
        if args.print_filter != DEFAULT_PRINT_FILTER:
            yellow_print('--- Print filter: {} ---'.format(args.print_filter))
        monitor.main_loop()
    except KeyboardInterrupt:
        pass
    finally:
        if ws:
            ws.close()
コード例 #18
0
ファイル: idf_monitor.py プロジェクト: llawall/esp-idf
def main():  # type: () -> None

    parser = get_parser()
    args = parser.parse_args()

    # GDB uses CreateFile to open COM port, which requires the COM name to be r'\\.\COMx' if the COM
    # number is larger than 10
    if os.name == 'nt' and args.port.startswith('COM'):
        args.port = args.port.replace('COM', r'\\.\COM')
        yellow_print(
            '--- WARNING: GDB cannot open serial ports accessed as COMx')
        yellow_print('--- Using %s instead...' % args.port)
    elif args.port.startswith('/dev/tty.') and sys.platform == 'darwin':
        args.port = args.port.replace('/dev/tty.', '/dev/cu.')
        yellow_print(
            '--- WARNING: Serial ports accessed as /dev/tty.* will hang gdb if launched.'
        )
        yellow_print('--- Using %s instead...' % args.port)

    serial_instance = serial.serial_for_url(args.port,
                                            args.baud,
                                            do_not_open=True)
    serial_instance.dtr = False
    serial_instance.rts = False
    args.elf_file.close()  # don't need this as a file

    # remove the parallel jobserver arguments from MAKEFLAGS, as any
    # parent make is only running 1 job (monitor), so we can re-spawn
    # all of the child makes we need (the -j argument remains part of
    # MAKEFLAGS)
    try:
        makeflags = os.environ[MAKEFLAGS_ENVIRON]
        makeflags = re.sub(r'--jobserver[^ =]*=[0-9,]+ ?', '', makeflags)
        os.environ[MAKEFLAGS_ENVIRON] = makeflags
    except KeyError:
        pass  # not running a make jobserver

    # Pass the actual used port to callee of idf_monitor (e.g. make) through `ESPPORT` environment
    # variable
    # To make sure the key as well as the value are str type, by the requirements of subprocess
    espport_val = str(args.port)
    os.environ.update({ESPPORT_ENVIRON: espport_val})

    ws = WebSocketClient(args.ws) if args.ws else None
    try:
        monitor = Monitor(
            serial_instance,
            args.elf_file.name,
            args.print_filter,
            args.make,
            args.encrypted,
            args.toolchain_prefix,
            args.eol,
            args.decode_coredumps,
            args.decode_panic,
            args.target,
            ws,
            enable_address_decoding=not args.disable_address_decoding,
            timestamps=args.timestamps,
            timestamp_format=args.timestamp_format)

        yellow_print('--- idf_monitor on {p.name} {p.baudrate} ---'.format(
            p=serial_instance))
        yellow_print(
            '--- Quit: {} | Menu: {} | Help: {} followed by {} ---'.format(
                key_description(monitor.console_parser.exit_key),
                key_description(monitor.console_parser.menu_key),
                key_description(monitor.console_parser.menu_key),
                key_description(CTRL_H)))
        if args.print_filter != DEFAULT_PRINT_FILTER:
            yellow_print('--- Print filter: {} ---'.format(args.print_filter))
        monitor.main_loop()
    except KeyboardInterrupt:
        pass
    finally:
        if ws:
            ws.close()
コード例 #19
0
ファイル: idf_monitor.py プロジェクト: llawall/esp-idf
    def main_loop(self):
        # type: () -> None
        self.console_reader.start()
        self.serial_reader.start()
        self.gdb_helper.gdb_exit = False
        self.serial_handler.start_cmd_sent = False
        try:
            while self.console_reader.alive and self.serial_reader.alive:
                try:
                    if self.gdb_helper.gdb_exit:
                        self.gdb_helper.gdb_exit = False
                        time.sleep(GDB_EXIT_TIMEOUT)
                        try:
                            # Continue the program after exit from the GDB
                            self.serial.write(
                                codecs.encode(GDB_UART_CONTINUE_COMMAND))
                            self.serial_handler.start_cmd_sent = True
                        except serial.SerialException:
                            pass  # this shouldn't happen, but sometimes port has closed in serial thread
                        except UnicodeEncodeError:
                            pass  # this can happen if a non-ascii character was passed, ignoring

                    try:
                        item = self.cmd_queue.get_nowait()
                    except queue.Empty:
                        try:
                            item = self.event_queue.get(
                                timeout=EVENT_QUEUE_TIMEOUT)
                        except queue.Empty:
                            continue

                    event_tag, data = item
                    if event_tag == TAG_CMD:
                        self.serial_handler.handle_commands(
                            data, self.target, self.run_make,
                            self.console_reader, self.serial_reader)
                    elif event_tag == TAG_KEY:
                        try:
                            self.serial.write(codecs.encode(data))
                        except serial.SerialException:
                            pass  # this shouldn't happen, but sometimes port has closed in serial thread
                        except UnicodeEncodeError:
                            pass  # this can happen if a non-ascii character was passed, ignoring
                    elif event_tag == TAG_SERIAL:
                        self.serial_handler.handle_serial_input(
                            data, self.console_parser, self.coredump,
                            self.gdb_helper, self._line_matcher,
                            self.check_gdb_stub_and_run)
                        if self._invoke_processing_last_line_timer is not None:
                            self._invoke_processing_last_line_timer.cancel()
                        self._invoke_processing_last_line_timer = threading.Timer(
                            LAST_LINE_THREAD_INTERVAL,
                            self.invoke_processing_last_line)
                        self._invoke_processing_last_line_timer.start()
                        # If no further data is received in the next short period
                        # of time then the _invoke_processing_last_line_timer
                        # generates an event which will result in the finishing of
                        # the last line. This is fix for handling lines sent
                        # without EOL.
                    elif event_tag == TAG_SERIAL_FLUSH:
                        self.serial_handler.handle_serial_input(
                            data,
                            self.console_parser,
                            self.coredump,
                            self.gdb_helper,
                            self._line_matcher,
                            self.check_gdb_stub_and_run,
                            finalize_line=True)
                    else:
                        raise RuntimeError('Bad event data %r' %
                                           ((event_tag, data), ))
                except KeyboardInterrupt:
                    try:
                        yellow_print(
                            'To exit from IDF monitor please use \"Ctrl+]\"')
                        self.serial.write(codecs.encode(CTRL_C))
                    except serial.SerialException:
                        pass  # this shouldn't happen, but sometimes port has closed in serial thread
                    except UnicodeEncodeError:
                        pass  # this can happen if a non-ascii character was passed, ignoring
        except SerialStopException:
            normal_print('Stopping condition has been received\n')
        except KeyboardInterrupt:
            pass
        finally:
            try:
                self.console_reader.stop()
                self.serial_reader.stop()
                self.logger.stop_logging()
                # Cancelling _invoke_processing_last_line_timer is not
                # important here because receiving empty data doesn't matter.
                self._invoke_processing_last_line_timer = None
            except Exception:  # noqa
                pass
            normal_print('\n')