mirror of
https://github.com/espressif/esptool.git
synced 2025-10-21 06:40:00 +08:00
201 lines
7.1 KiB
Python
Executable File
201 lines
7.1 KiB
Python
Executable File
#!/usr/bin/env python
|
|
from __future__ import division, print_function
|
|
|
|
import itertools
|
|
import os
|
|
import os.path
|
|
import subprocess
|
|
import sys
|
|
import tempfile
|
|
import unittest
|
|
|
|
IMAGES_DIR = os.path.join(os.path.abspath(os.path.dirname(__file__)), "images")
|
|
try:
|
|
ESPTOOL_PY = os.environ["ESPTOOL_PY"]
|
|
except KeyError:
|
|
ESPTOOL_PY = os.path.join(IMAGES_DIR, "../..", "esptool/__init__.py")
|
|
|
|
# import the version of esptool we are testing with
|
|
sys.path.append(os.path.dirname(ESPTOOL_PY))
|
|
|
|
|
|
from esptool.util import byte
|
|
|
|
|
|
def read_image(filename):
|
|
with open(os.path.join(IMAGES_DIR, filename), "rb") as f:
|
|
return f.read()
|
|
|
|
|
|
class MergeBinTests(unittest.TestCase):
|
|
def run_merge_bin(self, chip, offsets_names, options=[]):
|
|
"""Run merge_bin on a list of (offset, filename) tuples
|
|
with output to a named temporary file.
|
|
|
|
Filenames are relative to the 'test/images' directory.
|
|
|
|
Returns the contents of the merged file if successful.
|
|
"""
|
|
output_file = tempfile.NamedTemporaryFile(delete=False)
|
|
try:
|
|
output_file.close()
|
|
|
|
cmd = [
|
|
sys.executable,
|
|
ESPTOOL_PY,
|
|
"--chip",
|
|
chip,
|
|
"merge_bin",
|
|
"-o",
|
|
output_file.name,
|
|
] + options
|
|
for (offset, name) in offsets_names:
|
|
cmd += [hex(offset), name]
|
|
print("Executing %s" % (" ".join(cmd)))
|
|
|
|
output = str(
|
|
subprocess.check_output(cmd, cwd=IMAGES_DIR, stderr=subprocess.STDOUT)
|
|
)
|
|
print(output)
|
|
self.assertFalse(
|
|
"warning" in output.lower(), "merge_bin should not output warnings"
|
|
)
|
|
|
|
with open(output_file.name, "rb") as f:
|
|
return f.read()
|
|
except subprocess.CalledProcessError as e:
|
|
print(e.output)
|
|
raise
|
|
finally:
|
|
os.unlink(output_file.name)
|
|
|
|
def assertAllFF(self, some_bytes):
|
|
# this may need some improving as the failed assert messages may be
|
|
# very long and/or useless!
|
|
self.assertEqual(b"\xFF" * len(some_bytes), some_bytes)
|
|
|
|
def test_simple_merge(self):
|
|
merged = self.run_merge_bin(
|
|
"esp8266",
|
|
[(0x0, "one_kb.bin"), (0x1000, "one_kb.bin"), (0x10000, "one_kb.bin")],
|
|
)
|
|
one_kb = read_image("one_kb.bin")
|
|
|
|
self.assertEqual(0x400, len(one_kb))
|
|
|
|
self.assertEqual(0x10400, len(merged))
|
|
self.assertEqual(one_kb, merged[:0x400])
|
|
self.assertEqual(one_kb, merged[0x1000:0x1400])
|
|
self.assertEqual(one_kb, merged[0x10000:])
|
|
|
|
self.assertAllFF(merged[0x400:0x1000])
|
|
self.assertAllFF(merged[0x1400:0x10000])
|
|
|
|
def test_args_out_of_order(self):
|
|
# no matter which order we supply arguments, the output should be the same
|
|
args = [(0x0, "one_kb.bin"), (0x1000, "one_kb.bin"), (0x10000, "one_kb.bin")]
|
|
merged_orders = [
|
|
self.run_merge_bin("esp8266", perm_args)
|
|
for perm_args in itertools.permutations(args)
|
|
]
|
|
for m in merged_orders:
|
|
self.assertEqual(merged_orders[0], m)
|
|
|
|
def test_error_overlap(self):
|
|
args = [(0x1000, "one_mb.bin"), (0x20000, "one_kb.bin")]
|
|
for perm_args in itertools.permutations(args):
|
|
with self.assertRaises(subprocess.CalledProcessError) as fail:
|
|
self.run_merge_bin("esp32", perm_args)
|
|
self.assertIn(b"overlap", fail.exception.output)
|
|
|
|
def test_leading_padding(self):
|
|
merged = self.run_merge_bin("esp32c3", [(0x100000, "one_mb.bin")])
|
|
self.assertAllFF(merged[:0x100000])
|
|
self.assertEqual(read_image("one_mb.bin"), merged[0x100000:])
|
|
|
|
def test_update_bootloader_params(self):
|
|
merged = self.run_merge_bin(
|
|
"esp32",
|
|
[
|
|
(0x1000, "bootloader_esp32.bin"),
|
|
(0x10000, "ram_helloworld/helloworld-esp32.bin"),
|
|
],
|
|
["--flash_size", "2MB", "--flash_mode", "dout"],
|
|
)
|
|
self.assertAllFF(merged[:0x1000])
|
|
|
|
bootloader = read_image("bootloader_esp32.bin")
|
|
helloworld = read_image("ram_helloworld/helloworld-esp32.bin")
|
|
|
|
# test the bootloader is unchanged apart from the header
|
|
# (updating the header doesn't change CRC,
|
|
# and doesn't update the SHA although it will invalidate it!)
|
|
self.assertEqual(merged[0x1010 : 0x1000 + len(bootloader)], bootloader[0x10:])
|
|
|
|
# check the individual bytes in the header are as expected
|
|
merged_hdr = merged[0x1000:0x1010]
|
|
bootloader_hdr = bootloader[:0x10]
|
|
self.assertEqual(bootloader_hdr[:2], merged_hdr[:2])
|
|
self.assertEqual(3, byte(merged_hdr, 2)) # flash mode dout
|
|
self.assertEqual(0x10, byte(merged_hdr, 3) & 0xF0) # flash size 2MB (ESP32)
|
|
self.assertEqual(
|
|
byte(bootloader_hdr, 3) & 0x0F, byte(merged_hdr, 3) & 0x0F
|
|
) # flash speed is unchanged
|
|
self.assertEqual(
|
|
bootloader_hdr[4:], merged_hdr[4:]
|
|
) # remaining field are unchanged
|
|
|
|
# check all the padding is as expected
|
|
self.assertAllFF(merged[0x1000 + len(bootloader) : 0x10000])
|
|
self.assertEqual(merged[0x10000 : 0x10000 + len(helloworld)], helloworld)
|
|
|
|
def test_target_offset(self):
|
|
merged = self.run_merge_bin(
|
|
"esp32",
|
|
[
|
|
(0x1000, "bootloader_esp32.bin"),
|
|
(0x10000, "ram_helloworld/helloworld-esp32.bin"),
|
|
],
|
|
["--target-offset", "0x1000"],
|
|
)
|
|
|
|
bootloader = read_image("bootloader_esp32.bin")
|
|
helloworld = read_image("ram_helloworld/helloworld-esp32.bin")
|
|
self.assertEqual(bootloader, merged[: len(bootloader)])
|
|
self.assertEqual(helloworld, merged[0xF000 : 0xF000 + len(helloworld)])
|
|
self.assertAllFF(merged[0x1000 + len(bootloader) : 0xF000])
|
|
|
|
def test_fill_flash_size(self):
|
|
merged = self.run_merge_bin(
|
|
"esp32c3", [(0x0, "bootloader_esp32c3.bin")], ["--fill-flash-size", "4MB"]
|
|
)
|
|
bootloader = read_image("bootloader_esp32c3.bin")
|
|
|
|
self.assertEqual(0x400000, len(merged))
|
|
self.assertEqual(bootloader, merged[: len(bootloader)])
|
|
self.assertAllFF(merged[len(bootloader) :])
|
|
|
|
def test_fill_flash_size_w_target_offset(self):
|
|
merged = self.run_merge_bin(
|
|
"esp32",
|
|
[
|
|
(0x1000, "bootloader_esp32.bin"),
|
|
(0x10000, "ram_helloworld/helloworld-esp32.bin"),
|
|
],
|
|
["--target-offset", "0x1000", "--fill-flash-size", "2MB"],
|
|
)
|
|
|
|
self.assertEqual(
|
|
0x200000 - 0x1000, len(merged)
|
|
) # full length is without target-offset arg
|
|
|
|
bootloader = read_image("bootloader_esp32.bin")
|
|
helloworld = read_image("ram_helloworld/helloworld-esp32.bin")
|
|
self.assertEqual(bootloader, merged[: len(bootloader)])
|
|
self.assertEqual(helloworld, merged[0xF000 : 0xF000 + len(helloworld)])
|
|
self.assertAllFF(merged[0xF000 + len(helloworld) :])
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main(buffer=True)
|