flag and method to visualize the board config

via file dump or via USB. used to test the writing of the board config
to binary

Signed-off-by: Brian S. Stephan <bss@incorporeal.org>
This commit is contained in:
Brian S. Stephan 2024-01-06 16:55:23 -06:00
parent 1a44e8c1e3
commit 314fc909ff
Signed by: bss
GPG Key ID: 3DE06D3180895FCB
3 changed files with 51 additions and 4 deletions

View File

@ -17,6 +17,7 @@ from gp2040ce_bintools.rp2040 import get_bootsel_endpoints, read
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
BOARD_CONFIG_BINARY_LOCATION = 0x1F8000 BOARD_CONFIG_BINARY_LOCATION = 0x1F8000
BOARD_CONFIG_BOOTSEL_ADDRESS = 0x10000000 + BOARD_CONFIG_BINARY_LOCATION
STORAGE_SIZE = 16384 STORAGE_SIZE = 16384
USER_CONFIG_BINARY_LOCATION = 0x1FC000 USER_CONFIG_BINARY_LOCATION = 0x1FC000
USER_CONFIG_BOOTSEL_ADDRESS = 0x10000000 + USER_CONFIG_BINARY_LOCATION USER_CONFIG_BOOTSEL_ADDRESS = 0x10000000 + USER_CONFIG_BINARY_LOCATION
@ -124,13 +125,15 @@ def get_config_footer(content: bytes) -> tuple[int, int, str]:
return config_size, config_crc, config_magic return config_size, config_crc, config_magic
def get_config_from_file(filename: str, whole_board: bool = False, allow_no_file: bool = False) -> Message: def get_config_from_file(filename: str, whole_board: bool = False, allow_no_file: bool = False,
board_config: bool = False) -> Message:
"""Read the specified file (memory dump or whole board dump) and get back its config section. """Read the specified file (memory dump or whole board dump) and get back its config section.
Args: Args:
filename: the filename of the file to open and read filename: the filename of the file to open and read
whole_board: optional, if true, attempt to find the storage section from its normal location on a board whole_board: optional, if true, attempt to find the storage section from its normal location on a board
allow_no_file: if true, attempting to open a nonexistent file returns an empty config, else it errors allow_no_file: if true, attempting to open a nonexistent file returns an empty config, else it errors
board_config: if true, the board config is provided instead of the user config
Returns: Returns:
the parsed configuration the parsed configuration
""" """
@ -144,7 +147,10 @@ def get_config_from_file(filename: str, whole_board: bool = False, allow_no_file
return config_pb2.Config() return config_pb2.Config()
if whole_board: if whole_board:
return get_config(get_user_storage_section(content)) if board_config:
return get_config(get_board_storage_section(content))
else:
return get_config(get_user_storage_section(content))
else: else:
return get_config(content) return get_config(content)
@ -165,6 +171,15 @@ def get_config_from_usb(address: int) -> tuple[Message, object, object]:
return get_config(bytes(storage)), endpoint_out, endpoint_in return get_config(bytes(storage)), endpoint_out, endpoint_in
def get_board_config_from_usb() -> tuple[Message, object, object]:
"""Read the board configuration from the detected USB device.
Returns:
the parsed configuration, along with the USB out and in endpoints for reference
"""
return get_config_from_usb(BOARD_CONFIG_BOOTSEL_ADDRESS)
def get_user_config_from_usb() -> tuple[Message, object, object]: def get_user_config_from_usb() -> tuple[Message, object, object]:
"""Read the user configuration from the detected USB device. """Read the user configuration from the detected USB device.
@ -286,6 +301,8 @@ def visualize():
) )
parser.add_argument('--whole-board', action='store_true', help="indicate the binary file is a whole board dump") parser.add_argument('--whole-board', action='store_true', help="indicate the binary file is a whole board dump")
parser.add_argument('--json', action='store_true', help="print the config out as a JSON document") parser.add_argument('--json', action='store_true', help="print the config out as a JSON document")
parser.add_argument('--board-config', action='store_true', default=False,
help="display the board config rather than the user config")
group = parser.add_mutually_exclusive_group(required=True) group = parser.add_mutually_exclusive_group(required=True)
group.add_argument('--usb', action='store_true', help="retrieve the config from a RP2040 board connected over USB " group.add_argument('--usb', action='store_true', help="retrieve the config from a RP2040 board connected over USB "
"and in BOOTSEL mode") "and in BOOTSEL mode")
@ -295,9 +312,12 @@ def visualize():
args, _ = parser.parse_known_args() args, _ = parser.parse_known_args()
if args.usb: if args.usb:
config, _, _ = get_user_config_from_usb() if args.board_config:
config, _, _ = get_board_config_from_usb()
else:
config, _, _ = get_user_config_from_usb()
else: else:
config = get_config_from_file(args.filename, whole_board=args.whole_board) config = get_config_from_file(args.filename, whole_board=args.whole_board, board_config=args.board_config)
if args.json: if args.json:
print(MessageToJson(config)) print(MessageToJson(config))

View File

@ -94,6 +94,15 @@ def test_get_config_from_file_whole_board_dump():
assert config.addonOptions.bootselButtonOptions.enabled is False assert config.addonOptions.bootselButtonOptions.enabled is False
@with_pb2s
def test_get_board_config_from_file_whole_board_dump():
"""Test that we can open a storage dump file and find its config."""
filename = os.path.join(HERE, 'test-files', 'test-whole-board-with-board-config.bin')
config = storage.get_config_from_file(filename, whole_board=True, board_config=True)
assert config.boardVersion == 'v0.7.6-15-g71f4512'
assert config.addonOptions.bootselButtonOptions.enabled is False
@with_pb2s @with_pb2s
def test_get_config_from_file_file_not_fonud_ok(): def test_get_config_from_file_file_not_fonud_ok():
"""If we allow opening a file that doesn't exist (e.g. for the editor), check we get an empty config.""" """If we allow opening a file that doesn't exist (e.g. for the editor), check we get an empty config."""
@ -164,6 +173,24 @@ def test_pad_config_to_storage_raises(config_binary):
_ = storage.pad_config_to_storage_size(config_binary * 5) _ = storage.pad_config_to_storage_size(config_binary * 5)
@with_pb2s
def test_get_board_config_from_usb(config_binary):
"""Test we attempt to read from the proper location over USB."""
mock_out = mock.MagicMock()
mock_out.device.idVendor = 0xbeef
mock_out.device.idProduct = 0xcafe
mock_out.device.bus = 1
mock_out.device.address = 2
mock_in = mock.MagicMock()
with mock.patch('gp2040ce_bintools.storage.get_bootsel_endpoints', return_value=(mock_out, mock_in)) as mock_get:
with mock.patch('gp2040ce_bintools.storage.read', return_value=config_binary) as mock_read:
config, _, _ = storage.get_board_config_from_usb()
mock_get.assert_called_once()
mock_read.assert_called_with(mock_out, mock_in, 0x101F8000, 16384)
assert config == storage.get_config(config_binary)
@with_pb2s @with_pb2s
def test_get_user_config_from_usb(config_binary): def test_get_user_config_from_usb(config_binary):
"""Test we attempt to read from the proper location over USB.""" """Test we attempt to read from the proper location over USB."""