diff --git a/gp2040ce_bintools/pico.py b/gp2040ce_bintools/pico.py index 6d86892..f9a2caa 100644 --- a/gp2040ce_bintools/pico.py +++ b/gp2040ce_bintools/pico.py @@ -32,6 +32,15 @@ PICO_COMMANDS = { } +################# +# LIBRARY ITEMS # +################# + + +class PicoAlignmentError(ValueError): + """Exception raised when the address provided for an operation is invalid.""" + + def get_bootsel_endpoints() -> tuple[usb.core.Endpoint, usb.core.Endpoint]: """Retrieve the USB endpoint for purposes of interacting with a Pico in BOOTSEL mode. @@ -189,6 +198,9 @@ def write(out_end: usb.core.Endpoint, in_end: usb.core.Endpoint, location: int, location: memory address of where to start reading from content: the data to write """ + if (location % 256) != 0: + raise PicoAlignmentError("writes must start at 256 byte boundaries, please pad or align as appropriate!") + # set up the data command_size = 8 diff --git a/tests/test_pico.py b/tests/test_pico.py index caf3b54..e55dccf 100644 --- a/tests/test_pico.py +++ b/tests/test_pico.py @@ -5,6 +5,7 @@ import sys import unittest.mock as mock from array import array +import pytest from decorator import decorator import gp2040ce_bintools.pico as pico @@ -144,3 +145,36 @@ def test_write(): ] end_out.write.assert_has_calls(expected_writes) assert end_in.read.call_count == 6 + + +def test_misaligned_write(): + """Test that we can't write to a board at invalid memory addresses.""" + end_out, end_in = mock.MagicMock(), mock.MagicMock() + with pytest.raises(pico.PicoAlignmentError): + _ = pico.write(end_out, end_in, 0x101FE001, b'\x00\x01\x02\x03') + with pytest.raises(pico.PicoAlignmentError): + _ = pico.write(end_out, end_in, 0x101FE008, b'\x00\x01\x02\x03') + with pytest.raises(pico.PicoAlignmentError): + _ = pico.write(end_out, end_in, 0x101FE010, b'\x00\x01\x02\x03') + with pytest.raises(pico.PicoAlignmentError): + _ = pico.write(end_out, end_in, 0x101FE020, b'\x00\x01\x02\x03') + with pytest.raises(pico.PicoAlignmentError): + _ = pico.write(end_out, end_in, 0x101FE040, b'\x00\x01\x02\x03') + with pytest.raises(pico.PicoAlignmentError): + _ = pico.write(end_out, end_in, 0x101FE080, b'\x00\x01\x02\x03') + with pytest.raises(pico.PicoAlignmentError): + _ = pico.write(end_out, end_in, 0x101FE0FF, b'\x00\x01\x02\x03') + + _ = pico.write(end_out, end_in, 0x101FE100, b'\x00\x01\x02\x03') + + expected_writes = [ + mock.call(struct.pack('