xref: /btstack/src/btstack_util.c (revision ed7a067cb20201ce77a97129882c83d8f45c7ce8)
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 
171ebaeb1beSMatthias Ringwald uint32_t btstack_min(uint32_t a, uint32_t b){
172c1ab6cc1SMatthias Ringwald     return (a < b) ? a : b;
173ebaeb1beSMatthias Ringwald }
174ebaeb1beSMatthias Ringwald 
175ebaeb1beSMatthias Ringwald uint32_t btstack_max(uint32_t a, uint32_t b){
176c1ab6cc1SMatthias Ringwald     return (a > b) ? a : b;
177ebaeb1beSMatthias Ringwald }
178ebaeb1beSMatthias Ringwald 
17968af3967SMatthias Ringwald /**
180a9d566f7SMatthias Ringwald  * @brief Calculate delta between two uint32_t points in time
1816b65794dSMilanka Ringwald  * @return time_a - time_b - result > 0 if time_a is newer than time_b
18268af3967SMatthias Ringwald  */
18368af3967SMatthias Ringwald int32_t btstack_time_delta(uint32_t time_a, uint32_t time_b){
18468af3967SMatthias Ringwald     return (int32_t)(time_a - time_b);
18568af3967SMatthias Ringwald }
18668af3967SMatthias Ringwald 
187a9d566f7SMatthias Ringwald /**
188a9d566f7SMatthias Ringwald  * @brief Calculate delta between two uint16_t points in time
189a9d566f7SMatthias Ringwald  * @return time_a - time_b - result > 0 if time_a is newer than time_b
190a9d566f7SMatthias Ringwald  */
191a9d566f7SMatthias Ringwald int16_t btstack_time16_delta(uint16_t time_a, uint16_t time_b){
192a9d566f7SMatthias Ringwald     return (int16_t)(time_a - time_b);
193a9d566f7SMatthias Ringwald }
194c1c58647SMatthias Ringwald 
195eb886013SMatthias Ringwald char char_for_nibble(int nibble){
1968334d3d8SMatthias Ringwald 
1978334d3d8SMatthias Ringwald     static const char * char_to_nibble = "0123456789ABCDEF";
1988334d3d8SMatthias Ringwald 
199c1c58647SMatthias Ringwald     if (nibble < 16){
200c1c58647SMatthias Ringwald         return char_to_nibble[nibble];
201c1c58647SMatthias Ringwald     } else {
202eb886013SMatthias Ringwald         return '?';
203eb886013SMatthias Ringwald     }
204c1c58647SMatthias Ringwald }
205eb886013SMatthias Ringwald 
206405d63a9SMatthias Ringwald static inline char char_for_high_nibble(int value){
207405d63a9SMatthias Ringwald     return char_for_nibble((value >> 4) & 0x0f);
208405d63a9SMatthias Ringwald }
209405d63a9SMatthias Ringwald 
210405d63a9SMatthias Ringwald static inline char char_for_low_nibble(int value){
211405d63a9SMatthias Ringwald     return char_for_nibble(value & 0x0f);
212405d63a9SMatthias Ringwald }
213405d63a9SMatthias Ringwald 
214c1c58647SMatthias Ringwald 
215a6efb919SMatthias Ringwald int nibble_for_char(char c){
216c1ab6cc1SMatthias Ringwald     if ((c >= '0') && (c <= '9')) return c - '0';
217c1ab6cc1SMatthias Ringwald     if ((c >= 'a') && (c <= 'f')) return c - 'a' + 10;
218c1ab6cc1SMatthias Ringwald     if ((c >= 'A') && (c <= 'F')) return c - 'A' + 10;
219a6efb919SMatthias Ringwald     return -1;
220a6efb919SMatthias Ringwald }
221a6efb919SMatthias Ringwald 
22246059ae4SMilanka Ringwald #ifdef ENABLE_PRINTF_HEXDUMP
223eb886013SMatthias Ringwald void printf_hexdump(const void * data, int size){
224c1c58647SMatthias Ringwald     char buffer[4];
225c1c58647SMatthias Ringwald     buffer[2] = ' ';
226c1c58647SMatthias Ringwald     buffer[3] =  0;
2279dbfa930SMatthias Ringwald     const uint8_t * ptr = (const uint8_t *) data;
228c1c58647SMatthias Ringwald     while (size > 0){
2299dbfa930SMatthias Ringwald         uint8_t byte = *ptr++;
230c1c58647SMatthias Ringwald         buffer[0] = char_for_high_nibble(byte);
231c1c58647SMatthias Ringwald         buffer[1] = char_for_low_nibble(byte);
232c1c58647SMatthias Ringwald         printf("%s", buffer);
233c1c58647SMatthias Ringwald         size--;
234eb886013SMatthias Ringwald     }
235eb886013SMatthias Ringwald     printf("\n");
236eb886013SMatthias Ringwald }
23746059ae4SMilanka Ringwald #endif
238eb886013SMatthias Ringwald 
239cb42147aSMatthias Ringwald #if defined(ENABLE_LOG_INFO) || defined(ENABLE_LOG_DEBUG)
240cb42147aSMatthias Ringwald static void log_hexdump(int level, const void * data, int size){
241405d63a9SMatthias Ringwald #define ITEMS_PER_LINE 16
242405d63a9SMatthias Ringwald // template '0x12, '
243405d63a9SMatthias Ringwald #define BYTES_PER_BYTE  6
244405d63a9SMatthias Ringwald     char buffer[BYTES_PER_BYTE*ITEMS_PER_LINE+1];
2457224be7eSMatthias Ringwald     int i, j;
246eb886013SMatthias Ringwald     j = 0;
247eb886013SMatthias Ringwald     for (i=0; i<size;i++){
2487224be7eSMatthias Ringwald 
2497224be7eSMatthias Ringwald         // help static analyzer proof that j stays within bounds
250c1ab6cc1SMatthias Ringwald         if (j > (BYTES_PER_BYTE * (ITEMS_PER_LINE-1))){
2517224be7eSMatthias Ringwald             j = 0;
2527224be7eSMatthias Ringwald         }
2537224be7eSMatthias Ringwald 
254eb886013SMatthias Ringwald         uint8_t byte = ((uint8_t *)data)[i];
255eb886013SMatthias Ringwald         buffer[j++] = '0';
256eb886013SMatthias Ringwald         buffer[j++] = 'x';
257405d63a9SMatthias Ringwald         buffer[j++] = char_for_high_nibble(byte);
258405d63a9SMatthias Ringwald         buffer[j++] = char_for_low_nibble(byte);
259eb886013SMatthias Ringwald         buffer[j++] = ',';
260eb886013SMatthias Ringwald         buffer[j++] = ' ';
2617224be7eSMatthias Ringwald 
262c1ab6cc1SMatthias Ringwald         if (j >= (BYTES_PER_BYTE * ITEMS_PER_LINE) ){
263eb886013SMatthias Ringwald             buffer[j] = 0;
264cb42147aSMatthias Ringwald             HCI_DUMP_LOG(level, "%s", buffer);
265eb886013SMatthias Ringwald             j = 0;
266eb886013SMatthias Ringwald         }
267eb886013SMatthias Ringwald     }
268eb886013SMatthias Ringwald     if (j != 0){
269eb886013SMatthias Ringwald         buffer[j] = 0;
270cb42147aSMatthias Ringwald         HCI_DUMP_LOG(level, "%s", buffer);
271eb886013SMatthias Ringwald     }
272cb42147aSMatthias Ringwald }
273cb42147aSMatthias Ringwald #endif
274cb42147aSMatthias Ringwald 
275cb42147aSMatthias Ringwald void log_debug_hexdump(const void * data, int size){
276e950fa96SMatthias Ringwald #ifdef ENABLE_LOG_DEBUG
277fa087deaSMatthias Ringwald     log_hexdump(HCI_DUMP_LOG_LEVEL_DEBUG, data, size);
278cb42147aSMatthias Ringwald #else
2794bd79111SMatthias Ringwald     UNUSED(data);   // ok: no code
2804bd79111SMatthias Ringwald     UNUSED(size);   // ok: no code
281cb42147aSMatthias Ringwald #endif
282cb42147aSMatthias Ringwald }
283cb42147aSMatthias Ringwald 
284cb42147aSMatthias Ringwald void log_info_hexdump(const void * data, int size){
285cb42147aSMatthias Ringwald #ifdef ENABLE_LOG_INFO
286fa087deaSMatthias Ringwald     log_hexdump(HCI_DUMP_LOG_LEVEL_INFO, data, size);
287d0662982SMatthias Ringwald #else
2884bd79111SMatthias Ringwald     UNUSED(data);   // ok: no code
2894bd79111SMatthias Ringwald     UNUSED(size);   // ok: no code
2908314c363SMatthias Ringwald #endif
2917299c0feSMatthias Ringwald }
292eb886013SMatthias Ringwald 
2938314c363SMatthias Ringwald void log_info_key(const char * name, sm_key_t key){
29402bdfbf8SMatthias Ringwald #ifdef ENABLE_LOG_INFO
29502bdfbf8SMatthias Ringwald     char buffer[16*2+1];
29602bdfbf8SMatthias Ringwald     int i;
29702bdfbf8SMatthias Ringwald     int j = 0;
29802bdfbf8SMatthias Ringwald     for (i=0; i<16;i++){
29902bdfbf8SMatthias Ringwald         uint8_t byte = key[i];
300405d63a9SMatthias Ringwald         buffer[j++] = char_for_high_nibble(byte);
301405d63a9SMatthias Ringwald         buffer[j++] = char_for_low_nibble(byte);
30202bdfbf8SMatthias Ringwald     }
30302bdfbf8SMatthias Ringwald     buffer[j] = 0;
30402bdfbf8SMatthias Ringwald     log_info("%-6s %s", name, buffer);
305d0662982SMatthias Ringwald #else
306d0662982SMatthias Ringwald     UNUSED(name);
307cb42147aSMatthias Ringwald     (void)key;
30802bdfbf8SMatthias Ringwald #endif
309eb886013SMatthias Ringwald }
310eb886013SMatthias Ringwald 
3112b604902SMatthias Ringwald // UUIDs are stored in big endian, similar to bd_addr_t
3122b604902SMatthias Ringwald 
313eb886013SMatthias Ringwald // Bluetooth Base UUID: 00000000-0000-1000-8000- 00805F9B34FB
3142b604902SMatthias Ringwald const uint8_t bluetooth_base_uuid[] = { 0x00, 0x00, 0x00, 0x00, /* - */ 0x00, 0x00, /* - */ 0x10, 0x00, /* - */
315eb886013SMatthias Ringwald     0x80, 0x00, /* - */ 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB };
316eb886013SMatthias Ringwald 
31748cdff9cSMilanka Ringwald void uuid_add_bluetooth_prefix(uint8_t * uuid128, uint32_t short_uuid){
318b45b7749SMilanka Ringwald     (void)memcpy(uuid128, bluetooth_base_uuid, 16);
31948cdff9cSMilanka Ringwald     big_endian_store_32(uuid128, 0, short_uuid);
320eb886013SMatthias Ringwald }
321eb886013SMatthias Ringwald 
3225222912bSMatthias Ringwald int uuid_has_bluetooth_prefix(const uint8_t * uuid128){
3232b604902SMatthias Ringwald     return memcmp(&uuid128[4], &bluetooth_base_uuid[4], 12) == 0;
324eb886013SMatthias Ringwald }
325eb886013SMatthias Ringwald 
326eb886013SMatthias Ringwald static char uuid128_to_str_buffer[32+4+1];
3275222912bSMatthias Ringwald char * uuid128_to_str(const uint8_t * uuid){
3287224be7eSMatthias Ringwald     int i;
3297224be7eSMatthias Ringwald     int j = 0;
3307224be7eSMatthias Ringwald     // after 4, 6, 8, and 10 bytes = XYXYXYXY-XYXY-XYXY-XYXY-XYXYXYXYXYXY, there's a dash
3317224be7eSMatthias Ringwald     const int dash_locations = (1<<3) | (1<<5) | (1<<7) | (1<<9);
3327224be7eSMatthias Ringwald     for (i=0;i<16;i++){
333405d63a9SMatthias Ringwald         uint8_t byte = uuid[i];
334405d63a9SMatthias Ringwald         uuid128_to_str_buffer[j++] = char_for_high_nibble(byte);
335405d63a9SMatthias Ringwald         uuid128_to_str_buffer[j++] = char_for_low_nibble(byte);
3367224be7eSMatthias Ringwald         if (dash_locations & (1<<i)){
3377224be7eSMatthias Ringwald             uuid128_to_str_buffer[j++] = '-';
3387224be7eSMatthias Ringwald         }
3397224be7eSMatthias Ringwald     }
340eb886013SMatthias Ringwald     return uuid128_to_str_buffer;
341eb886013SMatthias Ringwald }
342eb886013SMatthias Ringwald 
343eb886013SMatthias Ringwald static char bd_addr_to_str_buffer[6*3];  // 12:45:78:01:34:67\0
34461c3ec28SMatthias Ringwald char * bd_addr_to_str_with_delimiter(const bd_addr_t addr, char delimiter){
345eb886013SMatthias Ringwald     char * p = bd_addr_to_str_buffer;
346eb886013SMatthias Ringwald     int i;
347eb886013SMatthias Ringwald     for (i = 0; i < 6 ; i++) {
348405d63a9SMatthias Ringwald         uint8_t byte = addr[i];
349405d63a9SMatthias Ringwald         *p++ = char_for_high_nibble(byte);
350405d63a9SMatthias Ringwald         *p++ = char_for_low_nibble(byte);
35161c3ec28SMatthias Ringwald         *p++ = delimiter;
352eb886013SMatthias Ringwald     }
353eb886013SMatthias Ringwald     *--p = 0;
354eb886013SMatthias Ringwald     return (char *) bd_addr_to_str_buffer;
355eb886013SMatthias Ringwald }
356eb886013SMatthias Ringwald 
35761c3ec28SMatthias Ringwald char * bd_addr_to_str(const bd_addr_t addr){
35861c3ec28SMatthias Ringwald     return bd_addr_to_str_with_delimiter(addr, ':');
35961c3ec28SMatthias Ringwald }
36061c3ec28SMatthias Ringwald 
3613c9da642SMatthias Ringwald void btstack_replace_bd_addr_placeholder(uint8_t * buffer, uint16_t size, const bd_addr_t address){
3623c9da642SMatthias Ringwald     const int bd_addr_string_len = 17;
36330314625SMatthias Ringwald     uint16_t i = 0;
36430314625SMatthias Ringwald     while ((i + bd_addr_string_len) <= size){
3653c9da642SMatthias Ringwald         if (memcmp(&buffer[i], "00:00:00:00:00:00", bd_addr_string_len)) {
3663c9da642SMatthias Ringwald             i++;
3673c9da642SMatthias Ringwald             continue;
3683c9da642SMatthias Ringwald         }
3693c9da642SMatthias Ringwald         // set address
3703c9da642SMatthias Ringwald         (void)memcpy(&buffer[i], bd_addr_to_str(address), bd_addr_string_len);
3713c9da642SMatthias Ringwald         i += bd_addr_string_len;
3723c9da642SMatthias Ringwald     }
3733c9da642SMatthias Ringwald }
3743c9da642SMatthias Ringwald 
375a6efb919SMatthias Ringwald static int scan_hex_byte(const char * byte_string){
37641f9be70SMatthias Ringwald     int upper_nibble = nibble_for_char(byte_string[0]);
377a6efb919SMatthias Ringwald     if (upper_nibble < 0) return -1;
37841f9be70SMatthias Ringwald     int lower_nibble = nibble_for_char(byte_string[1]);
379a6efb919SMatthias Ringwald     if (lower_nibble < 0) return -1;
380a6efb919SMatthias Ringwald     return (upper_nibble << 4) | lower_nibble;
381a6efb919SMatthias Ringwald }
382eb886013SMatthias Ringwald 
383a6efb919SMatthias Ringwald int sscanf_bd_addr(const char * addr_string, bd_addr_t addr){
38441f9be70SMatthias Ringwald     const char * the_string = addr_string;
385a6efb919SMatthias Ringwald     uint8_t buffer[BD_ADDR_LEN];
386a6efb919SMatthias Ringwald     int result = 0;
387eb886013SMatthias Ringwald     int i;
388eb886013SMatthias Ringwald     for (i = 0; i < BD_ADDR_LEN; i++) {
38941f9be70SMatthias Ringwald         int single_byte = scan_hex_byte(the_string);
390a6efb919SMatthias Ringwald         if (single_byte < 0) break;
39141f9be70SMatthias Ringwald         the_string += 2;
392b0920f25SMilanka Ringwald         buffer[i] = (uint8_t)single_byte;
39341f9be70SMatthias Ringwald         // don't check separator after last byte
394c1ab6cc1SMatthias Ringwald         if (i == (BD_ADDR_LEN - 1)) {
395a6efb919SMatthias Ringwald             result = 1;
396a6efb919SMatthias Ringwald             break;
397eb886013SMatthias Ringwald         }
398cd2e416cSMatthias Ringwald         // skip supported separators
39941f9be70SMatthias Ringwald         char next_char = *the_string;
4005df9dc78SMatthias Ringwald         if ((next_char == ':') || (next_char == '-') || (next_char == ' ')) {
40141f9be70SMatthias Ringwald             the_string++;
402cd2e416cSMatthias Ringwald         }
403a6efb919SMatthias Ringwald     }
404a6efb919SMatthias Ringwald 
4059305033eSMatthias Ringwald     if (result != 0){
406a6efb919SMatthias Ringwald         bd_addr_copy(addr, buffer);
407a6efb919SMatthias Ringwald     }
408a6efb919SMatthias Ringwald 	return result;
409eb886013SMatthias Ringwald }
4105d067ab1SMatthias Ringwald 
4115d067ab1SMatthias Ringwald uint32_t btstack_atoi(const char * str){
41241f9be70SMatthias Ringwald     const char * the_string = str;
4135d067ab1SMatthias Ringwald     uint32_t val = 0;
414ff3cc4a5SMatthias Ringwald     while (true){
41541f9be70SMatthias Ringwald         char chr = *the_string++;
416c1ab6cc1SMatthias Ringwald         if (!chr || (chr < '0') || (chr > '9'))
4175d067ab1SMatthias Ringwald             return val;
4184ea43905SMatthias Ringwald         val = (val * 10u) + (uint8_t)(chr - '0');
4195d067ab1SMatthias Ringwald     }
4205d067ab1SMatthias Ringwald }
4211f41c2c9SMatthias Ringwald 
422d1207cd8SMilanka Ringwald int string_len_for_uint32(uint32_t i){
423d1207cd8SMilanka Ringwald     if (i <         10) return 1;
424d1207cd8SMilanka Ringwald     if (i <        100) return 2;
425d1207cd8SMilanka Ringwald     if (i <       1000) return 3;
426d1207cd8SMilanka Ringwald     if (i <      10000) return 4;
427d1207cd8SMilanka Ringwald     if (i <     100000) return 5;
428d1207cd8SMilanka Ringwald     if (i <    1000000) return 6;
429d1207cd8SMilanka Ringwald     if (i <   10000000) return 7;
430d1207cd8SMilanka Ringwald     if (i <  100000000) return 8;
431d1207cd8SMilanka Ringwald     if (i < 1000000000) return 9;
432d1207cd8SMilanka Ringwald     return 10;
433d1207cd8SMilanka Ringwald }
434d1207cd8SMilanka Ringwald 
435d1207cd8SMilanka Ringwald int count_set_bits_uint32(uint32_t x){
43641f9be70SMatthias Ringwald     uint32_t v = x;
43741f9be70SMatthias Ringwald     v = (v & 0x55555555) + ((v >> 1)  & 0x55555555U);
43841f9be70SMatthias Ringwald     v = (v & 0x33333333) + ((v >> 2)  & 0x33333333U);
43941f9be70SMatthias Ringwald     v = (v & 0x0F0F0F0F) + ((v >> 4)  & 0x0F0F0F0FU);
44041f9be70SMatthias Ringwald     v = (v & 0x00FF00FF) + ((v >> 8)  & 0x00FF00FFU);
44141f9be70SMatthias Ringwald     v = (v & 0x0000FFFF) + ((v >> 16) & 0x0000FFFFU);
44241f9be70SMatthias Ringwald     return v;
443d1207cd8SMilanka Ringwald }
4441f41c2c9SMatthias Ringwald 
445ec08441fSMatthias Ringwald uint8_t btstack_clz(uint32_t value) {
446ec08441fSMatthias Ringwald #if defined(__GNUC__) || defined (__clang__)
447ec08441fSMatthias Ringwald     // use gcc/clang intrinsic
448ec08441fSMatthias Ringwald     return (uint8_t) __builtin_clz(value);
449ec08441fSMatthias Ringwald #elif defined(_MSC_VER)
450ec08441fSMatthias Ringwald     // use MSVC intrinsic
451ec08441fSMatthias Ringwald     DWORD leading_zero = 0;
452ec08441fSMatthias Ringwald     if (_BitScanReverse( &leading_zero, value )){
453ec08441fSMatthias Ringwald 		return (uint8_t)(31 - leading_zero);
454ec08441fSMatthias Ringwald     } else {
455ec08441fSMatthias Ringwald         return 32;
456ec08441fSMatthias Ringwald     }
457ec08441fSMatthias Ringwald #else
458ec08441fSMatthias Ringwald     // divide-and-conquer implementation for 32-bit integers
459ec08441fSMatthias Ringwald     if (x == 0) return 32;
460ec08441fSMatthias Ringwald     uint8_t r = 0;
461ec08441fSMatthias Ringwald     if ((x & 0xffff0000u) == 0) {
462ec08441fSMatthias Ringwald         x <<= 16;
463ec08441fSMatthias Ringwald         r += 16;
464ec08441fSMatthias Ringwald     }
465ec08441fSMatthias Ringwald     if ((x & 0xff000000u) == 0) {
466ec08441fSMatthias Ringwald         x <<= 8;
467ec08441fSMatthias Ringwald         r += 8;
468ec08441fSMatthias Ringwald     }
469ec08441fSMatthias Ringwald     if ((x & 0xf0000000u) == 0) {
470ec08441fSMatthias Ringwald         x <<= 4;
471ec08441fSMatthias Ringwald         r += 4;
472ec08441fSMatthias Ringwald     }
473ec08441fSMatthias Ringwald     if ((x & 0xc0000000u) == 0) {
474ec08441fSMatthias Ringwald         x <<= 2;
475ec08441fSMatthias Ringwald         r += 2;
476ec08441fSMatthias Ringwald     }
477ec08441fSMatthias Ringwald     if ((x & 0x80000000u) == 0) {
478ec08441fSMatthias Ringwald         x <<= 1;
479ec08441fSMatthias Ringwald         r += 1;
480ec08441fSMatthias Ringwald     }
481ec08441fSMatthias Ringwald     return r;
482ec08441fSMatthias Ringwald #endif
483ec08441fSMatthias Ringwald }
484ec08441fSMatthias Ringwald 
4851f41c2c9SMatthias Ringwald /*
4861f41c2c9SMatthias Ringwald  * CRC (reversed crc) lookup table as calculated by the table generator in ETSI TS 101 369 V6.3.0.
4871f41c2c9SMatthias Ringwald  */
4881f41c2c9SMatthias Ringwald 
4891f41c2c9SMatthias Ringwald #define CRC8_INIT  0xFF          // Initial FCS value
4901f41c2c9SMatthias Ringwald #define CRC8_OK    0xCF          // Good final FCS value
4911f41c2c9SMatthias Ringwald 
4921f41c2c9SMatthias Ringwald static const uint8_t crc8table[256] = {    /* reversed, 8-bit, poly=0x07 */
4931f41c2c9SMatthias Ringwald     0x00, 0x91, 0xE3, 0x72, 0x07, 0x96, 0xE4, 0x75, 0x0E, 0x9F, 0xED, 0x7C, 0x09, 0x98, 0xEA, 0x7B,
4941f41c2c9SMatthias Ringwald     0x1C, 0x8D, 0xFF, 0x6E, 0x1B, 0x8A, 0xF8, 0x69, 0x12, 0x83, 0xF1, 0x60, 0x15, 0x84, 0xF6, 0x67,
4951f41c2c9SMatthias Ringwald     0x38, 0xA9, 0xDB, 0x4A, 0x3F, 0xAE, 0xDC, 0x4D, 0x36, 0xA7, 0xD5, 0x44, 0x31, 0xA0, 0xD2, 0x43,
4961f41c2c9SMatthias Ringwald     0x24, 0xB5, 0xC7, 0x56, 0x23, 0xB2, 0xC0, 0x51, 0x2A, 0xBB, 0xC9, 0x58, 0x2D, 0xBC, 0xCE, 0x5F,
4971f41c2c9SMatthias Ringwald     0x70, 0xE1, 0x93, 0x02, 0x77, 0xE6, 0x94, 0x05, 0x7E, 0xEF, 0x9D, 0x0C, 0x79, 0xE8, 0x9A, 0x0B,
4981f41c2c9SMatthias Ringwald     0x6C, 0xFD, 0x8F, 0x1E, 0x6B, 0xFA, 0x88, 0x19, 0x62, 0xF3, 0x81, 0x10, 0x65, 0xF4, 0x86, 0x17,
4991f41c2c9SMatthias Ringwald     0x48, 0xD9, 0xAB, 0x3A, 0x4F, 0xDE, 0xAC, 0x3D, 0x46, 0xD7, 0xA5, 0x34, 0x41, 0xD0, 0xA2, 0x33,
5001f41c2c9SMatthias Ringwald     0x54, 0xC5, 0xB7, 0x26, 0x53, 0xC2, 0xB0, 0x21, 0x5A, 0xCB, 0xB9, 0x28, 0x5D, 0xCC, 0xBE, 0x2F,
5011f41c2c9SMatthias Ringwald     0xE0, 0x71, 0x03, 0x92, 0xE7, 0x76, 0x04, 0x95, 0xEE, 0x7F, 0x0D, 0x9C, 0xE9, 0x78, 0x0A, 0x9B,
5021f41c2c9SMatthias Ringwald     0xFC, 0x6D, 0x1F, 0x8E, 0xFB, 0x6A, 0x18, 0x89, 0xF2, 0x63, 0x11, 0x80, 0xF5, 0x64, 0x16, 0x87,
5031f41c2c9SMatthias Ringwald     0xD8, 0x49, 0x3B, 0xAA, 0xDF, 0x4E, 0x3C, 0xAD, 0xD6, 0x47, 0x35, 0xA4, 0xD1, 0x40, 0x32, 0xA3,
5041f41c2c9SMatthias Ringwald     0xC4, 0x55, 0x27, 0xB6, 0xC3, 0x52, 0x20, 0xB1, 0xCA, 0x5B, 0x29, 0xB8, 0xCD, 0x5C, 0x2E, 0xBF,
5051f41c2c9SMatthias Ringwald     0x90, 0x01, 0x73, 0xE2, 0x97, 0x06, 0x74, 0xE5, 0x9E, 0x0F, 0x7D, 0xEC, 0x99, 0x08, 0x7A, 0xEB,
5061f41c2c9SMatthias Ringwald     0x8C, 0x1D, 0x6F, 0xFE, 0x8B, 0x1A, 0x68, 0xF9, 0x82, 0x13, 0x61, 0xF0, 0x85, 0x14, 0x66, 0xF7,
5071f41c2c9SMatthias Ringwald     0xA8, 0x39, 0x4B, 0xDA, 0xAF, 0x3E, 0x4C, 0xDD, 0xA6, 0x37, 0x45, 0xD4, 0xA1, 0x30, 0x42, 0xD3,
5081f41c2c9SMatthias Ringwald     0xB4, 0x25, 0x57, 0xC6, 0xB3, 0x22, 0x50, 0xC1, 0xBA, 0x2B, 0x59, 0xC8, 0xBD, 0x2C, 0x5E, 0xCF
5091f41c2c9SMatthias Ringwald };
5101f41c2c9SMatthias Ringwald 
5111f41c2c9SMatthias Ringwald /*-----------------------------------------------------------------------------------*/
5121f41c2c9SMatthias Ringwald static uint8_t crc8(uint8_t *data, uint16_t len){
5131f41c2c9SMatthias Ringwald     uint16_t count;
5141f41c2c9SMatthias Ringwald     uint8_t crc = CRC8_INIT;
5151f41c2c9SMatthias Ringwald     for (count = 0; count < len; count++){
5161f41c2c9SMatthias Ringwald         crc = crc8table[crc ^ data[count]];
5171f41c2c9SMatthias Ringwald     }
5181f41c2c9SMatthias Ringwald     return crc;
5191f41c2c9SMatthias Ringwald }
5201f41c2c9SMatthias Ringwald 
5211f41c2c9SMatthias Ringwald /*-----------------------------------------------------------------------------------*/
52263dd1c76SMatthias Ringwald uint8_t btstack_crc8_check(uint8_t *data, uint16_t len, uint8_t check_sum){
5231f41c2c9SMatthias Ringwald     uint8_t crc;
5241f41c2c9SMatthias Ringwald     crc = crc8(data, len);
5251f41c2c9SMatthias Ringwald     crc = crc8table[crc ^ check_sum];
5261f41c2c9SMatthias Ringwald     if (crc == CRC8_OK){
5271f41c2c9SMatthias Ringwald         return 0;               /* Valid */
5281f41c2c9SMatthias Ringwald     } else {
5291f41c2c9SMatthias Ringwald         return 1;               /* Failed */
5301f41c2c9SMatthias Ringwald     }
5311f41c2c9SMatthias Ringwald }
5321f41c2c9SMatthias Ringwald 
5331f41c2c9SMatthias Ringwald /*-----------------------------------------------------------------------------------*/
53463dd1c76SMatthias Ringwald uint8_t btstack_crc8_calc(uint8_t *data, uint16_t len){
5351f41c2c9SMatthias Ringwald     /* Ones complement */
5364ea43905SMatthias Ringwald     return 0xFFu - crc8(data, len);
5371f41c2c9SMatthias Ringwald }
538a73d0b9dSMilanka Ringwald 
539a73d0b9dSMilanka Ringwald uint16_t btstack_next_cid_ignoring_zero(uint16_t current_cid){
540a73d0b9dSMilanka Ringwald     uint16_t next_cid;
541a73d0b9dSMilanka Ringwald     if (current_cid == 0xffff) {
542a73d0b9dSMilanka Ringwald         next_cid = 1;
543a73d0b9dSMilanka Ringwald     } else {
544a73d0b9dSMilanka Ringwald         next_cid = current_cid + 1;
545a73d0b9dSMilanka Ringwald     }
546a73d0b9dSMilanka Ringwald     return next_cid;
547a73d0b9dSMilanka Ringwald }
548de22414aSMatthias Ringwald 
549*ed7a067cSMilanka Ringwald uint16_t btstack_strcpy(char * dst, uint16_t dst_size, const char * src){
550*ed7a067cSMilanka Ringwald     uint16_t bytes_to_copy = btstack_min( dst_size - 1, strlen(src));
551de22414aSMatthias Ringwald     (void) memcpy(dst, src, bytes_to_copy);
552*ed7a067cSMilanka Ringwald     dst[dst_size-1] = 0;
553*ed7a067cSMilanka Ringwald     return bytes_to_copy + 1;
554de22414aSMatthias Ringwald }
5553ece4788SMatthias Ringwald 
5563ece4788SMatthias Ringwald void btstack_strcat(char * dst, uint16_t dst_size, const char * src){
5573ece4788SMatthias Ringwald     uint16_t src_len = (uint16_t) strlen(src);
5583ece4788SMatthias Ringwald     uint16_t dst_len = (uint16_t) strlen(dst);
5593ece4788SMatthias Ringwald     uint16_t bytes_to_copy = btstack_min( src_len, dst_size - dst_len - 1);
5603ece4788SMatthias Ringwald     (void) memcpy( &dst[dst_len], src, bytes_to_copy);
5613ece4788SMatthias Ringwald     dst[dst_len + bytes_to_copy] = 0;
5623ece4788SMatthias Ringwald }
563f819d1d9SMilanka Ringwald 
564f819d1d9SMilanka Ringwald uint16_t btstack_virtual_memcpy(
565f819d1d9SMilanka Ringwald     const uint8_t * field_data, uint16_t field_len, uint16_t field_offset, // position of field in complete data block
566f819d1d9SMilanka Ringwald     uint8_t * buffer, uint16_t buffer_size, uint16_t buffer_offset){
567f819d1d9SMilanka Ringwald 
568f819d1d9SMilanka Ringwald     uint16_t after_buffer = buffer_offset + buffer_size ;
569f819d1d9SMilanka Ringwald     // bail before buffer
570f819d1d9SMilanka Ringwald     if ((field_offset + field_len) < buffer_offset){
571f819d1d9SMilanka Ringwald         return 0;
572f819d1d9SMilanka Ringwald     }
573f819d1d9SMilanka Ringwald     // bail after buffer
574f819d1d9SMilanka Ringwald     if (field_offset >= after_buffer){
575f819d1d9SMilanka Ringwald         return 0;
576f819d1d9SMilanka Ringwald     }
577f819d1d9SMilanka Ringwald     // calc overlap
578f819d1d9SMilanka Ringwald     uint16_t bytes_to_copy = field_len;
579f819d1d9SMilanka Ringwald 
580f819d1d9SMilanka Ringwald     uint16_t skip_at_start = 0;
581f819d1d9SMilanka Ringwald     if (field_offset < buffer_offset){
582f819d1d9SMilanka Ringwald         skip_at_start = buffer_offset - field_offset;
583f819d1d9SMilanka Ringwald         bytes_to_copy -= skip_at_start;
584f819d1d9SMilanka Ringwald     }
585f819d1d9SMilanka Ringwald 
586f819d1d9SMilanka Ringwald     uint16_t skip_at_end = 0;
587f819d1d9SMilanka Ringwald     if ((field_offset + field_len) > after_buffer){
588f819d1d9SMilanka Ringwald         skip_at_end = (field_offset + field_len) - after_buffer;
589f819d1d9SMilanka Ringwald         bytes_to_copy -= skip_at_end;
590f819d1d9SMilanka Ringwald     }
591f819d1d9SMilanka Ringwald 
592f819d1d9SMilanka Ringwald     btstack_assert((skip_at_end + skip_at_start) <= field_len);
593f819d1d9SMilanka Ringwald     btstack_assert(bytes_to_copy <= field_len);
594f819d1d9SMilanka Ringwald 
595f819d1d9SMilanka Ringwald     memcpy(&buffer[(field_offset + skip_at_start) - buffer_offset], &field_data[skip_at_start], bytes_to_copy);
596f819d1d9SMilanka Ringwald     return bytes_to_copy;
597f819d1d9SMilanka Ringwald }
598