Skip to content

Commit cb9ad34

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

File tree

6 files changed

+180
-0
lines changed

6 files changed

+180
-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: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
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+
* \if host_specific
42+
* Host builds will return a fixed identifier starting with 0xA0 and incrementing
43+
* by one for a total of PICO_UNIQUE_BOARD_ID_SIZE_BYTES bytes.
44+
* The sequence can be changed by defining a project-specific version of
45+
* pico_get_unique_board_id.
46+
* \endif
47+
*/
48+
49+
#define PICO_UNIQUE_BOARD_ID_SIZE_BYTES 8
50+
51+
/**
52+
* \brief Unique board identifier
53+
* \ingroup pico_unique_id
54+
*
55+
* This structure contains an array of PICO_UNIQUE_BOARD_ID_SIZE_BYTES identifier bytes suitable for
56+
* holding the unique identifier for the device.
57+
*
58+
* \if rp2040_specific
59+
* On an RP2040-based board, the unique identifier is retrieved from the external NOR flash device at boot,
60+
* or for PICO_NO_FLASH builds the unique identifier is set to all 0xEE.
61+
* \endif
62+
*
63+
* \if rp2350_specific
64+
* On an RP2350-based board, the unique identifier is retrieved from OTP memory at boot.
65+
* \endif
66+
*
67+
* \if host_specific
68+
* The unique identifier is generated in pico_get_unique_board_id.
69+
* \endif
70+
*/
71+
typedef struct {
72+
uint8_t id[PICO_UNIQUE_BOARD_ID_SIZE_BYTES];
73+
} pico_unique_board_id_t;
74+
75+
/*! \brief Get unique ID
76+
* \ingroup pico_unique_id
77+
*
78+
* Get the unique 64-bit device identifier.
79+
*
80+
* \if rp2040_specific
81+
* On an RP2040-based board, the unique identifier is retrieved from the external NOR flash device at boot,
82+
* or for PICO_NO_FLASH builds the unique identifier is set to all 0xEE.
83+
* \endif
84+
*
85+
* \if rp2350_specific
86+
* On an RP2350-based board, the unique identifier is retrieved from OTP memory at boot.
87+
* \endif
88+
*
89+
* \if host_specific
90+
* Host builds set the unique identifier to a sequence starting with 0xA0 and incrementing by one for each byte.
91+
* Replace this function with a project-specific version if a different identifier is required.
92+
* \endif
93+
*
94+
* \param id_out a pointer to a pico_unique_board_id_t struct, to which the identifier will be written
95+
*/
96+
void pico_get_unique_board_id(pico_unique_board_id_t *id_out);
97+
98+
/*! \brief Get unique ID in string format
99+
* \ingroup pico_unique_id
100+
*
101+
* Get the unique 64-bit device identifier formatted as a 0-terminated ASCII hex string.
102+
*
103+
* \if rp2040_specific
104+
* On an RP2040-based board, the unique identifier is retrieved from the external NOR flash device at boot,
105+
* or for PICO_NO_FLASH builds the unique identifier is set to all 0xEE.
106+
* \endif
107+
*
108+
* \if rp2350_specific
109+
* On an RP2350-based board, the unique identifier is retrieved from OTP memory at boot.
110+
* \endif
111+
*
112+
* \if host_specific
113+
* Host builds return a sequence starting with 0xA0 and incrementing by one for each byte.
114+
* Replace pico_get_unique_board_id with a project-specific version if a different identifer is required.
115+
* \endif
116+
*
117+
* \param id_out a pointer to a char buffer of size len, to which the identifier will be written
118+
* \param len the size of id_out. For full serial, len >= 2 * PICO_UNIQUE_BOARD_ID_SIZE_BYTES + 1
119+
*/
120+
void pico_get_unique_board_id_string(char *id_out, uint len);
121+
122+
123+
#ifdef __cplusplus
124+
}
125+
#endif
126+
127+
#endif
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
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+
PICO_WEAK_FUNCTION_DEF(pico_get_unique_board_id)
10+
void PICO_WEAK_FUNCTION_IMPL_NAME(pico_get_unique_board_id)(pico_unique_board_id_t *id_out) {
11+
for (int i = 0; i < PICO_UNIQUE_BOARD_ID_SIZE_BYTES; i++) {
12+
id_out->id[i] = 0xa0 + i;
13+
}
14+
}
15+
16+
PICO_WEAK_FUNCTION_DEF(pico_get_unique_board_id_string)
17+
void PICO_WEAK_FUNCTION_IMPL_NAME(pico_get_unique_board_id_string)(char *id_out, uint len) {
18+
assert(len > 0);
19+
size_t i;
20+
21+
pico_unique_board_id_t id;
22+
pico_get_unique_board_id(&id);
23+
24+
// Generate hex one nibble at a time
25+
for (i = 0; (i < len - 1) && (i < PICO_UNIQUE_BOARD_ID_SIZE_BYTES * 2); i++) {
26+
int nibble = (id.id[i/2] >> (4 - 4 * (i&1))) & 0xf;
27+
id_out[i] = (char)(nibble < 10 ? nibble + '0' : nibble + 'A' - 10);
28+
}
29+
id_out[i] = 0;
30+
}

0 commit comments

Comments
 (0)