idf.py: add linux target support for idf.py flash and idf.py monitor

This commit is contained in:
Fu Hanxi 2021-09-23 09:30:20 +08:00
parent 811ed96042
commit bee690aa8d
7 changed files with 270 additions and 225 deletions

View File

@ -4024,11 +4024,9 @@ tools/find_build_apps/common.py
tools/find_build_apps/make.py
tools/gdb_panic_server.py
tools/gen_esp_err_to_name.py
tools/idf_monitor.py
tools/idf_monitor_base/ansi_color_converter.py
tools/idf_monitor_base/argument_parser.py
tools/idf_monitor_base/chip_specific_config.py
tools/idf_monitor_base/console_parser.py
tools/idf_monitor_base/console_reader.py
tools/idf_monitor_base/constants.py
tools/idf_monitor_base/coredump.py
@ -4037,8 +4035,6 @@ tools/idf_monitor_base/gdbhelper.py
tools/idf_monitor_base/line_matcher.py
tools/idf_monitor_base/logger.py
tools/idf_monitor_base/output_helpers.py
tools/idf_monitor_base/serial_handler.py
tools/idf_monitor_base/serial_reader.py
tools/idf_monitor_base/stoppable_thread.py
tools/idf_monitor_base/web_socket_client.py
tools/idf_py_actions/constants.py
@ -4048,7 +4044,6 @@ tools/idf_py_actions/debug_ext.py
tools/idf_py_actions/dfu_ext.py
tools/idf_py_actions/errors.py
tools/idf_py_actions/global_options.py
tools/idf_py_actions/serial_ext.py
tools/idf_py_actions/tools.py
tools/idf_py_actions/uf2_ext.py
tools/kconfig/conf.c
@ -4160,7 +4155,6 @@ tools/test_apps/system/startup/app_test.py
tools/test_apps/system/startup/main/chip_info_patch.c
tools/test_apps/system/startup/main/test_startup_main.c
tools/test_idf_monitor/dummy.c
tools/test_idf_monitor/idf_monitor_wrapper.py
tools/test_idf_monitor/run_test_idf_monitor.py
tools/test_idf_py/extra_path/some_ext.py
tools/test_idf_py/idf_ext.py

View File

