esp-test-utils 0.2.0__tar.gz → 0.2.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/.gitignore +3 -0
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/.pre-commit-config.yaml +7 -0
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/CHANGELOG.md +15 -0
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/PKG-INFO +3 -1
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/esp_test_utils.egg-info/PKG-INFO +3 -1
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/esp_test_utils.egg-info/SOURCES.txt +9 -0
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/esp_test_utils.egg-info/requires.txt +2 -0
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/esptest/adapter/dut/dut_base.py +18 -7
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/esptest/adapter/dut/esp_mixin.py +6 -1
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/esptest/config/env_config.py +37 -7
- esp_test_utils-0.2.2/esptest/db/runners.py +199 -0
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/esptest/devices/esp_serial.py +11 -0
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/esptest/scripts/downbin.py +20 -8
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/esptest/tools/download_bin.py +54 -5
- esp_test_utils-0.2.2/esptest/tools/http_download.py +61 -0
- esp_test_utils-0.2.2/esptest/utility/gen_esp32part.py +808 -0
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/esptest/utility/parse_bin_path.py +132 -43
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/pyproject.toml +7 -0
- esp_test_utils-0.2.2/tests/conftest.py +0 -0
- esp_test_utils-0.2.2/tests/db/test_db_runners.py +66 -0
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/tests/test_Dut.py +1 -1
- esp_test_utils-0.2.2/tests/tools/test_download_file.py +44 -0
- esp_test_utils-0.2.2/tests/utility/_files/test-bin.zip +0 -0
- esp_test_utils-0.2.2/tests/utility/_files/test-get-baud/ESP32AT-V4.1.1.0/sdkconfig +80 -0
- esp_test_utils-0.2.2/tests/utility/test_parse_bin_path.py +149 -0
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/.github/.gitkeep +0 -0
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/.github/workflows/pypi-publish.yml +0 -0
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/.gitlab-ci.yml +0 -0
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/CONTRIBUTING.md +0 -0
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/LICENSE +0 -0
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/README.md +0 -0
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/docs/Makefile +0 -0
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/docs/conf.py +0 -0
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/docs/index.rst +0 -0
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/docs/make.bat +0 -0
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/esp_test_utils.egg-info/dependency_links.txt +0 -0
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/esp_test_utils.egg-info/entry_points.txt +0 -0
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/esp_test_utils.egg-info/top_level.txt +0 -0
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/esptest/__init__.py +0 -0
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/esptest/__main__.py +0 -0
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/esptest/adapter/__init__.py +0 -0
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/esptest/adapter/dut/__init__.py +0 -0
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/esptest/adapter/dut/create_dut.py +0 -0
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/esptest/adapter/dut/esp_dut.py +0 -0
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/esptest/adapter/dut/esp_port.py +0 -0
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/esptest/adapter/dut/mac_mixin.py +0 -0
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/esptest/adapter/dut/wrapper.py +0 -0
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/esptest/adapter/port/__init__.py +0 -0
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/esptest/adapter/port/base_port.py +0 -0
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/esptest/adapter/port/serial_port.py +0 -0
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/esptest/all.py +0 -0
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/esptest/common/__init__.py +0 -0
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/esptest/common/compat_typing.py +0 -0
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/esptest/common/data_monitor.py +0 -0
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/esptest/common/decorators.py +0 -0
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/esptest/common/encoding.py +0 -0
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/esptest/common/generator.py +0 -0
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/esptest/common/shell.py +0 -0
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/esptest/common/timestamp.py +0 -0
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/esptest/config/__init__.py +0 -0
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/esptest/config/default_config.py +0 -0
- {esp_test_utils-0.2.0/esptest/devices → esp_test_utils-0.2.2/esptest/db}/__init__.py +0 -0
- {esp_test_utils-0.2.0/esptest/env → esp_test_utils-0.2.2/esptest/devices}/__init__.py +0 -0
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/esptest/devices/attenuator.py +0 -0
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/esptest/devices/serial_dut.py +0 -0
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/esptest/devices/serial_tools.py +0 -0
- {esp_test_utils-0.2.0/esptest/interface → esp_test_utils-0.2.2/esptest/env}/__init__.py +0 -0
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/esptest/env/base_env.py +0 -0
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/esptest/env/wifi_env.py +0 -0
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/esptest/esp_console/__init__.py +0 -0
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/esptest/esp_console/wifi_cmd.py +0 -0
- {esp_test_utils-0.2.0/esptest/network → esp_test_utils-0.2.2/esptest/interface}/__init__.py +0 -0
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/esptest/interface/dut.py +0 -0
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/esptest/interface/port.py +0 -0
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/esptest/iperf_utility/__init__.py +0 -0
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/esptest/iperf_utility/iperf_results.py +0 -0
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/esptest/iperf_utility/iperf_test.py +0 -0
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/esptest/iperf_utility/iperf_test.test.py +0 -0
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/esptest/iperf_utility/line_chart.py +0 -0
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/esptest/logger/__init__.py +0 -0
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/esptest/logger/logger.py +0 -0
- {esp_test_utils-0.2.0/tests → esp_test_utils-0.2.2/esptest/network}/__init__.py +0 -0
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/esptest/network/mac.py +0 -0
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/esptest/network/netif.py +0 -0
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/esptest/network/nic.py +0 -0
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/esptest/scripts/list_ports.py +0 -0
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/esptest/scripts/monitor.py +0 -0
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/esptest/scripts/set_att.py +0 -0
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/esptest/tools/copy_bin.py +0 -0
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/esptest/tools/pip_check.py +0 -0
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/example/jap_test.py +0 -0
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/example/restart_test.py +0 -0
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/setup.cfg +0 -0
- /esp_test_utils-0.2.0/tests/conftest.py → /esp_test_utils-0.2.2/tests/__init__.py +0 -0
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/tests/basic/test_decorators.py +0 -0
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/tests/basic/test_network.py +0 -0
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/tests/esp_console/_files/wifi_cmd_connected_1.log +0 -0
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/tests/esp_console/_files/wifi_cmd_connected_2.log +0 -0
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/tests/esp_console/conftest.py +0 -0
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/tests/esp_console/test_WifiCmd.py +0 -0
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/tests/iperf_utility/_files/dut_iperf_rx1.log +0 -0
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/tests/iperf_utility/_files/dut_iperf_rx2.log +0 -0
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/tests/iperf_utility/_files/pc_iperf_rx.log +0 -0
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/tests/iperf_utility/_files/pc_iperf_rx2.log +0 -0
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/tests/iperf_utility/test_chart.py +0 -0
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/tests/iperf_utility/test_iperf_results.py +0 -0
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/tests/iperf_utility/test_iperf_util.py +0 -0
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/tests/test_EnvConfig.py +0 -0
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/tests/test_common.py +0 -0
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/tests/test_import.py +0 -0
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/tests/tools/test_pip_check.py +0 -0
- {esp_test_utils-0.2.0 → esp_test_utils-0.2.2}/tools/ci/check_dev_version.py +0 -0
|
@@ -35,6 +35,7 @@ repos:
|
|
|
35
35
|
- 'types-psutil'
|
|
36
36
|
- 'types-PyYAML'
|
|
37
37
|
- 'typing_extensions'
|
|
38
|
+
- 'sqlalchemy'
|
|
38
39
|
|
|
39
40
|
- repo: https://github.com/espressif/conventional-precommit-linter
|
|
40
41
|
rev: v1.10.0
|
|
@@ -48,3 +49,9 @@ repos:
|
|
|
48
49
|
- id: codespell
|
|
49
50
|
args: ["--write-changes"]
|
|
50
51
|
additional_dependencies: [tomli]
|
|
52
|
+
|
|
53
|
+
exclude: |
|
|
54
|
+
(
|
|
55
|
+
^docs/.*
|
|
56
|
+
| gen_esp32part\.py$
|
|
57
|
+
)
|
|
@@ -1,3 +1,18 @@
|
|
|
1
|
+
## v0.2.2 (2025-10-29)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
- feat: get test variables from shell env
|
|
5
|
+
- fix: flash esp32 option no-stub
|
|
6
|
+
|
|
7
|
+
## v0.2.1 (2025-09-24)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
- feat(utility): support to flash bin to encrypted device
|
|
11
|
+
- feat: add runners database
|
|
12
|
+
- feat: add default gen part tool
|
|
13
|
+
- feat(utility): support to check flash enc from bin path
|
|
14
|
+
- fix: get baud from bin path sdkconfig file
|
|
15
|
+
|
|
1
16
|
## v0.2.0 (2025-07-16)
|
|
2
17
|
|
|
3
18
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: esp-test-utils
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.2
|
|
4
4
|
Summary: ESP Test Utils
|
|
5
5
|
Author-email: Chen Yudong <chenyudong@espressif.com>
|
|
6
6
|
License: Apache License
|
|
@@ -228,7 +228,9 @@ Requires-Dist: pyserial
|
|
|
228
228
|
Requires-Dist: PyYAML
|
|
229
229
|
Requires-Dist: pexpect
|
|
230
230
|
Requires-Dist: pyusb
|
|
231
|
+
Requires-Dist: esptool
|
|
231
232
|
Requires-Dist: packaging
|
|
233
|
+
Requires-Dist: sqlalchemy
|
|
232
234
|
Requires-Dist: typing_extensions; python_version < "3.11"
|
|
233
235
|
Provides-Extra: idfci
|
|
234
236
|
Requires-Dist: pyecharts; extra == "idfci"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: esp-test-utils
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.2
|
|
4
4
|
Summary: ESP Test Utils
|
|
5
5
|
Author-email: Chen Yudong <chenyudong@espressif.com>
|
|
6
6
|
License: Apache License
|
|
@@ -228,7 +228,9 @@ Requires-Dist: pyserial
|
|
|
228
228
|
Requires-Dist: PyYAML
|
|
229
229
|
Requires-Dist: pexpect
|
|
230
230
|
Requires-Dist: pyusb
|
|
231
|
+
Requires-Dist: esptool
|
|
231
232
|
Requires-Dist: packaging
|
|
233
|
+
Requires-Dist: sqlalchemy
|
|
232
234
|
Requires-Dist: typing_extensions; python_version < "3.11"
|
|
233
235
|
Provides-Extra: idfci
|
|
234
236
|
Requires-Dist: pyecharts; extra == "idfci"
|
|
@@ -44,6 +44,8 @@ esptest/common/timestamp.py
|
|
|
44
44
|
esptest/config/__init__.py
|
|
45
45
|
esptest/config/default_config.py
|
|
46
46
|
esptest/config/env_config.py
|
|
47
|
+
esptest/db/__init__.py
|
|
48
|
+
esptest/db/runners.py
|
|
47
49
|
esptest/devices/__init__.py
|
|
48
50
|
esptest/devices/attenuator.py
|
|
49
51
|
esptest/devices/esp_serial.py
|
|
@@ -74,7 +76,9 @@ esptest/scripts/monitor.py
|
|
|
74
76
|
esptest/scripts/set_att.py
|
|
75
77
|
esptest/tools/copy_bin.py
|
|
76
78
|
esptest/tools/download_bin.py
|
|
79
|
+
esptest/tools/http_download.py
|
|
77
80
|
esptest/tools/pip_check.py
|
|
81
|
+
esptest/utility/gen_esp32part.py
|
|
78
82
|
esptest/utility/parse_bin_path.py
|
|
79
83
|
example/jap_test.py
|
|
80
84
|
example/restart_test.py
|
|
@@ -86,6 +90,7 @@ tests/test_common.py
|
|
|
86
90
|
tests/test_import.py
|
|
87
91
|
tests/basic/test_decorators.py
|
|
88
92
|
tests/basic/test_network.py
|
|
93
|
+
tests/db/test_db_runners.py
|
|
89
94
|
tests/esp_console/conftest.py
|
|
90
95
|
tests/esp_console/test_WifiCmd.py
|
|
91
96
|
tests/esp_console/_files/wifi_cmd_connected_1.log
|
|
@@ -97,5 +102,9 @@ tests/iperf_utility/_files/dut_iperf_rx1.log
|
|
|
97
102
|
tests/iperf_utility/_files/dut_iperf_rx2.log
|
|
98
103
|
tests/iperf_utility/_files/pc_iperf_rx.log
|
|
99
104
|
tests/iperf_utility/_files/pc_iperf_rx2.log
|
|
105
|
+
tests/tools/test_download_file.py
|
|
100
106
|
tests/tools/test_pip_check.py
|
|
107
|
+
tests/utility/test_parse_bin_path.py
|
|
108
|
+
tests/utility/_files/test-bin.zip
|
|
109
|
+
tests/utility/_files/test-get-baud/ESP32AT-V4.1.1.0/sdkconfig
|
|
101
110
|
tools/ci/check_dev_version.py
|
|
@@ -11,7 +11,7 @@ from esptool.loader import ESPLoader
|
|
|
11
11
|
|
|
12
12
|
import esptest.common.compat_typing as t
|
|
13
13
|
|
|
14
|
-
from ...common.timestamp import
|
|
14
|
+
from ...common.timestamp import timestamp_slug
|
|
15
15
|
from ...interface.dut import DutInterface
|
|
16
16
|
from ...interface.port import PortInterface
|
|
17
17
|
from ...logger import get_logger
|
|
@@ -27,7 +27,8 @@ DEFAULT_SERIAL_CONFIGS = {'timeout': 0.005}
|
|
|
27
27
|
class DutConfig:
|
|
28
28
|
name: str = '' # default = dut name / port name
|
|
29
29
|
device: str = '' # log serial device, eg: '/dev/ttyUSB0', 'COM3', etc.
|
|
30
|
-
baudrate: int = 0 # 0: get from bin path or 115200
|
|
30
|
+
baudrate: int = 0 # console baudrate, 0: get from bin path or 115200
|
|
31
|
+
baudrate_from_bin_path: bool = True # always get baudrate from bin path if bin_path is set
|
|
31
32
|
serial_configs: t.Optional[t.Dict[str, t.Any]] = None # serial configs, eg: {'bytesize': 8, 'timeout': 0.1}
|
|
32
33
|
# capabilities
|
|
33
34
|
support_esptool: bool = False # esp port or serial port
|
|
@@ -61,7 +62,7 @@ class DutConfig:
|
|
|
61
62
|
self._auto_gen_name()
|
|
62
63
|
if not self.log_file:
|
|
63
64
|
_log_path = self.log_path or './dut_logs'
|
|
64
|
-
_file_name = f'{self.name}_{
|
|
65
|
+
_file_name = f'{self.name}_{timestamp_slug()}.log'.replace(':', '-')
|
|
65
66
|
self.log_file = str(Path(_log_path) / _file_name)
|
|
66
67
|
# serial configs
|
|
67
68
|
_serial_configs = DEFAULT_SERIAL_CONFIGS.copy()
|
|
@@ -71,10 +72,14 @@ class DutConfig:
|
|
|
71
72
|
# bin_path and get variables from bin path
|
|
72
73
|
if self.bin_path:
|
|
73
74
|
self.bin_path = Path(self.bin_path).expanduser().resolve()
|
|
74
|
-
|
|
75
|
-
self.
|
|
76
|
-
|
|
77
|
-
|
|
75
|
+
parsed_bin = ParseBinPath(self.bin_path)
|
|
76
|
+
self.esptool_stub = parsed_bin.stub
|
|
77
|
+
self.esptool_chip = parsed_bin.chip
|
|
78
|
+
if self.baudrate_from_bin_path:
|
|
79
|
+
# baudrate from bin path is much reliable than the specified one for uart0
|
|
80
|
+
self.baudrate = get_baud_from_bin_path(self.bin_path) or self.baudrate or 115200
|
|
81
|
+
if not self.baudrate:
|
|
82
|
+
self.baudrate = 115200 # set default baudrate to 115200
|
|
78
83
|
# download device
|
|
79
84
|
if not self.download_device:
|
|
80
85
|
self.download_device = self.device
|
|
@@ -224,6 +229,12 @@ class DutBase(VariablesMixin, DutInterface): # pylint: disable=too-many-public-
|
|
|
224
229
|
return self._base_port_proxy.raw_port
|
|
225
230
|
raise NotImplementedError()
|
|
226
231
|
|
|
232
|
+
@property
|
|
233
|
+
def log_file(self) -> t.Any:
|
|
234
|
+
if self._base_port_proxy:
|
|
235
|
+
return self._base_port_proxy.log_file
|
|
236
|
+
return None
|
|
237
|
+
|
|
227
238
|
@property
|
|
228
239
|
def name(self) -> t.Any:
|
|
229
240
|
return self.dut_config.name
|
|
@@ -95,7 +95,7 @@ class EspMixin(BaseProtocol):
|
|
|
95
95
|
esptool=self.dut_config.use_esptool,
|
|
96
96
|
erase_nvs=erase_nvs,
|
|
97
97
|
)
|
|
98
|
-
if not self.esp.IS_STUB:
|
|
98
|
+
if not self.esp.IS_STUB and self.esp.CHIP_NAME not in ['ESP32']:
|
|
99
99
|
# preview or dev targets
|
|
100
100
|
down_bin_tool.force_no_stub = True
|
|
101
101
|
with self.disable_redirect_thread():
|
|
@@ -105,6 +105,11 @@ class EspMixin(BaseProtocol):
|
|
|
105
105
|
def start_redirect_thread(self) -> None:
|
|
106
106
|
if self.esp:
|
|
107
107
|
self.esp._port.open() # pylint: disable=protected-access
|
|
108
|
+
if self.log_file:
|
|
109
|
+
with open(self.log_file, 'a', encoding='utf-8') as log_f:
|
|
110
|
+
log_f.write(
|
|
111
|
+
f'------------ reopen port: {self.esp._port.port} {self.esp._port.baudrate} --------------- \n' # pylint: disable=protected-access
|
|
112
|
+
)
|
|
108
113
|
super().start_redirect_thread()
|
|
109
114
|
|
|
110
115
|
def stop_redirect_thread(self) -> bool:
|
|
@@ -5,6 +5,30 @@ from typing import Any, List, Optional
|
|
|
5
5
|
|
|
6
6
|
import yaml
|
|
7
7
|
|
|
8
|
+
VAR_NAME_MAPPING = {
|
|
9
|
+
'ap_ssid': ['RUNNER_WIFI_SSID', 'RUNNER_AP_SSID'],
|
|
10
|
+
'ap_password': ['RUNNER_WIFI_PASSWORD', 'RUNNER_AP_PASSWORD'],
|
|
11
|
+
'pc_nic': ['RUNNER_PC_NIC'],
|
|
12
|
+
'dut1': ['ESPPORT1'],
|
|
13
|
+
'dut2': ['ESPPORT2'],
|
|
14
|
+
'dut3': ['ESPPORT3'],
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def get_variable_from_env(key: str) -> Any:
|
|
19
|
+
"""Get test variable from shell environment
|
|
20
|
+
|
|
21
|
+
Args:
|
|
22
|
+
key (str): which variable to get
|
|
23
|
+
"""
|
|
24
|
+
if key in VAR_NAME_MAPPING:
|
|
25
|
+
for var_name in VAR_NAME_MAPPING[key]:
|
|
26
|
+
var = os.getenv(var_name)
|
|
27
|
+
if var is not None:
|
|
28
|
+
logging.debug(f'Got env variable from shell env {var_name}: {var}')
|
|
29
|
+
return var
|
|
30
|
+
return None
|
|
31
|
+
|
|
8
32
|
|
|
9
33
|
class EnvConfig:
|
|
10
34
|
"""Get test environment variables from config file.
|
|
@@ -32,6 +56,8 @@ class EnvConfig:
|
|
|
32
56
|
# Find env config file from project root path
|
|
33
57
|
# CI_PROJECT_DIR was set by gitlab CI
|
|
34
58
|
PROJECT_ROOT_DIR = os.getenv('PROJECT_ROOT_DIR') or os.getenv('CI_PROJECT_DIR', '')
|
|
59
|
+
# allow EnvConfig load shell env variables, default enabled
|
|
60
|
+
DISABLE_LOAD_SHELL_ENV = os.getenv('ESPTEST_DISABLE_LOAD_SHELL_ENV', '').lower() in ('true', '1', 'yes', 'y')
|
|
35
61
|
|
|
36
62
|
# Allow input variables from terminal during local debugging
|
|
37
63
|
ALLOW_INPUT = not os.getenv('CI')
|
|
@@ -115,14 +141,18 @@ class EnvConfig:
|
|
|
115
141
|
# do not use dict.get because we can input the variable for local tests
|
|
116
142
|
if key in self.config_data:
|
|
117
143
|
var = self.config_data[key]
|
|
118
|
-
elif default:
|
|
144
|
+
elif default is not None:
|
|
119
145
|
var = default
|
|
120
146
|
else:
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
147
|
+
if not self.DISABLE_LOAD_SHELL_ENV:
|
|
148
|
+
# Try to get from shell environment variables
|
|
149
|
+
var = get_variable_from_env(key)
|
|
150
|
+
if var is None:
|
|
151
|
+
logging.warning(f'Failed to get env variable {self.env_tag}/{key}.')
|
|
152
|
+
logging.info(self.__doc__)
|
|
153
|
+
if not self.ALLOW_INPUT:
|
|
154
|
+
raise ValueError(f'Env variable not found: {self.env_tag}/{key}')
|
|
155
|
+
# For local test, support input the variable from console
|
|
156
|
+
var = input('You can input the variable now:')
|
|
127
157
|
logging.debug(f'Got env variable {self.env_tag}/{key}: {var}')
|
|
128
158
|
return var
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import contextlib
|
|
2
|
+
import csv
|
|
3
|
+
from typing import Any, Dict, Generator, List, Optional
|
|
4
|
+
|
|
5
|
+
from sqlalchemy import JSON, Engine, ForeignKey, Integer, String
|
|
6
|
+
from sqlalchemy.orm import DeclarativeBase, Mapped, Session, mapped_column, relationship
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class Base(DeclarativeBase):
|
|
10
|
+
pass
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class User(Base):
|
|
14
|
+
__tablename__ = 'user'
|
|
15
|
+
|
|
16
|
+
id: Mapped[int] = mapped_column(Integer, autoincrement=True, primary_key=True)
|
|
17
|
+
name: Mapped[str] = mapped_column(String(50), unique=True)
|
|
18
|
+
email: Mapped[Optional[str]] = mapped_column(String(50))
|
|
19
|
+
runners: Mapped[List['Runner']] = relationship(back_populates='user')
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class Runner(Base):
|
|
23
|
+
__tablename__ = 'runner'
|
|
24
|
+
|
|
25
|
+
id: Mapped[int] = mapped_column(Integer, autoincrement=True, primary_key=True)
|
|
26
|
+
mac: Mapped[str] = mapped_column(String(50), unique=True)
|
|
27
|
+
ip: Mapped[str] = mapped_column(String(100), unique=True)
|
|
28
|
+
vlan: Mapped[Optional[int]] = mapped_column(Integer)
|
|
29
|
+
switch_info: Mapped[Optional[str]] = mapped_column(String) # ip-port
|
|
30
|
+
name: Mapped[str] = mapped_column(String(50))
|
|
31
|
+
owner: Mapped[Optional[str]] = mapped_column(ForeignKey('user.name'), nullable=True)
|
|
32
|
+
tags: Mapped[Optional[List[str]]] = mapped_column(JSON) # only PostgreSQL supports ARRAY(String)
|
|
33
|
+
raw_data: Mapped[Optional[Dict[str, Any]]] = mapped_column(JSON)
|
|
34
|
+
description: Mapped[Optional[str]] = mapped_column(String)
|
|
35
|
+
# Link to user table
|
|
36
|
+
user: Mapped[User] = relationship(back_populates='runners')
|
|
37
|
+
|
|
38
|
+
def __str__(self) -> str:
|
|
39
|
+
tags_str = ','.join(self.tags) if self.tags else ''
|
|
40
|
+
return (
|
|
41
|
+
f'Runner('
|
|
42
|
+
f'id={self.id},'
|
|
43
|
+
f'mac={self.mac},'
|
|
44
|
+
f'ip={self.ip},'
|
|
45
|
+
f'vlan={self.vlan},'
|
|
46
|
+
f'switch_info={self.switch_info},'
|
|
47
|
+
f'name={self.name},'
|
|
48
|
+
f'owner={self.owner},'
|
|
49
|
+
f'tags="{tags_str}",'
|
|
50
|
+
f'raw_data={self.raw_data},'
|
|
51
|
+
f'description="{self.description}"'
|
|
52
|
+
')'
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class RunnerDB:
|
|
57
|
+
def __init__(self, engine: Engine) -> None:
|
|
58
|
+
self.engine = engine
|
|
59
|
+
self._session: Optional[Session] = None
|
|
60
|
+
self.__init_db()
|
|
61
|
+
|
|
62
|
+
def __init_db(self) -> None:
|
|
63
|
+
Base.metadata.create_all(self.engine)
|
|
64
|
+
|
|
65
|
+
@contextlib.contextmanager
|
|
66
|
+
def open_session(self, *args: Any, **kwargs: Any) -> Generator['DBSession', None, None]:
|
|
67
|
+
session = DBSession(self, *args, **kwargs)
|
|
68
|
+
yield session
|
|
69
|
+
try:
|
|
70
|
+
session.commit()
|
|
71
|
+
except:
|
|
72
|
+
session.rollback()
|
|
73
|
+
raise
|
|
74
|
+
finally:
|
|
75
|
+
session.close()
|
|
76
|
+
|
|
77
|
+
def to_csv(self, csv_file: str) -> None:
|
|
78
|
+
"""
|
|
79
|
+
Export the runners to a CSV file.
|
|
80
|
+
|
|
81
|
+
Args:
|
|
82
|
+
csv_file: The path to the CSV file.
|
|
83
|
+
session: The session to use. If None, use the default session.
|
|
84
|
+
"""
|
|
85
|
+
with self.open_session() as session:
|
|
86
|
+
runners = session.all_runners()
|
|
87
|
+
fields = [c.name for c in Runner.__table__.columns]
|
|
88
|
+
with open(csv_file, 'w', encoding='utf-8') as f:
|
|
89
|
+
writer = csv.writer(f)
|
|
90
|
+
writer.writerow(fields)
|
|
91
|
+
for runner in runners:
|
|
92
|
+
writer.writerow([getattr(runner, f) for f in fields])
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
class DBSession(Session):
|
|
96
|
+
def __init__(self, runner_db: RunnerDB, *args: Any, **kwargs: Any) -> None:
|
|
97
|
+
self.runner_db = runner_db
|
|
98
|
+
super().__init__(self.runner_db.engine, *args, **kwargs)
|
|
99
|
+
|
|
100
|
+
def all_runners(self) -> List[Runner]:
|
|
101
|
+
return self.query(Runner).outerjoin(Runner.user).all()
|
|
102
|
+
|
|
103
|
+
def all_users(self) -> List[User]:
|
|
104
|
+
return self.query(User).outerjoin(User.runners).all()
|
|
105
|
+
|
|
106
|
+
def get_runners_by_mac(self, mac: str) -> List[Runner]:
|
|
107
|
+
return self.query(Runner).filter(Runner.mac == mac).all()
|
|
108
|
+
|
|
109
|
+
def get_runners_by_ip(self, ip: str) -> List[Runner]:
|
|
110
|
+
return self.query(Runner).filter(Runner.ip == ip).all()
|
|
111
|
+
|
|
112
|
+
def get_users_by_name(self, name: str) -> List[User]:
|
|
113
|
+
return self.query(User).outerjoin(Runner.user).filter(User.name == name).all()
|
|
114
|
+
|
|
115
|
+
def get_users_by_email(self, email: str) -> List[User]:
|
|
116
|
+
return self.query(User).outerjoin(Runner.user).filter(User.email == email).all()
|
|
117
|
+
|
|
118
|
+
def remove_runner(self, runner: Runner) -> None:
|
|
119
|
+
"""
|
|
120
|
+
Remove a runner.
|
|
121
|
+
|
|
122
|
+
Args:
|
|
123
|
+
runner: The runner to remove.
|
|
124
|
+
session: The session to use. If None, use the default session.
|
|
125
|
+
"""
|
|
126
|
+
# session.merge(runner)
|
|
127
|
+
self.delete(runner)
|
|
128
|
+
self.flush()
|
|
129
|
+
|
|
130
|
+
def add_or_update_runner(self, runner: Runner) -> int:
|
|
131
|
+
"""
|
|
132
|
+
Add or update a runner.
|
|
133
|
+
|
|
134
|
+
Args:
|
|
135
|
+
runner: The runner to add or update.
|
|
136
|
+
session: The session to use. If None, use the default session.
|
|
137
|
+
"""
|
|
138
|
+
|
|
139
|
+
if runner.id is not None:
|
|
140
|
+
self.merge(runner)
|
|
141
|
+
else:
|
|
142
|
+
if self.get_runners_by_mac(runner.mac) or self.get_runners_by_ip(runner.ip):
|
|
143
|
+
raise ValueError(f'Runner with mac {runner.mac} or ip {runner.ip} already exists')
|
|
144
|
+
self.add(runner)
|
|
145
|
+
self.flush()
|
|
146
|
+
return runner.id
|
|
147
|
+
|
|
148
|
+
def add_or_update_user(self, user: User) -> int:
|
|
149
|
+
"""
|
|
150
|
+
Add or update an user.
|
|
151
|
+
|
|
152
|
+
Args:
|
|
153
|
+
user: The user to add or update.
|
|
154
|
+
session: The session to use. If None, use the default session.
|
|
155
|
+
"""
|
|
156
|
+
if user.id is not None:
|
|
157
|
+
self.merge(user)
|
|
158
|
+
else:
|
|
159
|
+
if self.get_users_by_name(user.name):
|
|
160
|
+
raise ValueError(f'User with name {user.name} already exists')
|
|
161
|
+
self.add(user)
|
|
162
|
+
self.flush()
|
|
163
|
+
return user.id
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
if __name__ == '__main__':
|
|
167
|
+
from sqlalchemy import create_engine
|
|
168
|
+
|
|
169
|
+
engine1 = create_engine('sqlite:///test.db')
|
|
170
|
+
# engine = create_engine("mysql+pymysql://user:pass@localhost/testdb")
|
|
171
|
+
db1 = RunnerDB(engine1)
|
|
172
|
+
import logging
|
|
173
|
+
|
|
174
|
+
logging.basicConfig(level=logging.DEBUG)
|
|
175
|
+
|
|
176
|
+
with db1.open_session() as session1:
|
|
177
|
+
for i in range(5):
|
|
178
|
+
runner1 = Runner(
|
|
179
|
+
# id=i+1,
|
|
180
|
+
mac=f'11:22:33:44:55:6{i}',
|
|
181
|
+
ip=f'192.168.1.{i}',
|
|
182
|
+
owner=f'test{i // 2}',
|
|
183
|
+
name=f'runner00{i}',
|
|
184
|
+
description=f'test runner 00{i} update 2',
|
|
185
|
+
tags=['esp32', 'generic', 'eco4'],
|
|
186
|
+
raw_data={'envs': {'esp32': [f'wifi_iperf_{i}']}, 'os': 'linux'},
|
|
187
|
+
)
|
|
188
|
+
session1.add_or_update_runner(runner1)
|
|
189
|
+
new_user = User(
|
|
190
|
+
# id=1,
|
|
191
|
+
name='test0'
|
|
192
|
+
)
|
|
193
|
+
session1.add_or_update_user(new_user)
|
|
194
|
+
session1.commit()
|
|
195
|
+
users = session1.query(User).outerjoin(User.runners).all()
|
|
196
|
+
print(users)
|
|
197
|
+
all_runners = session1.all_runners()
|
|
198
|
+
print(','.join([str(r) for r in all_runners]))
|
|
199
|
+
db1.to_csv('runners.csv')
|
|
@@ -84,3 +84,14 @@ def list_all_esp_ports() -> t.List[EspPortInfo]:
|
|
|
84
84
|
for port in get_all_serial_ports():
|
|
85
85
|
esp_ports.append(detect_one_port(port))
|
|
86
86
|
return esp_ports
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def get_available_ports(target: str, max_num: int = 0) -> t.List[EspPortInfo]:
|
|
90
|
+
detect_ports = []
|
|
91
|
+
for port in get_all_serial_ports():
|
|
92
|
+
esp_port = detect_one_port(port)
|
|
93
|
+
if esp_port.target == target:
|
|
94
|
+
detect_ports.append(esp_port)
|
|
95
|
+
if max_num > 0 and len(detect_ports) >= max_num: # pylint: disable=chained-comparison
|
|
96
|
+
return detect_ports
|
|
97
|
+
return detect_ports
|
|
@@ -2,26 +2,34 @@ import argparse
|
|
|
2
2
|
import logging
|
|
3
3
|
import os
|
|
4
4
|
import re
|
|
5
|
+
import sys
|
|
5
6
|
|
|
6
7
|
from esptest.devices.serial_tools import get_all_serial_ports
|
|
7
|
-
from esptest.tools.download_bin import download_bin_to_ports
|
|
8
|
+
from esptest.tools.download_bin import bin_path_to_dir, download_bin_to_ports
|
|
8
9
|
|
|
9
10
|
|
|
10
11
|
def main() -> None:
|
|
11
|
-
|
|
12
|
+
usage_string = '%(prog)s [bin_path] [options]'
|
|
13
|
+
parser = argparse.ArgumentParser(description='Download bin', usage=usage_string)
|
|
12
14
|
parser.add_argument('bin_path', type=str, nargs='?', help='esp bin path, default ./build')
|
|
13
15
|
parser.add_argument('-p', '--ports', type=str, nargs='*', help='download port list')
|
|
14
16
|
parser.add_argument(
|
|
15
17
|
'--range', type=str, help='port list from range (linux), eg: "0-10" equals to "-p ttyUSB0 ttyUSB1 ... ttyUSB10"'
|
|
16
18
|
)
|
|
17
|
-
parser.add_argument(
|
|
18
|
-
|
|
19
|
-
|
|
19
|
+
parser.add_argument(
|
|
20
|
+
'--all', action='store_true', help='download to all serial ports, ignored if "-p/--ports" is specified.'
|
|
21
|
+
)
|
|
22
|
+
parser.add_argument('--no-erase-nvs', dest='erase_nvs', action='store_false', help='skip erase nvs')
|
|
23
|
+
parser.add_argument('--max-workers', type=int, default=0, help='max download threads')
|
|
20
24
|
args = parser.parse_args()
|
|
21
25
|
|
|
22
26
|
bin_path = args.bin_path or './build'
|
|
23
27
|
if not os.path.isdir(bin_path):
|
|
24
|
-
|
|
28
|
+
try:
|
|
29
|
+
bin_path = bin_path_to_dir(bin_path)
|
|
30
|
+
except Exception as e: # pylint: disable=broad-except
|
|
31
|
+
logging.exception(f'Invalid bin path {bin_path} : {str(e)}')
|
|
32
|
+
sys.exit(1)
|
|
25
33
|
|
|
26
34
|
ports = []
|
|
27
35
|
if args.ports:
|
|
@@ -37,9 +45,13 @@ def main() -> None:
|
|
|
37
45
|
ports = [os.getenv('ESPPORT') or '/dev/ttyUSB0']
|
|
38
46
|
assert isinstance(ports, list)
|
|
39
47
|
|
|
40
|
-
|
|
41
|
-
|
|
48
|
+
try:
|
|
49
|
+
download_bin_to_ports(bin_path, ports, args.erase_nvs, args.max_workers)
|
|
50
|
+
except RuntimeError as e:
|
|
51
|
+
logging.error(str(e))
|
|
52
|
+
sys.exit(1)
|
|
42
53
|
|
|
43
54
|
|
|
44
55
|
if __name__ == '__main__':
|
|
56
|
+
logging.basicConfig(level=logging.INFO, format='%(asctime)s %(message)s')
|
|
45
57
|
main()
|
|
@@ -1,13 +1,18 @@
|
|
|
1
1
|
import asyncio
|
|
2
2
|
import concurrent
|
|
3
3
|
import concurrent.futures
|
|
4
|
+
import os
|
|
5
|
+
import re
|
|
4
6
|
import subprocess
|
|
7
|
+
import tempfile
|
|
8
|
+
import zipfile
|
|
5
9
|
from asyncio.events import AbstractEventLoop
|
|
6
10
|
from functools import lru_cache, partial
|
|
7
11
|
|
|
8
12
|
import esptest.common.compat_typing as t
|
|
9
13
|
from esptest.devices.serial_tools import compute_serial_port
|
|
10
14
|
from esptest.logger import get_logger
|
|
15
|
+
from esptest.tools.http_download import download_file
|
|
11
16
|
from esptest.utility.parse_bin_path import ParseBinPath
|
|
12
17
|
|
|
13
18
|
logger = get_logger('download_bin')
|
|
@@ -18,6 +23,32 @@ def _get_bin_parser(bin_path: str, parttool: str) -> ParseBinPath:
|
|
|
18
23
|
return ParseBinPath(bin_path, parttool)
|
|
19
24
|
|
|
20
25
|
|
|
26
|
+
@lru_cache()
|
|
27
|
+
def _tmp_dir() -> str:
|
|
28
|
+
return tempfile.mkdtemp()
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@lru_cache()
|
|
32
|
+
def bin_path_to_dir(bin_path: str) -> str:
|
|
33
|
+
bin_hash = hash(bin_path)
|
|
34
|
+
bin_hash_name = os.path.basename(bin_path)
|
|
35
|
+
if bin_path.startswith('http'):
|
|
36
|
+
assert bin_path.endswith('.zip') # for now only support zip from url
|
|
37
|
+
new_bin_path = os.path.join(_tmp_dir(), f'{bin_hash}', bin_hash_name)
|
|
38
|
+
os.makedirs(os.path.dirname(new_bin_path), exist_ok=True)
|
|
39
|
+
download_file(bin_path, new_bin_path)
|
|
40
|
+
bin_path = new_bin_path
|
|
41
|
+
if bin_path.endswith('.zip'):
|
|
42
|
+
new_bin_path = os.path.join(_tmp_dir(), f'{bin_hash}', bin_hash_name.removesuffix('.zip'))
|
|
43
|
+
os.makedirs(new_bin_path, exist_ok=True)
|
|
44
|
+
with zipfile.ZipFile(bin_path, 'r') as zip_ref:
|
|
45
|
+
zip_ref.extractall(new_bin_path)
|
|
46
|
+
bin_path = new_bin_path
|
|
47
|
+
if 'partition_table' not in os.listdir(bin_path):
|
|
48
|
+
logger.warning('Can not find partition_table from bin_path, maybe invalid!')
|
|
49
|
+
return bin_path
|
|
50
|
+
|
|
51
|
+
|
|
21
52
|
def _filter_esptool_log(log: str) -> str:
|
|
22
53
|
lines = log.splitlines(keepends=True)
|
|
23
54
|
new_log = ''
|
|
@@ -36,6 +67,7 @@ def _filter_esptool_log(log: str) -> str:
|
|
|
36
67
|
class DownBinTool:
|
|
37
68
|
# RETRY_CNT = 2
|
|
38
69
|
DEFAULT_BAUD_LIST = [921600, 460800]
|
|
70
|
+
FLASH_CRYPT_CNT_PATTERN = re.compile(r'(?:FLASH_CRYPT_CNT|SPI_BOOT_CRYPT_CNT).*\(0b([01]+)')
|
|
39
71
|
|
|
40
72
|
def __init__(
|
|
41
73
|
self,
|
|
@@ -45,7 +77,7 @@ class DownBinTool:
|
|
|
45
77
|
parttool: str = '',
|
|
46
78
|
esptool: str = '',
|
|
47
79
|
erase_nvs: bool = True,
|
|
48
|
-
force_no_stub: bool =
|
|
80
|
+
force_no_stub: bool = False,
|
|
49
81
|
): # pylint: disable=too-many-positional-arguments,too-many-arguments
|
|
50
82
|
self.bin_path = bin_path
|
|
51
83
|
self.port = compute_serial_port(port, strict=True)
|
|
@@ -54,11 +86,29 @@ class DownBinTool:
|
|
|
54
86
|
else:
|
|
55
87
|
self.baud_list = baud
|
|
56
88
|
self.esptool = esptool or 'python -m esptool'
|
|
89
|
+
self.espefuse = self.esptool.replace('esptool', 'espefuse')
|
|
57
90
|
self.erase_nvs = erase_nvs
|
|
58
91
|
self.bin_parser = _get_bin_parser(bin_path, parttool)
|
|
59
92
|
self.force_no_stub = force_no_stub
|
|
60
93
|
|
|
94
|
+
def check_flash_encrypted(self, efuse_summary: str) -> bool:
|
|
95
|
+
match = self.FLASH_CRYPT_CNT_PATTERN.search(efuse_summary)
|
|
96
|
+
if match:
|
|
97
|
+
return match.group(1).count('1') % 2 == 1
|
|
98
|
+
return False
|
|
99
|
+
|
|
61
100
|
def download(self) -> None:
|
|
101
|
+
efuse_cmd = self.espefuse.split()
|
|
102
|
+
try:
|
|
103
|
+
summary = subprocess.check_output(
|
|
104
|
+
efuse_cmd + ['--port', self.port, 'summary'], stderr=subprocess.STDOUT, text=True
|
|
105
|
+
)
|
|
106
|
+
except subprocess.CalledProcessError as err:
|
|
107
|
+
logger.error(err.output)
|
|
108
|
+
raise RuntimeError(f'Failed to get efuse information from {self.port}') from err
|
|
109
|
+
|
|
110
|
+
enc_indicator = ' [encrypted]' if self.check_flash_encrypted(summary) else ''
|
|
111
|
+
|
|
62
112
|
download_log = ''
|
|
63
113
|
for baud in self.baud_list:
|
|
64
114
|
args = self.esptool.split()
|
|
@@ -66,19 +116,18 @@ class DownBinTool:
|
|
|
66
116
|
args += ['--no-stub']
|
|
67
117
|
args += ['-p', self.port]
|
|
68
118
|
args += ['-b', f'{baud}']
|
|
69
|
-
args += self.bin_parser.flash_bin_args(erase_nvs=self.erase_nvs)
|
|
119
|
+
args += self.bin_parser.flash_bin_args(erase_nvs=self.erase_nvs, encrypted=bool(enc_indicator))
|
|
70
120
|
|
|
71
|
-
logger.
|
|
121
|
+
logger.info(f'Downloading {self.port}@{baud}{enc_indicator}: {self.bin_path}')
|
|
72
122
|
# get return code rather than check
|
|
73
123
|
ret = subprocess.run(args, capture_output=True, text=True, check=False)
|
|
74
124
|
if ret.returncode == 0:
|
|
75
125
|
return # succeed
|
|
76
126
|
# failed
|
|
77
|
-
download_log
|
|
127
|
+
download_log += f'esptool cmd failed ({ret.returncode}): ' + ' '.join(args)
|
|
78
128
|
download_log += f'\nDownload failed: [{self.port}@{baud}]\n'
|
|
79
129
|
esptool_msg = ret.stdout + ret.stderr
|
|
80
130
|
download_log += f'esptool output: {_filter_esptool_log(esptool_msg)}'
|
|
81
|
-
logger.debug(download_log)
|
|
82
131
|
logger.error(download_log)
|
|
83
132
|
raise RuntimeError(f'Failed to download Bin to {self.port}')
|
|
84
133
|
|