add a method to convert binary content to UF2
will be used in concatenate in order to write .uf2 files Signed-off-by: Brian S. Stephan <bss@incorporeal.org>
This commit is contained in:
parent
314fc909ff
commit
d6857d5da1
|
@ -6,6 +6,7 @@ SPDX-License-Identifier: MIT
|
|||
import argparse
|
||||
import copy
|
||||
import logging
|
||||
import struct
|
||||
from typing import Optional
|
||||
|
||||
from google.protobuf.message import Message
|
||||
|
@ -21,6 +22,11 @@ logger = logging.getLogger(__name__)
|
|||
GP2040CE_START_ADDRESS = 0x10000000
|
||||
GP2040CE_SIZE = 2 * 1024 * 1024
|
||||
|
||||
UF2_FAMILY_ID = 0xE48BFF56
|
||||
UF2_MAGIC_FIRST = 0x0A324655
|
||||
UF2_MAGIC_SECOND = 0x9E5D5157
|
||||
UF2_MAGIC_FINAL = 0x0AB16F30
|
||||
|
||||
|
||||
#################
|
||||
# LIBRARY ITEMS #
|
||||
|
@ -106,6 +112,38 @@ def concatenate_firmware_and_storage_files(firmware_filename: str,
|
|||
write(endpoint_out, endpoint_in, GP2040CE_START_ADDRESS, bytes(new_binary))
|
||||
|
||||
|
||||
def convert_binary_to_uf2(binary: 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
|
||||
Returns:
|
||||
the content in UF2 format
|
||||
"""
|
||||
size = len(binary)
|
||||
blocks = (len(binary) // 256) + 1 if len(binary) % 256 else len(binary) // 256
|
||||
uf2 = bytearray()
|
||||
|
||||
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 + 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
|
||||
return uf2
|
||||
|
||||
|
||||
def get_gp2040ce_from_usb() -> tuple[bytes, object, object]:
|
||||
"""Read the firmware + config sections from a USB device.
|
||||
|
||||
|
|
|
@ -52,9 +52,22 @@ def storage_dump():
|
|||
|
||||
@pytest.fixture
|
||||
def whole_board_dump():
|
||||
"""Read in a test whole board dump file of a GP2040-CE board."""
|
||||
"""Read in a test whole board dump file of a GP2040-CE board.
|
||||
|
||||
NOTE: this is from a 16 MB flash because I used an ABB for this test.
|
||||
"""
|
||||
filename = os.path.join(HERE, 'test-files', 'test-whole-board.bin')
|
||||
with open(filename, 'rb') as file:
|
||||
content = file.read()
|
||||
|
||||
yield content
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def whole_board_with_board_config_dump():
|
||||
"""Read in a test whole board dump file of a GP2040-CE board plus board config."""
|
||||
filename = os.path.join(HERE, 'test-files', 'test-whole-board-with-board-config.bin')
|
||||
with open(filename, 'rb') as file:
|
||||
content = file.read()
|
||||
|
||||
yield content
|
||||
|
|
|
@ -12,9 +12,10 @@ from decorator import decorator
|
|||
|
||||
from gp2040ce_bintools import get_config_pb2
|
||||
from gp2040ce_bintools.builder import (FirmwareLengthError, combine_firmware_and_config,
|
||||
concatenate_firmware_and_storage_files, get_gp2040ce_from_usb,
|
||||
pad_binary_up_to_board_config, pad_binary_up_to_user_config,
|
||||
replace_config_in_binary, write_new_config_to_filename, write_new_config_to_usb)
|
||||
concatenate_firmware_and_storage_files, convert_binary_to_uf2,
|
||||
get_gp2040ce_from_usb, pad_binary_up_to_board_config,
|
||||
pad_binary_up_to_user_config, replace_config_in_binary,
|
||||
write_new_config_to_filename, write_new_config_to_usb)
|
||||
from gp2040ce_bintools.storage import (get_board_storage_section, get_config, get_config_footer,
|
||||
get_user_storage_section, serialize_config_with_footer)
|
||||
|
||||
|
@ -75,6 +76,15 @@ def test_concatenate_both_configs_to_file(tmp_path):
|
|||
assert footer_size == 3309
|
||||
|
||||
|
||||
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 = convert_binary_to_uf2(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
|
||||
assert uf2[524:528] == bytearray(b'\x00\x01\x00\x10') # address to write the second chunk
|
||||
|
||||
|
||||
@with_pb2s
|
||||
def test_concatenate_user_json_to_file(tmp_path):
|
||||
"""Test that we write a file with firmware + JSON user config as expected."""
|
||||
|
|
Loading…
Reference in New Issue