@ -9,19 +9,8 @@
# - If core dump output is detected, it is converted to a human-readable report
# by espcoredump.py.
#
# Copyright 2015-2021 Espressif Systems (Shanghai) CO LTD
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Apache-2.0
#
# Contains elements taken from miniterm "Very simple serial terminal" which
# is part of pySerial. https://github.com/pyserial/pyserial
@ -30,23 +19,17 @@
# Originally released under BSD-3-Clause license.
#
from __future__ import division, print_function, unicode_literals
import codecs
import os
import queue
import re
import shlex
import subprocess
import sys
import threading
import time
from builtins import bytes, object
try:
from typing import Any, List, Optional, Union # noqa
except ImportError:
pass
import queue
import shlex
import sys
from builtins import bytes
from typing import Any, List, Optional, Type, Union
import serial
import serial.tools.list_ports
@ -67,16 +50,16 @@ from idf_monitor_base.line_matcher import LineMatcher
from idf_monitor_base.logger import Logger
from idf_monitor_base.output_helpers import normal_print, yellow_print
from idf_monitor_base.serial_handler import SerialHandler, run_make
from idf_monitor_base.serial_reader import SerialReader
from idf_monitor_base.serial_reader import LinuxReader, SerialReader
from idf_monitor_base.web_socket_client import WebSocketClient
from serial.tools import miniterm
key_description = miniterm.key_description
class Monitor(object):
class Monitor:
"""
Monitor application main class.
Monitor application base class.
This was originally derived from miniterm.Miniterm, but it turned out to be easier to write from scratch for this
purpose.
@ -96,12 +79,11 @@ class Monitor(object):
decode_coredumps=COREDUMP_DECODE_INFO, # type: str
decode_panic=PANIC_DECODE_DISABLE, # type: str
target='esp32', # type: str
websocket_client=None, # type: WebSocketClient
websocket_client=None, # type: Optional[WebSocketClient]
enable_address_decoding=True, # type: bool
timestamps=False, # type: bool
timestamp_format='' # type: str
):
super(Monitor, self).__init__()
self.event_queue = queue.Queue() # type: queue.Queue
self.cmd_queue = queue.Queue() # type: queue.Queue
self.console = miniterm.Console()
@ -110,76 +92,110 @@ class Monitor(object):
self.console.output = get_converter(self.console.output)
self.console.byte_output = get_converter(self.console.byte_output)
# testing hook - data from serial can make exit the monitor
socket_mode = serial_instance.port.startswith('socket://')
self.serial = serial_instance
self.console_parser = ConsoleParser(eol)
self.console_reader = ConsoleReader(self.console, self.event_queue, self.cmd_queue, self.console_parser,
socket_mode)
self.serial_reader = SerialReader(self.serial, self.event_queue)
self.elf_file = elf_file
self.logger = Logger(self.elf_file, self.console, timestamps, timestamp_format, b'', enable_address_decoding,
toolchain_prefix)
self.coredump = CoreDump(decode_coredumps, self.event_queue, self.logger, websocket_client, self.elf_file)
# allow for possibility the "make" arg is a list of arguments (for idf.py)
self.make = make if os.path.exists(make) else shlex.split(make) # type: Any[Union[str, List[str]], str]
self.target = target
self._line_matcher = LineMatcher(print_filter)
# testing hook - data from serial can make exit the monitor
if isinstance(self, SerialMonitor):
socket_mode = serial_instance.port.startswith('socket://')
self.serial = serial_instance
self.serial_reader = SerialReader(self.serial, self.event_queue)
self.gdb_helper = GDBHelper(toolchain_prefix, websocket_client, self.elf_file, self.serial.port,
self.serial.baudrate)
self.logger = Logger(self.elf_file, self.console, timestamps, timestamp_format, b'', enable_address_decoding,
toolchain_prefix)
self.coredump = CoreDump(decode_coredumps, self.event_queue, self.logger, websocket_client, self.elf_file)
else:
socket_mode = False
self.serial = subprocess.Popen([elf_file], stdin=subprocess.PIPE, stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
self.serial_reader = LinuxReader(self.serial, self.event_queue)
self.gdb_helper = None
self.serial_handler = SerialHandler(b'', socket_mode, self.logger, decode_panic, PANIC_IDLE, b'', target,
False, False, self.serial, encrypted)
self.console_parser = ConsoleParser(eol)
self.console_reader = ConsoleReader(self.console, self.event_queue, self.cmd_queue, self.console_parser,
socket_mode)
self._line_matcher = LineMatcher(print_filter)
# internal state
self._invoke_processing_last_line_timer = None # type: Optional[threading.Timer]
def invoke_processing_last_line(self):
# type: () -> None
self.event_queue.put((TAG_SERIAL_FLUSH, b''), False)
def __enter__(self) -> None:
""" Use 'with self' to temporarily disable monitoring behaviour """
self.serial_reader.stop()
self.console_reader.stop()
def main_loop(self):
# type: () -> None
def __exit__(self, exc_type, exc_val, exc_tb) -> None: # type: ignore
raise NotImplementedError
def run_make(self, target: str) -> None:
with self:
run_make(target, self.make, self.console, self.console_parser, self.event_queue, self.cmd_queue,
self.logger)
def _pre_start(self) -> None:
self.console_reader.start()
self.serial_reader.start()
self.gdb_helper.gdb_exit = False
self.serial_handler.start_cmd_sent = False
def main_loop(self) -> None:
self._pre_start()
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)
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:
# 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
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')
def serial_write(self, *args, **kwargs): # type: ignore
raise NotImplementedError
def check_gdb_stub_and_run(self, line: bytes) -> None:
raise NotImplementedError
def invoke_processing_last_line(self) -> None:
self.event_queue.put((TAG_SERIAL_FLUSH, b''), False)
def _main_loop(self) -> None:
try:
item = self.cmd_queue.get_nowait()
except queue.Empty:
try:
item = self.event_queue.get(timeout=EVENT_QUEUE_TIMEOUT)
except queue.Empty:
continue
return
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
self.serial_write(codecs.encode(data))
elif event_tag == TAG_SERIAL:
self.serial_handler.handle_serial_input(data, self.console_parser, self.coredump,
self.gdb_helper, self._line_matcher,
@ -200,55 +216,59 @@ class Monitor(object):
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')
def __enter__(self):
# type: () -> None
""" Use 'with self' to temporarily disable monitoring behaviour """
self.serial_reader.stop()
self.console_reader.stop()
def __exit__(self, *args, **kwargs): # type: ignore
class SerialMonitor(Monitor):
def __exit__(self, exc_type, exc_val, exc_tb) -> None: # type: ignore
""" Use 'with self' to temporarily disable monitoring behaviour """
self.console_reader.start()
self.serial_reader.gdb_exit = self.gdb_helper.gdb_exit # write gdb_exit flag
self.serial_reader.start()
def check_gdb_stub_and_run(self, line): # type: (bytes) -> None
def _pre_start(self) -> None:
super()._pre_start()
self.gdb_helper.gdb_exit = False
self.serial_handler.start_cmd_sent = False
def serial_write(self, *args, **kwargs): # type: ignore
self.serial: serial.Serial
try:
self.serial.write(*args, **kwargs)
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
def check_gdb_stub_and_run(self, line: bytes) -> None: # type: ignore # The base class one is a None value
if self.gdb_helper.check_gdb_stub_trigger(line):
with self: # disable console control
self.gdb_helper.run_gdb()
def run_make(self, target): # type: (str) -> None
with self:
run_make(target, self.make, self.console, self.console_parser, self.event_queue, self.cmd_queue,
self.logger)
def _main_loop(self) -> None:
if self.gdb_helper.gdb_exit:
self.gdb_helper.gdb_exit = False
time.sleep(GDB_EXIT_TIMEOUT)
# Continue the program after exit from the GDB
self.serial_write(codecs.encode(GDB_UART_CONTINUE_COMMAND))
self.serial_handler.start_cmd_sent = True
super()._main_loop()
def main(): # type: () -> None
class LinuxMonitor(Monitor):
def __exit__(self, exc_type, exc_val, exc_tb) -> None: # type: ignore
""" Use 'with self' to temporarily disable monitoring behaviour """
self.console_reader.start()
self.serial_reader.start()
def serial_write(self, *args, **kwargs): # type: ignore
self.serial.stdin.write(*args, **kwargs)
def check_gdb_stub_and_run(self, line: bytes) -> None:
return # fake function for linux target
def main() -> None:
parser = get_parser()
args = parser.parse_args()
@ -263,9 +283,6 @@ def main(): # type: () -> None
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
@ -279,21 +296,42 @@ def main(): # type: () -> None
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(args.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. 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)
cls = SerialMonitor
yellow_print('--- idf_monitor on {p.name} {p.baudrate} ---'.format(p=serial_instance))
monitor = cls(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,
not args.disable_address_decoding,
args.timestamps,
args.timestamp_format)
yellow_print('--- Quit: {} | Menu: {} | Help: {} followed by {} ---'.format(
key_description(monitor.console_parser.exit_key),
key_description(monitor.console_parser.menu_key),

View File

@ -1,16 +1,5 @@
# Copyright 2015-2021 Espressif Systems (Shanghai) CO LTD
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Apache-2.0
import queue
import textwrap
@ -21,7 +10,7 @@ from serial.tools import miniterm
from .constants import (CMD_APP_FLASH, CMD_ENTER_BOOT, CMD_MAKE, CMD_OUTPUT_TOGGLE, CMD_RESET, CMD_STOP,
CMD_TOGGLE_LOGGING, CMD_TOGGLE_TIMESTAMPS, CTRL_A, CTRL_F, CTRL_H, CTRL_I, CTRL_L, CTRL_P,
CTRL_R, CTRL_RBRACKET, CTRL_T, CTRL_X, CTRL_Y, TAG_CMD, TAG_KEY, __version__)
from .output_helpers import red_print, yellow_print
from .output_helpers import red_print
key_description = miniterm.key_description
@ -94,7 +83,6 @@ class ConsoleParser(object):
elif c in [CTRL_I, 'i', 'I']: # Toggle printing timestamps
ret = (TAG_CMD, CMD_TOGGLE_TIMESTAMPS)
elif c == CTRL_P:
yellow_print('Pause app (enter bootloader mode), press Ctrl-T Ctrl-R to restart')
# to fast trigger pause without press menu key
ret = (TAG_CMD, CMD_ENTER_BOOT)
elif c in [CTRL_X, 'x', 'X']: # Exiting from within the menu

View File

@ -1,23 +1,12 @@
# Copyright 2015-2021 Espressif Systems (Shanghai) CO LTD
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Apache-2.0
import os
import queue # noqa: F401
import re
import subprocess
import time
from typing import Callable
from typing import Callable, Optional
import serial # noqa: F401
from serial.tools import miniterm # noqa: F401
@ -28,13 +17,13 @@ from .console_reader import ConsoleReader # noqa: F401
from .constants import (CMD_APP_FLASH, CMD_ENTER_BOOT, CMD_MAKE, CMD_OUTPUT_TOGGLE, CMD_RESET, CMD_STOP,
CMD_TOGGLE_LOGGING, CMD_TOGGLE_TIMESTAMPS, PANIC_DECODE_DISABLE, PANIC_END, PANIC_IDLE,
PANIC_READING, PANIC_STACK_DUMP, PANIC_START)
from .coredump import CoreDump # noqa: F401
from .exceptions import SerialStopException # noqa: F401
from .gdbhelper import GDBHelper # noqa: F401
from .line_matcher import LineMatcher # noqa: F401
from .logger import Logger # noqa: F401
from .coredump import CoreDump
from .exceptions import SerialStopException
from .gdbhelper import GDBHelper
from .line_matcher import LineMatcher
from .logger import Logger
from .output_helpers import yellow_print
from .serial_reader import SerialReader # noqa: F401
from .serial_reader import Reader
def run_make(target, make, console, console_parser, event_queue, cmd_queue, logger):
@ -60,7 +49,7 @@ class SerialHandler:
The class is responsible for buffering serial input and performing corresponding commands.
"""
def __init__(self, last_line_part, serial_check_exit, logger, decode_panic, reading_panic, panic_buffer, target,
force_line_print, start_cmd_sent, serial_instance, encrypted, ):
force_line_print, start_cmd_sent, serial_instance, encrypted):
# type: (bytes, bool, Logger, str, int, bytes,str, bool, bool, serial.Serial, bool) -> None
self._last_line_part = last_line_part
self._serial_check_exit = serial_check_exit
@ -76,7 +65,7 @@ class SerialHandler:
def handle_serial_input(self, data, console_parser, coredump, gdb_helper, line_matcher,
check_gdb_stub_and_run, finalize_line=False):
# type: (bytes, ConsoleParser, CoreDump, GDBHelper, LineMatcher, Callable, bool) -> None
# type: (bytes, ConsoleParser, CoreDump, Optional[GDBHelper], LineMatcher, Callable, bool) -> None
# Remove "+" after Continue command
if self.start_cmd_sent:
self.start_cmd_sent = False
@ -97,6 +86,7 @@ class SerialHandler:
continue
if self._serial_check_exit and line == console_parser.exit_key.encode('latin-1'):
raise SerialStopException()
if gdb_helper:
self.check_panic_decode_trigger(line, gdb_helper)
with coredump.check(line):
if self._force_line_print or line_matcher.match(line.decode(errors='ignore')):
@ -125,6 +115,7 @@ class SerialHandler:
self.logger.pc_address_buffer = self._last_line_part[-9:]
# GDB sequence can be cut in half also. GDB sequence is 7
# characters long, therefore, we save the last 6 characters.
if gdb_helper:
gdb_helper.gdb_buffer = self._last_line_part[-6:]
self._last_line_part = b''
# else: keeping _last_line_part and it will be processed the next time
@ -151,7 +142,7 @@ class SerialHandler:
self._panic_buffer = b''
def handle_commands(self, cmd, chip, run_make_func, console_reader, serial_reader):
# type: (int, str, Callable, ConsoleReader, SerialReader) -> None
# type: (int, str, Callable, ConsoleReader, Reader) -> None
config = get_chip_config(chip)
reset_delay = config['reset']
enter_boot_set = config['enter_boot_set']
@ -160,6 +151,14 @@ class SerialHandler:
high = False
low = True
if chip == 'linux':
if cmd in [CMD_RESET,
CMD_MAKE,
CMD_APP_FLASH,
CMD_ENTER_BOOT]:
yellow_print('linux target does not support this command')
return
if cmd == CMD_STOP:
console_reader.stop()
serial_reader.stop()
@ -181,6 +180,7 @@ class SerialHandler:
elif cmd == CMD_TOGGLE_TIMESTAMPS:
self.logger.toggle_timestamps()
elif cmd == CMD_ENTER_BOOT:
yellow_print('Pause app (enter bootloader mode), press Ctrl-T Ctrl-R to restart')
self.serial_instance.setDTR(high) # IO0=HIGH
self.serial_instance.setRTS(low) # EN=LOW, chip in reset
self.serial_instance.setDTR(self.serial_instance.dtr) # usbser.sys workaround

