diff --git a/README.md b/README.md index d3ec328f..21b67f88 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,7 @@ SYNOPSIS: picotool erase -p [device-selection] picotool erase -r [device-selection] picotool reboot [-a] [-u] [-g ] [-c ] [device-selection] + picotool list picotool seal [--quiet] [--verbose] [--hash] [--sign] [--clear] [--pin-xip-sram] [--no-squash] [-t ] [-o ] [-t ] [] [] [--major ] [--minor ] [--rollback [..]] @@ -56,6 +57,7 @@ COMMANDS: 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 + list List all connected RP-series devices 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 @@ -71,7 +73,7 @@ Use "picotool help " for more info Note commands that aren't acting on files require a device in BOOTSEL mode to be connected. ## Links to documentation for `picotool` commands -[`info`](#info) [`config`](#config) [`load`](#load) [`save`](#save) [`verify`](#verify) [`erase`](#erase) [`reboot`](#reboot) [`seal`](#seal) [`encrypt`](#encrypt) [`partition`](#partition) [`uf2`](#uf2) [`otp`](#otp) [`coprodis`](#coprodis) [`link`](#link) [`bdev`](#bdev) +[`info`](#info) [`config`](#config) [`load`](#load) [`save`](#save) [`verify`](#verify) [`erase`](#erase) [`reboot`](#reboot) [`list`](#list) [`seal`](#seal) [`encrypt`](#encrypt) [`partition`](#partition) [`uf2`](#uf2) [`otp`](#otp) [`coprodis`](#coprodis) [`link`](#link) [`bdev`](#bdev) ## Building & Installing @@ -130,6 +132,10 @@ TARGET SELECTION: --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 + --debugprobe + Force a DebugProbe device using firmware version >2.3.1 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 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 @@ -139,6 +145,8 @@ TARGET SELECTION: 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 + --only-force + Same as --force, but will ignore devices already in BOOTSEL mode --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 @@ -247,6 +255,10 @@ TARGET SELECTION: --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 + --debugprobe + Force a DebugProbe device using firmware version >2.3.1 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 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 @@ -256,6 +268,8 @@ TARGET SELECTION: 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 + --only-force + Same as --force, but will ignore devices already in BOOTSEL mode --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 @@ -362,6 +376,10 @@ OPTIONS: --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 + --debugprobe + Force a DebugProbe device using firmware version >2.3.1 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 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 @@ -371,6 +389,8 @@ OPTIONS: 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 + --only-force + Same as --force, but will ignore devices already in BOOTSEL mode --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 @@ -440,6 +460,10 @@ OPTIONS: --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 + --debugprobe + Force a DebugProbe device using firmware version >2.3.1 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 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 @@ -449,6 +473,8 @@ OPTIONS: 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 + --only-force + Same as --force, but will ignore devices already in BOOTSEL mode --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 @@ -525,6 +551,10 @@ OPTIONS: --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 + --debugprobe + Force a DebugProbe device using firmware version >2.3.1 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 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 @@ -534,6 +564,8 @@ OPTIONS: 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 + --only-force + Same as --force, but will ignore devices already in BOOTSEL mode --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 @@ -586,6 +618,10 @@ OPTIONS: --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 + --debugprobe + Force a DebugProbe device using firmware version >2.3.1 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 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 @@ -595,6 +631,8 @@ OPTIONS: 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 + --only-force + Same as --force, but will ignore devices already in BOOTSEL mode --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 @@ -679,6 +717,10 @@ OPTIONS: --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 + --debugprobe + Force a DebugProbe device using firmware version >2.3.1 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 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 @@ -688,6 +730,8 @@ OPTIONS: 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 + --only-force + Same as --force, but will ignore devices already in BOOTSEL mode --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 @@ -696,6 +740,58 @@ OPTIONS: The BOOTSEL activity LED is active low (ignored by RP2040 and RP2350-A4) ``` +## list + +`list` allows you to list all connected RP-series devices + +```text +$ picotool help list +LIST: + List all connected RP-series devices + +SYNOPSIS: + picotool list +``` + +For example, with a DebugProbe and an RP2350 connected: + +```text +$ picotool list +Detected 2 RP-series devices: + + RP2350 device at bus 1, address 31 appears to have a USB reset interface, so consider -f (or + -F) to force reboot in order to run the command. + + RP2040 device at bus 1, address 32 appears to be a DebugProbe with a USB reset interface, so + consider --debugprobe to force reboot it in order to run the command. + +``` + +Then after running `picotool reboot -f -u`: + +```text +$ picotool list +Detected 2 RP-series devices: + + RP2350 device at bus 1, address 33 appears to be in BOOTSEL mode. + + RP2040 device at bus 1, address 32 appears to be a DebugProbe with a USB reset interface, so + consider --debugprobe to force reboot it in order to run the command. + +``` + +And also running `picotool reboot --debugprobe -u`: + +```text +$ picotool list +Detected 2 RP-series devices: + + RP2040 device at bus 1, address 34 appears to be in BOOTSEL mode. + + RP2350 device at bus 1, address 33 appears to be in BOOTSEL mode. + +``` + ## seal `seal` allows you to sign and/or hash a binary to run on RP2350. @@ -874,6 +970,10 @@ OPTIONS: --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 + --debugprobe + Force a DebugProbe device using firmware version >2.3.1 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 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 @@ -883,6 +983,8 @@ OPTIONS: 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 + --only-force + Same as --force, but will ignore devices already in BOOTSEL mode --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 @@ -1149,6 +1251,10 @@ OPTIONS: --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 + --debugprobe + Force a DebugProbe device using firmware version >2.3.1 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 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 @@ -1158,6 +1264,8 @@ OPTIONS: 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 + --only-force + Same as --force, but will ignore devices already in BOOTSEL mode --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 @@ -1265,6 +1373,10 @@ TARGET SELECTION: --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 + --debugprobe + Force a DebugProbe device using firmware version >2.3.1 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 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 @@ -1274,6 +1386,8 @@ TARGET SELECTION: 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 + --only-force + Same as --force, but will ignore devices already in BOOTSEL mode --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 @@ -1338,6 +1452,10 @@ TARGET SELECTION: --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 + --debugprobe + Force a DebugProbe device using firmware version >2.3.1 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 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 @@ -1347,6 +1465,8 @@ TARGET SELECTION: 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 + --only-force + Same as --force, but will ignore devices already in BOOTSEL mode --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 @@ -1398,6 +1518,10 @@ OPTIONS: --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 + --debugprobe + Force a DebugProbe device using firmware version >2.3.1 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 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 @@ -1407,6 +1531,8 @@ OPTIONS: 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 + --only-force + Same as --force, but will ignore devices already in BOOTSEL mode --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 @@ -1453,6 +1579,10 @@ OPTIONS: --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 + --debugprobe + Force a DebugProbe device using firmware version >2.3.1 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 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 @@ -1462,6 +1592,8 @@ OPTIONS: 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 + --only-force + Same as --force, but will ignore devices already in BOOTSEL mode --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 @@ -1550,6 +1682,10 @@ OPTIONS: --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 + --debugprobe + Force a DebugProbe device using firmware version >2.3.1 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 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 @@ -1559,6 +1695,8 @@ OPTIONS: 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 + --only-force + Same as --force, but will ignore devices already in BOOTSEL mode --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 @@ -1626,6 +1764,10 @@ TARGET SELECTION: --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 + --debugprobe + Force a DebugProbe device using firmware version >2.3.1 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 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 @@ -1635,6 +1777,8 @@ TARGET SELECTION: 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 + --only-force + Same as --force, but will ignore devices already in BOOTSEL mode --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 @@ -1842,6 +1986,10 @@ OPTIONS: --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 + --debugprobe + Force a DebugProbe device using firmware version >2.3.1 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 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 @@ -1851,6 +1999,8 @@ OPTIONS: 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 + --only-force + Same as --force, but will ignore devices already in BOOTSEL mode --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 @@ -1913,6 +2063,10 @@ OPTIONS: --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 + --debugprobe + Force a DebugProbe device using firmware version >2.3.1 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 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 @@ -1922,6 +2076,8 @@ OPTIONS: 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 + --only-force + Same as --force, but will ignore devices already in BOOTSEL mode --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 @@ -1988,6 +2144,10 @@ OPTIONS: --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 + --debugprobe + Force a DebugProbe device using firmware version >2.3.1 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 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 @@ -1997,6 +2157,8 @@ OPTIONS: 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 + --only-force + Same as --force, but will ignore devices already in BOOTSEL mode --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 @@ -2059,6 +2221,10 @@ OPTIONS: --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 + --debugprobe + Force a DebugProbe device using firmware version >2.3.1 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 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 @@ -2068,6 +2234,8 @@ OPTIONS: 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 + --only-force + Same as --force, but will ignore devices already in BOOTSEL mode --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 @@ -2130,6 +2298,10 @@ OPTIONS: --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 + --debugprobe + Force a DebugProbe device using firmware version >2.3.1 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 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 @@ -2139,6 +2311,8 @@ OPTIONS: 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 + --only-force + Same as --force, but will ignore devices already in BOOTSEL mode --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 @@ -2197,6 +2371,10 @@ OPTIONS: --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 + --debugprobe + Force a DebugProbe device using firmware version >2.3.1 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 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 @@ -2206,6 +2384,8 @@ OPTIONS: 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 + --only-force + Same as --force, but will ignore devices already in BOOTSEL mode --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 diff --git a/main.cpp b/main.cpp index d53d5301..261c8e9f 100644 --- a/main.cpp +++ b/main.cpp @@ -519,7 +519,7 @@ struct bdev_fs : public cli::value_base { struct cmd { explicit cmd(string name) : _name(std::move(name)) {} virtual ~cmd() = default; - enum device_support { none, one, zero_or_more }; + enum device_support { none, one, zero_or_more, any }; virtual group get_cli() = 0; virtual string get_doc() const = 0; virtual device_support get_device_support() { return one; } @@ -562,6 +562,7 @@ struct _settings { int led=DEFAULT_BOOTSEL_LED; bool active_low=false; bool force_rp2040 = false; + bool target_debugprobe = false; uint32_t offset = 0; uint32_t from = 0; uint32_t to = 0; @@ -573,6 +574,7 @@ struct _settings { int reboot_diagnostic_partition = BOOT_PARTITION_NONE; bool force = false; bool force_no_reboot = false; + bool only_force = false; string switch_cpu; uint32_t family_id = 0; model_t model = nullptr; @@ -708,12 +710,14 @@ auto device_selection = .if_missing([] { return "missing bus number"; })) % "Filter devices by USB bus number" + (option("--address") & integer("addr").min_value(1).max_value(127).set(settings.address) .if_missing([] { return "missing address"; })) % "Filter devices by USB device address" + - (option("--vid") & integer("vid").set(settings.vid).if_missing([] { return "missing vid"; })) % "Filter by vendor id" + + (option("--vid") & integer("vid").set(settings.vid).min(1).if_missing([] { return "missing vid"; })) % "Filter by vendor id" + (option("--pid") & integer("pid").set(settings.pid)) % "Filter by product id" + (option("--ser") & value("ser").set(settings.ser)) % "Filter by serial number" + option("--rp2040").set(settings.force_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" + + option("--debugprobe").set(settings.target_debugprobe) % "Force a DebugProbe device using firmware version >2.3.1 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" + option('f', "--force").set(settings.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" + option('F', "--force-no-reboot").set(settings.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" + + option("--only-force").set(settings.only_force) % "Same as --force, but will ignore devices already in BOOTSEL mode" + (option("--bootsel-led") & integer("gpio").set(settings.led)) % "Specify the GPIO for the BOOTSEL activity LED to flash (default " #if DEFAULT_BOOTSEL_LED < 0 @@ -1762,6 +1766,23 @@ struct version_command : public cmd { }; #if HAS_LIBUSB +struct list_command : public cmd { + list_command() : cmd("list") {} + bool execute(device_map &devices) override; + + device_support get_device_support() override { + return device_support::any; + } + + group get_cli() override { + return group(); + } + + string get_doc() const override { + return "List all connected RP-series devices"; + } +}; + struct reboot_command : public cmd { bool quiet; reboot_command() : cmd("reboot") {} @@ -1802,6 +1823,7 @@ vector> commands { std::shared_ptr(new verify_command()), std::shared_ptr(new erase_command()), reboot_cmd, + std::shared_ptr(new list_command()), #endif #if HAS_MBEDTLS std::shared_ptr(new seal_command()), @@ -4451,6 +4473,14 @@ string missing_device_string(bool wasRetry, bool requires_rp2350 = false) { } } else if (settings.bus != -1) { snprintf(buf, buf_len, "accessible %s devices in BOOTSEL mode were found on bus %d.", device_name, settings.bus); + } else if (settings.vid > 0) { + if (settings.pid != -1) { + snprintf(buf, buf_len, "accessible %s devices in BOOTSEL mode were found with vid %04x, pid %04x.", device_name, settings.vid, settings.pid); + } else { + snprintf(buf, buf_len, "accessible %s devices in BOOTSEL mode were found with vid %04x.", device_name, settings.vid); + } + } else if (settings.pid != -1) { + snprintf(buf, buf_len, "accessible %s devices in BOOTSEL mode were found with pid %04x.", device_name, settings.pid); } else if (!settings.ser.empty()) { snprintf(buf, buf_len, "accessible %s devices in BOOTSEL mode were found with serial number %s.", device_name, settings.ser.c_str()); } else { @@ -10054,8 +10084,8 @@ bool reboot_command::execute(device_map &devices) { if (!settings.switch_cpu.empty()) { fail(ERROR_ARGS, "--cpu may not be specified for forced reboot"); } - selected_chip = std::get<0>(devices[dr_vidpid_stdio_usb][0]); - reboot_device(std::get<1>(devices[dr_vidpid_stdio_usb][0]), std::get<2>(devices[dr_vidpid_stdio_usb][0]), settings.reboot_usb); + selected_chip = std::get<0>(devices[dr_vidpid_usb_reset][0]); + reboot_device(std::get<1>(devices[dr_vidpid_usb_reset][0]), std::get<2>(devices[dr_vidpid_usb_reset][0]), settings.reboot_usb); if (!quiet) { if (settings.reboot_usb) { std::cout << "The device was asked to reboot into BOOTSEL mode.\n"; @@ -10132,6 +10162,98 @@ bool reboot_command::execute(device_map &devices) { } return true; } + +static void print_device_info(device_map &devices, bool had_note=false, bool include_bootsel=false) { + auto printer = [&](enum picoboot_device_result r, const string &description) { + if (!had_note && !devices[r].empty()) { + fos << "\nbut:\n\n"; + had_note = true; + } + for (auto d : devices[r]) { + fos << bus_device_string(std::get<1>(d), std::get<0>(d)) << description << "\n"; + } + }; + + // Devices in BOOTSEL + if (settings.target_debugprobe) { + printer(dr_vidpid_bootrom_ok, + " appears to already be in BOOTSEL mode, but --debugprobe was passed so this is only targetting DebugProbes not already in BOOTSEL mode."); + } else if (settings.only_force) { + printer(dr_vidpid_bootrom_ok, + " appears to already be in BOOTSEL mode, but --only-force was passed so this is only targetting devices not already in BOOTSEL mode."); + } else if (include_bootsel) { + printer(dr_vidpid_bootrom_ok, + " appears to be in BOOTSEL mode."); + } + + // Devices missing required interfaces, so cannot be used by picotool + if (settings.vid != 0) { // if vid=0, vid/pid filtering is skipped, so this is returned for every accessible device (e.g. every USB device with sudo) + printer(dr_vidpid_bootrom_no_interface, + " was tried, but it does not have a PICOBOOT interface."); + } + printer(dr_vidpid_debugprobe_no_reset, + " appears to be a DebugProbe without a USB reset interface, so must be manually put into BOOTSEL mode."); + printer(dr_vidpid_stdio_usb_no_reset, + " appears to have a USB serial connection, but it does not have a USB reset interface so must be manually put into BOOTSEL mode."); + if (selected_cmd->force_requires_pre_reboot()) { + printer(dr_vidpid_usb_reset, + " appears to have a USB reset interface, so consider -f (or -F) to force reboot in order to run the command."); + } else { + // special case message for what is actually just reboot (the only command that doesn't require reboot first) + printer(dr_vidpid_usb_reset, + " appears to have a USB reset interface, so consider -f to force the reboot."); + } + + // Devices failed to open (e.g. requires sudo) +#if defined(__linux__) || defined(__APPLE__) + printer(dr_vidpid_bootrom_cant_connect, + " appears to be in BOOTSEL mode, but picotool was unable to connect. Maybe try 'sudo' or check your permissions."); + printer(dr_vidpid_stdio_usb_cant_connect, + " appears to have a USB serial connection, but picotool was unable to connect. Maybe try 'sudo' or check your permissions."); + printer(dr_vidpid_debugprobe_cant_connect, + " appears to be a DebugProbe, but picotool was unable to connect. Maybe try 'sudo' or check your permissions."); + printer(dr_vidpid_cant_connect, + " was tried, but picotool was unable to connect. Maybe try 'sudo' or check your permissions."); +#else + printer(dr_vidpid_bootrom_cant_connect, + " appears to be in BOOTSEL mode, but picotool was unable to connect. You may need to install a driver via Zadig. See Zadig in the README (https://github.com/raspberrypi/picotool#zadig) for more information"); + printer(dr_vidpid_stdio_usb_cant_connect, + " appears to have a USB serial connection, but picotool was unable to connect."); + printer(dr_vidpid_debugprobe_cant_connect, + " appears to be a DebugProbe, but picotool was unable to connect."); + printer(dr_vidpid_cant_connect, + " was tried, but picotool was unable to connect."); +#endif + + // Other known pids + printer(dr_vidpid_debugprobe, + " appears to be a DebugProbe with a USB reset interface, so consider --debugprobe to force reboot it in order to run the command."); + printer(dr_vidpid_micropython, + " appears to be running MicroPython, so must be manually put into BOOTSEL mode."); + printer(dr_vidpid_circuitpython, + " appears to be running CircuitPython, so must be manually put into BOOTSEL mode."); + printer(dr_vidpid_debugprobe_old, + " appears to be a DebugProbe running old firmware - you should manually put it into BOOTSEL mode and update the firmware (https://github.com/raspberrypi/debugprobe/releases)."); +} + +bool list_command::execute(device_map &devices) { + int num_devices = 0; + + for (auto devs = devices.begin(); devs != devices.end(); devs++) { + if (devs->first != dr_vidpid_unknown) { + num_devices += devs->second.size(); + } + } + + fos << "Detected " << num_devices << " RP-series devices:\n\n"; + fos.first_column(2); + fos.hanging_indent(4); + fos.paragraph_spacing(1); + fos.min_paragraph_lines_for_spacing(1); + print_device_info(devices, true, true); + + return false; +} #endif #if defined(_WIN32) @@ -10205,8 +10327,15 @@ int main(int argc, char **argv) { #if HAS_LIBUSB libusb_context *ctx = nullptr; + if (settings.target_debugprobe) { + if (settings.vid >= 0 || settings.pid >= 0) fail(ERROR_ARGS, "Cannot pass --debugprobe along with --vid or --pid"); + settings.vid = VENDOR_ID_RASPBERRY_PI; + settings.pid = PRODUCT_ID_DEBUGPROBE; + settings.only_force = true; + } + // save complicating the grammar - if (settings.force_no_reboot) settings.force = true; + if (settings.force_no_reboot || settings.only_force) settings.force = true; struct libusb_device **devs = nullptr; device_map devices; @@ -10255,13 +10384,22 @@ int main(int argc, char **argv) { } } auto supported = selected_cmd->get_device_support(); + bool bootsel_not_found = devices[dr_vidpid_bootrom_ok].empty(); + bool usb_reset_not_found = devices[dr_vidpid_usb_reset].empty(); + bool no_device_found = false; + if (settings.only_force) { + no_device_found = usb_reset_not_found; + } else if (settings.force) { + no_device_found = usb_reset_not_found && bootsel_not_found; + } else { + no_device_found = bootsel_not_found; + } switch (supported) { case cmd::device_support::zero_or_more: if (!settings.filenames[0].empty()) break; // fall thru case cmd::device_support::one: - if (devices[dr_vidpid_bootrom_ok].empty() && - (!settings.force || devices[dr_vidpid_stdio_usb].empty())) { + if (no_device_found) { if (tries == 0 || tries == MAX_REBOOT_TRIES) { if (tries) { fos << "\n\n"; @@ -10274,44 +10412,13 @@ int main(int argc, char **argv) { fos << " You may need to install a driver via Zadig. See Zadig in the README (https://github.com/raspberrypi/picotool#zadig) for more information."; } #endif - fos << " It is possible the device is not responding, and will have to be manually entered into BOOTSEL mode.\n"; + fos << " It is possible the device is not responding, and will have to be manually put into BOOTSEL mode.\n"; had_note = true; // suppress "but:" in this case } fos << "\n"; fos.first_column(0); fos.hanging_indent(4); - auto printer = [&](enum picoboot_device_result r, const string &description) { - if (!had_note && !devices[r].empty()) { - fos << "\nbut:\n\n"; - had_note = true; - } - for (auto d : devices[r]) { - fos << bus_device_string(std::get<1>(d), std::get<0>(d)) << description << "\n"; - } - }; - #if defined(__linux__) || defined(__APPLE__) - printer(dr_vidpid_bootrom_cant_connect, - " appears to be in BOOTSEL mode, but picotool was unable to connect. Maybe try 'sudo' or check your permissions."); - printer(dr_vidpid_stdio_usb_cant_connect, - " appears to have a USB serial connection, but picotool was unable to connect. Maybe try 'sudo' or check your permissions."); - #else - printer(dr_vidpid_bootrom_cant_connect, - " appears to be in BOOTSEL mode, but picotool was unable to connect. You may need to install a driver via Zadig. See Zadig in the README (https://github.com/raspberrypi/picotool#zadig) for more information"); - printer(dr_vidpid_stdio_usb_cant_connect, - " appears to have a USB serial connection, but picotool was unable to connect."); - #endif - printer(dr_vidpid_picoprobe, - " appears to be an RP-series PicoProbe device not in BOOTSEL mode."); - printer(dr_vidpid_micropython, - " appears to be an RP-series MicroPython device not in BOOTSEL mode."); - if (selected_cmd->force_requires_pre_reboot()) { - printer(dr_vidpid_stdio_usb, - " appears to have a USB serial connection, so consider -f (or -F) to force reboot in order to run the command."); - } else { - // special case message for what is actually just reboot (the only command that doesn't require reboot first) - printer(dr_vidpid_stdio_usb, - " appears to have a USB serial connection, so consider -f to force the reboot."); - } + print_device_info(devices, had_note); rc = ERROR_NO_DEVICE; } else { // waiting for rebooted device to show up @@ -10319,39 +10426,41 @@ int main(int argc, char **argv) { } } else if (supported == cmd::device_support::one) { if (devices[dr_vidpid_bootrom_ok].size() > 1 || - (devices[dr_vidpid_bootrom_ok].empty() && devices[dr_vidpid_stdio_usb].size() > 1)) { + (devices[dr_vidpid_bootrom_ok].empty() && devices[dr_vidpid_usb_reset].size() > 1)) { fail(ERROR_NOT_POSSIBLE, "Command requires a single RP-series device to be targeted."); } - if (!devices[dr_vidpid_bootrom_ok].empty()) { + if (!devices[dr_vidpid_bootrom_ok].empty() && !settings.only_force) { settings.force = false; // we have a device, so we're not forcing } - } else if (supported == cmd::device_support::zero_or_more && settings.force && !devices[dr_vidpid_bootrom_ok].empty()) { + } else if (supported == cmd::device_support::zero_or_more && settings.force && !devices[dr_vidpid_bootrom_ok].empty() && !settings.only_force) { // we have usable devices, so lets use them without force settings.force = false; } fos.first_column(0); fos.hanging_indent(0); break; + case cmd::device_support::any: default: break; } if (!rc) { if (settings.force && ctx) { // actually ctx should never be null as we are targeting device if force is set, but still - if (devices[dr_vidpid_stdio_usb].size() != 1 && !tries) { + if (devices[dr_vidpid_usb_reset].size() != 1 && !tries) { fail(ERROR_NOT_POSSIBLE, "Forced command requires a single rebootable RP-series device to be targeted."); } if (selected_cmd->force_requires_pre_reboot()) { if (!tries) { // we reboot into BOOTSEL mode and disable MSC interface (the 1 here) - auto &to_reboot = std::get<1>(devices[dr_vidpid_stdio_usb][0]); - auto &to_reboot_handle = std::get<2>(devices[dr_vidpid_stdio_usb][0]); + auto to_reboot_chip = std::get<0>(devices[dr_vidpid_usb_reset][0]); + auto &to_reboot = std::get<1>(devices[dr_vidpid_usb_reset][0]); + auto &to_reboot_handle = std::get<2>(devices[dr_vidpid_usb_reset][0]); unsigned int disable_mask = 1; // disable MSC interface #if defined(_WIN32) { struct libusb_device_descriptor desc; libusb_get_device_descriptor(to_reboot, &desc); - if (desc.idProduct == PRODUCT_ID_RP2040_STDIO_USB || settings.force_rp2040) { + if (to_reboot_chip == rp2040 || settings.force_rp2040) { // the Zadig driver should be setup for the device in BOOTSEL mode with no interfaces disabled, // as all the interfaces are enabled when you plug it in while holding down the BOOTSEL button disable_mask = 0; @@ -10393,6 +10502,8 @@ int main(int argc, char **argv) { // again is to assume it has the same serial number. settings.address = -1; settings.bus = -1; + // also clear only_force, as the device should now be rebooting to BOOTSEL mode + settings.only_force = false; if (settings.pid != -1 || settings.vid != -1) { // vid/pid filtering was enabled, but may change in BOOTSEL mode, so needs to be disabled if (settings.ser.empty()) { diff --git a/picoboot_connection/picoboot_connection.c b/picoboot_connection/picoboot_connection.c index 60370c32..954a8849 100644 --- a/picoboot_connection/picoboot_connection.c +++ b/picoboot_connection/picoboot_connection.c @@ -59,6 +59,34 @@ unsigned int interface; unsigned int out_ep; unsigned int in_ep; +enum picoboot_device_result match_rpi_pid(chip_t *chip, int dev_pid) { + switch (dev_pid) { + case PRODUCT_ID_MICROPYTHON: + return dr_vidpid_micropython; + case PRODUCT_ID_DEBUGPROBE_OLD: + return dr_vidpid_debugprobe_old; + case PRODUCT_ID_CIRCUITPYTHON: + return dr_vidpid_circuitpython; + case PRODUCT_ID_DEBUGPROBE: + *chip = rp2040; + return dr_vidpid_debugprobe; + case PRODUCT_ID_RP2040_STDIO_USB: + *chip = rp2040; + return dr_vidpid_usb_reset; + case PRODUCT_ID_STDIO_USB: + *chip = rp2350; + return dr_vidpid_usb_reset; + case PRODUCT_ID_RP2040_USBBOOT: + *chip = rp2040; + return dr_vidpid_bootrom_ok; + case PRODUCT_ID_RP2350_USBBOOT: + *chip = rp2350; + return dr_vidpid_bootrom_ok; + default: + return dr_vidpid_unknown; + } +} + enum picoboot_device_result picoboot_open_device(libusb_device *device, libusb_device_handle **dev_handle, chip_t *chip, int vid, int pid, const char* ser) { struct libusb_device_descriptor desc; struct libusb_config_descriptor *config; @@ -66,6 +94,10 @@ enum picoboot_device_result picoboot_open_device(libusb_device *device, libusb_d definitely_exclusive = false; *dev_handle = NULL; *chip = unknown; + bool checking_for_debugprobe = false; + if (vid == VENDOR_ID_RASPBERRY_PI && pid == PRODUCT_ID_DEBUGPROBE) { + checking_for_debugprobe = true; + } int ret = libusb_get_device_descriptor(device, &desc); enum picoboot_device_result res = dr_vidpid_unknown; if (ret && verbose) { @@ -75,34 +107,42 @@ enum picoboot_device_result picoboot_open_device(libusb_device *device, libusb_d if (pid >= 0) { bool match_vid = (vid < 0 ? VENDOR_ID_RASPBERRY_PI : (unsigned int)vid) == desc.idVendor; bool match_pid = pid == desc.idProduct; - if (!(match_vid && match_pid)) { + if (checking_for_debugprobe) { + // Special case - if you pass --debugprobe but there is an RP2040 in bootsel mode, + // treat that as a match so it returns dr_vidpid_bootrom_ok - it will not pick + // that anyway, + if (!match_vid || !(match_pid || desc.idProduct == PRODUCT_ID_RP2040_USBBOOT)) { + return dr_vidpid_unknown; + } else { + *chip = rp2040; + if (desc.idProduct == PRODUCT_ID_RP2040_USBBOOT) { + // No longer checking for debugprobe, as this is an RP2040 in bootsel mode + checking_for_debugprobe = false; + res = dr_vidpid_bootrom_ok; + } + } + } else if (!match_vid || !match_pid) { return dr_vidpid_unknown; + } else if (desc.idVendor == VENDOR_ID_RASPBERRY_PI) { + // Handle the case where --pid was passed, but it's a standard value + res = match_rpi_pid(chip, desc.idProduct); + if (res > dr_vidpid_debugprobe) { + // everything after dr_vidpid_debugprobe isn't handled in the rest of the function, + // so set back to unknown as it was selected and needs to be detected + // (e.g. micropython with a reset interface added) + res = dr_vidpid_unknown; + } } - } else if (vid != 0) { // ignore vid/pid filtering if no pid and vid == 0 - if (desc.idVendor != (vid < 0 ? VENDOR_ID_RASPBERRY_PI : (unsigned int)vid)) { + } else { // ignore vid/pid filtering if no pid and vid == 0 + if (vid != 0 && desc.idVendor != (vid < 0 ? VENDOR_ID_RASPBERRY_PI : (unsigned int)vid)) { return dr_vidpid_unknown; - } - switch (desc.idProduct) { - case PRODUCT_ID_MICROPYTHON: - return dr_vidpid_micropython; - case PRODUCT_ID_PICOPROBE: - return dr_vidpid_picoprobe; - case PRODUCT_ID_RP2040_STDIO_USB: - *chip = rp2040; - res = dr_vidpid_stdio_usb; - break; - case PRODUCT_ID_STDIO_USB: - *chip = rp2350; - res = dr_vidpid_stdio_usb; - break; - case PRODUCT_ID_RP2040_USBBOOT: - *chip = rp2040; - break; - case PRODUCT_ID_RP2350_USBBOOT: - *chip = rp2350; - break; - default: - return dr_vidpid_unknown; + } else if (desc.idVendor == VENDOR_ID_RASPBERRY_PI) { + res = match_rpi_pid(chip, desc.idProduct); + if (res > dr_vidpid_debugprobe) { + // everything after dr_vidpid_debugprobe isn't handled in the rest of the function, + // so return it now as it was not selected (e.g. micropython) + return res; + } } } ret = libusb_get_active_config_descriptor(device, &config); @@ -120,40 +160,59 @@ enum picoboot_device_result picoboot_open_device(libusb_device *device, libusb_d if (vid == 0 || strlen(ser) != 0) { // didn't check vid or ser, so treat as unknown return dr_vidpid_unknown; - } else if (res == dr_vidpid_stdio_usb) { + } else if (res == dr_vidpid_usb_reset) { // only set by having STDIO_USB PIDs return dr_vidpid_stdio_usb_cant_connect; - } else { + } else if (res == dr_vidpid_debugprobe || checking_for_debugprobe) { + return dr_vidpid_debugprobe_cant_connect; + } else if (res = dr_vidpid_bootrom_ok) { return dr_vidpid_bootrom_cant_connect; + } else { + return dr_vidpid_cant_connect; } } } - if (!ret && res == dr_vidpid_stdio_usb) { - if (strlen(ser) != 0) { - // Check USB serial number + // Check USB serial number - skipped for BOOTSEL rp2040 vid/pid, as it is not unique, so flash ID is used instead + bool usb_ser_match = strlen(ser) == 0; // true if no serial number passed, false otherwise + if (!ret && !(res == dr_vidpid_bootrom_ok && *chip == rp2040)) { + if (!usb_ser_match) { char ser_str[128]; libusb_get_string_descriptor_ascii(*dev_handle, desc.iSerialNumber, (unsigned char*)ser_str, sizeof(ser_str)); if (strcmp(ser, ser_str)) { return dr_vidpid_unknown; } else { - return res; + usb_ser_match = true; } - } else { - return res; } } - // Runtime reset interface with thirdparty VID - if (!ret) { + // Runtime reset interface detection - only runs if USB serial number above matched, or no serial number passed + if (!ret && usb_ser_match) { for (int i = 0; i < config->bNumInterfaces; i++) { if (config->interface[i].altsetting[0].bInterfaceClass == 0xff && config->interface[i].altsetting[0].bInterfaceSubClass == RESET_INTERFACE_SUBCLASS && config->interface[i].altsetting[0].bInterfaceProtocol == RESET_INTERFACE_PROTOCOL) { - return dr_vidpid_stdio_usb; + if (res == dr_vidpid_unknown) { + return dr_vidpid_usb_reset; + } else { + // May already be setup, e.g dr_vidpid_debugprobe + return res; + } } } + + if (res == dr_vidpid_debugprobe || checking_for_debugprobe) { + // DebugProbe with no reset interface + return dr_vidpid_debugprobe_no_reset; + } + + if (res == dr_vidpid_usb_reset) { + // STDIO_USB with no reset interface + return dr_vidpid_stdio_usb_no_reset; + } } + // Picoboot interface detection if (!ret) { if (config->bNumInterfaces == 1) { interface = 0; diff --git a/picoboot_connection/picoboot_connection.h b/picoboot_connection/picoboot_connection.h index 31ee5b2e..7e172fe6 100644 --- a/picoboot_connection/picoboot_connection.h +++ b/picoboot_connection/picoboot_connection.h @@ -16,28 +16,50 @@ #include "boot/picoboot.h" #include "model.h" -#define VENDOR_ID_RASPBERRY_PI 0x2e8au -#define PRODUCT_ID_RP2040_USBBOOT 0x0003u -#define PRODUCT_ID_PICOPROBE 0x0004u -#define PRODUCT_ID_MICROPYTHON 0x0005u -#define PRODUCT_ID_STDIO_USB 0x0009u +#define VENDOR_ID_RASPBERRY_PI 0x2e8au +#define PRODUCT_ID_RP2040_USBBOOT 0x0003u +#define PRODUCT_ID_DEBUGPROBE_OLD 0x0004u +#define PRODUCT_ID_MICROPYTHON 0x0005u +#define PRODUCT_ID_STDIO_USB 0x0009u #define PRODUCT_ID_RP2040_STDIO_USB 0x000au -#define PRODUCT_ID_RP2350_USBBOOT 0x000fu +#define PRODUCT_ID_CIRCUITPYTHON 0x000bu +#define PRODUCT_ID_DEBUGPROBE 0x000cu +#define PRODUCT_ID_RP2350_USBBOOT 0x000fu #ifdef __cplusplus extern "C" { #endif enum picoboot_device_result { - dr_vidpid_bootrom_ok, - dr_vidpid_bootrom_no_interface, - dr_vidpid_bootrom_cant_connect, - dr_vidpid_micropython, - dr_vidpid_picoprobe, - dr_vidpid_unknown, - dr_error, - dr_vidpid_stdio_usb, - dr_vidpid_stdio_usb_cant_connect, + // For these comments, selected vid/pid means either BOOTSEL vid/pid, stdio_usb vid/pid, or vid/pid was passed to picoboot_open_device + // (e.g. by passing --vid, --pid, or --debugprobe) + + // Devices that can be used by picotool + dr_vidpid_bootrom_ok, // selected vid/pid has a picoboot interface (i.e. device in BOOTSEL) + dr_vidpid_usb_reset, // selected vid/pid has a USB reset interface (e.g. stdio_usb, or custom vid/pid) + + // Devices missing required interfaces, so cannot be used by picotool + dr_vidpid_bootrom_no_interface, // selected vid/pid has no picoboot interface (and no reset interface as that is checked for first) + dr_vidpid_debugprobe_no_reset, // debugprobe vid/pid, but no reset interface (e.g. firmware <=2.3.1) + dr_vidpid_stdio_usb_no_reset, // stdio_usb vid/pid, but no reset interface (e.g. PICO_ENABLE_USB_RESET_VIA_VENDOR_INTERFACE=0) + + // Devices failed to open (e.g. requires sudo) + dr_vidpid_bootrom_cant_connect, // bootrom vid/pid + dr_vidpid_debugprobe_cant_connect, // debugprobe vid/pid + dr_vidpid_stdio_usb_cant_connect, // stdio_usb vid/pid + dr_vidpid_cant_connect, // custom vid/pid + + // Special known pids that require extra detection (e.g. USB reset interface) + dr_vidpid_debugprobe, // debugprobe vid/pid, with a USB reset interface - only returned when not searching for debugprobe vid/pid + + // Other known pids for no device found messages + dr_vidpid_micropython, // micropython vid/pid + dr_vidpid_circuitpython, // circuitpython vid/pid + dr_vidpid_debugprobe_old, // old debugprobe vid/pid (v1.0 and v1.0.1) + + // Ignored devices + dr_vidpid_unknown, // unknown device (e.g. no vid/pid/serial match) + dr_error, // an error occurred (e.g. libusb_get_device_descriptor or libusb_get_active_config_descriptor failed) };