diff --git a/drivers/CpuUid.cpp b/drivers/CpuUid.cpp index f48c86d05d..03861e5436 100644 --- a/drivers/CpuUid.cpp +++ b/drivers/CpuUid.cpp @@ -22,59 +22,50 @@ namespace mbed { +uint8_t CpuUid::_uidbuf[MBED_CPU_UID_SIZE] = {0}; +uint8_t* CpuUid::_uidptr = NULL; +char CpuUid::_strbuf[CPU_UID_STRING_BUFFER_SIZE] = {'\0'}; +char* CpuUid::_strptr = NULL; +#ifndef MBED_CPU_UID_STR_SIZE_MAX const char CpuUid::_hexChars[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; - -CpuUid::CpuUid() : _data(NULL) -{ - _size = cpu_uid_get_length(); -#ifdef MBED_ASSERT - MBED_ASSERT(_size > 0); #endif - if (0 < _size) { - _data = new uint8_t[_size]; - cpu_uid_get_uid(_data); - } + +CpuUid::CpuUid() +{ + populate_uid_buf(); } CpuUid::~CpuUid() { - if (_data) { - delete _data; +} + +void CpuUid::populate_uid_buf() +{ + if (_uidptr == NULL) { + cpu_uid_get_uid(_uidbuf); + _uidptr = _uidbuf; } } -CpuUid::operator std::string() +void CpuUid::populate_str_buf() { - std::string str; - - for (int i = 0; i < _size; ++i) { - str += _hexChars[_data[i] >> 4]; - str += _hexChars[_data[i] & 0x0F]; + if (_strptr == NULL) { +#ifdef MBED_CPU_UID_STR_SIZE_MAX + cpu_uid_get_str(_strbuf); + _strptr = _strbuf; +#else + int pos = 0; + populate_uid_buf(); + for (int i = 0; i < MBED_CPU_UID_SIZE; ++i) { + _strbuf[pos++] = _hexChars[_uidptr[i] >> 4]; + _strbuf[pos++] = _hexChars[_uidptr[i] & 0x0F]; + } + _strbuf[pos] = '\0'; + _strptr = _strbuf; +#endif } - - return str; } -CpuUid::operator cpu_uid_array_t() -{ - cpu_uid_array_t array; - - for (int i = 0; i < _size; ++i) { - array.push_back(_data[i]); - } - - return array; -} - -uint8_t CpuUid::operator[](int x) -{ - if (x >= 0 && x < _size) { - return _data[x]; - } - - return 0x00; -} - } // namespace mbed #endif diff --git a/drivers/CpuUid.h b/drivers/CpuUid.h index ada10b0fd9..4a27b418a3 100644 --- a/drivers/CpuUid.h +++ b/drivers/CpuUid.h @@ -20,6 +20,12 @@ #if defined(DEVICE_CPUUID) || defined(DOXYGEN_ONLY) +#ifdef MBED_CPU_UID_STR_SIZE_MAX +#define CPU_UID_STRING_BUFFER_SIZE MBED_CPU_UID_STR_SIZE_MAX +#else +#define CPU_UID_STRING_BUFFER_SIZE (MBED_CPU_UID_SIZE * 2 + 1) +#endif + #include #include @@ -33,10 +39,6 @@ namespace mbed { */ class CpuUid { public: - /** CPU UID array typedef - */ - typedef std::vector cpu_uid_array_t; - /** CpuUid constructor */ CpuUid(); @@ -51,7 +53,7 @@ public: */ int size() { - return _size; + return MBED_CPU_UID_SIZE; } /** Get CPU UID data pointer @@ -60,20 +62,26 @@ public: */ const uint8_t *data() { - return _data; + populate_uid_buf(); + return _uidptr; } - /** Overload operator for std::string + /** Get CPU UID vendor string * - * @return string object containing the CPU UID in uppercase hex letters in ascii format - */ - operator std::string(); - - /** Overload operator for cpu_uid_array_t + * @return Pointer to zero terminated uid vendor string + * + * @note + * If vendor did not define MBED_CPU_UID_STR_SIZE_MAX, CpuUid driver will + * assume the HAL interface function cpu_uid_get_str() is not implemented + * on the target, and instead the driver will construct just an ASCII + * string out of the uid byte buffer contents. * - * @return cpu_uid_array_t object containing the CPU UID */ - operator cpu_uid_array_t(); + const char *c_str() + { + populate_str_buf(); + return _strptr; + } /** Overload operator for byte pointer * @@ -81,7 +89,14 @@ public: */ operator const uint8_t*() { - return _data; + populate_uid_buf(); + return _uidptr; + } + + operator const char*() + { + populate_str_buf(); + return _strptr; } /** Overload operator for array subscript @@ -90,13 +105,27 @@ public: * * @return Byte located at index x */ - uint8_t operator[](int x); + uint8_t operator[](int x) + { + if (x >= 0 && x < MBED_CPU_UID_SIZE) { + populate_uid_buf(); + return _uidptr[x]; + } + + return 0x00; + } private: - uint8_t *_data; - int _size; + void populate_uid_buf(); + void populate_str_buf(); + static uint8_t _uidbuf[MBED_CPU_UID_SIZE]; + static uint8_t* _uidptr; + static char _strbuf[CPU_UID_STRING_BUFFER_SIZE]; + static char* _strptr; +#ifndef MBED_CPU_UID_STR_SIZE_MAX static const char _hexChars[16]; +#endif }; } // namespace mbed diff --git a/hal/cpu_uid_api.h b/hal/cpu_uid_api.h index 06d90573fd..dcb7a16114 100644 --- a/hal/cpu_uid_api.h +++ b/hal/cpu_uid_api.h @@ -23,6 +23,14 @@ #if DEVICE_CPUUID +#ifndef MBED_CPU_UID_SIZE +#error "CPU UID Vendor implementation must define macro MBED_CPU_UID_SIZE with the uid size in bytes!" +#endif + +#ifndef MBED_CPU_UID_STR_SIZE_MAX +#warning "CPU UID max vendor string length not defined! cpu_uid_get_str() HAL interface is disabled!" +#endif + #ifdef __cplusplus extern "C" { #endif @@ -32,25 +40,26 @@ extern "C" { * @{ */ - -/** Get length of CPU UID in bytes - * - * @return Number of uid bytes - * - * @note - * Shall be used by the driver to get the needed size of the byte buffer. - * Target implementation must return a value higher than 0 or the driver will assert. - * - */ -int cpu_uid_get_length(void); - /** Get CPU UID data bytes * - * @param uid Byte buffer for uid. Must at least be of size obtained by call to cpu_uid_get_length() + * @param uid Byte buffer for uid. Must be of size MBED_CPU_UID_SIZE * */ void cpu_uid_get_uid(uint8_t *uid); +#ifdef MBED_CPU_UID_STR_SIZE_MAX +/** Get UID vendor string + * + * @param str Character buffer for vendor specific UID string. Must be of size MBED_CPU_UID_STR_SIZE_MAX + * + * @note + * Implementing this function on target side can be used to provide a vendor specific + * string describing the contents of the UID. + * The string length including terminating zero character must not exceed MBED_CPU_UID_STR_SIZE_MAX bytes! + * + */ +void cpu_uid_get_str(char *str); +#endif /**@}*/ diff --git a/targets/TARGET_NORDIC/TARGET_NRF5/cpu_uid_api.c b/targets/TARGET_NORDIC/TARGET_NRF5/cpu_uid_api.c index f71ecf1ab3..3e33baae6b 100644 --- a/targets/TARGET_NORDIC/TARGET_NRF5/cpu_uid_api.c +++ b/targets/TARGET_NORDIC/TARGET_NRF5/cpu_uid_api.c @@ -43,24 +43,15 @@ #include "nrf.h" #include "cpu_uid_api.h" -#define UID_LENGTH 8 #define UID_WORDS 2 -int cpu_uid_get_length(void) -{ - return UID_LENGTH; -} - void cpu_uid_get_uid(uint8_t *uid) { int pos = 0; - for (int i = (UID_WORDS-1); i >= 0; --i) - { - for (int j = 3; j >= 0; --j) - { - uid[pos] = (uint8_t)((NRF_FICR->DEVICEID[i] >> (j*8)) & 0xFF); - ++pos; + for (int i = (UID_WORDS-1); i >= 0; --i) { + for (int j = 3; j >= 0; --j) { + uid[pos++] = (uint8_t)((NRF_FICR->DEVICEID[i] >> (j*8)) & 0xFF); } } } diff --git a/targets/TARGET_STM/cpu_uid_api.c b/targets/TARGET_STM/cpu_uid_api.c index f354a6eb27..edbd8ee84b 100644 --- a/targets/TARGET_STM/cpu_uid_api.c +++ b/targets/TARGET_STM/cpu_uid_api.c @@ -31,6 +31,7 @@ #if DEVICE_CPUUID +#include #if defined(TARGET_STM32F0) #include "stm32f0xx_ll_utils.h" #elif defined(TARGET_STM32F1) @@ -54,14 +55,11 @@ #endif #include "cpu_uid_api.h" -#define UID_LENGTH 12 #define UID_WORDS 3 - -int cpu_uid_get_length(void) -{ - return UID_LENGTH; -} +#ifdef MBED_CPU_UID_STR_SIZE_MAX +static int cpu_uid_itoa(int value, char *sp, int radix); +#endif void cpu_uid_get_uid(uint8_t *uid) { @@ -72,14 +70,82 @@ void cpu_uid_get_uid(uint8_t *uid) uid_buf[1] = LL_GetUID_Word1(); uid_buf[2] = LL_GetUID_Word2(); - for (int i = (UID_WORDS-1); i >= 0; --i) - { - for (int j = 3; j >= 0; --j) - { - uid[pos] = (uint8_t)((uid_buf[i] >> (j*8)) & 0xFF); - ++pos; + for (int i = (UID_WORDS-1); i >= 0; --i) { + for (int j = 3; j >= 0; --j) { + uid[pos++] = (uint8_t)((uid_buf[i] >> (j*8)) & 0xFF); } } } +#ifdef MBED_CPU_UID_STR_SIZE_MAX +void cpu_uid_get_str(char *str) +{ + char buffer[16]; + char lot_number[8]; + uint8_t wafer_number; + uint16_t x, y; + uint32_t uid_buf[UID_WORDS]; + + uid_buf[0] = LL_GetUID_Word0(); + uid_buf[1] = LL_GetUID_Word1(); + uid_buf[2] = LL_GetUID_Word2(); + + lot_number[0] = (uid_buf[2] >> 24) & 0x000000FF; + lot_number[1] = (uid_buf[2] >> 16) & 0x000000FF; + lot_number[2] = (uid_buf[2] >> 8) & 0x000000FF; + lot_number[3] = uid_buf[2] & 0x000000FF; + lot_number[4] = (uid_buf[1] >> 24) & 0x000000FF; + lot_number[5] = (uid_buf[1] >> 16) & 0x000000FF; + lot_number[6] = (uid_buf[1] >> 8) & 0x000000FF; + lot_number[7] = '\0'; + + wafer_number = uid_buf[1] & 0x000000FF; + + x = (uid_buf[0] >> 16) & 0x0000FFFF; + y = uid_buf[0] & 0x0000FFFF; + + // make a string in format "Lot xxxxxxx Wafer xxx X=xxxxx Y=xxxxx" - max 38 chars including terminating zero + strcpy(str, "Lot "); + strcat(str, lot_number); + strcat(str, " Wafer "); + cpu_uid_itoa(wafer_number, buffer, 10); + strcat(str, buffer); + strcat(str, " X="); + cpu_uid_itoa(x, buffer, 10); + strcat(str, buffer); + strcat(str, " Y="); + cpu_uid_itoa(y, buffer, 10); + strcat(str, buffer); +} + +int cpu_uid_itoa(int value, char *sp, int radix) +{ + char tmp[16];// be careful with the length of the buffer + char *tp = tmp; + int i; + unsigned v = value; + + while (v || tp == tmp) { + i = v % radix; + v /= radix; // v/=radix uses less CPU clocks than v=v/radix does + if (i < 10) { + *tp++ = i+'0'; + } + else { + *tp++ = i + 'a' - 10; + } + } + + int len = tp - tmp; + + while (tp > tmp) { + *sp++ = *--tp; + } + *sp = '\0'; + + return len; +} + +#endif + #endif diff --git a/targets/TARGET_Silicon_Labs/TARGET_EFM32/cpu_uid_api.c b/targets/TARGET_Silicon_Labs/TARGET_EFM32/cpu_uid_api.c index 0c86ec18f7..d755c4493f 100644 --- a/targets/TARGET_Silicon_Labs/TARGET_EFM32/cpu_uid_api.c +++ b/targets/TARGET_Silicon_Labs/TARGET_EFM32/cpu_uid_api.c @@ -28,22 +28,14 @@ #include "em_system.h" #include "cpu_uid_api.h" -#define UID_LENGTH 8 - -int cpu_uid_get_length(void) -{ - return UID_LENGTH; -} void cpu_uid_get_uid(uint8_t *uid) { int pos = 0; uint64_t tempuid = SYSTEM_GetUnique(); - for (int i = (UID_LENGTH-1); i >= 0; --i) - { - uid[pos] = (uint8_t)((tempuid >> (i*8)) & 0xFF); - ++pos; + for (int i = (MBED_CPU_UID_SIZE - 1); i >= 0; --i) { + uid[pos++] = (uint8_t)((tempuid >> (i*8)) & 0xFF); } } diff --git a/targets/targets.json b/targets/targets.json index 3af824e978..c89934fd2f 100644 --- a/targets/targets.json +++ b/targets/targets.json @@ -705,7 +705,7 @@ "public": false, "extra_labels": ["STM"], "supported_toolchains": ["ARM", "uARM", "IAR", "GCC_ARM"], - "macros": ["TRANSACTION_QUEUE_SIZE_SPI=2"], + "macros": ["TRANSACTION_QUEUE_SIZE_SPI=2", "MBED_CPU_UID_SIZE=12", "MBED_CPU_UID_STR_SIZE_MAX=38"], "config": { "lse_available": { "help": "Define if a Low Speed External xtal (LSE) is available on the board (0 = No, 1 = Yes). If Yes, the LSE will be used to clock the RTC, LPUART, ... otherwise the Low Speed Internal clock (LSI) will be used", @@ -2590,7 +2590,7 @@ "EFM32": { "inherits": ["Target"], "extra_labels": ["Silicon_Labs", "EFM32"], - "macros": ["MBEDTLS_CONFIG_HW_SUPPORT"], + "macros": ["MBEDTLS_CONFIG_HW_SUPPORT", "MBED_CPU_UID_SIZE=8"], "public": false }, "EFM32GG990F1024": { @@ -3212,7 +3212,8 @@ "CMSIS_VECTAB_VIRTUAL", "CMSIS_VECTAB_VIRTUAL_HEADER_FILE=\"cmsis_nvic.h\"", "NO_SYSTICK", - "MBED_TICKLESS" + "MBED_TICKLESS", + "MBED_CPU_UID_SIZE=8" ], "MERGE_BOOTLOADER": false, "extra_labels": ["NORDIC", "MCU_NRF51", "MCU_NRF51822_UNIFIED", "NRF5", "SDK11"], @@ -3270,7 +3271,7 @@ "MCU_NRF52": { "inherits": ["Target"], "core": "Cortex-M4F", - "macros": ["NRF52", "TARGET_NRF52832", "BLE_STACK_SUPPORT_REQD", "SOFTDEVICE_PRESENT", "S132", "CMSIS_VECTAB_VIRTUAL", "CMSIS_VECTAB_VIRTUAL_HEADER_FILE=\"cmsis_nvic.h\"", "MBED_TICKLESS"], + "macros": ["NRF52", "TARGET_NRF52832", "BLE_STACK_SUPPORT_REQD", "SOFTDEVICE_PRESENT", "S132", "CMSIS_VECTAB_VIRTUAL", "CMSIS_VECTAB_VIRTUAL_HEADER_FILE=\"cmsis_nvic.h\"", "MBED_TICKLESS", "MBED_CPU_UID_SIZE=8"], "device_has": ["STCLK_OFF_DURING_SLEEP", "CPUUID"], "extra_labels": ["NORDIC", "MCU_NRF52", "MCU_NRF52832", "NRF5", "SDK11", "NRF52_COMMON"], "OUTPUT_EXT": "hex",