mirror of
https://github.com/espressif/esptool.git
synced 2025-10-14 19:28:40 +08:00

Split merged hex files into multiple temporary binary files for commands like `write-flash` and `image-info` and others that support IntelHex files. Splitting is done based on the gaps in the addresses. This should prevent overriding the flash region between the files. Closes https://github.com/espressif/esptool/issues/1075
211 lines
7.9 KiB
Python
Executable File
211 lines
7.9 KiB
Python
Executable File
import os
|
|
import os.path
|
|
import subprocess
|
|
import sys
|
|
import tempfile
|
|
|
|
from conftest import need_to_install_package_err
|
|
|
|
import pytest
|
|
|
|
try:
|
|
import esptool # noqa: F401
|
|
except ImportError:
|
|
need_to_install_package_err()
|
|
|
|
IMAGES_DIR = os.path.join(os.path.abspath(os.path.dirname(__file__)), "images")
|
|
|
|
ESP8266_BIN = "not_4_byte_aligned.bin"
|
|
|
|
|
|
def read_image(filename):
|
|
with open(os.path.join(IMAGES_DIR, filename), "rb") as f:
|
|
return f.read()
|
|
|
|
|
|
@pytest.mark.host_test
|
|
class TestImageInfo:
|
|
def run_image_info(self, chip, file):
|
|
"""Runs image-info on a binary file.
|
|
Returns the command output.
|
|
Filenames are relative to the 'test/images' directory.
|
|
"""
|
|
|
|
cmd = [
|
|
sys.executable,
|
|
"-m",
|
|
"esptool",
|
|
"--chip",
|
|
chip,
|
|
"image-info",
|
|
]
|
|
# if path was passed use the whole path
|
|
# if file does not exists try to use file from IMAGES_DIR directory
|
|
cmd += [file] if os.path.isfile(file) else ["".join([IMAGES_DIR, os.sep, file])]
|
|
print("\nExecuting {}".format(" ".join(cmd)))
|
|
|
|
try:
|
|
output = subprocess.check_output(cmd, stderr=subprocess.STDOUT)
|
|
output = output.decode("utf-8")
|
|
print(output) # for more complete stdout logs on failure
|
|
assert "warning" not in output.lower(), (
|
|
"image-info should not output warnings"
|
|
)
|
|
return output
|
|
except subprocess.CalledProcessError as e:
|
|
print(e.output)
|
|
raise
|
|
|
|
def test_esp32c3(self):
|
|
out = self.run_image_info("esp32c3", "bootloader_esp32c3.bin")
|
|
|
|
# Header
|
|
assert "Entry point: 0x403c0000" in out, "Wrong entry point"
|
|
assert "Segments: 4" in out, "Wrong num of segments"
|
|
assert "Flash size: 2MB" in out, "Wrong flash size"
|
|
assert "Flash freq: 40m" in out, "Wrong flash frequency"
|
|
assert "Flash mode: DIO" in out, "Wrong flash mode"
|
|
|
|
# Extended header
|
|
assert "WP pin: 0xee (disabled)" in out, "Wrong WP pin"
|
|
assert "Chip ID: 5 (ESP32-C3)" in out, "Wrong chip ID"
|
|
assert (
|
|
"clk_drv: 0x0, q_drv: 0x0, d_drv: 0x0, "
|
|
"cs0_drv: 0x0, hd_drv: 0x0, wp_drv: 0x0" in out
|
|
), "Wrong flash pins drive settings"
|
|
|
|
assert "Minimal chip revision: v0.0" in out, "Wrong min revision"
|
|
assert "Maximal chip revision: v0.0" in out, "Wrong min revision"
|
|
|
|
# Segments
|
|
assert "1 0x01864 0x3fcd6114 0x00000034 DRAM, BYTE_ACCESSIBLE" in out, (
|
|
"Wrong segment info"
|
|
)
|
|
|
|
# Footer
|
|
assert "Checksum: 0x77 (valid)" in out, "Invalid checksum"
|
|
assert "c0a9d6d882b65580da2e5e6347 (valid)" in out, "Invalid hash"
|
|
|
|
# Check output against individual bytes in the headers
|
|
hdr = read_image("bootloader_esp32c3.bin")[:8]
|
|
ex_hdr = read_image("bootloader_esp32c3.bin")[8:24]
|
|
assert f"Segments: {hdr[1]}" in out, "Wrong num of segments"
|
|
assert f"WP pin: {ex_hdr[0]:#02x}" in out, "Wrong WP pin"
|
|
assert f"Chip ID: {ex_hdr[4]}" in out, "Wrong chip ID"
|
|
if ex_hdr[15] == 1: # Hash appended
|
|
assert "Validation hash: 4faeab1bd3fd" in out, "Invalid hash"
|
|
|
|
def test_esp8266(self):
|
|
out = self.run_image_info("esp8266", ESP8266_BIN)
|
|
assert "Image version: 1" in out, "Wrong image version"
|
|
assert "Entry point: 0x40101844" in out, "Wrong entry point"
|
|
assert "Flash size: 512KB" in out, "Wrong flash size"
|
|
assert "Flash freq: 40m" in out, "Wrong flash frequency"
|
|
assert "Flash mode: QIO" in out, "Wrong flash mode"
|
|
assert "Checksum: 0x6b (valid)" in out, "Invalid checksum"
|
|
assert "Segments: 1" in out, "Wrong number of segments"
|
|
assert "0 0x00014 0x40100000 0x00000008 IRAM" in out, "Wrong segment info"
|
|
|
|
def test_image_type_detection(self):
|
|
# ESP8266
|
|
out = self.run_image_info("auto", ESP8266_BIN)
|
|
assert "Detected image type: ESP8266" in out
|
|
assert "Flash freq: 40m" in out
|
|
out = self.run_image_info("auto", "esp8266_deepsleep.bin")
|
|
assert "Detected image type: ESP8266" in out
|
|
|
|
# ESP32, with and without detection
|
|
out = self.run_image_info("auto", "bootloader_esp32.bin")
|
|
assert "Detected image type: ESP32" in out
|
|
out = self.run_image_info("auto", "ram_helloworld/helloworld-esp32_edit.bin")
|
|
assert "Detected image type: ESP32" in out
|
|
out = self.run_image_info("esp32", "bootloader_esp32.bin")
|
|
assert "Detected image type: ESP32" not in out
|
|
|
|
# ESP32-C3
|
|
out = self.run_image_info("auto", "bootloader_esp32c3.bin")
|
|
assert "Detected image type: ESP32-C3" in out
|
|
|
|
# ESP32-S3
|
|
out = self.run_image_info("auto", "esp32s3_header.bin")
|
|
assert "Detected image type: ESP32-S3" in out
|
|
|
|
def test_invalid_image_type_detection(self, capsys):
|
|
with pytest.raises(subprocess.CalledProcessError):
|
|
# Invalid image
|
|
self.run_image_info("auto", "one_kb.bin")
|
|
assert (
|
|
"This is not a valid image (invalid magic number: 0xed)"
|
|
in capsys.readouterr().out
|
|
)
|
|
|
|
def test_application_info(self):
|
|
out = self.run_image_info("auto", "esp_idf_blink_esp32s2.bin")
|
|
assert "Application Information" in out
|
|
assert "Project name: blink" in out
|
|
assert "App version: qa-test-v5.0-20220830-4-g4532e6" in out
|
|
assert "Secure version: 0" in out
|
|
assert "Compile time: Sep 13 2022" in out
|
|
assert "19:46:07" in out
|
|
assert "3059e6b55a965865febd28fa9f6028ad5" in out
|
|
assert "cd0dab311febb0a3ea79eaa223ac2b0" in out
|
|
assert "ESP-IDF: v5.0-beta1-427-g4532e6e0b2-dirt" in out
|
|
# No application info in image
|
|
out = self.run_image_info("auto", "bootloader_esp32.bin")
|
|
assert "Application Information" not in out
|
|
out = self.run_image_info("auto", ESP8266_BIN)
|
|
assert "Application Information" not in out
|
|
|
|
def test_bootloader_info(self):
|
|
# This bootloader binary is built from "hello_world" project
|
|
# with default settings, IDF version is v5.2.
|
|
out = self.run_image_info("esp32", "bootloader_esp32_v5_2.bin")
|
|
assert "Image size: 26768 bytes" in out
|
|
assert "Bootloader Information" in out
|
|
assert "Bootloader version: 1" in out
|
|
assert "ESP-IDF: v5.2-dev-254-g1950b15" in out
|
|
assert "Compile time: Apr 25 2023 00:13:32" in out
|
|
|
|
def test_intel_hex(self):
|
|
# Convert and merge two files to Intel Hex using merge-bin
|
|
# Run image-info on the resulting Intel Hex file
|
|
# Verify that image info is shown for both files
|
|
|
|
def convert_bin2hex(file):
|
|
subprocess.check_output(
|
|
[
|
|
sys.executable,
|
|
"-m",
|
|
"esptool",
|
|
"--chip",
|
|
"esp32c3",
|
|
"merge-bin",
|
|
"--format",
|
|
"hex",
|
|
"0x0",
|
|
os.path.join(IMAGES_DIR, "bootloader_esp32c3.bin"),
|
|
"0x8000",
|
|
os.path.join(IMAGES_DIR, "esp32c3_header_min_rev.bin"),
|
|
"-o",
|
|
file,
|
|
]
|
|
)
|
|
|
|
fd, file = tempfile.mkstemp(suffix=".hex")
|
|
try:
|
|
convert_bin2hex(file)
|
|
out = self.run_image_info("esp32c3", file)
|
|
assert (
|
|
"Merged binary image detected. Processing each file individually."
|
|
in out
|
|
)
|
|
assert "Processing file 1/2, offset: 0x0, size: 17744 bytes" in out
|
|
assert "Processing file 2/2, offset: 0x8000, size: 48 bytes" in out
|
|
finally:
|
|
try:
|
|
# make sure that file was closed before removing it
|
|
os.close(fd)
|
|
except OSError:
|
|
pass
|
|
os.unlink(file)
|