improve concatenate to create smaller UF2s

the prior version, for the board/user configs, took the whole ~2MB
binary file and converted it to a UF2, which made for a lot of chunks
that were just writing 0s, between the end of the firmware and the start
of the config(s). this changes the logic to build each portion as
separate UF2 chunks and then combine them.

Signed-off-by: Brian S. Stephan <bss@incorporeal.org>
This commit is contained in:
Brian S. Stephan 2024-04-12 13:09:02 -05:00
parent 65ae51af72
commit 8e6a203398
Signed by: bss
GPG Key ID: 3DE06D3180895FCB
3 changed files with 53 additions and 5 deletions

View File

@ -95,15 +95,25 @@ def concatenate_firmware_and_storage_files(firmware_filename: str,
user_config_binary = serialize_config_with_footer(config)
with open(firmware_filename, 'rb') as firmware:
new_binary = combine_firmware_and_config(bytearray(firmware.read()), board_config_binary, user_config_binary,
firmware_binary = bytearray(firmware.read())
# create a sequential binary for .bin and USB uses, or index it for .uf2
if usb or combined_filename[-4:] != '.uf2':
new_binary = combine_firmware_and_config(firmware_binary, board_config_binary, user_config_binary,
replace_extra=replace_extra)
else:
new_binary = convert_binary_to_uf2(firmware_binary)
if board_config_binary:
new_binary += convert_binary_to_uf2(pad_config_to_storage_size(board_config_binary),
start=BOARD_CONFIG_BINARY_LOCATION)
if user_config_binary:
new_binary += convert_binary_to_uf2(pad_config_to_storage_size(user_config_binary),
start=USER_CONFIG_BINARY_LOCATION)
if combined_filename:
with open(combined_filename, 'wb') as combined:
if combined_filename[-4:] == '.uf2':
combined.write(convert_binary_to_uf2(new_binary))
else:
combined.write(new_binary)
combined.write(new_binary)
if usb:
endpoint_out, endpoint_in = get_bootsel_endpoints()
write(endpoint_out, endpoint_in, GP2040CE_START_ADDRESS, bytes(new_binary))

View File

@ -3,6 +3,7 @@
SPDX-FileCopyrightText: © 2023 Brian S. Stephan <bss@incorporeal.org>
SPDX-License-Identifier: GPL-3.0-or-later
"""
import math
import os
import sys
import unittest.mock as mock
@ -110,6 +111,33 @@ def test_concatenate_to_usb(tmp_path):
assert len(mock_write.call_args.args[3]) == 2 * 1024 * 1024
def test_concatenate_to_uf2(tmp_path, firmware_binary, config_binary):
"""Test that we write a UF2 file as expected."""
tmp_file = os.path.join(tmp_path, 'concat.uf2')
firmware_file = os.path.join(HERE, 'test-files', 'test-firmware.bin')
config_file = os.path.join(HERE, 'test-files', 'test-config.bin')
concatenate_firmware_and_storage_files(firmware_file, binary_board_config_filename=config_file,
binary_user_config_filename=config_file,
combined_filename=tmp_file)
with open(tmp_file, 'rb') as file:
content = file.read()
# size of the file should be 2x firmware in 256 byte blocks + 2x padded board config + 2x padding user config
assert len(content) == 2 * (math.ceil(len(firmware_binary)/256) * 256) + 2 * STORAGE_SIZE + 2 * STORAGE_SIZE
def test_concatenate_to_uf2_board_only(tmp_path, firmware_binary, config_binary):
"""Test that we write a UF2 file as expected."""
tmp_file = os.path.join(tmp_path, 'concat.uf2')
firmware_file = os.path.join(HERE, 'test-files', 'test-firmware.bin')
config_file = os.path.join(HERE, 'test-files', 'test-config.bin')
concatenate_firmware_and_storage_files(firmware_file, binary_board_config_filename=config_file,
combined_filename=tmp_file)
with open(tmp_file, 'rb') as file:
content = file.read()
# size of the file should be 2x firmware in 256 byte blocks + 2x padded board config + 2x padding user config
assert len(content) == 2 * (math.ceil(len(firmware_binary)/256) * 256) + 2 * STORAGE_SIZE
def test_padding_firmware(firmware_binary):
"""Test that firmware is padded to the expected size."""
padded = pad_binary_up_to_user_config(firmware_binary)

View File

@ -3,6 +3,7 @@
SPDX-FileCopyrightText: © 2023 Brian S. Stephan <bss@incorporeal.org>
SPDX-License-Identifier: GPL-3.0-or-later
"""
import math
import os
import sys
import unittest.mock as mock
@ -139,6 +140,15 @@ def test_convert_binary_to_uf2(whole_board_with_board_config_dump):
assert uf2[524:528] == bytearray(b'\x00\x01\x00\x10') # address to write the second chunk
def test_convert_unaligned_binary_to_uf2(firmware_binary):
"""Do some sanity checks in the attempt to convert a binary to a UF2."""
uf2 = storage.convert_binary_to_uf2(firmware_binary)
assert len(uf2) == math.ceil(len(firmware_binary)/256) * 512 # 256 byte complete/partial chunks -> 512 b chunks
assert uf2[0:4] == b'\x55\x46\x32\x0a' == b'UF2\n' # proper magic
assert uf2[8:12] == bytearray(b'\x00\x20\x00\x00') # family ID set
assert uf2[524:528] == bytearray(b'\x00\x01\x00\x10') # address to write the second chunk
def test_convert_binary_to_uf2_with_offsets(whole_board_with_board_config_dump):
"""Do some sanity checks in the attempt to convert a binary to a UF2."""
uf2 = storage.convert_binary_to_uf2(whole_board_with_board_config_dump, start=storage.USER_CONFIG_BINARY_LOCATION)