diff --git a/README.md b/README.md index d3ec328f..18d35ddd 100644 --- a/README.md +++ b/README.md @@ -44,34 +44,38 @@ SYNOPSIS: picotool bdev ls|mkdir|cp|rm|cat|format COMMANDS: - help Show general help or help for a specific command - 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. -Use "picotool help " for more info +TOPICS: + device-selection Options for Target Device Selection and Rebooting + family-ids Valid Family IDs + +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 -[`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 +[`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 @@ -79,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` @@ -92,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] @@ -116,39 +173,12 @@ OPTIONS: Include all information 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) + To target one or more connected RP-series device(s) (the default) + See "picotool help device-selection" for available options To target a file The file name - -t + -t, --type Specify file type (uf2 | elf | bin) explicitly, ignoring file extension ``` @@ -225,47 +255,18 @@ 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: - 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) + To target one or more connected RP-series device(s) (the default) + See "picotool help device-selection" for available options To target a file The file name - -t + -t, --type Specify file type (uf2 | elf | bin) explicitly, ignoring file extension ``` @@ -312,17 +313,13 @@ 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 + --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 @@ -341,42 +338,13 @@ 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 - --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. @@ -417,44 +385,15 @@ 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 - --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... @@ -498,48 +437,16 @@ 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 - --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 @@ -572,35 +479,8 @@ OPTIONS: The lower address bound in hex 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) + Target device selection + See "picotool help device-selection" for available options ``` e.g. first looking at what is on the device... @@ -650,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] @@ -661,39 +541,12 @@ 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 - --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 @@ -747,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 ``` @@ -805,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 @@ -829,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 ``` @@ -847,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 @@ -858,37 +725,10 @@ SYNOPSIS: picotool partition info [-m ] [device-selection] OPTIONS: - -m + -m, --family 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 @@ -917,7 +757,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 @@ -935,26 +775,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 @@ -973,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. @@ -995,28 +853,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 @@ -1046,33 +898,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 @@ -1124,46 +970,19 @@ $ 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] 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 @@ -1178,7 +997,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] @@ -1187,7 +1006,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] @@ -1195,24 +1014,26 @@ 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. + +Use "picotool help otp " for more info ``` -### 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 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] @@ -1220,7 +1041,7 @@ SYNOPSIS: OPTIONS: Row/field options - -c + -c, --copies Read multiple redundant values -r, --raw Get raw 24-bit values @@ -1228,7 +1049,7 @@ OPTIONS: Use error correction -n, --no-descriptions Don't show descriptions - -i + -i, --include Include extra otp definition Row/Field Selection -z, --fuzzy @@ -1252,40 +1073,13 @@ 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 $ 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] @@ -1293,7 +1087,7 @@ SYNOPSIS: OPTIONS: Redundancy/Error Correction Overrides - -c + -c, --copies Write multiple redundant values -r, --raw Set raw 24-bit values @@ -1301,7 +1095,7 @@ OPTIONS: Use error correction -s, --set-bits Set bits only - -i + -i, --include Include extra otp definition The value to set @@ -1325,34 +1119,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 @@ -1363,56 +1130,29 @@ 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 ] [device-selection] -OPTIONS: - Row options - -r, --raw - Set raw 24-bit values. This is the default for BIN files - -e, --ecc - Use error correction - -s - Start row to load at (note use 0x for hex) - -i - Include extra otp definition - File to load row(s) from - - The file name - -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) +OPTIONS: + Row options + -r, --raw + Set raw 24-bit values. This is the default for BIN files + -e, --ecc + Use error correction + -s, --start_row + Start row to load at (note use 0x for hex) + -i, --include + Include extra otp definition + File to load row(s) from + + The file name + -t, --type + Specify file type (json | bin) explicitly, ignoring file extension + Target device selection + 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: @@ -1431,43 +1171,19 @@ 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] + picotool otp white-label [-s ] [device-selection] OPTIONS: + Row options + -s, --start_row + Start row for white label struct (default 0x100) (note use 0x for hex) 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 @@ -1510,7 +1226,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) @@ -1518,7 +1234,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] [] @@ -1537,34 +1253,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 @@ -1594,7 +1283,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] @@ -1613,38 +1302,11 @@ 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 - -t + -t, --type Specify file type (json) explicitly, ignoring file extension ``` @@ -1655,7 +1317,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 ] [..] @@ -1668,7 +1330,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: @@ -1729,17 +1391,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 @@ -1754,7 +1416,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 " for more info ``` ### ls @@ -1793,7 +1457,7 @@ List contents of the block device ```text $ picotool help bdev ls BDEV LS: - List contents of the block device + List contents of the block device. SYNOPSIS: picotool bdev ls [] [-r] [-p ] [--partition-name 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 @@ -1829,34 +1485,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 @@ -1866,7 +1495,7 @@ Create directory on the block device ```text $ picotool help bdev mkdir BDEV MKDIR: - Create directory on the block device + Create directory on the block device. SYNOPSIS: picotool bdev mkdir [-p ] [--partition-name ] @@ -1877,22 +1506,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 @@ -1900,34 +1521,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 @@ -1939,7 +1533,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 ] @@ -1952,22 +1546,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 @@ -1975,34 +1561,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 @@ -2012,7 +1571,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 ] @@ -2023,22 +1582,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 @@ -2046,34 +1597,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 @@ -2083,7 +1607,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 ] @@ -2094,22 +1618,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 @@ -2117,34 +1633,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 @@ -2154,7 +1643,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 ] @@ -2163,27 +1652,40 @@ 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 Allow writing, even if the block device is not marked as writeable Target device selection + 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 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 Filter devices by USB bus number --address @@ -2214,6 +1716,20 @@ OPTIONS: 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 @@ -2401,27 +1917,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 @@ -2434,6 +1936,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 @@ -2443,9 +1946,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/cli.h b/cli.h index bfaae401..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; } @@ -653,6 +661,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 + "]"; @@ -661,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) { @@ -763,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()) { @@ -772,6 +798,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 +938,7 @@ namespace cli { private: string _major_group; + string _help_topic; group_type type; vector> elements; bool _no_match_beats_error = true; diff --git a/gen_help_txt.sh b/gen_help_txt.sh index 7fd00c01..1e6b679a 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 @@ -23,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 @@ -72,11 +70,9 @@ 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 [[ ! "$ALLOWED_MISSING_COMMANDS" =~ "$cmd" ]]; then - missing_commands+=("$cmd") - echo "Missing help text section for command: $cmd" - fi + if ! grep -qxF "\$ picotool help $cmd" tmp/README.md; then + missing_commands+=("$cmd") + echo "Missing help text section for command: $cmd" fi fi done <<< "$commands" @@ -97,17 +93,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 -qxF "\$ 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 ' ' '|'))$" | \ + grep -vE "^(help)$" | \ 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 @@ -118,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 @@ -143,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 @@ -153,13 +195,13 @@ 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" -# 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 diff --git a/main.cpp b/main.cpp index 19a9106a..900c7d41 100644 --- a/main.cpp +++ b/main.cpp @@ -723,7 +723,37 @@ 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 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 + { "family-ids", { + "Valid Family IDs", + family_id_help_text() + } }, +}; #define file_types_x(i)\ (option ('t', "--type") & value("type").set(settings.file_types[i]))\ @@ -818,6 +848,10 @@ auto device_selection = 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) { @@ -849,7 +883,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) @@ -858,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 @@ -878,13 +912,13 @@ 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 - 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) @@ -902,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"; @@ -931,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."; } }; @@ -948,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."; } }; @@ -966,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)."; } }; @@ -983,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."; } }; @@ -1000,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."; } }; @@ -1016,7 +1050,7 @@ struct bdev_format_command : public cmd { } string get_doc() const override { - return "Format the block device"; + return "Format the block device."; } }; @@ -1031,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."; } }; @@ -1043,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" ); @@ -1074,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" @@ -1095,21 +1129,21 @@ 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" + 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" & - 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" ); } @@ -1138,7 +1172,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" ) ); } @@ -1162,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" + @@ -1172,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" + @@ -1206,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)" + @@ -1287,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" + ( @@ -1315,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."; } }; @@ -1330,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."; } }; @@ -1363,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 @@ -1402,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."; } }; @@ -1434,7 +1468,7 @@ struct otp_dump_command : public cmd { } string get_doc() const override { - return "Dump entire OTP"; + return "Dump entire OTP."; } }; @@ -1497,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."; } }; @@ -1521,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."; } }; @@ -1533,7 +1567,7 @@ struct otp_white_label_command : public cmd { group get_cli() override { return ( - ( + 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" + @@ -1542,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 @@ -1563,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 { @@ -1595,18 +1630,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" + @@ -1633,18 +1668,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" + @@ -1670,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."; } }; @@ -1710,7 +1745,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."; } }; @@ -1757,7 +1792,7 @@ struct version_command : public cmd { } string get_doc() const override { - return "Display picotool version"; + return "Display picotool version."; } }; @@ -1784,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()); @@ -1854,18 +1889,60 @@ 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) { 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); @@ -1931,6 +2008,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 +2023,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,36 +2068,17 @@ 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) { + if (!selected_cmd || selected_cmd->is_multi()) { fos.first_column(0); fos.hanging_indent(0); fos.wrap_hard(); - fos << "Use \"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; @@ -2016,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() @@ -2079,6 +2159,12 @@ int parse(const int argc, char **argv) { usage(); return 0; } else { + auto topic = help_topics.find(args[0]); + if (topic != help_topics.end()) { + selected_cmd = nullptr; + 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() + " ";