Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/common/pico_base_headers/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ cc_library(
"//src/host/hardware_sync:__pkg__",
"//src/host/hardware_timer:__pkg__",
"//src/host/pico_platform:__pkg__",
"//src/host/pico_unique_id:__pkg__",
"//src/rp2040/boot_stage2:__pkg__",
"//src/rp2040/pico_platform:__pkg__",
"//src/rp2350/boot_stage2:__pkg__",
Expand Down
1 change: 1 addition & 0 deletions src/host.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ include (${CMAKE_DIR}/no_hardware.cmake)
pico_add_subdirectory(${HOST_DIR}/pico_stdio)
pico_add_subdirectory(${HOST_DIR}/pico_stdlib)
pico_add_subdirectory(${HOST_DIR}/pico_time_adapter)
pico_add_subdirectory(${HOST_DIR}/pico_unique_id)

unset(CMAKE_DIR)
unset(COMMON_DIR)
Expand Down
13 changes: 13 additions & 0 deletions src/host/pico_unique_id/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package(default_visibility = ["//visibility:public"])

cc_library(
name = "pico_unique_id",
srcs = ["unique_id.c"],
hdrs = ["include/pico/unique_id.h"],
includes = ["include"],
target_compatible_with = ["//bazel/constraint:host"],
deps = [
"//src/common/pico_base_headers",
"//src/host/pico_platform",
],
)
8 changes: 8 additions & 0 deletions src/host/pico_unique_id/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
pico_add_library(pico_unique_id)

target_sources(pico_unique_id INTERFACE
${CMAKE_CURRENT_LIST_DIR}/unique_id.c
)

target_include_directories(pico_unique_id_headers SYSTEM INTERFACE ${CMAKE_CURRENT_LIST_DIR}/include)
target_link_libraries(pico_unique_id_headers INTERFACE pico_base_headers)
127 changes: 127 additions & 0 deletions src/host/pico_unique_id/include/pico/unique_id.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
/*
* Copyright (c) 2021 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/

#ifndef _PICO_UNIQUE_ID_H
#define _PICO_UNIQUE_ID_H

#include "pico.h"

#ifdef __cplusplus
extern "C" {
#endif

/** \file pico/unique_id.h
* \defgroup pico_unique_id pico_unique_id
*
* \brief Unique device ID access API
*
* \if rp2040_specific
* RP2040 does not have an on-board unique identifier (all instances of RP2040
* silicon are identical and have no persistent state). However, RP2040 boots
* from serial NOR flash devices which have at least a 64-bit unique ID as a standard
* feature, and there is a 1:1 association between RP2040 and flash, so this
* is suitable for use as a unique identifier for an RP2040-based board.
*
* This library injects a call to the flash_get_unique_id function from the
* hardware_flash library, to run before main, and stores the result in a
* static location which can safely be accessed at any time via
* pico_get_unique_id().
*
* This avoids some pitfalls of the hardware_flash API, which requires any
* flash-resident interrupt routines to be disabled when called into.
* \endif
*
* \if rp2350_specific
* On boards using RP2350, the unique identifier is read from OTP memory on boot.
* \endif
*
* \if host_specific
* Host builds will return a fixed identifier starting with 0xA0 and incrementing
* by one for a total of PICO_UNIQUE_BOARD_ID_SIZE_BYTES bytes.
* The sequence can be changed by defining a project-specific version of
* pico_get_unique_board_id.
* \endif
*/

#define PICO_UNIQUE_BOARD_ID_SIZE_BYTES 8

/**
* \brief Unique board identifier
* \ingroup pico_unique_id
*
* This structure contains an array of PICO_UNIQUE_BOARD_ID_SIZE_BYTES identifier bytes suitable for
* holding the unique identifier for the device.
*
* \if rp2040_specific
* On an RP2040-based board, the unique identifier is retrieved from the external NOR flash device at boot,
* or for PICO_NO_FLASH builds the unique identifier is set to all 0xEE.
* \endif
*
* \if rp2350_specific
* On an RP2350-based board, the unique identifier is retrieved from OTP memory at boot.
* \endif
*
* \if host_specific
* The unique identifier is generated in pico_get_unique_board_id.
* \endif
*/
typedef struct {
uint8_t id[PICO_UNIQUE_BOARD_ID_SIZE_BYTES];
} pico_unique_board_id_t;

/*! \brief Get unique ID
* \ingroup pico_unique_id
*
* Get the unique 64-bit device identifier.
*
* \if rp2040_specific
* On an RP2040-based board, the unique identifier is retrieved from the external NOR flash device at boot,
* or for PICO_NO_FLASH builds the unique identifier is set to all 0xEE.
* \endif
*
* \if rp2350_specific
* On an RP2350-based board, the unique identifier is retrieved from OTP memory at boot.
* \endif
*
* \if host_specific
* Host builds set the unique identifier to a sequence starting with 0xA0 and incrementing by one for each byte.
* Replace this function with a project-specific version if a different identifier is required.
* \endif
*
* \param id_out a pointer to a pico_unique_board_id_t struct, to which the identifier will be written
*/
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 formatted as a 0-terminated ASCII hex string.
*
* \if rp2040_specific
* On an RP2040-based board, the unique identifier is retrieved from the external NOR flash device at boot,
* or for PICO_NO_FLASH builds the unique identifier is set to all 0xEE.
* \endif
*
* \if rp2350_specific
* On an RP2350-based board, the unique identifier is retrieved from OTP memory at boot.
* \endif
*
* \if host_specific
* Host builds return a sequence starting with 0xA0 and incrementing by one for each byte.
* Replace pico_get_unique_board_id with a project-specific version if a different identifer is required.
* \endif
*
* \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

#endif
30 changes: 30 additions & 0 deletions src/host/pico_unique_id/unique_id.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* Copyright (c) 2021 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/

#include "pico/unique_id.h"

PICO_WEAK_FUNCTION_DEF(pico_get_unique_board_id)
void PICO_WEAK_FUNCTION_IMPL_NAME(pico_get_unique_board_id)(pico_unique_board_id_t *id_out) {
for (int i = 0; i < PICO_UNIQUE_BOARD_ID_SIZE_BYTES; i++) {
id_out->id[i] = 0xa0 + i;
}
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps it's worth adding a comment (either here or in the header file) that explicitly says what pico_get_unique_board_id_string will return for "host" builds?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep. I've added comments and removed the static part. If someone wants to get a different ID, they just need to implement their own version of pico_get_unique_board_id, and pico_get_unique_board_id_string will automatically follow suit.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. But I was suggesting clarifying if (the default implementation of) pico_get_unique_board_id_string returns "A0A1A2A3A4A5A6A7" or "A7A6A5A4A3A2A1A0" 😉

PICO_WEAK_FUNCTION_DEF(pico_get_unique_board_id_string)
void PICO_WEAK_FUNCTION_IMPL_NAME(pico_get_unique_board_id_string)(char *id_out, uint len) {
assert(len > 0);
size_t i;

pico_unique_board_id_t id;
pico_get_unique_board_id(&id);

// Generate hex one nibble at a time
for (i = 0; (i < len - 1) && (i < PICO_UNIQUE_BOARD_ID_SIZE_BYTES * 2); i++) {
int nibble = (id.id[i/2] >> (4 - 4 * (i&1))) & 0xf;
id_out[i] = (char)(nibble < 10 ? nibble + '0' : nibble + 'A' - 10);
}
id_out[i] = 0;
}