From 564fda7313f92e7d3cbb9854a7eafa4950376522 Mon Sep 17 00:00:00 2001 From: William Vinnicombe Date: Tue, 14 Jul 2026 18:55:01 +0100 Subject: [PATCH 01/12] Add picotool help topics Move device selection options into a separate picotool help device-selection command, rather than appearing in every help output Also add a family-ids topic to list available family IDs (fixes #305) --- README.md | 613 +++--------------------------------------------------- cli.h | 12 ++ main.cpp | 117 ++++++++--- 3 files changed, 127 insertions(+), 615 deletions(-) diff --git a/README.md b/README.md index d3ec328f..00e273bc 100644 --- a/README.md +++ b/README.md @@ -65,6 +65,10 @@ COMMANDS: link Link multiple binaries into one block loop. bdev Commands related to embedded block devices +TOPICS: + device-selection Options for Target Device Selection + family-ids Valid Family IDs + Use "picotool help " for more info ``` @@ -117,34 +121,7 @@ OPTIONS: TARGET SELECTION: To target one or more connected RP-series device(s) in BOOTSEL mode (the default) - --bus - Filter devices by USB bus number - --address - Filter devices by USB device address - --vid - Filter by vendor id - --pid - Filter by product id - --ser - Filter by serial number - --rp2040 - Assume the device is an RP2040 - this is only required when using a custom vid/pid - with an RP2040 on Windows, and is ignored on other operating systems - -f, --force - Force a device not in BOOTSEL mode but running compatible code to reset so the - command can be executed. After executing the command (unless the command itself is - a 'reboot') the device will be rebooted back to application mode - -F, --force-no-reboot - Force a device not in BOOTSEL mode but running compatible code to reset so the - command can be executed. After executing the command (unless the command itself is - a 'reboot') the device will be left connected and accessible to picotool, but - without the USB drive mounted - --bootsel-led - Specify the GPIO for the BOOTSEL activity LED to flash (default none, ignored by - RP2350A-A2 in Arm mode) - only applicable if this command reboots the device to - BOOTSEL mode - --bootsel-led-active-low - The BOOTSEL activity LED is active low (ignored by RP2040 and RP2350-A4) + See "picotool help device-selection" for available options To target a file The file name @@ -234,34 +211,7 @@ OPTIONS: TARGET SELECTION: To target one or more connected RP-series device(s) in BOOTSEL mode (the default) - --bus - Filter devices by USB bus number - --address - Filter devices by USB device address - --vid - Filter by vendor id - --pid - Filter by product id - --ser - Filter by serial number - --rp2040 - Assume the device is an RP2040 - this is only required when using a custom vid/pid - with an RP2040 on Windows, and is ignored on other operating systems - -f, --force - Force a device not in BOOTSEL mode but running compatible code to reset so the - command can be executed. After executing the command (unless the command itself is - a 'reboot') the device will be rebooted back to application mode - -F, --force-no-reboot - Force a device not in BOOTSEL mode but running compatible code to reset so the - command can be executed. After executing the command (unless the command itself is - a 'reboot') the device will be left connected and accessible to picotool, but - without the USB drive mounted - --bootsel-led - Specify the GPIO for the BOOTSEL activity LED to flash (default none, ignored by - RP2350A-A2 in Arm mode) - only applicable if this command reboots the device to - BOOTSEL mode - --bootsel-led-active-low - The BOOTSEL activity LED is active low (ignored by RP2040 and RP2350-A4) + See "picotool help device-selection" for available options To target a file The file name @@ -349,34 +299,7 @@ OPTIONS: Load offset (memory address; default 0x10000000) Target device selection - --bus - Filter devices by USB bus number - --address - Filter devices by USB device address - --vid - Filter by vendor id - --pid - Filter by product id - --ser - Filter by serial number - --rp2040 - Assume the device is an RP2040 - this is only required when using a custom vid/pid - with an RP2040 on Windows, and is ignored on other operating systems - -f, --force - Force a device not in BOOTSEL mode but running compatible code to reset so the - command can be executed. After executing the command (unless the command itself is - a 'reboot') the device will be rebooted back to application mode - -F, --force-no-reboot - Force a device not in BOOTSEL mode but running compatible code to reset so the - command can be executed. After executing the command (unless the command itself is - a 'reboot') the device will be left connected and accessible to picotool, but - without the USB drive mounted - --bootsel-led - Specify the GPIO for the BOOTSEL activity LED to flash (default none, ignored by - RP2350A-A2 in Arm mode) - only applicable if this command reboots the device to - BOOTSEL mode - --bootsel-led-active-low - The BOOTSEL activity LED is active low (ignored by RP2040 and RP2350-A4) + See "picotool help device-selection" for available options ``` e.g. @@ -427,34 +350,7 @@ OPTIONS: -t Specify file type (uf2 | elf | bin) explicitly, ignoring file extension Source device selection - --bus - Filter devices by USB bus number - --address - Filter devices by USB device address - --vid - Filter by vendor id - --pid - Filter by product id - --ser - Filter by serial number - --rp2040 - Assume the device is an RP2040 - this is only required when using a custom vid/pid - with an RP2040 on Windows, and is ignored on other operating systems - -f, --force - Force a device not in BOOTSEL mode but running compatible code to reset so the - command can be executed. After executing the command (unless the command itself is - a 'reboot') the device will be rebooted back to application mode - -F, --force-no-reboot - Force a device not in BOOTSEL mode but running compatible code to reset so the - command can be executed. After executing the command (unless the command itself is - a 'reboot') the device will be left connected and accessible to picotool, but - without the USB drive mounted - --bootsel-led - Specify the GPIO for the BOOTSEL activity LED to flash (default none, ignored by - RP2350A-A2 in Arm mode) - only applicable if this command reboots the device to - BOOTSEL mode - --bootsel-led-active-low - The BOOTSEL activity LED is active low (ignored by RP2040 and RP2350-A4) + See "picotool help device-selection" for available options ``` e.g. first looking at what is on the device... @@ -512,34 +408,7 @@ OPTIONS: Load offset (memory address; default 0x10000000) Target device selection - --bus - Filter devices by USB bus number - --address - Filter devices by USB device address - --vid - Filter by vendor id - --pid - Filter by product id - --ser - Filter by serial number - --rp2040 - Assume the device is an RP2040 - this is only required when using a custom vid/pid - with an RP2040 on Windows, and is ignored on other operating systems - -f, --force - Force a device not in BOOTSEL mode but running compatible code to reset so the - command can be executed. After executing the command (unless the command itself is - a 'reboot') the device will be rebooted back to application mode - -F, --force-no-reboot - Force a device not in BOOTSEL mode but running compatible code to reset so the - command can be executed. After executing the command (unless the command itself is - a 'reboot') the device will be left connected and accessible to picotool, but - without the USB drive mounted - --bootsel-led - Specify the GPIO for the BOOTSEL activity LED to flash (default none, ignored by - RP2350A-A2 in Arm mode) - only applicable if this command reboots the device to - BOOTSEL mode - --bootsel-led-active-low - The BOOTSEL activity LED is active low (ignored by RP2040 and RP2350-A4) + See "picotool help device-selection" for available options ``` ## erase @@ -573,34 +442,7 @@ OPTIONS: The upper address bound in hex Source device selection - --bus - Filter devices by USB bus number - --address - Filter devices by USB device address - --vid - Filter by vendor id - --pid - Filter by product id - --ser - Filter by serial number - --rp2040 - Assume the device is an RP2040 - this is only required when using a custom vid/pid - with an RP2040 on Windows, and is ignored on other operating systems - -f, --force - Force a device not in BOOTSEL mode but running compatible code to reset so the - command can be executed. After executing the command (unless the command itself is - a 'reboot') the device will be rebooted back to application mode - -F, --force-no-reboot - Force a device not in BOOTSEL mode but running compatible code to reset so the - command can be executed. After executing the command (unless the command itself is - a 'reboot') the device will be left connected and accessible to picotool, but - without the USB drive mounted - --bootsel-led - Specify the GPIO for the BOOTSEL activity LED to flash (default none, ignored by - RP2350A-A2 in Arm mode) - only applicable if this command reboots the device to - BOOTSEL mode - --bootsel-led-active-low - The BOOTSEL activity LED is active low (ignored by RP2040 and RP2350-A4) + See "picotool help device-selection" for available options ``` e.g. first looking at what is on the device... @@ -666,34 +508,7 @@ OPTIONS: -c Select arm | riscv CPU (if possible) Selecting the device to reboot - --bus - Filter devices by USB bus number - --address - Filter devices by USB device address - --vid - Filter by vendor id - --pid - Filter by product id - --ser - Filter by serial number - --rp2040 - Assume the device is an RP2040 - this is only required when using a custom vid/pid - with an RP2040 on Windows, and is ignored on other operating systems - -f, --force - Force a device not in BOOTSEL mode but running compatible code to reset so the - command can be executed. After executing the command (unless the command itself is - a 'reboot') the device will be rebooted back to application mode - -F, --force-no-reboot - Force a device not in BOOTSEL mode but running compatible code to reset so the - command can be executed. After executing the command (unless the command itself is - a 'reboot') the device will be left connected and accessible to picotool, but - without the USB drive mounted - --bootsel-led - Specify the GPIO for the BOOTSEL activity LED to flash (default none, ignored by - RP2350A-A2 in Arm mode) - only applicable if this command reboots the device to - BOOTSEL mode - --bootsel-led-active-low - The BOOTSEL activity LED is active low (ignored by RP2040 and RP2350-A4) + See "picotool help device-selection" for available options ``` ## seal @@ -861,34 +676,7 @@ OPTIONS: -m family ID (will show target partition for said family) Target device selection - --bus - Filter devices by USB bus number - --address - Filter devices by USB device address - --vid - Filter by vendor id - --pid - Filter by product id - --ser - Filter by serial number - --rp2040 - Assume the device is an RP2040 - this is only required when using a custom vid/pid - with an RP2040 on Windows, and is ignored on other operating systems - -f, --force - Force a device not in BOOTSEL mode but running compatible code to reset so the - command can be executed. After executing the command (unless the command itself is - a 'reboot') the device will be rebooted back to application mode - -F, --force-no-reboot - Force a device not in BOOTSEL mode but running compatible code to reset so the - command can be executed. After executing the command (unless the command itself is - a 'reboot') the device will be left connected and accessible to picotool, but - without the USB drive mounted - --bootsel-led - Specify the GPIO for the BOOTSEL activity LED to flash (default none, ignored by - RP2350A-A2 in Arm mode) - only applicable if this command reboots the device to - BOOTSEL mode - --bootsel-led-active-low - The BOOTSEL activity LED is active low (ignored by RP2040 and RP2350-A4) + See "picotool help device-selection" for available options ``` ```text @@ -1136,34 +924,7 @@ SYNOPSIS: OPTIONS: Target device selection - --bus - Filter devices by USB bus number - --address - Filter devices by USB device address - --vid - Filter by vendor id - --pid - Filter by product id - --ser - Filter by serial number - --rp2040 - Assume the device is an RP2040 - this is only required when using a custom vid/pid - with an RP2040 on Windows, and is ignored on other operating systems - -f, --force - Force a device not in BOOTSEL mode but running compatible code to reset so the - command can be executed. After executing the command (unless the command itself is - a 'reboot') the device will be rebooted back to application mode - -F, --force-no-reboot - Force a device not in BOOTSEL mode but running compatible code to reset so the - command can be executed. After executing the command (unless the command itself is - a 'reboot') the device will be left connected and accessible to picotool, but - without the USB drive mounted - --bootsel-led - Specify the GPIO for the BOOTSEL activity LED to flash (default none, ignored by - RP2350A-A2 in Arm mode) - only applicable if this command reboots the device to - BOOTSEL mode - --bootsel-led-active-low - The BOOTSEL activity LED is active low (ignored by RP2040 and RP2350-A4) + See "picotool help device-selection" for available options ``` ## otp @@ -1252,34 +1013,7 @@ OPTIONS: TARGET SELECTION: Target device selection - --bus - Filter devices by USB bus number - --address - Filter devices by USB device address - --vid - Filter by vendor id - --pid - Filter by product id - --ser - Filter by serial number - --rp2040 - Assume the device is an RP2040 - this is only required when using a custom vid/pid - with an RP2040 on Windows, and is ignored on other operating systems - -f, --force - Force a device not in BOOTSEL mode but running compatible code to reset so the - command can be executed. After executing the command (unless the command itself is - a 'reboot') the device will be rebooted back to application mode - -F, --force-no-reboot - Force a device not in BOOTSEL mode but running compatible code to reset so the - command can be executed. After executing the command (unless the command itself is - a 'reboot') the device will be left connected and accessible to picotool, but - without the USB drive mounted - --bootsel-led - Specify the GPIO for the BOOTSEL activity LED to flash (default none, ignored by - RP2350A-A2 in Arm mode) - only applicable if this command reboots the device to - BOOTSEL mode - --bootsel-led-active-low - The BOOTSEL activity LED is active low (ignored by RP2040 and RP2350-A4) + See "picotool help device-selection" for available options ``` ```text @@ -1325,34 +1059,7 @@ OPTIONS: TARGET SELECTION: Target device selection - --bus - Filter devices by USB bus number - --address - Filter devices by USB device address - --vid - Filter by vendor id - --pid - Filter by product id - --ser - Filter by serial number - --rp2040 - Assume the device is an RP2040 - this is only required when using a custom vid/pid - with an RP2040 on Windows, and is ignored on other operating systems - -f, --force - Force a device not in BOOTSEL mode but running compatible code to reset so the - command can be executed. After executing the command (unless the command itself is - a 'reboot') the device will be rebooted back to application mode - -F, --force-no-reboot - Force a device not in BOOTSEL mode but running compatible code to reset so the - command can be executed. After executing the command (unless the command itself is - a 'reboot') the device will be left connected and accessible to picotool, but - without the USB drive mounted - --bootsel-led - Specify the GPIO for the BOOTSEL activity LED to flash (default none, ignored by - RP2350A-A2 in Arm mode) - only applicable if this command reboots the device to - BOOTSEL mode - --bootsel-led-active-low - The BOOTSEL activity LED is active low (ignored by RP2040 and RP2350-A4) + See "picotool help device-selection" for available options ``` ### load @@ -1385,34 +1092,7 @@ OPTIONS: -t Specify file type (json | bin) explicitly, ignoring file extension Target device selection - --bus - Filter devices by USB bus number - --address - Filter devices by USB device address - --vid - Filter by vendor id - --pid - Filter by product id - --ser - Filter by serial number - --rp2040 - Assume the device is an RP2040 - this is only required when using a custom vid/pid - with an RP2040 on Windows, and is ignored on other operating systems - -f, --force - Force a device not in BOOTSEL mode but running compatible code to reset so the - command can be executed. After executing the command (unless the command itself is - a 'reboot') the device will be rebooted back to application mode - -F, --force-no-reboot - Force a device not in BOOTSEL mode but running compatible code to reset so the - command can be executed. After executing the command (unless the command itself is - a 'reboot') the device will be left connected and accessible to picotool, but - without the USB drive mounted - --bootsel-led - Specify the GPIO for the BOOTSEL activity LED to flash (default none, ignored by - RP2350A-A2 in Arm mode) - only applicable if this command reboots the device to - BOOTSEL mode - --bootsel-led-active-low - The BOOTSEL activity LED is active low (ignored by RP2040 and RP2350-A4) + See "picotool help device-selection" for available options ``` For example, if you wish to sign a binary and then test secure boot with it, you can run the following set of commands: @@ -1440,34 +1120,7 @@ OPTIONS: JSON file with white labelling values Target device selection - --bus - Filter devices by USB bus number - --address - Filter devices by USB device address - --vid - Filter by vendor id - --pid - Filter by product id - --ser - Filter by serial number - --rp2040 - Assume the device is an RP2040 - this is only required when using a custom vid/pid - with an RP2040 on Windows, and is ignored on other operating systems - -f, --force - Force a device not in BOOTSEL mode but running compatible code to reset so the - command can be executed. After executing the command (unless the command itself is - a 'reboot') the device will be rebooted back to application mode - -F, --force-no-reboot - Force a device not in BOOTSEL mode but running compatible code to reset so the - command can be executed. After executing the command (unless the command itself is - a 'reboot') the device will be left connected and accessible to picotool, but - without the USB drive mounted - --bootsel-led - Specify the GPIO for the BOOTSEL activity LED to flash (default none, ignored by - RP2350A-A2 in Arm mode) - only applicable if this command reboots the device to - BOOTSEL mode - --bootsel-led-active-low - The BOOTSEL activity LED is active low (ignored by RP2040 and RP2350-A4) + See "picotool help device-selection" for available options ``` ```text @@ -1537,34 +1190,7 @@ OPTIONS: Key file (.pem) Target device selection - --bus - Filter devices by USB bus number - --address - Filter devices by USB device address - --vid - Filter by vendor id - --pid - Filter by product id - --ser - Filter by serial number - --rp2040 - Assume the device is an RP2040 - this is only required when using a custom vid/pid - with an RP2040 on Windows, and is ignored on other operating systems - -f, --force - Force a device not in BOOTSEL mode but running compatible code to reset so the - command can be executed. After executing the command (unless the command itself is - a 'reboot') the device will be rebooted back to application mode - -F, --force-no-reboot - Force a device not in BOOTSEL mode but running compatible code to reset so the - command can be executed. After executing the command (unless the command itself is - a 'reboot') the device will be left connected and accessible to picotool, but - without the USB drive mounted - --bootsel-led - Specify the GPIO for the BOOTSEL activity LED to flash (default none, ignored by - RP2350A-A2 in Arm mode) - only applicable if this command reboots the device to - BOOTSEL mode - --bootsel-led-active-low - The BOOTSEL activity LED is active low (ignored by RP2040 and RP2350-A4) + See "picotool help device-selection" for available options ``` ```text @@ -1613,34 +1239,7 @@ OPTIONS: TARGET SELECTION: To dump the contents of a target device - --bus - Filter devices by USB bus number - --address - Filter devices by USB device address - --vid - Filter by vendor id - --pid - Filter by product id - --ser - Filter by serial number - --rp2040 - Assume the device is an RP2040 - this is only required when using a custom vid/pid - with an RP2040 on Windows, and is ignored on other operating systems - -f, --force - Force a device not in BOOTSEL mode but running compatible code to reset so the - command can be executed. After executing the command (unless the command itself is - a 'reboot') the device will be rebooted back to application mode - -F, --force-no-reboot - Force a device not in BOOTSEL mode but running compatible code to reset so the - command can be executed. After executing the command (unless the command itself is - a 'reboot') the device will be left connected and accessible to picotool, but - without the USB drive mounted - --bootsel-led - Specify the GPIO for the BOOTSEL activity LED to flash (default none, ignored by - RP2350A-A2 in Arm mode) - only applicable if this command reboots the device to - BOOTSEL mode - --bootsel-led-active-low - The BOOTSEL activity LED is active low (ignored by RP2040 and RP2350-A4) + See "picotool help device-selection" for available options To dump the contents of an OTP JSON file The file name @@ -1829,34 +1428,7 @@ OPTIONS: --format Format the drive if necessary (may result in data loss) Target device selection - --bus - Filter devices by USB bus number - --address - Filter devices by USB device address - --vid - Filter by vendor id - --pid - Filter by product id - --ser - Filter by serial number - --rp2040 - Assume the device is an RP2040 - this is only required when using a custom vid/pid - with an RP2040 on Windows, and is ignored on other operating systems - -f, --force - Force a device not in BOOTSEL mode but running compatible code to reset so the - command can be executed. After executing the command (unless the command itself is - a 'reboot') the device will be rebooted back to application mode - -F, --force-no-reboot - Force a device not in BOOTSEL mode but running compatible code to reset so the - command can be executed. After executing the command (unless the command itself is - a 'reboot') the device will be left connected and accessible to picotool, but - without the USB drive mounted - --bootsel-led - Specify the GPIO for the BOOTSEL activity LED to flash (default none, ignored by - RP2350A-A2 in Arm mode) - only applicable if this command reboots the device to - BOOTSEL mode - --bootsel-led-active-low - The BOOTSEL activity LED is active low (ignored by RP2040 and RP2350-A4) + See "picotool help device-selection" for available options ``` ### mkdir @@ -1900,34 +1472,7 @@ OPTIONS: --format Format the drive if necessary (may result in data loss) Target device selection - --bus - Filter devices by USB bus number - --address - Filter devices by USB device address - --vid - Filter by vendor id - --pid - Filter by product id - --ser - Filter by serial number - --rp2040 - Assume the device is an RP2040 - this is only required when using a custom vid/pid - with an RP2040 on Windows, and is ignored on other operating systems - -f, --force - Force a device not in BOOTSEL mode but running compatible code to reset so the - command can be executed. After executing the command (unless the command itself is - a 'reboot') the device will be rebooted back to application mode - -F, --force-no-reboot - Force a device not in BOOTSEL mode but running compatible code to reset so the - command can be executed. After executing the command (unless the command itself is - a 'reboot') the device will be left connected and accessible to picotool, but - without the USB drive mounted - --bootsel-led - Specify the GPIO for the BOOTSEL activity LED to flash (default none, ignored by - RP2350A-A2 in Arm mode) - only applicable if this command reboots the device to - BOOTSEL mode - --bootsel-led-active-low - The BOOTSEL activity LED is active low (ignored by RP2040 and RP2350-A4) + See "picotool help device-selection" for available options ``` ### cp @@ -1975,34 +1520,7 @@ OPTIONS: --format Format the drive if necessary (may result in data loss) Target device selection - --bus - Filter devices by USB bus number - --address - Filter devices by USB device address - --vid - Filter by vendor id - --pid - Filter by product id - --ser - Filter by serial number - --rp2040 - Assume the device is an RP2040 - this is only required when using a custom vid/pid - with an RP2040 on Windows, and is ignored on other operating systems - -f, --force - Force a device not in BOOTSEL mode but running compatible code to reset so the - command can be executed. After executing the command (unless the command itself is - a 'reboot') the device will be rebooted back to application mode - -F, --force-no-reboot - Force a device not in BOOTSEL mode but running compatible code to reset so the - command can be executed. After executing the command (unless the command itself is - a 'reboot') the device will be left connected and accessible to picotool, but - without the USB drive mounted - --bootsel-led - Specify the GPIO for the BOOTSEL activity LED to flash (default none, ignored by - RP2350A-A2 in Arm mode) - only applicable if this command reboots the device to - BOOTSEL mode - --bootsel-led-active-low - The BOOTSEL activity LED is active low (ignored by RP2040 and RP2350-A4) + See "picotool help device-selection" for available options ``` ### rm @@ -2046,34 +1564,7 @@ OPTIONS: --format Format the drive if necessary (may result in data loss) Target device selection - --bus - Filter devices by USB bus number - --address - Filter devices by USB device address - --vid - Filter by vendor id - --pid - Filter by product id - --ser - Filter by serial number - --rp2040 - Assume the device is an RP2040 - this is only required when using a custom vid/pid - with an RP2040 on Windows, and is ignored on other operating systems - -f, --force - Force a device not in BOOTSEL mode but running compatible code to reset so the - command can be executed. After executing the command (unless the command itself is - a 'reboot') the device will be rebooted back to application mode - -F, --force-no-reboot - Force a device not in BOOTSEL mode but running compatible code to reset so the - command can be executed. After executing the command (unless the command itself is - a 'reboot') the device will be left connected and accessible to picotool, but - without the USB drive mounted - --bootsel-led - Specify the GPIO for the BOOTSEL activity LED to flash (default none, ignored by - RP2350A-A2 in Arm mode) - only applicable if this command reboots the device to - BOOTSEL mode - --bootsel-led-active-low - The BOOTSEL activity LED is active low (ignored by RP2040 and RP2350-A4) + See "picotool help device-selection" for available options ``` ### cat @@ -2117,34 +1608,7 @@ OPTIONS: --format Format the drive if necessary (may result in data loss) Target device selection - --bus - Filter devices by USB bus number - --address - Filter devices by USB device address - --vid - Filter by vendor id - --pid - Filter by product id - --ser - Filter by serial number - --rp2040 - Assume the device is an RP2040 - this is only required when using a custom vid/pid - with an RP2040 on Windows, and is ignored on other operating systems - -f, --force - Force a device not in BOOTSEL mode but running compatible code to reset so the - command can be executed. After executing the command (unless the command itself is - a 'reboot') the device will be rebooted back to application mode - -F, --force-no-reboot - Force a device not in BOOTSEL mode but running compatible code to reset so the - command can be executed. After executing the command (unless the command itself is - a 'reboot') the device will be left connected and accessible to picotool, but - without the USB drive mounted - --bootsel-led - Specify the GPIO for the BOOTSEL activity LED to flash (default none, ignored by - RP2350A-A2 in Arm mode) - only applicable if this command reboots the device to - BOOTSEL mode - --bootsel-led-active-low - The BOOTSEL activity LED is active low (ignored by RP2040 and RP2350-A4) + See "picotool help device-selection" for available options ``` ### format @@ -2184,34 +1648,7 @@ OPTIONS: --force-writeable Allow writing, even if the block device is not marked as writeable Target device selection - --bus - Filter devices by USB bus number - --address - Filter devices by USB device address - --vid - Filter by vendor id - --pid - Filter by product id - --ser - Filter by serial number - --rp2040 - Assume the device is an RP2040 - this is only required when using a custom vid/pid - with an RP2040 on Windows, and is ignored on other operating systems - -f, --force - Force a device not in BOOTSEL mode but running compatible code to reset so the - command can be executed. After executing the command (unless the command itself is - a 'reboot') the device will be rebooted back to application mode - -F, --force-no-reboot - Force a device not in BOOTSEL mode but running compatible code to reset so the - command can be executed. After executing the command (unless the command itself is - a 'reboot') the device will be left connected and accessible to picotool, but - without the USB drive mounted - --bootsel-led - Specify the GPIO for the BOOTSEL activity LED to flash (default none, ignored by - RP2350A-A2 in Arm mode) - only applicable if this command reboots the device to - BOOTSEL mode - --bootsel-led-active-low - The BOOTSEL activity LED is active low (ignored by RP2040 and RP2350-A4) + See "picotool help device-selection" for available options ``` ## Binary Information diff --git a/cli.h b/cli.h index bfaae401..34c51b8d 100644 --- a/cli.h +++ b/cli.h @@ -653,6 +653,13 @@ namespace cli { return *this; } + // Instead of expanding this group's options in place, point the reader at + // "picotool help " for the details (see the "help_topic" command dispatch). + group &help_topic(string topic) { + _help_topic = std::move(topic); + return *this; + } + static string decorate(const matchable &e, string s) { if (e.is_optional() && !e.doc_non_optional()) { return string("[") + s + "]"; @@ -772,6 +779,10 @@ namespace cli { if (!_major_group.empty()) { major_group = _major_group; } + if (!_help_topic.empty() && !this->_force_expand_help) { + options.add(major_group, minor_group, "", "See \"picotool help " + _help_topic + "\" for available options"); + return true; + } for (const auto &e : elements) { e->get_option_help(major_group, minor_group, options); } @@ -908,6 +919,7 @@ namespace cli { private: string _major_group; + string _help_topic; group_type type; vector> elements; bool _no_match_beats_error = true; diff --git a/main.cpp b/main.cpp index 19a9106a..1a0a7cac 100644 --- a/main.cpp +++ b/main.cpp @@ -723,7 +723,34 @@ auto device_selection = #endif ", ignored by RP2350A-A2 in Arm mode) - only applicable if this command reboots the device to BOOTSEL mode" + option("--bootsel-led-active-low").set(settings.active_low) % "The BOOTSEL activity LED is active low (ignored by RP2040 and RP2350-A4)" - ).min(0).doc_non_optional(true).collapse_synopsys("device-selection"); + ).min(0).doc_non_optional(true).collapse_synopsys("device-selection").help_topic("device-selection"); + +struct help_topic { + string title; + string doc; + group options; // optional, leave blank for topics without options +}; + +string family_id_help_text() { + return string("A family ID identifies the target chip and/or image type of a UF2 file, and is " + "accepted by the --family option of several commands.\n\n" + "Valid family IDs are: ") + cli::join(family_names, ", ") + ".\n\n" + "A family ID may also be given directly as a 32 bit hex value, e.g. 0x12345678."; +} + +std::map help_topics { +#if HAS_LIBUSB + { "device-selection", { + "Options for Target Device Selection", + "Options for selecting or filtering the target RP-series device(s). These options are accepted by most commands which target a device.", + group(device_selection).force_expand_help(true) + } }, +#endif + { "family-ids", { + "Valid Family IDs", + family_id_help_text() + } }, +}; #define file_types_x(i)\ (option ('t', "--type") & value("type").set(settings.file_types[i]))\ @@ -1854,12 +1881,50 @@ int parse(const int argc, char **argv) { int tab = 4; bool first = true; - auto section_header=[&](const string &name) { + auto section_header=[&](const string &name, bool upper = true) { fos.first_column(0); fos.hanging_indent(0); if (!first) fos.wrap_hard(); first = false; - fos << (uppercase(name) + ":\n"); + fos << ((upper ? uppercase(name) : name) + ":\n"); + }; + auto print_options_for=[&](const group &g) { + cli::option_map options; + g.get_option_help("", "", options); + for (const auto &major : options.contents.ordered_keys()) { + section_header(major.empty() ? "OPTIONS" : major); + bool first_opt = true; + for (const auto &minor : options.contents[major].ordered_keys()) { + fos.first_column(tab); + fos.hanging_indent(tab*2); + if (!minor.empty()) { + fos << minor << "\n"; + } else if (!first_opt) { + fos << "Other\n"; + } + first_opt = false; + for (const auto &opts : options.contents[major][minor]) { + if (!opts.first.empty()) { + fos.first_column(tab*2); + fos.hanging_indent(0); + fos << opts.first << "\n"; + fos.first_column(tab*3); + } else { + fos.first_column(tab*2); + } + fos.hanging_indent(0); + fos << opts.second << "\n"; + } + } + } + }; + auto print_help_topic=[&](const help_topic &topic) { + section_header(topic.title, false); + fos.first_column(tab); + fos.hanging_indent(0); + fos << topic.doc << "\n"; + print_options_for(topic.options); + fos.flush(); }; auto usage=[&]() { if (help_mode && selected_cmd) { @@ -1931,6 +1996,12 @@ int parse(const int argc, char **argv) { s << "\n"; fos << s.str(); }; + auto write_topic = [&](size_t max, const std::string& name, const help_topic& topic) { + fos.first_column(tab); + fos << name; + fos.first_column((int) (max + tab + 3)); + fos << topic.title << "\n"; + }; if (!selected_cmd) { size_t max = 0; section_header("COMMANDS"); @@ -1940,6 +2011,16 @@ int parse(const int argc, char **argv) { for (auto &cmd: commands) { write_command(max, cmd->name(), cmd); } + if (!help_topics.empty()) { + size_t topic_max = 0; + for (auto &topic: help_topics) { + topic_max = std::max(topic.first.size(), topic_max); + } + section_header("TOPICS"); + for (auto &topic: help_topics) { + write_topic(topic_max, topic.first, topic.second); + } + } } else if (selected_cmd->is_multi()) { section_header("SUB COMMANDS"); size_t max = 0; @@ -1975,30 +2056,7 @@ int parse(const int argc, char **argv) { fos << built_without_libusb_message; #endif } else { - cli::option_map options; - selected_cmd->get_cli().get_option_help("", "", options); - for (const auto &major : options.contents.ordered_keys()) { - section_header(major.empty() ? "OPTIONS" : major); - bool first = true; - for (const auto &minor : options.contents[major].ordered_keys()) { - fos.first_column(tab); - fos.hanging_indent(tab*2); - if (!minor.empty()) { - fos << minor << "\n"; - } else if (!first) { - fos << "Other\n"; - } - first = false; - for (const auto &opts : options.contents[major][minor]) { - fos.first_column(tab*2); - fos.hanging_indent(0); - fos << opts.first << "\n"; - fos.first_column(tab*3); - fos.hanging_indent(0); - fos << opts.second << "\n"; - } - } - } + print_options_for(selected_cmd->get_cli()); } if (!selected_cmd) { fos.first_column(0); @@ -2079,6 +2137,11 @@ int parse(const int argc, char **argv) { usage(); return 0; } else { + auto topic = help_topics.find(args[0]); + if (topic != help_topics.end()) { + print_help_topic(topic->second); + return 0; + } selected_cmd = find_command(args[0]); if (selected_cmd->is_multi() && args.size() > 1) { help_mode_prefix = selected_cmd->name() + " "; From 4a8fcecbb521a2de7c99896867ef47487c68d93c Mon Sep 17 00:00:00 2001 From: William Vinnicombe Date: Tue, 14 Jul 2026 19:09:20 +0100 Subject: [PATCH 02/12] Add help topics to readme --- README.md | 61 +++++++++++++++++++++++++++++++++++++++++++++++-- gen_help_txt.sh | 50 ++++++++++++++++++++++++++++++++++++---- 2 files changed, 104 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 00e273bc..e5216949 100644 --- a/README.md +++ b/README.md @@ -74,8 +74,8 @@ Use "picotool help " for more info Note commands that aren't acting on files require a device in BOOTSEL mode to be connected. -## Links to documentation for `picotool` commands -[`info`](#info) [`config`](#config) [`load`](#load) [`save`](#save) [`verify`](#verify) [`erase`](#erase) [`reboot`](#reboot) [`seal`](#seal) [`encrypt`](#encrypt) [`partition`](#partition) [`uf2`](#uf2) [`otp`](#otp) [`coprodis`](#coprodis) [`link`](#link) [`bdev`](#bdev) +## Links to documentation for `picotool` commands and help topics +[`info`](#info) [`config`](#config) [`load`](#load) [`save`](#save) [`verify`](#verify) [`erase`](#erase) [`reboot`](#reboot) [`seal`](#seal) [`encrypt`](#encrypt) [`partition`](#partition) [`uf2`](#uf2) [`otp`](#otp) [`coprodis`](#coprodis) [`link`](#link) [`bdev`](#bdev) [`device-selection`](#device-selection) [`family-ids`](#family-ids) ## Building & Installing @@ -1651,6 +1651,63 @@ OPTIONS: See "picotool help device-selection" for available options ``` +## Help topics + +`picotool help ` shows additional documentation that applies across multiple commands, rather than to a single command. + +### device-selection + +```text +$ picotool help device-selection +Options for Target Device Selection: + Options for selecting or filtering the target RP-series device(s). These options are + accepted by most commands which target a device. + +OPTIONS: + --bus + Filter devices by USB bus number + --address + Filter devices by USB device address + --vid + Filter by vendor id + --pid + Filter by product id + --ser + Filter by serial number + --rp2040 + Assume the device is an RP2040 - this is only required when using a custom vid/pid + with an RP2040 on Windows, and is ignored on other operating systems + -f, --force + Force a device not in BOOTSEL mode but running compatible code to reset so the + command can be executed. After executing the command (unless the command itself is + a 'reboot') the device will be rebooted back to application mode + -F, --force-no-reboot + Force a device not in BOOTSEL mode but running compatible code to reset so the + command can be executed. After executing the command (unless the command itself is + a 'reboot') the device will be left connected and accessible to picotool, but + without the USB drive mounted + --bootsel-led + Specify the GPIO for the BOOTSEL activity LED to flash (default none, ignored by + RP2350A-A2 in Arm mode) - only applicable if this command reboots the device to + BOOTSEL mode + --bootsel-led-active-low + The BOOTSEL activity LED is active low (ignored by RP2040 and RP2350-A4) +``` + +### family-ids + +```text +$ picotool help family-ids +Valid Family IDs: + A family ID identifies the target chip and/or image type of a UF2 file, and is accepted by + the --family option of several commands. + + Valid family IDs are: data, absolute, rp2040, rp2350-arm-s, rp2350-arm-ns, rp2350-riscv, + cyw43-firmware. + + A family ID may also be given directly as a 32 bit hex value, e.g. 0x12345678. +``` + ## Binary Information Binary information is machine locatable and generally machine consumable. I say generally because anyone can diff --git a/gen_help_txt.sh b/gen_help_txt.sh index 7fd00c01..54168c8a 100755 --- a/gen_help_txt.sh +++ b/gen_help_txt.sh @@ -97,17 +97,57 @@ if [ ${#missing_commands[@]} -ne 0 ]; then done fi -# Regenerate the links to documentation for picotool commands section -echo "Regenerating links to documentation for picotool commands..." +# Extract help topics to check for missing help text +echo "Extracting help topics from main.cpp..." +topics=$(sed -n '/std::map help_topics {/,/^};/p' main.cpp | \ + grep -oE '"[a-zA-Z0-9_-]+"[[:space:]]*,[[:space:]]*\{' | \ + sed -E 's/^"([a-zA-Z0-9_-]+)".*/\1/') + +echo "Checking for missing help topic sections..." +missing_topics=() +while IFS= read -r topic; do + if [ ! -z "$topic" ]; then + if ! grep -q "\$ picotool help $topic" tmp/README.md; then + missing_topics+=("$topic") + echo "Missing help text section for topic: $topic" + fi + fi +done <<< "$topics" + +# Same as for missing commands above - still fails the job later, this is just to +# provide the output to copy into the right place +if [ ${#missing_topics[@]} -ne 0 ]; then + echo "Adding missing help topic sections to end of file..." + for topic in "${missing_topics[@]}"; do + echo "Running: picotool help $topic" + picotool help "$topic" > "tmp/picotool_help_${topic// /_}.txt" + + { + printf '\n```text\n$ picotool help %s\n' "$topic" + cat "tmp/picotool_help_${topic// /_}.txt" + printf '```\n' + } >> tmp/README.md + done +fi + +# Regenerate the links to documentation for picotool commands and help topics section +echo "Regenerating links to documentation for picotool commands and help topics..." links_line=$(picotool help 2>/dev/null | \ awk '/^COMMANDS:/{f=1;next} f && /^[A-Z]/{exit} f && /^ [a-z]/{print $1}' | \ grep -vE "^(help|$(echo "$ALLOWED_MISSING_COMMANDS" | tr ' ' '|'))$" | \ while IFS= read -r cmd; do printf '[`%s`](#%s) ' "$cmd" "$cmd" done | sed 's/ $//') +topic_links_line=$(echo "$topics" | while IFS= read -r topic; do + [ -z "$topic" ] && continue + printf '[`%s`](#%s) ' "$topic" "$topic" + done | sed 's/ $//') +if [ -n "$topic_links_line" ]; then + links_line="$links_line $topic_links_line" +fi export LINKS_LINE="$links_line" perl -i -0777 -pe ' - s{(## Links to documentation for `picotool` commands\n)[^\n]+}{$1$ENV{LINKS_LINE}}; + s{(## Links to documentation for `picotool` commands and help topics\n)[^\n]+}{$1$ENV{LINKS_LINE}}; ' tmp/README.md mv tmp/README.md README.md @@ -158,8 +198,8 @@ done echo "Help text sections have been updated in README.md" -# Still fail if there are missing commands -if [ ${#missing_commands[@]} -ne 0 ]; then +# Still fail if there are missing commands or topics +if [ ${#missing_commands[@]} -ne 0 ] || [ ${#missing_topics[@]} -ne 0 ]; then echo "Failing job due to missing help text sections" exit 1 fi From 3e1f034594af5febe6fb4fb40a99f8d3a3bfad33 Mon Sep 17 00:00:00 2001 From: William Vinnicombe Date: Wed, 15 Jul 2026 11:57:05 +0100 Subject: [PATCH 03/12] Improve device selection and forced reboot docs --- README.md | 6 +++--- main.cpp | 13 ++++++++----- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index e5216949..c0ae8a71 100644 --- a/README.md +++ b/README.md @@ -1937,9 +1937,9 @@ purposes of binaries compiled using the [pico-sdk](https://github.com/raspberryp If your code has returned then rebooting with `-f/F` will not work - instead you can set the compile definition `PICO_ENTER_USB_BOOT_ON_EXIT` to reboot and be accessible to picotool once your code has finished execution, for example with `target_compile_definitions( PRIVATE PICO_ENTER_USB_BOOT_ON_EXIT=1)` -- Uses stdio_usb - -If your binary calls `stdio_init_all()` and you have `pico_enable_stdio_usb( 1)` in your CMakeLists.txt file then you meet -this requirement (see the [hello_usb](https://github.com/raspberrypi/pico-examples/tree/master/hello_world/usb) example) +- Uses stdio_usb or the pico_usb_reset library - +If your binary calls `stdio_init_all()`, does not use TinyUSB directly (i.e. does not link `tinyusb_device`), and you have `pico_enable_stdio_usb( 1)` in your CMakeLists.txt file, then you meet +this requirement (see the [hello_usb](https://github.com/raspberrypi/pico-examples/tree/master/hello_world/usb) example). If you are using TinyUSB directly, see the [library documentation](https://www.raspberrypi.com/documentation/pico-sdk/high_level.html#group_pico_usb_reset) or the [dev_multi_cdc](https://github.com/raspberrypi/pico-examples/tree/master/usb/device/dev_multi_cdc) example for more details on how to enable the `pico_usb_reset` library. ### Issues diff --git a/main.cpp b/main.cpp index 1a0a7cac..2f661453 100644 --- a/main.cpp +++ b/main.cpp @@ -741,8 +741,11 @@ string family_id_help_text() { std::map help_topics { #if HAS_LIBUSB { "device-selection", { - "Options for Target Device Selection", - "Options for selecting or filtering the target RP-series device(s). These options are accepted by most commands which target a device.", + "Options for Target Device Selection and Rebooting", + "Options for selecting or filtering the target RP-series device(s), including rebooting devices to BOOTSEL mode first. " + "These options are accepted by most commands which target a device.\n\n" + "For the `-f/F` options, compatible code is defined as code which uses stdio_usb or the pico_usb_reset library, and which is still running. " + "See Forced Reboots in the README (https://github.com/raspberrypi/picotool#forced-reboots) for more information.", group(device_selection).force_expand_help(true) } }, #endif @@ -876,7 +879,7 @@ struct info_command : public cmd { ).min(0).doc_non_optional(true) % "Information to display" + ( #if HAS_LIBUSB - device_selection % "To target one or more connected RP-series device(s) in BOOTSEL mode (the default)" | + device_selection % "To target one or more connected RP-series device(s) (the default)" | #endif file_selection % "To target a file" ).major_group("TARGET SELECTION").min(0).doc_non_optional(true) @@ -911,7 +914,7 @@ struct config_command : public cmd { (option('g', "--group") & value("group").set(settings.config.group)) % "Filter by feature group" + ( #if HAS_LIBUSB - device_selection % "To target one or more connected RP-series device(s) in BOOTSEL mode (the default)" | + device_selection % "To target one or more connected RP-series device(s) (the default)" | #endif file_selection % "To target a file" ).major_group("TARGET SELECTION").min(0).doc_non_optional(true) @@ -1165,7 +1168,7 @@ struct erase_command : public cmd { ).min(0).doc_non_optional(true) ).min(0).doc_non_optional(true).no_match_beats_error(false) % "Selection of data to erase" + ( // note this parenthesis seems to help with error messages for say erase --foo - device_selection % "Source device selection" + device_selection % "Target device selection" ) ); } From 15534426aec85a9328d2bda4b5ac4538a9410efc Mon Sep 17 00:00:00 2001 From: William Vinnicombe Date: Wed, 15 Jul 2026 12:23:31 +0100 Subject: [PATCH 04/12] Add "picotool help " --- README.md | 21 +++++++++++++-------- main.cpp | 2 +- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index c0ae8a71..171f4fee 100644 --- a/README.md +++ b/README.md @@ -66,10 +66,10 @@ COMMANDS: bdev Commands related to embedded block devices TOPICS: - device-selection Options for Target Device Selection + device-selection Options for Target Device Selection and Rebooting family-ids Valid Family IDs -Use "picotool help " for more info +Use "picotool help " or "picotool help " for more info ``` Note commands that aren't acting on files require a device in BOOTSEL mode to be connected. @@ -120,7 +120,7 @@ OPTIONS: Include all information TARGET SELECTION: - To target one or more connected RP-series device(s) in BOOTSEL mode (the default) + To target one or more connected RP-series device(s) (the default) See "picotool help device-selection" for available options To target a file @@ -210,7 +210,7 @@ OPTIONS: Filter by feature group TARGET SELECTION: - To target one or more connected RP-series device(s) in BOOTSEL mode (the default) + To target one or more connected RP-series device(s) (the default) See "picotool help device-selection" for available options To target a file @@ -441,7 +441,7 @@ OPTIONS: The lower address bound in hex The upper address bound in hex - Source device selection + Target device selection See "picotool help device-selection" for available options ``` @@ -1659,9 +1659,14 @@ OPTIONS: ```text $ picotool help device-selection -Options for Target Device Selection: - Options for selecting or filtering the target RP-series device(s). These options are - accepted by most commands which target a device. +Options for Target Device Selection and Rebooting: + Options for selecting or filtering the target RP-series device(s), including rebooting + devices to BOOTSEL mode first. These options are accepted by most commands which target a + device. + + For the `-f/F` options, compatible code is defined as code which uses stdio_usb or the + pico_usb_reset library, and which is still running. See Forced Reboots in the README + (https://github.com/raspberrypi/picotool#forced-reboots) for more information. OPTIONS: --bus diff --git a/main.cpp b/main.cpp index 2f661453..9dd45503 100644 --- a/main.cpp +++ b/main.cpp @@ -2065,7 +2065,7 @@ int parse(const int argc, char **argv) { fos.first_column(0); fos.hanging_indent(0); fos.wrap_hard(); - fos << "Use \"picotool help \" for more info\n"; + fos << "Use \"picotool help \" or \"picotool help \" for more info\n"; #if !HAS_LIBUSB if (!help_mode) { fos << built_without_libusb_message; From 7c9c3fc9d22e512365c9d794521da9d9455e3bda Mon Sep 17 00:00:00 2001 From: William Vinnicombe Date: Wed, 15 Jul 2026 12:36:34 +0100 Subject: [PATCH 05/12] Tidy up bdev docs, now bdev commands have been added --- README.md | 21 ++++----------------- 1 file changed, 4 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 171f4fee..2f36ea9b 100644 --- a/README.md +++ b/README.md @@ -1900,27 +1900,13 @@ quotes, newlines etc you may have better luck defining via bi_decl in the code. ### Block devices MicroPython and CircuitPython, eventually the SDK and others may support one or more storage devices in flash. We already -have macros to define these although picotool doesn't do anything with them yet... but backup/restore/file copy and even fuse mount -in the future might be interesting. +have macros to define these, and they can be accessed with the [`bdev`](#bdev) commands. In the future backup/restore and even fuse mount might be interesting additions. -I suggest we tag these now... - -This is what I have right now off the top of my head (at the time) +These can be tagged using the `bi_block_device` macro: ```c #define bi_block_device(_tag, _name, _offset, _size, _extra, _flags) ``` -with the data going into -```c -typedef struct __packed _binary_info_block_device { - struct _binary_info_core core; - bi_ptr_of(const char) name; // optional static name (independent of what is formatted) - uint32_t offset; - uint32_t size; - bi_ptr_of(binary_info_t) extra; // additional info - uint16_t flags; -} binary_info_block_device_t; -``` -and +using the following flags ```c enum { BINARY_INFO_BLOCK_DEV_FLAG_READ = 1 << 0, // if not readable, then it is basically hidden, but tools may choose to avoid overwriting it @@ -1933,6 +1919,7 @@ enum { BINARY_INFO_BLOCK_DEV_FLAG_PT_NONE = 3 << 4, // no partition table }; ``` +For more information see the Pico SDK, where this macro and flags are defined. ### Forced Reboots From 9d755f9dad94b6c04b22675385e5433bb2939d48 Mon Sep 17 00:00:00 2001 From: William Vinnicombe Date: Thu, 16 Jul 2026 11:55:44 +0100 Subject: [PATCH 06/12] Review fixups Add docs for `version` and remove ALLOWED_MISSING_COMMANDS "Post load actions" -> "Load options" set/get -> get/set Fix white-label -s option not showing up Fix otp permissions docs --- README.md | 69 ++++++++++++++++++++++++++++++++++++++++++++----- gen_help_txt.sh | 10 +++---- main.cpp | 7 +++-- 3 files changed, 68 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 2f36ea9b..b845979b 100644 --- a/README.md +++ b/README.md @@ -75,7 +75,7 @@ Use "picotool help " or "picotool help " for more info Note commands that aren't acting on files require a device in BOOTSEL mode to be connected. ## Links to documentation for `picotool` commands and help topics -[`info`](#info) [`config`](#config) [`load`](#load) [`save`](#save) [`verify`](#verify) [`erase`](#erase) [`reboot`](#reboot) [`seal`](#seal) [`encrypt`](#encrypt) [`partition`](#partition) [`uf2`](#uf2) [`otp`](#otp) [`coprodis`](#coprodis) [`link`](#link) [`bdev`](#bdev) [`device-selection`](#device-selection) [`family-ids`](#family-ids) +[`version`](#version) [`info`](#info) [`config`](#config) [`load`](#load) [`save`](#save) [`verify`](#verify) [`erase`](#erase) [`reboot`](#reboot) [`seal`](#seal) [`encrypt`](#encrypt) [`partition`](#partition) [`uf2`](#uf2) [`otp`](#otp) [`coprodis`](#coprodis) [`link`](#link) [`bdev`](#bdev) [`device-selection`](#device-selection) [`family-ids`](#family-ids) ## Building & Installing @@ -83,6 +83,59 @@ If you don't want to build picotool yourself, you can find pre-built executables If you do wish to build picotool yourself, then see [Building](BUILDING.md#building) for build instructions. For the Pico SDK to find your picotool you will need to install it, the simplest way being to run `cmake --install .` - see [Installing](BUILDING.md#installing-so-the-pico-sdk-can-find-it) for more details and alternatives. **You cannot just copy the binary into your `PATH`, else the Pico SDK will not be able to locate it.** +## version + +Displays the picotool version, and also allows checking compatibility with an expected `picotool` version, for example to check a newer `picotool` is backwards compatible with an older version. + +```text +$ picotool help version +VERSION: + Display picotool version + +SYNOPSIS: + picotool version [-s] [] + +OPTIONS: + -s, --semantic + Output semantic version number only + + Check compatibility with version +``` + +The normal output is this format: +```text +$ picotool version +picotool v2.3.0 (Linux, GNU-12.2.0, Release) +``` + +When built without libusb you get an additional message: +```text +$ picotool version +picotool v2.3.0 (Linux, GNU-12.2.0, Release) + +This version of picotool was compiled without USB support. Some commands are not available. +``` + +The semantic output is: +```text +$ picotool version -s +2.3.0 +``` + +When checking compatibility with a compatible version (e.g. 2.2.0 with version 2.3.0): +```text +$ picotool version -s 2.2.0 +2.3.0 +``` + +Or with an incompatible version (e.g. 2.4.0 with version 2.3.0), it will exit with error code `ERROR_INCOMPATIBLE` (-3): +```text +$ picotool version -s 2.4.0 +2.3.0 +ERROR: Version 2.4.0 not compatible with this software + +``` + ## info There is _Binary Information_ support in the SDK which allows for easily storing compact information that `picotool` @@ -262,7 +315,7 @@ SYNOPSIS: [-v] [-x] [-t ] [-o ] [device-selection] OPTIONS: - Post load actions + Load options --ignore-partitions When writing flash data, ignore the partition table and write to absolute space --family @@ -948,7 +1001,7 @@ SYNOPSIS: [device-selection] picotool otp load [-r] [-e] [-s ] [-i ] [-t ] [device-selection] - picotool otp white-label -s [device-selection] + picotool otp white-label [-s ] [device-selection] picotool otp permissions [--led ] [--hash] [--sign] [] [device-selection] picotool otp dump [-r] [-e] [-p] [--output ] [device-selection] @@ -966,9 +1019,9 @@ SUB COMMANDS: list List matching known registers/fields ``` -### set/get +### get/set -These commands will set/get specific rows of OTP. By default, they will write/read all redundant rows, but this can be overridden with the `-c` argument +These commands will get/set specific rows of OTP. By default, they will read/write all redundant rows, but this can be overridden with the `-c` argument ```text $ picotool help otp get @@ -1114,9 +1167,11 @@ OTP WHITE-LABEL: Set the white labelling values in OTP SYNOPSIS: - picotool otp white-label -s [device-selection] + picotool otp white-label [-s ] [device-selection] OPTIONS: + -s + Start row for white label struct (default 0x100) (note use 0x for hex) JSON file with white labelling values Target device selection @@ -1163,7 +1218,7 @@ Device Descriptor: ### permissions -This command will run a binary on your device in order to set the OTP permissions, as these are not directly accessible from `picotool` due to errata RP2350-E15 on RP2350 A2. +This command will run a binary on your device in order to set the OTP permissions, which may not be accessible in BOOTSEL mode. For example on RP2350 A2, the permissions for pages 32-63 are not writeable from BOOTSEL mode due to errata RP2350-E15. You may also have previously configured the permissions to block writes in BOOTSEL mode using `LOCK_BL`, but now wish to lock them down further. Because it runs a binary, the binary needs to be signed if secure boot is enabled. The binary will light an LED when running, which can be configured using the `--led` argument. You can define your OTP permissions in a json file, an example of which is in [sample-permissions.json](json/sample-permissions.json). The schema for this JSON file is [here](json/schemas/permissions-schema.json) diff --git a/gen_help_txt.sh b/gen_help_txt.sh index 54168c8a..281a65d6 100755 --- a/gen_help_txt.sh +++ b/gen_help_txt.sh @@ -1,7 +1,5 @@ #!/bin/bash -ALLOWED_MISSING_COMMANDS="version" - mkdir -p tmp cp README.md tmp/README.md @@ -73,10 +71,8 @@ missing_commands=() while IFS= read -r cmd; do if [ ! -z "$cmd" ]; then if ! grep -q "\$ picotool help $cmd" tmp/README.md; then - if [[ ! "$ALLOWED_MISSING_COMMANDS" =~ "$cmd" ]]; then - missing_commands+=("$cmd") - echo "Missing help text section for command: $cmd" - fi + missing_commands+=("$cmd") + echo "Missing help text section for command: $cmd" fi fi done <<< "$commands" @@ -134,7 +130,7 @@ fi echo "Regenerating links to documentation for picotool commands and help topics..." links_line=$(picotool help 2>/dev/null | \ awk '/^COMMANDS:/{f=1;next} f && /^[A-Z]/{exit} f && /^ [a-z]/{print $1}' | \ - grep -vE "^(help|$(echo "$ALLOWED_MISSING_COMMANDS" | tr ' ' '|'))$" | \ + grep -vE "^(help)$" | \ while IFS= read -r cmd; do printf '[`%s`](#%s) ' "$cmd" "$cmd" done | sed 's/ $//') diff --git a/main.cpp b/main.cpp index 9dd45503..496fe644 100644 --- a/main.cpp +++ b/main.cpp @@ -1134,7 +1134,7 @@ struct load_command : public cmd { option('u', "--update").set(settings.load.update) % "Skip writing flash sectors that already contain identical data" + option('v', "--verify").set(settings.load.verify) % "Verify the data was written correctly" + option('x', "--execute").set(settings.load.execute) % "Perform a bootrom reboot to execute the downloaded file as a program after the load - either a flash update boot for binaries in flash, or a RAM image boot for other binaries " - ).min(0).doc_non_optional(true) % "Post load actions" + + ).min(0).doc_non_optional(true) % "Load options" + file_selection % "File to load from" + ( option('o', "--offset").set(settings.offset_set) % "Specify the load address for a BIN file" & @@ -1563,9 +1563,7 @@ struct otp_white_label_command : public cmd { group get_cli() override { return ( - ( - (option('s', "--start_row") & integer("row").set(settings.otp.row)) % "Start row for white label struct (default 0x100) (note use 0x for hex)" - ).min(0).doc_non_optional(true) % "Row options" + + (option('s', "--start_row") & integer("row").set(settings.otp.row)) % "Start row for white label struct (default 0x100) (note use 0x for hex)" + named_untyped_file_selection_x("filename", 0) % "JSON file with white labelling values" + device_selection % "Target device selection" ); @@ -2142,6 +2140,7 @@ int parse(const int argc, char **argv) { } else { auto topic = help_topics.find(args[0]); if (topic != help_topics.end()) { + selected_cmd = nullptr; print_help_topic(topic->second); return 0; } From c5616ae8f0b968651b46d4a0c2a16ca4b3154acc Mon Sep 17 00:00:00 2001 From: William Vinnicombe Date: Thu, 16 Jul 2026 13:50:46 +0100 Subject: [PATCH 07/12] Review fixups gen_help_txt.sh tidyups Add topic mention to picotool help docs Missing comma in block devices docs --- README.md | 4 ++-- gen_help_txt.sh | 16 +++++++++++----- main.cpp | 2 +- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index b845979b..4a71cf5c 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ SYNOPSIS: picotool bdev ls|mkdir|cp|rm|cat|format COMMANDS: - help Show general help or help for a specific command + help Show general help, or help for a specific command or topic version Display picotool version info Display information from the target device(s) or file. Without any arguments, this will display basic information for all connected @@ -1955,7 +1955,7 @@ quotes, newlines etc you may have better luck defining via bi_decl in the code. ### Block devices MicroPython and CircuitPython, eventually the SDK and others may support one or more storage devices in flash. We already -have macros to define these, and they can be accessed with the [`bdev`](#bdev) commands. In the future backup/restore and even fuse mount might be interesting additions. +have macros to define these, and they can be accessed with the [`bdev`](#bdev) commands. In the future, backup/restore and even fuse mount might be interesting additions. These can be tagged using the `bi_block_device` macro: ```c diff --git a/gen_help_txt.sh b/gen_help_txt.sh index 281a65d6..9b929a31 100755 --- a/gen_help_txt.sh +++ b/gen_help_txt.sh @@ -21,8 +21,8 @@ while IFS= read -r line; do # Replace the old section with the new one escaped_line=$(echo "$line" | sed 's/[.*+?^${}()|[]/\\&/g') - perl -i -pe ' - BEGIN { $/ = undef; $new = `cat tmp/new_section.txt`; } + perl -i -0777 -pe ' + BEGIN { $new = `cat tmp/new_section.txt`; } s/```text\n'"$escaped_line"'\n.*?\n```/$new/s; ' tmp/README.md fi @@ -154,7 +154,7 @@ echo "Checking command order..." order_mismatch=false -check_cmd_order() { +check_cmd_topic_order() { local label="$1" tool_order="$2" readme_order="$3" local fp="" fr="" while IFS= read -r cmd; do @@ -179,7 +179,13 @@ tool_top_order=$(picotool help 2>/dev/null | \ readme_top_order=$(grep -n '^\$ picotool help [a-z][a-z-]*$' README.md | \ sed 's/^\([0-9]*\):.*\$ picotool help \([a-z][a-z-]*\)$/\1 \2/' | \ sort -n | awk '{print $2}' | awk '!seen[$0]++') -check_cmd_order "top-level commands" "$tool_top_order" "$readme_top_order" +check_cmd_topic_order "top-level commands" "$tool_top_order" "$readme_top_order" + +# Check help topic order (help_topics is a std::map, so picotool prints topics +# alphabetically by key rather than in main.cpp source order) +tool_topic_order=$(picotool help 2>/dev/null | \ + awk '/^TOPICS:/{f=1;next} f && /^[A-Z]/{exit} f && /^ [a-z]/{print $1}') +check_cmd_topic_order "help topics" "$tool_topic_order" "$readme_top_order" # Check sub-command order for each parent command for array in $sub_command_arrays; do @@ -189,7 +195,7 @@ for array in $sub_command_arrays; do readme_sub_order=$(grep -n "^\$ picotool help ${prefix} [a-z][a-z-]*$" README.md | \ sed "s/^\([0-9]*\):.*\$ picotool help ${prefix} \([a-z][a-z-]*\)$/\1 \2/" | \ sort -n | awk '{print $2}' | awk '!seen[$0]++') - check_cmd_order "${prefix} sub-commands" "$tool_sub_order" "$readme_sub_order" + check_cmd_topic_order "${prefix} sub-commands" "$tool_sub_order" "$readme_sub_order" done echo "Help text sections have been updated in README.md" diff --git a/main.cpp b/main.cpp index 496fe644..fefc3803 100644 --- a/main.cpp +++ b/main.cpp @@ -1738,7 +1738,7 @@ struct help_command : public cmd { } string get_doc() const override { - return "Show general help or help for a specific command"; + return "Show general help, or help for a specific command or topic"; } }; From a00c443d6f7db477167778c754bd373162e90af7 Mon Sep 17 00:00:00 2001 From: William Vinnicombe Date: Thu, 16 Jul 2026 15:35:34 +0100 Subject: [PATCH 08/12] Fix some options requiring separate lines Fixes things like --family appearing on separate lines Also ensures short and long options are shown in the help output --- README.md | 279 +++++++++++++++++++----------------------------------- cli.h | 27 +++++- main.cpp | 138 ++++++++++++++------------- 3 files changed, 193 insertions(+), 251 deletions(-) diff --git a/README.md b/README.md index 4a71cf5c..edda9c36 100644 --- a/README.md +++ b/README.md @@ -178,7 +178,7 @@ TARGET SELECTION: To target a file The file name - -t + -t, --type Specify file type (uf2 | elf | bin) explicitly, ignoring file extension ``` @@ -255,11 +255,9 @@ SYNOPSIS: picotool config [-s ] [-g ] [-t ] OPTIONS: - - Variable name - - New value - -g + -s, --set + Set config variable name to new value + -g, --group Filter by feature group TARGET SELECTION: @@ -268,7 +266,7 @@ TARGET SELECTION: To target a file The file name - -t + -t, --type Specify file type (uf2 | elf | bin) explicitly, ignoring file extension ``` @@ -318,14 +316,10 @@ OPTIONS: Load options --ignore-partitions When writing flash data, ignore the partition table and write to absolute space - --family + --family Specify the family ID of the file to load - - family ID to use for load - -p, --partition + -p, --partition Specify the partition to load into - - partition to load into -n, --no-overwrite When writing flash data, do not overwrite an existing program in flash. If picotool cannot determine the size/presence of the program in flash, the command fails @@ -344,13 +338,11 @@ OPTIONS: File to load from The file name - -t + -t, --type Specify file type (uf2 | elf | bin) explicitly, ignoring file extension BIN file options - -o, --offset - Specify the load address for a BIN file - - Load offset (memory address; default 0x10000000) + -o, --offset + Specify the load address for a BIN file (memory address; default 0x10000000) Target device selection See "picotool help device-selection" for available options ``` @@ -393,14 +385,12 @@ OPTIONS: Other -v, --verify Verify the data was saved correctly - --family + --family Specify the family ID to save the file as - - family ID to save file as File to save to The file name - -t + -t, --type Specify file type (uf2 | elf | bin) explicitly, ignoring file extension Source device selection See "picotool help device-selection" for available options @@ -447,19 +437,14 @@ OPTIONS: The file to compare against The file name - -t + -t, --type Specify file type (uf2 | elf | bin) explicitly, ignoring file extension Address options - -r, --range - Compare a sub range of memory only - - The lower address bound in hex - - The upper address bound in hex - -o, --offset - Specify the load address when comparing with a BIN file - - Load offset (memory address; default 0x10000000) + -r, --range + Compare a sub range of memory only (address bounds in hex) + -o, --offset + Specify the load address (memory address; default 0x10000000) when comparing with a + BIN file Target device selection See "picotool help device-selection" for available options ``` @@ -556,9 +541,9 @@ OPTIONS: Reboot back into the application (this is the default) -u, --usb Reboot back into BOOTSEL mode - -g + -g, --diagnostic Select diagnostic partition - -c + -c, --cpu Select arm | riscv CPU (if possible) Selecting the device to reboot See "picotool help device-selection" for available options @@ -615,17 +600,15 @@ OPTIONS: File to load from The file name - -t + -t, --type Specify file type (uf2 | elf | bin) explicitly, ignoring file extension BIN file options - -o, --offset - Specify the load address for a BIN file - - Load offset (memory address; default 0x10000000) + -o, --offset + Specify the load address for a BIN file (memory address; default 0x10000000) File to save to The file name - -t + -t, --type Specify file type (uf2 | elf | bin) explicitly, ignoring file extension ``` @@ -673,10 +656,9 @@ OPTIONS: Use ~180MHz ROSC configuration for embedded bootloader --use-mbedtls Use MbedTLS implementation of embedded bootloader (faster but less secure) - --otp-key-page - Specify the OTP page storing the AES key (IV salt is stored on the next page) - - OTP page (default 29) + --otp-key-page + Specify the OTP page storing the AES key (default 29; IV salt is stored on the next + page) AES Key Share or AES Key @@ -697,17 +679,15 @@ OPTIONS: File to load from The file name - -t + -t, --type Specify file type (uf2 | elf | bin) explicitly, ignoring file extension BIN file options - -o, --offset - Specify the load address for a BIN file - - Load offset (memory address; default 0x10000000) + -o, --offset + Specify the load address for a BIN file (memory address; default 0x10000000) File to save to The file name - -t + -t, --type Specify file type (uf2 | elf | bin) explicitly, ignoring file extension ``` @@ -726,7 +706,7 @@ SYNOPSIS: picotool partition info [-m ] [device-selection] OPTIONS: - -m + -m, --family family ID (will show target partition for said family) Target device selection See "picotool help device-selection" for available options @@ -776,26 +756,22 @@ OPTIONS: output file The file name - -t + -t, --type Specify file type (uf2 | elf | bin) explicitly, ignoring file extension UF2 output options - -o, --offset - Specify the load address for UF2 file output - - Load offset (memory address; default 0x10000000) - --family - Specify the family if for UF2 file output - - family ID for UF2 (default absolute) + -o, --offset + Specify the load address for UF2 file output (memory address; default 0x10000000) + --family + Specify the family id for UF2 file output (default absolute) embed partition table into bootloader ELF The file name - -t + -t, --type Specify file type (elf) explicitly, ignoring file extension Partition Table Options --sign The file name - -t + -t, --type Specify file type (pem) explicitly, ignoring file extension --no-hash Don't hash the partition table @@ -836,28 +812,22 @@ OPTIONS: File to load from The file name - -t + -t, --type Specify file type (uf2 | elf | bin) explicitly, ignoring file extension File to save UF2 to The file name - -t + -t, --type Specify file type (uf2) explicitly, ignoring file extension Packaging Options - -o, --offset - Specify the load address - - Load offset (memory address; default 0x10000000 for BIN file) + -o, --offset + Specify the load address (memory address; default 0x10000000 for BIN file) UF2 Family options - --family - Specify the family ID - - family ID for UF2 + --family + Specify the family ID for UF2 Platform options - --platform - Optional platform for memory-address validation - - platform to use (eg rp2040, rp2350) + --platform + Optional platform for memory-address validation (eg rp2040, rp2350) Errata RP2350-E10 Fix --abs-block Add an absolute block @@ -887,33 +857,27 @@ OPTIONS: First file to combine The file name - -t + -t, --type Specify file type (uf2) explicitly, ignoring file extension Second file to combine The file name - -t + -t, --type Specify file type (uf2) explicitly, ignoring file extension File to save output to The file name - -t + -t, --type Specify file type (uf2) explicitly, ignoring file extension UF2 Family options - --family - Specify the family ID - - family ID for combined UF2 (defaults to first one) + --family + Specify the family ID for combined UF2 (defaults to first one) Offset options - --offset + --offset Offset second UF2 by amount - - offset amount (default to 0) Partition options - --partition + --partition Place second UF2 in partition (first UF2 must contain a partition table) - - partition number (default to 0) Errata RP2350-E10 Fix --abs-block Add an absolute block @@ -1034,7 +998,7 @@ SYNOPSIS: OPTIONS: Row/field options - -c + -c, --copies Read multiple redundant values -r, --raw Get raw 24-bit values @@ -1042,7 +1006,7 @@ OPTIONS: Use error correction -n, --no-descriptions Don't show descriptions - -i + -i, --include Include extra otp definition Row/Field Selection -z, --fuzzy @@ -1080,7 +1044,7 @@ SYNOPSIS: OPTIONS: Redundancy/Error Correction Overrides - -c + -c, --copies Write multiple redundant values -r, --raw Set raw 24-bit values @@ -1088,7 +1052,7 @@ OPTIONS: Use error correction -s, --set-bits Set bits only - -i + -i, --include Include extra otp definition The value to set @@ -1135,14 +1099,14 @@ OPTIONS: Set raw 24-bit values. This is the default for BIN files -e, --ecc Use error correction - -s + -s, --start_row Start row to load at (note use 0x for hex) - -i + -i, --include Include extra otp definition File to load row(s) from The file name - -t + -t, --type Specify file type (json | bin) explicitly, ignoring file extension Target device selection See "picotool help device-selection" for available options @@ -1170,7 +1134,8 @@ SYNOPSIS: picotool otp white-label [-s ] [device-selection] OPTIONS: - -s + Row options + -s, --start_row Start row for white label struct (default 0x100) (note use 0x for hex) JSON file with white labelling values @@ -1298,7 +1263,7 @@ TARGET SELECTION: To dump the contents of an OTP JSON file The file name - -t + -t, --type Specify file type (json) explicitly, ignoring file extension ``` @@ -1322,7 +1287,7 @@ OPTIONS: Don't show descriptions -f, --field-descriptions Show all field descriptions - -i + -i, --include Include extra otp definition The row/field selector, each of which can select a whole row: @@ -1383,17 +1348,17 @@ OPTIONS: Don't print any output --verbose Print verbose output - -p + -p, --pad Specify alignment to pad to, defaults to 0x1000 File to write to The file name - -t + -t, --type Specify file type (uf2 | bin) explicitly, ignoring file extension Files to link The file name - -t + -t, --type Specify file type (uf2 | elf | bin) explicitly, ignoring file extension The file name @@ -1460,22 +1425,14 @@ OPTIONS: -r, --recursive List files in directories recursively Block device options - -p, --partition-number + -p, --partition-number Partition number to use as block device - - partition number - --partition-name + --partition-name Partition name to use as block device - - partition name - --partition-id + --partition-id Partition ID to use as block device - - partition id - --filesystem - Specify filesystem to use - - littlefs|fatfs + --filesystem + Specify filesystem to use (littlefs|fatfs) --force-formattable Allow formatting, even if the block device is not marked as fomattable --force-writeable @@ -1504,22 +1461,14 @@ OPTIONS: The directory name Block device options - -p, --partition-number + -p, --partition-number Partition number to use as block device - - partition number - --partition-name + --partition-name Partition name to use as block device - - partition name - --partition-id + --partition-id Partition ID to use as block device - - partition id - --filesystem - Specify filesystem to use - - littlefs|fatfs + --filesystem + Specify filesystem to use (littlefs|fatfs) --force-formattable Allow formatting, even if the block device is not marked as fomattable --force-writeable @@ -1552,22 +1501,14 @@ OPTIONS: The file name Block device options - -p, --partition-number + -p, --partition-number Partition number to use as block device - - partition number - --partition-name + --partition-name Partition name to use as block device - - partition name - --partition-id + --partition-id Partition ID to use as block device - - partition id - --filesystem - Specify filesystem to use - - littlefs|fatfs + --filesystem + Specify filesystem to use (littlefs|fatfs) --force-formattable Allow formatting, even if the block device is not marked as fomattable --force-writeable @@ -1596,22 +1537,14 @@ OPTIONS: The file name Block device options - -p, --partition-number + -p, --partition-number Partition number to use as block device - - partition number - --partition-name + --partition-name Partition name to use as block device - - partition name - --partition-id + --partition-id Partition ID to use as block device - - partition id - --filesystem - Specify filesystem to use - - littlefs|fatfs + --filesystem + Specify filesystem to use (littlefs|fatfs) --force-formattable Allow formatting, even if the block device is not marked as fomattable --force-writeable @@ -1640,22 +1573,14 @@ OPTIONS: The file name Block device options - -p, --partition-number + -p, --partition-number Partition number to use as block device - - partition number - --partition-name + --partition-name Partition name to use as block device - - partition name - --partition-id + --partition-id Partition ID to use as block device - - partition id - --filesystem - Specify filesystem to use - - littlefs|fatfs + --filesystem + Specify filesystem to use (littlefs|fatfs) --force-formattable Allow formatting, even if the block device is not marked as fomattable --force-writeable @@ -1682,22 +1607,14 @@ SYNOPSIS: OPTIONS: Block device options - -p, --partition-number + -p, --partition-number Partition number to use as block device - - partition number - --partition-name + --partition-name Partition name to use as block device - - partition name - --partition-id + --partition-id Partition ID to use as block device - - partition id - --filesystem - Specify filesystem to use - - littlefs|fatfs + --filesystem + Specify filesystem to use (littlefs|fatfs) --force-formattable Allow formatting, even if the block device is not marked as fomattable --force-writeable diff --git a/cli.h b/cli.h index 34c51b8d..259be689 100644 --- a/cli.h +++ b/cli.h @@ -195,6 +195,10 @@ namespace cli { return {_name}; } + virtual string option_label() const { + return synopsys()[0]; + } + virtual bool is_optional() const { return !_min; } @@ -353,14 +357,18 @@ namespace cli { _name = short_opt.empty() ? long_opt : short_opt; } - bool get_option_help(string major_group, string minor_group, option_map &options) const override { - if (doc().empty()) return false; + string option_label() const override { string label = short_opt.empty() ? "" : _name; if (!long_opt.empty()) { if (!label.empty()) label += ", "; label += long_opt; } - options.add(major_group, minor_group, label, doc()); + return label; + } + + bool get_option_help(string major_group, string minor_group, option_map &options) const override { + if (doc().empty()) return false; + options.add(major_group, minor_group, option_label(), doc()); return true; } @@ -668,6 +676,17 @@ namespace cli { } } + string option_label() const override { + if (type != set && type != sequence) { + return matchable::option_label(); + } + vector parts; + for (auto &x : elements) { + parts.push_back(decorate(*x, x->option_label())); + } + return join(parts, " "); + } + vector synopsys() const override { vector rc; switch (type) { @@ -770,7 +789,7 @@ namespace cli { bool get_option_help(string major_group, string minor_group, option_map &options) const override { // todo beware.. this check is necessary as is, but I'm not sure what removing it breaks in terms of formatting :-( if (is_optional() && !this->_doc_non_optional && !this->_force_expand_help) { - options.add(major_group, minor_group, synopsys()[0], doc()); + options.add(major_group, minor_group, option_label(), doc()); return true; } if (!doc().empty()) { diff --git a/main.cpp b/main.cpp index fefc3803..8a05d9ad 100644 --- a/main.cpp +++ b/main.cpp @@ -848,6 +848,10 @@ std::map help_topics { auto file_types = (option ('t', "--type") & value("type").set(settings.file_types[0])) % "Specify file type (uf2 | elf | bin) explicitly, ignoring file extension"; +group as_section(const group &g) { + return group() + g; +} + auto file_selection = ( value("filename").with_exclusion_filter([](const string &value) { @@ -908,9 +912,9 @@ struct config_command : public cmd { group get_cli() override { return ( (option('s', "--set") & ( - value("key").set(settings.config.key) % "Variable name" + - value("value").set(settings.config.value) % "New value") - ).force_expand_help(true) + + value("key").set(settings.config.key) + + value("value").set(settings.config.value)) + ) % "Set config variable name to new value" + (option('g', "--group") & value("group").set(settings.config.group)) % "Filter by feature group" + ( #if HAS_LIBUSB @@ -932,14 +936,14 @@ struct config_command : public cmd { #if HAS_LIBUSB auto bdev_base_options = ( - (option('p', "--partition-number") % "Partition number to use as block device" & - integer("partition number").set(settings.bdev.partition_number) % "partition number").force_expand_help(true) + - (option("--partition-name") % "Partition name to use as block device" & - value("partition name").set(settings.bdev.partition_name) % "partition name").force_expand_help(true) + - (option("--partition-id") % "Partition ID to use as block device" & - integer("partition id").set(settings.bdev.partition_id) % "partition id").force_expand_help(true) + - (option("--filesystem") % "Specify filesystem to use" & - bdev_fs("fs").set(settings.bdev.fs) % "littlefs|fatfs").force_expand_help(true) + + (option('p', "--partition-number") & + integer("partition number").set(settings.bdev.partition_number)) % "Partition number to use as block device" + + (option("--partition-name") & + value("partition name").set(settings.bdev.partition_name)) % "Partition name to use as block device" + + (option("--partition-id") & + integer("partition id").set(settings.bdev.partition_id)) % "Partition ID to use as block device" + + (option("--filesystem") & + bdev_fs("fs").set(settings.bdev.fs)) % "Specify filesystem to use (littlefs|fatfs)" + (option("--force-formattable").set(settings.bdev.force_formattable) % "Allow formatting, even if the block device is not marked as fomattable") + (option("--force-writeable").set(settings.bdev.force_writeable) % "Allow writing, even if the block device is not marked as writeable") ).min(0).doc_non_optional(true) % "Block device options"; @@ -1073,11 +1077,11 @@ struct verify_command : public cmd { return ( file_selection % "The file to compare against" + ( - (option('r', "--range").set(settings.range_set) % "Compare a sub range of memory only" & - hex("from").set(settings.from) % "The lower address bound in hex" & - hex("to").set(settings.to) % "The upper address bound in hex").force_expand_help(true) + - (option('o', "--offset").set(settings.offset_set) % "Specify the load address when comparing with a BIN file" & - hex("offset").set(settings.offset) % "Load offset (memory address; default 0x10000000)").force_expand_help(true) + (option('r', "--range").set(settings.range_set) & + hex("from").set(settings.from) & + hex("to").set(settings.to)) % "Compare a sub range of memory only (address bounds in hex)" + + (option('o', "--offset").set(settings.offset_set) & + hex("offset").set(settings.offset)) % "Specify the load address (memory address; default 0x10000000) when comparing with a BIN file" ).min(0).doc_non_optional(true) % "Address options" + device_selection % "Target device selection" ); @@ -1104,8 +1108,8 @@ struct save_command : public cmd { ).min(0).doc_non_optional(true) ).min(0).doc_non_optional(true).no_match_beats_error(false) % "Selection of data to save" + option('v', "--verify").set(settings.save.verify) % "Verify the data was saved correctly" + - (option("--family") % "Specify the family ID to save the file as" & - family_id("family_id").set(settings.family_id) % "family ID to save file as").force_expand_help(true) + + (option("--family") & + family_id("family_id").set(settings.family_id)) % "Specify the family ID to save the file as" + ( // note this parenthesis seems to help with error messages for say save --foo file_selection % "File to save to" + device_selection % "Source device selection" @@ -1125,10 +1129,10 @@ struct load_command : public cmd { return ( ( option("--ignore-partitions").set(settings.load.ignore_pt) % "When writing flash data, ignore the partition table and write to absolute space" + - (option("--family") % "Specify the family ID of the file to load" & - family_id("family_id").set(settings.family_id) % "family ID to use for load").force_expand_help(true) + - (option('p', "--partition") % "Specify the partition to load into" & - integer("partition").set(settings.load.partition) % "partition to load into").force_expand_help(true) + + (option("--family") & + family_id("family_id").set(settings.family_id)) % "Specify the family ID of the file to load" + + (option('p', "--partition") & + integer("partition").set(settings.load.partition)) % "Specify the partition to load into" + option('n', "--no-overwrite").set(settings.load.no_overwrite) % "When writing flash data, do not overwrite an existing program in flash. If picotool cannot determine the size/presence of the program in flash, the command fails" + option('N', "--no-overwrite-unsafe").set(settings.load.no_overwrite_force) % "When writing flash data, do not overwrite an existing program in flash. If picotool cannot determine the size/presence of the program in flash, the load continues anyway" + option('u', "--update").set(settings.load.update) % "Skip writing flash sectors that already contain identical data" + @@ -1136,10 +1140,10 @@ struct load_command : public cmd { option('x', "--execute").set(settings.load.execute) % "Perform a bootrom reboot to execute the downloaded file as a program after the load - either a flash update boot for binaries in flash, or a RAM image boot for other binaries " ).min(0).doc_non_optional(true) % "Load options" + file_selection % "File to load from" + - ( - option('o', "--offset").set(settings.offset_set) % "Specify the load address for a BIN file" & - hex("offset").set(settings.offset) % "Load offset (memory address; default 0x10000000)" - ).force_expand_help(true) % "BIN file options" + + as_section( + (option('o', "--offset").set(settings.offset_set) & + hex("offset").set(settings.offset)) % "Specify the load address for a BIN file (memory address; default 0x10000000)" + ).min(0).doc_non_optional(true) % "BIN file options" + device_selection % "Target device selection" ); } @@ -1192,9 +1196,9 @@ struct encrypt_command : public cmd { option("--fast-rosc").set(settings.encrypt.fast_rosc) % "Use ~180MHz ROSC configuration for embedded bootloader" + option("--use-mbedtls").set(settings.encrypt.use_mbedtls) % "Use MbedTLS implementation of embedded bootloader (faster but less secure)" + ( - option("--otp-key-page").set(settings.encrypt.otp_key_page_set) % "Specify the OTP page storing the AES key (IV salt is stored on the next page)" & - integer("page").set(settings.encrypt.otp_key_page) % "OTP page (default 29)" - ).force_expand_help(true) + + option("--otp-key-page").set(settings.encrypt.otp_key_page_set) & + integer("page").set(settings.encrypt.otp_key_page) + ) % "Specify the OTP page storing the AES key (default 29; IV salt is stored on the next page)" + ( option("--hash").set(settings.seal.hash) % "Hash the encrypted file" + option("--sign").set(settings.seal.sign) % "Sign the encrypted file" + @@ -1202,10 +1206,10 @@ struct encrypt_command : public cmd { option("--pin-xip-sram").set(settings.seal.pin_xip_sram) % "Pin XIP SRAM on load" ).min(0).doc_non_optional(true) % "Signing Configuration" + named_file_selection_x("infile", 0) % "File to load from" + - ( - option('o', "--offset").set(settings.offset_set) % "Specify the load address for a BIN file" & - hex("offset").set(settings.offset) % "Load offset (memory address; default 0x10000000)" - ).force_expand_help(true) % "BIN file options" + + as_section( + (option('o', "--offset").set(settings.offset_set) & + hex("offset").set(settings.offset)) % "Specify the load address for a BIN file (memory address; default 0x10000000)" + ).min(0).doc_non_optional(true) % "BIN file options" + named_file_selection_x("outfile", 1) % "File to save to" + named_untyped_file_selection_x("aes_key", 2) % "AES Key Share or AES Key" + named_untyped_file_selection_x("iv_salt", 3) % "IV Salt" + @@ -1236,10 +1240,10 @@ struct seal_command : public cmd { option("--no-squash").set(settings.seal.no_squash) % "Don't squash segments in the ELF file" ).min(0).doc_non_optional(true) % "Configuration" + named_file_selection_x("infile", 0) % "File to load from" + - ( - option('o', "--offset").set(settings.offset_set) % "Specify the load address for a BIN file" & - hex("offset").set(settings.offset) % "Load offset (memory address; default 0x10000000)" - ).force_expand_help(true) % "BIN file options" + + as_section( + (option('o', "--offset").set(settings.offset_set) & + hex("offset").set(settings.offset)) % "Specify the load address for a BIN file (memory address; default 0x10000000)" + ).min(0).doc_non_optional(true) % "BIN file options" + named_file_selection_x("outfile", 1) % "File to save to" + optional_untyped_file_selection_x("key", 2) % "Key file (.pem)" + optional_untyped_file_selection_x("otp", 3) % "JSON file to save OTP to (will edit existing file if it exists)" + @@ -1317,10 +1321,10 @@ struct partition_create_command : public cmd { named_untyped_file_selection_x("infile", 0) % "partition table JSON" + (named_file_selection_x("outfile", 1) % "output file" + ( - (option('o', "--offset").set(settings.offset_set) % "Specify the load address for UF2 file output" & - hex("offset").set(settings.offset) % "Load offset (memory address; default 0x10000000)").force_expand_help(true) + - (option("--family") % "Specify the family if for UF2 file output" & - family_id("family_id").set(settings.family_id) % "family ID for UF2 (default absolute)").force_expand_help(true) + (option('o', "--offset").set(settings.offset_set) & + hex("offset").set(settings.offset)) % "Specify the load address for UF2 file output (memory address; default 0x10000000)" + + (option("--family") & + family_id("family_id").set(settings.family_id)) % "Specify the family id for UF2 file output (default absolute)" ).min(0).force_expand_help(true) % "UF2 output options") + optional_typed_file_selection_x("bootloader", 2, "elf") % "embed partition table into bootloader ELF" + ( @@ -1563,7 +1567,9 @@ struct otp_white_label_command : public cmd { group get_cli() override { return ( - (option('s', "--start_row") & integer("row").set(settings.otp.row)) % "Start row for white label struct (default 0x100) (note use 0x for hex)" + + as_section( + (option('s', "--start_row") & integer("row").set(settings.otp.row)) % "Start row for white label struct (default 0x100) (note use 0x for hex)" + ).min(0).doc_non_optional(true) % "Row options" + named_untyped_file_selection_x("filename", 0) % "JSON file with white labelling values" + device_selection % "Target device selection" ); @@ -1623,18 +1629,18 @@ struct uf2_convert_command : public cmd { option("--verbose").set(settings.verbose) % "Print verbose output" + named_file_selection_x("infile", 0) % "File to load from" + named_typed_file_selection_x("outfile", 1, "uf2") % "File to save UF2 to" + - ( - option('o', "--offset").set(settings.offset_set) % "Specify the load address" & - hex("offset").set(settings.offset) % "Load offset (memory address; default 0x10000000 for BIN file)" - ).force_expand_help(true) % "Packaging Options" + - ( - option("--family") % "Specify the family ID" & - family_id("family_id").set(settings.family_id) % "family ID for UF2" - ).force_expand_help(true) % "UF2 Family options" + - ( - option("--platform") % "Optional platform for memory-address validation" & - platform_model("platform").set(settings.model) % "platform to use (eg rp2040, rp2350)" - ).force_expand_help(true) % "Platform options" + as_section( + (option('o', "--offset").set(settings.offset_set) & + hex("offset").set(settings.offset)) % "Specify the load address (memory address; default 0x10000000 for BIN file)" + ).min(0).doc_non_optional(true) % "Packaging Options" + + as_section( + (option("--family") & + family_id("family_id").set(settings.family_id)) % "Specify the family ID for UF2" + ).min(0).doc_non_optional(true) % "UF2 Family options" + + as_section( + (option("--platform") & + platform_model("platform").set(settings.model)) % "Optional platform for memory-address validation (eg rp2040, rp2350)" + ).min(0).doc_non_optional(true) % "Platform options" #if SUPPORT_RP2350_A2 + ( option("--abs-block").set(settings.uf2.abs_block) % "Add an absolute block" + @@ -1661,18 +1667,18 @@ struct uf2_combine_command : public cmd { named_typed_file_selection_x("infile1", 1, "uf2") % "First file to combine" + named_typed_file_selection_x("infile2", 2, "uf2") % "Second file to combine" + named_typed_file_selection_x("outfile", 0, "uf2") % "File to save output to" + - ( - option("--family") % "Specify the family ID" & - family_id("family_id").set(settings.family_id) % "family ID for combined UF2 (defaults to first one)" - ).force_expand_help(true) % "UF2 Family options" + - ( - option("--offset").set(settings.uf2.offset_set) % "Offset second UF2 by amount" & - hex("offset").set(settings.uf2.offset) % "offset amount (default to 0)" - ).force_expand_help(true) % "Offset options" + - ( - option("--partition").set(settings.uf2.partition_set) % "Place second UF2 in partition (first UF2 must contain a partition table)" & - integer("partition").min_value(0).max_value(PARTITION_TABLE_MAX_PARTITIONS-1).set(settings.uf2.partition) % "partition number (default to 0)" - ).force_expand_help(true) % "Partition options" + as_section( + (option("--family") & + family_id("family_id").set(settings.family_id)) % "Specify the family ID for combined UF2 (defaults to first one)" + ).min(0).doc_non_optional(true) % "UF2 Family options" + + as_section( + (option("--offset").set(settings.uf2.offset_set) & + hex("offset").set(settings.uf2.offset)) % "Offset second UF2 by amount" + ).min(0).doc_non_optional(true) % "Offset options" + + as_section( + (option("--partition").set(settings.uf2.partition_set) & + integer("partition").min_value(0).max_value(PARTITION_TABLE_MAX_PARTITIONS-1).set(settings.uf2.partition)) % "Place second UF2 in partition (first UF2 must contain a partition table)" + ).min(0).doc_non_optional(true) % "Partition options" #if SUPPORT_RP2350_A2 + ( option("--abs-block").set(settings.uf2.abs_block) % "Add an absolute block" + From bb950a4dd972842885eb4ca91b9d5f3243552766 Mon Sep 17 00:00:00 2001 From: William Vinnicombe Date: Thu, 16 Jul 2026 18:29:11 +0100 Subject: [PATCH 09/12] Clarify that uf2 info is RP2350-only, and add more (RP2350 only) printout Also ensure all lines end in full-stops --- README.md | 82 +++++++++++++++++++++++++++---------------------------- main.cpp | 49 ++++++++++++++++++--------------- 2 files changed, 68 insertions(+), 63 deletions(-) diff --git a/README.md b/README.md index edda9c36..f5a982cc 100644 --- a/README.md +++ b/README.md @@ -44,26 +44,26 @@ SYNOPSIS: picotool bdev ls|mkdir|cp|rm|cat|format COMMANDS: - help Show general help, or help for a specific command or topic - version Display picotool version + help Show general help, or help for a specific command or topic. + version Display picotool version. info Display information from the target device(s) or file. Without any arguments, this will display basic information for all connected - RP-series devices in BOOTSEL mode + RP-series devices in BOOTSEL mode. config Display or change program configuration settings from the target device(s) or file. load Load the program / memory range stored in a file onto the device. save Save the program / memory stored in flash on the device to a file. verify Check that the device contents match those in the file. erase Erase the program / memory stored in flash on the device. - reboot Reboot the device + reboot Reboot the device. seal Add final metadata to a binary, optionally including a hash and/or signature. encrypt Encrypt the program. - partition Commands related to RP2350 Partition Tables - uf2 Commands related to UF2 creation and status - otp Commands related to the RP2350 OTP (One-Time-Programmable) Memory + partition Commands related to RP2350 Partition Tables. + uf2 Commands related to UF2 creation and status. + otp Commands related to the RP2350 OTP (One-Time-Programmable) Memory. coprodis Post-process coprocessor instructions in disassembly files. link Link multiple binaries into one block loop. - bdev Commands related to embedded block devices + bdev Commands related to embedded block devices. TOPICS: device-selection Options for Target Device Selection and Rebooting @@ -90,7 +90,7 @@ Displays the picotool version, and also allows checking compatibility with an ex ```text $ picotool help version VERSION: - Display picotool version + Display picotool version. SYNOPSIS: picotool version [-s] [] @@ -149,7 +149,7 @@ $ picotool help info INFO: Display information from the target device(s) or file. Without any arguments, this will display basic information for all connected RP-series - devices in BOOTSEL mode + devices in BOOTSEL mode. SYNOPSIS: picotool info [-b] [-m] [-p] [-d] [--debug] [-l] [-a] [device-selection] @@ -530,7 +530,7 @@ Partition 1 ```text $ picotool help reboot REBOOT: - Reboot the device + Reboot the device. SYNOPSIS: picotool reboot [-a] [-u] [-g ] [-c ] [device-selection] @@ -738,7 +738,7 @@ By default, all partition tables are hashed, and you can also sign them. The sch ```text $ picotool help partition create PARTITION CREATE: - Create a partition table from json + Create a partition table from json. SYNOPSIS: picotool partition create [--quiet] [--verbose] [-t ] [[-o @@ -929,12 +929,12 @@ $ picotool load -x combined.uf2 ### info -This command reads the information on a device about why a UF2 download has failed. It will only give information if the most recent download has failed. +This command reads the information on an RP2350 device about why a UF2 download has failed. It will only give information if the most recent download has failed. ```text $ picotool help uf2 info UF2 INFO: - Print info about UF2 download. + Print info about UF2 download. (RP2350 only) SYNOPSIS: picotool uf2 info [device-selection] @@ -956,7 +956,7 @@ For the `list`, `set`, `get` and `load` commands, you can define your own OTP la ```text $ picotool help otp OTP: - Commands related to the RP2350 OTP (One-Time-Programmable) Memory + Commands related to the RP2350 OTP (One-Time-Programmable) Memory. SYNOPSIS: picotool otp get [-c ] [-r] [-e] [-n] [-i ] [device-selection] [-z] @@ -973,14 +973,14 @@ SYNOPSIS: picotool otp list [-p] [-n] [-f] [-i ] [..] SUB COMMANDS: - get Get the value of one or more OTP registers/fields (RP2350 only) - set Set the value of an OTP row/field (RP2350 only) + get Get the value of one or more OTP registers/fields. (RP2350 only) + set Set the value of an OTP row/field. (RP2350 only) load Load the row range stored in a file into OTP and verify. Data is 2 bytes/row for ECC, 4 bytes/row for raw (MSB is ignored). (RP2350 only) - white-label Set the white labelling values in OTP (RP2350 only) - permissions Set the OTP access permissions (RP2350 only) - dump Dump entire OTP (RP2350 only) - list List matching known registers/fields + white-label Set the white labelling values in OTP. (RP2350 only) + permissions Set the OTP access permissions. (RP2350 only) + dump Dump entire OTP. (RP2350 only) + list List matching known registers/fields. ``` ### get/set @@ -990,7 +990,7 @@ These commands will get/set specific rows of OTP. By default, they will read/wri ```text $ picotool help otp get OTP GET: - Get the value of one or more OTP registers/fields + Get the value of one or more OTP registers/fields. (RP2350 only) SYNOPSIS: picotool otp get [-c ] [-r] [-e] [-n] [-i ] [device-selection] [-z] @@ -1036,7 +1036,7 @@ TARGET SELECTION: ```text $ picotool help otp set OTP SET: - Set the value of an OTP row/field + Set the value of an OTP row/field. (RP2350 only) SYNOPSIS: picotool otp set [-c ] [-r] [-e] [-s] [-i ] [-z] @@ -1087,7 +1087,7 @@ This command allows loading of a range of OTP rows onto the device. The source c $ picotool help otp load OTP LOAD: Load the row range stored in a file into OTP and verify. Data is 2 bytes/row for ECC, 4 - bytes/row for raw (MSB is ignored). + bytes/row for raw (MSB is ignored). (RP2350 only) SYNOPSIS: picotool otp load [-r] [-e] [-s ] [-i ] [-t ] @@ -1128,7 +1128,7 @@ This can be configured from a JSON file, an example of which is in [sample-wl.js ```text $ picotool help otp white-label OTP WHITE-LABEL: - Set the white labelling values in OTP + Set the white labelling values in OTP. (RP2350 only) SYNOPSIS: picotool otp white-label [-s ] [device-selection] @@ -1191,7 +1191,7 @@ is in [sample-permissions.json](json/sample-permissions.json). The schema for th ```text $ picotool help otp permissions OTP PERMISSIONS: - Set the OTP access permissions + Set the OTP access permissions. (RP2350 only) SYNOPSIS: picotool otp permissions [--led ] [--hash] [--sign] [] @@ -1240,7 +1240,7 @@ This command will read the entire OTP contents and print it out as hex. ```text $ picotool help otp dump OTP DUMP: - Dump entire OTP + Dump entire OTP. (RP2350 only) SYNOPSIS: picotool otp dump [-r] [-e] [-p] [--output ] [device-selection] @@ -1274,7 +1274,7 @@ This command will list all the defined OTP rows & fields. You can list specific ```text $ picotool help otp list OTP LIST: - List matching known registers/fields + List matching known registers/fields. SYNOPSIS: picotool otp list [-p] [-n] [-f] [-i ] [..] @@ -1373,7 +1373,7 @@ The `bdev` commands are for interacting with block devices in Flash. The block d ```text $ picotool help bdev BDEV: - Commands related to embedded block devices + Commands related to embedded block devices. SYNOPSIS: picotool bdev ls [] [-r] [-p ] [--partition-name ] [-r] [-p ] [--partition-name [-p ] [--partition-name ] @@ -1488,7 +1488,7 @@ Copy file to/from the block device - use :filename to indicate files on the devi $ picotool help bdev cp BDEV CP: Copy file to/from the block device - use :filename to indicate files on the device (eg `cp - main.py :main.py` to upload to the device) + main.py :main.py` to upload to the device). SYNOPSIS: picotool bdev cp [-p ] [--partition-name ] @@ -1526,7 +1526,7 @@ Delete a file or an empty directory on the block device ```text $ picotool help bdev rm BDEV RM: - Delete a file or an empty directory on the block device + Delete a file or an empty directory on the block device. SYNOPSIS: picotool bdev rm [-p ] [--partition-name ] @@ -1562,7 +1562,7 @@ Print contents of file on the block device ```text $ picotool help bdev cat BDEV CAT: - Print contents of file on the block device + Print contents of file on the block device. SYNOPSIS: picotool bdev cat [-p ] [--partition-name ] @@ -1598,7 +1598,7 @@ Format the block device - may result in data loss ```text $ picotool help bdev format BDEV FORMAT: - Format the block device + Format the block device. SYNOPSIS: picotool bdev format [-p ] [--partition-name ] diff --git a/main.cpp b/main.cpp index 8a05d9ad..76302569 100644 --- a/main.cpp +++ b/main.cpp @@ -892,7 +892,7 @@ struct info_command : public cmd { string get_doc() const override { #if HAS_LIBUSB - return "Display information from the target device(s) or file.\nWithout any arguments, this will display basic information for all connected RP-series devices in BOOTSEL mode"; + return "Display information from the target device(s) or file.\nWithout any arguments, this will display basic information for all connected RP-series devices in BOOTSEL mode."; #else return "Display information from the target file."; #endif @@ -965,7 +965,7 @@ struct bdev_ls_command : public cmd { } string get_doc() const override { - return "List contents of the block device"; + return "List contents of the block device."; } }; @@ -982,7 +982,7 @@ struct bdev_mkdir_command : public cmd { } string get_doc() const override { - return "Create directory on the block device"; + return "Create directory on the block device."; } }; @@ -1000,7 +1000,7 @@ struct bdev_cp_command : public cmd { } string get_doc() const override { - return "Copy file to/from the block device - use :filename to indicate files on the device (eg `cp main.py :main.py` to upload to the device)"; + return "Copy file to/from the block device - use :filename to indicate files on the device (eg `cp main.py :main.py` to upload to the device)."; } }; @@ -1017,7 +1017,7 @@ struct bdev_rm_command : public cmd { } string get_doc() const override { - return "Delete a file or an empty directory on the block device"; + return "Delete a file or an empty directory on the block device."; } }; @@ -1034,7 +1034,7 @@ struct bdev_cat_command : public cmd { } string get_doc() const override { - return "Print contents of file on the block device"; + return "Print contents of file on the block device."; } }; @@ -1050,7 +1050,7 @@ struct bdev_format_command : public cmd { } string get_doc() const override { - return "Format the block device"; + return "Format the block device."; } }; @@ -1065,7 +1065,7 @@ vector> bdev_sub_commands { struct bdev_command : public multi_cmd { bdev_command() : multi_cmd("bdev", bdev_sub_commands) {} string get_doc() const override { - return "Commands related to embedded block devices"; + return "Commands related to embedded block devices."; } }; @@ -1349,7 +1349,7 @@ struct partition_create_command : public cmd { } string get_doc() const override { - return "Create a partition table from json"; + return "Create a partition table from json."; } }; @@ -1364,7 +1364,7 @@ vector> partition_sub_commands { struct partition_command : public multi_cmd { partition_command() : multi_cmd("partition", partition_sub_commands) {} string get_doc() const override { - return "Commands related to RP2350 Partition Tables"; + return "Commands related to RP2350 Partition Tables."; } }; @@ -1397,7 +1397,7 @@ struct otp_list_command : public cmd { } string get_doc() const override { - return "List matching known registers/fields"; + return "List matching known registers/fields."; } }; #if HAS_LIBUSB @@ -1436,7 +1436,7 @@ struct otp_get_command : public cmd { } string get_doc() const override { - return "Get the value of one or more OTP registers/fields"; + return "Get the value of one or more OTP registers/fields."; } }; @@ -1468,7 +1468,7 @@ struct otp_dump_command : public cmd { } string get_doc() const override { - return "Dump entire OTP"; + return "Dump entire OTP."; } }; @@ -1531,7 +1531,7 @@ struct otp_set_command : public cmd { } string get_doc() const override { - return "Set the value of an OTP row/field"; + return "Set the value of an OTP row/field."; } }; @@ -1555,7 +1555,7 @@ struct otp_permissions_command : public cmd { } string get_doc() const override { - return "Set the OTP access permissions"; + return "Set the OTP access permissions."; } }; @@ -1576,7 +1576,7 @@ struct otp_white_label_command : public cmd { } string get_doc() const override { - return "Set the white labelling values in OTP"; + return "Set the white labelling values in OTP."; } }; #endif @@ -1597,13 +1597,14 @@ vector> otp_sub_commands { struct otp_command : public multi_cmd { otp_command() : multi_cmd("otp", otp_sub_commands) {} string get_doc() const override { - return "Commands related to the RP2350 OTP (One-Time-Programmable) Memory"; + return "Commands related to the RP2350 OTP (One-Time-Programmable) Memory."; } }; #if HAS_LIBUSB struct uf2_info_command : public cmd { uf2_info_command() : cmd("info") {} + virtual bool requires_rp2350() const override { return true; } bool execute(device_map &devices) override; group get_cli() override { @@ -1704,7 +1705,7 @@ vector> uf2_sub_commands { struct uf2_command : public multi_cmd { uf2_command() : multi_cmd("uf2", uf2_sub_commands) {} string get_doc() const override { - return "Commands related to UF2 creation and status"; + return "Commands related to UF2 creation and status."; } }; @@ -1744,7 +1745,7 @@ struct help_command : public cmd { } string get_doc() const override { - return "Show general help, or help for a specific command or topic"; + return "Show general help, or help for a specific command or topic."; } }; @@ -1791,7 +1792,7 @@ struct version_command : public cmd { } string get_doc() const override { - return "Display picotool version"; + return "Display picotool version."; } }; @@ -1818,7 +1819,7 @@ struct reboot_command : public cmd { } string get_doc() const override { - return "Reboot the device"; + return "Reboot the device."; } }; auto reboot_cmd = std::shared_ptr(new reboot_command()); @@ -1937,7 +1938,11 @@ int parse(const int argc, char **argv) { if (help_mode && selected_cmd) { section_header(help_mode_prefix + selected_cmd->name()); fos.first_column(tab); - fos << selected_cmd->get_doc() << "\n"; + fos << selected_cmd->get_doc(); + if (selected_cmd->requires_rp2350()) { + fos << " (RP2350 only)"; + } + fos << "\n"; } else if (!selected_cmd && !no_global_header) { section_header(tool_name); fos.first_column(tab); From a21dc67e53580d599013bc6311d4c2860d115ef5 Mon Sep 17 00:00:00 2001 From: William Vinnicombe Date: Thu, 16 Jul 2026 19:07:23 +0100 Subject: [PATCH 10/12] Add "Use "picotool help uf2 " for more info" to end of `picotool help uf2` etc --- README.md | 4 ++++ main.cpp | 8 ++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f5a982cc..8ee1fa04 100644 --- a/README.md +++ b/README.md @@ -981,6 +981,8 @@ SUB COMMANDS: permissions Set the OTP access permissions. (RP2350 only) dump Dump entire OTP. (RP2350 only) list List matching known registers/fields. + +Use "picotool help otp " for more info ``` ### get/set @@ -1403,6 +1405,8 @@ SUB COMMANDS: rm Delete a file or an empty directory on the block device. cat Print contents of file on the block device. format Format the block device. + +Use "picotool help bdev " for more info ``` ### ls diff --git a/main.cpp b/main.cpp index 76302569..82261bf3 100644 --- a/main.cpp +++ b/main.cpp @@ -2070,11 +2070,15 @@ int parse(const int argc, char **argv) { } else { print_options_for(selected_cmd->get_cli()); } - if (!selected_cmd) { + if (!selected_cmd || selected_cmd->is_multi()) { fos.first_column(0); fos.hanging_indent(0); fos.wrap_hard(); - fos << "Use \"picotool help \" or \"picotool help \" for more info\n"; + if (selected_cmd) { + fos << "Use \"picotool help " << selected_cmd->name() << " \" for more info\n"; + } else { + fos << "Use \"picotool help \" or \"picotool help \" for more info\n"; + } #if !HAS_LIBUSB if (!help_mode) { fos << built_without_libusb_message; From 44caf275120132551151d9ac67a30dc1299f3975 Mon Sep 17 00:00:00 2001 From: William Vinnicombe Date: Thu, 16 Jul 2026 19:15:29 +0100 Subject: [PATCH 11/12] Support --version, but print warning when it is used --- main.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/main.cpp b/main.cpp index 82261bf3..900c7d41 100644 --- a/main.cpp +++ b/main.cpp @@ -2090,6 +2090,12 @@ int parse(const int argc, char **argv) { auto args = cli::make_args(argc, argv); + // Check if the only argument is --version, if so replace it with version + if (args[0] == "--version" && args.size() == 1) { + printf("WARNING: Use \"picotool version\" instead of \"picotool --version\"\n"); + args[0] = "version"; + } + // Check if any -h or --help argument was requested, if so insert the help subcommand before any // arguments, this will ensure the correct help gets printed automatically. bool help_requested = std::find(args.begin(), args.end(), "--help") != args.end() From 503fe3fc1c558a395f38d871aebcc18940271a44 Mon Sep 17 00:00:00 2001 From: William Vinnicombe Date: Thu, 16 Jul 2026 19:29:36 +0100 Subject: [PATCH 12/12] Add super-commands to the README --- README.md | 41 +++++++++++++++++++++++++++++++++++++++++ gen_help_txt.sh | 4 ++-- 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 8ee1fa04..18d35ddd 100644 --- a/README.md +++ b/README.md @@ -695,6 +695,25 @@ OPTIONS: The `partition` commands allow you to interact with the partition tables on RP2350 devices, and also create them. +```text +$ picotool help partition +PARTITION: + Commands related to RP2350 Partition Tables. + +SYNOPSIS: + picotool partition info [-m ] [device-selection] + picotool partition create [--quiet] [--verbose] [-t ] [[-o + ] [--family ]] [] [-t ] [[--sign + ] [-t ] [--no-hash] [--singleton] [--no-btstack-flash-bank]] + [[--abs-block] []] + +SUB COMMANDS: + info Print the device's partition table. + create Create a partition table from json. + +Use "picotool help partition " for more info +``` + ### info ```text @@ -790,6 +809,28 @@ OPTIONS: The `uf2` commands allow for creation of UF2s, and can provide information if a UF2 download has failed. +```text +$ picotool help uf2 +UF2: + Commands related to UF2 creation and status. + +SYNOPSIS: + picotool uf2 convert [--quiet] [--verbose] [-t ] [-t ] [-o + ] [--family ] [--platform ] [[--abs-block] + []] + picotool uf2 combine [--quiet] [--verbose] [-t ] [-t ] + [-t ] [--family ] [--offset ] [--partition + ] [[--abs-block] []] + picotool uf2 info [device-selection] + +SUB COMMANDS: + convert Convert ELF/BIN to UF2. + combine Combine multiple UF2 files. + info Print info about UF2 download. (RP2350 only) + +Use "picotool help uf2 " for more info +``` + ### convert This command replaces the elf2uf2 functionality that was previously in the Raspberry Pi Pico SDK. It will attempt to auto-detect the family ID, but if this fails you can specify one manually with the `--family` argument. diff --git a/gen_help_txt.sh b/gen_help_txt.sh index 9b929a31..1e6b679a 100755 --- a/gen_help_txt.sh +++ b/gen_help_txt.sh @@ -70,7 +70,7 @@ echo "Checking for missing help text sections..." missing_commands=() while IFS= read -r cmd; do if [ ! -z "$cmd" ]; then - if ! grep -q "\$ picotool help $cmd" tmp/README.md; then + if ! grep -qxF "\$ picotool help $cmd" tmp/README.md; then missing_commands+=("$cmd") echo "Missing help text section for command: $cmd" fi @@ -103,7 +103,7 @@ echo "Checking for missing help topic sections..." missing_topics=() while IFS= read -r topic; do if [ ! -z "$topic" ]; then - if ! grep -q "\$ picotool help $topic" tmp/README.md; then + if ! grep -qxF "\$ picotool help $topic" tmp/README.md; then missing_topics+=("$topic") echo "Missing help text section for topic: $topic" fi