1 /* 2 * Copyright (c) 2021 Raspberry Pi (Trading) Ltd. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 #include "hardware/flash.h" 8 #include "pico/bootrom.h" 9 #include "pico/unique_id.h" 10 11 static_assert(PICO_UNIQUE_BOARD_ID_SIZE_BYTES <= FLASH_UNIQUE_ID_SIZE_BYTES, "Board ID size must at least be the size of flash ID"); 12 13 static pico_unique_board_id_t retrieved_id; 14 _retrieve_unique_id_on_boot(void)15static void __attribute__((constructor)) _retrieve_unique_id_on_boot(void) { 16 #if PICO_RP2040 17 #if PICO_NO_FLASH 18 // The hardware_flash call will panic() if called directly on a NO_FLASH 19 // build. Since this constructor is pre-main it would be annoying to 20 // debug, so just produce something well-defined and obviously wrong. 21 for (int i = 0; i < PICO_UNIQUE_BOARD_ID_SIZE_BYTES; i++) 22 retrieved_id.id[i] = 0xee; 23 #elif (PICO_UNIQUE_BOARD_ID_SIZE_BYTES == FLASH_UNIQUE_ID_SIZE_BYTES) 24 flash_get_unique_id(retrieved_id.id); 25 #elif (PICO_UNIQUE_BOARD_ID_SIZE_BYTES < FLASH_UNIQUE_ID_SIZE_BYTES) 26 // The flash ID is >8 bytes (e.g. IS25LP016D) but we want to keep the 27 // pico unique board ID as 8 bytes, just use the last 8 bytes which are likely to change 28 uint8_t flash_id[FLASH_UNIQUE_ID_SIZE_BYTES]; 29 flash_get_unique_id(flash_id); 30 memcpy(retrieved_id.id, flash_id + FLASH_UNIQUE_ID_SIZE_BYTES - PICO_UNIQUE_BOARD_ID_SIZE_BYTES, PICO_UNIQUE_BOARD_ID_SIZE_BYTES); 31 #else 32 #error unique board ID size is greater than flash unique ID size 33 #endif 34 #else 35 rom_get_sys_info_fn func = (rom_get_sys_info_fn) rom_func_lookup(ROM_FUNC_GET_SYS_INFO); 36 union { 37 uint32_t words[9]; 38 uint8_t bytes[9 * 4]; 39 } out; 40 __unused int rc = func(out.words, 9, SYS_INFO_CHIP_INFO); 41 assert(rc == 4); 42 for (int i = 0; i < PICO_UNIQUE_BOARD_ID_SIZE_BYTES; i++) { 43 retrieved_id.id[i] = out.bytes[PICO_UNIQUE_BOARD_ID_SIZE_BYTES - 1 + 2 * 4 - i]; 44 } 45 #endif 46 } 47 pico_get_unique_board_id(pico_unique_board_id_t * id_out)48void pico_get_unique_board_id(pico_unique_board_id_t *id_out) { 49 *id_out = retrieved_id; 50 } 51 pico_get_unique_board_id_string(char * id_out,uint len)52void pico_get_unique_board_id_string(char *id_out, uint len) { 53 assert(len > 0); 54 size_t i; 55 // Generate hex one nibble at a time 56 for (i = 0; (i < len - 1) && (i < PICO_UNIQUE_BOARD_ID_SIZE_BYTES * 2); i++) { 57 int nibble = (retrieved_id.id[i/2] >> (4 - 4 * (i&1))) & 0xf; 58 id_out[i] = (char)(nibble < 10 ? nibble + '0' : nibble + 'A' - 10); 59 } 60 id_out[i] = 0; 61 } 62