View File

@ -1,18 +1,8 @@
# Copyright 2015-2021 Espressif Systems (Shanghai) CO LTD
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Apache-2.0
import queue
import subprocess
import sys
import time
@ -23,10 +13,15 @@ from .output_helpers import red_print, yellow_print
from .stoppable_thread import StoppableThread
class SerialReader(StoppableThread):
class Reader(StoppableThread):
""" Output Reader base class """
class SerialReader(Reader):
""" Read serial data from the serial port and push to the
event queue, until stopped.
"""
def __init__(self, serial_instance, event_queue):
# type: (serial.Serial, queue.Queue) -> None
super(SerialReader, self).__init__()
@ -96,3 +91,29 @@ class SerialReader(StoppableThread):
self.serial.cancel_read()
except Exception: # noqa
pass
class LinuxReader(Reader):
""" Read data from the subprocess that runs runnable and push to the
event queue, until stopped.
"""
def __init__(self, process, event_queue):
# type: (subprocess.Popen, queue.Queue) -> None
super().__init__()
self.proc = process
self.event_queue = event_queue
self._stdout = iter(self.proc.stdout.readline, b'') # type: ignore
def run(self): # type: () -> None
try:
while self.alive:
for line in self._stdout:
if line:
self.event_queue.put((TAG_SERIAL, line), False)
finally:
self.proc.terminate()
def _cancel(self): # type: () -> None
self.proc.terminate()

