|
25 | 25 | #include <memory> |
26 | 26 | #include <functional> |
27 | 27 | #include <ctime> |
| 28 | +#include <sstream> |
28 | 29 |
|
29 | 30 | #include "boot/uf2.h" |
30 | 31 | #include "picoboot_connection_cxx.h" |
@@ -255,6 +256,7 @@ struct _settings { |
255 | 256 | uint32_t binary_start = FLASH_START; |
256 | 257 | int bus=-1; |
257 | 258 | int address=-1; |
| 259 | + string serial; |
258 | 260 | uint32_t offset = 0; |
259 | 261 | uint32_t from = 0; |
260 | 262 | uint32_t to = 0; |
@@ -292,17 +294,31 @@ struct _settings { |
292 | 294 | _settings settings; |
293 | 295 | std::shared_ptr<cmd> selected_cmd; |
294 | 296 |
|
295 | | -auto device_selection = |
| 297 | +auto device_selection = ( |
296 | 298 | ( |
297 | 299 | (option("--bus") & integer("bus").min_value(0).max_value(255).set(settings.bus) |
298 | | - .if_missing([] { return "missing bus number"; })) % "Filter devices by USB bus number" + |
299 | | - (option("--address") & integer("addr").min_value(1).max_value(127).set(settings.address) |
300 | | - .if_missing([] { return "missing address"; })) % "Filter devices by USB device address" |
| 300 | + .if_missing([] { return "missing bus number"; })) |
| 301 | + % "Filter devices by USB bus number" |
| 302 | + + (option("--address") & integer("addr").min_value(1).max_value(127).set(settings.address) |
| 303 | + .if_missing([] { return "missing address"; })) |
| 304 | + % "Filter devices by USB device address" |
| 305 | + ).min(0).doc_non_optional(true) + |
| 306 | + ( |
| 307 | + (option("--serial") & value("serial").set(settings.serial) |
| 308 | + .if_missing([] { return "missing serial id"; })) |
| 309 | + % "Filter devices by serial id" |
301 | 310 | #if !defined(_WIN32) |
302 | | - + 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" + |
303 | | - 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 RPI-RP2 drive mounted" |
| 311 | + + option('f', "--force").set(settings.force) |
| 312 | + % "Force a device not in BOOTSEL mode but running compatible code to reset so the command can be executed. " |
| 313 | + "After executing the command (unless the command itself is a 'reboot') " |
| 314 | + "the device will be rebooted back to application mode" |
| 315 | + + option('F', "--force-no-reboot").set(settings.force_no_reboot) |
| 316 | + % "Force a device not in BOOTSEL mode but running compatible code to reset so the command can be executed. " |
| 317 | + "After executing the command (unless the command itself is a 'reboot') the device will be left connected " |
| 318 | + "and accessible to picotool, but without the RPI-RP2 drive mounted" |
304 | 319 | #endif |
305 | | - ).min(0).doc_non_optional(true); |
| 320 | + ).min(0).doc_non_optional(true) |
| 321 | +).min(0).doc_non_optional(true); |
306 | 322 |
|
307 | 323 | auto file_types = (option ('t', "--type") & value("type").set(settings.file_type)) |
308 | 324 | % "Specify file type (uf2 | elf | bin) explicitly, ignoring file extension"; |
@@ -1581,28 +1597,25 @@ void info_guts(memory_access &raw_access) { |
1581 | 1597 | } |
1582 | 1598 |
|
1583 | 1599 | string missing_device_string(bool wasRetry) { |
1584 | | - char b[256]; |
1585 | | - if (wasRetry) { |
1586 | | - strcpy(b, "Despite the reboot attempt, no "); |
1587 | | - } else { |
1588 | | - strcpy(b, "No "); |
| 1600 | + std::ostringstream oss; |
| 1601 | + oss << (wasRetry ? "Despite the reboot attempt, no" : "No") << " accessible RP2040 device"; |
| 1602 | + if (settings.bus != -1 && settings.serial.empty()) { |
| 1603 | + oss << 's'; |
| 1604 | + } |
| 1605 | + oss << " in BOOTSEL mode"; |
| 1606 | + if (!settings.serial.empty()) { |
| 1607 | + oss << " with serial ID '" << settings.serial << '\''; |
| 1608 | + } |
| 1609 | + oss << " was found"; |
| 1610 | + if (settings.bus != -1) { |
| 1611 | + oss << " at bus " << settings.bus; |
1589 | 1612 | } |
1590 | | - char *buf = b + strlen(b); |
1591 | | - int buf_len = b + sizeof(b) - buf; |
1592 | 1613 | if (settings.address != -1) { |
1593 | | - if (settings.bus != -1) { |
1594 | | - snprintf(buf, buf_len, "accessible RP2040 device in BOOTSEL mode was found at bus %d, address %d.", settings.bus, settings.address); |
1595 | | - } else { |
1596 | | - snprintf(buf, buf_len, "accessible RP2040 devices in BOOTSEL mode were found with address %d.", settings.address); |
1597 | | - } |
1598 | | - } else { |
1599 | | - if (settings.bus != -1) { |
1600 | | - snprintf(buf, buf_len, "accessible RP2040 devices in BOOTSEL mode were found found on bus %d.", settings.bus); |
1601 | | - } else { |
1602 | | - snprintf(buf, buf_len,"accessible RP2040 devices in BOOTSEL mode were found."); |
1603 | | - } |
| 1614 | + oss << (settings.bus == -1 ? " with" : ",") << " address " << settings.address; |
1604 | 1615 | } |
1605 | | - return b; |
| 1616 | + oss << '.'; |
| 1617 | + |
| 1618 | + return oss.str(); |
1606 | 1619 | } |
1607 | 1620 |
|
1608 | 1621 | bool help_command::execute(device_map &devices) { |
@@ -2179,6 +2192,20 @@ void cancelled(int) { |
2179 | 2192 | throw cancelled_exception(); |
2180 | 2193 | } |
2181 | 2194 |
|
| 2195 | +string get_usb_device_serial(libusb_device *device, libusb_device_handle *handle) { |
| 2196 | + struct libusb_device_descriptor desc{}; |
| 2197 | + int ret = libusb_get_device_descriptor(device, &desc); |
| 2198 | + if (!ret) { |
| 2199 | + unsigned char data[33]; |
| 2200 | + if (libusb_get_string_descriptor_ascii(handle, desc.iSerialNumber, data, 31)) { |
| 2201 | + data[32] = '\0'; |
| 2202 | + return reinterpret_cast<char const*>(data); |
| 2203 | + } |
| 2204 | + } |
| 2205 | + |
| 2206 | + return ""; |
| 2207 | +} |
| 2208 | + |
2182 | 2209 | int main(int argc, char **argv) { |
2183 | 2210 | libusb_context *ctx = nullptr; |
2184 | 2211 |
|
@@ -2229,6 +2256,7 @@ int main(int argc, char **argv) { |
2229 | 2256 | if (handle) { |
2230 | 2257 | to_close.push_back(handle); |
2231 | 2258 | } |
| 2259 | + if (!settings.serial.empty() && (!handle || settings.serial != get_usb_device_serial(*dev, handle))) continue; |
2232 | 2260 | if (result != dr_error) { |
2233 | 2261 | devices[result].push_back(std::make_pair(*dev, handle)); |
2234 | 2262 | } |
|
0 commit comments