From 1b157384bc9a60c1cabbfc5489215d732fc022f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Radim=20Karni=C5=A1?= Date: Tue, 17 Sep 2024 15:08:24 +0200 Subject: [PATCH] feat(hard_reset): Support custom hard reset sequence configuration Closes https://github.com/espressif/esptool/issues/1004 --- docs/en/esptool/configuration-file.rst | 19 ++++++++++++++++--- esp_rfc2217_server/esp_port_manager.py | 6 +++++- esptool/config.py | 1 + esptool/loader.py | 8 ++++++-- esptool/reset.py | 2 +- esptool/targets/esp32c5.py | 4 +--- esptool/targets/esp32s2.py | 4 +--- esptool/targets/esp32s3.py | 4 +--- test/test_esptool.py | 2 +- 9 files changed, 33 insertions(+), 17 deletions(-) diff --git a/docs/en/esptool/configuration-file.rst b/docs/en/esptool/configuration-file.rst index 1583f86d17..6cc63880cc 100644 --- a/docs/en/esptool/configuration-file.rst +++ b/docs/en/esptool/configuration-file.rst @@ -111,14 +111,19 @@ Complete list of configurable options: +------------------------------+-----------------------------------------------------------+----------+ | custom_reset_sequence | Custom reset sequence for resetting into the bootloader | | +------------------------------+-----------------------------------------------------------+----------+ +| custom_hard_reset_sequence | Custom reset sequence for hard resetting the chip | | ++------------------------------+-----------------------------------------------------------+----------+ -Custom Reset Sequence ---------------------- +Custom Reset Sequences +---------------------- The ``custom_reset_sequence`` configuration option allows you to define a reset sequence which will get used when an :ref:`automatic reset into the serial bootloader ` is performed. -The sequence is defined with a string in the following format: +The ``custom_hard_reset_sequence`` option allows you to define a reset sequence which will get +used when a hard reset (a reset out of the bootloader) is performed. + +A sequence is defined with a string in the following format: - Consists of individual commands divided by ``|`` (e.g. ``R0|D1|W0.5``). - Commands (e.g. ``R0``) are defined by a code (``R``) and an argument (``0``). @@ -148,3 +153,11 @@ For example: ``D0|R1|W0.1|D1|R0|W0.5|D0`` represents the following classic reset _setRTS(False) # EN=HIGH, chip out of reset time.sleep(0.05) _setDTR(False) # IO0=HIGH, done + +Similarly, ``R1|W0.1|R0`` represents the classic hard reset sequence: + +.. code-block:: python + + _setRTS(True) # EN=LOW, chip in reset + time.sleep(0.1) + _setRTS(False) # EN=HIGH, chip out of reset diff --git a/esp_rfc2217_server/esp_port_manager.py b/esp_rfc2217_server/esp_port_manager.py index 29f1046384..039441e0ea 100644 --- a/esp_rfc2217_server/esp_port_manager.py +++ b/esp_rfc2217_server/esp_port_manager.py @@ -74,7 +74,11 @@ def _hard_reset_thread(self): """ if self.logger: self.logger.info("Activating hard reset in thread") - HardReset(self.serial)() + cfg_custom_hard_reset_sequence = cfg.get("custom_hard_reset_sequence") + if cfg_custom_hard_reset_sequence is not None: + CustomReset(self.serial, cfg_custom_hard_reset_sequence)() + else: + HardReset(self.serial)() def _reset_thread(self): """ diff --git a/esptool/config.py b/esptool/config.py index ebbe3b8eed..a59e4b7ee2 100644 --- a/esptool/config.py +++ b/esptool/config.py @@ -21,6 +21,7 @@ "reset_delay", "open_port_attempts", "custom_reset_sequence", + "custom_hard_reset_sequence", ] diff --git a/esptool/loader.py b/esptool/loader.py index ca3ab9329d..1e7c71b41e 100644 --- a/esptool/loader.py +++ b/esptool/loader.py @@ -1525,9 +1525,13 @@ def get_crystal_freq(self): ) return norm_xtal - def hard_reset(self): + def hard_reset(self, uses_usb=False): print("Hard resetting via RTS pin...") - HardReset(self._port)() + cfg_custom_hard_reset_sequence = cfg.get("custom_hard_reset_sequence") + if cfg_custom_hard_reset_sequence is not None: + CustomReset(self._port, cfg_custom_hard_reset_sequence)() + else: + HardReset(self._port, uses_usb)() def soft_reset(self, stay_in_bootloader): if not self.IS_STUB: diff --git a/esptool/reset.py b/esptool/reset.py index ef91e4bdc1..dc4141d459 100644 --- a/esptool/reset.py +++ b/esptool/reset.py @@ -205,5 +205,5 @@ def _parse_string_to_seq(self, seq_str): cmds = seq_str.split("|") fn_calls_list = [self.format_dict[cmd[0]].format(cmd[1:]) for cmd in cmds] except Exception as e: - raise FatalError(f'Invalid "custom_reset_sequence" option format: {e}') + raise FatalError(f"Invalid custom reset sequence option format: {e}") return "\n".join(fn_calls_list) diff --git a/esptool/targets/esp32c5.py b/esptool/targets/esp32c5.py index 99c9b99db7..e18e14edf3 100644 --- a/esptool/targets/esp32c5.py +++ b/esptool/targets/esp32c5.py @@ -8,7 +8,6 @@ from .esp32c6 import ESP32C6ROM from ..loader import ESPLoader -from ..reset import HardReset from ..util import FatalError @@ -128,8 +127,7 @@ def get_crystal_freq_rom_expect(self): ) >> self.PCR_SYSCLK_XTAL_FREQ_S def hard_reset(self): - print("Hard resetting via RTS pin...") - HardReset(self._port, self.uses_usb_jtag_serial())() + ESPLoader.hard_reset(self, self.uses_usb_jtag_serial()) def change_baud(self, baud): if not self.IS_STUB: diff --git a/esptool/targets/esp32s2.py b/esptool/targets/esp32s2.py index e16f532f09..a4509b52f4 100644 --- a/esptool/targets/esp32s2.py +++ b/esptool/targets/esp32s2.py @@ -9,7 +9,6 @@ from .esp32 import ESP32ROM from ..loader import ESPLoader -from ..reset import HardReset from ..util import FatalError, NotImplementedInROMError @@ -310,8 +309,7 @@ def hard_reset(self): if uses_usb_otg: self._check_if_can_reset() - print("Hard resetting via RTS pin...") - HardReset(self._port, uses_usb_otg)() + ESPLoader.hard_reset(self, uses_usb_otg) def change_baud(self, baud): ESPLoader.change_baud(self, baud) diff --git a/esptool/targets/esp32s3.py b/esptool/targets/esp32s3.py index fb0f23a2f3..581128df7c 100644 --- a/esptool/targets/esp32s3.py +++ b/esptool/targets/esp32s3.py @@ -9,7 +9,6 @@ from .esp32 import ESP32ROM from ..loader import ESPLoader -from ..reset import HardReset from ..util import FatalError, NotImplementedInROMError @@ -382,8 +381,7 @@ def hard_reset(self): # Skip if response was not valid and proceed to reset; e.g. when monitoring while resetting pass - print("Hard resetting via RTS pin...") - HardReset(self._port, uses_usb_otg)() + ESPLoader.hard_reset(self, uses_usb_otg) def change_baud(self, baud): ESPLoader.change_baud(self, baud) diff --git a/test/test_esptool.py b/test/test_esptool.py index 9928b6f813..5fc1fb58b9 100755 --- a/test/test_esptool.py +++ b/test/test_esptool.py @@ -1604,7 +1604,7 @@ def test_custom_reset_sequence(self): with self.ConfigFile(config_file_path, invalid_reset_seq_config): output = self.run_esptool_error("flash_id") assert f"Loaded custom configuration from {config_file_path}" in output - assert 'Invalid "custom_reset_sequence" option format:' in output + assert "Invalid custom reset sequence option format:" in output def test_open_port_attempts(self): # Test that the open_port_attempts option is loaded correctly