diff --git a/src/rp2_common/pico_stdio_usb/CMakeLists.txt b/src/rp2_common/pico_stdio_usb/CMakeLists.txt index 8bc8853..170c516 100644 --- a/src/rp2_common/pico_stdio_usb/CMakeLists.txt +++ b/src/rp2_common/pico_stdio_usb/CMakeLists.txt @@ -13,9 +13,10 @@ if (TARGET tinyusb_device_unmarked) tinyusb_device_unmarked pico_stdio pico_time + pico_unique_id ) target_compile_definitions(pico_stdio_usb INTERFACE PICO_STDIO_USB=1 ) -endif() \ No newline at end of file +endif() diff --git a/src/rp2_common/pico_stdio_usb/stdio_usb_descriptors.c b/src/rp2_common/pico_stdio_usb/stdio_usb_descriptors.c index c66df42..91a91bd 100644 --- a/src/rp2_common/pico_stdio_usb/stdio_usb_descriptors.c +++ b/src/rp2_common/pico_stdio_usb/stdio_usb_descriptors.c @@ -30,6 +30,7 @@ #include "tusb.h" #include "pico/stdio_usb/reset_interface.h" +#include "pico/unique_id.h" #define USBD_VID (0x2E8A) // Raspberry Pi #define USBD_PID (0x000a) // Raspberry Pi Pico SDK CDC @@ -98,10 +99,12 @@ static const uint8_t usbd_desc_cfg[USBD_DESC_LEN] = { #endif }; +static char usbd_serial_str[PICO_UNIQUE_BOARD_ID_SIZE_BYTES * 2 + 1]; + static const char *const usbd_desc_str[] = { [USBD_STR_MANUF] = "Raspberry Pi", [USBD_STR_PRODUCT] = "Pico", - [USBD_STR_SERIAL] = "000000000000", // TODO + [USBD_STR_SERIAL] = usbd_serial_str, [USBD_STR_CDC] = "Board CDC", #if PICO_STDIO_USB_ENABLE_RESET_VIA_VENDOR_INTERFACE [USBD_STR_RPI_RESET] = "Reset", @@ -121,6 +124,11 @@ const uint16_t *tud_descriptor_string_cb(uint8_t index, uint16_t langid) { #define DESC_STR_MAX (20) static uint16_t desc_str[DESC_STR_MAX]; + // Assign the SN using the unique flash id + if (!usbd_serial_str[0]) { + pico_get_unique_board_id_string(usbd_serial_str, sizeof(usbd_serial_str)); + } + uint8_t len; if (index == 0) { desc_str[1] = 0x0409; // supported language is English @@ -141,4 +149,4 @@ const uint16_t *tud_descriptor_string_cb(uint8_t index, uint16_t langid) { return desc_str; } -#endif \ No newline at end of file +#endif diff --git a/src/rp2_common/pico_unique_id/include/pico/unique_id.h b/src/rp2_common/pico_unique_id/include/pico/unique_id.h index be956ca..31b09ed 100644 --- a/src/rp2_common/pico_unique_id/include/pico/unique_id.h +++ b/src/rp2_common/pico_unique_id/include/pico/unique_id.h @@ -57,6 +57,21 @@ typedef struct { */ void pico_get_unique_board_id(pico_unique_board_id_t *id_out); +/*! \brief Get unique ID in string format + * \ingroup pico_unique_id + * + * Get the unique 64-bit device identifier which was retrieved from the + * external NOR flash device at boot, formatted as an ASCII hex string. + * Will always 0-terminate. + * + * On PICO_NO_FLASH builds the unique identifier is set to all 0xEE. + * + * \param id_out a pointer to a char buffer of size len, to which the identifier will be written + * \param len the size of id_out. For full serial, len >= 2 * PICO_UNIQUE_BOARD_ID_SIZE_BYTES + 1 + */ +void pico_get_unique_board_id_string(char *id_out, uint len); + + #ifdef __cplusplus } #endif diff --git a/src/rp2_common/pico_unique_id/unique_id.c b/src/rp2_common/pico_unique_id/unique_id.c index fb39fb2..2e652c8 100644 --- a/src/rp2_common/pico_unique_id/unique_id.c +++ b/src/rp2_common/pico_unique_id/unique_id.c @@ -26,3 +26,14 @@ static void __attribute__((constructor)) _retrieve_unique_id_on_boot(void) { void pico_get_unique_board_id(pico_unique_board_id_t *id_out) { *id_out = retrieved_id; } + +void pico_get_unique_board_id_string(char *id_out, uint len) { + assert(len > 0); + size_t i; + // Generate hex one nibble at a time + for (i = 0; (i < len - 1) && (i < PICO_UNIQUE_BOARD_ID_SIZE_BYTES * 2); i++) { + int nibble = (retrieved_id.id[i/2] >> (4 - 4 * (i&1))) & 0xf; + id_out[i] = (char)(nibble < 10 ? nibble + '0' : nibble + 'A' - 10); + } + id_out[i] = 0; +}