Skip to content

Commit 624bf22

Browse files
committed
Add pico_unique_id library to host platform
Fixes #2750
1 parent 299fb7d commit 624bf22

File tree

6 files changed

+190
-0
lines changed

6 files changed

+190
-0
lines changed

src/common/pico_base_headers/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ cc_library(
9595
"//src/host/hardware_sync:__pkg__",
9696
"//src/host/hardware_timer:__pkg__",
9797
"//src/host/pico_platform:__pkg__",
98+
"//src/host/pico_unique_id:__pkg__",
9899
"//src/rp2040/boot_stage2:__pkg__",
99100
"//src/rp2040/pico_platform:__pkg__",
100101
"//src/rp2350/boot_stage2:__pkg__",

src/host.cmake

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ include (${CMAKE_DIR}/no_hardware.cmake)
3838
pico_add_subdirectory(${HOST_DIR}/pico_stdio)
3939
pico_add_subdirectory(${HOST_DIR}/pico_stdlib)
4040
pico_add_subdirectory(${HOST_DIR}/pico_time_adapter)
41+
pico_add_subdirectory(${HOST_DIR}/pico_unique_id)
4142

4243
unset(CMAKE_DIR)
4344
unset(COMMON_DIR)
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package(default_visibility = ["//visibility:public"])
2+
3+
cc_library(
4+
name = "pico_unique_id",
5+
srcs = ["unique_id.c"],
6+
hdrs = ["include/pico/unique_id.h"],
7+
includes = ["include"],
8+
target_compatible_with = ["//bazel/constraint:host"],
9+
deps = [
10+
"//src/common/pico_base_headers",
11+
"//src/host/pico_platform",
12+
],
13+
)
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
pico_add_library(pico_unique_id)
2+
3+
target_sources(pico_unique_id INTERFACE
4+
${CMAKE_CURRENT_LIST_DIR}/unique_id.c
5+
)
6+
7+
target_include_directories(pico_unique_id_headers SYSTEM INTERFACE ${CMAKE_CURRENT_LIST_DIR}/include)
8+
target_link_libraries(pico_unique_id_headers INTERFACE pico_base_headers)
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
/*
2+
* Copyright (c) 2021 Raspberry Pi (Trading) Ltd.
3+
*
4+
* SPDX-License-Identifier: BSD-3-Clause
5+
*/
6+
7+
#ifndef _PICO_UNIQUE_ID_H
8+
#define _PICO_UNIQUE_ID_H
9+
10+
#include "pico.h"
11+
12+
#ifdef __cplusplus
13+
extern "C" {
14+
#endif
15+
16+
/** \file pico/unique_id.h
17+
* \defgroup pico_unique_id pico_unique_id
18+
*
19+
* \brief Unique device ID access API
20+
*
21+
* \if rp2040_specific
22+
* RP2040 does not have an on-board unique identifier (all instances of RP2040
23+
* silicon are identical and have no persistent state). However, RP2040 boots
24+
* from serial NOR flash devices which have at least a 64-bit unique ID as a standard
25+
* feature, and there is a 1:1 association between RP2040 and flash, so this
26+
* is suitable for use as a unique identifier for an RP2040-based board.
27+
*
28+
* This library injects a call to the flash_get_unique_id function from the
29+
* hardware_flash library, to run before main, and stores the result in a
30+
* static location which can safely be accessed at any time via
31+
* pico_get_unique_id().
32+
*
33+
* This avoids some pitfalls of the hardware_flash API, which requires any
34+
* flash-resident interrupt routines to be disabled when called into.
35+
* \endif
36+
*
37+
* \if rp2350_specific
38+
* On boards using RP2350, the unique identifier is read from OTP memory on boot.
39+
* \endif
40+
*/
41+
42+
#define PICO_UNIQUE_BOARD_ID_SIZE_BYTES 8
43+
44+
/**
45+
* \brief Static initialization order
46+
* \ingroup pico_unique_id
47+
*
48+
* This defines the init_priority of the pico_unique_id. By default, it is 1000. The valid range is
49+
* from 101-65535. Set it to -1 to set the priority to none, thus putting it after 65535. Changing
50+
* this value will initialize the unique_id earlier or later in the static initialization order.
51+
* This is most useful for C++ consumers of the pico-sdk.
52+
*
53+
* See https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-constructor-function-attribute
54+
* and https://gcc.gnu.org/onlinedocs/gcc/C_002b_002b-Attributes.html#index-init_005fpriority-variable-attribute
55+
*
56+
* Here is an example of C++ static initializers that will run before, and then after, pico_unique_id is loaded:
57+
*
58+
* [[gnu::init_priority(500)]] my_class before_instance;
59+
* [[gnu::init_priority(2000)]] my_class after_instance;
60+
*
61+
*/
62+
#ifndef PICO_UNIQUE_BOARD_ID_INIT_PRIORITY
63+
#define PICO_UNIQUE_BOARD_ID_INIT_PRIORITY 1000
64+
#endif
65+
66+
/**
67+
* \brief Unique board identifier
68+
* \ingroup pico_unique_id
69+
*
70+
* This structure contains an array of PICO_UNIQUE_BOARD_ID_SIZE_BYTES identifier bytes suitable for
71+
* holding the unique identifier for the device.
72+
*
73+
* \if rp2040_specific
74+
* On an RP2040-based board, the unique identifier is retrieved from the external NOR flash device at boot,
75+
* or for PICO_NO_FLASH builds the unique identifier is set to all 0xEE.
76+
* \endif
77+
*
78+
* \if rp2350_specific
79+
* On an RP2350-based board, the unique identifier is retrieved from OTP memory at boot.
80+
* \endif
81+
*
82+
*/
83+
typedef struct {
84+
uint8_t id[PICO_UNIQUE_BOARD_ID_SIZE_BYTES];
85+
} pico_unique_board_id_t;
86+
87+
/*! \brief Get unique ID
88+
* \ingroup pico_unique_id
89+
*
90+
* Get the unique 64-bit device identifier.
91+
*
92+
* \if rp2040_specific
93+
* On an RP2040-based board, the unique identifier is retrieved from the external NOR flash device at boot,
94+
* or for PICO_NO_FLASH builds the unique identifier is set to all 0xEE.
95+
* \endif
96+
*
97+
* \if rp2350_specific
98+
* On an RP2350-based board, the unique identifier is retrieved from OTP memory at boot.
99+
* \endif
100+
*
101+
* \param id_out a pointer to a pico_unique_board_id_t struct, to which the identifier will be written
102+
*/
103+
void pico_get_unique_board_id(pico_unique_board_id_t *id_out);
104+
105+
/*! \brief Get unique ID in string format
106+
* \ingroup pico_unique_id
107+
*
108+
* Get the unique 64-bit device identifier formatted as a 0-terminated ASCII hex string.
109+
*
110+
* \if rp2040_specific
111+
* On an RP2040-based board, the unique identifier is retrieved from the external NOR flash device at boot,
112+
* or for PICO_NO_FLASH builds the unique identifier is set to all 0xEE.
113+
* \endif
114+
*
115+
* \if rp2350_specific
116+
* On an RP2350-based board, the unique identifier is retrieved from OTP memory at boot.
117+
* \endif
118+
*
119+
* \param id_out a pointer to a char buffer of size len, to which the identifier will be written
120+
* \param len the size of id_out. For full serial, len >= 2 * PICO_UNIQUE_BOARD_ID_SIZE_BYTES + 1
121+
*/
122+
void pico_get_unique_board_id_string(char *id_out, uint len);
123+
124+
125+
#ifdef __cplusplus
126+
}
127+
#endif
128+
129+
#endif
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/*
2+
* Copyright (c) 2021 Raspberry Pi (Trading) Ltd.
3+
*
4+
* SPDX-License-Identifier: BSD-3-Clause
5+
*/
6+
7+
#include "pico/unique_id.h"
8+
9+
static pico_unique_board_id_t retrieved_id;
10+
11+
#if PICO_UNIQUE_BOARD_ID_INIT_PRIORITY == -1
12+
#define PICO_UNIQUE_BOARD_ID_INIT_ATTRIBUTES constructor
13+
#else
14+
#define PICO_UNIQUE_BOARD_ID_INIT_ATTRIBUTES constructor(PICO_UNIQUE_BOARD_ID_INIT_PRIORITY)
15+
#endif
16+
17+
static void __attribute__((PICO_UNIQUE_BOARD_ID_INIT_ATTRIBUTES)) _retrieve_unique_id_on_boot(void) {
18+
for (int i = 0; i < PICO_UNIQUE_BOARD_ID_SIZE_BYTES; i++) {
19+
retrieved_id.id[i] = 0xa0 + i;
20+
}
21+
}
22+
23+
PICO_WEAK_FUNCTION_DEF(pico_get_unique_board_id)
24+
void PICO_WEAK_FUNCTION_IMPL_NAME(pico_get_unique_board_id)(pico_unique_board_id_t *id_out) {
25+
*id_out = retrieved_id;
26+
}
27+
28+
PICO_WEAK_FUNCTION_DEF(pico_get_unique_board_id_string)
29+
void PICO_WEAK_FUNCTION_IMPL_NAME(pico_get_unique_board_id_string)(char *id_out, uint len) {
30+
assert(len > 0);
31+
size_t i;
32+
// Generate hex one nibble at a time
33+
for (i = 0; (i < len - 1) && (i < PICO_UNIQUE_BOARD_ID_SIZE_BYTES * 2); i++) {
34+
int nibble = (retrieved_id.id[i/2] >> (4 - 4 * (i&1))) & 0xf;
35+
id_out[i] = (char)(nibble < 10 ? nibble + '0' : nibble + 'A' - 10);
36+
}
37+
id_out[i] = 0;
38+
}

0 commit comments

Comments
 (0)