Compare commits
2 Commits
ea4d4be709
...
e133abc922
Author | SHA1 | Date |
---|---|---|
Brian S. Stephan | e133abc922 | |
Brian S. Stephan | 2bb049c442 |
|
@ -101,25 +101,15 @@ def concatenate_firmware_and_storage_files(firmware_filename: str,
|
|||
new_binary = combine_firmware_and_config(firmware_binary, board_config_binary, user_config_binary,
|
||||
replace_extra=replace_extra)
|
||||
else:
|
||||
# this was kind of fine, but combining multiple calls of convert_binary_to_uf2 produced
|
||||
# incorrect total block counts in the file, which picotool handled with some squirrely
|
||||
# double-output behavior that has me worried it'd cause a real issue, so doing the
|
||||
# crude padding + write of empty blocks, for now...
|
||||
#
|
||||
# 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)
|
||||
#
|
||||
# the correct way to do the above would be to pass a list of {offset,binary_data} to convert...,
|
||||
# and have it calculate the total block size before starting to write, and then iterating over
|
||||
# the three lists. doable, just not on the top of my mind right now
|
||||
new_binary = storage.convert_binary_to_uf2(combine_firmware_and_config(firmware_binary, board_config_binary,
|
||||
user_config_binary,
|
||||
replace_extra=replace_extra))
|
||||
binary_list = [(0, firmware_binary)]
|
||||
# we must pad to storage start in order for the UF2 write addresses to make sense
|
||||
if board_config_binary:
|
||||
binary_list.append((storage.BOARD_CONFIG_BINARY_LOCATION,
|
||||
storage.pad_config_to_storage_size(board_config_binary)))
|
||||
if user_config_binary:
|
||||
binary_list.append((storage.USER_CONFIG_BINARY_LOCATION,
|
||||
storage.pad_config_to_storage_size(user_config_binary)))
|
||||
new_binary = storage.convert_binary_to_uf2(binary_list)
|
||||
|
||||
if combined_filename:
|
||||
with open(combined_filename, 'wb') as combined:
|
||||
|
@ -256,8 +246,10 @@ def write_new_config_to_filename(config: Message, filename: str, inject: bool =
|
|||
binary = storage.serialize_config_with_footer(config)
|
||||
with open(filename, 'wb') as file:
|
||||
if filename[-4:] == '.uf2':
|
||||
file.write(storage.convert_binary_to_uf2(storage.pad_config_to_storage_size(binary),
|
||||
start=storage.USER_CONFIG_BINARY_LOCATION))
|
||||
# we must pad to storage start in order for the UF2 write addresses to make sense
|
||||
file.write(storage.convert_binary_to_uf2([
|
||||
(storage.USER_CONFIG_BINARY_LOCATION, storage.pad_config_to_storage_size(binary)),
|
||||
]))
|
||||
else:
|
||||
file.write(binary)
|
||||
|
||||
|
|
|
@ -53,36 +53,37 @@ class ConfigMagicError(ConfigReadError):
|
|||
"""Exception raised when the config section does not have the magic value in its footer."""
|
||||
|
||||
|
||||
def convert_binary_to_uf2(binary: bytearray, start: int = 0) -> bytearray:
|
||||
def convert_binary_to_uf2(binaries: list[tuple[int, bytearray]]) -> bytearray:
|
||||
"""Convert a GP2040-CE binary payload to Microsoft's UF2 format.
|
||||
|
||||
https://github.com/microsoft/uf2/tree/master#overview
|
||||
|
||||
Args:
|
||||
binary: bytearray content to convert to a UF2 payload
|
||||
start: position offset to start at rather than flash start (for creating e.g. user config UF2s)
|
||||
binaries: list of start,binary pairs of binary data to write at the specified memory offset in flash
|
||||
Returns:
|
||||
the content in UF2 format
|
||||
"""
|
||||
size = len(binary)
|
||||
blocks = (len(binary) // 256) + 1 if len(binary) % 256 else len(binary) // 256
|
||||
uf2 = bytearray()
|
||||
total_blocks = sum([(len(binary) // 256) + 1 if len(binary) % 256 else len(binary) // 256
|
||||
for offset, binary in binaries])
|
||||
|
||||
index = 0
|
||||
while index < size:
|
||||
pad_count = 476 - len(binary[index:index+256])
|
||||
uf2 += struct.pack('<LLLLLLLL',
|
||||
UF2_MAGIC_FIRST, # first magic number
|
||||
UF2_MAGIC_SECOND, # second magic number
|
||||
0x00002000, # familyID present
|
||||
0x10000000 + start + index, # address to write to
|
||||
256, # bytes to write in this block
|
||||
index // 256, # sequential block number
|
||||
blocks, # total number of blocks
|
||||
UF2_FAMILY_ID) # family ID
|
||||
uf2 += binary[index:index+256] + bytearray(b'\x00' * pad_count) # content
|
||||
uf2 += struct.pack('<L', UF2_MAGIC_FINAL) # final magic number
|
||||
index += 256
|
||||
uf2 = bytearray()
|
||||
for start, binary in binaries:
|
||||
size = len(binary)
|
||||
index = 0
|
||||
while index < size:
|
||||
pad_count = 476 - len(binary[index:index+256])
|
||||
uf2 += struct.pack('<LLLLLLLL',
|
||||
UF2_MAGIC_FIRST, # first magic number
|
||||
UF2_MAGIC_SECOND, # second magic number
|
||||
0x00002000, # familyID present
|
||||
0x10000000 + start + index, # address to write to
|
||||
256, # bytes to write in this block
|
||||
index // 256, # sequential block number
|
||||
total_blocks, # total number of blocks
|
||||
UF2_FAMILY_ID) # family ID
|
||||
uf2 += binary[index:index+256] + bytearray(b'\x00' * pad_count) # content
|
||||
uf2 += struct.pack('<L', UF2_MAGIC_FINAL) # final magic number
|
||||
index += 256
|
||||
return uf2
|
||||
|
||||
|
||||
|
@ -393,8 +394,9 @@ def dump_config():
|
|||
with open(args.filename, 'wb') as out_file:
|
||||
if args.filename[-4:] == '.uf2':
|
||||
# we must pad to storage start in order for the UF2 write addresses to make sense
|
||||
out_file.write(convert_binary_to_uf2(pad_config_to_storage_size(binary_config),
|
||||
start=USER_CONFIG_BINARY_LOCATION))
|
||||
out_file.write(convert_binary_to_uf2([
|
||||
(USER_CONFIG_BINARY_LOCATION, pad_config_to_storage_size(binary_config)),
|
||||
]))
|
||||
else:
|
||||
out_file.write(binary_config)
|
||||
|
||||
|
|
|
@ -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
|
||||
|
@ -117,8 +118,9 @@ def test_concatenate_to_uf2(tmp_path, firmware_binary, config_binary):
|
|||
combined_filename=tmp_file)
|
||||
with open(tmp_file, 'rb') as file:
|
||||
content = file.read()
|
||||
# size of the file should be 2x the binary version, and the binary is 2 MB
|
||||
assert len(content) == 2 * 2 * 1024 * 1024
|
||||
# size of the file should be 2x the padded firmware + 2x the board config space + 2x the user config space
|
||||
assert len(content) == (math.ceil(len(firmware_binary)/256) * 512 +
|
||||
math.ceil(STORAGE_SIZE/256) * 512 * 2)
|
||||
|
||||
|
||||
def test_concatenate_to_uf2_board_only(tmp_path, firmware_binary, config_binary):
|
||||
|
@ -130,8 +132,9 @@ def test_concatenate_to_uf2_board_only(tmp_path, firmware_binary, config_binary)
|
|||
combined_filename=tmp_file)
|
||||
with open(tmp_file, 'rb') as file:
|
||||
content = file.read()
|
||||
# size of the file should be 2x the binary version (minus user config space), and the binary is 2 MB - 16KB
|
||||
assert len(content) == 2 * (2 * 1024 * 1024 - 16384)
|
||||
# size of the file should be 2x the padded firmware + 2x the board config space
|
||||
assert len(content) == (math.ceil(len(firmware_binary)/256) * 512 +
|
||||
math.ceil(STORAGE_SIZE/256) * 512)
|
||||
|
||||
|
||||
def test_find_version_string(firmware_binary):
|
||||
|
|
|
@ -133,7 +133,7 @@ def test_config_from_whole_board_parses(whole_board_dump):
|
|||
|
||||
def test_convert_binary_to_uf2(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)
|
||||
uf2 = storage.convert_binary_to_uf2([{0, whole_board_with_board_config_dump}])
|
||||
assert len(uf2) == 4194304 # binary is 8192 256 byte chunks, UF2 is 512 b per chunk
|
||||
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
|
||||
|
@ -142,7 +142,7 @@ def test_convert_binary_to_uf2(whole_board_with_board_config_dump):
|
|||
|
||||
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)
|
||||
uf2 = storage.convert_binary_to_uf2([{0, 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
|
||||
|
@ -151,7 +151,7 @@ def test_convert_unaligned_binary_to_uf2(firmware_binary):
|
|||
|
||||
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)
|
||||
uf2 = storage.convert_binary_to_uf2([{storage.USER_CONFIG_BINARY_LOCATION, whole_board_with_board_config_dump}])
|
||||
assert len(uf2) == 4194304 # binary is 8192 256 byte chunks, UF2 is 512 b per chunk
|
||||
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
|
||||
|
@ -160,7 +160,7 @@ def test_convert_binary_to_uf2_with_offsets(whole_board_with_board_config_dump):
|
|||
|
||||
def test_convert_binary_to_uf2_to_binary(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)
|
||||
uf2 = storage.convert_binary_to_uf2([{0, whole_board_with_board_config_dump}])
|
||||
binary = storage.convert_uf2_to_binary(uf2)
|
||||
assert len(binary) == 2097152
|
||||
assert whole_board_with_board_config_dump == binary
|
||||
|
@ -168,7 +168,7 @@ def test_convert_binary_to_uf2_to_binary(whole_board_with_board_config_dump):
|
|||
|
||||
def test_malformed_uf2(whole_board_with_board_config_dump):
|
||||
"""Check that we expect a properly-formed UF2."""
|
||||
uf2 = storage.convert_binary_to_uf2(whole_board_with_board_config_dump)
|
||||
uf2 = storage.convert_binary_to_uf2([{0, whole_board_with_board_config_dump}])
|
||||
|
||||
# truncated UF2 --- byte mismatch
|
||||
with pytest.raises(ValueError):
|
||||
|
|
Loading…
Reference in New Issue