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
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

View File

@ -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)

View File

@ -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)

View File

@ -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()