From cce165f0124bec60d47b3a9539bdb85f4e5635c6 Mon Sep 17 00:00:00 2001 From: "Brian S. Stephan" Date: Wed, 12 Jul 2023 17:37:45 -0500 Subject: [PATCH] add flag to have concatenate write direct to USB --- README.md | 5 ++++- gp2040ce_bintools/builder.py | 24 ++++++++++++++++-------- tests/test_builder.py | 27 ++++++++++++++++++++++++++- tests/test_commands.py | 2 +- 4 files changed, 47 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 8cadc00..1f7dd3c 100644 --- a/README.md +++ b/README.md @@ -59,10 +59,13 @@ This may be useful to ensure the board is flashed with a particular configuratio binary to flash many boards with a particular configuration (specific customizations, etc.), or keeping documented backups of what you're testing with during development. +The produced binary can be written to a file with `--new-binary-filename FILENAME` or straight to a RP2040 in BOOTSEL + mode with `--usb`. + Sample usage: ``` -% concatenate build/GP2040-CE_foo_bar.bin storage-dump.bin new-firmware-with-config.bin +% concatenate build/GP2040-CE_foo_bar.bin storage-dump.bin --new-binary-filename new-firmware-with-config.bin ``` ### dump-config diff --git a/gp2040ce_bintools/builder.py b/gp2040ce_bintools/builder.py index cbe2769..69db8e1 100644 --- a/gp2040ce_bintools/builder.py +++ b/gp2040ce_bintools/builder.py @@ -40,8 +40,9 @@ def combine_firmware_and_config(firmware_binary: bytearray, config_binary: bytea pad_config_to_storage_size(config_binary)) -def concatenate_firmware_and_storage_files(firmware_filename: str, storage_filename: str, combined_filename: str, - replace_extra: bool = False): +def concatenate_firmware_and_storage_files(firmware_filename: str, storage_filename: str, + combined_filename: str = '', usb: bool = False, + replace_extra: bool = False) -> None: """Open the provided binary files and combine them into one combined GP2040-CE with config file. Args: @@ -53,8 +54,12 @@ def concatenate_firmware_and_storage_files(firmware_filename: str, storage_filen with open(firmware_filename, 'rb') as firmware, open(storage_filename, 'rb') as storage: new_binary = combine_firmware_and_config(bytearray(firmware.read()), bytearray(storage.read()), replace_extra=replace_extra) - with open(combined_filename, 'wb') as combined: - combined.write(new_binary) + if combined_filename: + with open(combined_filename, 'wb') as combined: + combined.write(new_binary) + if usb: + endpoint_out, endpoint_in = get_bootsel_endpoints() + write(endpoint_out, endpoint_in, GP2040CE_START_ADDRESS, bytes(new_binary)) def get_gp2040ce_from_usb() -> tuple[bytes, object, object]: @@ -174,15 +179,18 @@ def concatenate(): "into one file suitable for flashing onto a board.", parents=[core_parser], ) - parser.add_argument('firmware_filename', help=".bin file of a GP2040-CE firmware, probably from a build") - parser.add_argument('config_filename', help=".bin file of a GP2040-CE board's storage section or config w/footer") - parser.add_argument('new_binary_filename', help="output .bin file of the resulting firmware + storage") parser.add_argument('--replace-extra', action='store_true', help="if the firmware file is larger than the location of storage, perhaps because it's " "actually a full board dump, overwrite its config section with the config binary") + parser.add_argument('firmware_filename', help=".bin file of a GP2040-CE firmware, probably from a build") + parser.add_argument('config_filename', help=".bin file of a GP2040-CE board's storage section or config w/footer") + group = parser.add_mutually_exclusive_group(required=True) + group.add_argument('--usb', action='store_true', help="write the resulting firmware + storage to USB") + group.add_argument('--new-binary-filename', help="output .bin file of the resulting firmware + storage") args, _ = parser.parse_known_args() - concatenate_firmware_and_storage_files(args.firmware_filename, args.config_filename, args.new_binary_filename, + concatenate_firmware_and_storage_files(args.firmware_filename, args.config_filename, + combined_filename=args.new_binary_filename, usb=args.usb, replace_extra=args.replace_extra) diff --git a/tests/test_builder.py b/tests/test_builder.py index 905db80..ec754d9 100644 --- a/tests/test_builder.py +++ b/tests/test_builder.py @@ -7,7 +7,8 @@ import pytest from decorator import decorator from gp2040ce_bintools import get_config_pb2 -from gp2040ce_bintools.builder import (FirmwareLengthError, combine_firmware_and_config, get_gp2040ce_from_usb, +from gp2040ce_bintools.builder import (FirmwareLengthError, combine_firmware_and_config, + concatenate_firmware_and_storage_files, get_gp2040ce_from_usb, pad_firmware_up_to_storage, replace_config_in_binary, write_new_config_to_filename, write_new_config_to_usb) from gp2040ce_bintools.storage import get_config, get_config_footer, get_storage_section, serialize_config_with_footer @@ -27,6 +28,30 @@ def with_pb2s(test, *args, **kwargs): del sys.modules['config_pb2'] +def test_concatenate_to_file(tmp_path): + """Test that we write a file as expected.""" + tmp_file = os.path.join(tmp_path, 'concat.bin') + 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, config_file, combined_filename=tmp_file) + with open(tmp_file, 'rb') as file: + content = file.read() + assert len(content) == 2 * 1024 * 1024 + + +def test_concatenate_to_usb(tmp_path): + """Test that we write a file as expected.""" + firmware_file = os.path.join(HERE, 'test-files', 'test-firmware.bin') + config_file = os.path.join(HERE, 'test-files', 'test-config.bin') + end_out, end_in = mock.MagicMock(), mock.MagicMock() + with mock.patch('gp2040ce_bintools.builder.get_bootsel_endpoints', return_value=(end_out, end_in)): + with mock.patch('gp2040ce_bintools.builder.write') as mock_write: + concatenate_firmware_and_storage_files(firmware_file, config_file, usb=True) + + assert mock_write.call_args.args[2] == 0x10000000 + assert len(mock_write.call_args.args[3]) == 2 * 1024 * 1024 + + def test_padding_firmware(firmware_binary): """Test that firmware is padded to the expected size.""" padded = pad_firmware_up_to_storage(firmware_binary) diff --git a/tests/test_commands.py b/tests/test_commands.py index b4dd099..1dc11c0 100644 --- a/tests/test_commands.py +++ b/tests/test_commands.py @@ -40,7 +40,7 @@ def test_concatenate_invocation(tmpdir): """Test that a normal invocation against a dump works.""" out_filename = os.path.join(tmpdir, 'out.bin') _ = run(['concatenate', 'tests/test-files/test-firmware.bin', 'tests/test-files/test-storage-area.bin', - out_filename]) + '--new-binary-filename', out_filename]) with open(out_filename, 'rb') as out_file, open('tests/test-files/test-storage-area.bin', 'rb') as storage_file: out = out_file.read() storage = storage_file.read()