1eb886013SMatthias Ringwald /* 2eb886013SMatthias Ringwald * Copyright (C) 2014 BlueKitchen GmbH 3eb886013SMatthias Ringwald * 4eb886013SMatthias Ringwald * Redistribution and use in source and binary forms, with or without 5eb886013SMatthias Ringwald * modification, are permitted provided that the following conditions 6eb886013SMatthias Ringwald * are met: 7eb886013SMatthias Ringwald * 8eb886013SMatthias Ringwald * 1. Redistributions of source code must retain the above copyright 9eb886013SMatthias Ringwald * notice, this list of conditions and the following disclaimer. 10eb886013SMatthias Ringwald * 2. Redistributions in binary form must reproduce the above copyright 11eb886013SMatthias Ringwald * notice, this list of conditions and the following disclaimer in the 12eb886013SMatthias Ringwald * documentation and/or other materials provided with the distribution. 13eb886013SMatthias Ringwald * 3. Neither the name of the copyright holders nor the names of 14eb886013SMatthias Ringwald * contributors may be used to endorse or promote products derived 15eb886013SMatthias Ringwald * from this software without specific prior written permission. 16eb886013SMatthias Ringwald * 4. Any redistribution, use, or modification is done solely for 17eb886013SMatthias Ringwald * personal benefit and not for any commercial purpose or for 18eb886013SMatthias Ringwald * monetary gain. 19eb886013SMatthias Ringwald * 20eb886013SMatthias Ringwald * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS 21eb886013SMatthias Ringwald * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22eb886013SMatthias Ringwald * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 232fca4dadSMilanka Ringwald * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN 242fca4dadSMilanka Ringwald * GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25eb886013SMatthias Ringwald * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 26eb886013SMatthias Ringwald * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 27eb886013SMatthias Ringwald * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 28eb886013SMatthias Ringwald * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29eb886013SMatthias Ringwald * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 30eb886013SMatthias Ringwald * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31eb886013SMatthias Ringwald * SUCH DAMAGE. 32eb886013SMatthias Ringwald * 33eb886013SMatthias Ringwald * Please inquire about commercial licensing options at 34eb886013SMatthias Ringwald * [email protected] 35eb886013SMatthias Ringwald * 36eb886013SMatthias Ringwald */ 37eb886013SMatthias Ringwald 38e501bae0SMatthias Ringwald #define BTSTACK_FILE__ "btstack_util.c" 39ab2c6ae4SMatthias Ringwald 40eb886013SMatthias Ringwald /* 41eb886013SMatthias Ringwald * General utility functions 42eb886013SMatthias Ringwald */ 43eb886013SMatthias Ringwald 447907f069SMatthias Ringwald #include "btstack_config.h" 4502bdfbf8SMatthias Ringwald #include "btstack_debug.h" 46eb886013SMatthias Ringwald #include "btstack_util.h" 4702bdfbf8SMatthias Ringwald 48ec08441fSMatthias Ringwald #ifdef _MSC_VER 49ec08441fSMatthias Ringwald #include <intrin.h> 50ec08441fSMatthias Ringwald #include <windows.h> 51ec08441fSMatthias Ringwald #endif 52ec08441fSMatthias Ringwald 5346059ae4SMilanka Ringwald #ifdef ENABLE_PRINTF_HEXDUMP 54eb886013SMatthias Ringwald #include <stdio.h> 5546059ae4SMilanka Ringwald #endif 5646059ae4SMilanka Ringwald 57eb886013SMatthias Ringwald #include <string.h> 58eb886013SMatthias Ringwald 5973988a59SMatthias Ringwald /** 6073988a59SMatthias Ringwald * @brief Compare two Bluetooth addresses 6173988a59SMatthias Ringwald * @param a 6273988a59SMatthias Ringwald * @param b 63969fc1c5SMilanka Ringwald * @return 0 if equal 6473988a59SMatthias Ringwald */ 655222912bSMatthias Ringwald int bd_addr_cmp(const bd_addr_t a, const bd_addr_t b){ 6673988a59SMatthias Ringwald return memcmp(a,b, BD_ADDR_LEN); 6773988a59SMatthias Ringwald } 6873988a59SMatthias Ringwald 6973988a59SMatthias Ringwald /** 7073988a59SMatthias Ringwald * @brief Copy Bluetooth address 7173988a59SMatthias Ringwald * @param dest 7273988a59SMatthias Ringwald * @param src 7373988a59SMatthias Ringwald */ 745222912bSMatthias Ringwald void bd_addr_copy(bd_addr_t dest, const bd_addr_t src){ 756535961aSMatthias Ringwald (void)memcpy(dest, src, BD_ADDR_LEN); 7673988a59SMatthias Ringwald } 7773988a59SMatthias Ringwald 7841f9be70SMatthias Ringwald uint16_t little_endian_read_16(const uint8_t * buffer, int position){ 7941f9be70SMatthias Ringwald return (uint16_t)(((uint16_t) buffer[position]) | (((uint16_t)buffer[position+1]) << 8)); 8073988a59SMatthias Ringwald } 8141f9be70SMatthias Ringwald uint32_t little_endian_read_24(const uint8_t * buffer, int position){ 8241f9be70SMatthias Ringwald return ((uint32_t) buffer[position]) | (((uint32_t)buffer[position+1]) << 8) | (((uint32_t)buffer[position+2]) << 16); 8373988a59SMatthias Ringwald } 8441f9be70SMatthias Ringwald uint32_t little_endian_read_32(const uint8_t * buffer, int position){ 8541f9be70SMatthias Ringwald return ((uint32_t) buffer[position]) | (((uint32_t)buffer[position+1]) << 8) | (((uint32_t)buffer[position+2]) << 16) | (((uint32_t) buffer[position+3]) << 24); 8673988a59SMatthias Ringwald } 8773988a59SMatthias Ringwald 8841f9be70SMatthias Ringwald void little_endian_store_16(uint8_t * buffer, uint16_t position, uint16_t value){ 8941f9be70SMatthias Ringwald uint16_t pos = position; 90b0920f25SMilanka Ringwald buffer[pos++] = (uint8_t)value; 91b0920f25SMilanka Ringwald buffer[pos++] = (uint8_t)(value >> 8); 92eb886013SMatthias Ringwald } 93eb886013SMatthias Ringwald 9441f9be70SMatthias Ringwald void little_endian_store_24(uint8_t * buffer, uint16_t position, uint32_t value){ 9541f9be70SMatthias Ringwald uint16_t pos = position; 96adbdd27aSMilanka Ringwald buffer[pos++] = (uint8_t)(value); 97adbdd27aSMilanka Ringwald buffer[pos++] = (uint8_t)(value >> 8); 98adbdd27aSMilanka Ringwald buffer[pos++] = (uint8_t)(value >> 16); 99adbdd27aSMilanka Ringwald } 100adbdd27aSMilanka Ringwald 10141f9be70SMatthias Ringwald void little_endian_store_32(uint8_t * buffer, uint16_t position, uint32_t value){ 10241f9be70SMatthias Ringwald uint16_t pos = position; 103b0920f25SMilanka Ringwald buffer[pos++] = (uint8_t)(value); 104b0920f25SMilanka Ringwald buffer[pos++] = (uint8_t)(value >> 8); 105b0920f25SMilanka Ringwald buffer[pos++] = (uint8_t)(value >> 16); 106b0920f25SMilanka Ringwald buffer[pos++] = (uint8_t)(value >> 24); 107eb886013SMatthias Ringwald } 108eb886013SMatthias Ringwald 10941f9be70SMatthias Ringwald uint32_t big_endian_read_16(const uint8_t * buffer, int position) { 11041f9be70SMatthias Ringwald return (uint16_t)(((uint16_t) buffer[position+1]) | (((uint16_t)buffer[position]) << 8)); 11173988a59SMatthias Ringwald } 11273988a59SMatthias Ringwald 11341f9be70SMatthias Ringwald uint32_t big_endian_read_24(const uint8_t * buffer, int position) { 11441f9be70SMatthias Ringwald return ( ((uint32_t)buffer[position+2]) | (((uint32_t)buffer[position+1]) << 8) | (((uint32_t) buffer[position]) << 16)); 115e57a2545SMilanka Ringwald } 116e57a2545SMilanka Ringwald 11741f9be70SMatthias Ringwald uint32_t big_endian_read_32(const uint8_t * buffer, int position) { 11841f9be70SMatthias Ringwald return ((uint32_t) buffer[position+3]) | (((uint32_t)buffer[position+2]) << 8) | (((uint32_t)buffer[position+1]) << 16) | (((uint32_t) buffer[position]) << 24); 11973988a59SMatthias Ringwald } 12073988a59SMatthias Ringwald 12141f9be70SMatthias Ringwald void big_endian_store_16(uint8_t * buffer, uint16_t position, uint16_t value){ 12241f9be70SMatthias Ringwald uint16_t pos = position; 123b0920f25SMilanka Ringwald buffer[pos++] = (uint8_t)(value >> 8); 124b0920f25SMilanka Ringwald buffer[pos++] = (uint8_t)(value); 125eb886013SMatthias Ringwald } 126eb886013SMatthias Ringwald 12741f9be70SMatthias Ringwald void big_endian_store_24(uint8_t * buffer, uint16_t position, uint32_t value){ 12841f9be70SMatthias Ringwald uint16_t pos = position; 129b0920f25SMilanka Ringwald buffer[pos++] = (uint8_t)(value >> 16); 130b0920f25SMilanka Ringwald buffer[pos++] = (uint8_t)(value >> 8); 131b0920f25SMilanka Ringwald buffer[pos++] = (uint8_t)(value); 1327f535380SMilanka Ringwald } 1337f535380SMilanka Ringwald 13441f9be70SMatthias Ringwald void big_endian_store_32(uint8_t * buffer, uint16_t position, uint32_t value){ 13541f9be70SMatthias Ringwald uint16_t pos = position; 136b0920f25SMilanka Ringwald buffer[pos++] = (uint8_t)(value >> 24); 137b0920f25SMilanka Ringwald buffer[pos++] = (uint8_t)(value >> 16); 138b0920f25SMilanka Ringwald buffer[pos++] = (uint8_t)(value >> 8); 139b0920f25SMilanka Ringwald buffer[pos++] = (uint8_t)(value); 140eb886013SMatthias Ringwald } 141eb886013SMatthias Ringwald 142eb886013SMatthias Ringwald // general swap/endianess utils 143b45b7749SMilanka Ringwald void reverse_bytes(const uint8_t * src, uint8_t * dest, int len){ 144eb886013SMatthias Ringwald int i; 145eb886013SMatthias Ringwald for (i = 0; i < len; i++) 146b45b7749SMilanka Ringwald dest[len - 1 - i] = src[i]; 147eb886013SMatthias Ringwald } 148b45b7749SMilanka Ringwald void reverse_24(const uint8_t * src, uint8_t * dest){ 149b45b7749SMilanka Ringwald reverse_bytes(src, dest, 3); 150eb886013SMatthias Ringwald } 151b45b7749SMilanka Ringwald void reverse_48(const uint8_t * src, uint8_t * dest){ 152b45b7749SMilanka Ringwald reverse_bytes(src, dest, 6); 153bf1b35bfSMatthias Ringwald } 154b45b7749SMilanka Ringwald void reverse_56(const uint8_t * src, uint8_t * dest){ 155b45b7749SMilanka Ringwald reverse_bytes(src, dest, 7); 156eb886013SMatthias Ringwald } 157b45b7749SMilanka Ringwald void reverse_64(const uint8_t * src, uint8_t * dest){ 158b45b7749SMilanka Ringwald reverse_bytes(src, dest, 8); 159eb886013SMatthias Ringwald } 160b45b7749SMilanka Ringwald void reverse_128(const uint8_t * src, uint8_t * dest){ 161b45b7749SMilanka Ringwald reverse_bytes(src, dest, 16); 162eb886013SMatthias Ringwald } 163b45b7749SMilanka Ringwald void reverse_256(const uint8_t * src, uint8_t * dest){ 164b45b7749SMilanka Ringwald reverse_bytes(src, dest, 32); 165cc7a2d78SMatthias Ringwald } 166eb886013SMatthias Ringwald 167724d70a2SMatthias Ringwald void reverse_bd_addr(const bd_addr_t src, bd_addr_t dest){ 168724d70a2SMatthias Ringwald reverse_bytes(src, dest, 6); 169724d70a2SMatthias Ringwald } 170724d70a2SMatthias Ringwald 17177955af6SMatthias Ringwald bool btstack_is_null(const uint8_t * buffer, uint16_t size){ 17277955af6SMatthias Ringwald uint16_t i; 17377955af6SMatthias Ringwald for (i=0; i < size ; i++){ 17477955af6SMatthias Ringwald if (buffer[i] != 0) { 17577955af6SMatthias Ringwald return false; 17677955af6SMatthias Ringwald } 17777955af6SMatthias Ringwald } 17877955af6SMatthias Ringwald return true; 17977955af6SMatthias Ringwald } 18077955af6SMatthias Ringwald 1816d708481SDirk Helbig bool btstack_is_null_bd_addr( const bd_addr_t addr ){ 1826d708481SDirk Helbig return btstack_is_null( addr, sizeof(bd_addr_t) ); 1836d708481SDirk Helbig } 1846d708481SDirk Helbig 185ebaeb1beSMatthias Ringwald uint32_t btstack_min(uint32_t a, uint32_t b){ 186c1ab6cc1SMatthias Ringwald return (a < b) ? a : b; 187ebaeb1beSMatthias Ringwald } 188ebaeb1beSMatthias Ringwald 189ebaeb1beSMatthias Ringwald uint32_t btstack_max(uint32_t a, uint32_t b){ 190c1ab6cc1SMatthias Ringwald return (a > b) ? a : b; 191ebaeb1beSMatthias Ringwald } 192ebaeb1beSMatthias Ringwald 19368af3967SMatthias Ringwald /** 194a9d566f7SMatthias Ringwald * @brief Calculate delta between two uint32_t points in time 1956b65794dSMilanka Ringwald * @return time_a - time_b - result > 0 if time_a is newer than time_b 19668af3967SMatthias Ringwald */ 19768af3967SMatthias Ringwald int32_t btstack_time_delta(uint32_t time_a, uint32_t time_b){ 19868af3967SMatthias Ringwald return (int32_t)(time_a - time_b); 19968af3967SMatthias Ringwald } 20068af3967SMatthias Ringwald 201a9d566f7SMatthias Ringwald /** 202a9d566f7SMatthias Ringwald * @brief Calculate delta between two uint16_t points in time 203a9d566f7SMatthias Ringwald * @return time_a - time_b - result > 0 if time_a is newer than time_b 204a9d566f7SMatthias Ringwald */ 205a9d566f7SMatthias Ringwald int16_t btstack_time16_delta(uint16_t time_a, uint16_t time_b){ 206a9d566f7SMatthias Ringwald return (int16_t)(time_a - time_b); 207a9d566f7SMatthias Ringwald } 208c1c58647SMatthias Ringwald 209d7d45b32SMatthias Ringwald char char_for_nibble(uint8_t nibble){ 2108334d3d8SMatthias Ringwald 2118334d3d8SMatthias Ringwald static const char * char_to_nibble = "0123456789ABCDEF"; 2128334d3d8SMatthias Ringwald 213c1c58647SMatthias Ringwald if (nibble < 16){ 214c1c58647SMatthias Ringwald return char_to_nibble[nibble]; 215c1c58647SMatthias Ringwald } else { 216eb886013SMatthias Ringwald return '?'; 217eb886013SMatthias Ringwald } 218c1c58647SMatthias Ringwald } 219eb886013SMatthias Ringwald 220405d63a9SMatthias Ringwald static inline char char_for_high_nibble(int value){ 221405d63a9SMatthias Ringwald return char_for_nibble((value >> 4) & 0x0f); 222405d63a9SMatthias Ringwald } 223405d63a9SMatthias Ringwald 224405d63a9SMatthias Ringwald static inline char char_for_low_nibble(int value){ 225405d63a9SMatthias Ringwald return char_for_nibble(value & 0x0f); 226405d63a9SMatthias Ringwald } 227405d63a9SMatthias Ringwald 228c1c58647SMatthias Ringwald 229a6efb919SMatthias Ringwald int nibble_for_char(char c){ 230c1ab6cc1SMatthias Ringwald if ((c >= '0') && (c <= '9')) return c - '0'; 231c1ab6cc1SMatthias Ringwald if ((c >= 'a') && (c <= 'f')) return c - 'a' + 10; 232c1ab6cc1SMatthias Ringwald if ((c >= 'A') && (c <= 'F')) return c - 'A' + 10; 233a6efb919SMatthias Ringwald return -1; 234a6efb919SMatthias Ringwald } 235a6efb919SMatthias Ringwald 23646059ae4SMilanka Ringwald #ifdef ENABLE_PRINTF_HEXDUMP 237eb886013SMatthias Ringwald void printf_hexdump(const void * data, int size){ 238c1c58647SMatthias Ringwald char buffer[4]; 239c1c58647SMatthias Ringwald buffer[2] = ' '; 240c1c58647SMatthias Ringwald buffer[3] = 0; 2419dbfa930SMatthias Ringwald const uint8_t * ptr = (const uint8_t *) data; 242c1c58647SMatthias Ringwald while (size > 0){ 2439dbfa930SMatthias Ringwald uint8_t byte = *ptr++; 244c1c58647SMatthias Ringwald buffer[0] = char_for_high_nibble(byte); 245c1c58647SMatthias Ringwald buffer[1] = char_for_low_nibble(byte); 246c1c58647SMatthias Ringwald printf("%s", buffer); 247c1c58647SMatthias Ringwald size--; 248eb886013SMatthias Ringwald } 249eb886013SMatthias Ringwald printf("\n"); 250eb886013SMatthias Ringwald } 25146059ae4SMilanka Ringwald #endif 252eb886013SMatthias Ringwald 253cb42147aSMatthias Ringwald #if defined(ENABLE_LOG_INFO) || defined(ENABLE_LOG_DEBUG) 254cb42147aSMatthias Ringwald static void log_hexdump(int level, const void * data, int size){ 255405d63a9SMatthias Ringwald #define ITEMS_PER_LINE 16 256405d63a9SMatthias Ringwald // template '0x12, ' 257405d63a9SMatthias Ringwald #define BYTES_PER_BYTE 6 258405d63a9SMatthias Ringwald char buffer[BYTES_PER_BYTE*ITEMS_PER_LINE+1]; 2597224be7eSMatthias Ringwald int i, j; 260eb886013SMatthias Ringwald j = 0; 261eb886013SMatthias Ringwald for (i=0; i<size;i++){ 2627224be7eSMatthias Ringwald 2637224be7eSMatthias Ringwald // help static analyzer proof that j stays within bounds 264c1ab6cc1SMatthias Ringwald if (j > (BYTES_PER_BYTE * (ITEMS_PER_LINE-1))){ 2657224be7eSMatthias Ringwald j = 0; 2667224be7eSMatthias Ringwald } 2677224be7eSMatthias Ringwald 268eb886013SMatthias Ringwald uint8_t byte = ((uint8_t *)data)[i]; 269eb886013SMatthias Ringwald buffer[j++] = '0'; 270eb886013SMatthias Ringwald buffer[j++] = 'x'; 271405d63a9SMatthias Ringwald buffer[j++] = char_for_high_nibble(byte); 272405d63a9SMatthias Ringwald buffer[j++] = char_for_low_nibble(byte); 273eb886013SMatthias Ringwald buffer[j++] = ','; 274eb886013SMatthias Ringwald buffer[j++] = ' '; 2757224be7eSMatthias Ringwald 276c1ab6cc1SMatthias Ringwald if (j >= (BYTES_PER_BYTE * ITEMS_PER_LINE) ){ 277eb886013SMatthias Ringwald buffer[j] = 0; 278cb42147aSMatthias Ringwald HCI_DUMP_LOG(level, "%s", buffer); 279eb886013SMatthias Ringwald j = 0; 280eb886013SMatthias Ringwald } 281eb886013SMatthias Ringwald } 282eb886013SMatthias Ringwald if (j != 0){ 283eb886013SMatthias Ringwald buffer[j] = 0; 284cb42147aSMatthias Ringwald HCI_DUMP_LOG(level, "%s", buffer); 285eb886013SMatthias Ringwald } 286cb42147aSMatthias Ringwald } 287cb42147aSMatthias Ringwald #endif 288cb42147aSMatthias Ringwald 289cb42147aSMatthias Ringwald void log_debug_hexdump(const void * data, int size){ 290e950fa96SMatthias Ringwald #ifdef ENABLE_LOG_DEBUG 291fa087deaSMatthias Ringwald log_hexdump(HCI_DUMP_LOG_LEVEL_DEBUG, data, size); 292cb42147aSMatthias Ringwald #else 2934bd79111SMatthias Ringwald UNUSED(data); // ok: no code 2944bd79111SMatthias Ringwald UNUSED(size); // ok: no code 295cb42147aSMatthias Ringwald #endif 296cb42147aSMatthias Ringwald } 297cb42147aSMatthias Ringwald 298cb42147aSMatthias Ringwald void log_info_hexdump(const void * data, int size){ 299cb42147aSMatthias Ringwald #ifdef ENABLE_LOG_INFO 300fa087deaSMatthias Ringwald log_hexdump(HCI_DUMP_LOG_LEVEL_INFO, data, size); 301d0662982SMatthias Ringwald #else 3024bd79111SMatthias Ringwald UNUSED(data); // ok: no code 3034bd79111SMatthias Ringwald UNUSED(size); // ok: no code 3048314c363SMatthias Ringwald #endif 3057299c0feSMatthias Ringwald } 306eb886013SMatthias Ringwald 3078314c363SMatthias Ringwald void log_info_key(const char * name, sm_key_t key){ 30802bdfbf8SMatthias Ringwald #ifdef ENABLE_LOG_INFO 30902bdfbf8SMatthias Ringwald char buffer[16*2+1]; 31002bdfbf8SMatthias Ringwald int i; 31102bdfbf8SMatthias Ringwald int j = 0; 31202bdfbf8SMatthias Ringwald for (i=0; i<16;i++){ 31302bdfbf8SMatthias Ringwald uint8_t byte = key[i]; 314405d63a9SMatthias Ringwald buffer[j++] = char_for_high_nibble(byte); 315405d63a9SMatthias Ringwald buffer[j++] = char_for_low_nibble(byte); 31602bdfbf8SMatthias Ringwald } 31702bdfbf8SMatthias Ringwald buffer[j] = 0; 31802bdfbf8SMatthias Ringwald log_info("%-6s %s", name, buffer); 319d0662982SMatthias Ringwald #else 320d0662982SMatthias Ringwald UNUSED(name); 321cb42147aSMatthias Ringwald (void)key; 32202bdfbf8SMatthias Ringwald #endif 323eb886013SMatthias Ringwald } 324eb886013SMatthias Ringwald 3252b604902SMatthias Ringwald // UUIDs are stored in big endian, similar to bd_addr_t 3262b604902SMatthias Ringwald 327eb886013SMatthias Ringwald // Bluetooth Base UUID: 00000000-0000-1000-8000- 00805F9B34FB 3282b604902SMatthias Ringwald const uint8_t bluetooth_base_uuid[] = { 0x00, 0x00, 0x00, 0x00, /* - */ 0x00, 0x00, /* - */ 0x10, 0x00, /* - */ 329eb886013SMatthias Ringwald 0x80, 0x00, /* - */ 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB }; 330eb886013SMatthias Ringwald 33148cdff9cSMilanka Ringwald void uuid_add_bluetooth_prefix(uint8_t * uuid128, uint32_t short_uuid){ 332b45b7749SMilanka Ringwald (void)memcpy(uuid128, bluetooth_base_uuid, 16); 33348cdff9cSMilanka Ringwald big_endian_store_32(uuid128, 0, short_uuid); 334eb886013SMatthias Ringwald } 335eb886013SMatthias Ringwald 336*8933879eSMatthias Ringwald bool uuid_has_bluetooth_prefix(const uint8_t * uuid128){ 3372b604902SMatthias Ringwald return memcmp(&uuid128[4], &bluetooth_base_uuid[4], 12) == 0; 338eb886013SMatthias Ringwald } 339eb886013SMatthias Ringwald 340eb886013SMatthias Ringwald static char uuid128_to_str_buffer[32+4+1]; 3415222912bSMatthias Ringwald char * uuid128_to_str(const uint8_t * uuid){ 3427224be7eSMatthias Ringwald int i; 3437224be7eSMatthias Ringwald int j = 0; 3447224be7eSMatthias Ringwald // after 4, 6, 8, and 10 bytes = XYXYXYXY-XYXY-XYXY-XYXY-XYXYXYXYXYXY, there's a dash 3457224be7eSMatthias Ringwald const int dash_locations = (1<<3) | (1<<5) | (1<<7) | (1<<9); 3467224be7eSMatthias Ringwald for (i=0;i<16;i++){ 347405d63a9SMatthias Ringwald uint8_t byte = uuid[i]; 348405d63a9SMatthias Ringwald uuid128_to_str_buffer[j++] = char_for_high_nibble(byte); 349405d63a9SMatthias Ringwald uuid128_to_str_buffer[j++] = char_for_low_nibble(byte); 3507224be7eSMatthias Ringwald if (dash_locations & (1<<i)){ 3517224be7eSMatthias Ringwald uuid128_to_str_buffer[j++] = '-'; 3527224be7eSMatthias Ringwald } 3537224be7eSMatthias Ringwald } 354eb886013SMatthias Ringwald return uuid128_to_str_buffer; 355eb886013SMatthias Ringwald } 356eb886013SMatthias Ringwald 357eb886013SMatthias Ringwald static char bd_addr_to_str_buffer[6*3]; // 12:45:78:01:34:67\0 35861c3ec28SMatthias Ringwald char * bd_addr_to_str_with_delimiter(const bd_addr_t addr, char delimiter){ 359eb886013SMatthias Ringwald char * p = bd_addr_to_str_buffer; 360eb886013SMatthias Ringwald int i; 361eb886013SMatthias Ringwald for (i = 0; i < 6 ; i++) { 362405d63a9SMatthias Ringwald uint8_t byte = addr[i]; 363405d63a9SMatthias Ringwald *p++ = char_for_high_nibble(byte); 364405d63a9SMatthias Ringwald *p++ = char_for_low_nibble(byte); 36561c3ec28SMatthias Ringwald *p++ = delimiter; 366eb886013SMatthias Ringwald } 367eb886013SMatthias Ringwald *--p = 0; 368eb886013SMatthias Ringwald return (char *) bd_addr_to_str_buffer; 369eb886013SMatthias Ringwald } 370eb886013SMatthias Ringwald 37161c3ec28SMatthias Ringwald char * bd_addr_to_str(const bd_addr_t addr){ 37261c3ec28SMatthias Ringwald return bd_addr_to_str_with_delimiter(addr, ':'); 37361c3ec28SMatthias Ringwald } 37461c3ec28SMatthias Ringwald 3753c9da642SMatthias Ringwald void btstack_replace_bd_addr_placeholder(uint8_t * buffer, uint16_t size, const bd_addr_t address){ 3763c9da642SMatthias Ringwald const int bd_addr_string_len = 17; 37730314625SMatthias Ringwald uint16_t i = 0; 37830314625SMatthias Ringwald while ((i + bd_addr_string_len) <= size){ 3793c9da642SMatthias Ringwald if (memcmp(&buffer[i], "00:00:00:00:00:00", bd_addr_string_len)) { 3803c9da642SMatthias Ringwald i++; 3813c9da642SMatthias Ringwald continue; 3823c9da642SMatthias Ringwald } 3833c9da642SMatthias Ringwald // set address 3843c9da642SMatthias Ringwald (void)memcpy(&buffer[i], bd_addr_to_str(address), bd_addr_string_len); 3853c9da642SMatthias Ringwald i += bd_addr_string_len; 3863c9da642SMatthias Ringwald } 3873c9da642SMatthias Ringwald } 3883c9da642SMatthias Ringwald 389a6efb919SMatthias Ringwald static int scan_hex_byte(const char * byte_string){ 39041f9be70SMatthias Ringwald int upper_nibble = nibble_for_char(byte_string[0]); 391a6efb919SMatthias Ringwald if (upper_nibble < 0) return -1; 39241f9be70SMatthias Ringwald int lower_nibble = nibble_for_char(byte_string[1]); 393a6efb919SMatthias Ringwald if (lower_nibble < 0) return -1; 394a6efb919SMatthias Ringwald return (upper_nibble << 4) | lower_nibble; 395a6efb919SMatthias Ringwald } 396eb886013SMatthias Ringwald 397a6efb919SMatthias Ringwald int sscanf_bd_addr(const char * addr_string, bd_addr_t addr){ 39841f9be70SMatthias Ringwald const char * the_string = addr_string; 399a6efb919SMatthias Ringwald uint8_t buffer[BD_ADDR_LEN]; 400a6efb919SMatthias Ringwald int result = 0; 401eb886013SMatthias Ringwald int i; 402eb886013SMatthias Ringwald for (i = 0; i < BD_ADDR_LEN; i++) { 40341f9be70SMatthias Ringwald int single_byte = scan_hex_byte(the_string); 404a6efb919SMatthias Ringwald if (single_byte < 0) break; 40541f9be70SMatthias Ringwald the_string += 2; 406b0920f25SMilanka Ringwald buffer[i] = (uint8_t)single_byte; 40741f9be70SMatthias Ringwald // don't check separator after last byte 408c1ab6cc1SMatthias Ringwald if (i == (BD_ADDR_LEN - 1)) { 409a6efb919SMatthias Ringwald result = 1; 410a6efb919SMatthias Ringwald break; 411eb886013SMatthias Ringwald } 412cd2e416cSMatthias Ringwald // skip supported separators 41341f9be70SMatthias Ringwald char next_char = *the_string; 4145df9dc78SMatthias Ringwald if ((next_char == ':') || (next_char == '-') || (next_char == ' ')) { 41541f9be70SMatthias Ringwald the_string++; 416cd2e416cSMatthias Ringwald } 417a6efb919SMatthias Ringwald } 418a6efb919SMatthias Ringwald 4199305033eSMatthias Ringwald if (result != 0){ 420a6efb919SMatthias Ringwald bd_addr_copy(addr, buffer); 421a6efb919SMatthias Ringwald } 422a6efb919SMatthias Ringwald return result; 423eb886013SMatthias Ringwald } 4245d067ab1SMatthias Ringwald 4255d067ab1SMatthias Ringwald uint32_t btstack_atoi(const char * str){ 42641f9be70SMatthias Ringwald const char * the_string = str; 4275d067ab1SMatthias Ringwald uint32_t val = 0; 428ff3cc4a5SMatthias Ringwald while (true){ 42941f9be70SMatthias Ringwald char chr = *the_string++; 430c1ab6cc1SMatthias Ringwald if (!chr || (chr < '0') || (chr > '9')) 4315d067ab1SMatthias Ringwald return val; 4324ea43905SMatthias Ringwald val = (val * 10u) + (uint8_t)(chr - '0'); 4335d067ab1SMatthias Ringwald } 4345d067ab1SMatthias Ringwald } 4351f41c2c9SMatthias Ringwald 436d1207cd8SMilanka Ringwald int string_len_for_uint32(uint32_t i){ 437d1207cd8SMilanka Ringwald if (i < 10) return 1; 438d1207cd8SMilanka Ringwald if (i < 100) return 2; 439d1207cd8SMilanka Ringwald if (i < 1000) return 3; 440d1207cd8SMilanka Ringwald if (i < 10000) return 4; 441d1207cd8SMilanka Ringwald if (i < 100000) return 5; 442d1207cd8SMilanka Ringwald if (i < 1000000) return 6; 443d1207cd8SMilanka Ringwald if (i < 10000000) return 7; 444d1207cd8SMilanka Ringwald if (i < 100000000) return 8; 445d1207cd8SMilanka Ringwald if (i < 1000000000) return 9; 446d1207cd8SMilanka Ringwald return 10; 447d1207cd8SMilanka Ringwald } 448d1207cd8SMilanka Ringwald 449d1207cd8SMilanka Ringwald int count_set_bits_uint32(uint32_t x){ 45041f9be70SMatthias Ringwald uint32_t v = x; 45141f9be70SMatthias Ringwald v = (v & 0x55555555) + ((v >> 1) & 0x55555555U); 45241f9be70SMatthias Ringwald v = (v & 0x33333333) + ((v >> 2) & 0x33333333U); 45341f9be70SMatthias Ringwald v = (v & 0x0F0F0F0F) + ((v >> 4) & 0x0F0F0F0FU); 45441f9be70SMatthias Ringwald v = (v & 0x00FF00FF) + ((v >> 8) & 0x00FF00FFU); 45541f9be70SMatthias Ringwald v = (v & 0x0000FFFF) + ((v >> 16) & 0x0000FFFFU); 45641f9be70SMatthias Ringwald return v; 457d1207cd8SMilanka Ringwald } 4581f41c2c9SMatthias Ringwald 459ec08441fSMatthias Ringwald uint8_t btstack_clz(uint32_t value) { 460ec08441fSMatthias Ringwald #if defined(__GNUC__) || defined (__clang__) 461ec08441fSMatthias Ringwald // use gcc/clang intrinsic 462ec08441fSMatthias Ringwald return (uint8_t) __builtin_clz(value); 463ec08441fSMatthias Ringwald #elif defined(_MSC_VER) 464ec08441fSMatthias Ringwald // use MSVC intrinsic 465ec08441fSMatthias Ringwald DWORD leading_zero = 0; 466ec08441fSMatthias Ringwald if (_BitScanReverse( &leading_zero, value )){ 467ec08441fSMatthias Ringwald return (uint8_t)(31 - leading_zero); 468ec08441fSMatthias Ringwald } else { 469ec08441fSMatthias Ringwald return 32; 470ec08441fSMatthias Ringwald } 471ec08441fSMatthias Ringwald #else 472ec08441fSMatthias Ringwald // divide-and-conquer implementation for 32-bit integers 473af0ac871SAlec Cantor uint32_t x = value; 474ec08441fSMatthias Ringwald if (x == 0) return 32; 475ec08441fSMatthias Ringwald uint8_t r = 0; 476ec08441fSMatthias Ringwald if ((x & 0xffff0000u) == 0) { 477ec08441fSMatthias Ringwald x <<= 16; 478ec08441fSMatthias Ringwald r += 16; 479ec08441fSMatthias Ringwald } 480ec08441fSMatthias Ringwald if ((x & 0xff000000u) == 0) { 481ec08441fSMatthias Ringwald x <<= 8; 482ec08441fSMatthias Ringwald r += 8; 483ec08441fSMatthias Ringwald } 484ec08441fSMatthias Ringwald if ((x & 0xf0000000u) == 0) { 485ec08441fSMatthias Ringwald x <<= 4; 486ec08441fSMatthias Ringwald r += 4; 487ec08441fSMatthias Ringwald } 488ec08441fSMatthias Ringwald if ((x & 0xc0000000u) == 0) { 489ec08441fSMatthias Ringwald x <<= 2; 490ec08441fSMatthias Ringwald r += 2; 491ec08441fSMatthias Ringwald } 492ec08441fSMatthias Ringwald if ((x & 0x80000000u) == 0) { 493ec08441fSMatthias Ringwald x <<= 1; 494ec08441fSMatthias Ringwald r += 1; 495ec08441fSMatthias Ringwald } 496ec08441fSMatthias Ringwald return r; 497ec08441fSMatthias Ringwald #endif 498ec08441fSMatthias Ringwald } 499ec08441fSMatthias Ringwald 5001f41c2c9SMatthias Ringwald /* 5011f41c2c9SMatthias Ringwald * CRC (reversed crc) lookup table as calculated by the table generator in ETSI TS 101 369 V6.3.0. 5021f41c2c9SMatthias Ringwald */ 5031f41c2c9SMatthias Ringwald 5041f41c2c9SMatthias Ringwald #define CRC8_INIT 0xFF // Initial FCS value 5051f41c2c9SMatthias Ringwald #define CRC8_OK 0xCF // Good final FCS value 5061f41c2c9SMatthias Ringwald 5071f41c2c9SMatthias Ringwald static const uint8_t crc8table[256] = { /* reversed, 8-bit, poly=0x07 */ 5081f41c2c9SMatthias Ringwald 0x00, 0x91, 0xE3, 0x72, 0x07, 0x96, 0xE4, 0x75, 0x0E, 0x9F, 0xED, 0x7C, 0x09, 0x98, 0xEA, 0x7B, 5091f41c2c9SMatthias Ringwald 0x1C, 0x8D, 0xFF, 0x6E, 0x1B, 0x8A, 0xF8, 0x69, 0x12, 0x83, 0xF1, 0x60, 0x15, 0x84, 0xF6, 0x67, 5101f41c2c9SMatthias Ringwald 0x38, 0xA9, 0xDB, 0x4A, 0x3F, 0xAE, 0xDC, 0x4D, 0x36, 0xA7, 0xD5, 0x44, 0x31, 0xA0, 0xD2, 0x43, 5111f41c2c9SMatthias Ringwald 0x24, 0xB5, 0xC7, 0x56, 0x23, 0xB2, 0xC0, 0x51, 0x2A, 0xBB, 0xC9, 0x58, 0x2D, 0xBC, 0xCE, 0x5F, 5121f41c2c9SMatthias Ringwald 0x70, 0xE1, 0x93, 0x02, 0x77, 0xE6, 0x94, 0x05, 0x7E, 0xEF, 0x9D, 0x0C, 0x79, 0xE8, 0x9A, 0x0B, 5131f41c2c9SMatthias Ringwald 0x6C, 0xFD, 0x8F, 0x1E, 0x6B, 0xFA, 0x88, 0x19, 0x62, 0xF3, 0x81, 0x10, 0x65, 0xF4, 0x86, 0x17, 5141f41c2c9SMatthias Ringwald 0x48, 0xD9, 0xAB, 0x3A, 0x4F, 0xDE, 0xAC, 0x3D, 0x46, 0xD7, 0xA5, 0x34, 0x41, 0xD0, 0xA2, 0x33, 5151f41c2c9SMatthias Ringwald 0x54, 0xC5, 0xB7, 0x26, 0x53, 0xC2, 0xB0, 0x21, 0x5A, 0xCB, 0xB9, 0x28, 0x5D, 0xCC, 0xBE, 0x2F, 5161f41c2c9SMatthias Ringwald 0xE0, 0x71, 0x03, 0x92, 0xE7, 0x76, 0x04, 0x95, 0xEE, 0x7F, 0x0D, 0x9C, 0xE9, 0x78, 0x0A, 0x9B, 5171f41c2c9SMatthias Ringwald 0xFC, 0x6D, 0x1F, 0x8E, 0xFB, 0x6A, 0x18, 0x89, 0xF2, 0x63, 0x11, 0x80, 0xF5, 0x64, 0x16, 0x87, 5181f41c2c9SMatthias Ringwald 0xD8, 0x49, 0x3B, 0xAA, 0xDF, 0x4E, 0x3C, 0xAD, 0xD6, 0x47, 0x35, 0xA4, 0xD1, 0x40, 0x32, 0xA3, 5191f41c2c9SMatthias Ringwald 0xC4, 0x55, 0x27, 0xB6, 0xC3, 0x52, 0x20, 0xB1, 0xCA, 0x5B, 0x29, 0xB8, 0xCD, 0x5C, 0x2E, 0xBF, 5201f41c2c9SMatthias Ringwald 0x90, 0x01, 0x73, 0xE2, 0x97, 0x06, 0x74, 0xE5, 0x9E, 0x0F, 0x7D, 0xEC, 0x99, 0x08, 0x7A, 0xEB, 5211f41c2c9SMatthias Ringwald 0x8C, 0x1D, 0x6F, 0xFE, 0x8B, 0x1A, 0x68, 0xF9, 0x82, 0x13, 0x61, 0xF0, 0x85, 0x14, 0x66, 0xF7, 5221f41c2c9SMatthias Ringwald 0xA8, 0x39, 0x4B, 0xDA, 0xAF, 0x3E, 0x4C, 0xDD, 0xA6, 0x37, 0x45, 0xD4, 0xA1, 0x30, 0x42, 0xD3, 5231f41c2c9SMatthias Ringwald 0xB4, 0x25, 0x57, 0xC6, 0xB3, 0x22, 0x50, 0xC1, 0xBA, 0x2B, 0x59, 0xC8, 0xBD, 0x2C, 0x5E, 0xCF 5241f41c2c9SMatthias Ringwald }; 5251f41c2c9SMatthias Ringwald 5261f41c2c9SMatthias Ringwald /*-----------------------------------------------------------------------------------*/ 5271f41c2c9SMatthias Ringwald static uint8_t crc8(uint8_t *data, uint16_t len){ 5281f41c2c9SMatthias Ringwald uint16_t count; 5291f41c2c9SMatthias Ringwald uint8_t crc = CRC8_INIT; 5301f41c2c9SMatthias Ringwald for (count = 0; count < len; count++){ 5311f41c2c9SMatthias Ringwald crc = crc8table[crc ^ data[count]]; 5321f41c2c9SMatthias Ringwald } 5331f41c2c9SMatthias Ringwald return crc; 5341f41c2c9SMatthias Ringwald } 5351f41c2c9SMatthias Ringwald 5361f41c2c9SMatthias Ringwald /*-----------------------------------------------------------------------------------*/ 53763dd1c76SMatthias Ringwald uint8_t btstack_crc8_check(uint8_t *data, uint16_t len, uint8_t check_sum){ 5381f41c2c9SMatthias Ringwald uint8_t crc; 5391f41c2c9SMatthias Ringwald crc = crc8(data, len); 5401f41c2c9SMatthias Ringwald crc = crc8table[crc ^ check_sum]; 5411f41c2c9SMatthias Ringwald if (crc == CRC8_OK){ 5421f41c2c9SMatthias Ringwald return 0; /* Valid */ 5431f41c2c9SMatthias Ringwald } else { 5441f41c2c9SMatthias Ringwald return 1; /* Failed */ 5451f41c2c9SMatthias Ringwald } 5461f41c2c9SMatthias Ringwald } 5471f41c2c9SMatthias Ringwald 5481f41c2c9SMatthias Ringwald /*-----------------------------------------------------------------------------------*/ 54963dd1c76SMatthias Ringwald uint8_t btstack_crc8_calc(uint8_t *data, uint16_t len){ 5501f41c2c9SMatthias Ringwald /* Ones complement */ 5514ea43905SMatthias Ringwald return 0xFFu - crc8(data, len); 5521f41c2c9SMatthias Ringwald } 553a73d0b9dSMilanka Ringwald 554a73d0b9dSMilanka Ringwald uint16_t btstack_next_cid_ignoring_zero(uint16_t current_cid){ 555a73d0b9dSMilanka Ringwald uint16_t next_cid; 556a73d0b9dSMilanka Ringwald if (current_cid == 0xffff) { 557a73d0b9dSMilanka Ringwald next_cid = 1; 558a73d0b9dSMilanka Ringwald } else { 559a73d0b9dSMilanka Ringwald next_cid = current_cid + 1; 560a73d0b9dSMilanka Ringwald } 561a73d0b9dSMilanka Ringwald return next_cid; 562a73d0b9dSMilanka Ringwald } 563de22414aSMatthias Ringwald 564ed7a067cSMilanka Ringwald uint16_t btstack_strcpy(char * dst, uint16_t dst_size, const char * src){ 565981f700bSMatthias Ringwald uint16_t bytes_to_copy = (uint16_t) btstack_min( dst_size - 1, strlen(src)); 566de22414aSMatthias Ringwald (void) memcpy(dst, src, bytes_to_copy); 567981f700bSMatthias Ringwald dst[bytes_to_copy] = 0; 568ed7a067cSMilanka Ringwald return bytes_to_copy + 1; 569de22414aSMatthias Ringwald } 5703ece4788SMatthias Ringwald 5713ece4788SMatthias Ringwald void btstack_strcat(char * dst, uint16_t dst_size, const char * src){ 5723ece4788SMatthias Ringwald uint16_t src_len = (uint16_t) strlen(src); 5733ece4788SMatthias Ringwald uint16_t dst_len = (uint16_t) strlen(dst); 5743ece4788SMatthias Ringwald uint16_t bytes_to_copy = btstack_min( src_len, dst_size - dst_len - 1); 5753ece4788SMatthias Ringwald (void) memcpy( &dst[dst_len], src, bytes_to_copy); 5763ece4788SMatthias Ringwald dst[dst_len + bytes_to_copy] = 0; 5773ece4788SMatthias Ringwald } 578f819d1d9SMilanka Ringwald 579f819d1d9SMilanka Ringwald uint16_t btstack_virtual_memcpy( 580f819d1d9SMilanka Ringwald const uint8_t * field_data, uint16_t field_len, uint16_t field_offset, // position of field in complete data block 581f819d1d9SMilanka Ringwald uint8_t * buffer, uint16_t buffer_size, uint16_t buffer_offset){ 582f819d1d9SMilanka Ringwald 583f819d1d9SMilanka Ringwald uint16_t after_buffer = buffer_offset + buffer_size ; 584f819d1d9SMilanka Ringwald // bail before buffer 585f819d1d9SMilanka Ringwald if ((field_offset + field_len) < buffer_offset){ 586f819d1d9SMilanka Ringwald return 0; 587f819d1d9SMilanka Ringwald } 588f819d1d9SMilanka Ringwald // bail after buffer 589f819d1d9SMilanka Ringwald if (field_offset >= after_buffer){ 590f819d1d9SMilanka Ringwald return 0; 591f819d1d9SMilanka Ringwald } 592f819d1d9SMilanka Ringwald // calc overlap 593f819d1d9SMilanka Ringwald uint16_t bytes_to_copy = field_len; 594f819d1d9SMilanka Ringwald 595f819d1d9SMilanka Ringwald uint16_t skip_at_start = 0; 596f819d1d9SMilanka Ringwald if (field_offset < buffer_offset){ 597f819d1d9SMilanka Ringwald skip_at_start = buffer_offset - field_offset; 598f819d1d9SMilanka Ringwald bytes_to_copy -= skip_at_start; 599f819d1d9SMilanka Ringwald } 600f819d1d9SMilanka Ringwald 601f819d1d9SMilanka Ringwald uint16_t skip_at_end = 0; 602f819d1d9SMilanka Ringwald if ((field_offset + field_len) > after_buffer){ 603f819d1d9SMilanka Ringwald skip_at_end = (field_offset + field_len) - after_buffer; 604f819d1d9SMilanka Ringwald bytes_to_copy -= skip_at_end; 605f819d1d9SMilanka Ringwald } 606f819d1d9SMilanka Ringwald 607f819d1d9SMilanka Ringwald btstack_assert((skip_at_end + skip_at_start) <= field_len); 608f819d1d9SMilanka Ringwald btstack_assert(bytes_to_copy <= field_len); 609f819d1d9SMilanka Ringwald 610f819d1d9SMilanka Ringwald memcpy(&buffer[(field_offset + skip_at_start) - buffer_offset], &field_data[skip_at_start], bytes_to_copy); 611f819d1d9SMilanka Ringwald return bytes_to_copy; 612f819d1d9SMilanka Ringwald } 613