add flag to have concatenate write direct to USB

This commit is contained in:
Brian S. Stephan 2023-07-12 17:37:45 -05:00
parent fb1729a957
commit cce165f012
Signed by: bss
GPG Key ID: 3DE06D3180895FCB
4 changed files with 47 additions and 11 deletions

View File

@ -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 binary to flash many boards with a particular configuration (specific customizations, etc.), or keeping documented
backups of what you're testing with during development. 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: 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 ### dump-config

View File

@ -40,8 +40,9 @@ def combine_firmware_and_config(firmware_binary: bytearray, config_binary: bytea
pad_config_to_storage_size(config_binary)) pad_config_to_storage_size(config_binary))
def concatenate_firmware_and_storage_files(firmware_filename: str, storage_filename: str, combined_filename: str, def concatenate_firmware_and_storage_files(firmware_filename: str, storage_filename: str,
replace_extra: bool = False): 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. """Open the provided binary files and combine them into one combined GP2040-CE with config file.
Args: 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: 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()), new_binary = combine_firmware_and_config(bytearray(firmware.read()), bytearray(storage.read()),
replace_extra=replace_extra) replace_extra=replace_extra)
with open(combined_filename, 'wb') as combined: if combined_filename:
combined.write(new_binary) 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]: def get_gp2040ce_from_usb() -> tuple[bytes, object, object]:
@ -174,15 +179,18 @@ def concatenate():
"into one file suitable for flashing onto a board.", "into one file suitable for flashing onto a board.",
parents=[core_parser], 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', parser.add_argument('--replace-extra', action='store_true',
help="if the firmware file is larger than the location of storage, perhaps because it's " 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") "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() 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) replace_extra=args.replace_extra)

View File

@ -7,7 +7,8 @@ import pytest
from decorator import decorator from decorator import decorator
from gp2040ce_bintools import get_config_pb2 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, pad_firmware_up_to_storage, replace_config_in_binary,
write_new_config_to_filename, write_new_config_to_usb) 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 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'] 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): def test_padding_firmware(firmware_binary):
"""Test that firmware is padded to the expected size.""" """Test that firmware is padded to the expected size."""
padded = pad_firmware_up_to_storage(firmware_binary) padded = pad_firmware_up_to_storage(firmware_binary)

View File

@ -40,7 +40,7 @@ def test_concatenate_invocation(tmpdir):
"""Test that a normal invocation against a dump works.""" """Test that a normal invocation against a dump works."""
out_filename = os.path.join(tmpdir, 'out.bin') out_filename = os.path.join(tmpdir, 'out.bin')
_ = run(['concatenate', 'tests/test-files/test-firmware.bin', 'tests/test-files/test-storage-area.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: with open(out_filename, 'rb') as out_file, open('tests/test-files/test-storage-area.bin', 'rb') as storage_file:
out = out_file.read() out = out_file.read()
storage = storage_file.read() storage = storage_file.read()