From 772ae953f0fc10e4f411161edd984f09f5ede3cd Mon Sep 17 00:00:00 2001 From: "Brian S. Stephan" Date: Thu, 6 Jul 2023 16:07:06 -0500 Subject: [PATCH] add method to reboot a pico (in BOOTSEL) --- gp2040ce_bintools/pico.py | 60 +++++++++++++++++++++++++++++++ pyproject.toml | 2 +- requirements/requirements-dev.txt | 13 ++++--- requirements/requirements.txt | 8 +++-- 4 files changed, 74 insertions(+), 9 deletions(-) create mode 100644 gp2040ce_bintools/pico.py diff --git a/gp2040ce_bintools/pico.py b/gp2040ce_bintools/pico.py new file mode 100644 index 0000000..7f3a703 --- /dev/null +++ b/gp2040ce_bintools/pico.py @@ -0,0 +1,60 @@ +"""Methods to interact with the Raspberry Pi Pico directly. + +Much of this code is a partial Python implementation of picotool. +""" +import struct + +import usb.core + +PICO_VENDOR = 0x2e8a +PICO_PRODUCT = 0x0003 + +PICOBOOT_CMD_STRUCT = ' usb.core.Endpoint: + """Retrieve the USB endpoint for purposes of interacting with a Pico in BOOTSEL mode.""" + # get the device and claim it from whatever else might have in the kernel + pico_device = usb.core.find(idVendor=PICO_VENDOR, idProduct=PICO_PRODUCT) + + if not pico_device: + raise ValueError("Pico board in BOOTSEL mode could not be found!") + + if pico_device.is_kernel_driver_active(0): + pico_device.detach_kernel_driver(0) + + pico_configuration = pico_device.get_active_configuration() + # two interfaces are present, we want the direct rather than mass storage + # pico_bootsel_interface = pico_configuration[(1, 0)] + pico_bootsel_interface = usb.util.find_descriptor(pico_configuration, + custom_match=lambda e: e.bInterfaceClass == 0xff) + out_endpoint = usb.util.find_descriptor(pico_bootsel_interface, + custom_match=lambda e: (usb.util.endpoint_direction(e.bEndpointAddress) == + usb.util.ENDPOINT_OUT)) + return out_endpoint + + +def reboot() -> None: + """Reboot a Pico in BOOTSEL mode.""" + global PICO_TOKEN + endpoint = get_bootsel_out_endpoint() + + # set up the data + PICO_TOKEN += 1 + command_size = 12 + transfer_len = 0 + boot_start = 0 + boot_end = PICO_SRAM_END + boot_delay_ms = 500 + endpoint.write(struct.pack(PICOBOOT_CMD_STRUCT + PICOBOOT_CMD_REBOOT_SUFFIX_STRUCT, + PICO_MAGIC, PICO_TOKEN, PICO_COMMANDS['REBOOT'], command_size, transfer_len, + boot_start, boot_end, boot_delay_ms)) diff --git a/pyproject.toml b/pyproject.toml index 13aaa0f..4f01274 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,7 +11,7 @@ authors = [ {name = "Brian S. Stephan", email = "bss@incorporeal.org"}, ] requires-python = ">=3.9" -dependencies = ["grpcio-tools", "textual"] +dependencies = ["grpcio-tools", "pyusb", "textual"] dynamic = ["version"] classifiers = [ "Environment :: Console", diff --git a/requirements/requirements-dev.txt b/requirements/requirements-dev.txt index c7bb514..417bc9f 100644 --- a/requirements/requirements-dev.txt +++ b/requirements/requirements-dev.txt @@ -22,7 +22,7 @@ decorator==5.1.1 # via gp2040ce-binary-tools (pyproject.toml) distlib==0.3.6 # via virtualenv -exceptiongroup==1.1.1 +exceptiongroup==1.1.2 # via pytest filelock==3.12.2 # via @@ -71,7 +71,7 @@ isort==5.12.0 # via flake8-isort linkify-it-py==2.0.2 # via markdown-it-py -markdown-it-py[linkify,plugins]==2.2.0 +markdown-it-py[linkify,plugins]==3.0.0 # via # mdit-py-plugins # rich @@ -95,7 +95,7 @@ packaging==23.1 # tox pbr==5.11.1 # via stevedore -pip-tools==6.13.0 +pip-tools==6.14.0 # via gp2040ce-binary-tools (pyproject.toml) platformdirs==3.8.0 # via @@ -128,6 +128,8 @@ pytest-asyncio==0.21.0 # via gp2040ce-binary-tools (pyproject.toml) pytest-cov==4.1.0 # via gp2040ce-binary-tools (pyproject.toml) +pyusb==1.2.1 + # via gp2040ce-binary-tools (pyproject.toml) pyyaml==6.0 # via bandit rich==13.4.2 @@ -142,7 +144,7 @@ snowballstemmer==2.2.0 # via pydocstyle stevedore==5.1.0 # via bandit -textual==0.28.1 +textual==0.29.0 # via gp2040ce-binary-tools (pyproject.toml) tomli==2.0.1 # via @@ -150,6 +152,7 @@ tomli==2.0.1 # coverage # flake8-pyproject # mypy + # pip-tools # pyproject-api # pyproject-hooks # pytest @@ -157,7 +160,7 @@ tomli==2.0.1 # tox tox==4.6.3 # via gp2040ce-binary-tools (pyproject.toml) -typing-extensions==4.6.3 +typing-extensions==4.7.1 # via # mypy # setuptools-scm diff --git a/requirements/requirements.txt b/requirements/requirements.txt index b047097..53ae014 100644 --- a/requirements/requirements.txt +++ b/requirements/requirements.txt @@ -12,7 +12,7 @@ importlib-metadata==6.7.0 # via textual linkify-it-py==2.0.2 # via markdown-it-py -markdown-it-py[linkify,plugins]==2.2.0 +markdown-it-py[linkify,plugins]==3.0.0 # via # mdit-py-plugins # rich @@ -25,11 +25,13 @@ protobuf==4.23.3 # via grpcio-tools pygments==2.15.1 # via rich +pyusb==1.2.1 + # via gp2040ce-binary-tools (pyproject.toml) rich==13.4.2 # via textual -textual==0.28.1 +textual==0.29.0 # via gp2040ce-binary-tools (pyproject.toml) -typing-extensions==4.6.3 +typing-extensions==4.7.1 # via textual uc-micro-py==1.0.2 # via linkify-it-py