View File

@ -1,8 +1,12 @@
# SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Apache-2.0
import json
import os
import sys
import click
from idf_monitor_base.output_helpers import yellow_print
from idf_py_actions.errors import FatalError, NoSerialPortFoundError
from idf_py_actions.global_options import global_options
from idf_py_actions.tools import ensure_build_directory, get_sdkconfig_value, run_target, run_tool
@ -11,6 +15,14 @@ PYTHON = sys.executable
def action_extensions(base_actions, project_path):
def _get_project_desc(ctx, args):
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)
return project_desc
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:
@ -75,20 +87,17 @@ def action_extensions(base_actions, project_path):
"""
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)
project_desc = _get_project_desc(ctx, args)
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 project_desc['target'] != 'linux':
esp_port = args.port or _get_default_serial_port(args)
monitor_args += ['-p', esp_port]
@ -96,6 +105,7 @@ def action_extensions(base_actions, project_path):
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')
@ -137,8 +147,13 @@ def action_extensions(base_actions, project_path):
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})
run_target(action, args, {'ESPBAUD': str(args.baud), 'ESPPORT': esp_port})
def erase_flash(action, ctx, args):
ensure_build_directory(args, ctx.info_name)

View File

@ -1,16 +1,5 @@
# Copyright 2019 Espressif Systems (Shanghai) PTE LTD
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# SPDX-FileCopyrightText: 2019-2021 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Apache-2.0
from __future__ import unicode_literals
@ -53,7 +42,7 @@ def main():
args = parser.parse_args()
serial_instance = serial.serial_for_url(args.port, 115200, do_not_open=True)
monitor = idf_monitor.Monitor(serial_instance, args.elf_file, args.print_filter, 'make',
monitor = idf_monitor.SerialMonitor(serial_instance, args.elf_file, args.print_filter, 'make',
toolchain_prefix=args.toolchain_prefix, eol='CR',
decode_panic=args.decode_panic, target=args.target)
sys.stderr.write('Monitor instance has been created.\n')