diff --git a/gp2040ce_bintools/builder.py b/gp2040ce_bintools/builder.py index 540381b..32a8b6a 100644 --- a/gp2040ce_bintools/builder.py +++ b/gp2040ce_bintools/builder.py @@ -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)) diff --git a/tests/test_builder.py b/tests/test_builder.py index e73ff1e..b61c651 100644 --- a/tests/test_builder.py +++ b/tests/test_builder.py @@ -3,6 +3,7 @@ SPDX-FileCopyrightText: © 2023 Brian S. Stephan 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) diff --git a/tests/test_storage.py b/tests/test_storage.py index cb12e75..5ef8da3 100644 --- a/tests/test_storage.py +++ b/tests/test_storage.py @@ -3,6 +3,7 @@ SPDX-FileCopyrightText: © 2023 Brian S. Stephan 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)